Clean up apks installed for a removed user

When a user is removed, enumerate through all installed packages
to see if any of them are not installed for any user. Delete the
package if no user has it "installed".

Added a pm option to install an apk for a specific user.

Fixed a crash in UserManagerService when executing the above
cleanup - dying users generate a null UserInfo.

Bug: 15426024
Change-Id: I571decde1ae1c257d0da6db153b896aad6d6bcb4
This commit is contained in:
Amith Yamasani
2014-08-28 18:06:51 -07:00
parent 551056ec0f
commit dda003ffa8
4 changed files with 82 additions and 5 deletions

View File

@@ -866,6 +866,7 @@ public final class Pm {
private void runInstall() {
int installFlags = PackageManager.INSTALL_ALL_USERS;
int userId = UserHandle.USER_ALL;
String installerPackageName = null;
String opt;
@@ -909,6 +910,13 @@ public final class Pm {
}
} else if (opt.equals("--abi")) {
abi = checkAbiArgument(nextOptionData());
} else if (opt.equals("--user")) {
userId = Integer.parseInt(nextOptionData());
if (userId == UserHandle.USER_ALL) {
installFlags |= PackageManager.INSTALL_ALL_USERS;
} else {
installFlags &= ~PackageManager.INSTALL_ALL_USERS;
}
} else {
System.err.println("Error: Unknown option: " + opt);
return;
@@ -953,8 +961,8 @@ public final class Pm {
VerificationParams verificationParams = new VerificationParams(verificationURI,
originatingURI, referrerURI, VerificationParams.NO_UID, null);
mPm.installPackage(apkFilePath, obs.getBinder(), installFlags, installerPackageName,
verificationParams, abi);
mPm.installPackageAsUser(apkFilePath, obs.getBinder(), installFlags, installerPackageName,
verificationParams, abi, userId);
synchronized (obs) {
while (!obs.finished) {

View File

@@ -198,6 +198,14 @@ interface IPackageManager {
in VerificationParams verificationParams,
in String packageAbiOverride);
void installPackageAsUser(in String originPath,
in IPackageInstallObserver2 observer,
int flags,
in String installerPackageName,
in VerificationParams verificationParams,
in String packageAbiOverride,
int userId);
void finishPackageInstall(int token);
void setInstallerPackageName(in String targetPackage, in String installerPackageName);

View File

@@ -7698,8 +7698,21 @@ public class PackageManagerService extends IPackageManager.Stub {
public void installPackage(String originPath, IPackageInstallObserver2 observer,
int installFlags, String installerPackageName, VerificationParams verificationParams,
String packageAbiOverride) {
installPackageAsUser(originPath, observer, installFlags, installerPackageName, verificationParams,
packageAbiOverride, UserHandle.getCallingUserId());
}
@Override
public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,
int installFlags, String installerPackageName, VerificationParams verificationParams,
String packageAbiOverride, int userId) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES,
null);
if (UserHandle.getCallingUserId() != userId) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
"installPackage " + userId);
}
final File originFile = new File(originPath);
final int uid = Binder.getCallingUid();
@@ -7717,7 +7730,7 @@ public class PackageManagerService extends IPackageManager.Stub {
if ((installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {
user = UserHandle.ALL;
} else {
user = new UserHandle(UserHandle.getUserId(uid));
user = new UserHandle(userId);
}
final int filteredInstallFlags;
@@ -12965,7 +12978,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
/** Called by UserManagerService */
void cleanUpUserLILPw(int userHandle) {
void cleanUpUserLILPw(UserManagerService userManager, int userHandle) {
mDirtyUsers.remove(userHandle);
mSettings.removeUserLPw(userHandle);
mPendingBroadcasts.remove(userHandle);
@@ -12976,6 +12989,50 @@ public class PackageManagerService extends IPackageManager.Stub {
mInstaller.removeUserDataDirs(userHandle);
}
mUserNeedsBadging.delete(userHandle);
removeUnusedPackagesLILPw(userManager, userHandle);
}
/**
* We're removing userHandle and would like to remove any downloaded packages
* that are no longer in use by any other user.
* @param userHandle the user being removed
*/
private void removeUnusedPackagesLILPw(UserManagerService userManager, final int userHandle) {
final boolean DEBUG_CLEAN_APKS = false;
int [] users = userManager.getUserIdsLPr();
Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
while (psit.hasNext()) {
PackageSetting ps = psit.next();
final String packageName = ps.pkg.packageName;
// Skip over if system app
if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0) {
continue;
}
if (DEBUG_CLEAN_APKS) {
Slog.i(TAG, "Checking package " + packageName);
}
boolean keep = false;
for (int i = 0; i < users.length; i++) {
if (users[i] != userHandle && ps.getInstalled(users[i])) {
keep = true;
if (DEBUG_CLEAN_APKS) {
Slog.i(TAG, " Keeping package " + packageName + " for user "
+ users[i]);
}
break;
}
}
if (!keep) {
if (DEBUG_CLEAN_APKS) {
Slog.i(TAG, " Removing package " + packageName);
}
mHandler.post(new Runnable() {
public void run() {
deletePackageX(packageName, userHandle, 0);
} //end run
});
}
}
}
/** Called by UserManagerService */

View File

@@ -293,6 +293,10 @@ public class UserManagerService extends IUserManager.Stub {
private List<UserInfo> getProfilesLocked(int userId, boolean enabledOnly) {
UserInfo user = getUserInfoLocked(userId);
ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size());
if (user == null) {
// Probably a dying user
return users;
}
for (int i = 0; i < mUsers.size(); i++) {
UserInfo profile = mUsers.valueAt(i);
if (!isProfileOf(user, profile)) {
@@ -1280,7 +1284,7 @@ public class UserManagerService extends IUserManager.Stub {
private void removeUserStateLocked(final int userHandle) {
// Cleanup package manager settings
mPm.cleanUpUserLILPw(userHandle);
mPm.cleanUpUserLILPw(this, userHandle);
// Remove this user from the list
mUsers.remove(userHandle);