dexopt编译类型
在Android 8.0中 , 一共有5中编译时机 (或者说原因) , 而dexopt
会根据这几个场景进行不同的编译过程 , 而对应的过程所使用的编译方法则是通过在SystemProperty
中提前预置 , 在使用时从SystemProperty
中读取来定义. :
触发类型 | 编译类型 | 触发时机 |
---|---|---|
first-boot | quicken | 手机第一次启动、或者恢复出场设置后 |
boot | verify | 手机非第一次启动时 |
install | speed-profile | PackageManagerService安装应用时 |
bg-dexopt | speed-profile | BackgroundDexOptService系统Idle时 |
ab-ota | speed-profile | OTA时 |
其中在updatePackagesIfNeeded
会判断Android N版本的启动 , 确定是否需要弹窗.
@Override
public void updatePackagesIfNeeded() {
// 判断是否是第一次启动
boolean causeFirstBoot = isFirstBoot() || mIsPreNUpgrade;
...
List<PackageParser.Package> pkgs;
// 得到要进行dexopt的packages
synchronized (mPackages) {
pkgs = PackageManagerServiceUtils.getPackagesForDexopt(mPackages.values(), this);
}
...
final long startTime = System.nanoTime();
// 其中如果mIsPreNUpgrade代表是否是Android N(7.0)之前的版本
// 如果是7.0之前的版本 , 是全量的OAT所以需要提示弹窗进行dexopt
// Android N后是混合编译 , 所以不需要弹窗
final int[] stats = performDexOptUpgrade(pkgs, mIsPreNUpgrade /* showDialog */,
getCompilerFilterForReason(causeFirstBoot ? REASON_FIRST_BOOT : REASON_BOOT));
...
}
Install的dexopt过程
- 调用
installPackageLI
开始安装流程.
private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
...
if (!forwardLocked && !pkg.applicationInfo.isExternalAsec()) {
...
if (!instantApp || Global.getInt(mContext.getContentResolver(), Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0) {
// 如果安装的不是instant app或者Instant App允许进行dexopt的话,
// 则调用PackageDexOptimizer.performDexOpt进行dexopt
mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,
null, false,
// 得到SystenProperty中定义的pm.dexopt.install , 也就是speed-profile
getCompilerFilterForReason(REASON_INSTALL),
getOrCreateCompilerPackageStats(pkg),
mDexManager.isUsedByOtherApps(pkg.packageName));
}
// 向BackgroundDexOptService发送该APP要进行Dexopt的操作
BackgroundDexOptService.notifyPackageChanged(pkg.packageName);
}
...
}
- 在
PackageDexOptimizer
的performDexOpt
中:
- 判断APK中是否有代码 , 即ApplicationInfo.FLAG_HAS_CODE
- 申请WakeLock
- 调用performDexOpt
int performDexOpt(PackageParser.Package pkg, String[] sharedLibraries,
String[] instructionSets, boolean checkProfiles, String targetCompilationFilter,
CompilerStats.PackageStats packageStats, boolean isUsedByOtherApps) {
// 判断是否有代码 , 即ApplicationInfo.FLAG_HAS_CODE
if (!canOptimizePackage(pkg)) {
return DEX_OPT_SKIPPED;
}
synchronized (mInstallLock) {
// 申请wakelock
final long acquireTime = acquireWakeLockLI(pkg.applicationInfo.uid);
try {
// 调用真正的dexopt
return performDexOptLI(pkg, sharedLibraries, instructionSets, checkProfiles,
targetCompilationFilter, packageStats, isUsedByOtherApps);
} finally {
releaseWakeLockLI(acquireTime);
}
}
}
private int performDexOptLI(PackageParser.Package pkg, String[] sharedLibraries,
String[] targetInstructionSets, boolean checkForProfileUpdates,
String targetCompilerFilter, CompilerStats.PackageStats packageStats,
boolean isUsedByOtherApps) {
// 获取当前系统的ISA指令集 , 也就是arm64等
final String[] instructionSets = targetInstructionSets != null ?
targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);
// 获取Dex对应的ISA指令集 , 也就是从systemproperty中获取ro.dalvik.vm.isa.arm64
final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
// 获取SpliteApk的路径
final List<String> paths = pkg.getAllCodePaths();
// 获取App的GroupId
final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
// 根据applicationInfo来得到真正的编译类型 , 普通的App安装都不变 , 仍然是speed-profile
final String compilerFilter = getRealCompilerFilter(pkg.applicationInfo,
targetCompilerFilter, isUsedByOtherApps);
// 判断当前profile文件是否有更新 , 如果是从bg-dexopt则为true
final boolean profileUpdated = checkForProfileUpdates &&
isProfileUpdated(pkg, sharedGid, compilerFilter);
// 得到so的路径
final String sharedLibrariesPath = getSharedLibrariesPath(sharedLibraries);
// Get the dexopt flags after getRealCompilerFilter to make sure we get the correct flags.
// 根据speed-profile得到flag, 包括debug、force等标识位
final int dexoptFlags = getDexFlags(pkg, compilerFilter);
// 得到APP的依赖路径
String[] splitDependencies = getSplitDependencies(pkg);
int result = DEX_OPT_SKIPPED;
for (int i = 0; i < paths.size(); i++) {
// 如果是SpliteApk的话 , 就继续遍历 , 直到找到代码路径
if ((i == 0 && (pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) == 0) ||
(i != 0 && (pkg.splitFlags[i - 1] & ApplicationInfo.FLAG_HAS_CODE) == 0)) {
continue;
}
// 找到dex代码路径
String path = paths.get(i);
String sharedLibrariesPathWithSplits;
// 拼接Library路径
if (sharedLibrariesPath != null && splitDependencies[i] != null) {
sharedLibrariesPathWithSplits = sharedLibrariesPath + ":" + splitDependencies[i];
} else {
sharedLibrariesPathWithSplits =
splitDependencies[i] != null ? splitDependencies[i] : sharedLibrariesPath;
}
// 根据Dex指令集 , 进行dexopt操作
for (String dexCodeIsa : dexCodeInstructionSets) {
// 执行dexopt操作
int newResult = dexOptPath(pkg, path, dexCodeIsa, compilerFilter, profileUpdated,
sharedLibrariesPathWithSplits, dexoptFlags, sharedGid, packageStats);
// The end result is:
// - FAILED if any path failed,
// - PERFORMED if at least one path needed compilation,
// - SKIPPED when all paths are up to date
if ((result != DEX_OPT_FAILED) && (newResult != DEX_OPT_SKIPPED)) {
result = newResult;
}
}
}
return result;
}
getRealCompilerFilter
private String getRealCompilerFilter(ApplicationInfo info, String targetCompilerFilter,
boolean isUsedByOtherApps) {
int flags = info.flags;
boolean vmSafeMode = (flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0;
if (vmSafeMode) {
// 判断是否为虚拟机安全模式 , 一般情况不是
return getSafeModeCompilerFilter(targetCompilerFilter);
}
if (isProfileGuidedCompilerFilter(targetCompilerFilter) && isUsedByOtherApps) {
// isProfileGuidedCompilerFilter内部会调用CompilerFilter::DependsOnProfile判断是否依赖profile文件
// 首先判断编译类型是否为根据Profile进行编译
// 如果是 , 则再判断是否使用其他App的代码
return getNonProfileGuidedCompilerFilter(targetCompilerFilter);
}
return targetCompilerFilter;
}
// 判断当前编译类型是否依赖Profile文件
bool CompilerFilter::DependsOnProfile(Filter filter) {
switch (filter) {
case CompilerFilter::kAssumeVerified:
case CompilerFilter::kExtract:
case CompilerFilter::kVerify:
case CompilerFilter::kQuicken:
case CompilerFilter::kSpace:
case CompilerFilter::kSpeed:
case CompilerFilter::kEverything: return false;
case CompilerFilter::kSpaceProfile:
// 由于install的类型为speed-profile , 所以返回true
case CompilerFilter::kSpeedProfile:
case CompilerFilter::kEverythingProfile: return true;
}
UNREACHABLE();
}
-
dexOptPath
真正开始执行dexopt , 为每一个Apk或者Splite Apk进行dexopt
private int dexOptPath(PackageParser.Package pkg, String path, String isa,
String compilerFilter, boolean profileUpdated, String sharedLibrariesPath,
int dexoptFlags, int uid, CompilerStats.PackageStats packageStats) {
// getDexoptNeeded内部会校验ISA指令集、compilerFilter、
int dexoptNeeded = getDexoptNeeded(path, isa, compilerFilter, profileUpdated);
// 如果不需要进行dexopt , 则直接返回
if (Math.abs(dexoptNeeded) == DexFile.NO_DEXOPT_NEEDED) {
return DEX_OPT_SKIPPED;
}
// 创建oat存放的目录
String oatDir = createOatDirIfSupported(pkg, isa);
// 相关信息请看下方
Log.i(TAG, "Running dexopt (dexoptNeeded=" + dexoptNeeded + ") on: " + path
+ " pkg=" + pkg.applicationInfo.packageName + " isa=" + isa
+ " dexoptFlags=" + printDexoptFlags(dexoptFlags)
+ " target-filter=" + compilerFilter + " oatDir=" + oatDir
+ " sharedLibraries=" + sharedLibrariesPath);
try {
long startTime = System.currentTimeMillis();
// 开始执行dexopt , 通过Binder调用到Installd.dexopt
mInstaller.dexopt(path, uid, pkg.packageName, isa, dexoptNeeded, oatDir, dexoptFlags,
compilerFilter, pkg.volumeUuid, sharedLibrariesPath, pkg.applicationInfo.seInfo);
if (packageStats != null) {
long endTime = System.currentTimeMillis();
packageStats.setCompileTime(path, (int)(endTime - startTime));
}
return DEX_OPT_PERFORMED;
} catch (InstallerException e) {
Slog.w(TAG, "Failed to dexopt", e);
return DEX_OPT_FAILED;
}
}
以下为安装App时所打印的日志
PackageManager.DexOptimizer:
Running dexopt (dexoptNeeded=1) on: /data/app/com.test.test-EpVKTOwnXDy__WVuVYeAGg==/base.apk
pkg=com.test.test
isa=arm64
dexoptFlags=boot_complete,profile_guided,public,enable_hidden_api_checks
targetFilter=speed-profile
oatDir=/data/app/com.baidu.xiaoduos.recommend-EpVKTOwnXDy__WVuVYeAGg==/oat
classLoaderContext=PCL[]
5.GetDexOptNeeded
, 判断当前编译模式是否需要执行dexopt
OatFileAssistant::DexOptNeeded OatFileAssistant::OatFileInfo::GetDexOptNeeded(
CompilerFilter::Filter target, bool profile_changed) {
// 如果编译类型是Verify、Quicken、AssumeVerified , 则返回false
// 如果编译类型是SpeedProfile、Speed , 就返回true , 代表需要编译
bool compilation_desired = CompilerFilter::IsAotCompilationEnabled(target);
// 检查编译类型和profile文件是否匹配
// 如果依赖profile文件 , 则会检查profile_changed
bool filter_okay = CompilerFilterIsOkay(target, profile_changed);
// status函数中主要判断当前是否存在Vdex、oat文件
// 如果oat文件存在或者vdex文件校验成功的话, 才会返回kOatUpToDate
if (filter_okay && Status() == kOatUpToDate) {
// The oat file is in good shape as is.
return kNoDexOptNeeded;
}
// 如果是不需要编译的类型 , 并且存在oat文件
// 校验通过后 , 如果只需要oat重定向的话 , 就直接返回 , 在运行时去重定向
if (filter_okay && !compilation_desired && Status() == kOatRelocationOutOfDate) {
return kNoDexOptNeeded;
}
// 如果是编译类型 , 需要重定向的话 , 就返回dex2oat重定向
if (filter_okay && Status() == kOatRelocationOutOfDate) {
return kDex2OatForRelocation;
}
// kOatCannotOpen , kOatDexOutOfDate , kOatBootImageOutOfDate 返回false
// kOatRelocationOutOfDate , kOatUpToDate 返回 true;
if (IsUseable()) {
return kDex2OatForFilter;
}
if (Status() == kOatBootImageOutOfDate) {
return kDex2OatForBootImage;
}
// 如果oat文件里有dex文件的话
if (oat_file_assistant_->HasOriginalDexFiles()) {
return kDex2OatFromScratch;
} else {
// Otherwise there is nothing we can do, even if we want to.
return kNoDexOptNeeded;
}
}
-
Installd
进程的启动 , 会在ServiceManager中注册InstalldNativeService
int main(const int argc, char *argv[]) {
return android::installd::installd_main(argc, argv);
}
static int installd_main(const int argc ATTRIBUTE_UNUSED, char *argv[]) {
int ret;
// 隐藏部分为selinux的初始化
...
// 初始化InstalldNaticeService
if ((ret = InstalldNativeService::start()) != android::OK) {
SLOGE("Unable to start InstalldNativeService: %d", ret);
exit(1);
}
// 开启线程池
IPCThreadState::self()->joinThreadPool();
return 0;
}
} // namespace installd
} // namespace android
-
InstalldNativeService::start()
, 启动InstalldNartiveService并且初始化Binder线程池
status_t InstalldNativeService::start() {
//
IPCThreadState::self()->disableBackgroundScheduling(true);
// 注册到ServiceManager
status_t ret = BinderService<InstalldNativeService>::publish();
if (ret != android::OK) {
return ret;
}
sp<ProcessState> ps(ProcessState::self());
// 启动线程池
ps->startThreadPool();
// 设置Binder线程名
ps->giveThreadPoolName();
return android::OK;
}
8.当installd
收到dexopt请求时 , 会调用InstalldNaticeService::dexopt
函数
binder::Status InstalldNativeService::dexopt(const std::string& apkPath, int32_t uid,
const std::unique_ptr<std::string>& packageName, const std::string& instructionSet,
int32_t dexoptNeeded, const std::unique_ptr<std::string>& outputPath, int32_t dexFlags,
const std::string& compilerFilter, const std::unique_ptr<std::string>& uuid,
const std::unique_ptr<std::string>& sharedLibraries,
const std::unique_ptr<std::string>& seInfo) {
// 加锁
std::lock_guard<std::recursive_mutex> lock(mLock);
const char* apk_path = apkPath.c_str();
const char* pkgname = packageName ? packageName->c_str() : "*";
const char* instruction_set = instructionSet.c_str();
const char* oat_dir = outputPath ? outputPath->c_str() : nullptr;
const char* compiler_filter = compilerFilter.c_str();
const char* volume_uuid = uuid ? uuid->c_str() : nullptr;
const char* shared_libraries = sharedLibraries ? sharedLibraries->c_str() : nullptr;
const char* se_info = seInfo ? seInfo->c_str() : nullptr;
int res = android::installd::dexopt(apk_path, uid, pkgname, instruction_set, dexoptNeeded,
oat_dir, dexFlags, compiler_filter, volume_uuid, shared_libraries, se_info);
return res ? error(res, "Failed to dexopt") : ok();
}
9.在dexopt.cc
中的dexopt函数中 ,
int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* instruction_set,
int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
const char* volume_uuid, const char* shared_libraries, const char* se_info) {
bool is_public = (dexopt_flags & DEXOPT_PUBLIC) != 0;
bool debuggable = (dexopt_flags & DEXOPT_DEBUGGABLE) != 0;
bool boot_complete = (dexopt_flags & DEXOPT_BOOTCOMPLETE) != 0;
bool profile_guided = (dexopt_flags & DEXOPT_PROFILE_GUIDED) != 0;
bool is_secondary_dex = (dexopt_flags & DEXOPT_SECONDARY_DEX) != 0;
// Check if we're dealing with a secondary dex file and if we need to compile it.
std::string oat_dir_str;
std::string dex_real_path;
// 如果是multidex
if (is_secondary_dex) {
// 处理multidex的dexopt
if (process_secondary_dex_dexopt(dex_path, pkgname, dexopt_flags, volume_uuid, uid,
instruction_set, compiler_filter, &is_public, &dexopt_needed, &oat_dir_str,
&dex_real_path)) {
oat_dir = oat_dir_str.c_str();
dex_path = dex_real_path.c_str();
if (dexopt_needed == NO_DEXOPT_NEEDED) {
return 0; // Nothing to do, report success.
}
} else {
return -1; // We had an error, logged in the process method.
}
}
// 打开主dex文件
unique_fd input_fd(open(dex_path, O_RDONLY, 0));
...
// 输出的oat文件名
char out_oat_path[PKG_PATH_MAX];
// 打开oat文件
Dex2oatFileWrapper out_oat_fd = open_oat_out_file(dex_path, oat_dir, is_public, uid,
instruction_set, is_secondary_dex, out_oat_path);
// Open vdex files.
Dex2oatFileWrapper in_vdex_fd;
Dex2oatFileWrapper out_vdex_fd;
// 打开vde文件
if (!open_vdex_files(dex_path, out_oat_path, dexopt_needed, instruction_set, is_public, uid,
is_secondary_dex, profile_guided, &in_vdex_fd, &out_vdex_fd)) {
return -1;
}
// 创建一个swap文件 , 用来替换oat文件
unique_fd swap_fd = maybe_open_dexopt_swap_file(out_oat_path);
// 创建oat文件
Dex2oatFileWrapper image_fd =
maybe_open_app_image(out_oat_path, profile_guided, is_public, uid, is_secondary_dex);
// 打开相关的profile文件
Dex2oatFileWrapper reference_profile_fd = maybe_open_reference_profile(
pkgname, dex_path, profile_guided, is_public, uid, is_secondary_dex);
pid_t pid = fork();
if (pid == 0) {
// 先将uid和gid设置成用户进程 , 否则会出现root权限的问题
drop_capabilities(uid);
// 设置进程优先级为后台进程
SetDex2OatScheduling(boot_complete);
// 文件加锁
if (flock(out_oat_fd.get(), LOCK_EX | LOCK_NB) != 0) {
ALOGE("flock(%s) failed: %s\n", out_oat_path, strerror(errno));
_exit(67);
}
// 执行dex2oat
run_dex2oat(input_fd.get(),
out_oat_fd.get(),
in_vdex_fd.get(),
out_vdex_fd.get(),
image_fd.get(),
dex_path,
out_oat_path,
swap_fd.get(),
instruction_set,
compiler_filter,
debuggable,
boot_complete,
reference_profile_fd.get(),
shared_libraries);
_exit(68); /* only get here on exec failure */
} else {
// 主进程等待子进程执行完
int res = wait_child(pid);
if (res == 0) {
ALOGV("DexInv: --- END '%s' (success) ---\n", dex_path);
} else {
ALOGE("DexInv: --- END '%s' --- status=0x%04x, process failed\n", dex_path, res);
return res;
}
}
// 更新oat文件的访问时间
update_out_oat_access_times(dex_path, out_oat_path);
...
return 0;
}
-
run_dex2oat
中主要是拼接了dex2oat的参数 , 然后通过execute调用/bin/dex2oat程序来执行的dex2oat
static void run_dex2oat(int zip_fd, int oat_fd, int input_vdex_fd, int output_vdex_fd, int image_fd,
const char* input_file_name, const char* output_file_name, int swap_fd,
const char* instruction_set, const char* compiler_filter,
bool debuggable, bool post_bootcomplete, int profile_fd, const char* shared_libraries) {
// Get the relative path to the input file.
const char* relative_input_file_name = get_location_from_path(input_file_name);
char dex2oat_Xms_flag[kPropertyValueMax];
bool have_dex2oat_Xms_flag = get_property("dalvik.vm.dex2oat-Xms", dex2oat_Xms_flag, NULL) > 0;
char dex2oat_Xmx_flag[kPropertyValueMax];
bool have_dex2oat_Xmx_flag = get_property("dalvik.vm.dex2oat-Xmx", dex2oat_Xmx_flag, NULL) > 0;
char dex2oat_threads_buf[kPropertyValueMax];
bool have_dex2oat_threads_flag = get_property(post_bootcomplete
? "dalvik.vm.dex2oat-threads"
: "dalvik.vm.boot-dex2oat-threads",
dex2oat_threads_buf,
NULL) > 0;
char dex2oat_threads_arg[kPropertyValueMax + 2];
if (have_dex2oat_threads_flag) {
sprintf(dex2oat_threads_arg, "-j%s", dex2oat_threads_buf);
}
char dex2oat_isa_features_key[kPropertyKeyMax];
sprintf(dex2oat_isa_features_key, "dalvik.vm.isa.%s.features", instruction_set);
char dex2oat_isa_features[kPropertyValueMax];
bool have_dex2oat_isa_features = get_property(dex2oat_isa_features_key,
dex2oat_isa_features, NULL) > 0;
char dex2oat_isa_variant_key[kPropertyKeyMax];
sprintf(dex2oat_isa_variant_key, "dalvik.vm.isa.%s.variant", instruction_set);
char dex2oat_isa_variant[kPropertyValueMax];
bool have_dex2oat_isa_variant = get_property(dex2oat_isa_variant_key,
dex2oat_isa_variant, NULL) > 0;
const char *dex2oat_norelocation = "-Xnorelocate";
bool have_dex2oat_relocation_skip_flag = false;
char dex2oat_flags[kPropertyValueMax];
int dex2oat_flags_count = get_property("dalvik.vm.dex2oat-flags",
dex2oat_flags, NULL) <= 0 ? 0 : split_count(dex2oat_flags);
ALOGV("dalvik.vm.dex2oat-flags=%s\n", dex2oat_flags);
// If we are booting without the real /data, don't spend time compiling.
char vold_decrypt[kPropertyValueMax];
bool have_vold_decrypt = get_property("vold.decrypt", vold_decrypt, "") > 0;
bool skip_compilation = (have_vold_decrypt &&
(strcmp(vold_decrypt, "trigger_restart_min_framework") == 0 ||
(strcmp(vold_decrypt, "1") == 0)));
bool generate_debug_info = property_get_bool("debug.generate-debug-info", false);
char app_image_format[kPropertyValueMax];
char image_format_arg[strlen("--image-format=") + kPropertyValueMax];
bool have_app_image_format =
image_fd >= 0 && get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0;
if (have_app_image_format) {
sprintf(image_format_arg, "--image-format=%s", app_image_format);
}
char dex2oat_large_app_threshold[kPropertyValueMax];
bool have_dex2oat_large_app_threshold =
get_property("dalvik.vm.dex2oat-very-large", dex2oat_large_app_threshold, NULL) > 0;
char dex2oat_large_app_threshold_arg[strlen("--very-large-app-threshold=") + kPropertyValueMax];
if (have_dex2oat_large_app_threshold) {
sprintf(dex2oat_large_app_threshold_arg,
"--very-large-app-threshold=%s",
dex2oat_large_app_threshold);
}
static const char* DEX2OAT_BIN = "/system/bin/dex2oat";
static const char* RUNTIME_ARG = "--runtime-arg";
static const int MAX_INT_LEN = 12; // '-'+10dig+'\0' -OR- 0x+8dig
// clang FORTIFY doesn't let us use strlen in constant array bounds, so we
// use arraysize instead.
char zip_fd_arg[arraysize("--zip-fd=") + MAX_INT_LEN];
char zip_location_arg[arraysize("--zip-location=") + PKG_PATH_MAX];
char input_vdex_fd_arg[arraysize("--input-vdex-fd=") + MAX_INT_LEN];
char output_vdex_fd_arg[arraysize("--output-vdex-fd=") + MAX_INT_LEN];
char oat_fd_arg[arraysize("--oat-fd=") + MAX_INT_LEN];
char oat_location_arg[arraysize("--oat-location=") + PKG_PATH_MAX];
char instruction_set_arg[arraysize("--instruction-set=") + MAX_INSTRUCTION_SET_LEN];
char instruction_set_variant_arg[arraysize("--instruction-set-variant=") + kPropertyValueMax];
char instruction_set_features_arg[arraysize("--instruction-set-features=") + kPropertyValueMax];
char dex2oat_Xms_arg[arraysize("-Xms") + kPropertyValueMax];
char dex2oat_Xmx_arg[arraysize("-Xmx") + kPropertyValueMax];
char dex2oat_compiler_filter_arg[arraysize("--compiler-filter=") + kPropertyValueMax];
bool have_dex2oat_swap_fd = false;
char dex2oat_swap_fd[arraysize("--swap-fd=") + MAX_INT_LEN];
bool have_dex2oat_image_fd = false;
char dex2oat_image_fd[arraysize("--app-image-fd=") + MAX_INT_LEN];
sprintf(zip_fd_arg, "--zip-fd=%d", zip_fd);
sprintf(zip_location_arg, "--zip-location=%s", relative_input_file_name);
sprintf(input_vdex_fd_arg, "--input-vdex-fd=%d", input_vdex_fd);
sprintf(output_vdex_fd_arg, "--output-vdex-fd=%d", output_vdex_fd);
sprintf(oat_fd_arg, "--oat-fd=%d", oat_fd);
sprintf(oat_location_arg, "--oat-location=%s", output_file_name);
sprintf(instruction_set_arg, "--instruction-set=%s", instruction_set);
sprintf(instruction_set_variant_arg, "--instruction-set-variant=%s", dex2oat_isa_variant);
sprintf(instruction_set_features_arg, "--instruction-set-features=%s", dex2oat_isa_features);
if (swap_fd >= 0) {
have_dex2oat_swap_fd = true;
sprintf(dex2oat_swap_fd, "--swap-fd=%d", swap_fd);
}
if (image_fd >= 0) {
have_dex2oat_image_fd = true;
sprintf(dex2oat_image_fd, "--app-image-fd=%d", image_fd);
}
if (have_dex2oat_Xms_flag) {
sprintf(dex2oat_Xms_arg, "-Xms%s", dex2oat_Xms_flag);
}
if (have_dex2oat_Xmx_flag) {
sprintf(dex2oat_Xmx_arg, "-Xmx%s", dex2oat_Xmx_flag);
}
// Compute compiler filter.
bool have_dex2oat_compiler_filter_flag = false;
if (skip_compilation) {
strcpy(dex2oat_compiler_filter_arg, "--compiler-filter=extract");
have_dex2oat_compiler_filter_flag = true;
have_dex2oat_relocation_skip_flag = true;
} else if (compiler_filter != nullptr) {
if (strlen(compiler_filter) + strlen("--compiler-filter=") <
arraysize(dex2oat_compiler_filter_arg)) {
sprintf(dex2oat_compiler_filter_arg, "--compiler-filter=%s", compiler_filter);
have_dex2oat_compiler_filter_flag = true;
} else {
ALOGW("Compiler filter name '%s' is too large (max characters is %zu)",
compiler_filter,
kPropertyValueMax);
}
}
if (!have_dex2oat_compiler_filter_flag) {
char dex2oat_compiler_filter_flag[kPropertyValueMax];
have_dex2oat_compiler_filter_flag = get_property("dalvik.vm.dex2oat-filter",
dex2oat_compiler_filter_flag, NULL) > 0;
if (have_dex2oat_compiler_filter_flag) {
sprintf(dex2oat_compiler_filter_arg,
"--compiler-filter=%s",
dex2oat_compiler_filter_flag);
}
}
// Check whether all apps should be compiled debuggable.
if (!debuggable) {
char prop_buf[kPropertyValueMax];
debuggable =
(get_property("dalvik.vm.always_debuggable", prop_buf, "0") > 0) &&
(prop_buf[0] == '1');
}
char profile_arg[strlen("--profile-file-fd=") + MAX_INT_LEN];
if (profile_fd != -1) {
sprintf(profile_arg, "--profile-file-fd=%d", profile_fd);
}
// Get the directory of the apk to pass as a base classpath directory.
char base_dir[arraysize("--classpath-dir=") + PKG_PATH_MAX];
std::string apk_dir(input_file_name);
unsigned long dir_index = apk_dir.rfind('/');
bool has_base_dir = dir_index != std::string::npos;
if (has_base_dir) {
apk_dir = apk_dir.substr(0, dir_index);
sprintf(base_dir, "--classpath-dir=%s", apk_dir.c_str());
}
ALOGV("Running %s in=%s out=%s\n", DEX2OAT_BIN, relative_input_file_name, output_file_name);
const char* argv[9 // program name, mandatory arguments and the final NULL
+ (have_dex2oat_isa_variant ? 1 : 0)
+ (have_dex2oat_isa_features ? 1 : 0)
+ (have_dex2oat_Xms_flag ? 2 : 0)
+ (have_dex2oat_Xmx_flag ? 2 : 0)
+ (have_dex2oat_compiler_filter_flag ? 1 : 0)
+ (have_dex2oat_threads_flag ? 1 : 0)
+ (have_dex2oat_swap_fd ? 1 : 0)
+ (have_dex2oat_image_fd ? 1 : 0)
+ (have_dex2oat_relocation_skip_flag ? 2 : 0)
+ (generate_debug_info ? 1 : 0)
+ (debuggable ? 1 : 0)
+ (have_app_image_format ? 1 : 0)
+ dex2oat_flags_count
+ (profile_fd == -1 ? 0 : 1)
+ (shared_libraries != nullptr ? 4 : 0)
+ (has_base_dir ? 1 : 0)
+ (have_dex2oat_large_app_threshold ? 1 : 0)];
int i = 0;
argv[i++] = DEX2OAT_BIN;
argv[i++] = zip_fd_arg;
argv[i++] = zip_location_arg;
argv[i++] = input_vdex_fd_arg;
argv[i++] = output_vdex_fd_arg;
argv[i++] = oat_fd_arg;
argv[i++] = oat_location_arg;
argv[i++] = instruction_set_arg;
if (have_dex2oat_isa_variant) {
argv[i++] = instruction_set_variant_arg;
}
if (have_dex2oat_isa_features) {
argv[i++] = instruction_set_features_arg;
}
if (have_dex2oat_Xms_flag) {
argv[i++] = RUNTIME_ARG;
argv[i++] = dex2oat_Xms_arg;
}
if (have_dex2oat_Xmx_flag) {
argv[i++] = RUNTIME_ARG;
argv[i++] = dex2oat_Xmx_arg;
}
if (have_dex2oat_compiler_filter_flag) {
argv[i++] = dex2oat_compiler_filter_arg;
}
if (have_dex2oat_threads_flag) {
argv[i++] = dex2oat_threads_arg;
}
if (have_dex2oat_swap_fd) {
argv[i++] = dex2oat_swap_fd;
}
if (have_dex2oat_image_fd) {
argv[i++] = dex2oat_image_fd;
}
if (generate_debug_info) {
argv[i++] = "--generate-debug-info";
}
if (debuggable) {
argv[i++] = "--debuggable";
}
if (have_app_image_format) {
argv[i++] = image_format_arg;
}
if (have_dex2oat_large_app_threshold) {
argv[i++] = dex2oat_large_app_threshold_arg;
}
if (dex2oat_flags_count) {
i += split(dex2oat_flags, argv + i);
}
if (have_dex2oat_relocation_skip_flag) {
argv[i++] = RUNTIME_ARG;
argv[i++] = dex2oat_norelocation;
}
if (profile_fd != -1) {
argv[i++] = profile_arg;
}
if (shared_libraries != nullptr) {
argv[i++] = RUNTIME_ARG;
argv[i++] = "-classpath";
argv[i++] = RUNTIME_ARG;
argv[i++] = shared_libraries;
}
if (has_base_dir) {
argv[i++] = base_dir;
}
// Do not add after dex2oat_flags, they should override others for debugging.
argv[i] = NULL;
execv(DEX2OAT_BIN, (char * const *)argv);
ALOGE("execv(%s) failed: %s\n", DEX2OAT_BIN, strerror(errno));
}