美文网首页
Android 8.0 dexopt执行时机

Android 8.0 dexopt执行时机

作者: None_Ling | 来源:发表于2020-11-24 17:33 被阅读0次

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

    相关文章

      网友评论

          本文标题:Android 8.0 dexopt执行时机

          本文链接:https://www.haomeiwen.com/subject/nayviktx.html