Merge "Add install reason"
diff --git a/api/current.txt b/api/current.txt
index ec0faf4..afaec20 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -9944,6 +9944,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);
@@ -10177,6 +10178,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 8827279..bb89c65 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -10365,6 +10365,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);
@@ -10653,6 +10654,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 dcc693a..c0b240a 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -9972,6 +9972,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);
@@ -10044,6 +10045,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);
@@ -10206,6 +10208,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
@@ -39123,6 +39127,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..f33362f 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 b29bf7b..7e47a11 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -12149,7 +12149,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;
 
@@ -12185,7 +12185,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;
 
@@ -12369,7 +12369,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;
@@ -12394,6 +12394,7 @@
                 if (!pkgSetting.getInstalled(userId)) {
                     pkgSetting.setInstalled(true, userId);
                     pkgSetting.setHidden(false, userId);
+                    pkgSetting.setInstallReason(installReason, userId);
                     mSettings.writePackageRestrictionsLPr(userId);
                     installed = true;
                 }
@@ -13408,11 +13409,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;
@@ -13424,6 +13426,7 @@
             this.packageAbiOverride = packageAbiOverride;
             this.grantedRuntimePermissions = grantedPermissions;
             this.certificates = certificates;
+            this.installReason = installReason;
         }
 
         @Override
@@ -13893,6 +13896,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
@@ -13903,7 +13907,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;
@@ -13917,6 +13922,7 @@
             this.traceMethod = traceMethod;
             this.traceCookie = traceCookie;
             this.certificates = certificates;
+            this.installReason = installReason;
         }
 
         abstract int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException;
@@ -14011,7 +14017,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");
             }
@@ -14020,7 +14027,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;
         }
@@ -14245,15 +14253,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();
@@ -14269,8 +14279,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));
         }
@@ -14539,7 +14550,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) {
@@ -14770,7 +14782,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
@@ -14802,7 +14814,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);
@@ -14864,7 +14876,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;
@@ -14964,17 +14977,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;
                 }
             }
@@ -14984,7 +15006,6 @@
                 childRemovedRes.isUpdate = false;
                 childRemovedRes.dataRemoved = true;
                 synchronized (mPackages) {
-                    PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
                     if (childPs != null) {
                         childRemovedRes.origUsers = childPs.queryInstalledUsers(allUsers, true);
                     }
@@ -15007,10 +15028,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);
         }
     }
 
@@ -15025,7 +15046,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);
 
@@ -15068,7 +15090,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);
@@ -15164,7 +15187,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);
 
@@ -15237,7 +15261,8 @@
                     }
                 }
 
-                updateSettingsLI(newPackage, installerPackageName, allUsers, res, user);
+                updateSettingsLI(newPackage, installerPackageName, allUsers, res, user,
+                        installReason);
                 prepareAppDataAfterInstallLIF(newPackage);
             }
         } catch (PackageManagerException e) {
@@ -15425,10 +15450,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;
@@ -15436,13 +15461,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;
@@ -15500,6 +15525,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;
@@ -15877,10 +15926,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) {
@@ -16388,6 +16437,7 @@
         int removedAppId = -1;
         int[] origUsers;
         int[] removedUsers = null;
+        SparseArray<Integer> installReasons;
         boolean isRemovedPackageSystemUpdate = false;
         boolean isUpdate;
         boolean dataRemoved;
@@ -17026,7 +17076,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);
         }
     }
 
@@ -21045,7 +21096,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;
 
@@ -21829,4 +21881,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 f1a28e2..471acba 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -7604,7 +7604,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, "
@@ -7903,7 +7904,8 @@
                 }
 
                 // Install the app.
-                mIPackageManager.installExistingPackageAsUser(packageName, userId);
+                mIPackageManager.installExistingPackageAsUser(packageName, userId,
+                        PackageManager.INSTALL_REASON_POLICY);
 
             } catch (RemoteException re) {
                 // shouldn't happen
@@ -7945,7 +7947,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;
+    }
 }