summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Jeff Hao <jeffhao@google.com> 2014-10-14 22:31:16 +0000
committer Android Git Automerger <android-git-automerger@android.com> 2014-10-14 22:31:16 +0000
commit1201d2a018c85e9c5092e670b334cc4ed4ebcaef (patch)
tree95100e70a9792f859fc87a222c5dc95474d81f43
parent60cdb909304f0d4b93a1a17228bdcc888f16cf41 (diff)
parentdbfbb17512fe6a5b3c7198d60b6a149969174a71 (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.java5
-rw-r--r--core/java/android/content/pm/PackageParser.java5
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java196
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) {