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 commit65cde7d42d
) 2. Improve priority ordering of apps when performing boot dexopt. Added core apps and updated system apps. (cherry picked from commit272bf3a274
) 3. Stop boot dexopt when low on memory. (cherry picked from commit1d892dcb6b
) Bug: 17641843 Change-Id: Ie32f1c21047d3462aaf728f7633fecf647ba2b47
This commit is contained in:
@ -234,6 +234,9 @@ public class PackageInfo implements Parcelable {
|
|||||||
*/
|
*/
|
||||||
public int installLocation = INSTALL_LOCATION_INTERNAL_ONLY;
|
public int installLocation = INSTALL_LOCATION_INTERNAL_ONLY;
|
||||||
|
|
||||||
|
/** @hide */
|
||||||
|
public boolean coreApp;
|
||||||
|
|
||||||
/** @hide */
|
/** @hide */
|
||||||
public boolean requiredForAllUsers;
|
public boolean requiredForAllUsers;
|
||||||
|
|
||||||
@ -293,6 +296,7 @@ public class PackageInfo implements Parcelable {
|
|||||||
dest.writeTypedArray(reqFeatures, parcelableFlags);
|
dest.writeTypedArray(reqFeatures, parcelableFlags);
|
||||||
dest.writeTypedArray(featureGroups, parcelableFlags);
|
dest.writeTypedArray(featureGroups, parcelableFlags);
|
||||||
dest.writeInt(installLocation);
|
dest.writeInt(installLocation);
|
||||||
|
dest.writeInt(coreApp ? 1 : 0);
|
||||||
dest.writeInt(requiredForAllUsers ? 1 : 0);
|
dest.writeInt(requiredForAllUsers ? 1 : 0);
|
||||||
dest.writeString(restrictedAccountType);
|
dest.writeString(restrictedAccountType);
|
||||||
dest.writeString(requiredAccountType);
|
dest.writeString(requiredAccountType);
|
||||||
@ -337,6 +341,7 @@ public class PackageInfo implements Parcelable {
|
|||||||
reqFeatures = source.createTypedArray(FeatureInfo.CREATOR);
|
reqFeatures = source.createTypedArray(FeatureInfo.CREATOR);
|
||||||
featureGroups = source.createTypedArray(FeatureGroupInfo.CREATOR);
|
featureGroups = source.createTypedArray(FeatureGroupInfo.CREATOR);
|
||||||
installLocation = source.readInt();
|
installLocation = source.readInt();
|
||||||
|
coreApp = source.readInt() != 0;
|
||||||
requiredForAllUsers = source.readInt() != 0;
|
requiredForAllUsers = source.readInt() != 0;
|
||||||
restrictedAccountType = source.readString();
|
restrictedAccountType = source.readString();
|
||||||
requiredAccountType = source.readString();
|
requiredAccountType = source.readString();
|
||||||
|
@ -415,6 +415,7 @@ public class PackageParser {
|
|||||||
pi.sharedUserLabel = p.mSharedUserLabel;
|
pi.sharedUserLabel = p.mSharedUserLabel;
|
||||||
pi.applicationInfo = generateApplicationInfo(p, flags, state, userId);
|
pi.applicationInfo = generateApplicationInfo(p, flags, state, userId);
|
||||||
pi.installLocation = p.installLocation;
|
pi.installLocation = p.installLocation;
|
||||||
|
pi.coreApp = p.coreApp;
|
||||||
if ((pi.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0
|
if ((pi.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0
|
||||||
|| (pi.applicationInfo.flags&ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
|
|| (pi.applicationInfo.flags&ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
|
||||||
pi.requiredForAllUsers = p.mRequiredForAllUsers;
|
pi.requiredForAllUsers = p.mRequiredForAllUsers;
|
||||||
@ -1384,6 +1385,8 @@ public class PackageParser {
|
|||||||
PARSE_DEFAULT_INSTALL_LOCATION);
|
PARSE_DEFAULT_INSTALL_LOCATION);
|
||||||
pkg.applicationInfo.installLocation = pkg.installLocation;
|
pkg.applicationInfo.installLocation = pkg.installLocation;
|
||||||
|
|
||||||
|
pkg.coreApp = attrs.getAttributeBooleanValue(null, "coreApp", false);
|
||||||
|
|
||||||
sa.recycle();
|
sa.recycle();
|
||||||
|
|
||||||
/* Set the global "forward lock" flag */
|
/* Set the global "forward lock" flag */
|
||||||
@ -4267,6 +4270,8 @@ public class PackageParser {
|
|||||||
|
|
||||||
public int installLocation;
|
public int installLocation;
|
||||||
|
|
||||||
|
public boolean coreApp;
|
||||||
|
|
||||||
/* An app that's required for all users and cannot be uninstalled for a user */
|
/* An app that's required for all users and cannot be uninstalled for a user */
|
||||||
public boolean mRequiredForAllUsers;
|
public boolean mRequiredForAllUsers;
|
||||||
|
|
||||||
|
@ -80,6 +80,7 @@ import org.xmlpull.v1.XmlSerializer;
|
|||||||
|
|
||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
import android.app.ActivityManagerNative;
|
import android.app.ActivityManagerNative;
|
||||||
|
import android.app.AppGlobals;
|
||||||
import android.app.IActivityManager;
|
import android.app.IActivityManager;
|
||||||
import android.app.admin.IDevicePolicyManager;
|
import android.app.admin.IDevicePolicyManager;
|
||||||
import android.app.backup.IBackupManager;
|
import android.app.backup.IBackupManager;
|
||||||
@ -4471,6 +4472,97 @@ public class PackageManagerService extends IPackageManager.Stub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (pkgs != null) {
|
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.
|
// Filter out packages that aren't recently used.
|
||||||
//
|
//
|
||||||
// The exception is first boot of a non-eng device (aka !mLazyDexOpt), which
|
// 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);
|
Log.i(TAG, "Skipped optimizing " + skipped + " of " + total);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int i = 0;
|
private HashSet<String> getPackageNamesForIntent(Intent intent) {
|
||||||
for (PackageParser.Package pkg : pkgs) {
|
List<ResolveInfo> ris = null;
|
||||||
i++;
|
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) {
|
if (DEBUG_DEXOPT) {
|
||||||
Log.i(TAG, "Optimizing app " + i + " of " + pkgs.size()
|
Log.i(TAG, "Optimizing app " + curr + " of " + total + ": " + pkg.packageName);
|
||||||
+ ": " + pkg.packageName);
|
|
||||||
}
|
}
|
||||||
if (!isFirstBoot()) {
|
if (!isFirstBoot()) {
|
||||||
try {
|
try {
|
||||||
ActivityManagerNative.getDefault().showBootMessage(
|
ActivityManagerNative.getDefault().showBootMessage(
|
||||||
mContext.getResources().getString(
|
mContext.getResources().getString(R.string.android_upgrading_apk,
|
||||||
R.string.android_upgrading_apk,
|
curr, total), true);
|
||||||
i, pkgs.size()), true);
|
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PackageParser.Package p = pkg;
|
PackageParser.Package p = pkg;
|
||||||
synchronized (mInstallLock) {
|
synchronized (mInstallLock) {
|
||||||
performDexOptLI(p, null /* instruction sets */, false /* force dex */, false /* defer */,
|
performDexOptLI(p, null /* instruction sets */, false /* force dex */,
|
||||||
true /* include dependencies */);
|
false /* defer */, true /* include dependencies */);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5077,6 +5180,9 @@ public class PackageManagerService extends IPackageManager.Stub {
|
|||||||
|
|
||||||
if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
|
if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
|
||||||
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
|
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) {
|
if ((parseFlags&PackageParser.PARSE_IS_PRIVILEGED) != 0) {
|
||||||
|
Reference in New Issue
Block a user