[pm] delete unfinished sessions when installer is uninstalled
A malicious app can create many new sessions without any permission. Prior to this CL, those sessions might remain for days even after the app has been uninstalled. This change makes PackageInstallerService promptly abandon unfinished sessions as soon as the installer package is uninstalled. BUG: 219030339 Test: atest android.content.pm.cts.InstallSessionCleanupTest Change-Id: I72c4a29e031cb47c16c9a0fbafdf68b75c4d6a55
This commit is contained in:
@@ -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<TempUserState> 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -380,8 +380,8 @@ public final class Settings implements Watchable, Snappable {
|
||||
private final SnapshotCache<WatchedArrayMap<String, PackageSetting>> 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<String> mInstallerPackages;
|
||||
@@ -5923,4 +5923,8 @@ public final class Settings implements Watchable, Snappable {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean isInstallerPackage(@NonNull String packageName) {
|
||||
return mInstallerPackages.contains(packageName);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user