Merge "Frameworks/base: Refactor package manager" into nyc-dev am: a7f2bcc
am: 31e9eec
* commit '31e9eec4ea3a359d572d4eb843537484f18ceb84':
Frameworks/base: Refactor package manager
This commit is contained in:
@@ -454,8 +454,21 @@ interface IPackageManager {
|
||||
*/
|
||||
boolean performDexOptIfNeeded(String packageName, String instructionSet);
|
||||
|
||||
boolean performDexOpt(String packageName, String instructionSet, boolean useProfiles,
|
||||
boolean extractOnly, boolean force);
|
||||
/**
|
||||
* Ask the package manager to perform a dex-opt for the given reason. The package
|
||||
* manager will map the reason to a compiler filter according to the current system
|
||||
* configuration.
|
||||
*/
|
||||
boolean performDexOpt(String packageName, String instructionSet, boolean checkProfiles,
|
||||
int compileReason, boolean force);
|
||||
/**
|
||||
* Ask the package manager to perform a dex-opt with the given compiler filter.
|
||||
*
|
||||
* Note: exposed only for the shell command to allow moving packages explicitly to a
|
||||
* definite state.
|
||||
*/
|
||||
boolean performDexOptMode(String packageName, String instructionSet, boolean checkProfiles,
|
||||
String targetCompilerFilter, boolean force);
|
||||
|
||||
void forceDexOpt(String packageName);
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ import android.net.LocalSocketAddress;
|
||||
import android.os.SystemClock;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Slog;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
@@ -140,14 +139,14 @@ public class InstallerConnection {
|
||||
}
|
||||
|
||||
public void dexopt(String apkPath, int uid, String instructionSet, int dexoptNeeded,
|
||||
int dexFlags, String volumeUuid, boolean useProfiles) throws InstallerException {
|
||||
int dexFlags, String compilerFilter, String volumeUuid) throws InstallerException {
|
||||
dexopt(apkPath, uid, "*", instructionSet, dexoptNeeded,
|
||||
null /*outputPath*/, dexFlags, volumeUuid, useProfiles);
|
||||
null /*outputPath*/, dexFlags, compilerFilter, volumeUuid);
|
||||
}
|
||||
|
||||
public void dexopt(String apkPath, int uid, String pkgName, String instructionSet,
|
||||
int dexoptNeeded, String outputPath, int dexFlags, String volumeUuid,
|
||||
boolean useProfiles) throws InstallerException {
|
||||
int dexoptNeeded, String outputPath, int dexFlags, String compilerFilter,
|
||||
String volumeUuid) throws InstallerException {
|
||||
execute("dexopt",
|
||||
apkPath,
|
||||
uid,
|
||||
@@ -156,8 +155,27 @@ public class InstallerConnection {
|
||||
dexoptNeeded,
|
||||
outputPath,
|
||||
dexFlags,
|
||||
volumeUuid,
|
||||
useProfiles ? '1' : '0');
|
||||
compilerFilter,
|
||||
volumeUuid);
|
||||
}
|
||||
|
||||
public boolean mergeProfiles(int uid, String pkgName) throws InstallerException {
|
||||
String rawReply = executeForResult("merge_profiles", uid, pkgName);
|
||||
if (rawReply == null) {
|
||||
throw new IllegalStateException("Unexpected null reply");
|
||||
}
|
||||
final String res[] = rawReply.split(" ");
|
||||
|
||||
if ((res == null) || (res.length != 2)) {
|
||||
throw new InstallerException("Invalid size result: " + rawReply);
|
||||
}
|
||||
|
||||
// Just as a sanity check. Anything != "true" will be interpreted as false by parseBoolean.
|
||||
if (!res[1].equals("true") && !res[1].equals("false")) {
|
||||
throw new InstallerException("Invalid boolean result: " + rawReply);
|
||||
}
|
||||
|
||||
return Boolean.parseBoolean(res[1]);
|
||||
}
|
||||
|
||||
private boolean connect() {
|
||||
|
||||
@@ -501,12 +501,14 @@ public class ZygoteInit {
|
||||
for (String classPathElement : classPathElements) {
|
||||
// System server is fully AOTed and never profiled
|
||||
// for profile guided compilation.
|
||||
// TODO: Make this configurable between INTERPRET_ONLY, SPEED, SPACE and EVERYTHING?
|
||||
final int dexoptNeeded = DexFile.getDexOptNeeded(
|
||||
classPathElement, instructionSet, DexFile.COMPILATION_TYPE_FULL);
|
||||
classPathElement, instructionSet, "speed",
|
||||
false /* newProfile */);
|
||||
if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
|
||||
installer.dexopt(classPathElement, Process.SYSTEM_UID, instructionSet,
|
||||
dexoptNeeded, 0 /*dexFlags*/, null /*volumeUuid*/,
|
||||
false /*useProfiles*/);
|
||||
dexoptNeeded, 0 /*dexFlags*/, "speed",
|
||||
null /*volumeUuid*/);
|
||||
}
|
||||
}
|
||||
} catch (IOException | InstallerException e) {
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.server.pm;
|
||||
|
||||
import static com.android.server.pm.PackageManagerServiceCompilerMapping.REASON_BACKGROUND_DEXOPT;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.job.JobInfo;
|
||||
import android.app.job.JobParameters;
|
||||
@@ -51,8 +53,6 @@ public class BackgroundDexOptService extends JobService {
|
||||
|
||||
final AtomicBoolean mIdleTime = new AtomicBoolean(false);
|
||||
|
||||
private boolean useJitProfiles = SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false);
|
||||
|
||||
public static void schedule(Context context) {
|
||||
JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
|
||||
JobInfo job = new JobInfo.Builder(BACKGROUND_DEXOPT_JOB, sDexoptServiceName)
|
||||
@@ -93,8 +93,8 @@ public class BackgroundDexOptService extends JobService {
|
||||
// skip previously failing package
|
||||
continue;
|
||||
}
|
||||
if (!pm.performDexOpt(pkg, /* instruction set */ null, useJitProfiles,
|
||||
/* extractOnly */ false, /* force */ false)) {
|
||||
if (!pm.performDexOpt(pkg, /* instruction set */ null, /* checkProfiles */ true,
|
||||
REASON_BACKGROUND_DEXOPT, /* force */ false)) {
|
||||
// there was a problem running dexopt,
|
||||
// remember this so we do not keep retrying.
|
||||
sFailedPackageNames.add(pkg);
|
||||
|
||||
@@ -20,7 +20,6 @@ import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageStats;
|
||||
import android.os.Build;
|
||||
import android.os.storage.StorageManager;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.os.InstallerConnection;
|
||||
@@ -37,17 +36,17 @@ public final class Installer extends SystemService {
|
||||
* frameworks/native/cmds/installd/installd.h
|
||||
* **************************************************************************/
|
||||
/** Application should be visible to everyone */
|
||||
public static final int DEXOPT_PUBLIC = 1 << 1;
|
||||
public static final int DEXOPT_PUBLIC = 1 << 1;
|
||||
/** Application wants to run in VM safe mode */
|
||||
public static final int DEXOPT_SAFEMODE = 1 << 2;
|
||||
public static final int DEXOPT_SAFEMODE = 1 << 2;
|
||||
/** Application wants to allow debugging of its code */
|
||||
public static final int DEXOPT_DEBUGGABLE = 1 << 3;
|
||||
public static final int DEXOPT_DEBUGGABLE = 1 << 3;
|
||||
/** The system boot has finished */
|
||||
public static final int DEXOPT_BOOTCOMPLETE = 1 << 4;
|
||||
/** Do not compile, only extract bytecode into an OAT file */
|
||||
public static final int DEXOPT_EXTRACTONLY = 1 << 5;
|
||||
public static final int DEXOPT_BOOTCOMPLETE = 1 << 4;
|
||||
/** Hint that the dexopt type is profile-guided. */
|
||||
public static final int DEXOPT_PROFILE_GUIDED = 1 << 5;
|
||||
/** This is an OTA update dexopt */
|
||||
public static final int DEXOPT_OTA = 1 << 6;
|
||||
public static final int DEXOPT_OTA = 1 << 6;
|
||||
|
||||
// NOTE: keep in sync with installd
|
||||
public static final int FLAG_CLEAR_CACHE_ONLY = 1 << 8;
|
||||
@@ -137,19 +136,23 @@ public final class Installer extends SystemService {
|
||||
}
|
||||
|
||||
public void dexopt(String apkPath, int uid, String instructionSet, int dexoptNeeded,
|
||||
int dexFlags, String volumeUuid, boolean useProfiles) throws InstallerException {
|
||||
int dexFlags, String compilerFilter, String volumeUuid) throws InstallerException {
|
||||
assertValidInstructionSet(instructionSet);
|
||||
mInstaller.dexopt(apkPath, uid, instructionSet, dexoptNeeded, dexFlags,
|
||||
volumeUuid, useProfiles);
|
||||
compilerFilter, volumeUuid);
|
||||
}
|
||||
|
||||
public void dexopt(String apkPath, int uid, String pkgName, String instructionSet,
|
||||
int dexoptNeeded, @Nullable String outputPath, int dexFlags,
|
||||
String volumeUuid, boolean useProfiles)
|
||||
String compilerFilter, String volumeUuid)
|
||||
throws InstallerException {
|
||||
assertValidInstructionSet(instructionSet);
|
||||
mInstaller.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded,
|
||||
outputPath, dexFlags, volumeUuid, useProfiles);
|
||||
outputPath, dexFlags, compilerFilter, volumeUuid);
|
||||
}
|
||||
|
||||
public boolean mergeProfiles(int uid, String pkgName) throws InstallerException {
|
||||
return mInstaller.mergeProfiles(uid, pkgName);
|
||||
}
|
||||
|
||||
public void idmap(String targetApkPath, String overlayApkPath, int uid)
|
||||
|
||||
@@ -19,11 +19,12 @@ package com.android.server.pm;
|
||||
import static com.android.server.pm.Installer.DEXOPT_OTA;
|
||||
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
|
||||
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
|
||||
import static com.android.server.pm.PackageManagerServiceCompilerMapping.getCompilerFilterForReason;
|
||||
import static com.android.server.pm.PackageManagerServiceCompilerMapping.REASON_AB_OTA;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.IOtaDexopt;
|
||||
import android.content.pm.PackageParser;
|
||||
import android.content.pm.PackageParser.Package;
|
||||
import android.os.Environment;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ResultReceiver;
|
||||
@@ -130,6 +131,7 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
|
||||
// TODO: If apps are not installed in the internal /data partition, we should compare
|
||||
// against that storage's free capacity.
|
||||
File dataDir = Environment.getDataDirectory();
|
||||
@SuppressWarnings("deprecation")
|
||||
long lowThreshold = StorageManager.from(mContext).getStorageLowBytes(dataDir);
|
||||
if (lowThreshold == 0) {
|
||||
throw new IllegalStateException("Invalid low memory threshold");
|
||||
@@ -142,7 +144,7 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
|
||||
}
|
||||
|
||||
mPackageDexOptimizer.performDexOpt(nextPackage, null /* ISAs */, false /* useProfiles */,
|
||||
false /* extractOnly */);
|
||||
getCompilerFilterForReason(REASON_AB_OTA));
|
||||
}
|
||||
|
||||
private void moveAbArtifacts(Installer installer) {
|
||||
|
||||
@@ -20,13 +20,10 @@ import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageParser;
|
||||
import android.content.pm.PackageParser.Package;
|
||||
import android.os.Environment;
|
||||
import android.os.PowerManager;
|
||||
import android.os.UserHandle;
|
||||
import android.os.WorkSource;
|
||||
import android.os.storage.StorageManager;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
|
||||
@@ -34,18 +31,18 @@ import com.android.internal.os.InstallerConnection.InstallerException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import dalvik.system.DexFile;
|
||||
|
||||
import static com.android.server.pm.Installer.DEXOPT_BOOTCOMPLETE;
|
||||
import static com.android.server.pm.Installer.DEXOPT_DEBUGGABLE;
|
||||
import static com.android.server.pm.Installer.DEXOPT_PROFILE_GUIDED;
|
||||
import static com.android.server.pm.Installer.DEXOPT_PUBLIC;
|
||||
import static com.android.server.pm.Installer.DEXOPT_SAFEMODE;
|
||||
import static com.android.server.pm.Installer.DEXOPT_EXTRACTONLY;
|
||||
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
|
||||
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
|
||||
import static com.android.server.pm.PackageManagerServiceCompilerMapping.getFullCompilerFilter;
|
||||
|
||||
/**
|
||||
* Helper class for running dexopt command on packages.
|
||||
@@ -59,8 +56,6 @@ class PackageDexOptimizer {
|
||||
static final int DEX_OPT_DEFERRED = 2;
|
||||
static final int DEX_OPT_FAILED = -1;
|
||||
|
||||
private static final boolean DEBUG_DEXOPT = PackageManagerService.DEBUG_DEXOPT;
|
||||
|
||||
private final Installer mInstaller;
|
||||
private final Object mInstallLock;
|
||||
|
||||
@@ -94,8 +89,8 @@ class PackageDexOptimizer {
|
||||
* <p>Calls to {@link com.android.server.pm.Installer#dexopt} on {@link #mInstaller} are
|
||||
* synchronized on {@link #mInstallLock}.
|
||||
*/
|
||||
int performDexOpt(PackageParser.Package pkg, String[] instructionSets, boolean useProfiles,
|
||||
boolean extractOnly) {
|
||||
int performDexOpt(PackageParser.Package pkg, String[] instructionSets, boolean checkProfiles,
|
||||
String targetCompilationFilter) {
|
||||
synchronized (mInstallLock) {
|
||||
final boolean useLock = mSystemReady;
|
||||
if (useLock) {
|
||||
@@ -103,7 +98,8 @@ class PackageDexOptimizer {
|
||||
mDexoptWakeLock.acquire();
|
||||
}
|
||||
try {
|
||||
return performDexOptLI(pkg, instructionSets, useProfiles, extractOnly);
|
||||
return performDexOptLI(pkg, instructionSets, checkProfiles,
|
||||
targetCompilationFilter);
|
||||
} finally {
|
||||
if (useLock) {
|
||||
mDexoptWakeLock.release();
|
||||
@@ -128,7 +124,7 @@ class PackageDexOptimizer {
|
||||
}
|
||||
|
||||
private int performDexOptLI(PackageParser.Package pkg, String[] targetInstructionSets,
|
||||
boolean useProfiles, boolean extractOnly) {
|
||||
boolean checkProfiles, String targetCompilerFilter) {
|
||||
final String[] instructionSets = targetInstructionSets != null ?
|
||||
targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);
|
||||
|
||||
@@ -136,36 +132,51 @@ class PackageDexOptimizer {
|
||||
return DEX_OPT_SKIPPED;
|
||||
}
|
||||
|
||||
final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly();
|
||||
final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
|
||||
|
||||
boolean isProfileGuidedFilter = DexFile.isProfileGuidedCompilerFilter(targetCompilerFilter);
|
||||
// If any part of the app is used by other apps, we cannot use profile-guided
|
||||
// compilation.
|
||||
// TODO: This needs to be refactored to be also checked when the target mode is
|
||||
// profile-guided.
|
||||
if (isProfileGuidedFilter) {
|
||||
for (String path : paths) {
|
||||
if (isUsedByOtherApps(path)) {
|
||||
checkProfiles = false;
|
||||
|
||||
// TODO: Should we only upgrade to the non-profile-guided version? That is,
|
||||
// given verify-profile, should we move to interpret-only?
|
||||
targetCompilerFilter = getFullCompilerFilter();
|
||||
isProfileGuidedFilter = false;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we're asked to take profile updates into account, check now.
|
||||
boolean newProfile = false;
|
||||
if (checkProfiles && isProfileGuidedFilter) {
|
||||
// Merge profiles, see if we need to do anything.
|
||||
try {
|
||||
newProfile = mInstaller.mergeProfiles(sharedGid, pkg.packageName);
|
||||
} catch (InstallerException e) {
|
||||
Slog.w(TAG, "Failed to merge profiles", e);
|
||||
}
|
||||
}
|
||||
|
||||
final boolean vmSafeMode = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0;
|
||||
final boolean debuggable = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
|
||||
|
||||
final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly();
|
||||
boolean performedDexOpt = false;
|
||||
final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
|
||||
for (String dexCodeInstructionSet : dexCodeInstructionSets) {
|
||||
for (String path : paths) {
|
||||
if (useProfiles && isUsedByOtherApps(path)) {
|
||||
// We cannot use profile guided compilation if the apk was used by another app.
|
||||
useProfiles = false;
|
||||
}
|
||||
int dexoptNeeded;
|
||||
|
||||
try {
|
||||
int compilationTypeMask = 0;
|
||||
if (extractOnly) {
|
||||
// For extract only, any type of compilation is good.
|
||||
compilationTypeMask = DexFile.COMPILATION_TYPE_FULL
|
||||
| DexFile.COMPILATION_TYPE_PROFILE_GUIDE
|
||||
| DexFile.COMPILATION_TYPE_EXTRACT_ONLY;
|
||||
} else {
|
||||
// Branch taken for profile guide and full compilation.
|
||||
// Profile guide compilation should only recompile a previous
|
||||
// profile compiled/extract only file and should not be attempted if the
|
||||
// apk is already fully compiled. So test against a full compilation type.
|
||||
compilationTypeMask = DexFile.COMPILATION_TYPE_FULL;
|
||||
}
|
||||
dexoptNeeded = DexFile.getDexOptNeeded(path,
|
||||
dexCodeInstructionSet, compilationTypeMask);
|
||||
dexCodeInstructionSet, targetCompilerFilter, newProfile);
|
||||
} catch (IOException ioe) {
|
||||
Slog.w(TAG, "IOException reading apk: " + path, ioe);
|
||||
return DEX_OPT_FAILED;
|
||||
@@ -194,20 +205,20 @@ class PackageDexOptimizer {
|
||||
Log.i(TAG, "Running dexopt (" + dexoptType + ") on: " + path + " pkg="
|
||||
+ pkg.applicationInfo.packageName + " isa=" + dexCodeInstructionSet
|
||||
+ " vmSafeMode=" + vmSafeMode + " debuggable=" + debuggable
|
||||
+ " extractOnly=" + extractOnly + " oatDir = " + oatDir);
|
||||
final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
|
||||
+ " target-filter=" + targetCompilerFilter + " oatDir = " + oatDir);
|
||||
// Profile guide compiled oat files should not be public.
|
||||
final boolean isPublic = !pkg.isForwardLocked() && !useProfiles;
|
||||
final boolean isPublic = !pkg.isForwardLocked() && !isProfileGuidedFilter;
|
||||
final int profileFlag = isProfileGuidedFilter ? DEXOPT_PROFILE_GUIDED : 0;
|
||||
final int dexFlags = adjustDexoptFlags(
|
||||
( isPublic ? DEXOPT_PUBLIC : 0)
|
||||
| (vmSafeMode ? DEXOPT_SAFEMODE : 0)
|
||||
| (debuggable ? DEXOPT_DEBUGGABLE : 0)
|
||||
| (extractOnly ? DEXOPT_EXTRACTONLY : 0)
|
||||
| profileFlag
|
||||
| DEXOPT_BOOTCOMPLETE);
|
||||
|
||||
try {
|
||||
mInstaller.dexopt(path, sharedGid, pkg.packageName, dexCodeInstructionSet,
|
||||
dexoptNeeded, oatDir, dexFlags, pkg.volumeUuid, useProfiles);
|
||||
dexoptNeeded, oatDir, dexFlags, targetCompilerFilter, pkg.volumeUuid);
|
||||
performedDexOpt = true;
|
||||
} catch (InstallerException e) {
|
||||
Slog.w(TAG, "Failed to dexopt", e);
|
||||
|
||||
@@ -92,6 +92,13 @@ import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet;
|
||||
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
|
||||
import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
|
||||
import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet;
|
||||
import static com.android.server.pm.PackageManagerServiceCompilerMapping.getCompilerFilterForReason;
|
||||
import static com.android.server.pm.PackageManagerServiceCompilerMapping.getFullCompilerFilter;
|
||||
import static com.android.server.pm.PackageManagerServiceCompilerMapping.REASON_BOOT;
|
||||
import static com.android.server.pm.PackageManagerServiceCompilerMapping.REASON_FORCED_DEXOPT;
|
||||
import static com.android.server.pm.PackageManagerServiceCompilerMapping.REASON_INSTALL;
|
||||
import static com.android.server.pm.PackageManagerServiceCompilerMapping.REASON_NON_SYSTEM_LIBRARY;
|
||||
import static com.android.server.pm.PackageManagerServiceCompilerMapping.REASON_SHARED_APK;
|
||||
import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_FAILURE;
|
||||
import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_SUCCESS;
|
||||
import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
|
||||
@@ -1956,6 +1963,9 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
|
||||
public static PackageManagerService main(Context context, Installer installer,
|
||||
boolean factoryTest, boolean onlyCore) {
|
||||
// Self-check for initial settings.
|
||||
PackageManagerServiceCompilerMapping.checkProperties();
|
||||
|
||||
PackageManagerService m = new PackageManagerService(context, installer,
|
||||
factoryTest, onlyCore);
|
||||
m.enableSystemUserPackages();
|
||||
@@ -2168,12 +2178,13 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
// AOT compilation (if needed).
|
||||
int dexoptNeeded = DexFile.getDexOptNeeded(
|
||||
lib, dexCodeInstructionSet,
|
||||
DexFile.COMPILATION_TYPE_FULL);
|
||||
getCompilerFilterForReason(REASON_SHARED_APK),
|
||||
false /* newProfile */);
|
||||
if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
|
||||
mInstaller.dexopt(lib, Process.SYSTEM_UID, dexCodeInstructionSet,
|
||||
dexoptNeeded, DEXOPT_PUBLIC /*dexFlags*/,
|
||||
StorageManager.UUID_PRIVATE_INTERNAL,
|
||||
false /*useProfiles*/);
|
||||
getCompilerFilterForReason(REASON_SHARED_APK),
|
||||
StorageManager.UUID_PRIVATE_INTERNAL);
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
Slog.w(TAG, "Library not found: " + lib);
|
||||
@@ -6934,7 +6945,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
// and would have to be patched (would be SELF_PATCHOAT, which is deprecated).
|
||||
// Instead, force the extraction in this case.
|
||||
performDexOpt(pkg.packageName, null /* instructionSet */,
|
||||
false /* useProfiles */, true /* extractOnly */, prunedCache);
|
||||
false /* checkProfiles */, REASON_BOOT, prunedCache);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6953,29 +6964,37 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
// TODO: this is not used nor needed. Delete it.
|
||||
@Override
|
||||
public boolean performDexOptIfNeeded(String packageName, String instructionSet) {
|
||||
return performDexOptTraced(packageName, instructionSet, false /* useProfiles */,
|
||||
false /* extractOnly */, false /* force */);
|
||||
return performDexOptTraced(packageName, instructionSet, false /* checkProfiles */,
|
||||
getFullCompilerFilter(), false /* force */);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean performDexOpt(String packageName, String instructionSet, boolean useProfiles,
|
||||
boolean extractOnly, boolean force) {
|
||||
return performDexOptTraced(packageName, instructionSet, useProfiles, extractOnly, force);
|
||||
public boolean performDexOpt(String packageName, String instructionSet,
|
||||
boolean checkProfiles, int compileReason, boolean force) {
|
||||
return performDexOptTraced(packageName, instructionSet, checkProfiles,
|
||||
getCompilerFilterForReason(compileReason), force);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean performDexOptMode(String packageName, String instructionSet,
|
||||
boolean checkProfiles, String targetCompilerFilter, boolean force) {
|
||||
return performDexOptTraced(packageName, instructionSet, checkProfiles,
|
||||
targetCompilerFilter, force);
|
||||
}
|
||||
|
||||
private boolean performDexOptTraced(String packageName, String instructionSet,
|
||||
boolean useProfiles, boolean extractOnly, boolean force) {
|
||||
boolean checkProfiles, String targetCompilerFilter, boolean force) {
|
||||
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
|
||||
try {
|
||||
return performDexOptInternal(packageName, instructionSet, useProfiles, extractOnly,
|
||||
force);
|
||||
return performDexOptInternal(packageName, instructionSet, checkProfiles,
|
||||
targetCompilerFilter, force);
|
||||
} finally {
|
||||
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean performDexOptInternal(String packageName, String instructionSet,
|
||||
boolean useProfiles, boolean extractOnly, boolean force) {
|
||||
boolean checkProfiles, String targetCompilerFilter, boolean force) {
|
||||
PackageParser.Package p;
|
||||
final String targetInstructionSet;
|
||||
synchronized (mPackages) {
|
||||
@@ -6993,7 +7012,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
synchronized (mInstallLock) {
|
||||
final String[] instructionSets = new String[] { targetInstructionSet };
|
||||
int result = performDexOptInternalWithDependenciesLI(p, instructionSets,
|
||||
useProfiles, extractOnly, force);
|
||||
checkProfiles, targetCompilerFilter, force);
|
||||
return result == PackageDexOptimizer.DEX_OPT_PERFORMED;
|
||||
}
|
||||
} finally {
|
||||
@@ -7014,7 +7033,8 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
}
|
||||
|
||||
private int performDexOptInternalWithDependenciesLI(PackageParser.Package p,
|
||||
String instructionSets[], boolean useProfiles, boolean extractOnly, boolean force) {
|
||||
String instructionSets[], boolean checkProfiles, String targetCompilerFilter,
|
||||
boolean force) {
|
||||
// Select the dex optimizer based on the force parameter.
|
||||
// Note: The force option is rarely used (cmdline input for testing, mostly), so it's OK to
|
||||
// allocate an object here.
|
||||
@@ -7028,13 +7048,13 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
if (!deps.isEmpty()) {
|
||||
for (PackageParser.Package depPackage : deps) {
|
||||
// TODO: Analyze and investigate if we (should) profile libraries.
|
||||
// Currently this will do a full compilation of the library.
|
||||
pdo.performDexOpt(depPackage, instructionSets, false /* useProfiles */,
|
||||
false /* extractOnly */);
|
||||
// Currently this will do a full compilation of the library by default.
|
||||
pdo.performDexOpt(depPackage, instructionSets, false /* checkProfiles */,
|
||||
getCompilerFilterForReason(REASON_NON_SYSTEM_LIBRARY));
|
||||
}
|
||||
}
|
||||
|
||||
return pdo.performDexOpt(p, instructionSets, useProfiles, extractOnly);
|
||||
return pdo.performDexOpt(p, instructionSets, checkProfiles, targetCompilerFilter);
|
||||
}
|
||||
|
||||
Collection<PackageParser.Package> findSharedNonSystemLibraries(PackageParser.Package p) {
|
||||
@@ -7112,7 +7132,8 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
// Whoever is calling forceDexOpt wants a fully compiled package.
|
||||
// Don't use profiles since that may cause compilation to be skipped.
|
||||
final int res = performDexOptInternalWithDependenciesLI(pkg, instructionSets,
|
||||
false /* useProfiles */, false /* extractOnly */, true /* force */);
|
||||
false /* checkProfiles */, getCompilerFilterForReason(REASON_FORCED_DEXOPT),
|
||||
true /* force */);
|
||||
|
||||
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
|
||||
if (res != PackageDexOptimizer.DEX_OPT_PERFORMED) {
|
||||
@@ -13979,7 +14000,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
// Do not run PackageDexOptimizer through the local performDexOpt
|
||||
// method because `pkg` is not in `mPackages` yet.
|
||||
int result = mPackageDexOptimizer.performDexOpt(pkg, null /* instructionSets */,
|
||||
false /* useProfiles */, true /* extractOnly */);
|
||||
false /* checkProfiles */, getCompilerFilterForReason(REASON_INSTALL));
|
||||
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
|
||||
if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
|
||||
String msg = "Extracking package failed for " + pkgName;
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.pm;
|
||||
|
||||
import android.os.SystemProperties;
|
||||
|
||||
import dalvik.system.DexFile;
|
||||
|
||||
/**
|
||||
* Manage (retrieve) mappings from compilation reason to compilation filter.
|
||||
*/
|
||||
class PackageManagerServiceCompilerMapping {
|
||||
// Compilation reasons.
|
||||
public static final int REASON_BOOT = 0;
|
||||
public static final int REASON_INSTALL = 1;
|
||||
public static final int REASON_BACKGROUND_DEXOPT = 2;
|
||||
public static final int REASON_AB_OTA = 3;
|
||||
public static final int REASON_NON_SYSTEM_LIBRARY = 4;
|
||||
public static final int REASON_SHARED_APK = 5;
|
||||
public static final int REASON_FORCED_DEXOPT = 6;
|
||||
|
||||
private static final int REASON_LAST = REASON_FORCED_DEXOPT;
|
||||
|
||||
// Names for compilation reasons.
|
||||
static final String REASON_STRINGS[] = {
|
||||
"boot", "install", "bg-dexopt", "ab-ota", "nsys-library", "shared-apk", "forced-dexopt"
|
||||
};
|
||||
|
||||
// Static block to ensure the strings array is of the right length.
|
||||
static {
|
||||
if (REASON_LAST + 1 != REASON_STRINGS.length) {
|
||||
throw new IllegalStateException("REASON_STRINGS not correct");
|
||||
}
|
||||
}
|
||||
|
||||
private static String getSystemPropertyName(int reason) {
|
||||
if (reason < 0 || reason >= REASON_STRINGS.length) {
|
||||
throw new IllegalArgumentException("reason " + reason + " invalid");
|
||||
}
|
||||
|
||||
return "pm.dexopt." + REASON_STRINGS[reason];
|
||||
}
|
||||
|
||||
// Load the property for the given reason and check for validity. This will throw an
|
||||
// exception in case the reason or value are invalid.
|
||||
private static String getAndCheckValidity(int reason) {
|
||||
String sysPropValue = SystemProperties.get(getSystemPropertyName(reason));
|
||||
if (sysPropValue == null || sysPropValue.isEmpty() ||
|
||||
!DexFile.isValidCompilerFilter(sysPropValue)) {
|
||||
throw new IllegalStateException("Value \"" + sysPropValue +"\" not valid "
|
||||
+ "(reason " + REASON_STRINGS[reason] + ")");
|
||||
}
|
||||
|
||||
// Ensure that some reasons are not mapped to profile-guided filters.
|
||||
switch (reason) {
|
||||
case REASON_SHARED_APK:
|
||||
case REASON_FORCED_DEXOPT:
|
||||
if (DexFile.isProfileGuidedCompilerFilter(sysPropValue)) {
|
||||
throw new IllegalStateException("\"" + sysPropValue + "\" is profile-guided, "
|
||||
+ "but not allowed for " + REASON_STRINGS[reason]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return sysPropValue;
|
||||
}
|
||||
|
||||
// Check that the properties are set and valid.
|
||||
// Note: this is done in a separate method so this class can be statically initialized.
|
||||
static void checkProperties() {
|
||||
// We're gonna check all properties and collect the exceptions, so we can give a general
|
||||
// overview. Store the exceptions here.
|
||||
RuntimeException toThrow = null;
|
||||
|
||||
for (int reason = 0; reason <= REASON_LAST; reason++) {
|
||||
try {
|
||||
// Check that the system property name is legal.
|
||||
String sysPropName = getSystemPropertyName(reason);
|
||||
if (sysPropName == null ||
|
||||
sysPropName.isEmpty() ||
|
||||
sysPropName.length() > SystemProperties.PROP_NAME_MAX) {
|
||||
throw new IllegalStateException("Reason system property name \"" +
|
||||
sysPropName +"\" for reason " + REASON_STRINGS[reason]);
|
||||
}
|
||||
|
||||
// Check validity, ignore result.
|
||||
getAndCheckValidity(reason);
|
||||
} catch (Exception exc) {
|
||||
if (toThrow == null) {
|
||||
toThrow = new IllegalStateException("PMS compiler filter settings are bad.");
|
||||
}
|
||||
toThrow.addSuppressed(exc);
|
||||
}
|
||||
}
|
||||
|
||||
if (toThrow != null) {
|
||||
throw toThrow;
|
||||
}
|
||||
}
|
||||
|
||||
public static String getCompilerFilterForReason(int reason) {
|
||||
return getAndCheckValidity(reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the compiler filter for "full" compilation.
|
||||
*
|
||||
* We derive that from the traditional "dalvik.vm.dex2oat-filter" property and just make
|
||||
* sure this isn't profile-guided. Returns "speed" in case of invalid (or missing) values.
|
||||
*/
|
||||
public static String getFullCompilerFilter() {
|
||||
String value = SystemProperties.get("dalvik.vm.dex2oat-filter");
|
||||
if (value == null || value.isEmpty()) {
|
||||
return "speed";
|
||||
}
|
||||
|
||||
if (!DexFile.isValidCompilerFilter(value) ||
|
||||
DexFile.isProfileGuidedCompilerFilter(value)) {
|
||||
return "speed";
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -50,6 +50,8 @@ import android.text.TextUtils;
|
||||
import android.util.PrintWriterPrinter;
|
||||
import com.android.internal.util.SizedInputStream;
|
||||
|
||||
import dalvik.system.DexFile;
|
||||
|
||||
import libcore.io.IoUtils;
|
||||
|
||||
import java.io.File;
|
||||
@@ -249,11 +251,38 @@ class PackageManagerShellCommand extends ShellCommand {
|
||||
private int runCompile() throws RemoteException {
|
||||
final PrintWriter pw = getOutPrintWriter();
|
||||
boolean useJitProfiles = false;
|
||||
boolean extractOnly = false;
|
||||
boolean forceCompilation = false;
|
||||
boolean allPackages = false;
|
||||
boolean clearProfileData = false;
|
||||
String compilationMode = "default";
|
||||
String compilerFilter = null;
|
||||
String compilationReason = null;
|
||||
|
||||
if (peekNextArg() == null) {
|
||||
// No arguments, show help.
|
||||
pw.println("Usage: cmd package compile [-c] [-f] [--reset] [-m mode] " +
|
||||
"[-r reason] [-a|pkg]");
|
||||
pw.println();
|
||||
pw.println(" -c Clear profile data");
|
||||
pw.println(" -f Force compilation");
|
||||
pw.println(" --reset Reset package");
|
||||
pw.println(" -m mode Compilation mode, one of the dex2oat compiler filters");
|
||||
pw.println(" verify-none");
|
||||
pw.println(" verify-at-runtime");
|
||||
pw.println(" verify-profile");
|
||||
pw.println(" interpret-only");
|
||||
pw.println(" space-profile");
|
||||
pw.println(" space");
|
||||
pw.println(" speed-profile");
|
||||
pw.println(" speed");
|
||||
pw.println(" everything");
|
||||
pw.println(" -r reason Compiler reason, one of the package manager reasons");
|
||||
for (int i = 0; i < PackageManagerServiceCompilerMapping.REASON_STRINGS.length; i++) {
|
||||
pw.println(" " +
|
||||
PackageManagerServiceCompilerMapping.REASON_STRINGS[i]);
|
||||
}
|
||||
pw.println(" -a Apply to all packages");
|
||||
return 1;
|
||||
}
|
||||
|
||||
String opt;
|
||||
while ((opt = getNextOption()) != null) {
|
||||
@@ -268,12 +297,15 @@ class PackageManagerShellCommand extends ShellCommand {
|
||||
forceCompilation = true;
|
||||
break;
|
||||
case "-m":
|
||||
compilationMode = getNextArgRequired();
|
||||
compilerFilter = getNextArgRequired();
|
||||
break;
|
||||
case "-r":
|
||||
compilationReason = getNextArgRequired();
|
||||
break;
|
||||
case "--reset":
|
||||
forceCompilation = true;
|
||||
clearProfileData = true;
|
||||
compilationMode = "extract";
|
||||
compilerFilter = "reset";
|
||||
break;
|
||||
default:
|
||||
pw.println("Error: Unknown option: " + opt);
|
||||
@@ -281,27 +313,55 @@ class PackageManagerShellCommand extends ShellCommand {
|
||||
}
|
||||
}
|
||||
|
||||
switch (compilationMode) {
|
||||
case "default":
|
||||
useJitProfiles = SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false);
|
||||
extractOnly = false;
|
||||
break;
|
||||
case "full":
|
||||
useJitProfiles = false;
|
||||
extractOnly = false;
|
||||
break;
|
||||
case "profile":
|
||||
useJitProfiles = true;
|
||||
extractOnly = false;
|
||||
break;
|
||||
case "extract":
|
||||
useJitProfiles = false;
|
||||
extractOnly = true;
|
||||
break;
|
||||
default:
|
||||
pw.println("Error: Unknown compilation mode: " + compilationMode);
|
||||
return 1;
|
||||
if (compilerFilter != null && compilationReason != null) {
|
||||
pw.println("Cannot use compilation filter (\"-m\") and compilation reason (\"-r\") " +
|
||||
"at the same time");
|
||||
return 1;
|
||||
}
|
||||
if (compilerFilter == null && compilationReason == null) {
|
||||
pw.println("Cannot run without any of compilation filter (\"-m\") and compilation " +
|
||||
"reason (\"-r\") at the same time");
|
||||
return 1;
|
||||
}
|
||||
|
||||
String targetCompilerFilter;
|
||||
if (compilerFilter != null) {
|
||||
// Specially recognize default and reset. Otherwise, only accept valid modes.
|
||||
if ("default".equals(compilerFilter)) {
|
||||
// Use the default mode for background dexopt.
|
||||
targetCompilerFilter =
|
||||
PackageManagerServiceCompilerMapping.getCompilerFilterForReason(
|
||||
PackageManagerServiceCompilerMapping.REASON_BACKGROUND_DEXOPT);
|
||||
} else if ("reset".equals(compilerFilter)) {
|
||||
// Use the default mode for install.
|
||||
targetCompilerFilter =
|
||||
PackageManagerServiceCompilerMapping.getCompilerFilterForReason(
|
||||
PackageManagerServiceCompilerMapping.REASON_INSTALL);
|
||||
} else {
|
||||
if (!DexFile.isValidCompilerFilter(compilerFilter)) {
|
||||
pw.println("Error: \"" + compilerFilter +
|
||||
"\" is not a valid compilation filter.");
|
||||
return 1;
|
||||
}
|
||||
targetCompilerFilter = compilerFilter;
|
||||
}
|
||||
} else {
|
||||
int reason = -1;
|
||||
for (int i = 0; i < PackageManagerServiceCompilerMapping.REASON_STRINGS.length; i++) {
|
||||
if (PackageManagerServiceCompilerMapping.REASON_STRINGS[i].equals(
|
||||
compilationReason)) {
|
||||
reason = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (reason == -1) {
|
||||
pw.println("Error: Unknown compilation reason: " + compilationReason);
|
||||
return 1;
|
||||
}
|
||||
targetCompilerFilter =
|
||||
PackageManagerServiceCompilerMapping.getCompilerFilterForReason(reason);
|
||||
}
|
||||
|
||||
|
||||
List<String> packageNames = null;
|
||||
if (allPackages) {
|
||||
@@ -321,8 +381,8 @@ class PackageManagerShellCommand extends ShellCommand {
|
||||
mInterface.clearApplicationProfileData(packageName);
|
||||
}
|
||||
|
||||
boolean result = mInterface.performDexOpt(packageName, null /* instructionSet */,
|
||||
useJitProfiles, extractOnly, forceCompilation);
|
||||
boolean result = mInterface.performDexOptMode(packageName, null /* instructionSet */,
|
||||
useJitProfiles, targetCompilerFilter, forceCompilation);
|
||||
if (!result) {
|
||||
failedPackages.add(packageName);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user