diff options
19 files changed, 283 insertions, 47 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index c147be9b3caf..1acab8a443b0 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -88,6 +88,7 @@ package android { field public static final String DIAGNOSTIC = "android.permission.DIAGNOSTIC"; field public static final String DISABLE_KEYGUARD = "android.permission.DISABLE_KEYGUARD"; field public static final String DUMP = "android.permission.DUMP"; + field public static final String ENFORCE_UPDATE_OWNERSHIP = "android.permission.ENFORCE_UPDATE_OWNERSHIP"; field public static final String EXPAND_STATUS_BAR = "android.permission.EXPAND_STATUS_BAR"; field public static final String FACTORY_TEST = "android.permission.FACTORY_TEST"; field public static final String FOREGROUND_SERVICE = "android.permission.FOREGROUND_SERVICE"; @@ -11691,6 +11692,7 @@ package android.content.pm { method @Nullable public String getInstallingPackageName(); method @Nullable public String getOriginatingPackageName(); method public int getPackageSource(); + method @Nullable public String getUpdateOwnerPackageName(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.InstallSourceInfo> CREATOR; } @@ -11981,6 +11983,7 @@ package android.content.pm { method public int getParentSessionId(); method public boolean isKeepApplicationEnabledSetting(); method public boolean isMultiPackage(); + method public boolean isRequestUpdateOwnership(); method public boolean isStaged(); method @NonNull public java.io.InputStream openRead(@NonNull String) throws java.io.IOException; method @NonNull public java.io.OutputStream openWrite(@NonNull String, long, long) throws java.io.IOException; @@ -12036,6 +12039,7 @@ package android.content.pm { method public boolean isCommitted(); method public boolean isKeepApplicationEnabledSetting(); method public boolean isMultiPackage(); + method public boolean isRequestUpdateOwnership(); method public boolean isSealed(); method public boolean isStaged(); method public boolean isStagedSessionActive(); @@ -12074,6 +12078,7 @@ package android.content.pm { method public void setOriginatingUri(@Nullable android.net.Uri); method public void setPackageSource(int); method public void setReferrerUri(@Nullable android.net.Uri); + method @RequiresPermission(android.Manifest.permission.ENFORCE_UPDATE_OWNERSHIP) public void setRequestUpdateOwnership(boolean); method public void setRequireUserAction(int); method public void setSize(long); method public void setWhitelistedRestrictedPermissions(@Nullable java.util.Set<java.lang.String>); diff --git a/core/java/android/content/pm/IPackageInstallerSession.aidl b/core/java/android/content/pm/IPackageInstallerSession.aidl index 60a7b13ff6e9..c9a56324de79 100644 --- a/core/java/android/content/pm/IPackageInstallerSession.aidl +++ b/core/java/android/content/pm/IPackageInstallerSession.aidl @@ -63,6 +63,7 @@ interface IPackageInstallerSession { void requestUserPreapproval(in PackageInstaller.PreapprovalDetails details, in IntentSender statusReceiver); boolean isKeepApplicationEnabledSetting(); + boolean isRequestUpdateOwnership(); ParcelFileDescriptor getAppMetadataFd(); ParcelFileDescriptor openWriteAppMetadata(); diff --git a/core/java/android/content/pm/InstallSourceInfo.java b/core/java/android/content/pm/InstallSourceInfo.java index 88f1a16ec3ab..67123e87a265 100644 --- a/core/java/android/content/pm/InstallSourceInfo.java +++ b/core/java/android/content/pm/InstallSourceInfo.java @@ -35,6 +35,8 @@ public final class InstallSourceInfo implements Parcelable { @Nullable private final String mInstallingPackageName; + @Nullable private final String mUpdateOwnerPackageName; + @Nullable private final int mPackageSource; /** @hide */ @@ -42,18 +44,20 @@ public final class InstallSourceInfo implements Parcelable { @Nullable SigningInfo initiatingPackageSigningInfo, @Nullable String originatingPackageName, @Nullable String installingPackageName) { this(initiatingPackageName, initiatingPackageSigningInfo, originatingPackageName, - installingPackageName, PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED); + installingPackageName, null /* updateOwnerPackageName */, + PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED); } /** @hide */ public InstallSourceInfo(@Nullable String initiatingPackageName, @Nullable SigningInfo initiatingPackageSigningInfo, @Nullable String originatingPackageName, @Nullable String installingPackageName, - int packageSource) { + @Nullable String updateOwnerPackageName, int packageSource) { mInitiatingPackageName = initiatingPackageName; mInitiatingPackageSigningInfo = initiatingPackageSigningInfo; mOriginatingPackageName = originatingPackageName; mInstallingPackageName = installingPackageName; + mUpdateOwnerPackageName = updateOwnerPackageName; mPackageSource = packageSource; } @@ -69,6 +73,7 @@ public final class InstallSourceInfo implements Parcelable { dest.writeParcelable(mInitiatingPackageSigningInfo, flags); dest.writeString(mOriginatingPackageName); dest.writeString(mInstallingPackageName); + dest.writeString8(mUpdateOwnerPackageName); dest.writeInt(mPackageSource); } @@ -77,6 +82,7 @@ public final class InstallSourceInfo implements Parcelable { mInitiatingPackageSigningInfo = source.readParcelable(SigningInfo.class.getClassLoader(), android.content.pm.SigningInfo.class); mOriginatingPackageName = source.readString(); mInstallingPackageName = source.readString(); + mUpdateOwnerPackageName = source.readString8(); mPackageSource = source.readInt(); } @@ -137,6 +143,21 @@ public final class InstallSourceInfo implements Parcelable { } /** + * The name of the package that is the update owner, or null if not available. + * + * This indicates the update ownership enforcement is enabled for this app, + * and which package is the update owner. + * + * Returns null if the update ownership enforcement is disabled for the app. + * + * @see PackageInstaller.SessionParams#setRequestUpdateOwnership + */ + @Nullable + public String getUpdateOwnerPackageName() { + return mUpdateOwnerPackageName; + } + + /** * Information about the package source when installer installed this app. */ public @PackageInstaller.PackageSourceType int getPackageSource() { diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index 703a92523cf5..8f295633e01a 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -1910,6 +1910,20 @@ public class PackageInstaller { throw e.rethrowFromSystemServer(); } } + + /** + * @return {@code true} if the installer requested the update ownership enforcement + * for the packages in this session. + * + * @see PackageInstaller.SessionParams#setRequestUpdateOwnership + */ + public boolean isRequestUpdateOwnership() { + try { + return mSession.isRequestUpdateOwnership(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } /** @@ -2713,6 +2727,30 @@ public class PackageInstaller { this.keepApplicationEnabledSetting = true; } + /** + * Optionally indicate whether the package being installed needs the update ownership + * enforcement. Once the update ownership enforcement is enabled, the other installers + * will need the user action to update the package even if the installers have been + * granted the {@link android.Manifest.permission#INSTALL_PACKAGES INSTALL_PACKAGES} + * permission. Default to {@code false}. + * + * The update ownership enforcement can only be enabled on initial installation. Set + * this to {@code true} on package update indicates the installer package wants to be + * the update owner if the update ownership enforcement has enabled. + * + * Note: To enable the update ownership enforcement, the installer must have the + * {@link android.Manifest.permission#ENFORCE_UPDATE_OWNERSHIP ENFORCE_UPDATE_OWNERSHIP} + * permission. + */ + @RequiresPermission(Manifest.permission.ENFORCE_UPDATE_OWNERSHIP) + public void setRequestUpdateOwnership(boolean enable) { + if (enable) { + this.installFlags |= PackageManager.INSTALL_REQUEST_UPDATE_OWNERSHIP; + } else { + this.installFlags &= ~PackageManager.INSTALL_REQUEST_UPDATE_OWNERSHIP; + } + } + /** {@hide} */ public void dump(IndentingPrintWriter pw) { pw.printPair("mode", mode); @@ -3585,6 +3623,16 @@ public class PackageInstaller { return isPreapprovalRequested; } + /** + * @return {@code true} if the installer requested the update ownership enforcement + * for the packages in this session. + * + * @see PackageInstaller.SessionParams#setRequestUpdateOwnership + */ + public boolean isRequestUpdateOwnership() { + return (installFlags & PackageManager.INSTALL_REQUEST_UPDATE_OWNERSHIP) != 0; + } + @Override public int describeContents() { return 0; diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 7cc8af7fcab0..030537510cee 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -1355,6 +1355,7 @@ public abstract class PackageManager { INSTALL_ENABLE_ROLLBACK, INSTALL_ALLOW_DOWNGRADE, INSTALL_STAGED, + INSTALL_REQUEST_UPDATE_OWNERSHIP, }) @Retention(RetentionPolicy.SOURCE) public @interface InstallFlags {} @@ -1553,6 +1554,13 @@ public abstract class PackageManager { */ public static final int INSTALL_BYPASS_LOW_TARGET_SDK_BLOCK = 0x00800000; + /** + * Flag parameter for {@link PackageInstaller.SessionParams} to indicate that the + * update ownership enforcement is requested. + * @hide + */ + public static final int INSTALL_REQUEST_UPDATE_OWNERSHIP = 1 << 25; + /** @hide */ @IntDef(flag = true, value = { DONT_KILL_APP, diff --git a/core/proto/android/service/package.proto b/core/proto/android/service/package.proto index 1dedbb9362a3..0fe2a6bebb49 100644 --- a/core/proto/android/service/package.proto +++ b/core/proto/android/service/package.proto @@ -124,6 +124,9 @@ message PackageProto { // The package on behalf of which the initiiating package requested the install. optional string originating_package_name = 2; + + // The package that is the update owner. + optional string update_owner_package_name = 3; } message StatesProto { diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 5136fcbab7dd..2a697fe99a6c 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -6815,6 +6815,16 @@ android:protectionLevel="normal" /> <uses-permission android:name="android.permission.UPDATE_PACKAGES_WITHOUT_USER_ACTION"/> + <!-- Allows an application to indicate via {@link + android.content.pm.PackageInstaller.SessionParams#setRequestUpdateOwnership} + that it has the intention of becoming the update owner. + <p>Protection level: normal + --> + <permission android:name="android.permission.ENFORCE_UPDATE_OWNERSHIP" + android:protectionLevel="normal" /> + <uses-permission android:name="android.permission.ENFORCE_UPDATE_OWNERSHIP" /> + + <!-- Allows an application to take screenshots of layers that normally would be blacked out when a screenshot is taken. Specifically, layers that have the flag {@link android.view.SurfaceControl#SECURE} will be screenshot if the caller requests to diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java index 0eac9ef5e1a2..c6700e62afa0 100644 --- a/services/core/java/com/android/server/pm/ComputerEngine.java +++ b/services/core/java/com/android/server/pm/ComputerEngine.java @@ -4981,6 +4981,7 @@ public class ComputerEngine implements Computer { String installerPackageName; String initiatingPackageName; String originatingPackageName; + String updateOwnerPackageName; final InstallSource installSource = getInstallSource(packageName, callingUid, userId); if (installSource == null) { @@ -4996,6 +4997,15 @@ public class ComputerEngine implements Computer { } } + updateOwnerPackageName = installSource.mUpdateOwnerPackageName; + if (updateOwnerPackageName != null) { + final PackageStateInternal ps = mSettings.getPackage(updateOwnerPackageName); + if (ps == null + || shouldFilterApplicationIncludingUninstalled(ps, callingUid, userId)) { + updateOwnerPackageName = null; + } + } + if (installSource.mIsInitiatingPackageUninstalled) { // We can't check visibility in the usual way, since the initiating package is no // longer present. So we apply simpler rules to whether to expose the info: @@ -5052,7 +5062,8 @@ public class ComputerEngine implements Computer { } return new InstallSourceInfo(initiatingPackageName, initiatingPackageSigningInfo, - originatingPackageName, installerPackageName, installSource.mPackageSource); + originatingPackageName, installerPackageName, updateOwnerPackageName, + installSource.mPackageSource); } @PackageManager.EnabledState diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java index 803c97a47688..8711447fd819 100644 --- a/services/core/java/com/android/server/pm/InstallPackageHelper.java +++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java @@ -311,10 +311,15 @@ final class InstallPackageHelper { pkgSetting.setForceQueryableOverride(true); } - // If this is part of a standard install, set the initiating package name, else rely on - // previous device state. InstallSource installSource = request.getInstallSource(); + final boolean isApex = (scanFlags & SCAN_AS_APEX) != 0; + final String updateOwnerFromSysconfig = isApex || !pkgSetting.isSystem() ? null + : mPm.mInjector.getSystemConfig().getSystemAppUpdateOwnerPackageName( + parsedPackage.getPackageName()); + // For new install (standard install), the installSource isn't null. if (installSource != null) { + // If this is part of a standard install, set the initiating package name, else rely on + // previous device state. if (installSource.mInitiatingPackageName != null) { final PackageSetting ips = mPm.mSettings.getPackageLPr( installSource.mInitiatingPackageName); @@ -323,7 +328,37 @@ final class InstallPackageHelper { ips.getSignatures()); } } + + // Handle the update ownership enforcement for APK + if (updateOwnerFromSysconfig != null) { + // For system app, we always use the update owner from sysconfig if presented. + installSource = installSource.setUpdateOwnerPackageName(updateOwnerFromSysconfig); + } else if (!isApex) { + final boolean isUpdate = oldPkgSetting != null; + final String oldUpdateOwner = + isUpdate ? oldPkgSetting.getInstallSource().mUpdateOwnerPackageName : null; + final boolean isUpdateOwnershipEnabled = oldUpdateOwner != null; + final boolean isRequestUpdateOwnership = (request.getInstallFlags() + & PackageManager.INSTALL_REQUEST_UPDATE_OWNERSHIP) != 0; + + // Here we assign the update owner for the package, and the rules are: + // -. If the installer doesn't request update ownership on initial installation, + // keep the update owner as null. + // -. If the installer doesn't want to be the owner to provide the subsequent + // update (doesn't request to be the update owner), e.g., non-store installer + // (file manager), ADB, or DO/PO, we should not update the owner. + // -. Else, the installer requests update ownership on initial installation or + // update, we use installSource.mUpdateOwnerPackageName as the update owner. + if (!isRequestUpdateOwnership || (isUpdate && !isUpdateOwnershipEnabled)) { + installSource = installSource.setUpdateOwnerPackageName(oldUpdateOwner); + } + } + pkgSetting.setInstallSource(installSource); + // non-standard install (addForInit and install existing packages), installSource is null. + } else if (updateOwnerFromSysconfig != null) { + // For system app, we always use the update owner from sysconfig if presented. + pkgSetting.setUpdateOwnerPackage(updateOwnerFromSysconfig); } if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0) { diff --git a/services/core/java/com/android/server/pm/InstallSource.java b/services/core/java/com/android/server/pm/InstallSource.java index dde9905ccc86..65bde518d0a1 100644 --- a/services/core/java/com/android/server/pm/InstallSource.java +++ b/services/core/java/com/android/server/pm/InstallSource.java @@ -34,12 +34,18 @@ public 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, INVALID_UID, null, - false, false, null, PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED); + static final InstallSource EMPTY = new InstallSource(null /* initiatingPackageName */, + null /* originatingPackageName */, null /* installerPackageName */, INVALID_UID, + null /* updateOwnerPackageName */, null /* installerAttributionTag */, + false /* isOrphaned */, false /* isInitiatingPackageUninstalled */, + null /* initiatingPackageSignatures */, PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED); /** 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, INVALID_UID, null, true, false, null, + null /* initiatingPackageName */, null /* originatingPackageName */, + null /* installerPackageName */, INVALID_UID, null /* updateOwnerPackageName */, + null /* installerAttributionTag */, true /* isOrphaned */, + false /* isInitiatingPackageUninstalled */, null /* initiatingPackageSignatures */, PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED); /** @@ -73,6 +79,13 @@ public final class InstallSource { final String mInstallerPackageName; /** + * Package name of the app that requested the installer ownership. Note that this may be + * modified. + */ + @Nullable + final String mUpdateOwnerPackageName; + + /** * UID of the installer package, corresponding to the {@link #mInstallerPackageName}. */ final int mInstallerPackageUid; @@ -96,55 +109,64 @@ public final class InstallSource { static InstallSource create(@Nullable String initiatingPackageName, @Nullable String originatingPackageName, @Nullable String installerPackageName, - int installerPackageUid, @Nullable String installerAttributionTag, boolean isOrphaned, + int installerPackageUid, @Nullable String updateOwnerPackageName, + @Nullable String installerAttributionTag, boolean isOrphaned, boolean isInitiatingPackageUninstalled) { return create(initiatingPackageName, originatingPackageName, installerPackageName, - installerPackageUid, installerAttributionTag, + installerPackageUid, updateOwnerPackageName, installerAttributionTag, PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED, isOrphaned, isInitiatingPackageUninstalled); } static InstallSource create(@Nullable String initiatingPackageName, @Nullable String originatingPackageName, @Nullable String installerPackageName, - int installerPackageUid, @Nullable String installerAttributionTag, int packageSource) { + int installerPackageUid, @Nullable String updateOwnerPackageName, + @Nullable String installerAttributionTag, int packageSource) { return create(initiatingPackageName, originatingPackageName, installerPackageName, - installerPackageUid, installerAttributionTag, packageSource, false, false); + installerPackageUid, updateOwnerPackageName, installerAttributionTag, + packageSource, false /* isOrphaned */, false /* isInitiatingPackageUninstalled */); } static InstallSource create(@Nullable String initiatingPackageName, @Nullable String originatingPackageName, @Nullable String installerPackageName, - int installerPackageUid, @Nullable String installerAttributionTag, int packageSource, - boolean isOrphaned, boolean isInitiatingPackageUninstalled) { + int installerPackageUid, @Nullable String updateOwnerPackageName, + @Nullable String installerAttributionTag, int packageSource, boolean isOrphaned, + boolean isInitiatingPackageUninstalled) { return createInternal( intern(initiatingPackageName), intern(originatingPackageName), intern(installerPackageName), installerPackageUid, + intern(updateOwnerPackageName), installerAttributionTag, packageSource, - isOrphaned, isInitiatingPackageUninstalled, null); + isOrphaned, isInitiatingPackageUninstalled, + null /* initiatingPackageSignatures */); } private static InstallSource createInternal(@Nullable String initiatingPackageName, @Nullable String originatingPackageName, @Nullable String installerPackageName, - int installerPackageUid, @Nullable String installerAttributionTag, int packageSource, - boolean isOrphaned, boolean isInitiatingPackageUninstalled, + int installerPackageUid, @Nullable String updateOwnerPackageName, + @Nullable String installerAttributionTag, int packageSource, boolean isOrphaned, + boolean isInitiatingPackageUninstalled, @Nullable PackageSignatures initiatingPackageSignatures) { if (initiatingPackageName == null && originatingPackageName == null - && installerPackageName == null && initiatingPackageSignatures == null + && installerPackageName == null && updateOwnerPackageName == null + && initiatingPackageSignatures == null && !isInitiatingPackageUninstalled && packageSource == PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED) { return isOrphaned ? EMPTY_ORPHANED : EMPTY; } return new InstallSource(initiatingPackageName, originatingPackageName, - installerPackageName, installerPackageUid, installerAttributionTag, isOrphaned, - isInitiatingPackageUninstalled, initiatingPackageSignatures, packageSource + installerPackageName, installerPackageUid, updateOwnerPackageName, + installerAttributionTag, isOrphaned, isInitiatingPackageUninstalled, + initiatingPackageSignatures, packageSource ); } private InstallSource(@Nullable String initiatingPackageName, @Nullable String originatingPackageName, @Nullable String installerPackageName, - int installerPackageUid, + int installerPackageUid, @Nullable String updateOwnerPackageName, @Nullable String installerAttributionTag, boolean isOrphaned, boolean isInitiatingPackageUninstalled, @Nullable PackageSignatures initiatingPackageSignatures, @@ -157,6 +179,7 @@ public final class InstallSource { mOriginatingPackageName = originatingPackageName; mInstallerPackageName = installerPackageName; mInstallerPackageUid = installerPackageUid; + mUpdateOwnerPackageName = updateOwnerPackageName; mInstallerAttributionTag = installerAttributionTag; mIsOrphaned = isOrphaned; mIsInitiatingPackageUninstalled = isInitiatingPackageUninstalled; @@ -174,9 +197,23 @@ public final class InstallSource { return this; } return createInternal(mInitiatingPackageName, mOriginatingPackageName, - intern(installerPackageName), installerPackageUid, mInstallerAttributionTag, - mPackageSource, mIsOrphaned, mIsInitiatingPackageUninstalled, - mInitiatingPackageSignatures); + intern(installerPackageName), installerPackageUid, mUpdateOwnerPackageName, + mInstallerAttributionTag, mPackageSource, mIsOrphaned, + mIsInitiatingPackageUninstalled, mInitiatingPackageSignatures); + } + + /** + * Return an InstallSource the same as this one except with the specified + * {@link #mUpdateOwnerPackageName}. + */ + InstallSource setUpdateOwnerPackageName(@Nullable String updateOwnerPackageName) { + if (Objects.equals(updateOwnerPackageName, mUpdateOwnerPackageName)) { + return this; + } + return createInternal(mInitiatingPackageName, mOriginatingPackageName, + mInstallerPackageName, mInstallerPackageUid, intern(updateOwnerPackageName), + mInstallerAttributionTag, mPackageSource, mIsOrphaned, + mIsInitiatingPackageUninstalled, mInitiatingPackageSignatures); } /** @@ -188,8 +225,8 @@ public final class InstallSource { return this; } return createInternal(mInitiatingPackageName, mOriginatingPackageName, - mInstallerPackageName, - mInstallerPackageUid, mInstallerAttributionTag, mPackageSource, isOrphaned, + mInstallerPackageName, mInstallerPackageUid, mUpdateOwnerPackageName, + mInstallerAttributionTag, mPackageSource, isOrphaned, mIsInitiatingPackageUninstalled, mInitiatingPackageSignatures); } @@ -202,8 +239,8 @@ public final class InstallSource { return this; } return createInternal(mInitiatingPackageName, mOriginatingPackageName, - mInstallerPackageName, - mInstallerPackageUid, mInstallerAttributionTag, mPackageSource, mIsOrphaned, + mInstallerPackageName, mInstallerPackageUid, mUpdateOwnerPackageName, + mInstallerAttributionTag, mPackageSource, mIsOrphaned, mIsInitiatingPackageUninstalled, signatures); } @@ -220,6 +257,7 @@ public final class InstallSource { boolean isInitiatingPackageUninstalled = mIsInitiatingPackageUninstalled; String originatingPackageName = mOriginatingPackageName; String installerPackageName = mInstallerPackageName; + String updateOwnerPackageName = mUpdateOwnerPackageName; int installerPackageUid = mInstallerPackageUid; boolean isOrphaned = mIsOrphaned; @@ -242,13 +280,18 @@ public final class InstallSource { isOrphaned = true; modified = true; } + if (packageName.equals(updateOwnerPackageName)) { + updateOwnerPackageName = null; + modified = true; + } if (!modified) { return this; } return createInternal(mInitiatingPackageName, originatingPackageName, installerPackageName, - installerPackageUid, null, mPackageSource, isOrphaned, + installerPackageUid, updateOwnerPackageName, + null /* installerAttributionTag */, mPackageSource, isOrphaned, isInitiatingPackageUninstalled, mInitiatingPackageSignatures); } diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 8c5bab6a55dd..239853c857cc 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -878,9 +878,14 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements requestedInstallerPackageName = null; } + if (isApex || mContext.checkCallingOrSelfPermission( + Manifest.permission.ENFORCE_UPDATE_OWNERSHIP) == PackageManager.PERMISSION_DENIED) { + params.installFlags &= ~PackageManager.INSTALL_REQUEST_UPDATE_OWNERSHIP; + } + InstallSource installSource = InstallSource.create(installerPackageName, originatingPackageName, requestedInstallerPackageName, requestedInstallerPackageUid, - installerAttributionTag, params.packageSource); + requestedInstallerPackageName, installerAttributionTag, params.packageSource); session = new PackageInstallerSession(mInternalCallback, mContext, mPm, this, mSilentUpdatePolicy, mInstallThread.getLooper(), mStagingManager, sessionId, userId, callingUid, installSource, params, createdMillis, 0L, stageDir, stageCid, diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 0556c3ba8557..4bbf09de72a0 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -226,6 +226,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private static final String ATTR_USER_ID = "userId"; private static final String ATTR_INSTALLER_PACKAGE_NAME = "installerPackageName"; private static final String ATTR_INSTALLER_PACKAGE_UID = "installerPackageUid"; + private static final String ATTR_UPDATE_OWNER_PACKAGE_NAME = "updateOwnererPackageName"; private static final String ATTR_INSTALLER_ATTRIBUTION_TAG = "installerAttributionTag"; private static final String ATTR_INSTALLER_UID = "installerUid"; private static final String ATTR_INITIATING_PACKAGE_NAME = @@ -2205,8 +2206,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } mInstallerUid = newOwnerAppInfo.uid; - mInstallSource = InstallSource.create(packageName, null, packageName, - mInstallerUid, null, params.packageSource); + mInstallSource = InstallSource.create(packageName, null /* originatingPackageName */, + packageName, mInstallerUid, packageName, null /* installerAttributionTag */, + params.packageSource); } } @@ -4438,6 +4440,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { return params.keepApplicationEnabledSetting; } + @Override + public boolean isRequestUpdateOwnership() { + return (params.installFlags & PackageManager.INSTALL_REQUEST_UPDATE_OWNERSHIP) != 0; + } + void setSessionReady() { synchronized (mLock) { // Do not allow destroyed/failed session to change state @@ -4774,6 +4781,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { writeStringAttribute(out, ATTR_INSTALLER_PACKAGE_NAME, mInstallSource.mInstallerPackageName); out.attributeInt(null, ATTR_INSTALLER_PACKAGE_UID, mInstallSource.mInstallerPackageUid); + writeStringAttribute(out, ATTR_UPDATE_OWNER_PACKAGE_NAME, + mInstallSource.mUpdateOwnerPackageName); writeStringAttribute(out, ATTR_INSTALLER_ATTRIBUTION_TAG, mInstallSource.mInstallerAttributionTag); out.attributeInt(null, ATTR_INSTALLER_UID, mInstallerUid); @@ -4941,6 +4950,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { final String installerPackageName = readStringAttribute(in, ATTR_INSTALLER_PACKAGE_NAME); final int installPackageUid = in.getAttributeInt(null, ATTR_INSTALLER_PACKAGE_UID, INVALID_UID); + final String updateOwnerPackageName = readStringAttribute(in, + ATTR_UPDATE_OWNER_PACKAGE_NAME); final String installerAttributionTag = readStringAttribute(in, ATTR_INSTALLER_ATTRIBUTION_TAG); final int installerUid = in.getAttributeInt(null, ATTR_INSTALLER_UID, pm.snapshotComputer() @@ -5113,7 +5124,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { InstallSource installSource = InstallSource.create(installInitiatingPackageName, installOriginatingPackageName, installerPackageName, installPackageUid, - installerAttributionTag, params.packageSource); + updateOwnerPackageName, installerAttributionTag, params.packageSource); return new PackageInstallerSession(callback, context, pm, sessionProvider, silentUpdatePolicy, installerThread, stagingManager, sessionId, userId, installerUid, installSource, params, createdMillis, committedMillis, stageDir, diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java index 877b1127cfb4..6562de96388f 100644 --- a/services/core/java/com/android/server/pm/PackageSetting.java +++ b/services/core/java/com/android/server/pm/PackageSetting.java @@ -300,6 +300,8 @@ public class PackageSetting extends SettingBase implements PackageStateInternal installSource.mInitiatingPackageName); proto.write(PackageProto.InstallSourceProto.ORIGINATING_PACKAGE_NAME, installSource.mOriginatingPackageName); + proto.write(PackageProto.InstallSourceProto.UPDATE_OWNER_PACKAGE_NAME, + installSource.mUpdateOwnerPackageName); proto.end(sourceToken); } proto.write(PackageProto.StatesProto.IS_LOADING, isLoading()); @@ -368,6 +370,12 @@ public class PackageSetting extends SettingBase implements PackageStateInternal return this; } + public PackageSetting setUpdateOwnerPackage(@Nullable String updateOwnerPackageName) { + installSource = installSource.setUpdateOwnerPackageName(updateOwnerPackageName); + onChanged(); + return this; + } + public PackageSetting setInstallSource(InstallSource installSource) { this.installSource = Objects.requireNonNull(installSource); onChanged(); diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 6ebef2057e78..97fb0c2e3fe9 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -3050,6 +3050,9 @@ public final class Settings implements Watchable, Snappable { if (installSource.mInstallerPackageUid != INVALID_UID) { serializer.attributeInt(null, "installerUid", installSource.mInstallerPackageUid); } + if (installSource.mUpdateOwnerPackageName != null) { + serializer.attribute(null, "updateOwner", installSource.mUpdateOwnerPackageName); + } if (installSource.mInstallerAttributionTag != null) { serializer.attribute(null, "installerAttributionTag", installSource.mInstallerAttributionTag); @@ -3880,6 +3883,7 @@ public final class Settings implements Watchable, Snappable { String systemStr = null; String installerPackageName = null; int installerPackageUid = INVALID_UID; + String updateOwnerPackageName = null; String installerAttributionTag = null; int packageSource = PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED; boolean isOrphaned = false; @@ -3923,6 +3927,7 @@ public final class Settings implements Watchable, Snappable { versionCode = parser.getAttributeLong(null, "version", 0); installerPackageName = parser.getAttributeValue(null, "installer"); installerPackageUid = parser.getAttributeInt(null, "installerUid", INVALID_UID); + updateOwnerPackageName = parser.getAttributeValue(null, "updateOwner"); installerAttributionTag = parser.getAttributeValue(null, "installerAttributionTag"); packageSource = parser.getAttributeInt(null, "packageSource", PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED); @@ -4065,8 +4070,9 @@ public final class Settings implements Watchable, Snappable { if (packageSetting != null) { InstallSource installSource = InstallSource.create( installInitiatingPackageName, installOriginatingPackageName, - installerPackageName, installerPackageUid, installerAttributionTag, - packageSource, isOrphaned, installInitiatorUninstalled); + installerPackageName, installerPackageUid, updateOwnerPackageName, + installerAttributionTag, packageSource, isOrphaned, + installInitiatorUninstalled); packageSetting.setInstallSource(installSource) .setVolumeUuid(volumeUuid) .setCategoryOverride(categoryHint) @@ -4734,6 +4740,8 @@ public final class Settings implements Watchable, Snappable { pw.print(ps.getInstallSource().mInstallerPackageName != null ? ps.getInstallSource().mInstallerPackageName : "?"); pw.print(ps.getInstallSource().mInstallerPackageUid); + pw.print(ps.getInstallSource().mUpdateOwnerPackageName != null + ? ps.getInstallSource().mUpdateOwnerPackageName : "?"); pw.print(ps.getInstallSource().mInstallerAttributionTag != null ? "(" + ps.getInstallSource().mInstallerAttributionTag + ")" : ""); pw.print(","); @@ -5017,6 +5025,10 @@ public final class Settings implements Watchable, Snappable { pw.print(prefix); pw.print(" installerPackageUid="); pw.println(ps.getInstallSource().mInstallerPackageUid); } + if (ps.getInstallSource().mUpdateOwnerPackageName != null) { + pw.print(prefix); pw.print(" updateOwnerPackageName="); + pw.println(ps.getInstallSource().mUpdateOwnerPackageName); + } if (ps.getInstallSource().mInstallerAttributionTag != null) { pw.print(prefix); pw.print(" installerAttributionTag="); pw.println(ps.getInstallSource().mInstallerAttributionTag); diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.java index 5e5e7e3a98a9..56cd7a924acd 100644 --- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.java +++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.java @@ -1024,7 +1024,10 @@ public class AppsFilterImplTest { DUMMY_TARGET_APPID); PackageSetting calling = simulateAddPackage(appsFilter, pkg("com.some.other.package"), DUMMY_CALLING_APPID, - withInstallSource(target.getPackageName(), null, null, INVALID_UID, null, false)); + withInstallSource(target.getPackageName(), null /* originatingPackageName */, + null /* installerPackageName */, INVALID_UID, + null /* updateOwnerPackageName */, null /* installerAttributionTag */, + false /* isInitiatingPackageUninstalled */)); assertFalse( appsFilter.shouldFilterApplication(mSnapshot, DUMMY_CALLING_APPID, calling, target, @@ -1043,7 +1046,10 @@ public class AppsFilterImplTest { DUMMY_TARGET_APPID); PackageSetting calling = simulateAddPackage(appsFilter, pkg("com.some.other.package"), DUMMY_CALLING_APPID, - withInstallSource(target.getPackageName(), null, null, INVALID_UID, null, true)); + withInstallSource(target.getPackageName(), null /* originatingPackageName */, + null /* installerPackageName */, INVALID_UID, + null /* updateOwnerPackageName */, null /* installerAttributionTag */, + true /* isInitiatingPackageUninstalled */)); assertTrue( appsFilter.shouldFilterApplication(mSnapshot, DUMMY_CALLING_APPID, calling, target, @@ -1066,8 +1072,10 @@ public class AppsFilterImplTest { DUMMY_TARGET_APPID); watcher.verifyChangeReported("add package"); PackageSetting calling = simulateAddPackage(appsFilter, pkg("com.some.other.package"), - DUMMY_CALLING_APPID, withInstallSource(null, target.getPackageName(), null, - INVALID_UID, null, false)); + DUMMY_CALLING_APPID, withInstallSource(null /* initiatingPackageName */, + target.getPackageName(), null /* installerPackageName */, INVALID_UID, + null /* updateOwnerPackageName */, null /* installerAttributionTag */, + false /* isInitiatingPackageUninstalled */)); watcher.verifyChangeReported("add package"); assertTrue( @@ -1092,8 +1100,11 @@ public class AppsFilterImplTest { DUMMY_TARGET_APPID); watcher.verifyChangeReported("add package"); PackageSetting calling = simulateAddPackage(appsFilter, pkg("com.some.other.package"), - DUMMY_CALLING_APPID, withInstallSource(null, null, target.getPackageName(), - DUMMY_TARGET_APPID, null, false)); + DUMMY_CALLING_APPID, withInstallSource(null /* initiatingPackageName */, + null /* originatingPackageName */, target.getPackageName(), + DUMMY_TARGET_APPID, null /* updateOwnerPackageName */, + null /* installerAttributionTag */, + false /* isInitiatingPackageUninstalled */)); watcher.verifyChangeReported("add package"); assertFalse( @@ -1679,10 +1690,12 @@ public class AppsFilterImplTest { private WithSettingBuilder withInstallSource(String initiatingPackageName, String originatingPackageName, String installerPackageName, int installerPackageUid, - String installerAttributionTag, boolean isInitiatingPackageUninstalled) { + String updateOwnerPackageName, String installerAttributionTag, + boolean isInitiatingPackageUninstalled) { final InstallSource installSource = InstallSource.create(initiatingPackageName, originatingPackageName, installerPackageName, installerPackageUid, - installerAttributionTag, /* isOrphaned= */ false, isInitiatingPackageUninstalled); + updateOwnerPackageName, installerAttributionTag, /* isOrphaned= */ false, + isInitiatingPackageUninstalled); return setting -> setting.setInstallSource(installSource); } } diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageInstallerSessionTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageInstallerSessionTest.java index 4da082e0370b..98655c895aff 100644 --- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageInstallerSessionTest.java +++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageInstallerSessionTest.java @@ -167,8 +167,8 @@ public class PackageInstallerSessionTest { params.isMultiPackage = true; } InstallSource installSource = InstallSource.create("testInstallInitiator", - "testInstallOriginator", "testInstaller", -1, "testAttributionTag", - PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED); + "testInstallOriginator", "testInstaller", -1, "testUpdateOwner", + "testAttributionTag", PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED); return new PackageInstallerSession( /* callback */ null, /* context */null, diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java index cfd5279a0fa9..d2547a3ff336 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java @@ -723,8 +723,8 @@ public class StagingManagerTest { params.isStaged = true; InstallSource installSource = InstallSource.create("testInstallInitiator", - "testInstallOriginator", "testInstaller", 100, "testAttributionTag", - PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED); + "testInstallOriginator", "testInstaller", 100, "testUpdateOwner", + "testAttributionTag", PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED); PackageInstallerSession session = new PackageInstallerSession( /* callback */ null, diff --git a/services/tests/servicestests/src/com/android/server/locales/LocaleManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/locales/LocaleManagerServiceTest.java index 065aec5b2f64..07fda309f03e 100644 --- a/services/tests/servicestests/src/com/android/server/locales/LocaleManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/locales/LocaleManagerServiceTest.java @@ -77,6 +77,7 @@ public class LocaleManagerServiceTest { /* initiatingPackageName = */ null, /* initiatingPackageSigningInfo = */ null, /* originatingPackageName = */ null, /* installingPackageName = */ DEFAULT_INSTALLER_PACKAGE_NAME, + /* updateOwnerPackageName = */ null, /* packageSource = */ PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED); private LocaleManagerService mLocaleManagerService; diff --git a/services/tests/servicestests/src/com/android/server/locales/SystemAppUpdateTrackerTest.java b/services/tests/servicestests/src/com/android/server/locales/SystemAppUpdateTrackerTest.java index 494796ee48eb..9429462a6723 100644 --- a/services/tests/servicestests/src/com/android/server/locales/SystemAppUpdateTrackerTest.java +++ b/services/tests/servicestests/src/com/android/server/locales/SystemAppUpdateTrackerTest.java @@ -89,6 +89,7 @@ public class SystemAppUpdateTrackerTest { /* initiatingPackageName = */ null, /* initiatingPackageSigningInfo = */ null, /* originatingPackageName = */ null, /* installingPackageName = */ DEFAULT_INSTALLER_PACKAGE_NAME, + /* updateOwnerPackageName = */ null, /* packageSource = */ PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED); @Mock |