summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Svet Ganov <svetoslavganov@google.com> 2017-12-22 09:43:48 -0800
committer Svetoslav Ganov <svetoslavganov@google.com> 2017-12-23 02:36:46 +0000
commitd223db316d11a625a73f86392e7055d5c6f26e7d (patch)
treec620a6396b419bf5feb64355edf36726957fdfda
parent3cb35f37607cdb429734de905706c05957843da6 (diff)
Add infrastructure for running a11y tests in instant mode
This change adds a special flag when binding to a service to request instant apps to be considered as well (assuming the caller has the permission to see instant apps). This flag is scoped only for the platform to use and is intended only for development and testing. Specifically, we have a class of CTS tests that has tests plus service in the same APK (accessibility, printing, autofill, any other plugin based sub-system). Instead of doing the tediuous work split all these into one APK with tests and one with the services where the latter exposes a remote interface to the former, we will be adding shell commands to the dedicated sub-system to allow temporary binding to plugins provided by instant apps. The goal is not validating the plugin behavious, rather a working plugin is required to test app side funcionality. This change adds a shell command to allow the a11y manager serivce to bind to plugins provided by instant apps. This is required to be able to run relevant CTS test cases in instant mode. Test: cts-tradefed run cts-dev -m CtsAccessibilityTestCases cts-tradefed run cts-dev -m CtsAccessibilityServiceTestCases Bug: 70978575 Change-Id: Ifced735a9a6e495747372dd8b00fdd64933a09c7
-rw-r--r--core/java/android/content/Context.java9
-rw-r--r--core/res/AndroidManifest.xml10
-rw-r--r--packages/Shell/AndroidManifest.xml1
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java4
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java64
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java8
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityShellCommand.java100
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java27
8 files changed, 204 insertions, 19 deletions
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 137c1697d498..bd8103aebf69 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -324,6 +324,15 @@ public abstract class Context {
public static final int BIND_ADJUST_WITH_ACTIVITY = 0x0080;
/**
+ * @hide Flag for {@link #bindService}: allows binding to a service provided
+ * by an instant app. Note that the caller may not have access to the instant
+ * app providing the service which is a violation of the instant app sandbox.
+ * This flag is intended ONLY for development/testing and should be used with
+ * great care. Only the system is allowed to use this flag.
+ */
+ public static final int BIND_ALLOW_INSTANT = 0x00400000;
+
+ /**
* @hide Flag for {@link #bindService}: like {@link #BIND_NOT_FOREGROUND}, but puts it
* up in to the important background state (instead of transient).
*/
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 86d2ee3cd081..272e3c73bf89 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3534,11 +3534,19 @@
@hide -->
<permission android:name="android.permission.ACCESS_INSTANT_APPS"
android:protectionLevel="signature|installer|verifier" />
+ <uses-permission android:name="android.permission.ACCESS_INSTANT_APPS"/>
<!-- Allows the holder to view the instant applications on the device.
@hide -->
<permission android:name="android.permission.VIEW_INSTANT_APPS"
- android:protectionLevel="signature|preinstalled" />
+ android:protectionLevel="signature|preinstalled" />
+
+ <!-- Allows the holder to manage whether the system can bind to services
+ provided by instant apps. This permission is intended to protect
+ test/development fucntionality and should be used only in such cases.
+ @hide -->
+ <permission android:name="android.permission.MANAGE_BIND_INSTANT_SERVICE"
+ android:protectionLevel="signature" />
<!-- Allows receiving the usage of media resource e.g. video/audio codec and
graphic memory.
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index eab42dac5a27..d675a7a83056 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -132,6 +132,7 @@
<uses-permission android:name="android.permission.CHANGE_OVERLAY_PACKAGES" />
<!-- Permission needed to access privileged VR APIs -->
<uses-permission android:name="android.permission.RESTRICTED_VR_ACCESS" />
+ <uses-permission android:name="android.permission.MANAGE_BIND_INSTANT_SERVICE" />
<application android:label="@string/app_label"
android:defaultToDeviceProtectedStorage="true"
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index 3d7d6b7e5f3f..ed068b931bad 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -30,6 +30,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.graphics.Region;
import android.os.Binder;
@@ -740,6 +741,9 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
@Override
public boolean isFingerprintGestureDetectionAvailable() {
+ if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
+ return false;
+ }
if (isCapturingFingerprintGestures()) {
FingerprintGestureDispatcher dispatcher =
mSystemSupport.getFingerprintGestureDispatcher();
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index d83f6ae0425e..50b0be1a11d2 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -64,7 +64,9 @@ import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
+import android.os.ResultReceiver;
import android.os.ServiceManager;
+import android.os.ShellCallback;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
@@ -299,6 +301,14 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
return state;
}
+ boolean getBindInstantServiceAllowed(int userId) {
+ return mSecurityPolicy.getBindInstantServiceAllowed(userId);
+ }
+
+ void setBindInstantServiceAllowed(int userId, boolean allowed) {
+ mSecurityPolicy.setBindInstantServiceAllowed(userId, allowed);
+ }
+
private void registerBroadcastReceivers() {
PackageMonitor monitor = new PackageMonitor() {
@Override
@@ -1218,14 +1228,18 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
private boolean readInstalledAccessibilityServiceLocked(UserState userState) {
mTempAccessibilityServiceInfoList.clear();
+ int flags = PackageManager.GET_SERVICES
+ | PackageManager.GET_META_DATA
+ | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
+ | PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
+
+ if (userState.mBindInstantServiceAllowed) {
+ flags |= PackageManager.MATCH_INSTANT;
+ }
+
List<ResolveInfo> installedServices = mPackageManager.queryIntentServicesAsUser(
- new Intent(AccessibilityService.SERVICE_INTERFACE),
- PackageManager.GET_SERVICES
- | PackageManager.GET_META_DATA
- | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
- | PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
- mCurrentUserId);
+ new Intent(AccessibilityService.SERVICE_INTERFACE), flags, mCurrentUserId);
for (int i = 0, count = installedServices.size(); i < count; i++) {
ResolveInfo resolveInfo = installedServices.get(i);
@@ -2709,6 +2723,14 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
}
+ @Override
+ public void onShellCommand(FileDescriptor in, FileDescriptor out,
+ FileDescriptor err, String[] args, ShellCallback callback,
+ ResultReceiver resultReceiver) {
+ new AccessibilityShellCommand(this).exec(this, in, out, err, args,
+ callback, resultReceiver);
+ }
+
final class WindowsForAccessibilityCallback implements
WindowManagerInternal.WindowsForAccessibilityCallback {
@@ -3076,6 +3098,32 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
return uidPackages;
}
+ private boolean getBindInstantServiceAllowed(int userId) {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.MANAGE_BIND_INSTANT_SERVICE,
+ "getBindInstantServiceAllowed");
+ UserState state = mUserStates.get(userId);
+ return (state != null) && state.mBindInstantServiceAllowed;
+ }
+
+ private void setBindInstantServiceAllowed(int userId, boolean allowed) {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.MANAGE_BIND_INSTANT_SERVICE,
+ "setBindInstantServiceAllowed");
+ UserState state = mUserStates.get(userId);
+ if (state == null) {
+ if (!allowed) {
+ return;
+ }
+ state = new UserState(userId);
+ mUserStates.put(userId, state);
+ }
+ if (state.mBindInstantServiceAllowed != allowed) {
+ state.mBindInstantServiceAllowed = allowed;
+ onUserStateChangedLocked(state);
+ }
+ }
+
public void clearWindowsLocked() {
List<WindowInfo> windows = Collections.emptyList();
final int activeWindowId = mActiveWindowId;
@@ -3558,6 +3606,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
public boolean mIsFilterKeyEventsEnabled;
public boolean mAccessibilityFocusOnlyInActiveWindow;
+ public boolean mBindInstantServiceAllowed;
+
public UserState(int userId) {
mUserId = userId;
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
index 5f6efb613be7..96b897926136 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
@@ -91,10 +91,12 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
if (userState == null) return;
final long identity = Binder.clearCallingIdentity();
try {
+ int flags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE;
+ if (userState.mBindInstantServiceAllowed) {
+ flags |= Context.BIND_ALLOW_INSTANT;
+ }
if (mService == null && mContext.bindServiceAsUser(
- mIntent, this,
- Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
- new UserHandle(userState.mUserId))) {
+ mIntent, this, flags, new UserHandle(userState.mUserId))) {
userState.getBindingServicesLocked().add(mComponentName);
}
} finally {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityShellCommand.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityShellCommand.java
new file mode 100644
index 000000000000..ff59c24a7ca2
--- /dev/null
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityShellCommand.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.accessibility;
+
+import android.annotation.NonNull;
+import android.os.ShellCommand;
+import android.os.UserHandle;
+
+import java.io.PrintWriter;
+
+/**
+ * Shell command implementation for the accessibility manager service
+ */
+final class AccessibilityShellCommand extends ShellCommand {
+ final @NonNull AccessibilityManagerService mService;
+
+ AccessibilityShellCommand(@NonNull AccessibilityManagerService service) {
+ mService = service;
+ }
+
+ @Override
+ public int onCommand(String cmd) {
+ if (cmd == null) {
+ return handleDefaultCommands(cmd);
+ }
+ switch (cmd) {
+ case "get-bind-instant-service-allowed": {
+ return runGetBindInstantServiceAllowed();
+ }
+ case "set-bind-instant-service-allowed": {
+ return runSetBindInstantServiceAllowed();
+ }
+ }
+ return -1;
+ }
+
+ private int runGetBindInstantServiceAllowed() {
+ final Integer userId = parseUserId();
+ if (userId == null) {
+ return -1;
+ }
+ getOutPrintWriter().println(Boolean.toString(
+ mService.getBindInstantServiceAllowed(userId)));
+ return 0;
+ }
+
+ private int runSetBindInstantServiceAllowed() {
+ final Integer userId = parseUserId();
+ if (userId == null) {
+ return -1;
+ }
+ final String allowed = getNextArgRequired();
+ if (allowed == null) {
+ getErrPrintWriter().println("Error: no true/false specified");
+ return -1;
+ }
+ mService.setBindInstantServiceAllowed(userId,
+ Boolean.parseBoolean(allowed));
+ return 0;
+ }
+
+ private Integer parseUserId() {
+ final String option = getNextOption();
+ if (option != null) {
+ if (option.equals("--user")) {
+ return UserHandle.parseUserArg(getNextArgRequired());
+ } else {
+ getErrPrintWriter().println("Unknown option: " + option);
+ return null;
+ }
+ }
+ return UserHandle.USER_SYSTEM;
+ }
+
+ @Override
+ public void onHelp() {
+ PrintWriter pw = getOutPrintWriter();
+ pw.println("Accessibility service (accessibility) commands:");
+ pw.println(" help");
+ pw.println(" Print this help text.");
+ pw.println(" set-bind-instant-service-allowed [--user <USER_ID>] true|false ");
+ pw.println(" Set whether binding to services provided by instant apps is allowed.");
+ pw.println(" get-bind-instant-service-allowed [--user <USER_ID>]");
+ pw.println(" Get whether binding to services provided by instant apps is allowed.");
+ }
+} \ No newline at end of file
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 088ddeaab820..2f7d4c1ec634 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -348,7 +348,7 @@ public final class ActiveServices {
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType, callingPackage,
- callingPid, callingUid, userId, true, callerFg, false);
+ callingPid, callingUid, userId, true, callerFg, false, false);
if (res == null) {
return null;
}
@@ -597,7 +597,7 @@ public final class ActiveServices {
// If this service is active, make sure it is stopped.
ServiceLookupResult r = retrieveServiceLocked(service, resolvedType, null,
- Binder.getCallingPid(), Binder.getCallingUid(), userId, false, false, false);
+ Binder.getCallingPid(), Binder.getCallingUid(), userId, false, false, false, false);
if (r != null) {
if (r.record != null) {
final long origId = Binder.clearCallingIdentity();
@@ -658,7 +658,7 @@ public final class ActiveServices {
IBinder peekServiceLocked(Intent service, String resolvedType, String callingPackage) {
ServiceLookupResult r = retrieveServiceLocked(service, resolvedType, callingPackage,
Binder.getCallingPid(), Binder.getCallingUid(),
- UserHandle.getCallingUserId(), false, false, false);
+ UserHandle.getCallingUserId(), false, false, false, false);
IBinder ret = null;
if (r != null) {
@@ -1282,12 +1282,19 @@ public final class ActiveServices {
+ ") set BIND_ALLOW_WHITELIST_MANAGEMENT when binding service " + service);
}
+ if ((flags & Context.BIND_ALLOW_INSTANT) != 0 && !isCallerSystem) {
+ throw new SecurityException(
+ "Non-system caller " + caller + " (pid=" + Binder.getCallingPid()
+ + ") set BIND_ALLOW_INSTANT when binding service " + service);
+ }
+
final boolean callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
final boolean isBindExternal = (flags & Context.BIND_EXTERNAL_SERVICE) != 0;
+ final boolean allowInstant = (flags & Context.BIND_ALLOW_INSTANT) != 0;
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType, callingPackage, Binder.getCallingPid(),
- Binder.getCallingUid(), userId, true, callerFg, isBindExternal);
+ Binder.getCallingUid(), userId, true, callerFg, isBindExternal, allowInstant);
if (res == null) {
return 0;
}
@@ -1657,7 +1664,8 @@ public final class ActiveServices {
private ServiceLookupResult retrieveServiceLocked(Intent service,
String resolvedType, String callingPackage, int callingPid, int callingUid, int userId,
- boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal) {
+ boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal,
+ boolean allowInstant) {
ServiceRecord r = null;
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "retrieveServiceLocked: " + service
+ " type=" + resolvedType + " callingUid=" + callingUid);
@@ -1685,11 +1693,14 @@ public final class ActiveServices {
}
if (r == null) {
try {
+ int flags = ActivityManagerService.STOCK_PM_FLAGS
+ | PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
+ if (allowInstant) {
+ flags |= PackageManager.MATCH_INSTANT;
+ }
// TODO: come back and remove this assumption to triage all services
ResolveInfo rInfo = mAm.getPackageManagerInternalLocked().resolveService(service,
- resolvedType, ActivityManagerService.STOCK_PM_FLAGS
- | PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
- userId, callingUid);
+ resolvedType, flags, userId, callingUid);
ServiceInfo sInfo =
rInfo != null ? rInfo.serviceInfo : null;
if (sInfo == null) {