Add install reason
This CL allows a reason to be specified when installing a package. The
install reason is a sticky piece of metadata: When a package is e.g.
installed via enterprise policy and an update is then manually
installed or sideloaded, the install reason will remain "policy."
The install reason is tracked separately for each user.
With this CL, two install reasons exist: "policy" and "unknown." Other
install reasons will likely be supported in the future.
Bug: 32692748
Bug: 33415829
Test: Tested manually with "adb install" / "adb uninstall"
Change-Id: I0c9b9e1b8eb666bb6962564f6efd97e41703cd86
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index aedcdce..f3185a8 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1635,7 +1635,8 @@
public int installExistingPackageAsUser(String packageName, int userId)
throws NameNotFoundException {
try {
- int res = mPM.installExistingPackageAsUser(packageName, userId);
+ int res = mPM.installExistingPackageAsUser(packageName, userId,
+ PackageManager.INSTALL_REASON_UNKNOWN);
if (res == INSTALL_FAILED_INVALID_URI) {
throw new NameNotFoundException("Package " + packageName + " doesn't exist");
}
@@ -2411,6 +2412,18 @@
return getUserManager().isManagedProfile(userId);
}
+ /**
+ * @hide
+ */
+ @Override
+ public int getInstallReason(String packageName, UserHandle user) {
+ try {
+ return mPM.getInstallReason(packageName, user.getIdentifier());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/** {@hide} */
private static class MoveCallbackDelegate extends IPackageMoveObserver.Stub implements
Handler.Callback {
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index eb0ca2e..19cca8e 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -523,7 +523,7 @@
boolean setInstallLocation(int loc);
int getInstallLocation();
- int installExistingPackageAsUser(String packageName, int userId);
+ int installExistingPackageAsUser(String packageName, int userId, int installReason);
void verifyPendingInstall(int id, int verificationCode);
void extendVerificationTimeout(int id, int verificationCodeAtTimeout, long millisecondsToDelay);
@@ -584,4 +584,6 @@
boolean isPackageDeviceAdminOnAnyUser(String packageName);
List<String> getPreviousCodePaths(in String packageName);
+
+ int getInstallReason(String packageName, int userId);
}
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 646bd3c..db3f637 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -881,6 +881,8 @@
/** {@hide} */
public int installLocation = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY;
/** {@hide} */
+ public int installReason = PackageManager.INSTALL_REASON_UNKNOWN;
+ /** {@hide} */
public long sizeBytes = -1;
/** {@hide} */
public String appPackageName;
@@ -919,6 +921,7 @@
mode = source.readInt();
installFlags = source.readInt();
installLocation = source.readInt();
+ installReason = source.readInt();
sizeBytes = source.readLong();
appPackageName = source.readString();
appIcon = source.readParcelable(null);
@@ -1076,6 +1079,10 @@
}
}
+ public void setInstallReason(int installReason) {
+ this.installReason = installReason;
+ }
+
/** {@hide} */
public void dump(IndentingPrintWriter pw) {
pw.printPair("mode", mode);
@@ -1104,6 +1111,7 @@
dest.writeInt(mode);
dest.writeInt(installFlags);
dest.writeInt(installLocation);
+ dest.writeInt(installReason);
dest.writeLong(sizeBytes);
dest.writeString(appPackageName);
dest.writeParcelable(appIcon, flags);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 0cd67b7..04e649c 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -740,6 +740,21 @@
*/
public static final int DONT_KILL_APP = 0x00000001;
+ /** @hide */
+ @IntDef({INSTALL_REASON_UNKNOWN, INSTALL_REASON_POLICY})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface InstallReason {}
+
+ /**
+ * Code indicating that the reason for installing this package is unknown.
+ */
+ public static final int INSTALL_REASON_UNKNOWN = 0;
+
+ /**
+ * Code indicating that this package was installed due to enterprise policy.
+ */
+ public static final int INSTALL_REASON_POLICY = 1;
+
/**
* Installation return code: this is passed to the
* {@link IPackageInstallObserver} on success.
@@ -5881,4 +5896,25 @@
}
}
}
+
+ /**
+ * Return the install reason that was recorded when a package was first installed for a specific
+ * user. Requesting the install reason for another user will require the permission
+ * INTERACT_ACROSS_USERS_FULL.
+ *
+ * @param packageName The package for which to retrieve the install reason
+ * @param user The user for whom to retrieve the install reason
+ *
+ * @return The install reason, currently one of {@code INSTALL_REASON_UNKNOWN} and
+ * {@code INSTALL_REASON_POLICY}. If the package is not installed for the given user,
+ * {@code INSTALL_REASON_UNKNOWN} is returned.
+ *
+ * @see #INSTALL_REASON_UNKNOWN
+ * @see #INSTALL_REASON_POLICY
+ *
+ * @hide
+ */
+ @TestApi
+ public abstract @InstallReason int getInstallReason(String packageName,
+ @NonNull UserHandle user);
}
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index eb3f275..e19aa99 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -48,6 +48,7 @@
public int domainVerificationStatus;
public int appLinkGeneration;
public int categoryHint = ApplicationInfo.CATEGORY_UNDEFINED;
+ public int installReason;
public ArraySet<String> disabledComponents;
public ArraySet<String> enabledComponents;
@@ -59,6 +60,7 @@
enabled = COMPONENT_ENABLED_STATE_DEFAULT;
domainVerificationStatus =
PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
+ installReason = PackageManager.INSTALL_REASON_UNKNOWN;
}
public PackageUserState(PackageUserState o) {
@@ -74,6 +76,7 @@
domainVerificationStatus = o.domainVerificationStatus;
appLinkGeneration = o.appLinkGeneration;
categoryHint = o.categoryHint;
+ installReason = o.installReason;
disabledComponents = ArrayUtils.cloneOrNull(o.disabledComponents);
enabledComponents = ArrayUtils.cloneOrNull(o.enabledComponents);
}
@@ -202,6 +205,9 @@
if (categoryHint != oldState.categoryHint) {
return false;
}
+ if (installReason != oldState.installReason) {
+ return false;
+ }
if ((disabledComponents == null && oldState.disabledComponents != null)
|| (disabledComponents != null && oldState.disabledComponents == null)) {
return false;