Merge "Dexopt for Context.createPackageContext when code is included." into lmp-dev

This commit is contained in:
Narayan Kamath
2014-07-16 19:08:02 +00:00
committed by Android (Google) Code Review
6 changed files with 64 additions and 28 deletions

View File

@ -56,6 +56,7 @@ import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Objects;
final class IntentReceiverLeaked extends AndroidRuntimeException {
public IntentReceiverLeaked(String msg) {
@ -252,6 +253,22 @@ public final class LoadedApk {
}
if (mIncludeCode && !mPackageName.equals("android")) {
// Avoid the binder call when the package is the current application package.
// The activity manager will perform ensure that dexopt is performed before
// spinning up the process.
if (!Objects.equals(mPackageName, ActivityThread.currentPackageName())) {
final String isa = VMRuntime.getRuntime().vmInstructionSet();
try {
// TODO: We can probably do away with the isa argument since
// the AM and PM have enough information to figure this out
// themselves. If we do need it, we should match it against the
// list of devices ISAs before sending it down to installd.
ActivityThread.getPackageManager().performDexOptIfNeeded(mPackageName, isa);
} catch (RemoteException re) {
// Ignored.
}
}
final ArrayList<String> zipPaths = new ArrayList<>();
final ArrayList<String> libPaths = new ArrayList<>();

View File

@ -384,10 +384,16 @@ interface IPackageManager {
/**
* Ask the package manager to perform dex-opt (if needed) on the given
* package, if it already hasn't done mode. Only does this if running
* in the special development "no pre-dexopt" mode.
* package and for the given instruction set if it already hasn't done
* so.
*
* If the supplied instructionSet is null, the package manager will use
* the packages default instruction set.
*
* In most cases, apps are dexopted in advance and this function will
* be a no-op.
*/
boolean performDexOpt(String packageName);
boolean performDexOptIfNeeded(String packageName, String instructionSet);
/**
* Update status of external media on the package manager to scan and

View File

@ -4201,7 +4201,7 @@ public class PackageParser {
public int mPreferredOrder = 0;
// For use by package manager to keep track of where it needs to do dexopt.
public boolean mDexOptNeeded = true;
public final ArraySet<String> mDexOptPerformed = new ArraySet<>(4);
// For use by package manager to keep track of when a package was last used.
public long mLastPackageUsageTimeInMills;

View File

@ -2809,7 +2809,7 @@ public final class ActivityManagerService extends ActivityManagerNative
void ensurePackageDexOpt(String packageName) {
IPackageManager pm = AppGlobals.getPackageManager();
try {
if (pm.performDexOpt(packageName)) {
if (pm.performDexOptIfNeeded(packageName, null /* instruction set */)) {
mDidDexOpt = true;
}
} catch (RemoteException e) {

View File

@ -75,7 +75,7 @@ public class BackgroundDexOptService extends JobService {
schedule(BackgroundDexOptService.this);
return;
}
pm.performDexOpt(pkg, false);
pm.performDexOpt(pkg, null /* instruction set */, false);
}
// ran to completion, so we abandon our timeslice and do not reschedule
jobFinished(jobParams, false);

View File

@ -26,7 +26,6 @@ import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
import static android.content.pm.PackageManager.INSTALL_EXTERNAL;
import static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
import static android.content.pm.PackageManager.INSTALL_FAILED_CONFLICTING_PROVIDER;
import static android.content.pm.PackageManager.INSTALL_FAILED_CPU_ABI_INCOMPATIBLE;
import static android.content.pm.PackageManager.INSTALL_FAILED_DEXOPT;
import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION;
@ -4542,24 +4541,29 @@ public class PackageManagerService extends IPackageManager.Stub {
}
PackageParser.Package p = pkg;
synchronized (mInstallLock) {
if (p.mDexOptNeeded) {
performDexOptLI(p, false /* force dex */, false /* defer */,
true /* include dependencies */);
}
performDexOptLI(p, null /* instruction sets */, false /* force dex */, false /* defer */,
true /* include dependencies */);
}
}
}
}
@Override
public boolean performDexOpt(String packageName) {
enforceSystemOrRoot("Only the system can request dexopt be performed");
return performDexOpt(packageName, true);
public boolean performDexOptIfNeeded(String packageName, String instructionSet) {
return performDexOpt(packageName, instructionSet, true);
}
public boolean performDexOpt(String packageName, boolean updateUsage) {
private static String getPrimaryInstructionSet(ApplicationInfo info) {
if (info.primaryCpuAbi == null) {
return getPreferredInstructionSet();
}
return VMRuntime.getInstructionSet(info.primaryCpuAbi);
}
public boolean performDexOpt(String packageName, String instructionSet, boolean updateUsage) {
PackageParser.Package p;
final String targetInstructionSet;
synchronized (mPackages) {
p = mPackages.get(packageName);
if (p == null) {
@ -4569,13 +4573,17 @@ public class PackageManagerService extends IPackageManager.Stub {
p.mLastPackageUsageTimeInMills = System.currentTimeMillis();
}
mPackageUsage.write(false);
if (!p.mDexOptNeeded) {
targetInstructionSet = instructionSet != null ? instructionSet :
getPrimaryInstructionSet(p.applicationInfo);
if (p.mDexOptPerformed.contains(targetInstructionSet)) {
return false;
}
}
synchronized (mInstallLock) {
return performDexOptLI(p, false /* force dex */, false /* defer */,
final String[] instructionSets = new String[] { targetInstructionSet };
return performDexOptLI(p, instructionSets, false /* force dex */, false /* defer */,
true /* include dependencies */) == DEX_OPT_PERFORMED;
}
}
@ -4585,9 +4593,9 @@ public class PackageManagerService extends IPackageManager.Stub {
synchronized (mPackages) {
for (PackageParser.Package p : mPackages.values()) {
if (DEBUG_DEXOPT) {
Log.i(TAG, p.packageName + " mDexOptNeeded=" + p.mDexOptNeeded);
Log.i(TAG, p.packageName + " mDexOptPerformed=" + p.mDexOptPerformed.toArray());
}
if (!p.mDexOptNeeded) {
if (!p.mDexOptPerformed.isEmpty()) {
continue;
}
if (pkgs == null) {
@ -4655,6 +4663,10 @@ public class PackageManagerService extends IPackageManager.Stub {
// 3.) we are skipping an unneeded dexopt
for (String path : paths) {
for (String instructionSet : instructionSets) {
if (!forceDex && pkg.mDexOptPerformed.contains(instructionSet)) {
continue;
}
try {
final boolean isDexOptNeeded = DexFile.isDexOptNeededInternal(path,
pkg.packageName, instructionSet, defer);
@ -4669,10 +4681,10 @@ public class PackageManagerService extends IPackageManager.Stub {
// Don't bother running dexopt again if we failed, it will probably
// just result in an error again. Also, don't bother dexopting for other
// paths & ISAs.
pkg.mDexOptNeeded = false;
return DEX_OPT_FAILED;
} else {
performedDexOpt = true;
pkg.mDexOptPerformed.add(instructionSet);
}
}
@ -4706,7 +4718,6 @@ public class PackageManagerService extends IPackageManager.Stub {
// deferred dex-opt. We've either dex-opted one more paths or instruction sets or
// we've skipped all of them because they are up to date. In both cases this
// package doesn't need dexopt any longer.
pkg.mDexOptNeeded = false;
return performedDexOpt ? DEX_OPT_PERFORMED : DEX_OPT_SKIPPED;
}
@ -4762,8 +4773,8 @@ public class PackageManagerService extends IPackageManager.Stub {
return allInstructionSets;
}
private int performDexOptLI(PackageParser.Package pkg, boolean forceDex, boolean defer,
boolean inclDependencies) {
private int performDexOptLI(PackageParser.Package pkg, String[] instructionSets,
boolean forceDex, boolean defer, boolean inclDependencies) {
HashSet<String> done;
if (inclDependencies && (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null)) {
done = new HashSet<String>();
@ -4771,7 +4782,7 @@ public class PackageManagerService extends IPackageManager.Stub {
} else {
done = null;
}
return performDexOptLI(pkg, null /* target instruction sets */, forceDex, defer, done);
return performDexOptLI(pkg, instructionSets, forceDex, defer, done);
}
private boolean verifyPackageUpdateLPr(PackageSetting oldPkg, PackageParser.Package newPkg) {
@ -5569,7 +5580,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
if ((scanMode&SCAN_NO_DEX) == 0) {
if (performDexOptLI(pkg, forceDex, (scanMode&SCAN_DEFER_DEX) != 0, false)
if (performDexOptLI(pkg, null /* instruction sets */, forceDex, (scanMode&SCAN_DEFER_DEX) != 0, false)
== DEX_OPT_FAILED) {
if ((scanMode & SCAN_DELETE_DATA_ON_FAILURES) != 0) {
removeDataDirsLI(pkg.packageName);
@ -5648,7 +5659,8 @@ public class PackageManagerService extends IPackageManager.Stub {
if ((scanMode&SCAN_NO_DEX) == 0) {
for (int i=0; i<clientLibPkgs.size(); i++) {
PackageParser.Package clientPkg = clientLibPkgs.get(i);
if (performDexOptLI(clientPkg, forceDex, (scanMode&SCAN_DEFER_DEX) != 0, false)
if (performDexOptLI(clientPkg, null /* instruction sets */,
forceDex, (scanMode&SCAN_DEFER_DEX) != 0, false)
== DEX_OPT_FAILED) {
if ((scanMode & SCAN_DELETE_DATA_ON_FAILURES) != 0) {
removeDataDirsLI(pkg.packageName);
@ -6128,7 +6140,8 @@ public class PackageManagerService extends IPackageManager.Stub {
ps.pkg.applicationInfo.primaryCpuAbi = adjustedAbi;
Slog.i(TAG, "Adjusting ABI for : " + ps.name + " to " + adjustedAbi);
if (performDexOptLI(ps.pkg, forceDexOpt, deferDexOpt, true) == DEX_OPT_FAILED) {
if (performDexOptLI(ps.pkg, null /* instruction sets */, forceDexOpt,
deferDexOpt, true) == DEX_OPT_FAILED) {
ps.primaryCpuAbiString = null;
ps.pkg.applicationInfo.primaryCpuAbi = null;
return;
@ -10235,7 +10248,7 @@ public class PackageManagerService extends IPackageManager.Stub {
* remove the target to make sure there isn't a stale
* file from a previous version of the package.
*/
newPackage.mDexOptNeeded = true;
newPackage.mDexOptPerformed.clear();
mInstaller.rmdex(oldCodePath, instructionSet);
mInstaller.rmdex(newPackage.baseCodePath, instructionSet);
}