diff options
6 files changed, 128 insertions, 40 deletions
diff --git a/services/core/java/com/android/server/pm/InstallSource.java b/services/core/java/com/android/server/pm/InstallSource.java index 0541797523a4..6684e3f8973e 100644 --- a/services/core/java/com/android/server/pm/InstallSource.java +++ b/services/core/java/com/android/server/pm/InstallSource.java @@ -18,6 +18,8 @@ package com.android.server.pm; import android.annotation.Nullable; +import com.android.internal.util.Preconditions; + import java.util.Objects; /** @@ -29,16 +31,27 @@ 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 * app that performed the download. This value is provided by the initiating package and not @@ -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 diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index e2dfa126225f..c43f23454ca6 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -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, diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 426cd01d3d0b..2548841ebfbf 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -1452,7 +1452,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, @@ -3115,7 +3115,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, diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 6bd9c4847a77..a9571d97200c 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -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); diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index f9a336166825..ec84b51577f9 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -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 { diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java index c478ec472e61..15327b6e5463 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java @@ -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, |