CVE-2025-48594 AI-generated analysis
platform/frameworks/base, services/companion (CompanionDeviceManagerService on 14; association/DisassociationProcessor on 15/16)
The CompanionDeviceManager UID callback that drains revoked/pending associations now resolves every package sharing a UID via PackageManager.getPackagesForUid() and processes pending revoked associations for each of them, instead of only the single package name previously resolved for the UID.
Root cause
In the UID callback of CompanionDeviceManagerService (Android 14, hunk around line 1562) the code called getPackageNameByUid(uid) and then iterated getPendingRoleHolderRemovalAssociationsForUser(userId) looking only for associations whose getPackageName() equalled that single name. On 15/16 the same logic in DisassociationProcessor used mPackageManagerInternal.getNameForUid(uid) and only disassociated mAssociationStore.getRevokedAssociations(userId, packageName) for that one name. For a UID shared by several packages, revoked associations belonging to packages other than the resolved name were not matched and stayed pending.
How the fix works
- services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java (Android 14): adds a PackageManager field mPackageManager initialised from context.getPackageManager() in the constructor.
- Same file, UID callback: replaces getPackageNameByUid(uid) with mPackageManager.getPackagesForUid(uid); returns early only if the array is null or empty.
- Same callback: wraps the existing loop over getPendingRoleHolderRemovalAssociationsForUser(userId) in an outer loop over all packageNames, so for each package the matching associations go through maybeRemoveRoleHolderForAssociation(association) and removeFromPendingRoleHolderRemoval(association); needToPersistStateForUser is set if any removal happened, as before.
- services/companion/java/com/android/server/companion/association/DisassociationProcessor.java (Android 15 and 16): same pattern, adds mPackageManager, replaces mPackageManagerInternal.getNameForUid(uid) with mPackageManager.getPackagesForUid(uid), and loops over all packages calling disassociate(association.getId()) (15) or disassociate(association.getId(), REASON_REVOKED) (16) for mAssociationStore.getRevokedAssociations(userId, packageName).
Completeness
- The fix covers only the UID callback that drains revoked/pending associations; all packages of the UID are now processed in that path.
- The 14 variant keeps the existing behaviour that an association whose role holder could not be removed (maybeRemoveRoleHolderForAssociation returns false) stays pending for a later attempt.
- The diff does not touch other places that may map a UID to a single package name (the getPackageNameByUid helper is not removed or changed in the diff); the material does not show whether such other call sites exist.
- On 15/16 the trailing check mAssociationStore.getRevokedAssociations().isEmpty() is unchanged and now runs after all packages of the UID have been processed.
Behavior changes
- The callback now uses PackageManager.getPackagesForUid() instead of a single-name lookup; a UID with no packages still returns early.
- For shared-UID apps, revoked associations of every package in the UID are now processed in one pass; on 14 this may trigger role holder removal and state persistence for more packages than before, on 15/16 more disassociate() calls.
- No new error codes or API surface; additional field mPackageManager in the service/processor.
Per major
- Android 14: same fix: CompanionDeviceManagerService.java in android-security-14.0.0_r24 (cherry-picked from another change); 8/8 lines of the patched region present at android-security-14.0.0_r29.
- Android 15: adapted fix: same logic applied to association/DisassociationProcessor.java (getNameForUid replaced by getPackagesForUid, loop calls disassociate(association.getId())) in android-security-15.0.0_r12; 8/8 lines present at android-security-15.0.0_r17.
- Android 16: adapted fix: same as 15 with disassociate(association.getId(), REASON_REVOKED) in android-security-16.0.0_r3; 8/8 lines present at android-security-16.0.0_r8.
- Android 17: not affected (not listed by the bulletin); 6/8 lines of the patched region present at android-security-17.0.0_r1.
Unknowns
- The exact enclosing method name of the patched callback on 14 is not shown in the diff hunk header.
- The implementation of getPackageNameByUid / getNameForUid for shared UIDs, and whether other call sites in the companion service still resolve a UID to a single package name.
- What the 6/8 line match at android-security-17.0.0_r1 means for the code on 17.