summaryrefslogtreecommitdiff
path: root/services/contentcapture/java
diff options
context:
space:
mode:
authorFelipe Leme <felipeal@google.com>2019-03-27 13:40:40 -0700
committerFelipe Leme <felipeal@google.com>2019-03-27 17:11:08 -0700
commit9bee9440dbbba689f9d0c1dab3f19698e258d9d4 (patch)
tree76bdfcfbe9ba6e1c4197a5d7ed6f1a9c0215d6b6 /services/contentcapture/java
parent469e872bf0b38d88aaa6a7e05c9ee0d3f9d5d9d5 (diff)
Fixed ContentCapture and AugmentedAutofill methods that should not hold the main lock...
...otherwise they could ANR the ActivityManagerService and crash the system Test: manual verification Test: atest AugmentedLoginActivityTest Test: atest CtsContentCaptureServiceTestCases # sanity check (minus usual flakiness) Fixes: 129410913 Bug: 126266412 Change-Id: I4b0b0c389dd2c34928c6fffeec2854518a5e7da1
Diffstat (limited to 'services/contentcapture/java')
-rw-r--r--services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java119
-rw-r--r--services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java53
2 files changed, 115 insertions, 57 deletions
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index b2760e037f44..4a230e7bf759 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -40,6 +40,7 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.os.Binder;
+import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
@@ -50,8 +51,10 @@ import android.os.UserManager;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.service.contentcapture.ActivityEvent.ActivityEventType;
+import android.util.ArraySet;
import android.util.LocalLog;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.view.contentcapture.ContentCaptureHelper;
import android.view.contentcapture.ContentCaptureManager;
@@ -60,6 +63,7 @@ import android.view.contentcapture.UserDataRemovalRequest;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.infra.AbstractRemoteService;
+import com.android.internal.infra.GlobalWhitelistState;
import com.android.internal.os.IResultReceiver;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.Preconditions;
@@ -117,6 +121,9 @@ public final class ContentCaptureManagerService extends
@GuardedBy("mLock") int mDevCfgLogHistorySize;
@GuardedBy("mLock") int mDevCfgIdleUnbindTimeoutMs;
+ final GlobalContentCaptureOptions mGlobalContentCaptureOptions =
+ new GlobalContentCaptureOptions();
+
public ContentCaptureManagerService(@NonNull Context context) {
super(context, new FrameworkResourcesServiceNameResolver(context,
com.android.internal.R.string.config_defaultContentCaptureService),
@@ -136,12 +143,12 @@ public final class ContentCaptureManagerService extends
mRequestsHistory = null;
}
- // Sets which services are disabled by settings
final UserManager um = getContext().getSystemService(UserManager.class);
final List<UserInfo> users = um.getUsers();
for (int i = 0; i < users.size(); i++) {
final int userId = users.get(i).id;
final boolean disabled = !isEnabledBySettings(userId);
+ // Sets which services are disabled by settings
if (disabled) {
Slog.i(mTag, "user " + userId + " disabled by settings");
if (mDisabledBySettings == null) {
@@ -149,6 +156,10 @@ public final class ContentCaptureManagerService extends
}
mDisabledBySettings.put(userId, true);
}
+ // Sets the global options for the service.
+ mGlobalContentCaptureOptions.setServiceInfo(userId,
+ mServiceNameResolver.getServiceName(userId),
+ mServiceNameResolver.isTemporary(userId));
}
}
@@ -188,6 +199,14 @@ public final class ContentCaptureManagerService extends
}
@Override // from AbstractMasterSystemService
+ protected void onServiceNameChanged(@UserIdInt int userId, @NonNull String serviceName,
+ boolean isTemporary) {
+ mGlobalContentCaptureOptions.setServiceInfo(userId, serviceName, isTemporary);
+
+ super.onServiceNameChanged(userId, serviceName, isTemporary);
+ }
+
+ @Override // from AbstractMasterSystemService
protected void enforceCallingPermissionForManagement() {
getContext().enforceCallingPermission(MANAGE_CONTENT_CAPTURE, mTag);
}
@@ -496,6 +515,8 @@ public final class ContentCaptureManagerService extends
pw.print(prefix2); pw.print("logHistorySize: "); pw.println(mDevCfgLogHistorySize);
pw.print(prefix2); pw.print("idleUnbindTimeoutMs: ");
pw.println(mDevCfgIdleUnbindTimeoutMs);
+ pw.print(prefix); pw.println("Global Options:");
+ mGlobalContentCaptureOptions.dump(prefix2, pw);
}
final class ContentCaptureManagerServiceStub extends IContentCaptureManager.Stub {
@@ -670,13 +691,7 @@ public final class ContentCaptureManagerService extends
@Override
public ContentCaptureOptions getOptionsForPackage(int userId, @NonNull String packageName) {
- synchronized (mLock) {
- final ContentCapturePerUserService service = peekServiceForUserLocked(userId);
- if (service != null) {
- return service.getOptionsForPackageLocked(packageName);
- }
- }
- return null;
+ return mGlobalContentCaptureOptions.getOptions(userId, packageName);
}
@Override
@@ -690,4 +705,92 @@ public final class ContentCaptureManagerService extends
}
}
}
+
+ /**
+ * Content capture options associated with all services.
+ *
+ * <p>This object is defined here instead of on each {@link ContentCapturePerUserService}
+ * because it cannot hold a lock on the main lock when
+ * {@link GlobalContentCaptureOptions#getOptions(int, String)} is called by external services.
+ */
+ final class GlobalContentCaptureOptions extends GlobalWhitelistState {
+
+ @GuardedBy("mGlobalWhitelistStateLock")
+ private final SparseArray<String> mServicePackages = new SparseArray<>();
+ @GuardedBy("mGlobalWhitelistStateLock")
+ private final SparseBooleanArray mTemporaryServices = new SparseBooleanArray();
+
+ private void setServiceInfo(@UserIdInt int userId, @Nullable String serviceName,
+ boolean isTemporary) {
+ synchronized (mGlobalWhitelistStateLock) {
+ if (isTemporary) {
+ mTemporaryServices.put(userId, true);
+ } else {
+ mTemporaryServices.delete(userId);
+ }
+ if (serviceName != null) {
+ final ComponentName componentName =
+ ComponentName.unflattenFromString(serviceName);
+ if (componentName == null) {
+ Slog.w(mTag, "setServiceInfo(): invalid name: " + serviceName);
+ mServicePackages.remove(userId);
+ } else {
+ mServicePackages.put(userId, componentName.getPackageName());
+ }
+ } else {
+ mServicePackages.remove(userId);
+ }
+ }
+ }
+
+ @Nullable
+ @GuardedBy("mGlobalWhitelistStateLock")
+ public ContentCaptureOptions getOptions(@UserIdInt int userId,
+ @NonNull String packageName) {
+ synchronized (mGlobalWhitelistStateLock) {
+ if (!isWhitelisted(userId, packageName)) {
+ if (packageName.equals(mServicePackages.get(userId))) {
+ if (verbose) Slog.v(mTag, "getOptionsForPackage() lite for " + packageName);
+ return new ContentCaptureOptions(mDevCfgLoggingLevel);
+ }
+ if (verbose) {
+ Slog.v(mTag, "getOptionsForPackage(" + packageName + "): not whitelisted");
+ }
+ return null;
+ }
+
+ final ArraySet<ComponentName> whitelistedComponents =
+ getWhitelistedComponents(userId, packageName);
+ if (Build.IS_USER && mServiceNameResolver.isTemporary(userId)) {
+ if (!packageName.equals(mServicePackages.get(userId))) {
+ Slog.w(mTag, "Ignoring package " + packageName
+ + " while using temporary service " + mServicePackages.get(userId));
+ return null;
+ }
+ }
+ final ContentCaptureOptions options = new ContentCaptureOptions(mDevCfgLoggingLevel,
+ mDevCfgMaxBufferSize, mDevCfgIdleFlushingFrequencyMs,
+ mDevCfgTextChangeFlushingFrequencyMs, mDevCfgLogHistorySize,
+ whitelistedComponents);
+ if (verbose) {
+ Slog.v(mTag, "getOptionsForPackage(" + packageName + "): " + options);
+ }
+ return options;
+ }
+ }
+
+ @Override
+ public void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
+ super.dump(prefix, pw);
+
+ synchronized (mGlobalWhitelistStateLock) {
+ if (mServicePackages.size() > 0) {
+ pw.print(prefix); pw.print("Service packages: "); pw.println(mServicePackages);
+ }
+ if (mTemporaryServices.size() > 0) {
+ pw.print(prefix); pw.print("Temp services: "); pw.println(mTemporaryServices);
+ }
+ }
+ }
+ }
}
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
index f0c6f7e7b0b8..593434499401 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
@@ -34,13 +34,11 @@ import android.app.ActivityManagerInternal;
import android.app.assist.AssistContent;
import android.app.assist.AssistStructure;
import android.content.ComponentName;
-import android.content.ContentCaptureOptions;
import android.content.pm.ActivityPresentationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ServiceInfo;
import android.os.Binder;
-import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.UserHandle;
@@ -52,7 +50,6 @@ import android.service.contentcapture.ContentCaptureServiceInfo;
import android.service.contentcapture.IContentCaptureServiceCallback;
import android.service.contentcapture.SnapshotData;
import android.util.ArrayMap;
-import android.util.ArraySet;
import android.util.Slog;
import android.view.contentcapture.UserDataRemovalRequest;
@@ -238,7 +235,8 @@ final class ContentCapturePerUserService
final int taskId = activityPresentationInfo.taskId;
final int displayId = activityPresentationInfo.displayId;
final ComponentName componentName = activityPresentationInfo.componentName;
- final boolean whiteListed = isWhitelistedLocked(componentName);
+ final boolean whiteListed = mMaster.mGlobalContentCaptureOptions.isWhitelisted(mUserId,
+ componentName);
final ComponentName serviceComponentName = getServiceComponentName();
final boolean enabled = isEnabledLocked();
if (mMaster.mRequestsHistory != null) {
@@ -315,11 +313,6 @@ final class ContentCapturePerUserService
newSession.notifySessionStartedLocked(clientReceiver);
}
- @GuardedBy("mLock")
- private boolean isWhitelistedLocked(@NonNull ComponentName componentName) {
- return mWhitelistHelper.isWhitelisted(componentName);
- }
-
// TODO(b/119613670): log metrics
@GuardedBy("mLock")
public void finishSessionLocked(@NonNull String sessionId) {
@@ -457,40 +450,6 @@ final class ContentCapturePerUserService
}
@GuardedBy("mLock")
- @Nullable
- ContentCaptureOptions getOptionsForPackageLocked(@NonNull String packageName) {
- if (!mWhitelistHelper.isWhitelisted(packageName)) {
- if (packageName.equals(getServicePackageName())) {
- if (mMaster.verbose) Slog.v(mTag, "getOptionsForPackage() lite for " + packageName);
- return new ContentCaptureOptions(mMaster.mDevCfgLoggingLevel);
- }
- if (mMaster.verbose) {
- Slog.v(mTag, "getOptionsForPackage(" + packageName + "): not whitelisted");
- }
- return null;
- }
-
- final ArraySet<ComponentName> whitelistedComponents = mWhitelistHelper
- .getWhitelistedComponents(packageName);
- if (Build.IS_USER && isTemporaryServiceSetLocked()) {
- final String servicePackageName = getServicePackageName();
- if (!packageName.equals(servicePackageName)) {
- Slog.w(mTag, "Ignoring package " + packageName
- + " while using temporary service " + servicePackageName);
- return null;
- }
- }
- ContentCaptureOptions options = new ContentCaptureOptions(mMaster.mDevCfgLoggingLevel,
- mMaster.mDevCfgMaxBufferSize, mMaster.mDevCfgIdleFlushingFrequencyMs,
- mMaster.mDevCfgTextChangeFlushingFrequencyMs, mMaster.mDevCfgLogHistorySize,
- whitelistedComponents);
- if (mMaster.verbose) {
- Slog.v(mTag, "getOptionsForPackage(" + packageName + "): " + options);
- }
- return options;
- }
-
- @GuardedBy("mLock")
void onActivityEventLocked(@NonNull ComponentName componentName, @ActivityEventType int type) {
if (mRemoteService == null) {
if (mMaster.debug) Slog.d(mTag, "onActivityEvent(): no remote service");
@@ -522,8 +481,6 @@ final class ContentCapturePerUserService
mRemoteService.dump(prefix2, pw);
}
- mWhitelistHelper.dump(prefix, "Whitelist", pw);
-
if (mSessions.isEmpty()) {
pw.print(prefix); pw.println("no sessions");
} else {
@@ -560,7 +517,7 @@ final class ContentCapturePerUserService
if (mMaster.verbose) {
Slog.v(TAG, "resetting content capture whitelist");
}
- mWhitelistHelper.setWhitelist((List) null, null);
+ mMaster.mGlobalContentCaptureOptions.resetWhitelist(mUserId);
}
private final class ContentCaptureServiceRemoteCallback extends
@@ -576,9 +533,7 @@ final class ContentCapturePerUserService
+ ", " + (activities == null
? "null_activities" : activities.size() + " activities") + ")");
}
- synchronized (mLock) {
- mWhitelistHelper.setWhitelist(packages, activities);
- }
+ mMaster.mGlobalContentCaptureOptions.setWhitelist(mUserId, packages, activities);
}
@Override