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:
Andreas Gampe
2016-03-24 02:11:50 +00:00
committed by android-build-merger
10 changed files with 382 additions and 113 deletions

View File

@@ -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);

View File

@@ -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() {

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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)

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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);
}