diff options
| author | 2019-03-28 17:32:49 +0000 | |
|---|---|---|
| committer | 2019-03-28 17:32:49 +0000 | |
| commit | f83f8ee39aa55fd143d3545d160b68755e6f8ca5 (patch) | |
| tree | c22dfb1fa20dad69629fdaed0dcb4e16f137e406 | |
| parent | bf92d73a37fa00ceca81567886417ada4ce74121 (diff) | |
| parent | 9bee9440dbbba689f9d0c1dab3f19698e258d9d4 (diff) | |
Merge "Fixed ContentCapture and AugmentedAutofill methods that should not hold the main lock..."
10 files changed, 390 insertions, 112 deletions
diff --git a/core/java/com/android/internal/infra/GlobalWhitelistState.java b/core/java/com/android/internal/infra/GlobalWhitelistState.java new file mode 100644 index 000000000000..dfa59b7bd0ac --- /dev/null +++ b/core/java/com/android/internal/infra/GlobalWhitelistState.java @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2019 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.internal.infra; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.UserIdInt; +import android.content.ComponentName; +import android.util.ArraySet; +import android.util.SparseArray; + +import com.android.internal.annotations.GuardedBy; + +import java.io.PrintWriter; +import java.util.List; + +/** + * Helper class used to manage a {@link WhitelistHelper} per user instance when the main service + * cannot hold a lock when external entities (typically {@code ActivityManagerService}) needs to + * get whitelist info. + * + * <p>This class is thread safe. + */ +public class GlobalWhitelistState { + + // Uses full-name to avoid collision with service-provided mLock + protected final Object mGlobalWhitelistStateLock = new Object(); + + @Nullable + @GuardedBy("mGlobalWhitelistStateLock") + protected SparseArray<WhitelistHelper> mWhitelisterHelpers; + + /** + * Sets the whitelist for the given user. + */ + public void setWhitelist(@UserIdInt int userId, @Nullable List<String> packageNames, + @Nullable List<ComponentName> components) { + synchronized (mGlobalWhitelistStateLock) { + if (mWhitelisterHelpers == null) { + mWhitelisterHelpers = new SparseArray<>(1); + } + WhitelistHelper helper = mWhitelisterHelpers.get(userId); + if (helper == null) { + helper = new WhitelistHelper(); + mWhitelisterHelpers.put(userId, helper); + } + helper.setWhitelist(packageNames, components); + } + } + + /** + * Checks if the given package is whitelisted for the given user. + */ + public boolean isWhitelisted(@UserIdInt int userId, @NonNull String packageName) { + synchronized (mGlobalWhitelistStateLock) { + if (mWhitelisterHelpers == null) return false; + final WhitelistHelper helper = mWhitelisterHelpers.get(userId); + return helper == null ? false : helper.isWhitelisted(packageName); + } + } + + /** + * Checks if the given component is whitelisted for the given user. + */ + public boolean isWhitelisted(@UserIdInt int userId, @NonNull ComponentName componentName) { + synchronized (mGlobalWhitelistStateLock) { + if (mWhitelisterHelpers == null) return false; + final WhitelistHelper helper = mWhitelisterHelpers.get(userId); + return helper == null ? false : helper.isWhitelisted(componentName); + } + } + + /** + * Gets the whitelisted components for the given package and user. + */ + public ArraySet<ComponentName> getWhitelistedComponents(@UserIdInt int userId, + @NonNull String packageName) { + synchronized (mGlobalWhitelistStateLock) { + if (mWhitelisterHelpers == null) return null; + final WhitelistHelper helper = mWhitelisterHelpers.get(userId); + return helper == null ? null : helper.getWhitelistedComponents(packageName); + } + } + + /** + * Resets the whitelist for the given user. + */ + public void resetWhitelist(@NonNull int userId) { + synchronized (mGlobalWhitelistStateLock) { + if (mWhitelisterHelpers == null) return; + mWhitelisterHelpers.remove(userId); + if (mWhitelisterHelpers.size() == 0) { + mWhitelisterHelpers = null; + } + } + } + + /** + * Dumps it! + */ + public void dump(@NonNull String prefix, @NonNull PrintWriter pw) { + pw.print(prefix); pw.print("State: "); + synchronized (mGlobalWhitelistStateLock) { + if (mWhitelisterHelpers == null) { + pw.println("empty"); + return; + } + pw.print(mWhitelisterHelpers.size()); pw.println(" services"); + final String prefix2 = prefix + " "; + for (int i = 0; i < mWhitelisterHelpers.size(); i++) { + final int userId = mWhitelisterHelpers.keyAt(i); + final WhitelistHelper helper = mWhitelisterHelpers.valueAt(i); + helper.dump(prefix2, "Whitelist for userId " + userId, pw); + } + } + } +} diff --git a/core/java/com/android/internal/infra/WhitelistHelper.java b/core/java/com/android/internal/infra/WhitelistHelper.java index 183b465afbfd..d7753db6b0f7 100644 --- a/core/java/com/android/internal/infra/WhitelistHelper.java +++ b/core/java/com/android/internal/infra/WhitelistHelper.java @@ -31,6 +31,7 @@ import java.util.List; /** * Helper class for keeping track of whitelisted packages/activities. * + * <p><b>NOTE: </b>this class is not thread safe. * @hide */ public final class WhitelistHelper { diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java index 7020e7ea6965..fdc3567aa002 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java @@ -42,6 +42,7 @@ import android.content.pm.UserInfo; import android.database.ContentObserver; import android.graphics.Rect; import android.os.Binder; +import android.os.Build; import android.os.Bundle; import android.os.IBinder; import android.os.Parcelable; @@ -61,6 +62,7 @@ import android.util.ArrayMap; import android.util.LocalLog; import android.util.Slog; import android.util.SparseArray; +import android.util.SparseBooleanArray; import android.view.autofill.AutofillId; import android.view.autofill.AutofillManager; import android.view.autofill.AutofillManager.SmartSuggestionMode; @@ -72,6 +74,8 @@ import android.view.autofill.IAutoFillManagerClient; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.infra.AbstractRemoteService; +import com.android.internal.infra.GlobalWhitelistState; +import com.android.internal.infra.WhitelistHelper; import com.android.internal.os.IResultReceiver; import com.android.internal.util.DumpUtils; import com.android.internal.util.Preconditions; @@ -146,6 +150,7 @@ public final class AutofillManagerService private final LocalLog mWtfHistory = new LocalLog(50); private final AutofillCompatState mAutofillCompatState = new AutofillCompatState(); + private final LocalService mLocalService = new LocalService(); private final ActivityManagerInternal mAm; @@ -178,6 +183,8 @@ public final class AutofillManagerService @GuardedBy("mLock") int mAugmentedServiceRequestTimeoutMs; + final AugmentedAutofillState mAugmentedAutofillState = new AugmentedAutofillState(); + public AutofillManagerService(Context context) { super(context, new SecureSettingsServiceNameResolver(context, Settings.Secure.AUTOFILL_SERVICE), @@ -187,7 +194,7 @@ public final class AutofillManagerService DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_AUTOFILL, ActivityThread.currentApplication().getMainExecutor(), - (namespace, key, value) -> onDeviceConfigChange(key, value)); + (namespace, key, value) -> onDeviceConfigChange(key)); setLogLevelFromSettings(); setMaxPartitionsFromSettings(); @@ -201,15 +208,20 @@ public final class AutofillManagerService mAugmentedAutofillResolver = new FrameworkResourcesServiceNameResolver(getContext(), com.android.internal.R.string.config_defaultAugmentedAutofillService); mAugmentedAutofillResolver.setOnTemporaryServiceNameChangedCallback( - (u, s) -> getServiceForUserLocked(u).updateRemoteAugmentedAutofillService()); + (u, s, t) -> onAugmentedServiceNameChanged(u, s, t)); if (mSupportedSmartSuggestionModes != AutofillManager.FLAG_SMART_SUGGESTION_OFF) { - // Must eager load the services so they bind to the augmented autofill service 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; + // Must eager load the services so they bind to the augmented autofill service getServiceForUserLocked(userId); + + // And also set the global state + mAugmentedAutofillState.setServiceInfo(userId, + mAugmentedAutofillResolver.getServiceName(userId), + mAugmentedAutofillResolver.isTemporary(userId)); } } } @@ -258,7 +270,7 @@ public final class AutofillManagerService } } - private void onDeviceConfigChange(@NonNull String key, @Nullable String value) { + private void onDeviceConfigChange(@NonNull String key) { switch (key) { case AutofillManager.DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES: case AutofillManager.DEVICE_CONFIG_AUGMENTED_SERVICE_IDLE_UNBIND_TIMEOUT: @@ -270,6 +282,14 @@ public final class AutofillManagerService } } + private void onAugmentedServiceNameChanged(@UserIdInt int userId, @Nullable String serviceName, + boolean isTemporary) { + mAugmentedAutofillState.setServiceInfo(userId, serviceName, isTemporary); + synchronized (mLock) { + getServiceForUserLocked(userId).updateRemoteAugmentedAutofillService(); + } + } + @Override // from AbstractMasterSystemService protected AutofillManagerServiceImpl newServiceLocked(@UserIdInt int resolvedUserId, boolean disabled) { @@ -783,15 +803,7 @@ public final class AutofillManagerService final boolean compatModeEnabled = mAutofillCompatState.isCompatibilityModeRequested( packageName, versionCode, userId); final AutofillOptions options = new AutofillOptions(loggingLevel, compatModeEnabled); - - synchronized (mLock) { - final AutofillManagerServiceImpl service = - getServiceForUserLocked(UserHandle.getCallingUserId()); - if (service != null) { - service.setAugmentedAutofillWhitelistLocked(options, packageName); - } - } - + mAugmentedAutofillState.injectAugmentedAutofillInfo(options, userId, packageName); return options; } } @@ -934,6 +946,89 @@ public final class AutofillManagerService } } + /** + * Augmented autofill metadata associated with all services. + * + * <p>This object is defined here instead of on each {@link AutofillManagerServiceImpl} because + * it cannot hold a lock on the main lock when + * {@link AugmentedAutofillState#injectAugmentedAutofillInfo(AutofillOptions, int, String)} + * is called by external services. + */ + static final class AugmentedAutofillState 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(TAG, "setServiceInfo(): invalid name: " + serviceName); + mServicePackages.remove(userId); + } else { + mServicePackages.put(userId, componentName.getPackageName()); + } + } else { + mServicePackages.remove(userId); + } + } + } + + public void injectAugmentedAutofillInfo(@NonNull AutofillOptions options, + @UserIdInt int userId, @NonNull String packageName) { + synchronized (mGlobalWhitelistStateLock) { + if (mWhitelisterHelpers == null) return; + final WhitelistHelper helper = mWhitelisterHelpers.get(userId); + if (helper != null) { + options.augmentedAutofillEnabled = helper.isWhitelisted(packageName); + options.whitelistedActivitiesForAugmentedAutofill = helper + .getWhitelistedComponents(packageName); + } + } + } + + @Override + public boolean isWhitelisted(@UserIdInt int userId, @NonNull ComponentName componentName) { + synchronized (mGlobalWhitelistStateLock) { + if (!super.isWhitelisted(userId, componentName)) return false; + + if (Build.IS_USER && mTemporaryServices.get(userId)) { + final String packageName = componentName.getPackageName(); + if (!packageName.equals(mServicePackages.get(userId))) { + Slog.w(TAG, "Ignoring package " + packageName + " for augmented autofill " + + "while using temporary service " + mServicePackages.get(userId)); + return false; + } + } + } + return true; + } + + @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); + } + } + } + } + final class AutoFillManagerServiceStub extends IAutoFillManager.Stub { @Override public void addClient(IAutoFillManagerClient client, ComponentName componentName, @@ -1370,6 +1465,8 @@ public final class AutofillManagerService pw.println(); pw.println("WTF history:"); pw.println(); mWtfHistory.reverseDump(fd, pw, args); } + pw.println("Augmented Autofill State: "); + mAugmentedAutofillState.dump(prefix, pw); } } finally { sDebug = realDebug; diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java index fe540bf3a8cf..4bd6fbd39de4 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java @@ -31,7 +31,6 @@ import android.annotation.Nullable; import android.app.ActivityManagerInternal; import android.app.ActivityTaskManager; import android.app.IActivityTaskManager; -import android.content.AutofillOptions; import android.content.ComponentName; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; @@ -40,7 +39,6 @@ import android.graphics.Rect; import android.metrics.LogMaker; import android.os.AsyncTask; import android.os.Binder; -import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; @@ -76,7 +74,6 @@ import android.view.autofill.IAutoFillManagerClient; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; -import com.android.internal.infra.WhitelistHelper; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.server.LocalServices; @@ -170,12 +167,6 @@ final class AutofillManagerServiceImpl @Nullable private ServiceInfo mRemoteAugmentedAutofillServiceInfo; - /** - * List of packages/activities that are whitelisted to be trigger augmented autofill. - */ - @GuardedBy("mLock") - private final WhitelistHelper mAugmentedWhitelistHelper = new WhitelistHelper(); - AutofillManagerServiceImpl(AutofillManagerService master, Object lock, LocalLog uiLatencyHistory, LocalLog wtfHistory, int userId, AutoFillUI ui, AutofillCompatState autofillCompatState, @@ -951,8 +942,6 @@ final class AutofillManagerServiceImpl pw.println(mRemoteAugmentedAutofillServiceInfo); } - mAugmentedWhitelistHelper.dump(prefix, "Augmented autofill whitelist", pw); - pw.print(prefix); pw.print("Field classification enabled: "); pw.println(isFieldClassificationEnabledLocked()); pw.print(prefix); pw.print("Compat pkgs: "); @@ -1234,27 +1223,7 @@ final class AutofillManagerServiceImpl @GuardedBy("mLock") boolean isWhitelistedForAugmentedAutofillLocked(@NonNull ComponentName componentName) { - if (Build.IS_USER && mMaster.mAugmentedAutofillResolver.isTemporary(mUserId)) { - final String serviceName = mMaster.mAugmentedAutofillResolver.getServiceName(mUserId); - final ComponentName component = ComponentName.unflattenFromString(serviceName); - final String servicePackage = component == null ? null : component.getPackageName(); - final String packageName = componentName.getPackageName(); - if (!packageName.equals(servicePackage)) { - Slog.w(TAG, "Ignoring package " + packageName + " for augmented autofill while " - + "using temporary service " + servicePackage); - return false; - } - } - - return mAugmentedWhitelistHelper.isWhitelisted(componentName); - } - - @GuardedBy("mLock") - void setAugmentedAutofillWhitelistLocked(@NonNull AutofillOptions options, - @NonNull String packageName) { - options.augmentedAutofillEnabled = mAugmentedWhitelistHelper.isWhitelisted(packageName); - options.whitelistedActivitiesForAugmentedAutofill = mAugmentedWhitelistHelper - .getWhitelistedComponents(packageName); + return mMaster.mAugmentedAutofillState.isWhitelisted(mUserId, componentName); } /** @@ -1268,7 +1237,7 @@ final class AutofillManagerServiceImpl if (mMaster.verbose) { Slog.v(TAG, "whitelisting packages: " + packages + "and activities: " + components); } - mAugmentedWhitelistHelper.setWhitelist(packages, components); + mMaster.mAugmentedAutofillState.setWhitelist(mUserId, packages, components); } } @@ -1280,7 +1249,7 @@ final class AutofillManagerServiceImpl if (mMaster.verbose) { Slog.v(TAG, "resetting augmented autofill whitelist"); } - whitelistForAugmentedAutofillPackages(null, null); + mMaster.mAugmentedAutofillState.resetWhitelist(mUserId); } private void sendStateToClients(boolean resetClient) { 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 diff --git a/services/core/java/com/android/server/contentcapture/ContentCaptureManagerInternal.java b/services/core/java/com/android/server/contentcapture/ContentCaptureManagerInternal.java index fa7d3fca75b5..ad04b7d10433 100644 --- a/services/core/java/com/android/server/contentcapture/ContentCaptureManagerInternal.java +++ b/services/core/java/com/android/server/contentcapture/ContentCaptureManagerInternal.java @@ -49,6 +49,9 @@ public abstract class ContentCaptureManagerInternal { /** * Gets the content capture options for the given user and package, or {@code null} if the * package is not whitelisted by the service. + * + * <p><b>NOTE: </b>this method is called by the {@code ActivityManager} service and hence cannot + * hold the main service lock. */ @Nullable public abstract ContentCaptureOptions getOptionsForPackage(@UserIdInt int userId, diff --git a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java index ed894ee0bee8..39e93f5e44fe 100644 --- a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java +++ b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java @@ -181,9 +181,8 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem mServiceNameResolver = serviceNameResolver; if (mServiceNameResolver != null) { - mServiceNameResolver - .setOnTemporaryServiceNameChangedCallback( - (u, s) -> updateCachedServiceLocked(u)); + mServiceNameResolver.setOnTemporaryServiceNameChangedCallback( + (u, s, t) -> onServiceNameChanged(u, s, t)); } if (disallowProperty == null) { @@ -582,6 +581,23 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem } /** + * Called when the service name changed (typically when using temporary services). + * + * <p>By default, it calls {@link #updateCachedServiceLocked(int)}; subclasses must either call + * that same method, or {@code super.onServiceNameChanged()}. + * + * @param userId user handle. + * @param serviceName the new service name. + * @param isTemporary whether the new service is temporary. + */ + protected void onServiceNameChanged(@UserIdInt int userId, @Nullable String serviceName, + boolean isTemporary) { + synchronized (mLock) { + updateCachedServiceLocked(userId); + } + } + + /** * Visits all services in the cache. */ @GuardedBy("mLock") diff --git a/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java b/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java index d20481331e56..35d59561fdeb 100644 --- a/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java +++ b/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java @@ -155,7 +155,8 @@ public final class FrameworkResourcesServiceNameResolver implements ServiceNameR } mTemporaryServiceExpiration = SystemClock.elapsedRealtime() + durationMs; mTemporaryHandler.sendEmptyMessageDelayed(MSG_RESET_TEMPORARY_SERVICE, durationMs); - notifyTemporaryServiceNameChangedLocked(userId, componentName); + notifyTemporaryServiceNameChangedLocked(userId, componentName, + /* isTemporary= */ true); } } @@ -169,7 +170,8 @@ public final class FrameworkResourcesServiceNameResolver implements ServiceNameR mTemporaryHandler.removeMessages(MSG_RESET_TEMPORARY_SERVICE); mTemporaryHandler = null; } - notifyTemporaryServiceNameChangedLocked(userId, /* newTemporaryName= */ null); + notifyTemporaryServiceNameChangedLocked(userId, /* newTemporaryName= */ null, + /* isTemporary= */ false); } } @@ -235,9 +237,9 @@ public final class FrameworkResourcesServiceNameResolver implements ServiceNameR } private void notifyTemporaryServiceNameChangedLocked(@UserIdInt int userId, - @Nullable String newTemporaryName) { + @Nullable String newTemporaryName, boolean isTemporary) { if (mOnSetCallback != null) { - mOnSetCallback.onNameResolved(userId, newTemporaryName); + mOnSetCallback.onNameResolved(userId, newTemporaryName, isTemporary); } } } diff --git a/services/core/java/com/android/server/infra/ServiceNameResolver.java b/services/core/java/com/android/server/infra/ServiceNameResolver.java index 8c348ebbfcd4..e20c45992e05 100644 --- a/services/core/java/com/android/server/infra/ServiceNameResolver.java +++ b/services/core/java/com/android/server/infra/ServiceNameResolver.java @@ -39,7 +39,8 @@ public interface ServiceNameResolver { /** * The name change callback. */ - void onNameResolved(@UserIdInt int userId, @Nullable String serviceName); + void onNameResolved(@UserIdInt int userId, @Nullable String serviceName, + boolean isTemporary); } /** |