Android 8.0 dexopt执行时机

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版本的启动 , 确定是否需要弹窗.

@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开始安装流程.
 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
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
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
 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;
  }
}
  1. 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
  1. 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;
}
  1. 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));
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容