diff options
author | Felipe Leme <felipeal@google.com> | 2019-03-27 13:40:40 -0700 |
---|---|---|
committer | Felipe Leme <felipeal@google.com> | 2019-03-27 17:11:08 -0700 |
commit | 9bee9440dbbba689f9d0c1dab3f19698e258d9d4 (patch) | |
tree | 76bdfcfbe9ba6e1c4197a5d7ed6f1a9c0215d6b6 /services/contentcapture/java | |
parent | 469e872bf0b38d88aaa6a7e05c9ee0d3f9d5d9d5 (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')
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 |