From e677b4717e54506fa0384192666281bf15cc2204 Mon Sep 17 00:00:00 2001 From: William Loh Date: Sat, 8 Oct 2022 01:13:50 +0000 Subject: [PATCH] Add API to skip application enable in install flow This CL addes a new API to PackageInstaller.SessionParams that can be used to skip the app enable step during the package install flow. This can be used by installers to keep the app's existing enabled state after a upgrade instead of setting it to enabled by default. This also corrects the variable userId used in the enable step to currentUserId that was preventing it from enabling the app when installed for all users. Bug: 244430570 Test: atest PackageManagerShellCommandTest#testAppUpdateSkipEnable Change-Id: I42b003f8c42a7f8c45a581bd9383c78090462d0f --- core/api/current.txt | 3 ++ .../content/pm/IPackageInstallerSession.aidl | 2 + .../android/content/pm/PackageInstaller.java | 39 +++++++++++++++++++ .../com/android/server/pm/InstallArgs.java | 7 +++- .../server/pm/InstallPackageHelper.java | 17 +++++--- .../com/android/server/pm/InstallRequest.java | 7 +++- .../android/server/pm/InstallingSession.java | 3 ++ .../server/pm/PackageInstallerSession.java | 12 ++++++ .../server/pm/PackageManagerShellCommand.java | 3 ++ 9 files changed, 85 insertions(+), 8 deletions(-) diff --git a/core/api/current.txt b/core/api/current.txt index b4116cf699595..e995ed1022c2c 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -11736,6 +11736,7 @@ package android.content.pm { method @NonNull public int[] getChildSessionIds(); method @NonNull public String[] getNames() throws java.io.IOException; method public int getParentSessionId(); + method public boolean isKeepApplicationEnabledSetting(); method public boolean isMultiPackage(); method public boolean isStaged(); method @NonNull public java.io.InputStream openRead(@NonNull String) throws java.io.IOException; @@ -11787,6 +11788,7 @@ package android.content.pm { method public boolean hasParentSessionId(); method public boolean isActive(); method public boolean isCommitted(); + method public boolean isKeepApplicationEnabledSetting(); method public boolean isMultiPackage(); method public boolean isSealed(); method public boolean isStaged(); @@ -11819,6 +11821,7 @@ package android.content.pm { method public void setInstallLocation(int); method public void setInstallReason(int); method public void setInstallScenario(int); + method public void setKeepApplicationEnabledSetting(); method public void setMultiPackage(); method public void setOriginatingUid(int); method public void setOriginatingUri(@Nullable android.net.Uri); diff --git a/core/java/android/content/pm/IPackageInstallerSession.aidl b/core/java/android/content/pm/IPackageInstallerSession.aidl index 1fc6bdaa963a9..7d9c64add492d 100644 --- a/core/java/android/content/pm/IPackageInstallerSession.aidl +++ b/core/java/android/content/pm/IPackageInstallerSession.aidl @@ -61,4 +61,6 @@ interface IPackageInstallerSession { int getInstallFlags(); void requestUserPreapproval(in PackageInstaller.PreapprovalDetails details, in IntentSender statusReceiver); + + boolean isKeepApplicationEnabledSetting(); } diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index d7686e22756e2..35518276ac095 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -1717,6 +1717,18 @@ public class PackageInstaller { e.rethrowFromSystemServer(); } } + + /** + * @return {@code true} if this session will keep the existing application enabled setting + * after installation. + */ + public boolean isKeepApplicationEnabledSetting() { + try { + return mSession.isKeepApplicationEnabledSetting(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } /** @@ -1855,6 +1867,8 @@ public class PackageInstaller { public boolean forceQueryableOverride; /** {@hide} */ public int requireUserAction = USER_ACTION_UNSPECIFIED; + /** {@hide} */ + public boolean keepApplicationEnabledSetting = false; /** * Construct parameters for a new package install session. @@ -1899,6 +1913,7 @@ public class PackageInstaller { rollbackDataPolicy = source.readInt(); requireUserAction = source.readInt(); packageSource = source.readInt(); + keepApplicationEnabledSetting = source.readBoolean(); } /** {@hide} */ @@ -1929,6 +1944,7 @@ public class PackageInstaller { ret.rollbackDataPolicy = rollbackDataPolicy; ret.requireUserAction = requireUserAction; ret.packageSource = packageSource; + ret.keepApplicationEnabledSetting = keepApplicationEnabledSetting; return ret; } @@ -2415,6 +2431,14 @@ public class PackageInstaller { this.installScenario = installScenario; } + /** + * Request to keep the original application enabled setting. This will prevent the + * application from being enabled if it was previously in a disabled state. + */ + public void setKeepApplicationEnabledSetting() { + this.keepApplicationEnabledSetting = true; + } + /** {@hide} */ public void dump(IndentingPrintWriter pw) { pw.printPair("mode", mode); @@ -2443,6 +2467,7 @@ public class PackageInstaller { pw.printPair("requiredInstalledVersionCode", requiredInstalledVersionCode); pw.printPair("dataLoaderParams", dataLoaderParams); pw.printPair("rollbackDataPolicy", rollbackDataPolicy); + pw.printPair("keepApplicationEnabledSetting", keepApplicationEnabledSetting); pw.println(); } @@ -2483,6 +2508,7 @@ public class PackageInstaller { dest.writeInt(rollbackDataPolicy); dest.writeInt(requireUserAction); dest.writeInt(packageSource); + dest.writeBoolean(keepApplicationEnabledSetting); } public static final Parcelable.Creator @@ -2684,6 +2710,9 @@ public class PackageInstaller { /** @hide */ public boolean isPreapprovalRequested; + /** @hide */ + public boolean keepApplicationEnabledSetting; + /** {@hide} */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public SessionInfo() { @@ -2737,6 +2766,7 @@ public class PackageInstaller { requireUserAction = source.readInt(); installerUid = source.readInt(); packageSource = source.readInt(); + keepApplicationEnabledSetting = source.readBoolean(); } /** @@ -3268,6 +3298,14 @@ public class PackageInstaller { return installerUid; } + /** + * Returns {@code true} if this session will keep the existing application enabled setting + * after installation. + */ + public boolean isKeepApplicationEnabledSetting() { + return keepApplicationEnabledSetting; + } + @Override public int describeContents() { return 0; @@ -3317,6 +3355,7 @@ public class PackageInstaller { dest.writeInt(requireUserAction); dest.writeInt(installerUid); dest.writeInt(packageSource); + dest.writeBoolean(keepApplicationEnabledSetting); } public static final Parcelable.Creator diff --git a/services/core/java/com/android/server/pm/InstallArgs.java b/services/core/java/com/android/server/pm/InstallArgs.java index a94a4e2a70be7..ced547c358990 100644 --- a/services/core/java/com/android/server/pm/InstallArgs.java +++ b/services/core/java/com/android/server/pm/InstallArgs.java @@ -59,6 +59,7 @@ final class InstallArgs { final boolean mForceQueryableOverride; final int mDataLoaderType; final int mPackageSource; + final boolean mKeepApplicationEnabledSetting; // The list of instruction sets supported by this app. This is currently // only used during the rmdex() phase to clean up resources. We can get rid of this @@ -72,7 +73,8 @@ final class InstallArgs { List allowlistedRestrictedPermissions, int autoRevokePermissionsMode, String traceMethod, int traceCookie, SigningDetails signingDetails, int installReason, int installScenario, - boolean forceQueryableOverride, int dataLoaderType, int packageSource) { + boolean forceQueryableOverride, int dataLoaderType, int packageSource, + boolean keepApplicationEnabledSetting) { mOriginInfo = originInfo; mMoveInfo = moveInfo; mInstallFlags = installFlags; @@ -93,6 +95,7 @@ final class InstallArgs { mForceQueryableOverride = forceQueryableOverride; mDataLoaderType = dataLoaderType; mPackageSource = packageSource; + mKeepApplicationEnabledSetting = keepApplicationEnabledSetting; } /** @@ -104,7 +107,7 @@ final class InstallArgs { null, null, instructionSets, null, null, null, MODE_DEFAULT, null, 0, SigningDetails.UNKNOWN, PackageManager.INSTALL_REASON_UNKNOWN, PackageManager.INSTALL_SCENARIO_DEFAULT, false, DataLoaderType.NONE, - PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED); + PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED, false); mCodeFile = (codePath != null) ? new File(codePath) : null; } diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java index 5dd5d81cfbb64..8884304eb362a 100644 --- a/services/core/java/com/android/server/pm/InstallPackageHelper.java +++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java @@ -2036,7 +2036,8 @@ final class InstallPackageHelper { Slog.d(TAG, "Implicitly enabling system package on upgrade: " + pkgName); } // Enable system package for requested users - if (installedForUsers != null) { + if (installedForUsers != null + && !installRequest.isKeepApplicationEnabledSetting()) { for (int origUserId : installedForUsers) { if (userId == UserHandle.USER_ALL || userId == origUserId) { ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, @@ -2086,16 +2087,22 @@ final class InstallPackageHelper { if (userId != UserHandle.USER_ALL) { // It's implied that when a user requests installation, they want the app to - // be installed and enabled. + // be installed and enabled. The caller, however, can explicitly specify to + // keep the existing enabled state. ps.setInstalled(true, userId); - ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, userId, installerPackageName); + if (!installRequest.isKeepApplicationEnabledSetting()) { + ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, userId, + installerPackageName); + } } else if (allUsers != null) { // The caller explicitly specified INSTALL_ALL_USERS flag. // Thus, updating the settings to install the app for all users. for (int currentUserId : allUsers) { ps.setInstalled(true, currentUserId); - ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, userId, - installerPackageName); + if (!installRequest.isKeepApplicationEnabledSetting()) { + ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, currentUserId, + installerPackageName); + } } } diff --git a/services/core/java/com/android/server/pm/InstallRequest.java b/services/core/java/com/android/server/pm/InstallRequest.java index 71571dc4f3066..5974a9cbab676 100644 --- a/services/core/java/com/android/server/pm/InstallRequest.java +++ b/services/core/java/com/android/server/pm/InstallRequest.java @@ -128,7 +128,8 @@ final class InstallRequest { params.mAutoRevokePermissionsMode, params.mTraceMethod, params.mTraceCookie, params.mSigningDetails, params.mInstallReason, params.mInstallScenario, params.mForceQueryableOverride, - params.mDataLoaderType, params.mPackageSource); + params.mDataLoaderType, params.mPackageSource, + params.mKeepApplicationEnabledSetting); mPackageMetrics = new PackageMetrics(this); mIsInstallInherit = params.mIsInherit; mSessionId = params.mSessionId; @@ -498,6 +499,10 @@ final class InstallRequest { return mScanResult.mChangedAbiCodePath; } + public boolean isKeepApplicationEnabledSetting() { + return mInstallArgs == null ? false : mInstallArgs.mKeepApplicationEnabledSetting; + } + public boolean isForceQueryableOverride() { return mInstallArgs != null && mInstallArgs.mForceQueryableOverride; } diff --git a/services/core/java/com/android/server/pm/InstallingSession.java b/services/core/java/com/android/server/pm/InstallingSession.java index 69ced1b39585d..2b6398af348e7 100644 --- a/services/core/java/com/android/server/pm/InstallingSession.java +++ b/services/core/java/com/android/server/pm/InstallingSession.java @@ -98,6 +98,7 @@ class InstallingSession { final boolean mIsInherit; final int mSessionId; final int mRequireUserAction; + final boolean mKeepApplicationEnabledSetting; // For move install InstallingSession(OriginInfo originInfo, MoveInfo moveInfo, IPackageInstallObserver2 observer, @@ -130,6 +131,7 @@ class InstallingSession { mIsInherit = false; mSessionId = -1; mRequireUserAction = USER_ACTION_UNSPECIFIED; + mKeepApplicationEnabledSetting = false; } InstallingSession(int sessionId, File stagedDir, IPackageInstallObserver2 observer, @@ -163,6 +165,7 @@ class InstallingSession { mIsInherit = sessionParams.mode == MODE_INHERIT_EXISTING; mSessionId = sessionId; mRequireUserAction = sessionParams.requireUserAction; + mKeepApplicationEnabledSetting = sessionParams.keepApplicationEnabledSetting; } @Override diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 2ee12bf978234..3983acfe9d2df 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -269,6 +269,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private static final String ATTR_SIGNATURE = "signature"; private static final String ATTR_CHECKSUM_KIND = "checksumKind"; private static final String ATTR_CHECKSUM_VALUE = "checksumValue"; + private static final String ATTR_KEEP_APPLICATION_ENABLED_SETTING = + "keepApplicationEnabledSetting"; private static final String PROPERTY_NAME_INHERIT_NATIVE = "pi.inherit_native_on_dont_kill"; private static final int[] EMPTY_CHILD_SESSION_ARRAY = EmptyArray.INT; @@ -1098,6 +1100,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { info.requireUserAction = params.requireUserAction; info.installerUid = mInstallerUid; info.packageSource = params.packageSource; + info.keepApplicationEnabledSetting = params.keepApplicationEnabledSetting; } return info; } @@ -4310,6 +4313,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { mPreapprovalRequested.set(true); } + @Override + public boolean isKeepApplicationEnabledSetting() { + return params.keepApplicationEnabledSetting; + } + void setSessionReady() { synchronized (mLock) { // Do not allow destroyed/failed session to change state @@ -4691,6 +4699,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { writeStringAttribute(out, ATTR_ABI_OVERRIDE, params.abiOverride); writeStringAttribute(out, ATTR_VOLUME_UUID, params.volumeUuid); out.attributeInt(null, ATTR_INSTALL_REASON, params.installReason); + writeBooleanAttribute(out, ATTR_KEEP_APPLICATION_ENABLED_SETTING, + params.keepApplicationEnabledSetting); final boolean isDataLoader = params.dataLoaderParams != null; writeBooleanAttribute(out, ATTR_IS_DATALOADER, isDataLoader); @@ -4852,6 +4862,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { params.volumeUuid = readStringAttribute(in, ATTR_VOLUME_UUID); params.installReason = in.getAttributeInt(null, ATTR_INSTALL_REASON); params.packageSource = in.getAttributeInt(null, ATTR_PACKAGE_SOURCE); + params.keepApplicationEnabledSetting = in.getAttributeBoolean(null, + ATTR_KEEP_APPLICATION_ENABLED_SETTING, false); if (in.getAttributeBoolean(null, ATTR_IS_DATALOADER, false)) { params.dataLoaderParams = new DataLoaderParams( diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index cc1306dbc2b36..e1efc612224c4 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -3234,6 +3234,9 @@ class PackageManagerShellCommand extends ShellCommand { case "--skip-verification": sessionParams.installFlags |= PackageManager.INSTALL_DISABLE_VERIFICATION; break; + case "--skip-enable": + sessionParams.setKeepApplicationEnabledSetting(); + break; default: throw new IllegalArgumentException("Unknown option " + opt); }