Merge "Preserve install initiatior package on uninstall."
This commit is contained in:
@@ -18,6 +18,8 @@ package com.android.server.pm;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
@@ -29,15 +31,26 @@ final class InstallSource {
|
||||
* An instance of InstallSource representing an absence of knowledge of the source of
|
||||
* a package. Used in preference to null.
|
||||
*/
|
||||
static final InstallSource EMPTY = new InstallSource(null, null, null, false);
|
||||
static final InstallSource EMPTY = new InstallSource(null, null, null, false, false, null);
|
||||
|
||||
/** We also memoize this case because it is common - all un-updated system apps. */
|
||||
private static final InstallSource EMPTY_ORPHANED = new InstallSource(null, null, null, true);
|
||||
private static final InstallSource EMPTY_ORPHANED = new InstallSource(
|
||||
null, null, null, true, false, null);
|
||||
|
||||
/** The package that requested the installation, if known. */
|
||||
/**
|
||||
* The package that requested the installation, if known. May not correspond to a currently
|
||||
* installed package if {@link #isInitiatingPackageUninstalled} is true.
|
||||
*/
|
||||
@Nullable
|
||||
final String initiatingPackageName;
|
||||
|
||||
/**
|
||||
* The signing details of the initiating package, if known. Always null if
|
||||
* {@link #initiatingPackageName} is null.
|
||||
*/
|
||||
@Nullable
|
||||
final PackageSignatures initiatingPackageSignatures;
|
||||
|
||||
/**
|
||||
* The package on behalf of which the initiating package requested the installation, if any.
|
||||
* For example if a downloaded APK is installed via the Package Installer this could be the
|
||||
@@ -57,76 +70,120 @@ final class InstallSource {
|
||||
/** Indicates if the package that was the installerPackageName has been uninstalled. */
|
||||
final boolean isOrphaned;
|
||||
|
||||
/**
|
||||
* Indicates if the package in initiatingPackageName has been uninstalled. Always false if
|
||||
* {@link #initiatingPackageName} is null.
|
||||
*/
|
||||
final boolean isInitiatingPackageUninstalled;
|
||||
|
||||
static InstallSource create(@Nullable String initiatingPackageName,
|
||||
@Nullable String originatingPackageName, @Nullable String installerPackageName) {
|
||||
return create(initiatingPackageName, originatingPackageName, installerPackageName,
|
||||
false, false);
|
||||
}
|
||||
|
||||
static InstallSource create(@Nullable String initiatingPackageName,
|
||||
@Nullable String originatingPackageName, @Nullable String installerPackageName,
|
||||
boolean isOrphaned) {
|
||||
boolean isOrphaned, boolean isInitiatingPackageUninstalled) {
|
||||
return createInternal(
|
||||
intern(initiatingPackageName),
|
||||
intern(originatingPackageName),
|
||||
intern(installerPackageName),
|
||||
isOrphaned);
|
||||
isOrphaned, isInitiatingPackageUninstalled, null);
|
||||
}
|
||||
|
||||
private static InstallSource createInternal(@Nullable String initiatingPackageName,
|
||||
@Nullable String originatingPackageName, @Nullable String installerPackageName,
|
||||
boolean isOrphaned) {
|
||||
boolean isOrphaned, boolean isInitiatingPackageUninstalled,
|
||||
@Nullable PackageSignatures initiatingPackageSignatures) {
|
||||
if (initiatingPackageName == null && originatingPackageName == null
|
||||
&& installerPackageName == null) {
|
||||
&& installerPackageName == null && initiatingPackageSignatures == null
|
||||
&& !isInitiatingPackageUninstalled) {
|
||||
return isOrphaned ? EMPTY_ORPHANED : EMPTY;
|
||||
}
|
||||
return new InstallSource(initiatingPackageName, originatingPackageName,
|
||||
installerPackageName, isOrphaned);
|
||||
installerPackageName, isOrphaned, isInitiatingPackageUninstalled,
|
||||
initiatingPackageSignatures
|
||||
);
|
||||
}
|
||||
|
||||
private InstallSource(@Nullable String initiatingPackageName,
|
||||
@Nullable String originatingPackageName, @Nullable String installerPackageName,
|
||||
boolean isOrphaned) {
|
||||
boolean isOrphaned, boolean isInitiatingPackageUninstalled,
|
||||
@Nullable PackageSignatures initiatingPackageSignatures) {
|
||||
if (initiatingPackageName == null) {
|
||||
Preconditions.checkArgument(initiatingPackageSignatures == null);
|
||||
Preconditions.checkArgument(!isInitiatingPackageUninstalled);
|
||||
}
|
||||
this.initiatingPackageName = initiatingPackageName;
|
||||
this.originatingPackageName = originatingPackageName;
|
||||
this.installerPackageName = installerPackageName;
|
||||
this.isOrphaned = isOrphaned;
|
||||
this.isInitiatingPackageUninstalled = isInitiatingPackageUninstalled;
|
||||
this.initiatingPackageSignatures = initiatingPackageSignatures;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an InstallSource the same as this one except with the specified installerPackageName.
|
||||
* Return an InstallSource the same as this one except with the specified
|
||||
* {@link #installerPackageName}.
|
||||
*/
|
||||
InstallSource setInstallerPackage(String installerPackageName) {
|
||||
InstallSource setInstallerPackage(@Nullable String installerPackageName) {
|
||||
if (Objects.equals(installerPackageName, this.installerPackageName)) {
|
||||
return this;
|
||||
}
|
||||
return createInternal(initiatingPackageName, originatingPackageName,
|
||||
intern(installerPackageName), isOrphaned);
|
||||
intern(installerPackageName), isOrphaned, isInitiatingPackageUninstalled,
|
||||
initiatingPackageSignatures
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an InstallSource the same as this one except with the specified value for isOrphaned.
|
||||
* Return an InstallSource the same as this one except with the specified value for
|
||||
* {@link #isOrphaned}.
|
||||
*/
|
||||
InstallSource setIsOrphaned(boolean isOrphaned) {
|
||||
if (isOrphaned == this.isOrphaned) {
|
||||
return this;
|
||||
}
|
||||
return createInternal(initiatingPackageName, originatingPackageName, installerPackageName,
|
||||
isOrphaned);
|
||||
isOrphaned, isInitiatingPackageUninstalled, initiatingPackageSignatures);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an InstallSource the same as this one except it does not refer to the specified
|
||||
* installer package name (which is being uninstalled).
|
||||
* Return an InstallSource the same as this one except with the specified
|
||||
* {@link #initiatingPackageSignatures}.
|
||||
*/
|
||||
InstallSource removeInstallerPackage(String packageName) {
|
||||
InstallSource setInitiatingPackageSignatures(@Nullable PackageSignatures signatures) {
|
||||
if (signatures == initiatingPackageSignatures) {
|
||||
return this;
|
||||
}
|
||||
return createInternal(initiatingPackageName, originatingPackageName, installerPackageName,
|
||||
isOrphaned, isInitiatingPackageUninstalled, signatures);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an InstallSource the same as this one updated to reflect that the specified installer
|
||||
* package name has been uninstalled.
|
||||
*/
|
||||
InstallSource removeInstallerPackage(@Nullable String packageName) {
|
||||
if (packageName == null) {
|
||||
return this;
|
||||
}
|
||||
|
||||
boolean modified = false;
|
||||
String initiatingPackageName = this.initiatingPackageName;
|
||||
boolean isInitiatingPackageUninstalled = this.isInitiatingPackageUninstalled;
|
||||
String originatingPackageName = this.originatingPackageName;
|
||||
String installerPackageName = this.installerPackageName;
|
||||
boolean isOrphaned = this.isOrphaned;
|
||||
|
||||
if (packageName.equals(initiatingPackageName)) {
|
||||
initiatingPackageName = null;
|
||||
modified = true;
|
||||
if (packageName.equals(this.initiatingPackageName)) {
|
||||
if (!isInitiatingPackageUninstalled) {
|
||||
// In this case we deliberately do not clear the package name (and signatures).
|
||||
// We allow an app to retrieve details of its own install initiator even after
|
||||
// it has been uninstalled.
|
||||
isInitiatingPackageUninstalled = true;
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
if (packageName.equals(originatingPackageName)) {
|
||||
originatingPackageName = null;
|
||||
@@ -141,8 +198,9 @@ final class InstallSource {
|
||||
if (!modified) {
|
||||
return this;
|
||||
}
|
||||
|
||||
return createInternal(initiatingPackageName, originatingPackageName, installerPackageName,
|
||||
isOrphaned);
|
||||
isOrphaned, isInitiatingPackageUninstalled, initiatingPackageSignatures);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -635,7 +635,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
|
||||
}
|
||||
}
|
||||
InstallSource installSource = InstallSource.create(installerPackageName,
|
||||
originatingPackageName, requestedInstallerPackageName, false);
|
||||
originatingPackageName, requestedInstallerPackageName);
|
||||
session = new PackageInstallerSession(mInternalCallback, mContext, mPm, this,
|
||||
mInstallThread.getLooper(), mStagingManager, sessionId, userId, callingUid,
|
||||
installSource, params, createdMillis,
|
||||
|
||||
@@ -1475,7 +1475,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
}
|
||||
|
||||
mInstallerUid = uid;
|
||||
mInstallSource = InstallSource.create(packageName, null, packageName, false);
|
||||
mInstallSource = InstallSource.create(packageName, null, packageName);
|
||||
}
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
onSessionTransferStatus(statusReceiver, packageName,
|
||||
@@ -3138,7 +3138,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
}
|
||||
|
||||
InstallSource installSource = InstallSource.create(installInitiatingPackageName,
|
||||
installOriginatingPackageName, installerPackageName, false);
|
||||
installOriginatingPackageName, installerPackageName);
|
||||
return new PackageInstallerSession(callback, context, pm, sessionProvider,
|
||||
installerThread, stagingManager, sessionId, userId, installerUid,
|
||||
installSource, params, createdMillis, stageDir, stageCid, fileInfosArray,
|
||||
|
||||
@@ -15158,10 +15158,10 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "updateSettings");
|
||||
|
||||
final String pkgName = pkg.getPackageName();
|
||||
final InstallSource installSource = installArgs.installSource;
|
||||
final String installerPackageName = installSource.installerPackageName;
|
||||
final int[] installedForUsers = res.origUsers;
|
||||
final int installReason = installArgs.installReason;
|
||||
InstallSource installSource = installArgs.installSource;
|
||||
final String installerPackageName = installSource.installerPackageName;
|
||||
|
||||
if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + pkg.getCodePath());
|
||||
synchronized (mLock) {
|
||||
@@ -15207,6 +15207,14 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, userId, installerPackageName);
|
||||
}
|
||||
|
||||
if (installSource.initiatingPackageName != null) {
|
||||
final PackageSetting ips = mSettings.mPackages.get(
|
||||
installSource.initiatingPackageName);
|
||||
if (ips != null) {
|
||||
installSource = installSource.setInitiatingPackageSignatures(
|
||||
ips.signatures);
|
||||
}
|
||||
}
|
||||
ps.setInstallSource(installSource);
|
||||
mSettings.addInstallerPackageNames(installSource);
|
||||
|
||||
@@ -19976,19 +19984,25 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
// All installSource strings are interned, so == is ok here
|
||||
if (installSource.initiatingPackageName == installSource.installerPackageName) {
|
||||
// The installer and initiator will often be the same, and when they are
|
||||
// we can skip doing the same check again.
|
||||
initiatingPackageName = installerPackageName;
|
||||
if (installSource.isInitiatingPackageUninstalled) {
|
||||
// TODO(b/146555198) Allow the app itself to see the info
|
||||
// (at least for non-instant apps)
|
||||
initiatingPackageName = null;
|
||||
} else {
|
||||
initiatingPackageName = installSource.initiatingPackageName;
|
||||
final PackageSetting ps = mSettings.mPackages.get(initiatingPackageName);
|
||||
if (ps == null || shouldFilterApplicationLocked(ps, callingUid, userId)) {
|
||||
initiatingPackageName = null;
|
||||
// All installSource strings are interned, so == is ok here
|
||||
if (installSource.initiatingPackageName == installSource.installerPackageName) {
|
||||
// The installer and initiator will often be the same, and when they are
|
||||
// we can skip doing the same check again.
|
||||
initiatingPackageName = installerPackageName;
|
||||
} else {
|
||||
initiatingPackageName = installSource.initiatingPackageName;
|
||||
final PackageSetting ps = mSettings.mPackages.get(initiatingPackageName);
|
||||
if (ps == null || shouldFilterApplicationLocked(ps, callingUid, userId)) {
|
||||
initiatingPackageName = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
originatingPackageName = installSource.originatingPackageName;
|
||||
if (originatingPackageName != null) {
|
||||
final PackageSetting ps = mSettings.mPackages.get(originatingPackageName);
|
||||
|
||||
@@ -2819,6 +2819,9 @@ public final class Settings {
|
||||
if (installSource.initiatingPackageName != null) {
|
||||
serializer.attribute(null, "installInitiator", installSource.initiatingPackageName);
|
||||
}
|
||||
if (installSource.isInitiatingPackageUninstalled) {
|
||||
serializer.attribute(null, "installInitiatorUninstalled", "true");
|
||||
}
|
||||
if (installSource.originatingPackageName != null) {
|
||||
serializer.attribute(null, "installOriginator", installSource.originatingPackageName);
|
||||
}
|
||||
@@ -2836,6 +2839,11 @@ public final class Settings {
|
||||
|
||||
pkg.signatures.writeXml(serializer, "sigs", mPastSignatures);
|
||||
|
||||
if (installSource.initiatingPackageSignatures != null) {
|
||||
installSource.initiatingPackageSignatures.writeXml(
|
||||
serializer, "install-initiator-sigs", mPastSignatures);
|
||||
}
|
||||
|
||||
writePermissionsLPr(serializer, pkg.getPermissionsState().getInstallPermissionStates());
|
||||
|
||||
writeSigningKeySetLPr(serializer, pkg.keySetData);
|
||||
@@ -3571,6 +3579,7 @@ public final class Settings {
|
||||
String isOrphaned = null;
|
||||
String installOriginatingPackageName = null;
|
||||
String installInitiatingPackageName = null;
|
||||
String installInitiatorUninstalled = null;
|
||||
String volumeUuid = null;
|
||||
String categoryHintString = null;
|
||||
String updateAvailable = null;
|
||||
@@ -3616,6 +3625,8 @@ public final class Settings {
|
||||
isOrphaned = parser.getAttributeValue(null, "isOrphaned");
|
||||
installInitiatingPackageName = parser.getAttributeValue(null, "installInitiator");
|
||||
installOriginatingPackageName = parser.getAttributeValue(null, "installOriginator");
|
||||
installInitiatorUninstalled = parser.getAttributeValue(null,
|
||||
"installInitiatorUninstalled");
|
||||
volumeUuid = parser.getAttributeValue(null, "volumeUuid");
|
||||
categoryHintString = parser.getAttributeValue(null, "categoryHint");
|
||||
if (categoryHintString != null) {
|
||||
@@ -3772,7 +3783,8 @@ public final class Settings {
|
||||
packageSetting.uidError = "true".equals(uidError);
|
||||
InstallSource installSource = InstallSource.create(
|
||||
installInitiatingPackageName, installOriginatingPackageName,
|
||||
installerPackageName, "true".equals(isOrphaned));
|
||||
installerPackageName, "true".equals(isOrphaned),
|
||||
"true".equals(installInitiatorUninstalled));
|
||||
packageSetting.installSource = installSource;
|
||||
packageSetting.volumeUuid = volumeUuid;
|
||||
packageSetting.categoryHint = categoryHint;
|
||||
@@ -3849,6 +3861,11 @@ public final class Settings {
|
||||
mKeySetRefs.put(id, 1);
|
||||
}
|
||||
packageSetting.keySetData.addDefinedKeySet(id, alias);
|
||||
} else if (tagName.equals("install-initiator-sigs")) {
|
||||
final PackageSignatures signatures = new PackageSignatures();
|
||||
signatures.readXml(parser, mPastSignatures);
|
||||
packageSetting.installSource =
|
||||
packageSetting.installSource.setInitiatingPackageSignatures(signatures);
|
||||
} else if (tagName.equals(TAG_DOMAIN_VERIFICATION)) {
|
||||
readDomainVerificationLPw(parser, packageSetting);
|
||||
} else {
|
||||
|
||||
@@ -156,8 +156,7 @@ public class PackageInstallerSessionTest {
|
||||
if (isMultiPackage) {
|
||||
params.isMultiPackage = true;
|
||||
}
|
||||
InstallSource installSource = InstallSource.create("testInstaller", null, "testInstaller",
|
||||
false);
|
||||
InstallSource installSource = InstallSource.create("testInstaller", null, "testInstaller");
|
||||
return new PackageInstallerSession(
|
||||
/* callback */ null,
|
||||
/* context */null,
|
||||
|
||||
Reference in New Issue
Block a user