Remove scanPackageInternal()

The final, major refactoring for this release. Replace
scanPackageInternal() with addForInit(). This new method delegates
all modifications of the package setting object to the existing
scanPackageOnly() method.

There is one block of code where we modify the ApplicationInfo
object in the PackageParser.Package. It could be argued [and I would
agree] that the ApplicationInfo doesn't belong in the Pacakge
object at all. But, regardless, updating this info is being done
in addForInit(). It would be ideal if we could push this down to
scanPackageOnly(). Unfortunately, we expect the ApplicationInfo
to be updated correctly prior to scanPackageOnly().

Bug: 63539144
Test: Manual.
Test: w/ base image
Test: 1] upgrade OTA
Test: 2] clean flash
Test: w/ image containing additional applications
Test: 1] add a system application
Test: 2] add a system application w/ version installed on /data. version on /data has greater version code
Test: 3] add a system application w/ version installed on /data. version on /data has lower version code
Test: 4] add a system application w/ version installed on /data. version on /data has signature mis-match
Test: 5] remove a system application
Test: 6] remove a system application w/ upgrade installed on /data
Test: 7] update a system application
Test: 8] update a system application w/ upgrade installed on /data. version on /data has greater version code
Test: 9] update a system application w/ upgrade installed on /data. version on /data has lower version code
Change-Id: I00a6f1cd056d9e5ee81154a522b7d50ea9174273
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 51087c3..8088ab5 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -811,6 +811,8 @@
 
     public static final int PARSE_MUST_BE_APK = 1 << 0;
     public static final int PARSE_IGNORE_PROCESSES = 1 << 1;
+    /** @deprecated forward lock no longer functional. remove. */
+    @Deprecated
     public static final int PARSE_FORWARD_LOCK = 1 << 2;
     public static final int PARSE_EXTERNAL_STORAGE = 1 << 3;
     public static final int PARSE_IS_SYSTEM_DIR = 1 << 4;
@@ -6001,6 +6003,8 @@
             }
         }
 
+        /** @deprecated Forward locked apps no longer supported. Resource path not needed. */
+        @Deprecated
         public void setApplicationInfoResourcePath(String resourcePath) {
             this.applicationInfo.setResourcePath(resourcePath);
             if (childPackages != null) {
@@ -6011,6 +6015,8 @@
             }
         }
 
+        /** @deprecated Forward locked apps no longer supported. Resource path not needed. */
+        @Deprecated
         public void setApplicationInfoBaseResourcePath(String resourcePath) {
             this.applicationInfo.setBaseResourcePath(resourcePath);
             if (childPackages != null) {
@@ -6059,6 +6065,8 @@
             // Children have no splits
         }
 
+        /** @deprecated Forward locked apps no longer supported. Resource path not needed. */
+        @Deprecated
         public void setApplicationInfoSplitResourcePaths(String[] resroucePaths) {
             this.applicationInfo.setSplitResourcePaths(resroucePaths);
             // Children have no splits
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index c02ce09..2a66de0 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2748,7 +2748,6 @@
                 for (String deletedAppName : possiblyDeletedUpdatedSystemApps) {
                     PackageParser.Package deletedPkg = mPackages.get(deletedAppName);
                     mSettings.removeDisabledSystemPackageLPw(deletedAppName);
-
                     final String msg;
                     if (deletedPkg == null) {
                         // should have found an update, but, we didn't; remove everything
@@ -8292,14 +8291,14 @@
         }
 
         // Scan the parent
-        PackageParser.Package scannedPkg = scanPackageInternalLI(pkg, parseFlags,
+        PackageParser.Package scannedPkg = addForInitLI(pkg, parseFlags,
                 scanFlags, currentTime, user);
 
         // Scan the children
         final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
         for (int i = 0; i < childCount; i++) {
             PackageParser.Package childPackage = pkg.childPackages.get(i);
-            scanPackageInternalLI(childPackage, parseFlags, scanFlags,
+            addForInitLI(childPackage, parseFlags, scanFlags,
                     currentTime, user);
         }
 
@@ -8312,50 +8311,85 @@
     }
 
     /**
-     *  Scans a package and returns the newly parsed package.
-     *  @throws PackageManagerException on a parse error.
+     * Adds a new package to the internal data structures during platform initialization.
+     * <p>After adding, the package is known to the system and available for querying.
+     * <p>For packages located on the device ROM [eg. packages located in /system, /vendor,
+     * etc...], additional checks are performed. Basic verification [such as ensuring
+     * matching signatures, checking version codes, etc...] occurs if the package is
+     * identical to a previously known package. If the package fails a signature check,
+     * the version installed on /data will be removed. If the version of the new package
+     * is less than or equal than the version on /data, it will be ignored.
+     * <p>Regardless of the package location, the results are applied to the internal
+     * structures and the package is made available to the rest of the system.
+     * <p>NOTE: The return value should be removed. It's the passed in package object.
      */
-    private PackageParser.Package scanPackageInternalLI(PackageParser.Package pkg,
+    private PackageParser.Package addForInitLI(PackageParser.Package pkg,
             @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
             @Nullable UserHandle user)
                     throws PackageManagerException {
-        PackageSetting ps = null;
-        PackageSetting updatedPs;
-        // reader
-        synchronized (mPackages) {
-            // Look to see if we already know about this package.
-            String oldName = mSettings.getRenamedPackageLPr(pkg.packageName);
-            if (pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(oldName)) {
-                // This package has been renamed to its original name.  Let's
-                // use that.
-                ps = mSettings.getPackageLPr(oldName);
-            }
-            // If there was no original package, see one for the real package name.
-            if (ps == null) {
-                ps = mSettings.getPackageLPr(pkg.packageName);
-            }
-            // Check to see if this package could be hiding/updating a system
-            // package.  Must look for it either under the original or real
-            // package name depending on our state.
-            updatedPs = mSettings.getDisabledSystemPkgLPr(ps != null ? ps.name : pkg.packageName);
-            if (DEBUG_INSTALL && updatedPs != null) Slog.d(TAG, "updatedPkg = " + updatedPs);
+        final boolean scanSystemPartition = (parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0;
+        final String renamedPkgName;
+        final PackageSetting disabledPkgSetting;
+        final boolean isSystemPkgUpdated;
+        final boolean pkgAlreadyExists;
+        PackageSetting pkgSetting;
 
-            // If this is a package we don't know about on the system partition, we
-            // may need to remove disabled child packages on the system partition
-            // or may need to not add child packages if the parent apk is updated
-            // on the data partition and no longer defines this child package.
-            if ((scanFlags & SCAN_AS_SYSTEM) != 0) {
-                // If this is a parent package for an updated system app and this system
-                // app got an OTA update which no longer defines some of the child packages
-                // we have to prune them from the disabled system packages.
-                PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(pkg.packageName);
-                if (disabledPs != null) {
+        // NOTE: installPackageLI() has the same code to setup the package's
+        // application info. This probably should be done lower in the call
+        // stack [such as scanPackageOnly()]. However, we verify the application
+        // info prior to that [in scanPackageNew()] and thus have to setup
+        // the application info early.
+        pkg.setApplicationVolumeUuid(pkg.volumeUuid);
+        pkg.setApplicationInfoCodePath(pkg.codePath);
+        pkg.setApplicationInfoBaseCodePath(pkg.baseCodePath);
+        pkg.setApplicationInfoSplitCodePaths(pkg.splitCodePaths);
+        pkg.setApplicationInfoResourcePath(pkg.codePath);
+        pkg.setApplicationInfoBaseResourcePath(pkg.baseCodePath);
+        pkg.setApplicationInfoSplitResourcePaths(pkg.splitCodePaths);
+
+        synchronized (mPackages) {
+            renamedPkgName = mSettings.getRenamedPackageLPr(pkg.mRealPackage);
+            final String realPkgName = getRealPackageName(pkg, renamedPkgName);
+            if (realPkgName != null) {
+                ensurePackageRenamed(pkg, renamedPkgName);
+            }
+            final PackageSetting originalPkgSetting = getOriginalPackageLocked(pkg, renamedPkgName);
+            final PackageSetting installedPkgSetting = mSettings.getPackageLPr(pkg.packageName);
+            pkgSetting = originalPkgSetting == null ? installedPkgSetting : originalPkgSetting;
+            pkgAlreadyExists = pkgSetting != null;
+            final String disabledPkgName = pkgAlreadyExists ? pkgSetting.name : pkg.packageName;
+            disabledPkgSetting = mSettings.getDisabledSystemPkgLPr(disabledPkgName);
+            isSystemPkgUpdated = disabledPkgSetting != null;
+
+            if (DEBUG_INSTALL && isSystemPkgUpdated) {
+                Slog.d(TAG, "updatedPkg = " + disabledPkgSetting);
+            }
+
+            final SharedUserSetting sharedUserSetting = (pkg.mSharedUserId != null)
+                    ? mSettings.getSharedUserLPw(pkg.mSharedUserId,
+                            0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true)
+                    : null;
+            if (DEBUG_PACKAGE_SCANNING
+                    && (parseFlags & PackageParser.PARSE_CHATTY) != 0
+                    && sharedUserSetting != null) {
+                Log.d(TAG, "Shared UserID " + pkg.mSharedUserId
+                        + " (uid=" + sharedUserSetting.userId + "):"
+                        + " packages=" + sharedUserSetting.packages);
+            }
+
+            if (scanSystemPartition) {
+                // Potentially prune child packages. If the application on the /system
+                // partition has been updated via OTA, but, is still disabled by a
+                // version on /data, cycle through all of its children packages and
+                // remove children that are no longer defined.
+                if (isSystemPkgUpdated) {
                     final int scannedChildCount = (pkg.childPackages != null)
                             ? pkg.childPackages.size() : 0;
-                    final int disabledChildCount = disabledPs.childPackageNames != null
-                            ? disabledPs.childPackageNames.size() : 0;
+                    final int disabledChildCount = disabledPkgSetting.childPackageNames != null
+                            ? disabledPkgSetting.childPackageNames.size() : 0;
                     for (int i = 0; i < disabledChildCount; i++) {
-                        String disabledChildPackageName = disabledPs.childPackageNames.get(i);
+                        String disabledChildPackageName =
+                                disabledPkgSetting.childPackageNames.get(i);
                         boolean disabledPackageAvailable = false;
                         for (int j = 0; j < scannedChildCount; j++) {
                             PackageParser.Package childPkg = pkg.childPackages.get(j);
@@ -8363,261 +8397,116 @@
                                 disabledPackageAvailable = true;
                                 break;
                             }
-                         }
-                         if (!disabledPackageAvailable) {
-                             mSettings.removeDisabledSystemPackageLPw(disabledChildPackageName);
-                         }
-                    }
-                }
-            }
-        }
-
-        final boolean isUpdatedPkg = updatedPs != null;
-        final boolean isUpdatedSystemPkg = isUpdatedPkg && (scanFlags & SCAN_AS_SYSTEM) != 0;
-        boolean isUpdatedPkgBetter = false;
-        // First check if this is a system package that may involve an update
-        if (isUpdatedSystemPkg) {
-            // If new package is not located in "/system/priv-app" (e.g. due to an OTA),
-            // it needs to drop FLAG_PRIVILEGED.
-            if (locationIsPrivileged(pkg.codePath)) {
-                updatedPs.pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
-            } else {
-                updatedPs.pkgPrivateFlags &= ~ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
-            }
-            // If new package is not located in "/oem" (e.g. due to an OTA),
-            // it needs to drop FLAG_OEM.
-            if (locationIsOem(pkg.codePath)) {
-                updatedPs.pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_OEM;
-            } else {
-                updatedPs.pkgPrivateFlags &= ~ApplicationInfo.PRIVATE_FLAG_OEM;
-            }
-            // If new package is not located in "/vendor" (e.g. due to an OTA),
-            // it needs to drop FLAG_VENDOR.
-            if (locationIsVendor(pkg.codePath)) {
-                updatedPs.pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_VENDOR;
-            } else {
-                updatedPs.pkgPrivateFlags &= ~ApplicationInfo.PRIVATE_FLAG_VENDOR;
-            }
-
-            if (ps != null && !ps.codePathString.equals(pkg.codePath)) {
-                // The path has changed from what was last scanned...  check the
-                // version of the new path against what we have stored to determine
-                // what to do.
-                if (DEBUG_INSTALL) Slog.d(TAG, "Path changing from " + ps.codePath);
-                if (pkg.getLongVersionCode() <= ps.versionCode) {
-                    // The system package has been updated and the code path does not match
-                    // Ignore entry. Skip it.
-                    if (DEBUG_INSTALL) Slog.i(TAG, "Package " + ps.name + " at " + pkg.codePath
-                            + " ignored: updated version " + ps.versionCode
-                            + " better than this " + pkg.getLongVersionCode());
-                    if (!updatedPs.codePathString.equals(pkg.codePath)) {
-                        Slog.w(PackageManagerService.TAG, "Code path for hidden system pkg "
-                                + ps.name + " changing from " + updatedPs.codePathString
-                                + " to " + pkg.codePath);
-                        final File codePath = new File(pkg.codePath);
-                        updatedPs.codePath = codePath;
-                        updatedPs.codePathString = pkg.codePath;
-                        updatedPs.resourcePath = codePath;
-                        updatedPs.resourcePathString = pkg.codePath;
-                    }
-                    updatedPs.pkg = pkg;
-                    updatedPs.versionCode = pkg.getLongVersionCode();
-
-                    // Update the disabled system child packages to point to the package too.
-                    final int childCount = updatedPs.childPackageNames != null
-                            ? updatedPs.childPackageNames.size() : 0;
-                    for (int i = 0; i < childCount; i++) {
-                        String childPackageName = updatedPs.childPackageNames.get(i);
-                        PackageSetting updatedChildPkg = mSettings.getDisabledSystemPkgLPr(
-                                childPackageName);
-                        if (updatedChildPkg != null) {
-                            updatedChildPkg.pkg = pkg;
-                            updatedChildPkg.versionCode = pkg.getLongVersionCode();
+                        }
+                        if (!disabledPackageAvailable) {
+                            mSettings.removeDisabledSystemPackageLPw(disabledChildPackageName);
                         }
                     }
-                } else {
-                    // The current app on the system partition is better than
-                    // what we have updated to on the data partition; switch
-                    // back to the system partition version.
-                    // At this point, its safely assumed that package installation for
-                    // apps in system partition will go through. If not there won't be a working
-                    // version of the app
-                    // writer
-                    synchronized (mPackages) {
-                        // Just remove the loaded entries from package lists.
-                        mPackages.remove(ps.name);
-                    }
-
-                    logCriticalInfo(Log.WARN, "Package " + ps.name + " at " + pkg.codePath
-                            + " reverting from " + ps.codePathString
-                            + ": new version " + pkg.getLongVersionCode()
-                            + " better than installed " + ps.versionCode);
-
-                    InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
-                            ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(ps));
-                    synchronized (mInstallLock) {
-                        args.cleanUpResourcesLI();
-                    }
-                    synchronized (mPackages) {
-                        mSettings.enableSystemPackageLPw(ps.name);
-                    }
-                    isUpdatedPkgBetter = true;
+                    // we're updating the disabled package, so, scan it as the package setting
+                    final ScanRequest request = new ScanRequest(pkg, sharedUserSetting,
+                            disabledPkgSetting /* pkgSetting */, null /* disabledPkgSetting */,
+                            null /* originalPkgSetting */, null, parseFlags, scanFlags,
+                            (pkg == mPlatformPackage), user);
+                    scanPackageOnlyLI(request, mFactoryTest, -1L);
                 }
             }
         }
 
-        String resourcePath = null;
-        String baseResourcePath = null;
-        if ((parseFlags & PackageParser.PARSE_FORWARD_LOCK) != 0 && !isUpdatedPkgBetter) {
-            if (ps != null && ps.resourcePathString != null) {
-                resourcePath = ps.resourcePathString;
-                baseResourcePath = ps.resourcePathString;
-            } else {
-                // Should not happen at all. Just log an error.
-                Slog.e(TAG, "Resource path not set for package " + pkg.packageName);
+        final boolean newPkgChangedPaths =
+                pkgAlreadyExists && !pkgSetting.codePathString.equals(pkg.codePath);
+        final boolean newPkgVersionGreater =
+                pkgAlreadyExists && pkg.getLongVersionCode() > pkgSetting.versionCode;
+        final boolean isSystemPkgBetter = scanSystemPartition && isSystemPkgUpdated
+                && newPkgChangedPaths && newPkgVersionGreater;
+        if (isSystemPkgBetter) {
+            // The version of the application on /system is greater than the version on
+            // /data. Switch back to the application on /system.
+            // It's safe to assume the application on /system will correctly scan. If not,
+            // there won't be a working copy of the application.
+            synchronized (mPackages) {
+                // just remove the loaded entries from package lists
+                mPackages.remove(pkgSetting.name);
             }
-        } else {
-            resourcePath = pkg.codePath;
-            baseResourcePath = pkg.baseCodePath;
+
+            logCriticalInfo(Log.WARN,
+                    "System package updated;"
+                    + " name: " + pkgSetting.name
+                    + "; " + pkgSetting.versionCode + " --> " + pkg.getLongVersionCode()
+                    + "; " + pkgSetting.codePathString + " --> " + pkg.codePath);
+
+            final InstallArgs args = createInstallArgsForExisting(
+                    packageFlagsToInstallFlags(pkgSetting), pkgSetting.codePathString,
+                    pkgSetting.resourcePathString, getAppDexInstructionSets(pkgSetting));
+            args.cleanUpResourcesLI();
+            synchronized (mPackages) {
+                mSettings.enableSystemPackageLPw(pkgSetting.name);
+            }
         }
 
-        // Set application objects path explicitly.
-        pkg.setApplicationVolumeUuid(pkg.volumeUuid);
-        pkg.setApplicationInfoCodePath(pkg.codePath);
-        pkg.setApplicationInfoBaseCodePath(pkg.baseCodePath);
-        pkg.setApplicationInfoSplitCodePaths(pkg.splitCodePaths);
-        pkg.setApplicationInfoResourcePath(resourcePath);
-        pkg.setApplicationInfoBaseResourcePath(baseResourcePath);
-        pkg.setApplicationInfoSplitResourcePaths(pkg.splitCodePaths);
-
-        // throw an exception if we have an update to a system application, but, it's not more
-        // recent than the package we've already scanned
-        if (isUpdatedSystemPkg && !isUpdatedPkgBetter) {
-            // Set CPU Abis to application info.
-            if ((scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0) {
-                final String cpuAbiOverride = deriveAbiOverride(pkg.cpuAbiOverride, updatedPs);
-                derivePackageAbi(pkg, cpuAbiOverride, false);
-            } else {
-                pkg.applicationInfo.primaryCpuAbi = updatedPs.primaryCpuAbiString;
-                pkg.applicationInfo.secondaryCpuAbi = updatedPs.secondaryCpuAbiString;
-            }
-            pkg.mExtras = updatedPs;
-
+        if (scanSystemPartition && isSystemPkgUpdated && !isSystemPkgBetter) {
+            // The version of the application on the /system partition is less than or
+            // equal to the version on the /data partition. Throw an exception and use
+            // the application already installed on the /data partition.
             throw new PackageManagerException(Log.WARN, "Package " + pkg.packageName + " at "
-                    + pkg.codePath + " ignored: updated version " + updatedPs.versionCode
+                    + pkg.codePath + " ignored: updated version " + disabledPkgSetting.versionCode
                     + " better than this " + pkg.getLongVersionCode());
         }
 
-        if (isUpdatedPkg) {
-            // updated system applications don't initially have the SCAN_AS_SYSTEM flag set
-            scanFlags |= SCAN_AS_SYSTEM;
+        // verify certificates against what was last scanned
+        collectCertificatesLI(pkgSetting, pkg, parseFlags);
 
-            // An updated privileged application will not have the PARSE_IS_PRIVILEGED
-            // flag set initially
-            if ((updatedPs.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
-                scanFlags |= SCAN_AS_PRIVILEGED;
-            }
-
-            // An updated OEM app will not have the SCAN_AS_OEM
-            // flag set initially
-            if ((updatedPs.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0) {
-                scanFlags |= SCAN_AS_OEM;
-            }
-
-            // An updated vendor app will not have the SCAN_AS_VENDOR
-            // flag set initially
-            if ((updatedPs.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0) {
-                scanFlags |= SCAN_AS_VENDOR;
-            }
-        }
-
-        // Verify certificates against what was last scanned
-        collectCertificatesLI(ps, pkg, parseFlags);
-
-        /*
-         * A new system app appeared, but we already had a non-system one of the
-         * same name installed earlier.
-         */
         boolean shouldHideSystemApp = false;
-        if (!isUpdatedPkg && ps != null
-                && (parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0 && !isSystemApp(ps)) {
-            /*
-             * Check to make sure the signatures match first. If they don't,
-             * wipe the installed application and its data.
-             */
-            if (compareSignatures(ps.signatures.mSignatures, pkg.mSigningDetails.signatures)
+        // A new application appeared on /system, but, we already have a copy of
+        // the application installed on /data.
+        if (scanSystemPartition && !isSystemPkgUpdated && pkgAlreadyExists
+                && !pkgSetting.isSystem()) {
+            // if the signatures don't match, wipe the installed application and its data
+            if (compareSignatures(pkgSetting.signatures.mSignatures, pkg.mSigningDetails.signatures)
                     != PackageManager.SIGNATURE_MATCH) {
-                logCriticalInfo(Log.WARN, "Package " + ps.name + " appeared on system, but"
-                        + " signatures don't match existing userdata copy; removing");
+                logCriticalInfo(Log.WARN,
+                        "System package signature mismatch;"
+                        + " name: " + pkgSetting.name);
                 try (PackageFreezer freezer = freezePackage(pkg.packageName,
                         "scanPackageInternalLI")) {
                     deletePackageLIF(pkg.packageName, null, true, null, 0, null, false, null);
                 }
-                ps = null;
-            } else {
-                /*
-                 * If the newly-added system app is an older version than the
-                 * already installed version, hide it. It will be scanned later
-                 * and re-added like an update.
-                 */
-                if (pkg.getLongVersionCode() <= ps.versionCode) {
-                    shouldHideSystemApp = true;
-                    logCriticalInfo(Log.INFO, "Package " + ps.name + " appeared at " + pkg.codePath
-                            + " but new version " + pkg.getLongVersionCode()
-                            + " better than installed " + ps.versionCode + "; hiding system");
-                } else {
-                    /*
-                     * The newly found system app is a newer version that the
-                     * one previously installed. Simply remove the
-                     * already-installed application and replace it with our own
-                     * while keeping the application data.
-                     */
-                    logCriticalInfo(Log.WARN, "Package " + ps.name + " at " + pkg.codePath
-                            + " reverting from " + ps.codePathString + ": new version "
-                            + pkg.getLongVersionCode() + " better than installed "
-                            + ps.versionCode);
-                    InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
-                            ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(ps));
-                    synchronized (mInstallLock) {
-                        args.cleanUpResourcesLI();
-                    }
+                pkgSetting = null;
+            } else if (newPkgVersionGreater) {
+                // The application on /system is newer than the application on /data.
+                // Simply remove the application on /data [keeping application data]
+                // and replace it with the version on /system.
+                logCriticalInfo(Log.WARN,
+                        "System package enabled;"
+                        + " name: " + pkgSetting.name
+                        + "; " + pkgSetting.versionCode + " --> " + pkg.getLongVersionCode()
+                        + "; " + pkgSetting.codePathString + " --> " + pkg.codePath);
+                InstallArgs args = createInstallArgsForExisting(
+                        packageFlagsToInstallFlags(pkgSetting), pkgSetting.codePathString,
+                        pkgSetting.resourcePathString, getAppDexInstructionSets(pkgSetting));
+                synchronized (mInstallLock) {
+                    args.cleanUpResourcesLI();
                 }
+            } else {
+                // The application on /system is older than the application on /data. Hide
+                // the application on /system and the version on /data will be scanned later
+                // and re-added like an update.
+                shouldHideSystemApp = true;
+                logCriticalInfo(Log.INFO,
+                        "System package disabled;"
+                        + " name: " + pkgSetting.name
+                        + "; old: " + pkgSetting.codePathString + " @ " + pkgSetting.versionCode
+                        + "; new: " + pkg.codePath + " @ " + pkg.codePath);
             }
         }
 
-        // The apk is forward locked (not public) if its code and resources
-        // are kept in different files. (except for app in either system or
-        // vendor path).
-        // TODO grab this value from PackageSettings
-        if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
-            if (ps != null && !ps.codePath.equals(ps.resourcePath)) {
-                parseFlags |= PackageParser.PARSE_FORWARD_LOCK;
-            }
-        }
-
-        final int userId = ((user == null) ? 0 : user.getIdentifier());
-        if (ps != null && ps.getInstantApp(userId)) {
-            scanFlags |= SCAN_AS_INSTANT_APP;
-        }
-        if (ps != null && ps.getVirtulalPreload(userId)) {
-            scanFlags |= SCAN_AS_VIRTUAL_PRELOAD;
-        }
-
-        // Note that we invoke the following method only if we are about to unpack an application
-        PackageParser.Package scannedPkg = scanPackageNewLI(pkg, parseFlags, scanFlags
+        final PackageParser.Package scannedPkg = scanPackageNewLI(pkg, parseFlags, scanFlags
                 | SCAN_UPDATE_SIGNATURE, currentTime, user);
 
-        /*
-         * If the system app should be overridden by a previously installed
-         * data, hide the system app now and let the /data/app scan pick it up
-         * again.
-         */
         if (shouldHideSystemApp) {
             synchronized (mPackages) {
                 mSettings.disableSystemPackageLPw(pkg.packageName, true);
             }
         }
-
         return scannedPkg;
     }
 
@@ -9711,10 +9600,53 @@
             this.originalPkgSetting = originalPkgSetting;
             this.realPkgName = realPkgName;
             this.parseFlags = parseFlags;
-            this.scanFlags = scanFlags;
+            this.scanFlags = adjustScanFlags(scanFlags, pkgSetting, disabledPkgSetting, user);
             this.isPlatformPackage = isPlatformPackage;
             this.user = user;
         }
+
+        /**
+         * Returns the actual scan flags depending upon the state of the other settings.
+         * <p>Updated system applications will not have the following flags set
+         * by default and need to be adjusted after the fact:
+         * <ul>
+         * <li>{@link #SCAN_AS_SYSTEM}</li>
+         * <li>{@link #SCAN_AS_PRIVILEGED}</li>
+         * <li>{@link #SCAN_AS_OEM}</li>
+         * <li>{@link #SCAN_AS_VENDOR}</li>
+         * <li>{@link #SCAN_AS_INSTANT_APP}</li>
+         * <li>{@link #SCAN_AS_VIRTUAL_PRELOAD}</li>
+         * </ul>
+         */
+        private static @ScanFlags int adjustScanFlags(@ScanFlags int scanFlags,
+                PackageSetting pkgSetting, PackageSetting disabledPkgSetting, UserHandle user) {
+            if (disabledPkgSetting != null) {
+                // updated system application, must at least have SCAN_AS_SYSTEM
+                scanFlags |= SCAN_AS_SYSTEM;
+                if ((disabledPkgSetting.pkgPrivateFlags
+                        & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
+                    scanFlags |= SCAN_AS_PRIVILEGED;
+                }
+                if ((disabledPkgSetting.pkgPrivateFlags
+                        & ApplicationInfo.PRIVATE_FLAG_OEM) != 0) {
+                    scanFlags |= SCAN_AS_OEM;
+                }
+                if ((disabledPkgSetting.pkgPrivateFlags
+                        & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0) {
+                    scanFlags |= SCAN_AS_VENDOR;
+                }
+            }
+            if (pkgSetting != null) {
+                final int userId = ((user == null) ? 0 : user.getIdentifier());
+                if (pkgSetting.getInstantApp(userId)) {
+                    scanFlags |= SCAN_AS_INSTANT_APP;
+                }
+                if (pkgSetting.getVirtulalPreload(userId)) {
+                    scanFlags |= SCAN_AS_VIRTUAL_PRELOAD;
+                }
+            }
+            return scanFlags;
+        }
     }
 
     @GuardedBy("mInstallLock")
@@ -9963,10 +9895,16 @@
      */
     private static @Nullable String getRealPackageName(@NonNull PackageParser.Package pkg,
             @Nullable String renamedPkgName) {
-        if (pkg.mOriginalPackages == null || !pkg.mOriginalPackages.contains(renamedPkgName)) {
-            return null;
+        if (isPackageRenamed(pkg, renamedPkgName)) {
+            return pkg.mRealPackage;
         }
-        return pkg.mRealPackage;
+        return null;
+    }
+
+    /** Returns {@code true} if the package has been renamed. Otherwise, {@code false}. */
+    private static boolean isPackageRenamed(@NonNull PackageParser.Package pkg,
+            @Nullable String renamedPkgName) {
+        return pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(renamedPkgName);
     }
 
     /**
@@ -9979,7 +9917,7 @@
     @GuardedBy("mPackages")
     private @Nullable PackageSetting getOriginalPackageLocked(@NonNull PackageParser.Package pkg,
             @Nullable String renamedPkgName) {
-        if (pkg.mOriginalPackages == null || pkg.mOriginalPackages.contains(renamedPkgName)) {
+        if (!isPackageRenamed(pkg, renamedPkgName)) {
             return null;
         }
         for (int i = pkg.mOriginalPackages.size() - 1; i >= 0; --i) {
@@ -10102,7 +10040,6 @@
             usesStaticLibraries = new String[pkg.usesStaticLibraries.size()];
             pkg.usesStaticLibraries.toArray(usesStaticLibraries);
         }
-
         final boolean createNewPackage = (pkgSetting == null);
         if (createNewPackage) {
             final String parentPackageName = (pkg.parentPackage != null)
@@ -10126,17 +10063,17 @@
             // secondaryCpuAbi are not known at this point so we always update them
             // to null here, only to reset them at a later point.
             Settings.updatePackageSetting(pkgSetting, disabledPkgSetting, sharedUserSetting,
-                    destCodeFile, pkg.applicationInfo.nativeLibraryDir,
+                    destCodeFile, destResourceFile, pkg.applicationInfo.nativeLibraryDir,
                     pkg.applicationInfo.primaryCpuAbi, pkg.applicationInfo.secondaryCpuAbi,
                     pkg.applicationInfo.flags, pkg.applicationInfo.privateFlags,
                     pkg.getChildPackageNames(), UserManagerService.getInstance(),
                     usesStaticLibraries, pkg.usesStaticLibrariesVersions);
         }
         if (createNewPackage && originalPkgSetting != null) {
-            // If we are first transitioning from an original package,
-            // fix up the new package's name now.  We need to do this after
-            // looking up the package under its new name, so getPackageLP
-            // can take care of fiddling things correctly.
+            // This is the initial transition from the original package, so,
+            // fix up the new package's name now. We must do this after looking
+            // up the package under its new name, so getPackageLP takes care of
+            // fiddling things correctly.
             pkg.setPackageName(originalPkgSetting.name);
 
             // File a report about this.
@@ -10223,7 +10160,7 @@
         // would've already compiled the app without taking the package setting into
         // account.
         if ((scanFlags & SCAN_NO_DEX) == 0 && (scanFlags & SCAN_NEW_INSTALL) != 0) {
-            if (cpuAbiOverride == null && pkgSetting.cpuAbiOverrideString != null) {
+            if (cpuAbiOverride == null && pkg.packageName != null) {
                 Slog.w(TAG, "Ignoring persisted ABI override " + cpuAbiOverride +
                         " for package " + pkg.packageName);
             }
@@ -10238,7 +10175,7 @@
         pkg.cpuAbiOverride = cpuAbiOverride;
 
         if (DEBUG_ABI_SELECTION) {
-            Slog.d(TAG, "Resolved nativeLibraryRoot for " + pkg.applicationInfo.packageName
+            Slog.d(TAG, "Resolved nativeLibraryRoot for " + pkg.packageName
                     + " to root=" + pkg.applicationInfo.nativeLibraryRootDir + ", isa="
                     + pkg.applicationInfo.nativeLibraryRootRequiresIsa);
         }
@@ -10293,6 +10230,22 @@
         }
         pkgSetting.setTimeStamp(scanFileTime);
 
+        pkgSetting.pkg = pkg;
+        pkgSetting.pkgFlags = pkg.applicationInfo.flags;
+        if (pkg.getLongVersionCode() != pkgSetting.versionCode) {
+            pkgSetting.versionCode = pkg.getLongVersionCode();
+        }
+        // Update volume if needed
+        final String volumeUuid = pkg.applicationInfo.volumeUuid;
+        if (!Objects.equals(volumeUuid, pkgSetting.volumeUuid)) {
+            Slog.i(PackageManagerService.TAG,
+                    "Update" + (pkgSetting.isSystem() ? " system" : "")
+                    + " package " + pkg.packageName
+                    + " volume from " + pkgSetting.volumeUuid
+                    + " to " + volumeUuid);
+            pkgSetting.volumeUuid = volumeUuid;
+        }
+
         return new ScanResult(true, pkgSetting, changedAbiCodePath);
     }
 
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index 37f9a74..2552643 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -18,6 +18,7 @@
 
 import android.content.pm.PackageParser;
 import android.content.pm.Signature;
+import android.content.pm.PackageParser.SigningDetails;
 import android.os.Environment;
 import android.util.Slog;
 import android.util.Xml;
@@ -451,7 +452,8 @@
     public String getMatchedSeInfo(PackageParser.Package pkg) {
         // Check for exact signature matches across all certs.
         Signature[] certs = mCerts.toArray(new Signature[0]);
-        if (!Signature.areExactMatch(certs, pkg.mSigningDetails.signatures)) {
+        if (pkg.mSigningDetails != SigningDetails.UNKNOWN
+                && !Signature.areExactMatch(certs, pkg.mSigningDetails.signatures)) {
             return null;
         }
 
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index ed80c70..102f52f 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -783,11 +783,12 @@
      */
     static void updatePackageSetting(@NonNull PackageSetting pkgSetting,
             @Nullable PackageSetting disabledPkg, @Nullable SharedUserSetting sharedUser,
-            @NonNull File codePath, @Nullable String legacyNativeLibraryPath,
-            @Nullable String primaryCpuAbi, @Nullable String secondaryCpuAbi,
-            int pkgFlags, int pkgPrivateFlags, @Nullable List<String> childPkgNames,
-            @NonNull UserManagerService userManager, @Nullable String[] usesStaticLibraries,
-            @Nullable long[] usesStaticLibrariesVersions) throws PackageManagerException {
+            @NonNull File codePath, File resourcePath,
+            @Nullable String legacyNativeLibraryPath, @Nullable String primaryCpuAbi,
+            @Nullable String secondaryCpuAbi, int pkgFlags, int pkgPrivateFlags,
+            @Nullable List<String> childPkgNames, @NonNull UserManagerService userManager,
+            @Nullable String[] usesStaticLibraries, @Nullable long[] usesStaticLibrariesVersions)
+                    throws PackageManagerException {
         final String pkgName = pkgSetting.name;
         if (pkgSetting.sharedUser != sharedUser) {
             PackageManagerService.reportSettingsProblem(Log.WARN,
@@ -799,29 +800,19 @@
         }
 
         if (!pkgSetting.codePath.equals(codePath)) {
-            // Check to see if its a disabled system app
-            if ((pkgSetting.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0) {
-                // This is an updated system app with versions in both system
-                // and data partition. Just let the most recent version
-                // take precedence.
-                Slog.w(PackageManagerService.TAG,
-                        "Trying to update system app code path from "
-                        + pkgSetting.codePathString + " to " + codePath.toString());
-            } else {
-                // Just a change in the code path is not an issue, but
-                // let's log a message about it.
-                Slog.i(PackageManagerService.TAG,
-                        "Package " + pkgName + " codePath changed from "
-                        + pkgSetting.codePath + " to " + codePath
-                        + "; Retaining data and using new");
-
-                // The owner user's installed flag is set false
-                // when the application was installed by other user
-                // and the installed flag is not updated
-                // when the application is appended as system app later.
-                if ((pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0
-                        && disabledPkg == null) {
-                    List<UserInfo> allUserInfos = getAllUsers(userManager);
+            final boolean isSystem = pkgSetting.isSystem();
+            Slog.i(PackageManagerService.TAG,
+                    "Update" + (isSystem ? " system" : "")
+                    + " package " + pkgName
+                    + " code path from " + pkgSetting.codePathString
+                    + " to " + codePath.toString()
+                    + "; Retain data and using new");
+            if (!isSystem) {
+                // The package isn't considered as installed if the application was
+                // first installed by another user. Update the installed flag when the
+                // application ever becomes part of the system.
+                if ((pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0 && disabledPkg == null) {
+                    final List<UserInfo> allUserInfos = getAllUsers(userManager);
                     if (allUserInfos != null) {
                         for (UserInfo userInfo : allUserInfos) {
                             pkgSetting.setInstalled(true, userInfo.id);
@@ -829,14 +820,24 @@
                     }
                 }
 
-                /*
-                 * Since we've changed paths, we need to prefer the new
-                 * native library path over the one stored in the
-                 * package settings since we might have moved from
-                 * internal to external storage or vice versa.
-                 */
+                // Since we've changed paths, prefer the new native library path over
+                // the one stored in the package settings since we might have moved from
+                // internal to external storage or vice versa.
                 pkgSetting.legacyNativeLibraryPathString = legacyNativeLibraryPath;
             }
+            pkgSetting.codePath = codePath;
+            pkgSetting.codePathString = codePath.toString();
+        }
+        if (!pkgSetting.resourcePath.equals(resourcePath)) {
+            final boolean isSystem = pkgSetting.isSystem();
+            Slog.i(PackageManagerService.TAG,
+                    "Update" + (isSystem ? " system" : "")
+                    + " package " + pkgName
+                    + " resource path from " + pkgSetting.resourcePathString
+                    + " to " + resourcePath.toString()
+                    + "; Retain data and using new");
+            pkgSetting.resourcePath = resourcePath;
+            pkgSetting.resourcePathString = resourcePath.toString();
         }
         // If what we are scanning is a system (and possibly privileged) package,
         // then make it so, regardless of whether it was previously installed only
@@ -853,13 +854,14 @@
         if (childPkgNames != null) {
             pkgSetting.childPackageNames = new ArrayList<>(childPkgNames);
         }
-        if (usesStaticLibraries != null) {
-            pkgSetting.usesStaticLibraries = Arrays.copyOf(usesStaticLibraries,
-                    usesStaticLibraries.length);
-        }
-        if (usesStaticLibrariesVersions != null) {
-            pkgSetting.usesStaticLibrariesVersions = Arrays.copyOf(usesStaticLibrariesVersions,
-                    usesStaticLibrariesVersions.length);
+        // Update static shared library dependencies if needed
+        if (usesStaticLibraries != null && usesStaticLibrariesVersions != null
+                && usesStaticLibraries.length == usesStaticLibrariesVersions.length) {
+            pkgSetting.usesStaticLibraries = usesStaticLibraries;
+            pkgSetting.usesStaticLibrariesVersions = usesStaticLibrariesVersions;
+        } else {
+            pkgSetting.usesStaticLibraries = null;
+            pkgSetting.usesStaticLibrariesVersions = null;
         }
     }
 
@@ -912,70 +914,18 @@
                 userId);
     }
 
+    // TODO: Move to scanPackageOnlyLI() after verifying signatures are setup correctly
+    // by that time.
     void insertPackageSettingLPw(PackageSetting p, PackageParser.Package pkg) {
-        p.pkg = pkg;
-        // pkg.mSetEnabled = p.getEnabled(userId);
-        // pkg.mSetStopped = p.getStopped(userId);
-        final String volumeUuid = pkg.applicationInfo.volumeUuid;
-        final String codePath = pkg.applicationInfo.getCodePath();
-        final String resourcePath = pkg.applicationInfo.getResourcePath();
-        final String legacyNativeLibraryPath = pkg.applicationInfo.nativeLibraryRootDir;
-        // Update volume if needed
-        if (!Objects.equals(volumeUuid, p.volumeUuid)) {
-            Slog.w(PackageManagerService.TAG, "Volume for " + p.pkg.packageName +
-                    " changing from " + p.volumeUuid + " to " + volumeUuid);
-            p.volumeUuid = volumeUuid;
-        }
-        // Update code path if needed
-        if (!Objects.equals(codePath, p.codePathString)) {
-            Slog.w(PackageManagerService.TAG, "Code path for " + p.pkg.packageName +
-                    " changing from " + p.codePathString + " to " + codePath);
-            p.codePath = new File(codePath);
-            p.codePathString = codePath;
-        }
-        //Update resource path if needed
-        if (!Objects.equals(resourcePath, p.resourcePathString)) {
-            Slog.w(PackageManagerService.TAG, "Resource path for " + p.pkg.packageName +
-                    " changing from " + p.resourcePathString + " to " + resourcePath);
-            p.resourcePath = new File(resourcePath);
-            p.resourcePathString = resourcePath;
-        }
-        // Update the native library paths if needed
-        if (!Objects.equals(legacyNativeLibraryPath, p.legacyNativeLibraryPathString)) {
-            p.legacyNativeLibraryPathString = legacyNativeLibraryPath;
-        }
-
-        // Update the required Cpu Abi
-        p.primaryCpuAbiString = pkg.applicationInfo.primaryCpuAbi;
-        p.secondaryCpuAbiString = pkg.applicationInfo.secondaryCpuAbi;
-        p.cpuAbiOverrideString = pkg.cpuAbiOverride;
-        // Update version code if needed
-        if (pkg.getLongVersionCode() != p.versionCode) {
-            p.versionCode = pkg.getLongVersionCode();
-        }
         // Update signatures if needed.
         if (p.signatures.mSignatures == null) {
             p.signatures.assignSignatures(pkg.mSigningDetails);
         }
-        // Update flags if needed.
-        if (pkg.applicationInfo.flags != p.pkgFlags) {
-            p.pkgFlags = pkg.applicationInfo.flags;
-        }
         // If this app defines a shared user id initialize
         // the shared user signatures as well.
         if (p.sharedUser != null && p.sharedUser.signatures.mSignatures == null) {
             p.sharedUser.signatures.assignSignatures(pkg.mSigningDetails);
         }
-        // Update static shared library dependencies if needed
-        if (pkg.usesStaticLibraries != null && pkg.usesStaticLibrariesVersions != null
-                && pkg.usesStaticLibraries.size() == pkg.usesStaticLibrariesVersions.length) {
-            p.usesStaticLibraries = new String[pkg.usesStaticLibraries.size()];
-            pkg.usesStaticLibraries.toArray(p.usesStaticLibraries);
-            p.usesStaticLibrariesVersions = pkg.usesStaticLibrariesVersions;
-        } else {
-            p.usesStaticLibraries = null;
-            p.usesStaticLibrariesVersions = null;
-        }
         addPackageSettingLPw(p, p.sharedUser);
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index b073ee5..0abb48f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -294,6 +294,7 @@
                 null /*disabledPkg*/,
                 null /*sharedUser*/,
                 UPDATED_CODE_PATH /*codePath*/,
+                null /*resourcePath*/,
                 null /*legacyNativeLibraryPath*/,
                 "arm64-v8a" /*primaryCpuAbi*/,
                 "armeabi" /*secondaryCpuAbi*/,
@@ -327,6 +328,7 @@
                 null /*disabledPkg*/,
                 null /*sharedUser*/,
                 UPDATED_CODE_PATH /*codePath*/,
+                null /*resourcePath*/,
                 null /*legacyNativeLibraryPath*/,
                 "arm64-v8a" /*primaryCpuAbi*/,
                 "armeabi" /*secondaryCpuAbi*/,
@@ -367,6 +369,7 @@
                     null /*disabledPkg*/,
                     testUserSetting01 /*sharedUser*/,
                     UPDATED_CODE_PATH /*codePath*/,
+                    null /*resourcePath*/,
                     null /*legacyNativeLibraryPath*/,
                     "arm64-v8a" /*primaryCpuAbi*/,
                     "armeabi" /*secondaryCpuAbi*/,