Break install up into phases
Install will be broken up into four phases: 1) Prepare - Analyzes any current install state, parses the package and does initial validation on it. 2) Scan - Interrogates the parsed packages given the context collected in prepare. 3) Reconcile - Validates scanned packages in the context of each other and the current system state to ensure that the install will be successful. Any failures to reconcile will fail the install. 4) Commit - Commits all scanned packages and updates system state. This is the only place that system state may be modified in the install flow and all predictable errors must be determined before this phase. This change moves most low hanging fruit out of prepare and into one of the phase that most makes sense to own it. Bug: 109941548 Test: manual - install a few dozen apps from Play Store Test: manual - install update to GMS Core Change-Id: Ibd4acc15996d8621d16e1f94d0d5c07826f66e3d
This commit is contained in:
@@ -1048,11 +1048,14 @@ public class ComponentResolver {
|
||||
final String otherPackageName =
|
||||
(other != null && other.getComponentName() != null)
|
||||
? other.getComponentName().getPackageName() : "?";
|
||||
throw new PackageManagerException(
|
||||
INSTALL_FAILED_CONFLICTING_PROVIDER,
|
||||
"Can't install because provider name " + names[j]
|
||||
+ " (in package " + pkg.applicationInfo.packageName
|
||||
+ ") is already used by " + otherPackageName);
|
||||
// if we're installing over the same already-installed package, this is ok
|
||||
if (otherPackageName != pkg.packageName) {
|
||||
throw new PackageManagerException(
|
||||
INSTALL_FAILED_CONFLICTING_PROVIDER,
|
||||
"Can't install because provider name " + names[j]
|
||||
+ " (in package " + pkg.applicationInfo.packageName
|
||||
+ ") is already used by " + otherPackageName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -207,4 +207,13 @@ public final class PackageSetting extends PackageSettingBase {
|
||||
writeUsersInfoToProto(proto, PackageProto.USERS);
|
||||
proto.end(packageToken);
|
||||
}
|
||||
|
||||
/** Updates all fields in the current setting from another. */
|
||||
public void updateFrom(PackageSetting other) {
|
||||
super.updateFrom(other);
|
||||
appId = other.appId;
|
||||
pkg = other.pkg;
|
||||
sharedUserId = other.sharedUserId;
|
||||
sharedUser = other.sharedUser;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageParser;
|
||||
import android.content.pm.PackageUserState;
|
||||
import android.content.pm.Signature;
|
||||
import android.os.BaseBundle;
|
||||
import android.os.PersistableBundle;
|
||||
import android.service.pm.PackageProto;
|
||||
import android.util.ArraySet;
|
||||
@@ -109,7 +108,7 @@ public abstract class PackageSettingBase extends SettingBase {
|
||||
|
||||
// Whether this package is currently stopped, thus can not be
|
||||
// started until explicitly launched by the user.
|
||||
private final SparseArray<PackageUserState> userState = new SparseArray<PackageUserState>();
|
||||
private final SparseArray<PackageUserState> mUserState = new SparseArray<>();
|
||||
|
||||
/**
|
||||
* Non-persisted value. During an "upgrade without restart", we need the set
|
||||
@@ -118,7 +117,7 @@ public abstract class PackageSettingBase extends SettingBase {
|
||||
* restart, this field will be cleared since the classloader would be created
|
||||
* using the full set of code paths when the package's process is started.
|
||||
*/
|
||||
Set<String> oldCodePaths;
|
||||
Set<String> mOldCodePaths;
|
||||
|
||||
/** Package name of the app that installed this package */
|
||||
String installerPackageName;
|
||||
@@ -223,7 +222,7 @@ public abstract class PackageSettingBase extends SettingBase {
|
||||
/**
|
||||
* Makes a shallow copy of the given package settings.
|
||||
*
|
||||
* NOTE: For some fields [such as keySetData, signatures, userState, verificationInfo, etc...],
|
||||
* NOTE: For some fields [such as keySetData, signatures, mUserState, verificationInfo, etc...],
|
||||
* the original object is copied and a new one is not created.
|
||||
*/
|
||||
public void copyFrom(PackageSettingBase orig) {
|
||||
@@ -244,7 +243,7 @@ public abstract class PackageSettingBase extends SettingBase {
|
||||
keySetData = orig.keySetData;
|
||||
lastUpdateTime = orig.lastUpdateTime;
|
||||
legacyNativeLibraryPathString = orig.legacyNativeLibraryPathString;
|
||||
// Intentionally skip oldCodePaths; it's not relevant for copies
|
||||
// Intentionally skip mOldCodePaths; it's not relevant for copies
|
||||
parentPackageName = orig.parentPackageName;
|
||||
primaryCpuAbiString = orig.primaryCpuAbiString;
|
||||
resourcePath = orig.resourcePath;
|
||||
@@ -253,9 +252,9 @@ public abstract class PackageSettingBase extends SettingBase {
|
||||
signatures = orig.signatures;
|
||||
timeStamp = orig.timeStamp;
|
||||
uidError = orig.uidError;
|
||||
userState.clear();
|
||||
for (int i=0; i<orig.userState.size(); i++) {
|
||||
userState.put(orig.userState.keyAt(i), orig.userState.valueAt(i));
|
||||
mUserState.clear();
|
||||
for (int i = 0; i < orig.mUserState.size(); i++) {
|
||||
mUserState.put(orig.mUserState.keyAt(i), orig.mUserState.valueAt(i));
|
||||
}
|
||||
verificationInfo = orig.verificationInfo;
|
||||
versionCode = orig.versionCode;
|
||||
@@ -271,16 +270,16 @@ public abstract class PackageSettingBase extends SettingBase {
|
||||
}
|
||||
|
||||
private PackageUserState modifyUserState(int userId) {
|
||||
PackageUserState state = userState.get(userId);
|
||||
PackageUserState state = mUserState.get(userId);
|
||||
if (state == null) {
|
||||
state = new PackageUserState();
|
||||
userState.put(userId, state);
|
||||
mUserState.put(userId, state);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
public PackageUserState readUserState(int userId) {
|
||||
PackageUserState state = userState.get(userId);
|
||||
PackageUserState state = mUserState.get(userId);
|
||||
if (state == null) {
|
||||
return DEFAULT_USER_STATE;
|
||||
}
|
||||
@@ -330,7 +329,7 @@ public abstract class PackageSettingBase extends SettingBase {
|
||||
/** Only use for testing. Do NOT use in production code. */
|
||||
@VisibleForTesting
|
||||
SparseArray<PackageUserState> getUserState() {
|
||||
return userState;
|
||||
return mUserState;
|
||||
}
|
||||
|
||||
boolean isAnyInstalled(int[] users) {
|
||||
@@ -536,14 +535,14 @@ public abstract class PackageSettingBase extends SettingBase {
|
||||
}
|
||||
|
||||
void removeUser(int userId) {
|
||||
userState.delete(userId);
|
||||
mUserState.delete(userId);
|
||||
}
|
||||
|
||||
public int[] getNotInstalledUserIds() {
|
||||
int count = 0;
|
||||
int userStateCount = userState.size();
|
||||
int userStateCount = mUserState.size();
|
||||
for (int i = 0; i < userStateCount; i++) {
|
||||
if (userState.valueAt(i).installed == false) {
|
||||
if (!mUserState.valueAt(i).installed) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
@@ -551,8 +550,8 @@ public abstract class PackageSettingBase extends SettingBase {
|
||||
int[] excludedUserIds = new int[count];
|
||||
int idx = 0;
|
||||
for (int i = 0; i < userStateCount; i++) {
|
||||
if (userState.valueAt(i).installed == false) {
|
||||
excludedUserIds[idx++] = userState.keyAt(i);
|
||||
if (!mUserState.valueAt(i).installed) {
|
||||
excludedUserIds[idx++] = mUserState.keyAt(i);
|
||||
}
|
||||
}
|
||||
return excludedUserIds;
|
||||
@@ -591,11 +590,11 @@ public abstract class PackageSettingBase extends SettingBase {
|
||||
}
|
||||
|
||||
protected void writeUsersInfoToProto(ProtoOutputStream proto, long fieldId) {
|
||||
int count = userState.size();
|
||||
int count = mUserState.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
final long userToken = proto.start(fieldId);
|
||||
final int userId = userState.keyAt(i);
|
||||
final PackageUserState state = userState.valueAt(i);
|
||||
final int userId = mUserState.keyAt(i);
|
||||
final PackageUserState state = mUserState.valueAt(i);
|
||||
proto.write(PackageProto.UserInfoProto.ID, userId);
|
||||
final int installType;
|
||||
if (state.instantApp) {
|
||||
@@ -630,4 +629,48 @@ public abstract class PackageSettingBase extends SettingBase {
|
||||
PackageUserState userState = readUserState(userId);
|
||||
return userState.harmfulAppWarning;
|
||||
}
|
||||
|
||||
protected PackageSettingBase updateFrom(PackageSettingBase other) {
|
||||
super.copyFrom(other);
|
||||
this.parentPackageName = other.parentPackageName;
|
||||
this.childPackageNames = other.childPackageNames;
|
||||
this.codePath = other.codePath;
|
||||
this.codePathString = other.codePathString;
|
||||
this.resourcePath = other.resourcePath;
|
||||
this.resourcePathString = other.resourcePathString;
|
||||
this.usesStaticLibraries = other.usesStaticLibraries;
|
||||
this.usesStaticLibrariesVersions = other.usesStaticLibrariesVersions;
|
||||
this.legacyNativeLibraryPathString = other.legacyNativeLibraryPathString;
|
||||
this.primaryCpuAbiString = other.primaryCpuAbiString;
|
||||
this.secondaryCpuAbiString = other.secondaryCpuAbiString;
|
||||
this.cpuAbiOverrideString = other.cpuAbiOverrideString;
|
||||
this.timeStamp = other.timeStamp;
|
||||
this.firstInstallTime = other.firstInstallTime;
|
||||
this.lastUpdateTime = other.lastUpdateTime;
|
||||
this.versionCode = other.versionCode;
|
||||
this.uidError = other.uidError;
|
||||
this.signatures = other.signatures;
|
||||
this.installPermissionsFixed = other.installPermissionsFixed;
|
||||
this.keySetData = other.keySetData;
|
||||
this.installerPackageName = other.installerPackageName;
|
||||
this.isOrphaned = other.isOrphaned;
|
||||
this.volumeUuid = other.volumeUuid;
|
||||
this.categoryHint = other.categoryHint;
|
||||
this.updateAvailable = other.updateAvailable;
|
||||
this.verificationInfo = other.verificationInfo;
|
||||
|
||||
if (mOldCodePaths != null) {
|
||||
if (other.mOldCodePaths != null) {
|
||||
mOldCodePaths.clear();
|
||||
mOldCodePaths.addAll(other.mOldCodePaths);
|
||||
} else {
|
||||
mOldCodePaths = null;
|
||||
}
|
||||
}
|
||||
mUserState.clear();
|
||||
for (int i = 0; i < other.mUserState.size(); i++) {
|
||||
mUserState.put(other.mUserState.keyAt(i), other.mUserState.valueAt(i));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -539,16 +539,18 @@ public final class Settings {
|
||||
if((p.pkg != null) && (p.pkg.applicationInfo != null)) {
|
||||
p.pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
|
||||
}
|
||||
mDisabledSysPackages.put(name, p);
|
||||
|
||||
final PackageSetting disabled;
|
||||
if (replaced) {
|
||||
// a little trick... when we install the new package, we don't
|
||||
// want to modify the existing PackageSetting for the built-in
|
||||
// version. so at this point we need a new PackageSetting that
|
||||
// is okay to muck with.
|
||||
PackageSetting newp = new PackageSetting(p);
|
||||
replacePackageLPw(name, newp);
|
||||
// version. so at this point we make a copy to place into the
|
||||
// disabled set.
|
||||
disabled = new PackageSetting(p);
|
||||
} else {
|
||||
disabled = p;
|
||||
}
|
||||
mDisabledSysPackages.put(name, disabled);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -1105,19 +1107,6 @@ public final class Settings {
|
||||
mInstallerPackages.remove(packageName);
|
||||
}
|
||||
|
||||
private void replacePackageLPw(String name, PackageSetting newp) {
|
||||
final PackageSetting p = mPackages.get(name);
|
||||
if (p != null) {
|
||||
if (p.sharedUser != null) {
|
||||
p.sharedUser.removePackage(p);
|
||||
p.sharedUser.addPackage(newp);
|
||||
} else {
|
||||
replaceUserIdLPw(p.appId, newp);
|
||||
}
|
||||
}
|
||||
mPackages.put(name, newp);
|
||||
}
|
||||
|
||||
private boolean addUserIdLPw(int uid, Object obj, Object name) {
|
||||
if (uid > Process.LAST_APPLICATION_UID) {
|
||||
return false;
|
||||
|
||||
@@ -24,7 +24,6 @@ import android.util.ArraySet;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -69,24 +68,26 @@ public final class SharedUserSetting extends SettingBase {
|
||||
proto.end(token);
|
||||
}
|
||||
|
||||
void removePackage(PackageSetting packageSetting) {
|
||||
if (packages.remove(packageSetting)) {
|
||||
// recalculate the pkgFlags for this shared user if needed
|
||||
if ((this.pkgFlags & packageSetting.pkgFlags) != 0) {
|
||||
int aggregatedFlags = uidFlags;
|
||||
for (PackageSetting ps : packages) {
|
||||
aggregatedFlags |= ps.pkgFlags;
|
||||
}
|
||||
setFlags(aggregatedFlags);
|
||||
}
|
||||
if ((this.pkgPrivateFlags & packageSetting.pkgPrivateFlags) != 0) {
|
||||
int aggregatedPrivateFlags = uidPrivateFlags;
|
||||
for (PackageSetting ps : packages) {
|
||||
aggregatedPrivateFlags |= ps.pkgPrivateFlags;
|
||||
}
|
||||
setPrivateFlags(aggregatedPrivateFlags);
|
||||
}
|
||||
boolean removePackage(PackageSetting packageSetting) {
|
||||
if (!packages.remove(packageSetting)) {
|
||||
return false;
|
||||
}
|
||||
// recalculate the pkgFlags for this shared user if needed
|
||||
if ((this.pkgFlags & packageSetting.pkgFlags) != 0) {
|
||||
int aggregatedFlags = uidFlags;
|
||||
for (PackageSetting ps : packages) {
|
||||
aggregatedFlags |= ps.pkgFlags;
|
||||
}
|
||||
setFlags(aggregatedFlags);
|
||||
}
|
||||
if ((this.pkgPrivateFlags & packageSetting.pkgPrivateFlags) != 0) {
|
||||
int aggregatedPrivateFlags = uidPrivateFlags;
|
||||
for (PackageSetting ps : packages) {
|
||||
aggregatedPrivateFlags |= ps.pkgPrivateFlags;
|
||||
}
|
||||
setPrivateFlags(aggregatedPrivateFlags);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void addPackage(PackageSetting packageSetting) {
|
||||
@@ -143,4 +144,16 @@ public final class SharedUserSetting extends SettingBase {
|
||||
}
|
||||
}
|
||||
|
||||
/** Updates all fields in this shared user setting from another. */
|
||||
public SharedUserSetting updateFrom(SharedUserSetting sharedUser) {
|
||||
copyFrom(sharedUser);
|
||||
this.userId = sharedUser.userId;
|
||||
this.uidFlags = sharedUser.uidFlags;
|
||||
this.uidPrivateFlags = sharedUser.uidPrivateFlags;
|
||||
this.seInfoTargetSdkVersion = sharedUser.seInfoTargetSdkVersion;
|
||||
this.packages.clear();
|
||||
this.packages.addAll(sharedUser.packages);
|
||||
this.signaturesChanged = sharedUser.signaturesChanged;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -716,9 +716,9 @@ public class PackageManagerSettingsTests {
|
||||
assertNotSame(origPkgSetting.mPermissionsState, testPkgSetting.mPermissionsState);
|
||||
assertThat(origPkgSetting.mPermissionsState, is(testPkgSetting.mPermissionsState));
|
||||
assertThat(origPkgSetting.name, is(testPkgSetting.name));
|
||||
// oldCodePaths is _not_ copied
|
||||
// assertNotSame(origPkgSetting.oldCodePaths, testPkgSetting.oldCodePaths);
|
||||
// assertThat(origPkgSetting.oldCodePaths, is(not(testPkgSetting.oldCodePaths)));
|
||||
// mOldCodePaths is _not_ copied
|
||||
// assertNotSame(origPkgSetting.mOldCodePaths, testPkgSetting.mOldCodePaths);
|
||||
// assertThat(origPkgSetting.mOldCodePaths, is(not(testPkgSetting.mOldCodePaths)));
|
||||
assertSame(origPkgSetting.parentPackageName, testPkgSetting.parentPackageName);
|
||||
assertThat(origPkgSetting.parentPackageName, is(testPkgSetting.parentPackageName));
|
||||
assertSame(origPkgSetting.pkg, testPkgSetting.pkg);
|
||||
|
||||
Reference in New Issue
Block a user