adb shell cmd package compile -m XXX 强制编译
流程研究
Pm.java
private int runShellCommand(String serviceName, String[] args) {
final HandlerThread handlerThread = new HandlerThread("results");
handlerThread.start();
try {
ServiceManager.getService(serviceName).shellCommand(
FileDescriptor.in, FileDescriptor.out, FileDescriptor.err,
args, new MyShellCallback(),
new ResultReceiver(new Handler(handlerThread.getLooper())));
return 0;
} catch (RemoteException e) {
e.printStackTrace();
} finally {
handlerThread.quitSafely();
}
return -1;
}
—>
Binder.java
/**
* @param in The raw file descriptor that an input data stream can be read from.
* @param out The raw file descriptor that normal command messages should be written to.
* @param err The raw file descriptor that command error messages should be written to.
* @param args Command-line arguments.
* @param callback Callback through which to interact with the invoking shell.
* @param resultReceiver Called when the command has finished executing, with the result code.
* @throws RemoteException
* @hide
*/
public void shellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
@Nullable FileDescriptor err,
@NonNull String[] args, @Nullable ShellCallback callback,
@NonNull ResultReceiver resultReceiver) throws RemoteException {
onShellCommand(in, out, err, args, callback, resultReceiver);
}
/**
* Handle a call to {@link #shellCommand}. The default implementation simply prints
* an error message. Override and replace with your own.
* <p class="caution">Note: no permission checking is done before calling this method; you must
* apply any security checks as appropriate for the command being executed.
* Consider using {@link ShellCommand} to help in the implementation.</p>
* @hide
*/
public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
@Nullable FileDescriptor err,
@NonNull String[] args, @Nullable ShellCallback callback,
@NonNull ResultReceiver resultReceiver) throws RemoteException {
FileOutputStream fout = new FileOutputStream(err != null ? err : out);
PrintWriter pw = new FastPrintWriter(fout);
pw.println("No shell command implementation.");
pw.flush();
resultReceiver.send(0, null);
}
–>
PackageManagerService.java
@Override
public void onShellCommand(FileDescriptor in, FileDescriptor out,
FileDescriptor err, String[] args, ShellCallback callback,
ResultReceiver resultReceiver) {
(new PackageManagerShellCommand(this)).exec(
this, in, out, err, args, callback, resultReceiver);
}
–>PackageManagerShellCommand.java:ShellCommand
public int exec(Binder target, FileDescriptor in, FileDescriptor out, FileDescriptor err,
String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
String cmd;
int start;
if (args != null && args.length > 0) {
cmd = args[0];
start = 1;
} else {
cmd = null;
start = 0;
}
init(target, in, out, err, args, callback, start);
mCmd = cmd;
mResultReceiver = resultReceiver;
if (DEBUG) Slog.d(TAG, "Starting command " + mCmd + " on " + mTarget);
int res = -1;
try {
res = onCommand(mCmd);
if (DEBUG) Slog.d(TAG, "Executed command " + mCmd + " on " + mTarget);
} catch (SecurityException e) {
...
} catch (Throwable e) {
...
} finally {
...
mResultReceiver.send(res, null);
}
if (DEBUG) Slog.d(TAG, "Finished command " + mCmd + " on " + mTarget);
return res;
}
–>
@Override
public int onCommand(String cmd) {
if (cmd == null) {
return handleDefaultCommands(cmd);
}
final PrintWriter pw = getOutPrintWriter();
try {
switch(cmd) {
case "install":
return runInstall();
case "install-abandon":
case "install-destroy":
return runInstallAbandon();
case "install-commit":
return runInstallCommit();
case "install-create":
return runInstallCreate();
case "install-remove":
return runInstallRemove();
case "install-write":
return runInstallWrite();
case "install-existing":
return runInstallExisting();
case "compile":
return runCompile();
case "reconcile-secondary-dex-files":
return runreconcileSecondaryDexFiles();
case "bg-dexopt-job":
return runDexoptJob();
case "dump-profiles":
return runDumpProfiles();
case "list":
return runList();
case "uninstall":
return runUninstall();
case "resolve-activity":
return runResolveActivity();
case "query-activities":
return runQueryIntentActivities();
case "query-services":
return runQueryIntentServices();
case "query-receivers":
return runQueryIntentReceivers();
case "suspend":
return runSuspend(true);
case "unsuspend":
return runSuspend(false);
case "set-home-activity":
return runSetHomeActivity();
case "get-privapp-permissions":
return runGetPrivappPermissions();
case "get-instantapp-resolver":
return runGetInstantAppResolver();
case "has-feature":
return runHasFeature();
default:
return handleDefaultCommands(cmd);
}
} catch (RemoteException e) {
pw.println("Remote exception: " + e);
}
return -1;
}
–>
runCompile
private int runCompile() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
boolean checkProfiles = SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false);
boolean forceCompilation = false;
boolean allPackages = false;
boolean clearProfileData = false;
String compilerFilter = null;
String compilationReason = null;
String checkProfilesRaw = null;
boolean secondaryDex = false;
String split = null;
String opt;
while ((opt = getNextOption()) != null) {
switch (opt) {
case "-a":
allPackages = true;
break;
case "-c":
clearProfileData = true;
break;
case "-f":
forceCompilation = true;
break;
case "-m":
compilerFilter = getNextArgRequired(); 获取filter
break;
case "-r":
compilationReason = getNextArgRequired(); 获取reason
break;
case "--check-prof":
checkProfilesRaw = getNextArgRequired();
break;
case "--reset":
forceCompilation = true;
clearProfileData = true;
compilationReason = "install";
break;
case "--secondary-dex":
secondaryDex = true;
break;
case "--split":
split = getNextArgRequired();
break;
default:
pw.println("Error: Unknown option: " + opt);
return 1;
}
}
if (checkProfilesRaw != null) {
if ("true".equals(checkProfilesRaw)) {
checkProfiles = true;
} else if ("false".equals(checkProfilesRaw)) {
checkProfiles = false;
} else {
pw.println("Invalid value for \"--check-prof\". Expected \"true\" or \"false\".");
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;
}
if (allPackages && split != null) {
pw.println("-a cannot be specified together with --split");
return 1;
}
if (secondaryDex && split != null) {
pw.println("--secondary-dex cannot be specified together with --split");
return 1;
}
String targetCompilerFilter;
//如果有filter 则设置filter 否则根据reason 获取reason对应的filter
if (compilerFilter != null) {
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) {
packageNames = mInterface.getAllPackages();
} else {
String packageName = getNextArg();
if (packageName == null) {
pw.println("Error: package name not specified");
return 1;
}
packageNames = Collections.singletonList(packageName);
}
List<String> failedPackages = new ArrayList<>();
int index = 0;
for (String packageName : packageNames) {
if (clearProfileData) {
mInterface.clearApplicationProfileData(packageName);
}
if (allPackages) {
pw.println(++index + "/" + packageNames.size() + ": " + packageName);
pw.flush();
}
boolean result = secondaryDex ? mInterface.performDexOptSecondary(packageName, targetCompilerFilter, forceCompilation) : mInterface.performDexOptMode(packageName, checkProfiles, targetCompilerFilter, forceCompilation, true /* bootComplete */, split);
进行dexopt 优化
if (!result) {
failedPackages.add(packageName);
}
}
if (failedPackages.isEmpty()) {
pw.println("Success");
return 0;
} else if (failedPackages.size() == 1) {
pw.println("Failure: package " + failedPackages.get(0) + " could not be compiled");
return 1;
} else {
pw.print("Failure: the following packages could not be compiled: ");
boolean is_first = true;
for (String packageName : failedPackages) {
if (is_first) {
is_first = false;
} else {
pw.print(", ");
}
pw.print(packageName);
}
pw.println();
return 1;
}
}
–> 如果secondaryDex为false
mInterface.performDexOptMode(packageName,
checkProfiles, targetCompilerFilter, forceCompilation,
true /* bootComplete */, split);
–>PackageManagerService.java
@Override
public boolean performDexOptMode(String packageName,
boolean checkProfiles, String targetCompilerFilter, boolean force,
boolean bootComplete, String splitName) {
int flags = (checkProfiles ? DexoptOptions.DEXOPT_CHECK_FOR_PROFILES_UPDATES : 0) |
(force ? DexoptOptions.DEXOPT_FORCE : 0) |
(bootComplete ? DexoptOptions.DEXOPT_BOOT_COMPLETE : 0);
return performDexOpt(new DexoptOptions(packageName, targetCompilerFilter,
splitName, flags));
}