Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dbfbb175 authored by Jeff Hao's avatar Jeff Hao
Browse files

Backport of ordering apps for boot dexopt.

This is a squashed commit of the following changes:

1. Order apps by priority when performing boot dexopt.
   (cherry picked from commit 65cde7d4)

2. Improve priority ordering of apps when performing boot dexopt.
   Added core apps and updated system apps.
   (cherry picked from commit 272bf3a2)

3. Stop boot dexopt when low on memory.
   (cherry picked from commit 1d892dcb)

Bug: 17641843
Change-Id: Ie32f1c21047d3462aaf728f7633fecf647ba2b47
parent 0a1ffdb3
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -234,6 +234,9 @@ public class PackageInfo implements Parcelable {
     */
    public int installLocation = INSTALL_LOCATION_INTERNAL_ONLY;

    /** @hide */
    public boolean coreApp;

    /** @hide */
    public boolean requiredForAllUsers;

@@ -293,6 +296,7 @@ public class PackageInfo implements Parcelable {
        dest.writeTypedArray(reqFeatures, parcelableFlags);
        dest.writeTypedArray(featureGroups, parcelableFlags);
        dest.writeInt(installLocation);
        dest.writeInt(coreApp ? 1 : 0);
        dest.writeInt(requiredForAllUsers ? 1 : 0);
        dest.writeString(restrictedAccountType);
        dest.writeString(requiredAccountType);
@@ -337,6 +341,7 @@ public class PackageInfo implements Parcelable {
        reqFeatures = source.createTypedArray(FeatureInfo.CREATOR);
        featureGroups = source.createTypedArray(FeatureGroupInfo.CREATOR);
        installLocation = source.readInt();
        coreApp = source.readInt() != 0;
        requiredForAllUsers = source.readInt() != 0;
        restrictedAccountType = source.readString();
        requiredAccountType = source.readString();
+5 −0
Original line number Diff line number Diff line
@@ -415,6 +415,7 @@ public class PackageParser {
        pi.sharedUserLabel = p.mSharedUserLabel;
        pi.applicationInfo = generateApplicationInfo(p, flags, state, userId);
        pi.installLocation = p.installLocation;
        pi.coreApp = p.coreApp;
        if ((pi.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0
                || (pi.applicationInfo.flags&ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
            pi.requiredForAllUsers = p.mRequiredForAllUsers;
@@ -1384,6 +1385,8 @@ public class PackageParser {
                PARSE_DEFAULT_INSTALL_LOCATION);
        pkg.applicationInfo.installLocation = pkg.installLocation;

        pkg.coreApp = attrs.getAttributeBooleanValue(null, "coreApp", false);

        sa.recycle();

        /* Set the global "forward lock" flag */
@@ -4267,6 +4270,8 @@ public class PackageParser {

        public int installLocation;

        public boolean coreApp;

        /* An app that's required for all users and cannot be uninstalled for a user */
        public boolean mRequiredForAllUsers;

+151 −45
Original line number Diff line number Diff line
@@ -80,6 +80,7 @@ import org.xmlpull.v1.XmlSerializer;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.AppGlobals;
import android.app.IActivityManager;
import android.app.admin.IDevicePolicyManager;
import android.app.backup.IBackupManager;
@@ -4471,6 +4472,97 @@ public class PackageManagerService extends IPackageManager.Stub {
        }
        if (pkgs != null) {
            // Sort apps by importance for dexopt ordering. Important apps are given more priority
            // in case the device runs out of space.
            ArrayList<PackageParser.Package> sortedPkgs = new ArrayList<PackageParser.Package>();
            // Give priority to core apps.
            for (Iterator<PackageParser.Package> it = pkgs.iterator(); it.hasNext();) {
                PackageParser.Package pkg = it.next();
                if (pkg.coreApp) {
                    if (DEBUG_DEXOPT) {
                        Log.i(TAG, "Adding core app " + sortedPkgs.size() + ": " + pkg.packageName);
                    }
                    sortedPkgs.add(pkg);
                    it.remove();
                }
            }
            // Give priority to system apps that listen for pre boot complete.
            Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
            HashSet<String> pkgNames = getPackageNamesForIntent(intent);
            for (Iterator<PackageParser.Package> it = pkgs.iterator(); it.hasNext();) {
                PackageParser.Package pkg = it.next();
                if (pkgNames.contains(pkg.packageName)) {
                    if (DEBUG_DEXOPT) {
                        Log.i(TAG, "Adding pre boot system app " + sortedPkgs.size() + ": " + pkg.packageName);
                    }
                    sortedPkgs.add(pkg);
                    it.remove();
                }
            }
            // Give priority to system apps.
            for (Iterator<PackageParser.Package> it = pkgs.iterator(); it.hasNext();) {
                PackageParser.Package pkg = it.next();
                if (isSystemApp(pkg) && !isUpdatedSystemApp(pkg)) {
                    if (DEBUG_DEXOPT) {
                        Log.i(TAG, "Adding system app " + sortedPkgs.size() + ": " + pkg.packageName);
                    }
                    sortedPkgs.add(pkg);
                    it.remove();
                }
            }
            // Give priority to updated system apps.
            for (Iterator<PackageParser.Package> it = pkgs.iterator(); it.hasNext();) {
                PackageParser.Package pkg = it.next();
                if (isUpdatedSystemApp(pkg)) {
                    if (DEBUG_DEXOPT) {
                        Log.i(TAG, "Adding updated system app " + sortedPkgs.size() + ": " + pkg.packageName);
                    }
                    sortedPkgs.add(pkg);
                    it.remove();
                }
            }
            // Give priority to apps that listen for boot complete.
            intent = new Intent(Intent.ACTION_BOOT_COMPLETED);
            pkgNames = getPackageNamesForIntent(intent);
            for (Iterator<PackageParser.Package> it = pkgs.iterator(); it.hasNext();) {
                PackageParser.Package pkg = it.next();
                if (pkgNames.contains(pkg.packageName)) {
                    if (DEBUG_DEXOPT) {
                        Log.i(TAG, "Adding boot app " + sortedPkgs.size() + ": " + pkg.packageName);
                    }
                    sortedPkgs.add(pkg);
                    it.remove();
                }
            }
            // Filter out packages that aren't recently used.
            filterRecentlyUsedApps(pkgs);
            // Add all remaining apps.
            for (PackageParser.Package pkg : pkgs) {
                if (DEBUG_DEXOPT) {
                    Log.i(TAG, "Adding app " + sortedPkgs.size() + ": " + pkg.packageName);
                }
                sortedPkgs.add(pkg);
            }
            int i = 0;
            int total = sortedPkgs.size();
            File dataDir = Environment.getDataDirectory();
            long lowThreshold = StorageManager.from(mContext).getStorageLowBytes(dataDir);
            if (lowThreshold == 0) {
                throw new IllegalStateException("Invalid low memory threshold");
            }
            for (PackageParser.Package pkg : sortedPkgs) {
                long usableSpace = dataDir.getUsableSpace();
                if (usableSpace < lowThreshold) {
                    Log.w(TAG, "Not running dexopt on remaining apps due to low memory: " + usableSpace);
                    break;
                }
                performBootDexOpt(pkg, ++i, total);
            }
        }
    }
    private void filterRecentlyUsedApps(HashSet<PackageParser.Package> pkgs) {
        // Filter out packages that aren't recently used.
        //
        // The exception is first boot of a non-eng device (aka !mLazyDexOpt), which
@@ -4504,29 +4596,40 @@ public class PackageManagerService extends IPackageManager.Stub {
                Log.i(TAG, "Skipped optimizing " + skipped + " of " + total);
            }
        }
    }
            int i = 0;
            for (PackageParser.Package pkg : pkgs) {
                i++;
    private HashSet<String> getPackageNamesForIntent(Intent intent) {
        List<ResolveInfo> ris = null;
        try {
            ris = AppGlobals.getPackageManager().queryIntentReceivers(
                    intent, null, 0, UserHandle.USER_OWNER);
        } catch (RemoteException e) {
        }
        HashSet<String> pkgNames = new HashSet<String>();
        if (ris != null) {
            for (ResolveInfo ri : ris) {
                pkgNames.add(ri.activityInfo.packageName);
            }
        }
        return pkgNames;
    }
    private void performBootDexOpt(PackageParser.Package pkg, int curr, int total) {
        if (DEBUG_DEXOPT) {
                    Log.i(TAG, "Optimizing app " + i + " of " + pkgs.size()
                          + ": " + pkg.packageName);
            Log.i(TAG, "Optimizing app " + curr + " of " + total + ": " + pkg.packageName);
        }
        if (!isFirstBoot()) {
            try {
                ActivityManagerNative.getDefault().showBootMessage(
                                mContext.getResources().getString(
                                        R.string.android_upgrading_apk,
                                        i, pkgs.size()), true);
                        mContext.getResources().getString(R.string.android_upgrading_apk,
                                curr, total), true);
            } catch (RemoteException e) {
            }
        }
        PackageParser.Package p = pkg;
        synchronized (mInstallLock) {
                    performDexOptLI(p, null /* instruction sets */, false /* force dex */, false /* defer */,
                            true /* include dependencies */);
                }
            }
            performDexOptLI(p, null /* instruction sets */, false /* force dex */,
                            false /* defer */, true /* include dependencies */);
        }
    }
@@ -5077,6 +5180,9 @@ public class PackageManagerService extends IPackageManager.Stub {
        if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
        } else {
            // Only allow system apps to be flagged as core apps.
            pkg.coreApp = false;
        }
        if ((parseFlags&PackageParser.PARSE_IS_PRIVILEGED) != 0) {