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/api/current.txt b/api/current.txt
index 4ea29f1..a42689e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -9938,6 +9938,7 @@
method public void setAppLabel(java.lang.CharSequence);
method public void setAppPackageName(java.lang.String);
method public void setInstallLocation(int);
+ method public void setInstallReason(int);
method public void setOriginatingUid(int);
method public void setOriginatingUri(android.net.Uri);
method public void setReferrerUri(android.net.Uri);
@@ -10171,6 +10172,8 @@
field public static final int GET_SIGNATURES = 64; // 0x40
field public static final deprecated int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
field public static final int GET_URI_PERMISSION_PATTERNS = 2048; // 0x800
+ field public static final int INSTALL_REASON_POLICY = 1; // 0x1
+ field public static final int INSTALL_REASON_UNKNOWN = 0; // 0x0
field public static final int MATCH_ALL = 131072; // 0x20000
field public static final int MATCH_DEFAULT_ONLY = 65536; // 0x10000
field public static final int MATCH_DIRECT_BOOT_AWARE = 524288; // 0x80000
diff --git a/api/system-current.txt b/api/system-current.txt
index 87853e3..ce5c4be 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -10359,6 +10359,7 @@
method public void setGrantedRuntimePermissions(java.lang.String[]);
method public void setInstallAsInstantApp(boolean);
method public void setInstallLocation(int);
+ method public void setInstallReason(int);
method public void setOriginatingUid(int);
method public void setOriginatingUri(android.net.Uri);
method public void setReferrerUri(android.net.Uri);
@@ -10647,6 +10648,8 @@
field public static final int INSTALL_PARSE_FAILED_NOT_APK = -100; // 0xffffff9c
field public static final int INSTALL_PARSE_FAILED_NO_CERTIFICATES = -103; // 0xffffff99
field public static final int INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION = -102; // 0xffffff9a
+ field public static final int INSTALL_REASON_POLICY = 1; // 0x1
+ field public static final int INSTALL_REASON_UNKNOWN = 0; // 0x0
field public static final int INSTALL_SUCCEEDED = 1; // 0x1
field public static final int INTENT_FILTER_VERIFICATION_FAILURE = -1; // 0xffffffff
field public static final int INTENT_FILTER_VERIFICATION_SUCCESS = 1; // 0x1
diff --git a/api/test-current.txt b/api/test-current.txt
index ba766e3..9ba22df 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -9966,6 +9966,7 @@
method public void setAppLabel(java.lang.CharSequence);
method public void setAppPackageName(java.lang.String);
method public void setInstallLocation(int);
+ method public void setInstallReason(int);
method public void setOriginatingUid(int);
method public void setOriginatingUri(android.net.Uri);
method public void setReferrerUri(android.net.Uri);
@@ -10038,6 +10039,7 @@
method public abstract android.graphics.drawable.Drawable getDefaultActivityIcon();
method public abstract java.lang.String getDefaultBrowserPackageNameAsUser(int);
method public abstract android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo);
+ method public abstract int getInstallReason(java.lang.String, android.os.UserHandle);
method public abstract java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int);
method public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
method public abstract java.lang.String getInstallerPackageName(java.lang.String);
@@ -10200,6 +10202,8 @@
field public static final int GET_SIGNATURES = 64; // 0x40
field public static final deprecated int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
field public static final int GET_URI_PERMISSION_PATTERNS = 2048; // 0x800
+ field public static final int INSTALL_REASON_POLICY = 1; // 0x1
+ field public static final int INSTALL_REASON_UNKNOWN = 0; // 0x0
field public static final int MATCH_ALL = 131072; // 0x20000
field public static final int MATCH_DEFAULT_ONLY = 65536; // 0x10000
field public static final int MATCH_DIRECT_BOOT_AWARE = 524288; // 0x80000
@@ -39106,6 +39110,7 @@
method public android.graphics.drawable.Drawable getDefaultActivityIcon();
method public java.lang.String getDefaultBrowserPackageNameAsUser(int);
method public android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo);
+ method public int getInstallReason(java.lang.String, android.os.UserHandle);
method public java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int);
method public java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
method public java.lang.String getInstallerPackageName(java.lang.String);
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;
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java b/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java
index c4aa57d..4c11197 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java
@@ -115,7 +115,8 @@
PackageManager.MATCH_ANY_USER, userId);
if (info == null || !info.enabled
|| (info.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
- mIPm.installExistingPackageAsUser(packageName, mUser.getIdentifier());
+ mIPm.installExistingPackageAsUser(packageName, mUser.getIdentifier(),
+ PackageManager.INSTALL_REASON_UNKNOWN);
if (DEBUG) {
Log.d(TAG, "Installing " + packageName);
}
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AppRestrictionsHelperTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AppRestrictionsHelperTest.java
index 3f989bd..f33362f8 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AppRestrictionsHelperTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AppRestrictionsHelperTest.java
@@ -145,7 +145,8 @@
mock(AppRestrictionsHelper.OnDisableUiForPackageListener.class);
mHelper.applyUserAppsStates(mockListener);
- verify(mIpm, times(1)).installExistingPackageAsUser("app1", testUserId);
+ verify(mIpm, times(1)).installExistingPackageAsUser("app1", testUserId,
+ PackageManager.INSTALL_REASON_UNKNOWN);
verify(mIpm, times(1)).setApplicationHiddenSettingAsUser("app2", false, testUserId);
verify(mockListener).onDisableUiForPackage("app2");
verify(mPm, times(1)).deletePackageAsUser(eq("app3"), any(IPackageDeleteObserver.class),
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 4382057..26d3cfe 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -12138,7 +12138,7 @@
final InstallParams params = new InstallParams(origin, null /*moveInfo*/, observer,
installFlags, installerPackageName, null /*volumeUuid*/, verificationInfo, user,
null /*packageAbiOverride*/, null /*grantedPermissions*/,
- null /*certificates*/);
+ null /*certificates*/, PackageManager.INSTALL_REASON_UNKNOWN);
params.setTraceMethod("installAsUser").setTraceCookie(System.identityHashCode(params));
msg.obj = params;
@@ -12174,7 +12174,7 @@
final InstallParams params = new InstallParams(origin, null, observer,
sessionParams.installFlags, installerPackageName, sessionParams.volumeUuid,
verificationInfo, user, sessionParams.abiOverride,
- sessionParams.grantedRuntimePermissions, certificates);
+ sessionParams.grantedRuntimePermissions, certificates, sessionParams.installReason);
params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
msg.obj = params;
@@ -12358,7 +12358,7 @@
* @hide
*/
@Override
- public int installExistingPackageAsUser(String packageName, int userId) {
+ public int installExistingPackageAsUser(String packageName, int userId, int installReason) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES,
null);
PackageSetting pkgSetting;
@@ -12383,6 +12383,7 @@
if (!pkgSetting.getInstalled(userId)) {
pkgSetting.setInstalled(true, userId);
pkgSetting.setHidden(false, userId);
+ pkgSetting.setInstallReason(installReason, userId);
mSettings.writePackageRestrictionsLPr(userId);
installed = true;
}
@@ -13397,11 +13398,12 @@
final String[] grantedRuntimePermissions;
final VerificationInfo verificationInfo;
final Certificate[][] certificates;
+ final int installReason;
InstallParams(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer,
int installFlags, String installerPackageName, String volumeUuid,
VerificationInfo verificationInfo, UserHandle user, String packageAbiOverride,
- String[] grantedPermissions, Certificate[][] certificates) {
+ String[] grantedPermissions, Certificate[][] certificates, int installReason) {
super(user);
this.origin = origin;
this.move = move;
@@ -13413,6 +13415,7 @@
this.packageAbiOverride = packageAbiOverride;
this.grantedRuntimePermissions = grantedPermissions;
this.certificates = certificates;
+ this.installReason = installReason;
}
@Override
@@ -13882,6 +13885,7 @@
final String traceMethod;
final int traceCookie;
final Certificate[][] certificates;
+ final int installReason;
// 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
@@ -13892,7 +13896,8 @@
int installFlags, String installerPackageName, String volumeUuid,
UserHandle user, String[] instructionSets,
String abiOverride, String[] installGrantPermissions,
- String traceMethod, int traceCookie, Certificate[][] certificates) {
+ String traceMethod, int traceCookie, Certificate[][] certificates,
+ int installReason) {
this.origin = origin;
this.move = move;
this.installFlags = installFlags;
@@ -13906,6 +13911,7 @@
this.traceMethod = traceMethod;
this.traceCookie = traceCookie;
this.certificates = certificates;
+ this.installReason = installReason;
}
abstract int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException;
@@ -14000,7 +14006,8 @@
params.installerPackageName, params.volumeUuid,
params.getUser(), null /*instructionSets*/, params.packageAbiOverride,
params.grantedRuntimePermissions,
- params.traceMethod, params.traceCookie, params.certificates);
+ params.traceMethod, params.traceCookie, params.certificates,
+ params.installReason);
if (isFwdLocked()) {
throw new IllegalArgumentException("Forward locking only supported in ASEC");
}
@@ -14009,7 +14016,8 @@
/** Existing install */
FileInstallArgs(String codePath, String resourcePath, String[] instructionSets) {
super(OriginInfo.fromNothing(), null, null, 0, null, null, null, instructionSets,
- null, null, null, 0, null /*certificates*/);
+ null, null, null, 0, null /*certificates*/,
+ PackageManager.INSTALL_REASON_UNKNOWN);
this.codeFile = (codePath != null) ? new File(codePath) : null;
this.resourceFile = (resourcePath != null) ? new File(resourcePath) : null;
}
@@ -14234,15 +14242,17 @@
params.installerPackageName, params.volumeUuid,
params.getUser(), null /* instruction sets */, params.packageAbiOverride,
params.grantedRuntimePermissions,
- params.traceMethod, params.traceCookie, params.certificates);
+ params.traceMethod, params.traceCookie, params.certificates,
+ params.installReason);
}
/** Existing install */
AsecInstallArgs(String fullCodePath, String[] instructionSets,
boolean isExternal, boolean isForwardLocked) {
super(OriginInfo.fromNothing(), null, null, (isExternal ? INSTALL_EXTERNAL : 0)
- | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null,
- instructionSets, null, null, null, 0, null /*certificates*/);
+ | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null,
+ instructionSets, null, null, null, 0, null /*certificates*/,
+ PackageManager.INSTALL_REASON_UNKNOWN);
// Hackily pretend we're still looking at a full code path
if (!fullCodePath.endsWith(RES_FILE_NAME)) {
fullCodePath = new File(fullCodePath, RES_FILE_NAME).getAbsolutePath();
@@ -14258,8 +14268,9 @@
AsecInstallArgs(String cid, String[] instructionSets, boolean isForwardLocked) {
super(OriginInfo.fromNothing(), null, null, (isAsecExternal(cid) ? INSTALL_EXTERNAL : 0)
- | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null,
- instructionSets, null, null, null, 0, null /*certificates*/);
+ | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null,
+ instructionSets, null, null, null, 0, null /*certificates*/,
+ PackageManager.INSTALL_REASON_UNKNOWN);
this.cid = cid;
setMountPath(PackageHelper.getSdDir(cid));
}
@@ -14528,7 +14539,8 @@
params.installerPackageName, params.volumeUuid,
params.getUser(), null /* instruction sets */, params.packageAbiOverride,
params.grantedRuntimePermissions,
- params.traceMethod, params.traceCookie, params.certificates);
+ params.traceMethod, params.traceCookie, params.certificates,
+ params.installReason);
}
int copyApk(IMediaContainerService imcs, boolean temp) {
@@ -14759,7 +14771,7 @@
*/
private void installNewPackageLIF(PackageParser.Package pkg, final int policyFlags,
int scanFlags, UserHandle user, String installerPackageName, String volumeUuid,
- PackageInstalledInfo res) {
+ PackageInstalledInfo res, int installReason) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installNewPackage");
// Remember this for later, in case we need to rollback this install
@@ -14791,7 +14803,7 @@
PackageParser.Package newPackage = scanPackageTracedLI(pkg, policyFlags, scanFlags,
System.currentTimeMillis(), user);
- updateSettingsLI(newPackage, installerPackageName, null, res, user);
+ updateSettingsLI(newPackage, installerPackageName, null, res, user, installReason);
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
prepareAppDataAfterInstallLIF(newPackage);
@@ -14853,7 +14865,8 @@
}
private void replacePackageLIF(PackageParser.Package pkg, final int policyFlags, int scanFlags,
- UserHandle user, String installerPackageName, PackageInstalledInfo res) {
+ UserHandle user, String installerPackageName, PackageInstalledInfo res,
+ int installReason) {
final boolean isEphemeral = (policyFlags & PackageParser.PARSE_IS_EPHEMERAL) != 0;
final PackageParser.Package oldPackage;
@@ -14953,17 +14966,26 @@
res.removedInfo.removedPackage = oldPackage.packageName;
res.removedInfo.isUpdate = true;
res.removedInfo.origUsers = installedUsers;
+ final PackageSetting ps = mSettings.getPackageLPr(pkgName);
+ res.removedInfo.installReasons = new SparseArray<>(installedUsers.length);
+ for (int i = 0; i < installedUsers.length; i++) {
+ final int userId = installedUsers[i];
+ res.removedInfo.installReasons.put(userId, ps.getInstallReason(userId));
+ }
+
final int childCount = (oldPackage.childPackages != null)
? oldPackage.childPackages.size() : 0;
for (int i = 0; i < childCount; i++) {
boolean childPackageUpdated = false;
PackageParser.Package childPkg = oldPackage.childPackages.get(i);
+ final PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
if (res.addedChildPackages != null) {
PackageInstalledInfo childRes = res.addedChildPackages.get(childPkg.packageName);
if (childRes != null) {
childRes.removedInfo.uid = childPkg.applicationInfo.uid;
childRes.removedInfo.removedPackage = childPkg.packageName;
childRes.removedInfo.isUpdate = true;
+ childRes.removedInfo.installReasons = res.removedInfo.installReasons;
childPackageUpdated = true;
}
}
@@ -14973,7 +14995,6 @@
childRemovedRes.isUpdate = false;
childRemovedRes.dataRemoved = true;
synchronized (mPackages) {
- PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
if (childPs != null) {
childRemovedRes.origUsers = childPs.queryInstalledUsers(allUsers, true);
}
@@ -14996,10 +15017,10 @@
| (privileged ? PackageParser.PARSE_IS_PRIVILEGED : 0);
replaceSystemPackageLIF(oldPackage, pkg, systemPolicyFlags, scanFlags,
- user, allUsers, installerPackageName, res);
+ user, allUsers, installerPackageName, res, installReason);
} else {
replaceNonSystemPackageLIF(oldPackage, pkg, policyFlags, scanFlags,
- user, allUsers, installerPackageName, res);
+ user, allUsers, installerPackageName, res, installReason);
}
}
@@ -15014,7 +15035,8 @@
private void replaceNonSystemPackageLIF(PackageParser.Package deletedPackage,
PackageParser.Package pkg, final int policyFlags, int scanFlags, UserHandle user,
- int[] allUsers, String installerPackageName, PackageInstalledInfo res) {
+ int[] allUsers, String installerPackageName, PackageInstalledInfo res,
+ int installReason) {
if (DEBUG_INSTALL) Slog.d(TAG, "replaceNonSystemPackageLI: new=" + pkg + ", old="
+ deletedPackage);
@@ -15057,7 +15079,8 @@
try {
final PackageParser.Package newPackage = scanPackageTracedLI(pkg, policyFlags,
scanFlags | SCAN_UPDATE_TIME, System.currentTimeMillis(), user);
- updateSettingsLI(newPackage, installerPackageName, allUsers, res, user);
+ updateSettingsLI(newPackage, installerPackageName, allUsers, res, user,
+ installReason);
// Update the in-memory copy of the previous code paths.
PackageSetting ps = mSettings.mPackages.get(pkgName);
@@ -15153,7 +15176,8 @@
private void replaceSystemPackageLIF(PackageParser.Package deletedPackage,
PackageParser.Package pkg, final int policyFlags, int scanFlags, UserHandle user,
- int[] allUsers, String installerPackageName, PackageInstalledInfo res) {
+ int[] allUsers, String installerPackageName, PackageInstalledInfo res,
+ int installReason) {
if (DEBUG_INSTALL) Slog.d(TAG, "replaceSystemPackageLI: new=" + pkg
+ ", old=" + deletedPackage);
@@ -15226,7 +15250,8 @@
}
}
- updateSettingsLI(newPackage, installerPackageName, allUsers, res, user);
+ updateSettingsLI(newPackage, installerPackageName, allUsers, res, user,
+ installReason);
prepareAppDataAfterInstallLIF(newPackage);
}
} catch (PackageManagerException e) {
@@ -15414,10 +15439,10 @@
}
private void updateSettingsLI(PackageParser.Package newPackage, String installerPackageName,
- int[] allUsers, PackageInstalledInfo res, UserHandle user) {
+ int[] allUsers, PackageInstalledInfo res, UserHandle user, int installReason) {
// Update the parent package setting
updateSettingsInternalLI(newPackage, installerPackageName, allUsers, res.origUsers,
- res, user);
+ res, user, installReason);
// Update the child packages setting
final int childCount = (newPackage.childPackages != null)
? newPackage.childPackages.size() : 0;
@@ -15425,13 +15450,13 @@
PackageParser.Package childPackage = newPackage.childPackages.get(i);
PackageInstalledInfo childRes = res.addedChildPackages.get(childPackage.packageName);
updateSettingsInternalLI(childPackage, installerPackageName, allUsers,
- childRes.origUsers, childRes, user);
+ childRes.origUsers, childRes, user, installReason);
}
}
private void updateSettingsInternalLI(PackageParser.Package newPackage,
String installerPackageName, int[] allUsers, int[] installedForUsers,
- PackageInstalledInfo res, UserHandle user) {
+ PackageInstalledInfo res, UserHandle user, int installReason) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "updateSettings");
String pkgName = newPackage.packageName;
@@ -15489,6 +15514,30 @@
ps.setInstalled(true, userId);
ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, userId, installerPackageName);
}
+
+ // When replacing an existing package, preserve the original install reason for all
+ // users that had the package installed before.
+ final Set<Integer> previousUserIds = new ArraySet<>();
+ if (res.removedInfo != null && res.removedInfo.installReasons != null) {
+ final int installReasonCount = res.removedInfo.installReasons.size();
+ for (int i = 0; i < installReasonCount; i++) {
+ final int previousUserId = res.removedInfo.installReasons.keyAt(i);
+ final int previousInstallReason = res.removedInfo.installReasons.valueAt(i);
+ ps.setInstallReason(previousInstallReason, previousUserId);
+ previousUserIds.add(previousUserId);
+ }
+ }
+
+ // Set install reason for users that are having the package newly installed.
+ if (userId == UserHandle.USER_ALL) {
+ for (int currentUserId : sUserManager.getUserIds()) {
+ if (!previousUserIds.contains(currentUserId)) {
+ ps.setInstallReason(installReason, currentUserId);
+ }
+ }
+ } else if (!previousUserIds.contains(userId)) {
+ ps.setInstallReason(installReason, userId);
+ }
}
res.name = pkgName;
res.uid = newPackage.applicationInfo.uid;
@@ -15866,10 +15915,10 @@
"installPackageLI")) {
if (replace) {
replacePackageLIF(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
- installerPackageName, res);
+ installerPackageName, res, args.installReason);
} else {
installNewPackageLIF(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
- args.user, installerPackageName, volumeUuid, res);
+ args.user, installerPackageName, volumeUuid, res, args.installReason);
}
}
synchronized (mPackages) {
@@ -16377,6 +16426,7 @@
int removedAppId = -1;
int[] origUsers;
int[] removedUsers = null;
+ SparseArray<Integer> installReasons;
boolean isRemovedPackageSystemUpdate = false;
boolean isUpdate;
boolean dataRemoved;
@@ -17015,7 +17065,8 @@
false /*installed*/, true /*stopped*/, true /*notLaunched*/,
false /*hidden*/, false /*suspended*/, null, null, null,
false /*blockUninstall*/,
- ps.readUserState(nextUserId).domainVerificationStatus, 0);
+ ps.readUserState(nextUserId).domainVerificationStatus, 0,
+ PackageManager.INSTALL_REASON_UNKNOWN);
}
}
@@ -21034,7 +21085,8 @@
final OriginInfo origin = OriginInfo.fromExistingFile(codeFile);
final InstallParams params = new InstallParams(origin, move, installObserver, installFlags,
installerPackageName, volumeUuid, null /*verificationInfo*/, user,
- packageAbiOverride, null /*grantedPermissions*/, null /*certificates*/);
+ packageAbiOverride, null /*grantedPermissions*/, null /*certificates*/,
+ PackageManager.INSTALL_REASON_UNKNOWN);
params.setTraceMethod("movePackage").setTraceCookie(System.identityHashCode(params));
msg.obj = params;
@@ -21818,4 +21870,18 @@
public void deleteCompilerPackageStats(String pkgName) {
mCompilerStats.deletePackageStats(pkgName);
}
+
+ @Override
+ public int getInstallReason(String packageName, int userId) {
+ enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ true /* requireFullPermission */, false /* checkShell */,
+ "get install reason");
+ synchronized (mPackages) {
+ final PackageSetting ps = mSettings.mPackages.get(packageName);
+ if (ps != null) {
+ return ps.getInstallReason(userId);
+ }
+ }
+ return PackageManager.INSTALL_REASON_UNKNOWN;
+ }
}
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 9456a5c..b332fa5 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -292,6 +292,14 @@
return readUserState(userId).installed;
}
+ int getInstallReason(int userId) {
+ return readUserState(userId).installReason;
+ }
+
+ void setInstallReason(int installReason, int userId) {
+ modifyUserState(userId).installReason = installReason;
+ }
+
/** Only use for testing. Do NOT use in production code. */
@VisibleForTesting
SparseArray<PackageUserState> getUserState() {
@@ -377,7 +385,7 @@
boolean notLaunched, boolean hidden, boolean suspended,
String lastDisableAppCaller, ArraySet<String> enabledComponents,
ArraySet<String> disabledComponents, boolean blockUninstall, int domainVerifState,
- int linkGeneration) {
+ int linkGeneration, int installReason) {
PackageUserState state = modifyUserState(userId);
state.ceDataInode = ceDataInode;
state.enabled = enabled;
@@ -392,6 +400,7 @@
state.blockUninstall = blockUninstall;
state.domainVerificationStatus = domainVerifState;
state.appLinkGeneration = linkGeneration;
+ state.installReason = installReason;
}
ArraySet<String> getEnabledComponents(int userId) {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 395108b..8761a6d 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -216,6 +216,7 @@
private static final String ATTR_ENABLED_CALLER = "enabledCaller";
private static final String ATTR_DOMAIN_VERIFICATON_STATE = "domainVerificationStatus";
private static final String ATTR_APP_LINK_GENERATION = "app-link-generation";
+ private static final String ATTR_INSTALL_REASON = "install-reason";
private static final String ATTR_PACKAGE_NAME = "packageName";
private static final String ATTR_FINGERPRINT = "fingerprint";
@@ -736,7 +737,8 @@
false, // suspended
null, null, null,
false, // blockUninstall
- INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED, 0);
+ INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED, 0,
+ PackageManager.INSTALL_REASON_UNKNOWN);
}
}
}
@@ -1615,7 +1617,8 @@
false, // suspended
null, null, null,
false, // blockUninstall
- INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED, 0);
+ INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED, 0,
+ PackageManager.INSTALL_REASON_UNKNOWN);
}
return;
}
@@ -1695,6 +1698,8 @@
if (linkGeneration > maxAppLinkGeneration) {
maxAppLinkGeneration = linkGeneration;
}
+ final int installReason = XmlUtils.readIntAttribute(parser,
+ ATTR_INSTALL_REASON, PackageManager.INSTALL_REASON_UNKNOWN);
ArraySet<String> enabledComponents = null;
ArraySet<String> disabledComponents = null;
@@ -1717,7 +1722,7 @@
ps.setUserState(userId, ceDataInode, enabled, installed, stopped, notLaunched,
hidden, suspended, enabledCaller, enabledComponents, disabledComponents,
- blockUninstall, verifState, linkGeneration);
+ blockUninstall, verifState, linkGeneration, installReason);
} else if (tagName.equals("preferred-activities")) {
readPreferredActivitiesLPw(parser, userId);
} else if (tagName.equals(TAG_PERSISTENT_PREFERRED_ACTIVITIES)) {
@@ -2004,6 +2009,10 @@
XmlUtils.writeIntAttribute(serializer, ATTR_APP_LINK_GENERATION,
ustate.appLinkGeneration);
}
+ if (ustate.installReason != PackageManager.INSTALL_REASON_UNKNOWN) {
+ serializer.attribute(null, ATTR_INSTALL_REASON,
+ Integer.toString(ustate.installReason));
+ }
if (!ArrayUtils.isEmpty(ustate.enabledComponents)) {
serializer.startTag(null, TAG_ENABLED_COMPONENTS);
for (final String name : ustate.enabledComponents) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index cfd2bed..046840e 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -7576,7 +7576,8 @@
try {
// Install the profile owner if not present.
if (!mIPackageManager.isPackageAvailable(adminPkg, userHandle)) {
- mIPackageManager.installExistingPackageAsUser(adminPkg, userHandle);
+ mIPackageManager.installExistingPackageAsUser(adminPkg, userHandle,
+ PackageManager.INSTALL_REASON_POLICY);
}
} catch (RemoteException e) {
Slog.e(LOG_TAG, "Failed to make remote calls for createAndManageUser, "
@@ -7875,7 +7876,8 @@
}
// Install the app.
- mIPackageManager.installExistingPackageAsUser(packageName, userId);
+ mIPackageManager.installExistingPackageAsUser(packageName, userId,
+ PackageManager.INSTALL_REASON_POLICY);
} catch (RemoteException re) {
// shouldn't happen
@@ -7917,7 +7919,8 @@
String packageName = info.activityInfo.packageName;
if (isSystemApp(mIPackageManager, packageName, parentUserId)) {
numberOfAppsInstalled++;
- mIPackageManager.installExistingPackageAsUser(packageName, userId);
+ mIPackageManager.installExistingPackageAsUser(packageName, userId,
+ PackageManager.INSTALL_REASON_POLICY);
} else {
Slog.d(LOG_TAG, "Not enabling " + packageName + " since is not a"
+ " system app");
diff --git a/services/retaildemo/java/com/android/server/retaildemo/PreloadAppsInstaller.java b/services/retaildemo/java/com/android/server/retaildemo/PreloadAppsInstaller.java
index 2038c9e..3fa72dc 100644
--- a/services/retaildemo/java/com/android/server/retaildemo/PreloadAppsInstaller.java
+++ b/services/retaildemo/java/com/android/server/retaildemo/PreloadAppsInstaller.java
@@ -103,7 +103,8 @@
Log.d(TAG, "installExistingPackage " + packageName + " u" + userId);
}
try {
- mPackageManager.installExistingPackageAsUser(packageName, userId);
+ mPackageManager.installExistingPackageAsUser(packageName, userId,
+ PackageManager.INSTALL_REASON_UNKNOWN);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} finally {
diff --git a/services/tests/servicestests/src/com/android/server/retaildemo/PreloadAppsInstallerTest.java b/services/tests/servicestests/src/com/android/server/retaildemo/PreloadAppsInstallerTest.java
index 3eeeaf6..346dc42 100644
--- a/services/tests/servicestests/src/com/android/server/retaildemo/PreloadAppsInstallerTest.java
+++ b/services/tests/servicestests/src/com/android/server/retaildemo/PreloadAppsInstallerTest.java
@@ -103,7 +103,8 @@
observer.getValue().onPackageInstalled(path, PackageManager.INSTALL_SUCCEEDED,
null, null);
// Verify that we try to install the package in system user.
- verify(mIpm).installExistingPackageAsUser(path, UserHandle.USER_SYSTEM);
+ verify(mIpm).installExistingPackageAsUser(path, UserHandle.USER_SYSTEM,
+ PackageManager.INSTALL_REASON_UNKNOWN);
}
assertEquals("DEMO_USER_SETUP should be set to 1 after preloaded apps are installed",
"1",
@@ -139,7 +140,8 @@
observer.getValue().onPackageInstalled(path, PackageManager.INSTALL_SUCCEEDED,
null, null);
// Verify that we try to install the package in system user.
- verify(mIpm).installExistingPackageAsUser(path, UserHandle.USER_SYSTEM);
+ verify(mIpm).installExistingPackageAsUser(path, UserHandle.USER_SYSTEM,
+ PackageManager.INSTALL_REASON_UNKNOWN);
}
assertEquals("DEMO_USER_SETUP should be set to 1 after preloaded apps are installed",
"1",
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 7158969..c46d4a5 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -1064,4 +1064,11 @@
public Drawable loadUnbadgedItemIcon(PackageItemInfo itemInfo, ApplicationInfo appInfo) {
throw new UnsupportedOperationException();
}
+
+ /**
+ * @hide
+ */
+ public int getInstallReason(String packageName, UserHandle user) {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
index 8835b58..bc7bc74 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
@@ -868,4 +868,9 @@
public boolean isPackageAvailable(String packageName) {
return false;
}
+
+ @Override
+ public int getInstallReason(String packageName, UserHandle user) {
+ return INSTALL_REASON_UNKNOWN;
+ }
}