Merge "UserSystemPackageInstaller only (un)installs when appropriate" into rvc-dev am: 9968525afb am: e8c7af4d96

Change-Id: I308a6d53885ffd5c0659d43f9759aeedf1a81708
This commit is contained in:
Adam Bookatz
2020-03-30 19:27:02 +00:00
committed by Automerger Merge Worker
11 changed files with 191 additions and 85 deletions

View File

@@ -1031,6 +1031,27 @@ public abstract class PackageManager {
*/
public static final int INSTALL_REASON_ROLLBACK = 5;
/** @hide */
@IntDef(prefix = { "UNINSTALL_REASON_" }, value = {
UNINSTALL_REASON_UNKNOWN,
UNINSTALL_REASON_USER_TYPE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface UninstallReason {}
/**
* Code indicating that the reason for uninstalling this package is unknown.
* @hide
*/
public static final int UNINSTALL_REASON_UNKNOWN = 0;
/**
* Code indicating that this package was uninstalled due to the type of user.
* See UserSystemPackageInstaller
* @hide
*/
public static final int UNINSTALL_REASON_USER_TYPE = 1;
/**
* @hide
*/

View File

@@ -74,6 +74,7 @@ public class PackageUserState {
public int appLinkGeneration;
public int categoryHint = ApplicationInfo.CATEGORY_UNDEFINED;
public int installReason;
public @PackageManager.UninstallReason int uninstallReason;
public String harmfulAppWarning;
public ArraySet<String> disabledComponents;
@@ -92,6 +93,7 @@ public class PackageUserState {
domainVerificationStatus =
PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
installReason = PackageManager.INSTALL_REASON_UNKNOWN;
uninstallReason = PackageManager.UNINSTALL_REASON_UNKNOWN;
}
@VisibleForTesting
@@ -112,6 +114,7 @@ public class PackageUserState {
appLinkGeneration = o.appLinkGeneration;
categoryHint = o.categoryHint;
installReason = o.installReason;
uninstallReason = o.uninstallReason;
disabledComponents = ArrayUtils.cloneOrNull(o.disabledComponents);
enabledComponents = ArrayUtils.cloneOrNull(o.enabledComponents);
overlayPaths =
@@ -353,6 +356,9 @@ public class PackageUserState {
if (installReason != oldState.installReason) {
return false;
}
if (uninstallReason != oldState.uninstallReason) {
return false;
}
if ((disabledComponents == null && oldState.disabledComponents != null)
|| (disabledComponents != null && oldState.disabledComponents == null)) {
return false;
@@ -407,6 +413,7 @@ public class PackageUserState {
hashCode = 31 * hashCode + appLinkGeneration;
hashCode = 31 * hashCode + categoryHint;
hashCode = 31 * hashCode + installReason;
hashCode = 31 * hashCode + uninstallReason;
hashCode = 31 * hashCode + Objects.hashCode(disabledComponents);
hashCode = 31 * hashCode + Objects.hashCode(enabledComponents);
hashCode = 31 * hashCode + Objects.hashCode(harmfulAppWarning);

View File

@@ -2406,8 +2406,7 @@
- to henceforth disable feature and try to undo its previous effects: 0
Note: This list must be kept current with PACKAGE_WHITELIST_MODE_PROP in
frameworks/base/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java -->
<integer name="config_userTypePackageWhitelistMode">29</integer> <!-- 1+4+8+16 -->
<!-- TODO(b/143200798): Change to value 13, i.e. 1+4+8, when b/143200798 is resolved. -->
<integer name="config_userTypePackageWhitelistMode">13</integer> <!-- 1+4+8 -->
<!-- Whether UI for multi user should be shown -->
<bool name="config_enableMultiUserUI">false</bool>

View File

@@ -97,8 +97,8 @@ The way that a device treats system packages that do not have any entry (for any
is determined by the config resource value config_userTypePackageWhitelistMode.
See frameworks/base/core/res/res/values/config.xml#config_userTypePackageWhitelistMode.
Changes to the whitelist during system updates can result in installing new system packages
to pre-existing users, but cannot uninstall system packages from pre-existing users.
Changes to the whitelist during system updates can result in installing additional system packages
to pre-existing users, but cannot uninstall pre-existing system packages from pre-existing users.
-->
<config>
<install-in-user-type package="com.android.providers.settings">

View File

@@ -426,17 +426,6 @@ public abstract class PackageManagerInternal {
*/
public abstract String getNameForUid(int uid);
/**
* Marks a package as installed (or not installed) for a given user.
*
* @param pkg the package whose installation is to be set
* @param userId the user for whom to set it
* @param installed the new installed state
* @return true if the installed state changed as a result
*/
public abstract boolean setInstalled(AndroidPackage pkg,
@UserIdInt int userId, boolean installed);
/**
* Request to perform the second phase of ephemeral resolution.
* @param responseObj The response of the first phase of ephemeral resolution
@@ -521,12 +510,6 @@ public abstract class PackageManagerInternal {
*/
public abstract boolean isPackagePersistent(String packageName);
/**
* Returns whether or not the given package represents a legacy system application released
* prior to runtime permissions.
*/
public abstract boolean isLegacySystemApp(AndroidPackage pkg);
/**
* Get all overlay packages for a user.
* @param userId The user for which to get the overlays.

View File

@@ -93,6 +93,7 @@ import static android.content.pm.PackageManager.MOVE_FAILED_SYSTEM_PACKAGE;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.content.pm.PackageManager.RESTRICTION_NONE;
import static android.content.pm.PackageManager.UNINSTALL_REASON_UNKNOWN;
import static android.content.pm.PackageParser.isApkFile;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import static android.os.incremental.IncrementalManager.isIncrementalPath;
@@ -736,9 +737,10 @@ public class PackageManagerService extends IPackageManager.Stub
final private ArrayMap<String, File> mExpectingBetter = new ArrayMap<>();
/**
* Tracks existing system packages prior to receiving an OTA. Keys are package name.
* Tracks existing packages prior to receiving an OTA. Keys are package name.
* Only non-null during an OTA, and even then it is nulled again once systemReady().
*/
final private ArraySet<String> mExistingSystemPackages = new ArraySet<>();
private @Nullable ArraySet<String> mExistingPackages = null;
/**
* Whether or not system app permissions should be promoted from install to runtime.
*/
@@ -2569,9 +2571,10 @@ public class PackageManagerService extends IPackageManager.Stub
private void installWhitelistedSystemPackages() {
synchronized (mLock) {
final boolean scheduleWrite = mUserManager.installWhitelistedSystemPackages(
isFirstBoot(), isDeviceUpgrading());
isFirstBoot(), isDeviceUpgrading(), mExistingPackages);
if (scheduleWrite) {
scheduleWritePackageRestrictionsLocked(UserHandle.USER_ALL);
scheduleWriteSettingsLocked();
}
}
}
@@ -2881,13 +2884,12 @@ public class PackageManagerService extends IPackageManager.Stub
mIsPreNMR1Upgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N_MR1;
mIsPreQUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.Q;
// save off the names of pre-existing system packages prior to scanning; we don't
// want to automatically grant runtime permissions for new system apps
if (mPromoteSystemApps) {
// Save the names of pre-existing packages prior to scanning, so we can determine
// which system packages are completely new due to an upgrade.
if (isDeviceUpgrading()) {
mExistingPackages = new ArraySet<>(mSettings.mPackages.size());
for (PackageSetting ps : mSettings.mPackages.values()) {
if (isSystemApp(ps)) {
mExistingSystemPackages.add(ps.name);
}
mExistingPackages.add(ps.name);
}
}
@@ -3348,7 +3350,6 @@ public class PackageManagerService extends IPackageManager.Stub
}
// clear only after permissions and other defaults have been updated
mExistingSystemPackages.clear();
mPromoteSystemApps = false;
// All the changes are done during package scanning.
@@ -12775,6 +12776,7 @@ public class PackageManagerService extends IPackageManager.Stub
pkgSetting.setInstalled(true, userId);
pkgSetting.setHidden(false, userId);
pkgSetting.setInstallReason(installReason, userId);
pkgSetting.setUninstallReason(PackageManager.UNINSTALL_REASON_UNKNOWN, userId);
mSettings.writePackageRestrictionsLPr(userId);
mSettings.writeKernelMappingLPr(pkgSetting);
installed = true;
@@ -15607,7 +15609,8 @@ public class PackageManagerService extends IPackageManager.Stub
}
// It's implied that when a user requests installation, they want the app to be
// installed and enabled.
// installed and enabled. (This does not apply to USER_ALL, which here means only
// install on users for which the app is already installed).
if (userId != UserHandle.USER_ALL) {
ps.setInstalled(true, userId);
ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, userId, installerPackageName);
@@ -15625,7 +15628,7 @@ public class PackageManagerService extends IPackageManager.Stub
mSettings.addInstallerPackageNames(installSource);
// When replacing an existing package, preserve the original install reason for all
// users that had the package installed before.
// users that had the package installed before. Similarly for uninstall reasons.
final Set<Integer> previousUserIds = new ArraySet<>();
if (res.removedInfo != null && res.removedInfo.installReasons != null) {
final int installReasonCount = res.removedInfo.installReasons.size();
@@ -15636,10 +15639,20 @@ public class PackageManagerService extends IPackageManager.Stub
previousUserIds.add(previousUserId);
}
}
if (res.removedInfo != null && res.removedInfo.uninstallReasons != null) {
for (int i = 0; i < res.removedInfo.uninstallReasons.size(); i++) {
final int previousUserId = res.removedInfo.uninstallReasons.keyAt(i);
final int previousReason = res.removedInfo.uninstallReasons.valueAt(i);
ps.setUninstallReason(previousReason, previousUserId);
}
}
// Set install reason for users that are having the package newly installed.
final int[] allUsersList = mUserManager.getUserIds();
if (userId == UserHandle.USER_ALL) {
for (int currentUserId : mUserManager.getUserIds()) {
// TODO(b/152629990): It appears that the package doesn't actually get newly
// installed in this case, so the installReason shouldn't get modified?
for (int currentUserId : allUsersList) {
if (!previousUserIds.contains(currentUserId)) {
ps.setInstallReason(installReason, currentUserId);
}
@@ -15647,6 +15660,12 @@ public class PackageManagerService extends IPackageManager.Stub
} else if (!previousUserIds.contains(userId)) {
ps.setInstallReason(installReason, userId);
}
// Ensure that the uninstall reason is UNKNOWN for users with the package installed.
for (int currentUserId : allUsersList) {
if (ps.getInstalled(currentUserId)) {
ps.setUninstallReason(UNINSTALL_REASON_UNKNOWN, currentUserId);
}
}
mSettings.writeKernelMappingLPr(ps);
}
res.name = pkgName;
@@ -17010,6 +17029,7 @@ public class PackageManagerService extends IPackageManager.Stub
final String pkgName11 = parsedPackage.getPackageName();
final int[] allUsers;
final int[] installedUsers;
final int[] uninstalledUsers;
synchronized (mLock) {
oldPackage = mPackages.get(pkgName11);
@@ -17084,6 +17104,7 @@ public class PackageManagerService extends IPackageManager.Stub
// In case of rollback, remember per-user/profile install state
allUsers = mUserManager.getUserIds();
installedUsers = ps.queryInstalledUsers(allUsers, true);
uninstalledUsers = ps.queryInstalledUsers(allUsers, false);
// don't allow an upgrade from full to ephemeral
@@ -17122,6 +17143,11 @@ public class PackageManagerService extends IPackageManager.Stub
final int userId = installedUsers[i];
res.removedInfo.installReasons.put(userId, ps.getInstallReason(userId));
}
res.removedInfo.uninstallReasons = new SparseArray<>(uninstalledUsers.length);
for (int i = 0; i < uninstalledUsers.length; i++) {
final int userId = uninstalledUsers[i];
res.removedInfo.uninstallReasons.put(userId, ps.getUninstallReason(userId));
}
sysPkg = oldPackage.isSystem();
if (sysPkg) {
@@ -17954,6 +17980,7 @@ public class PackageManagerService extends IPackageManager.Stub
int[] broadcastUsers = null;
int[] instantUserIds = null;
SparseArray<Integer> installReasons;
SparseArray<Integer> uninstallReasons;
boolean isRemovedPackageSystemUpdate = false;
boolean isUpdate;
boolean dataRemoved;
@@ -18176,6 +18203,9 @@ public class PackageManagerService extends IPackageManager.Stub
installedStateChanged = true;
}
deletedPs.setInstalled(installed, userId);
if (installed) {
deletedPs.setUninstallReason(UNINSTALL_REASON_UNKNOWN, userId);
}
}
}
}
@@ -18358,6 +18388,9 @@ public class PackageManagerService extends IPackageManager.Stub
installedStateChanged = true;
}
ps.setInstalled(installed, userId);
if (installed) {
ps.setUninstallReason(UNINSTALL_REASON_UNKNOWN, userId);
}
mSettings.writeRuntimePermissionsForUserLPr(userId, false);
}
@@ -18630,7 +18663,9 @@ public class PackageManagerService extends IPackageManager.Stub
null /*enabledComponents*/,
null /*disabledComponents*/,
ps.readUserState(nextUserId).domainVerificationStatus,
0, PackageManager.INSTALL_REASON_UNKNOWN,
0 /*linkGeneration*/,
PackageManager.INSTALL_REASON_UNKNOWN,
PackageManager.UNINSTALL_REASON_UNKNOWN,
null /*harmfulAppWarning*/);
}
mSettings.writeKernelMappingLPr(ps);
@@ -20781,6 +20816,8 @@ public class PackageManagerService extends IPackageManager.Stub
// installation on reboot. Make sure this is the last component to be call since the
// installation might require other components to be ready.
mInstallerService.restoreAndApplyStagedSessionIfNeeded();
mExistingPackages = null;
}
public void waitForAppDataPrepared() {
@@ -22733,16 +22770,17 @@ public class PackageManagerService extends IPackageManager.Stub
/**
* Called by UserManagerService.
*
* @param installablePackages system packages that should be initially installed for this user,
* or {@code null} if all system packages should be installed
* @param userTypeInstallablePackages system packages that should be initially installed for
* this type of user, or {@code null} if all system packages
* should be installed
* @param disallowedPackages packages that should not be initially installed. Takes precedence
* over installablePackages.
*/
void createNewUser(int userId, @Nullable Set<String> installablePackages,
void createNewUser(int userId, @Nullable Set<String> userTypeInstallablePackages,
String[] disallowedPackages) {
synchronized (mInstallLock) {
mSettings.createNewUserLI(this, mInstaller, userId,
installablePackages, disallowedPackages);
userTypeInstallablePackages, disallowedPackages);
}
synchronized (mLock) {
scheduleWritePackageRestrictionsLocked(userId);
@@ -23755,19 +23793,6 @@ public class PackageManagerService extends IPackageManager.Stub
return PackageManagerService.this.getNameForUid(uid);
}
@Override
public boolean setInstalled(AndroidPackage pkg, @UserIdInt int userId,
boolean installed) {
synchronized (mLock) {
final PackageSetting ps = mSettings.mPackages.get(pkg.getPackageName());
if (ps.getInstalled(userId) != installed) {
ps.setInstalled(installed, userId);
return true;
}
return false;
}
}
@Override
public void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj,
Intent origIntent, String resolvedType, String callingPackage,
@@ -23837,16 +23862,6 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
@Override
public boolean isLegacySystemApp(AndroidPackage pkg) {
synchronized (mLock) {
final PackageSetting ps = getPackageSetting(pkg.getPackageName());
return mPromoteSystemApps
&& ps.isSystem()
&& mExistingSystemPackages.contains(ps.name);
}
}
@Override
public List<PackageInfo> getOverlayPackages(int userId) {
final ArrayList<PackageInfo> overlayPackages = new ArrayList<PackageInfo>();

View File

@@ -24,6 +24,7 @@ import android.annotation.NonNull;
import android.content.pm.ApplicationInfo;
import android.content.pm.IntentFilterVerificationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.UninstallReason;
import android.content.pm.PackageParser;
import android.content.pm.PackageUserState;
import android.content.pm.Signature;
@@ -315,6 +316,14 @@ public abstract class PackageSettingBase extends SettingBase {
modifyUserState(userId).installReason = installReason;
}
int getUninstallReason(int userId) {
return readUserState(userId).uninstallReason;
}
void setUninstallReason(@UninstallReason int uninstallReason, int userId) {
modifyUserState(userId).uninstallReason = uninstallReason;
}
void setOverlayPaths(List<String> overlayPaths, int userId) {
modifyUserState(userId).setOverlayPaths(overlayPaths == null ? null :
overlayPaths.toArray(new String[overlayPaths.size()]));
@@ -471,7 +480,7 @@ public abstract class PackageSettingBase extends SettingBase {
ArrayMap<String, PackageUserState.SuspendParams> suspendParams, boolean instantApp,
boolean virtualPreload, String lastDisableAppCaller,
ArraySet<String> enabledComponents, ArraySet<String> disabledComponents,
int domainVerifState, int linkGeneration, int installReason,
int domainVerifState, int linkGeneration, int installReason, int uninstallReason,
String harmfulAppWarning) {
PackageUserState state = modifyUserState(userId);
state.ceDataInode = ceDataInode;
@@ -489,6 +498,7 @@ public abstract class PackageSettingBase extends SettingBase {
state.domainVerificationStatus = domainVerifState;
state.appLinkGeneration = linkGeneration;
state.installReason = installReason;
state.uninstallReason = uninstallReason;
state.instantApp = instantApp;
state.virtualPreload = virtualPreload;
state.harmfulAppWarning = harmfulAppWarning;
@@ -502,7 +512,7 @@ public abstract class PackageSettingBase extends SettingBase {
otherState.virtualPreload, otherState.lastDisableAppCaller,
otherState.enabledComponents, otherState.disabledComponents,
otherState.domainVerificationStatus, otherState.appLinkGeneration,
otherState.installReason, otherState.harmfulAppWarning);
otherState.installReason, otherState.uninstallReason, otherState.harmfulAppWarning);
}
ArraySet<String> getEnabledComponents(int userId) {

View File

@@ -24,6 +24,8 @@ import static android.content.pm.PackageManager.INSTALL_FAILED_SHARED_USER_INCOM
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY;
import static android.content.pm.PackageManager.UNINSTALL_REASON_UNKNOWN;
import static android.content.pm.PackageManager.UNINSTALL_REASON_USER_TYPE;
import static android.os.Process.PACKAGE_INFO_GID;
import static android.os.Process.SYSTEM_UID;
@@ -266,6 +268,7 @@ public final class Settings {
private static final String ATTR_DOMAIN_VERIFICATON_STATE = "domainVerificationStatus";
private static final String ATTR_APP_LINK_GENERATION = "app-link-generation";
private static final String ATTR_INSTALL_REASON = "install-reason";
private static final String ATTR_UNINSTALL_REASON = "uninstall-reason";
private static final String ATTR_INSTANT_APP = "instant-app";
private static final String ATTR_VIRTUAL_PRELOAD = "virtual-preload";
private static final String ATTR_HARMFUL_APP_WARNING = "harmful-app-warning";
@@ -684,7 +687,9 @@ public final class Settings {
null /*enabledComponents*/,
null /*disabledComponents*/,
INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED,
0, PackageManager.INSTALL_REASON_UNKNOWN,
0 /*linkGeneration*/,
PackageManager.INSTALL_REASON_UNKNOWN,
PackageManager.UNINSTALL_REASON_UNKNOWN,
null /*harmfulAppWarning*/);
}
}
@@ -768,6 +773,7 @@ public final class Settings {
if (allUserInfos != null) {
for (UserInfo userInfo : allUserInfos) {
pkgSetting.setInstalled(true, userInfo.id);
pkgSetting.setUninstallReason(UNINSTALL_REASON_UNKNOWN, userInfo.id);
}
}
}
@@ -1580,7 +1586,9 @@ public final class Settings {
null /*enabledComponents*/,
null /*disabledComponents*/,
INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED,
0, PackageManager.INSTALL_REASON_UNKNOWN,
0 /*linkGeneration*/,
PackageManager.INSTALL_REASON_UNKNOWN,
PackageManager.UNINSTALL_REASON_UNKNOWN,
null /*harmfulAppWarning*/);
}
return;
@@ -1678,6 +1686,8 @@ public final class Settings {
}
final int installReason = XmlUtils.readIntAttribute(parser,
ATTR_INSTALL_REASON, PackageManager.INSTALL_REASON_UNKNOWN);
final int uninstallReason = XmlUtils.readIntAttribute(parser,
ATTR_UNINSTALL_REASON, PackageManager.UNINSTALL_REASON_UNKNOWN);
ArraySet<String> enabledComponents = null;
ArraySet<String> disabledComponents = null;
@@ -1751,7 +1761,7 @@ public final class Settings {
hidden, distractionFlags, suspended, suspendParamsMap,
instantApp, virtualPreload,
enabledCaller, enabledComponents, disabledComponents, verifState,
linkGeneration, installReason, harmfulAppWarning);
linkGeneration, installReason, uninstallReason, harmfulAppWarning);
} else if (tagName.equals("preferred-activities")) {
readPreferredActivitiesLPw(parser, userId);
} else if (tagName.equals(TAG_PERSISTENT_PREFERRED_ACTIVITIES)) {
@@ -2079,6 +2089,10 @@ public final class Settings {
serializer.attribute(null, ATTR_INSTALL_REASON,
Integer.toString(ustate.installReason));
}
if (ustate.uninstallReason != PackageManager.UNINSTALL_REASON_UNKNOWN) {
serializer.attribute(null, ATTR_UNINSTALL_REASON,
Integer.toString(ustate.uninstallReason));
}
if (ustate.harmfulAppWarning != null) {
serializer.attribute(null, ATTR_HARMFUL_APP_WARNING,
ustate.harmfulAppWarning);
@@ -4126,7 +4140,7 @@ public final class Settings {
}
void createNewUserLI(@NonNull PackageManagerService service, @NonNull Installer installer,
@UserIdInt int userHandle, @Nullable Set<String> installablePackages,
@UserIdInt int userHandle, @Nullable Set<String> userTypeInstallablePackages,
String[] disallowedPackages) {
final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing",
Trace.TRACE_TAG_PACKAGE_MANAGER);
@@ -4137,7 +4151,7 @@ public final class Settings {
String[] seinfos;
int[] targetSdkVersions;
int packagesCount;
final boolean skipPackageWhitelist = installablePackages == null;
final boolean skipPackageWhitelist = userTypeInstallablePackages == null;
synchronized (mLock) {
Collection<PackageSetting> packages = mPackages.values();
packagesCount = packages.size();
@@ -4152,13 +4166,20 @@ public final class Settings {
if (ps.pkg == null) {
continue;
}
final boolean shouldInstall = ps.isSystem() &&
(skipPackageWhitelist || installablePackages.contains(ps.name)) &&
final boolean shouldMaybeInstall = ps.isSystem() &&
!ArrayUtils.contains(disallowedPackages, ps.name) &&
!ps.getPkgState().isHiddenUntilInstalled();
final boolean shouldReallyInstall = shouldMaybeInstall &&
(skipPackageWhitelist || userTypeInstallablePackages.contains(ps.name));
// Only system apps are initially installed.
ps.setInstalled(shouldInstall, userHandle);
if (!shouldInstall) {
ps.setInstalled(shouldReallyInstall, userHandle);
// If userTypeInstallablePackages is the *only* reason why we're not installing,
// then uninstallReason is USER_TYPE. If there's a different reason, or if we
// actually are installing, put UNKNOWN.
final int uninstallReason = (shouldMaybeInstall && !shouldReallyInstall) ?
UNINSTALL_REASON_USER_TYPE : UNINSTALL_REASON_UNKNOWN;
ps.setUninstallReason(uninstallReason, userHandle);
if (!shouldReallyInstall) {
writeKernelMappingLPr(ps);
}
// Need to create a data directory for all apps under this user. Accumulate all

View File

@@ -3438,10 +3438,10 @@ public class UserManagerService extends IUserManager.Stub {
StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
t.traceEnd();
final Set<String> installablePackages =
final Set<String> userTypeInstallablePackages =
mSystemPackageInstaller.getInstallablePackagesForUserType(userType);
t.traceBegin("PM.createNewUser");
mPm.createNewUser(userId, installablePackages, disallowedPackages);
mPm.createNewUser(userId, userTypeInstallablePackages, disallowedPackages);
t.traceEnd();
userInfo.partial = false;
@@ -3562,8 +3562,10 @@ public class UserManagerService extends IUserManager.Stub {
}
/** Install/uninstall system packages for all users based on their user-type, as applicable. */
boolean installWhitelistedSystemPackages(boolean isFirstBoot, boolean isUpgrade) {
return mSystemPackageInstaller.installWhitelistedSystemPackages(isFirstBoot, isUpgrade);
boolean installWhitelistedSystemPackages(boolean isFirstBoot, boolean isUpgrade,
@Nullable ArraySet<String> existingPackages) {
return mSystemPackageInstaller.installWhitelistedSystemPackages(
isFirstBoot, isUpgrade, existingPackages);
}
private long getCreationTime() {

View File

@@ -20,6 +20,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageParser;
import android.content.res.Resources;
@@ -74,6 +75,14 @@ import java.util.Set;
* <li>Otherwise, the package is implicitly treated as blacklisted for all users</li>
* </ul>
*
* <p>Packages are only installed/uninstalled by this mechanism when a new user is created or during
* an update. In the case of updates:<ul>
* <li>new packages are (un)installed per the whitelist/blacklist</li>
* <li>pre-existing installed blacklisted packages are never uninstalled</li>
* <li>pre-existing not-installed whitelisted packages are only installed if the reason why they
* had been previously uninstalled was due to UserSystemPackageInstaller</li>
* </ul>
*
* <p><b>NOTE:</b> the {@code SystemConfig} state is only updated on first boot or after a system
* update. So, to verify changes during development, you can emulate the latter by calling:
* <pre><code>
@@ -171,8 +180,12 @@ class UserSystemPackageInstaller {
*
* This is responsible for enforcing the whitelist for pre-existing users (i.e. USER_SYSTEM);
* enforcement for new users is done when they are created in UserManagerService.createUser().
*
* @param preExistingPackages list of packages on the device prior to the upgrade. Cannot be
* null if isUpgrade is true.
*/
boolean installWhitelistedSystemPackages(boolean isFirstBoot, boolean isUpgrade) {
boolean installWhitelistedSystemPackages(boolean isFirstBoot, boolean isUpgrade,
@Nullable ArraySet<String> preExistingPackages) {
final int mode = getWhitelistMode();
checkWhitelistedSystemPackages(mode);
final boolean isConsideredUpgrade = isUpgrade && !isIgnoreOtaMode(mode);
@@ -198,19 +211,50 @@ class UserSystemPackageInstaller {
final boolean install =
(userWhitelist == null || userWhitelist.contains(pkg.getPackageName()))
&& !pkgSetting.getPkgState().isHiddenUntilInstalled();
if (isConsideredUpgrade && !isFirstBoot && !install) {
return; // To be careful, we dont uninstall apps during OTAs
}
final boolean changed = pmInt.setInstalled(pkg, userId, install);
if (changed) {
Slog.i(TAG, (install ? "Installed " : "Uninstalled ")
+ pkg.getPackageName() + " for user " + userId);
if (pkgSetting.getInstalled(userId) == install
|| !shouldChangeInstallationState(pkgSetting, install, userId, isFirstBoot,
isConsideredUpgrade, preExistingPackages)) {
return;
}
pkgSetting.setInstalled(install, userId);
pkgSetting.setUninstallReason(
install ? PackageManager.UNINSTALL_REASON_UNKNOWN :
PackageManager.UNINSTALL_REASON_USER_TYPE,
userId);
Slog.i(TAG, (install ? "Installed " : "Uninstalled ")
+ pkg.getPackageName() + " for user " + userId);
});
}
return true;
}
/**
* Returns whether to proceed with install/uninstall for the given package.
* In particular, do not install a package unless it was only uninstalled due to the user type;
* and do not uninstall a package if it previously was installed (prior to the OTA).
*
* Should be called only within PackageManagerInternal.forEachPackageSetting() since it
* requires the LP lock.
*
* @param preOtaPkgs list of packages on the device prior to the upgrade.
* Cannot be null if isUpgrade is true.
*/
private static boolean shouldChangeInstallationState(PackageSetting pkgSetting,
boolean install,
@UserIdInt int userId,
boolean isFirstBoot,
boolean isUpgrade,
@Nullable ArraySet<String> preOtaPkgs) {
if (install) {
// Only proceed with install if we are the only reason why it had been uninstalled.
return pkgSetting.getUninstallReason(userId)
== PackageManager.UNINSTALL_REASON_USER_TYPE;
} else {
// Only proceed with uninstall if the package is new to the device.
return isFirstBoot || (isUpgrade && !preOtaPkgs.contains(pkgSetting.name));
}
}
/**
* Checks whether the system packages and the mWhitelistedPackagesForUserTypes whitelist are
* in 1-to-1 correspondence.

View File

@@ -84,6 +84,10 @@ public class PackageUserStateTest {
oldUserState = new PackageUserState();
oldUserState.suspended = true;
assertThat(testUserState.equals(oldUserState), is(false));
oldUserState = new PackageUserState();
oldUserState.uninstallReason = PackageManager.UNINSTALL_REASON_USER_TYPE;
assertThat(testUserState.equals(oldUserState), is(false));
}
@Test