CVE-2026-0016 AI-generated analysis
platform/frameworks/base, Credential Manager service (services/credentials) and the shared AbstractMasterSystemService infra (services/core/java/com/android/server/infra)
Makes Credential Manager package-update handling user-correct: CredentialManagerService.updateProvidersWhenServiceRemoved now reads and writes the Secure settings of the passed userId instead of UserHandle.myUserId(), and AbstractMasterSystemService.removeInvalidCachedServicesLocked only acts on cached services belonging to the user whose package changed.
Root cause
Two defects on the package-update path. (1) In CredentialManagerService.updateProvidersWhenServiceRemoved(settingsWrapper, componentName, userId), three settings accesses used UserHandle.myUserId() (the user of the system_server process) instead of the userId parameter: the write of Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, and the read and the write of Settings.Secure.CREDENTIAL_SERVICE. The initial read of CREDENTIAL_SERVICE_PRIMARY, isAutofillProviderPresent and clearAllCredentialProviders already used userId. A service removal handled for one user could therefore change the credential provider settings of the system process's user. (2) In AbstractMasterSystemService.removeInvalidCachedServicesLocked(validServices, packageName, userId), visitServicesLocked iterates mServicesCacheList across all users (per index search) and the check matched only on package name. A package change in one user could therefore call handleServiceRemovedMultiModeLocked(serviceComponentName, userId) for another user's service with the same package name, pairing that service's component with the changing user's userId. The package monitor is registered with UserHandle.ALL (mPackageMonitor.register(getContext(), null, UserHandle.ALL, true)).
How the fix works
- Commit 10b748dbc348 (android-security-16.0.0_r7), services/core/java/com/android/server/infra/AbstractMasterSystemService.java:removeInvalidCachedServicesLocked: inside the visitServicesLocked lambda, reads int serviceUserId = s.getUserId() and adds serviceUserId == userId to the condition. Only services of the changing user with the matching package are now checked against validServices and passed to handleServiceRemovedMultiModeLocked.
- Same commit, services/credentials/java/com/android/server/credentials/CredentialManagerService.java:updateProvidersWhenServiceRemoved: replaces UserHandle.myUserId() with the userId parameter in three places: putStringForUser(Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, ...), getStringForUser(Settings.Secure.CREDENTIAL_SERVICE, ...) and putStringForUser(Settings.Secure.CREDENTIAL_SERVICE, ...). On the Android 16 security branch this is applied unconditionally (no flag check in production code).
- Same commit, services/tests/servicestests/Android.bp: adds android.credentials.flags-aconfig-java to static_libs. CredentialManagerServiceTest.java: rewrites the tests to pass explicit user ids and adds getStoredProvidersExceptService and updateProvidersWhenServiceRemoved tests. These include updateProvidersWhenServiceRemoved_multiUser_otherUserUnchanged (a removal for USER_ID_10 leaves the USER_ID_0 settings untouched). The test also enables Flags.FLAG_MULTI_USER_FIX_ENABLED via SetFlagsRule.
- Commit ffdfa5c70fca (android-security-16.0.0_r7), CredentialManagerServiceTest.java only ('Remove multi user flag reference'): removes the Flags import, the SetFlagsRule and the enableFlags call. This matches the Android 16 production diff, which has no flag gate.
- Android 17 (a631806c7aef in android-17.0.0_r1): same AbstractMasterSystemService change. In CredentialManagerService.updateProvidersWhenServiceRemoved, the userId-based calls are wrapped in if (Flags.multiUserFixEnabled()) and the old UserHandle.myUserId() calls are kept in the else branches. That part of the fix is active only when android.credentials.flags.multi_user_fix_enabled is on.
Completeness
- Covers all three remaining UserHandle.myUserId() uses in updateProvidersWhenServiceRemoved. Per the surrounding code, the other settings accesses in that function (initial CREDENTIAL_SERVICE_PRIMARY read, isAutofillProviderPresent, clearAllCredentialProviders) already took userId.
- Adds the user filter in removeInvalidCachedServicesLocked only. The adjacent handlePackageUpdateLocked(String packageName) in the same file still calls visitServicesLocked((s) -> s.handlePackageUpdateLocked(packageName)) over all users' services with no user filter. Whether that matters depends on per-service handlers that the material does not show.
- updateProvidersWhenPackageRemoved is exercised by the new tests but not modified by the diff. The material does not show how it handles the settings user.
- On Android 17 the CredentialManagerService part is flag-gated; with the flag off, the old UserHandle.myUserId() behavior remains. The AbstractMasterSystemService part is unconditional on both branches.
Behavior changes
- Removing a credential provider service for user N now updates CREDENTIAL_SERVICE_PRIMARY and CREDENTIAL_SERVICE for user N instead of the system process's user.
- A package change in user N no longer calls handleServiceRemovedMultiModeLocked for cached services of other users that share the package name.
- Android 17 only: the settings-user correction depends on the aconfig flag android.credentials.flags.multi_user_fix_enabled.
- FrameworksServicesTests now depends on android.credentials.flags-aconfig-java.
Per major
- Android 14: Not affected per the bulletin. Only 3/8 lines of the patched region are present at android-security-14.0.0_r29, so the patched code differs or is partly absent.
- Android 15: Not affected per the bulletin. Only 2/8 lines of the patched region are present at android-security-15.0.0_r17, so the patched code differs or is partly absent.
- Android 16: Resolved in android-security-16.0.0_r7 by 10b748dbc348 (adapted and unflagged: userId used unconditionally) plus ffdfa5c70fca (test-only removal of the flag reference). 8/8 lines are present at android-security-16.0.0_r8.
- Android 17: Resolved in android-17.0.0_r1 by a631806c7aef. The CredentialManagerService part is gated by Flags.multiUserFixEnabled() with legacy else branches; the AbstractMasterSystemService part is unconditional. 8/8 lines are present at android-security-17.0.0_r1.
Unknowns
- What information is disclosed (the bulletin classifies this as ID, High) is not shown.
- Which path from the package monitor callbacks into updateProvidersWhenServiceRemoved is involved is not shown.
- Why Android 14 and 15 are not affected is not shown beyond the partial presence of the patched region.
- Whether android.credentials.flags.multi_user_fix_enabled is enabled by default on Android 17 builds.
- What handleServiceRemovedMultiModeLocked and the per-service handlePackageUpdateLocked implementations do.