前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android 8.0 dexopt执行时机

Android 8.0 dexopt执行时机

作者头像
None_Ling
发布2020-11-26 17:18:33
1.8K2
发布2020-11-26 17:18:33
举报
文章被收录于专栏:Android相关Android相关

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时

pm.dexopt

其中在updatePackagesIfNeeded会判断Android N版本的启动 , 确定是否需要弹窗.

代码语言:javascript
复制
@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过程

  1. 调用installPackageLI开始安装流程.
代码语言:javascript
复制
 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);
        }
    ...
}
  1. PackageDexOptimizerperformDexOpt中:
  • 判断APK中是否有代码 , 即ApplicationInfo.FLAG_HAS_CODE
  • 申请WakeLock
  • 调用performDexOpt
代码语言:javascript
复制
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;
    }
  1. getRealCompilerFilter
代码语言:javascript
复制
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();
}
  1. dexOptPath真正开始执行dexopt , 为每一个Apk或者Splite Apk进行dexopt
代码语言:javascript
复制
 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时所打印的日志

代码语言:javascript
复制
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

代码语言:javascript
复制
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;
  }
}
  1. Installd进程的启动 , 会在ServiceManager中注册InstalldNativeService
代码语言:javascript
复制
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
  1. InstalldNativeService::start() , 启动InstalldNartiveService并且初始化Binder线程池
代码语言:javascript
复制
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函数

代码语言:javascript
复制
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函数中 ,

代码语言:javascript
复制
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;
}
  1. run_dex2oat中主要是拼接了dex2oat的参数 , 然后通过execute调用/bin/dex2oat程序来执行的dex2oat
代码语言:javascript
复制
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));
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • dexopt编译类型
  • Install的dexopt过程
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档