Loading services/core/java/com/android/server/infra/AbstractMasterSystemService.java +49 −1 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.pm.UserInfo; import android.credentials.flags.Flags; import android.database.ContentObserver; import android.net.Uri; import android.os.Binder; Loading Loading @@ -1173,8 +1174,19 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem final String[] serviceNames = mServiceNameResolver.getDefaultServiceNameList( userId); if (serviceNames != null) { if (Flags.packageUpdateFixEnabled()) { if (mServiceNameResolver.isConfiguredInMultipleMode()) { // Remove any service that is in the cache but is no longer valid // after this modification for this particular package removeInvalidCachedServicesLocked(serviceNames, packageName, userId); } } // Update services that are still valid for (int i = 0; i < serviceNames.length; i++) { peekAndUpdateCachedServiceLocked(packageName, userId, serviceNames[i]); peekAndUpdateCachedServiceLocked(packageName, userId, serviceNames[i]); } } } Loading Loading @@ -1230,6 +1242,36 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem monitor.register(getContext(), null, UserHandle.ALL, true); } @GuardedBy("mLock") @SuppressWarnings("GuardedBy") // ErrorProne requires this.mLock for // handleServiceRemovedMultiModeLocked which is the same private void removeInvalidCachedServicesLocked(String[] validServices, String packageName, int userId) { visitServicesLocked((s) -> { ComponentName serviceComponentName = s .getServiceComponentName(); if (serviceComponentName != null && serviceComponentName .getPackageName().equals(packageName)) { if (!serviceInValidServiceList(serviceComponentName, validServices)) { handleServiceRemovedMultiModeLocked( serviceComponentName, userId); } } }); } private boolean serviceInValidServiceList(ComponentName serviceComponentName, String[] serviceNames) { for (String service: serviceNames) { ComponentName componentName = ComponentName.unflattenFromString(service); if (componentName != null && componentName.equals(serviceComponentName)) { return true; } } return false; } @GuardedBy("mLock") @SuppressWarnings("unused") protected void onServicePackageDataClearedMultiModeLocked(String packageName, int userId) { Loading @@ -1245,6 +1287,12 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem if (verbose) Slog.v(mTag, "handlePackageRemovedMultiModeLocked(" + userId + ")"); } @GuardedBy("mLock") protected void handleServiceRemovedMultiModeLocked(ComponentName serviceComponentName, int userId) { if (verbose) Slog.v(mTag, "handleServiceRemovedMultiModeLocked(" + userId + ")"); } @GuardedBy("mLock") protected void removeServiceFromCache(@NonNull S service, int userId) { if (mServicesCacheList.get(userId) != null) { Loading services/core/java/com/android/server/infra/AbstractPerUserSystemService.java +1 −1 Original line number Diff line number Diff line Loading @@ -323,7 +323,7 @@ public abstract class AbstractPerUserSystemService<S extends AbstractPerUserSyst * if the service is disabled. */ @Nullable public final ComponentName getServiceComponentName() { public ComponentName getServiceComponentName() { synchronized (mLock) { return mServiceInfo == null ? null : mServiceInfo.getComponentName(); } Loading services/credentials/java/com/android/server/credentials/CredentialManagerService.java +212 −37 Original line number Diff line number Diff line Loading @@ -204,7 +204,7 @@ public final class CredentialManagerService @SuppressWarnings("GuardedBy") // ErrorProne requires service.mLock which is the same // this.mLock protected void handlePackageRemovedMultiModeLocked(String packageName, int userId) { updateProvidersWhenPackageRemoved(new SettingsWrapper(mContext), packageName); updateProvidersWhenPackageRemoved(new SettingsWrapper(mContext), packageName, userId); List<CredentialManagerServiceImpl> services = peekServiceListForUserLocked(userId); if (services == null) { Loading Loading @@ -233,6 +233,47 @@ public final class CredentialManagerService } } @GuardedBy("mLock") @SuppressWarnings("GuardedBy") // ErrorProne requires service.mLock which is the same // this.mLock protected void handleServiceRemovedMultiModeLocked(ComponentName componentName, int userId) { updateProvidersWhenServiceRemoved(new SettingsWrapper(mContext), componentName, userId); List<CredentialManagerServiceImpl> services = peekServiceListForUserLocked(userId); if (services == null) { return; } List<CredentialManagerServiceImpl> servicesToBeRemoved = new ArrayList<>(); for (CredentialManagerServiceImpl service : services) { if (service != null) { CredentialProviderInfo credentialProviderInfo = service.getCredentialProviderInfo(); ComponentName serviceComponentName = credentialProviderInfo.getServiceInfo().getComponentName(); if (serviceComponentName != null && serviceComponentName.equals(componentName)) { servicesToBeRemoved.add(service); } } } removeServicesLocked(servicesToBeRemoved, userId); } @GuardedBy("mLock") @SuppressWarnings("GuardedBy") // ErrorProne requires service.mLock which is the same // this.mLock private void removeServicesLocked( List<CredentialManagerServiceImpl> servicesToBeRemoved, int userId) { // Iterate over all the services to be removed, and remove them from the user configurable // services cache, the system services cache as well as the setting key-value pair. for (CredentialManagerServiceImpl serviceToBeRemoved : servicesToBeRemoved) { removeServiceFromCache(serviceToBeRemoved, userId); removeServiceFromSystemServicesCache(serviceToBeRemoved, userId); CredentialDescriptionRegistry.forUser(userId) .evictProviderWithPackageName(serviceToBeRemoved.getServicePackageName()); } } @GuardedBy("mLock") private void removeServiceFromSystemServicesCache( CredentialManagerServiceImpl serviceToBeRemoved, int userId) { Loading Loading @@ -1136,27 +1177,123 @@ public final class CredentialManagerService } } /** Updates the list of providers when a particular service within an app is to be removed. */ public static void updateProvidersWhenServiceRemoved( SettingsWrapper settingsWrapper, ComponentName componentName, int userId) { Slog.i(TAG, "updateProvidersWhenServiceRemoved for: " + componentName.flattenToString()); // Get the current primary providers. String rawPrimaryProviders = settingsWrapper.getStringForUser( Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, userId); if (TextUtils.isEmpty(rawPrimaryProviders)) { Slog.w(TAG, "primary settings key is null"); } else { // Remove any service from the primary setting that matches with the service // being removed, and set the filtered list back to the settings key. Set<String> filteredPrimaryProviders = getStoredProvidersExceptService( rawPrimaryProviders, componentName); // If there are no more primary providers AND there is no autofill provider either, // that means all providers must be cleared as that is what the Settings UI app // displays to the user.If the autofill provider is present then UI shows that as the // preferred service and other credential provider services can continue to work. if (filteredPrimaryProviders.isEmpty() && !isAutofillProviderPresent(settingsWrapper, userId)) { Slog.d(TAG, "Clearing all credential providers"); if (clearAllCredentialProviders(settingsWrapper, userId)) { return; } Slog.e(TAG, "Failed to clear all credential providers"); } // Set the filtered primary providers to the settings key if (!settingsWrapper.putStringForUser( Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, String.join(":", filteredPrimaryProviders), UserHandle.myUserId(), /* overrideableByRestore= */ true)) { Slog.e(TAG, "Failed to remove primary service: " + componentName); return; } } // Read the credential providers to remove any reference of the removed service. String rawCredentialProviders = settingsWrapper.getStringForUser( Settings.Secure.CREDENTIAL_SERVICE, UserHandle.myUserId()); // Remove any provider services that are same as the one being removed. Set<String> filteredCredentialProviders = getStoredProvidersExceptService( rawCredentialProviders, componentName); if (!settingsWrapper.putStringForUser( Settings.Secure.CREDENTIAL_SERVICE, String.join(":", filteredCredentialProviders), UserHandle.myUserId(), /* overrideableByRestore= */ true)) { Slog.e(TAG, "Failed to remove secondary service: " + componentName); } } private static boolean isAutofillProviderPresent(SettingsWrapper settingsWrapper, int userId) { // Read the autofill provider so we don't accidentally erase it. String autofillProvider = settingsWrapper.getStringForUser( Settings.Secure.AUTOFILL_SERVICE, userId); return autofillProvider != null && !autofillProvider.isEmpty() && !isPlaceholderAutofillProvider(autofillProvider, settingsWrapper); } private static boolean isPlaceholderAutofillProvider(String autofillProvider, SettingsWrapper settingsWrapper) { // If there is an autofill provider and it is the credential autofill service indicating // that the currently selected primary provider does not support autofill // then we should keep as is String credentialAutofillService = settingsWrapper.mContext.getResources().getString( R.string.config_defaultCredentialManagerAutofillService); return autofillProvider != null && TextUtils.equals( autofillProvider, credentialAutofillService); } private static boolean clearAllCredentialProviders(SettingsWrapper settingsWrapper, int userId) { if (!settingsWrapper.putStringForUser( Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, null, userId, /* overrideableByRestore= */ true)) { return false; } return settingsWrapper.putStringForUser( Settings.Secure.CREDENTIAL_SERVICE, null, userId, /* overrideableByRestore= */ true); } /** Updates the list of providers when an app is uninstalled. */ public static void updateProvidersWhenPackageRemoved( SettingsWrapper settingsWrapper, String packageName) { SettingsWrapper settingsWrapper, String packageName, int userId) { Slog.i(TAG, "updateProvidersWhenPackageRemoved"); // Get the current providers. String rawProviders = settingsWrapper.getStringForUser( Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, UserHandle.myUserId()); Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, userId); if (rawProviders == null) { Slog.w(TAG, "settings key is null"); return; } } else { // Remove any providers from the primary setting that contain the package name // being removed. Set<String> primaryProviders = getStoredProviders(rawProviders, packageName); Set<String> primaryProviders = getStoredProvidersExceptPackage(rawProviders, packageName); if (!settingsWrapper.putStringForUser( Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, String.join(":", primaryProviders), UserHandle.myUserId(), userId, /* overrideableByRestore= */ true)) { Slog.e(TAG, "Failed to remove primary package: " + packageName); return; Loading @@ -1165,7 +1302,7 @@ public final class CredentialManagerService // Read the autofill provider so we don't accidentally erase it. String autofillProvider = settingsWrapper.getStringForUser( Settings.Secure.AUTOFILL_SERVICE, UserHandle.myUserId()); Settings.Secure.AUTOFILL_SERVICE, userId); // If there is an autofill provider and it is the credential autofill service indicating // that the currently selected primary provider does not support autofill Loading @@ -1181,31 +1318,70 @@ public final class CredentialManagerService if (!settingsWrapper.putStringForUser( Settings.Secure.AUTOFILL_SERVICE, "", UserHandle.myUserId(), userId, /* overrideableByRestore= */ true)) { Slog.e(TAG, "Failed to remove autofill package: " + packageName); } } } // If there are no more primary providers AND there is no autofill provider either, // that means all providers must be cleared as that is what the Settings UI app // displays to the user.If the autofill provider is present then UI shows that as the // preferred service and other credential provider services can continue to work. if (primaryProviders.isEmpty() && !isAutofillProviderPresent(settingsWrapper, userId)) { Slog.d(TAG, "Clearing all credential providers"); if (clearAllCredentialProviders(settingsWrapper, userId)) { return; } Slog.e(TAG, "Failed to clear all credential providers"); } } // Read the credential providers to remove any reference of the removed app. String rawCredentialProviders = settingsWrapper.getStringForUser( Settings.Secure.CREDENTIAL_SERVICE, UserHandle.myUserId()); Settings.Secure.CREDENTIAL_SERVICE, userId); // Remove any providers that belong to the removed app. Set<String> credentialProviders = getStoredProviders(rawCredentialProviders, packageName); Set<String> credentialProviders = getStoredProvidersExceptPackage( rawCredentialProviders, packageName); if (!settingsWrapper.putStringForUser( Settings.Secure.CREDENTIAL_SERVICE, String.join(":", credentialProviders), UserHandle.myUserId(), userId, /* overrideableByRestore= */ true)) { Slog.e(TAG, "Failed to remove secondary package: " + packageName); } } /** Gets the list of stored providers from a string removing any mention of package name. */ public static Set<String> getStoredProviders(String rawProviders, String packageName) { public static Set<String> getStoredProvidersExceptService(String rawProviders, ComponentName componentName) { // If the app being removed matches any of the package names from // this list then don't add it in the output. Set<String> providers = new HashSet<>(); if (rawProviders == null || componentName == null) { return providers; } for (String rawComponentName : rawProviders.split(":")) { if (TextUtils.isEmpty(rawComponentName) || rawComponentName.equals("null")) { Slog.d(TAG, "provider component name is empty or null"); continue; } ComponentName cn = ComponentName.unflattenFromString(rawComponentName); if (cn != null && !cn.equals(componentName)) { providers.add(cn.flattenToString()); } } return providers; } /** Gets the list of stored providers from a string removing any mention of package name. */ public static Set<String> getStoredProvidersExceptPackage( String rawProviders, String packageName) { // If the app being removed matches any of the package names from // this list then don't add it in the output. Set<String> providers = new HashSet<>(); Loading @@ -1213,8 +1389,7 @@ public final class CredentialManagerService return providers; } for (String rawComponentName : rawProviders.split(":")) { if (TextUtils.isEmpty(rawComponentName) || rawComponentName.equals("null")) { if (TextUtils.isEmpty(rawComponentName) || rawComponentName.equals("null")) { Slog.d(TAG, "provider component name is empty or null"); continue; } Loading services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java +7 −0 Original line number Diff line number Diff line Loading @@ -57,6 +57,13 @@ public final class CredentialManagerServiceImpl extends } } @Nullable @Override @GuardedBy("mLock") public ComponentName getServiceComponentName() { return getComponentName(); } @GuardedBy("mLock") public ComponentName getComponentName() { return mInfo.getServiceInfo().getComponentName(); Loading services/tests/servicestests/src/com/android/server/credentials/CredentialManagerServiceTest.java +13 −7 Original line number Diff line number Diff line Loading @@ -51,20 +51,22 @@ public final class CredentialManagerServiceTest { @Test public void getStoredProviders_emptyValue_success() { Set<String> providers = CredentialManagerService.getStoredProviders("", ""); Set<String> providers = CredentialManagerService.getStoredProvidersExceptPackage( "", ""); assertThat(providers.size()).isEqualTo(0); } @Test public void getStoredProviders_nullValue_success() { Set<String> providers = CredentialManagerService.getStoredProviders(null, null); Set<String> providers = CredentialManagerService.getStoredProvidersExceptPackage( null, null); assertThat(providers.size()).isEqualTo(0); } @Test public void getStoredProviders_success() { Set<String> providers = CredentialManagerService.getStoredProviders( CredentialManagerService.getStoredProvidersExceptPackage( "com.example.test/.TestActivity:com.example.test/.TestActivity2:" + "com.example.test2/.TestActivity:blank", "com.example.test"); Loading @@ -74,6 +76,7 @@ public final class CredentialManagerServiceTest { @Test public void onProviderRemoved_success() { int userId = UserHandle.myUserId(); setSettingsKey( Settings.Secure.AUTOFILL_SERVICE, CredentialManagerService.AUTOFILL_PLACEHOLDER_VALUE); Loading @@ -85,7 +88,7 @@ public final class CredentialManagerServiceTest { "com.example.test/com.example.test.TestActivity"); CredentialManagerService.updateProvidersWhenPackageRemoved( mSettingsWrapper, "com.example.test"); mSettingsWrapper, "com.example.test", userId); assertThat(getSettingsKey(Settings.Secure.AUTOFILL_SERVICE)).isEqualTo(""); assertThat(getSettingsKey(Settings.Secure.CREDENTIAL_SERVICE)) Loading @@ -95,6 +98,7 @@ public final class CredentialManagerServiceTest { @Test public void onProviderRemoved_notPrimaryRemoved_success() { int userId = UserHandle.myUserId(); final String testCredentialPrimaryValue = "com.example.test/com.example.test.TestActivity"; final String testCredentialValue = "com.example.test/com.example.test.TestActivity:com.example.test2/com.example.test2.TestActivity"; Loading @@ -106,7 +110,7 @@ public final class CredentialManagerServiceTest { setSettingsKey(Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, testCredentialPrimaryValue); CredentialManagerService.updateProvidersWhenPackageRemoved( mSettingsWrapper, "com.example.test3"); mSettingsWrapper, "com.example.test3", userId); // Since the provider removed was not a primary provider then we should do nothing. assertThat(getSettingsKey(Settings.Secure.AUTOFILL_SERVICE)) Loading @@ -120,6 +124,7 @@ public final class CredentialManagerServiceTest { @Test public void onProviderRemoved_isAlsoAutofillProvider_success() { int userId = UserHandle.myUserId(); setSettingsKey( Settings.Secure.AUTOFILL_SERVICE, "com.example.test/com.example.test.AutofillProvider"); Loading @@ -131,7 +136,7 @@ public final class CredentialManagerServiceTest { "com.example.test/com.example.test.TestActivity"); CredentialManagerService.updateProvidersWhenPackageRemoved( mSettingsWrapper, "com.example.test"); mSettingsWrapper, "com.example.test", userId); assertThat(getSettingsKey(Settings.Secure.AUTOFILL_SERVICE)).isEqualTo(""); assertThat(getSettingsKey(Settings.Secure.CREDENTIAL_SERVICE)) Loading @@ -141,6 +146,7 @@ public final class CredentialManagerServiceTest { @Test public void onProviderRemoved_notPrimaryRemoved_isAlsoAutofillProvider_success() { int userId = UserHandle.myUserId(); final String testCredentialPrimaryValue = "com.example.test/com.example.test.TestActivity"; final String testCredentialValue = "com.example.test/com.example.test.TestActivity:com.example.test2/com.example.test2.TestActivity"; Loading @@ -151,7 +157,7 @@ public final class CredentialManagerServiceTest { setSettingsKey(Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, testCredentialPrimaryValue); CredentialManagerService.updateProvidersWhenPackageRemoved( mSettingsWrapper, "com.example.test3"); mSettingsWrapper, "com.example.test3", userId); // Since the provider removed was not a primary provider then we should do nothing. assertCredentialPropertyEquals( Loading Loading
services/core/java/com/android/server/infra/AbstractMasterSystemService.java +49 −1 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.pm.UserInfo; import android.credentials.flags.Flags; import android.database.ContentObserver; import android.net.Uri; import android.os.Binder; Loading Loading @@ -1173,8 +1174,19 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem final String[] serviceNames = mServiceNameResolver.getDefaultServiceNameList( userId); if (serviceNames != null) { if (Flags.packageUpdateFixEnabled()) { if (mServiceNameResolver.isConfiguredInMultipleMode()) { // Remove any service that is in the cache but is no longer valid // after this modification for this particular package removeInvalidCachedServicesLocked(serviceNames, packageName, userId); } } // Update services that are still valid for (int i = 0; i < serviceNames.length; i++) { peekAndUpdateCachedServiceLocked(packageName, userId, serviceNames[i]); peekAndUpdateCachedServiceLocked(packageName, userId, serviceNames[i]); } } } Loading Loading @@ -1230,6 +1242,36 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem monitor.register(getContext(), null, UserHandle.ALL, true); } @GuardedBy("mLock") @SuppressWarnings("GuardedBy") // ErrorProne requires this.mLock for // handleServiceRemovedMultiModeLocked which is the same private void removeInvalidCachedServicesLocked(String[] validServices, String packageName, int userId) { visitServicesLocked((s) -> { ComponentName serviceComponentName = s .getServiceComponentName(); if (serviceComponentName != null && serviceComponentName .getPackageName().equals(packageName)) { if (!serviceInValidServiceList(serviceComponentName, validServices)) { handleServiceRemovedMultiModeLocked( serviceComponentName, userId); } } }); } private boolean serviceInValidServiceList(ComponentName serviceComponentName, String[] serviceNames) { for (String service: serviceNames) { ComponentName componentName = ComponentName.unflattenFromString(service); if (componentName != null && componentName.equals(serviceComponentName)) { return true; } } return false; } @GuardedBy("mLock") @SuppressWarnings("unused") protected void onServicePackageDataClearedMultiModeLocked(String packageName, int userId) { Loading @@ -1245,6 +1287,12 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem if (verbose) Slog.v(mTag, "handlePackageRemovedMultiModeLocked(" + userId + ")"); } @GuardedBy("mLock") protected void handleServiceRemovedMultiModeLocked(ComponentName serviceComponentName, int userId) { if (verbose) Slog.v(mTag, "handleServiceRemovedMultiModeLocked(" + userId + ")"); } @GuardedBy("mLock") protected void removeServiceFromCache(@NonNull S service, int userId) { if (mServicesCacheList.get(userId) != null) { Loading
services/core/java/com/android/server/infra/AbstractPerUserSystemService.java +1 −1 Original line number Diff line number Diff line Loading @@ -323,7 +323,7 @@ public abstract class AbstractPerUserSystemService<S extends AbstractPerUserSyst * if the service is disabled. */ @Nullable public final ComponentName getServiceComponentName() { public ComponentName getServiceComponentName() { synchronized (mLock) { return mServiceInfo == null ? null : mServiceInfo.getComponentName(); } Loading
services/credentials/java/com/android/server/credentials/CredentialManagerService.java +212 −37 Original line number Diff line number Diff line Loading @@ -204,7 +204,7 @@ public final class CredentialManagerService @SuppressWarnings("GuardedBy") // ErrorProne requires service.mLock which is the same // this.mLock protected void handlePackageRemovedMultiModeLocked(String packageName, int userId) { updateProvidersWhenPackageRemoved(new SettingsWrapper(mContext), packageName); updateProvidersWhenPackageRemoved(new SettingsWrapper(mContext), packageName, userId); List<CredentialManagerServiceImpl> services = peekServiceListForUserLocked(userId); if (services == null) { Loading Loading @@ -233,6 +233,47 @@ public final class CredentialManagerService } } @GuardedBy("mLock") @SuppressWarnings("GuardedBy") // ErrorProne requires service.mLock which is the same // this.mLock protected void handleServiceRemovedMultiModeLocked(ComponentName componentName, int userId) { updateProvidersWhenServiceRemoved(new SettingsWrapper(mContext), componentName, userId); List<CredentialManagerServiceImpl> services = peekServiceListForUserLocked(userId); if (services == null) { return; } List<CredentialManagerServiceImpl> servicesToBeRemoved = new ArrayList<>(); for (CredentialManagerServiceImpl service : services) { if (service != null) { CredentialProviderInfo credentialProviderInfo = service.getCredentialProviderInfo(); ComponentName serviceComponentName = credentialProviderInfo.getServiceInfo().getComponentName(); if (serviceComponentName != null && serviceComponentName.equals(componentName)) { servicesToBeRemoved.add(service); } } } removeServicesLocked(servicesToBeRemoved, userId); } @GuardedBy("mLock") @SuppressWarnings("GuardedBy") // ErrorProne requires service.mLock which is the same // this.mLock private void removeServicesLocked( List<CredentialManagerServiceImpl> servicesToBeRemoved, int userId) { // Iterate over all the services to be removed, and remove them from the user configurable // services cache, the system services cache as well as the setting key-value pair. for (CredentialManagerServiceImpl serviceToBeRemoved : servicesToBeRemoved) { removeServiceFromCache(serviceToBeRemoved, userId); removeServiceFromSystemServicesCache(serviceToBeRemoved, userId); CredentialDescriptionRegistry.forUser(userId) .evictProviderWithPackageName(serviceToBeRemoved.getServicePackageName()); } } @GuardedBy("mLock") private void removeServiceFromSystemServicesCache( CredentialManagerServiceImpl serviceToBeRemoved, int userId) { Loading Loading @@ -1136,27 +1177,123 @@ public final class CredentialManagerService } } /** Updates the list of providers when a particular service within an app is to be removed. */ public static void updateProvidersWhenServiceRemoved( SettingsWrapper settingsWrapper, ComponentName componentName, int userId) { Slog.i(TAG, "updateProvidersWhenServiceRemoved for: " + componentName.flattenToString()); // Get the current primary providers. String rawPrimaryProviders = settingsWrapper.getStringForUser( Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, userId); if (TextUtils.isEmpty(rawPrimaryProviders)) { Slog.w(TAG, "primary settings key is null"); } else { // Remove any service from the primary setting that matches with the service // being removed, and set the filtered list back to the settings key. Set<String> filteredPrimaryProviders = getStoredProvidersExceptService( rawPrimaryProviders, componentName); // If there are no more primary providers AND there is no autofill provider either, // that means all providers must be cleared as that is what the Settings UI app // displays to the user.If the autofill provider is present then UI shows that as the // preferred service and other credential provider services can continue to work. if (filteredPrimaryProviders.isEmpty() && !isAutofillProviderPresent(settingsWrapper, userId)) { Slog.d(TAG, "Clearing all credential providers"); if (clearAllCredentialProviders(settingsWrapper, userId)) { return; } Slog.e(TAG, "Failed to clear all credential providers"); } // Set the filtered primary providers to the settings key if (!settingsWrapper.putStringForUser( Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, String.join(":", filteredPrimaryProviders), UserHandle.myUserId(), /* overrideableByRestore= */ true)) { Slog.e(TAG, "Failed to remove primary service: " + componentName); return; } } // Read the credential providers to remove any reference of the removed service. String rawCredentialProviders = settingsWrapper.getStringForUser( Settings.Secure.CREDENTIAL_SERVICE, UserHandle.myUserId()); // Remove any provider services that are same as the one being removed. Set<String> filteredCredentialProviders = getStoredProvidersExceptService( rawCredentialProviders, componentName); if (!settingsWrapper.putStringForUser( Settings.Secure.CREDENTIAL_SERVICE, String.join(":", filteredCredentialProviders), UserHandle.myUserId(), /* overrideableByRestore= */ true)) { Slog.e(TAG, "Failed to remove secondary service: " + componentName); } } private static boolean isAutofillProviderPresent(SettingsWrapper settingsWrapper, int userId) { // Read the autofill provider so we don't accidentally erase it. String autofillProvider = settingsWrapper.getStringForUser( Settings.Secure.AUTOFILL_SERVICE, userId); return autofillProvider != null && !autofillProvider.isEmpty() && !isPlaceholderAutofillProvider(autofillProvider, settingsWrapper); } private static boolean isPlaceholderAutofillProvider(String autofillProvider, SettingsWrapper settingsWrapper) { // If there is an autofill provider and it is the credential autofill service indicating // that the currently selected primary provider does not support autofill // then we should keep as is String credentialAutofillService = settingsWrapper.mContext.getResources().getString( R.string.config_defaultCredentialManagerAutofillService); return autofillProvider != null && TextUtils.equals( autofillProvider, credentialAutofillService); } private static boolean clearAllCredentialProviders(SettingsWrapper settingsWrapper, int userId) { if (!settingsWrapper.putStringForUser( Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, null, userId, /* overrideableByRestore= */ true)) { return false; } return settingsWrapper.putStringForUser( Settings.Secure.CREDENTIAL_SERVICE, null, userId, /* overrideableByRestore= */ true); } /** Updates the list of providers when an app is uninstalled. */ public static void updateProvidersWhenPackageRemoved( SettingsWrapper settingsWrapper, String packageName) { SettingsWrapper settingsWrapper, String packageName, int userId) { Slog.i(TAG, "updateProvidersWhenPackageRemoved"); // Get the current providers. String rawProviders = settingsWrapper.getStringForUser( Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, UserHandle.myUserId()); Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, userId); if (rawProviders == null) { Slog.w(TAG, "settings key is null"); return; } } else { // Remove any providers from the primary setting that contain the package name // being removed. Set<String> primaryProviders = getStoredProviders(rawProviders, packageName); Set<String> primaryProviders = getStoredProvidersExceptPackage(rawProviders, packageName); if (!settingsWrapper.putStringForUser( Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, String.join(":", primaryProviders), UserHandle.myUserId(), userId, /* overrideableByRestore= */ true)) { Slog.e(TAG, "Failed to remove primary package: " + packageName); return; Loading @@ -1165,7 +1302,7 @@ public final class CredentialManagerService // Read the autofill provider so we don't accidentally erase it. String autofillProvider = settingsWrapper.getStringForUser( Settings.Secure.AUTOFILL_SERVICE, UserHandle.myUserId()); Settings.Secure.AUTOFILL_SERVICE, userId); // If there is an autofill provider and it is the credential autofill service indicating // that the currently selected primary provider does not support autofill Loading @@ -1181,31 +1318,70 @@ public final class CredentialManagerService if (!settingsWrapper.putStringForUser( Settings.Secure.AUTOFILL_SERVICE, "", UserHandle.myUserId(), userId, /* overrideableByRestore= */ true)) { Slog.e(TAG, "Failed to remove autofill package: " + packageName); } } } // If there are no more primary providers AND there is no autofill provider either, // that means all providers must be cleared as that is what the Settings UI app // displays to the user.If the autofill provider is present then UI shows that as the // preferred service and other credential provider services can continue to work. if (primaryProviders.isEmpty() && !isAutofillProviderPresent(settingsWrapper, userId)) { Slog.d(TAG, "Clearing all credential providers"); if (clearAllCredentialProviders(settingsWrapper, userId)) { return; } Slog.e(TAG, "Failed to clear all credential providers"); } } // Read the credential providers to remove any reference of the removed app. String rawCredentialProviders = settingsWrapper.getStringForUser( Settings.Secure.CREDENTIAL_SERVICE, UserHandle.myUserId()); Settings.Secure.CREDENTIAL_SERVICE, userId); // Remove any providers that belong to the removed app. Set<String> credentialProviders = getStoredProviders(rawCredentialProviders, packageName); Set<String> credentialProviders = getStoredProvidersExceptPackage( rawCredentialProviders, packageName); if (!settingsWrapper.putStringForUser( Settings.Secure.CREDENTIAL_SERVICE, String.join(":", credentialProviders), UserHandle.myUserId(), userId, /* overrideableByRestore= */ true)) { Slog.e(TAG, "Failed to remove secondary package: " + packageName); } } /** Gets the list of stored providers from a string removing any mention of package name. */ public static Set<String> getStoredProviders(String rawProviders, String packageName) { public static Set<String> getStoredProvidersExceptService(String rawProviders, ComponentName componentName) { // If the app being removed matches any of the package names from // this list then don't add it in the output. Set<String> providers = new HashSet<>(); if (rawProviders == null || componentName == null) { return providers; } for (String rawComponentName : rawProviders.split(":")) { if (TextUtils.isEmpty(rawComponentName) || rawComponentName.equals("null")) { Slog.d(TAG, "provider component name is empty or null"); continue; } ComponentName cn = ComponentName.unflattenFromString(rawComponentName); if (cn != null && !cn.equals(componentName)) { providers.add(cn.flattenToString()); } } return providers; } /** Gets the list of stored providers from a string removing any mention of package name. */ public static Set<String> getStoredProvidersExceptPackage( String rawProviders, String packageName) { // If the app being removed matches any of the package names from // this list then don't add it in the output. Set<String> providers = new HashSet<>(); Loading @@ -1213,8 +1389,7 @@ public final class CredentialManagerService return providers; } for (String rawComponentName : rawProviders.split(":")) { if (TextUtils.isEmpty(rawComponentName) || rawComponentName.equals("null")) { if (TextUtils.isEmpty(rawComponentName) || rawComponentName.equals("null")) { Slog.d(TAG, "provider component name is empty or null"); continue; } Loading
services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java +7 −0 Original line number Diff line number Diff line Loading @@ -57,6 +57,13 @@ public final class CredentialManagerServiceImpl extends } } @Nullable @Override @GuardedBy("mLock") public ComponentName getServiceComponentName() { return getComponentName(); } @GuardedBy("mLock") public ComponentName getComponentName() { return mInfo.getServiceInfo().getComponentName(); Loading
services/tests/servicestests/src/com/android/server/credentials/CredentialManagerServiceTest.java +13 −7 Original line number Diff line number Diff line Loading @@ -51,20 +51,22 @@ public final class CredentialManagerServiceTest { @Test public void getStoredProviders_emptyValue_success() { Set<String> providers = CredentialManagerService.getStoredProviders("", ""); Set<String> providers = CredentialManagerService.getStoredProvidersExceptPackage( "", ""); assertThat(providers.size()).isEqualTo(0); } @Test public void getStoredProviders_nullValue_success() { Set<String> providers = CredentialManagerService.getStoredProviders(null, null); Set<String> providers = CredentialManagerService.getStoredProvidersExceptPackage( null, null); assertThat(providers.size()).isEqualTo(0); } @Test public void getStoredProviders_success() { Set<String> providers = CredentialManagerService.getStoredProviders( CredentialManagerService.getStoredProvidersExceptPackage( "com.example.test/.TestActivity:com.example.test/.TestActivity2:" + "com.example.test2/.TestActivity:blank", "com.example.test"); Loading @@ -74,6 +76,7 @@ public final class CredentialManagerServiceTest { @Test public void onProviderRemoved_success() { int userId = UserHandle.myUserId(); setSettingsKey( Settings.Secure.AUTOFILL_SERVICE, CredentialManagerService.AUTOFILL_PLACEHOLDER_VALUE); Loading @@ -85,7 +88,7 @@ public final class CredentialManagerServiceTest { "com.example.test/com.example.test.TestActivity"); CredentialManagerService.updateProvidersWhenPackageRemoved( mSettingsWrapper, "com.example.test"); mSettingsWrapper, "com.example.test", userId); assertThat(getSettingsKey(Settings.Secure.AUTOFILL_SERVICE)).isEqualTo(""); assertThat(getSettingsKey(Settings.Secure.CREDENTIAL_SERVICE)) Loading @@ -95,6 +98,7 @@ public final class CredentialManagerServiceTest { @Test public void onProviderRemoved_notPrimaryRemoved_success() { int userId = UserHandle.myUserId(); final String testCredentialPrimaryValue = "com.example.test/com.example.test.TestActivity"; final String testCredentialValue = "com.example.test/com.example.test.TestActivity:com.example.test2/com.example.test2.TestActivity"; Loading @@ -106,7 +110,7 @@ public final class CredentialManagerServiceTest { setSettingsKey(Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, testCredentialPrimaryValue); CredentialManagerService.updateProvidersWhenPackageRemoved( mSettingsWrapper, "com.example.test3"); mSettingsWrapper, "com.example.test3", userId); // Since the provider removed was not a primary provider then we should do nothing. assertThat(getSettingsKey(Settings.Secure.AUTOFILL_SERVICE)) Loading @@ -120,6 +124,7 @@ public final class CredentialManagerServiceTest { @Test public void onProviderRemoved_isAlsoAutofillProvider_success() { int userId = UserHandle.myUserId(); setSettingsKey( Settings.Secure.AUTOFILL_SERVICE, "com.example.test/com.example.test.AutofillProvider"); Loading @@ -131,7 +136,7 @@ public final class CredentialManagerServiceTest { "com.example.test/com.example.test.TestActivity"); CredentialManagerService.updateProvidersWhenPackageRemoved( mSettingsWrapper, "com.example.test"); mSettingsWrapper, "com.example.test", userId); assertThat(getSettingsKey(Settings.Secure.AUTOFILL_SERVICE)).isEqualTo(""); assertThat(getSettingsKey(Settings.Secure.CREDENTIAL_SERVICE)) Loading @@ -141,6 +146,7 @@ public final class CredentialManagerServiceTest { @Test public void onProviderRemoved_notPrimaryRemoved_isAlsoAutofillProvider_success() { int userId = UserHandle.myUserId(); final String testCredentialPrimaryValue = "com.example.test/com.example.test.TestActivity"; final String testCredentialValue = "com.example.test/com.example.test.TestActivity:com.example.test2/com.example.test2.TestActivity"; Loading @@ -151,7 +157,7 @@ public final class CredentialManagerServiceTest { setSettingsKey(Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, testCredentialPrimaryValue); CredentialManagerService.updateProvidersWhenPackageRemoved( mSettingsWrapper, "com.example.test3"); mSettingsWrapper, "com.example.test3", userId); // Since the provider removed was not a primary provider then we should do nothing. assertCredentialPropertyEquals( Loading