From b22e916ae838cde9776a2cbdd3d8e71fce3c129f Mon Sep 17 00:00:00 2001 From: Patrick Baumann Date: Fri, 12 Apr 2019 10:35:29 -0700 Subject: [PATCH] Fixes incorrect app id cleanup on failure This change makes sure that we track the creation of app IDs so that we only delete when we actually created something new. Fixes: 130209119 Test: atest SharedUserIdTest Change-Id: I03e38b4dc16e9ccccd7d10bfe78bcaedc317d0cb --- .../server/pm/PackageManagerService.java | 46 +++++++++++-------- .../java/com/android/server/pm/Settings.java | 10 +++- 2 files changed, 36 insertions(+), 20 deletions(-) diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index d3aa746f75969..650c1369b8fb7 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -9329,6 +9329,7 @@ public class PackageManagerService extends IPackageManager.Stub | SCAN_UPDATE_SIGNATURE, currentTime, user); if (scanResult.success) { synchronized (mPackages) { + boolean appIdCreated = false; try { final String pkgName = scanResult.pkgSetting.name; final Map reconcileResult = reconcilePackagesLocked( @@ -9341,11 +9342,12 @@ public class PackageManagerService extends IPackageManager.Stub Collections.singletonMap(pkgName, getSharedLibLatestVersionSetting(scanResult))), mSettings.mKeySetManagerService); - prepareScanResultLocked(scanResult); - commitReconciledScanResultLocked( - reconcileResult.get(pkgName)); + appIdCreated = optimisticallyRegisterAppId(scanResult); + commitReconciledScanResultLocked(reconcileResult.get(pkgName)); } catch (PackageManagerException e) { - unprepareScanResultLocked(scanResult); + if (appIdCreated) { + cleanUpAppIdCreation(scanResult); + } throw e; } } @@ -10832,27 +10834,32 @@ public class PackageManagerService extends IPackageManager.Stub } - /** Prepares the system to commit a {@link ScanResult} in a way that will not fail. */ - private void prepareScanResultLocked(@NonNull ScanResult result) + /** + * Prepares the system to commit a {@link ScanResult} in a way that will not fail by registering + * the app ID required for reconcile. + * @return {@code true} if a new app ID was registered and will need to be cleaned up on + * failure. + */ + private boolean optimisticallyRegisterAppId(@NonNull ScanResult result) throws PackageManagerException { if (!result.existingSettingCopied) { // THROWS: when we can't allocate a user id. add call to check if there's // enough space to ensure we won't throw; otherwise, don't modify state - mSettings.registerAppIdLPw(result.pkgSetting); + return mSettings.registerAppIdLPw(result.pkgSetting); } + return false; } /** - * Reverts any changes to the system that were made by - * {@link #prepareScanResultLocked(ScanResult)} + * Reverts any app ID creation that were made by + * {@link #optimisticallyRegisterAppId(ScanResult)}. Note: this is only necessary if the + * referenced method returned true. */ - private void unprepareScanResultLocked(@NonNull ScanResult result) { - if (!result.existingSettingCopied) { - // iff we've acquired an app ID for a new package setting, remove it so that it can be - // acquired by another request. - if (result.pkgSetting.appId > 0) { - mSettings.removeAppIdLPw(result.pkgSetting.appId); - } + private void cleanUpAppIdCreation(@NonNull ScanResult result) { + // iff we've acquired an app ID for a new package setting, remove it so that it can be + // acquired by another request. + if (result.pkgSetting.appId > 0) { + mSettings.removeAppIdLPw(result.pkgSetting.appId); } } @@ -16696,6 +16703,7 @@ public class PackageManagerService extends IPackageManager.Stub final Map versionInfos = new ArrayMap<>(requests.size()); final Map lastStaticSharedLibSettings = new ArrayMap<>(requests.size()); + final Map createdAppId = new ArrayMap<>(requests.size()); boolean success = false; try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackagesLI"); @@ -16735,7 +16743,7 @@ public class PackageManagerService extends IPackageManager.Stub + " in multi-package install request."); return; } - prepareScanResultLocked(result); + createdAppId.put(packageName, optimisticallyRegisterAppId(result)); versionInfos.put(result.pkgSetting.pkg.packageName, getSettingsVersionForPackage(result.pkgSetting.pkg)); if (result.staticSharedLibraryInfo != null) { @@ -16792,7 +16800,9 @@ public class PackageManagerService extends IPackageManager.Stub } finally { if (!success) { for (ScanResult result : preparedScans.values()) { - unprepareScanResultLocked(result); + if (createdAppId.getOrDefault(result.request.pkg.packageName, false)) { + cleanUpAppIdCreation(result); + } } } for (PrepareResult result : prepareResults.values()) { diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 41a8a776e3f7f..dae07bdc37d57 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -810,15 +810,20 @@ public final class Settings { /** * Registers a user ID with the system. Potentially allocates a new user ID. + * @return {@code true} if a new app ID was created in the process. {@code false} can be + * returned in the case that a shared user ID already exists or the explicit app ID is + * already registered. * @throws PackageManagerException If a user ID could not be allocated. */ - void registerAppIdLPw(PackageSetting p) throws PackageManagerException { + boolean registerAppIdLPw(PackageSetting p) throws PackageManagerException { + final boolean createdNew; if (p.appId == 0) { // Assign new user ID p.appId = acquireAndRegisterNewAppIdLPw(p); + createdNew = true; } else { // Add new setting to list of user IDs - registerExistingAppIdLPw(p.appId, p, p.name); + createdNew = registerExistingAppIdLPw(p.appId, p, p.name); } if (p.appId < 0) { PackageManagerService.reportSettingsProblem(Log.WARN, @@ -826,6 +831,7 @@ public final class Settings { throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Package " + p.name + " could not be assigned a valid UID"); } + return createdNew; } /**