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:
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user