diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index c12ee03fb86d1..f368d88875cfb 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -9334,6 +9334,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( @@ -9346,11 +9347,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; } } @@ -10837,27 +10839,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); } } @@ -16701,6 +16708,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"); @@ -16740,7 +16748,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) { @@ -16797,7 +16805,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; } /**