summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/current.txt5
-rw-r--r--core/java/android/content/pm/IPackageInstallerSession.aidl1
-rw-r--r--core/java/android/content/pm/InstallSourceInfo.java25
-rw-r--r--core/java/android/content/pm/PackageInstaller.java48
-rw-r--r--core/java/android/content/pm/PackageManager.java8
-rw-r--r--core/proto/android/service/package.proto3
-rw-r--r--core/res/AndroidManifest.xml10
-rw-r--r--services/core/java/com/android/server/pm/ComputerEngine.java13
-rw-r--r--services/core/java/com/android/server/pm/InstallPackageHelper.java39
-rw-r--r--services/core/java/com/android/server/pm/InstallSource.java91
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java7
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java17
-rw-r--r--services/core/java/com/android/server/pm/PackageSetting.java8
-rw-r--r--services/core/java/com/android/server/pm/Settings.java16
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.java29
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageInstallerSessionTest.java4
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/locales/LocaleManagerServiceTest.java1
-rw-r--r--services/tests/servicestests/src/com/android/server/locales/SystemAppUpdateTrackerTest.java1
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