diff options
| author | 2014-10-14 22:31:16 +0000 | |
|---|---|---|
| committer | 2014-10-14 22:31:16 +0000 | |
| commit | 1201d2a018c85e9c5092e670b334cc4ed4ebcaef (patch) | |
| tree | 95100e70a9792f859fc87a222c5dc95474d81f43 | |
| parent | 60cdb909304f0d4b93a1a17228bdcc888f16cf41 (diff) | |
| parent | dbfbb17512fe6a5b3c7198d60b6a149969174a71 (diff) | |
am dbfbb175: Backport of ordering apps for boot dexopt.
* commit 'dbfbb17512fe6a5b3c7198d60b6a149969174a71':
Backport of ordering apps for boot dexopt.
| -rw-r--r-- | core/java/android/content/pm/PackageInfo.java | 5 | ||||
| -rw-r--r-- | core/java/android/content/pm/PackageParser.java | 5 | ||||
| -rw-r--r-- | services/core/java/com/android/server/pm/PackageManagerService.java | 196 |
3 files changed, 161 insertions, 45 deletions
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java index 765b2a921605..b66bd0172758 100644 --- a/core/java/android/content/pm/PackageInfo.java +++ b/core/java/android/content/pm/PackageInfo.java @@ -235,6 +235,9 @@ public class PackageInfo implements Parcelable { public int installLocation = INSTALL_LOCATION_INTERNAL_ONLY; /** @hide */ + public boolean coreApp; + + /** @hide */ public boolean requiredForAllUsers; /** @hide */ @@ -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(); diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 3364741e52c4..ca4ff6a49c6c 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -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; diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index a8a946adc8b8..b79e15756a11 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -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,65 +4472,167 @@ public class PackageManagerService extends IPackageManager.Stub { } if (pkgs != null) { - // Filter out packages that aren't recently used. - // - // The exception is first boot of a non-eng device (aka !mLazyDexOpt), which - // should do a full dexopt. - if (mLazyDexOpt || (!isFirstBoot() && mPackageUsage.isHistoricalPackageUsageAvailable())) { - // TODO: add a property to control this? - long dexOptLRUThresholdInMinutes; - if (mLazyDexOpt) { - dexOptLRUThresholdInMinutes = 30; // only last 30 minutes of apps for eng builds. - } else { - dexOptLRUThresholdInMinutes = 7 * 24 * 60; // apps used in the 7 days for users. - } - long dexOptLRUThresholdInMills = dexOptLRUThresholdInMinutes * 60 * 1000; - - int total = pkgs.size(); - int skipped = 0; - long now = System.currentTimeMillis(); - for (Iterator<PackageParser.Package> i = pkgs.iterator(); i.hasNext();) { - PackageParser.Package pkg = i.next(); - long then = pkg.mLastPackageUsageTimeInMills; - if (then + dexOptLRUThresholdInMills < now) { - if (DEBUG_DEXOPT) { - Log.i(TAG, "Skipping dexopt of " + pkg.packageName + " last resumed: " + - ((then == 0) ? "never" : new Date(then))); - } - i.remove(); - skipped++; + // 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, "Skipped optimizing " + skipped + " of " + total); + Log.i(TAG, "Adding app " + sortedPkgs.size() + ": " + pkg.packageName); } + sortedPkgs.add(pkg); } int i = 0; - for (PackageParser.Package pkg : pkgs) { - i++; - if (DEBUG_DEXOPT) { - Log.i(TAG, "Optimizing app " + i + " of " + pkgs.size() - + ": " + pkg.packageName); + 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; } - if (!isFirstBoot()) { - try { - ActivityManagerNative.getDefault().showBootMessage( - mContext.getResources().getString( - R.string.android_upgrading_apk, - i, pkgs.size()), true); - } catch (RemoteException e) { + 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 + // should do a full dexopt. + if (mLazyDexOpt || (!isFirstBoot() && mPackageUsage.isHistoricalPackageUsageAvailable())) { + // TODO: add a property to control this? + long dexOptLRUThresholdInMinutes; + if (mLazyDexOpt) { + dexOptLRUThresholdInMinutes = 30; // only last 30 minutes of apps for eng builds. + } else { + dexOptLRUThresholdInMinutes = 7 * 24 * 60; // apps used in the 7 days for users. + } + long dexOptLRUThresholdInMills = dexOptLRUThresholdInMinutes * 60 * 1000; + + int total = pkgs.size(); + int skipped = 0; + long now = System.currentTimeMillis(); + for (Iterator<PackageParser.Package> i = pkgs.iterator(); i.hasNext();) { + PackageParser.Package pkg = i.next(); + long then = pkg.mLastPackageUsageTimeInMills; + if (then + dexOptLRUThresholdInMills < now) { + if (DEBUG_DEXOPT) { + Log.i(TAG, "Skipping dexopt of " + pkg.packageName + " last resumed: " + + ((then == 0) ? "never" : new Date(then))); } + i.remove(); + skipped++; } - PackageParser.Package p = pkg; - synchronized (mInstallLock) { - performDexOptLI(p, null /* instruction sets */, false /* force dex */, false /* defer */, - true /* include dependencies */); - } + } + if (DEBUG_DEXOPT) { + Log.i(TAG, "Skipped optimizing " + skipped + " of " + total); } } } + 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 " + curr + " of " + total + ": " + pkg.packageName); + } + if (!isFirstBoot()) { + try { + ActivityManagerNative.getDefault().showBootMessage( + 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 */); + } + } + @Override public boolean performDexOptIfNeeded(String packageName, String instructionSet) { return performDexOpt(packageName, instructionSet, false); @@ -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) { |