diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java index 7dae22a44cc5f..d3d291ea52ac8 100644 --- a/services/core/java/com/android/server/pm/DeletePackageHelper.java +++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java @@ -108,7 +108,7 @@ final class DeletePackageHelper { } /** - * This method is an internal method that could be get invoked either + * This method is an internal method that could be invoked either * to delete an installed package or to clean up a failed installation. * After deleting an installed package, a broadcast is sent to notify any * listeners that the package has been removed. For cleaning up a failed @@ -146,6 +146,8 @@ final class DeletePackageHelper { int[] allUsers; final int freezeUser; final SparseArray priorUserStates; + + final boolean isInstallerPackage; /** enabled state of the uninstalled application */ synchronized (mPm.mLock) { final Computer computer = mPm.snapshotComputer(); @@ -226,6 +228,8 @@ final class DeletePackageHelper { freezeUser = removeUser; priorUserStates = null; } + + isInstallerPackage = mPm.mSettings.isInstallerPackage(packageName); } synchronized (mPm.mInstallLock) { @@ -324,6 +328,12 @@ final class DeletePackageHelper { } } + if (res && isInstallerPackage) { + final PackageInstallerService packageInstallerService = + mPm.mInjector.getPackageInstallerService(); + packageInstallerService.onInstallerPackageDeleted(uninstalledPs.getAppId(), removeUser); + } + return res ? PackageManager.DELETE_SUCCEEDED : PackageManager.DELETE_FAILED_INTERNAL_ERROR; } diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 9b5984e09c8b9..e406a1a4bca78 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -861,6 +861,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements synchronized (mSessions) { mSessions.put(sessionId, session); } + mPm.addInstallerPackageName(session.getInstallSource()); mCallbacks.notifySessionCreated(session.sessionId, session.userId); @@ -1735,4 +1736,37 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements .setPackage(sessionInfo.installerPackageName); mContext.sendBroadcastAsUser(sessionUpdatedIntent, UserHandle.of(userId)); } + + /** + * Abandon unfinished sessions if the installer package has been uninstalled. + * @param installerAppId the app ID of the installer package that has been uninstalled. + * @param userId the user that has the installer package uninstalled. + */ + void onInstallerPackageDeleted(int installerAppId, int userId) { + synchronized (mSessions) { + for (int i = 0; i < mSessions.size(); i++) { + final PackageInstallerSession session = mSessions.valueAt(i); + if (!matchesInstaller(session, installerAppId, userId)) { + continue; + } + // Find parent session and only abandon parent session if installer matches + PackageInstallerSession root = !session.hasParentSessionId() + ? session : mSessions.get(session.getParentSessionId()); + if (root != null && matchesInstaller(root, installerAppId, userId) + && !root.isDestroyed()) { + root.abandon(); + } + } + } + } + + private boolean matchesInstaller(PackageInstallerSession session, int installerAppId, + int userId) { + final int installerUid = session.getInstallerUid(); + if (installerAppId == UserHandle.USER_ALL) { + return UserHandle.getAppId(installerUid) == installerAppId; + } else { + return UserHandle.getUid(userId, installerAppId) == installerUid; + } + } } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index e1af9a7ab96f9..ccdd913c9e862 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -7167,4 +7167,10 @@ public class PackageManagerService implements PackageSender, TestUtilityService void notifyInstantAppPackageInstalled(String packageName, int[] newUsers) { mInstantAppRegistry.onPackageInstalled(snapshotComputer(), packageName, newUsers); } + + void addInstallerPackageName(InstallSource installSource) { + synchronized (mLock) { + mSettings.addInstallerPackageNames(installSource); + } + } } diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index b53cfc558f6e6..e6d59d43ffbe1 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -380,8 +380,8 @@ public final class Settings implements Watchable, Snappable { private final SnapshotCache> mPackagesSnapshot; /** - * List of packages that were involved in installing other packages, i.e. are listed - * in at least one app's InstallSource. + * List of packages that were involved in installing other packages, i.e. packages that created + * new sessions or are listed in at least one app's InstallSource. */ @Watched private final WatchedArraySet mInstallerPackages; @@ -5923,4 +5923,8 @@ public final class Settings implements Watchable, Snappable { } } } + + boolean isInstallerPackage(@NonNull String packageName) { + return mInstallerPackages.contains(packageName); + } }