美文网首页安卓
Android PMS(三)-Installd执行dexopt流

Android PMS(三)-Installd执行dexopt流

作者: Stan_Z | 来源:发表于2019-07-18 21:07 被阅读0次

    原创内容,转载请注明出处,多谢配合。

    APK经过复制、创建对应包文件夹、安装之后,还剩一个比较重要的点需要分析,那就是dex编译。

    上篇在installPackageLI中:

    private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
               ...
           mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,
                                   null /* instructionSets */, false /* checkProfiles */,
                                   getCompilerFilterForReason(REASON_INSTALL),
                                  getOrCreateCompilerPackageStats(pkg),
           mDexManager.isUsedByOtherApps(pkg.packageName));
                  ...
    }
    

    执行dex编译优化

    frameworks/base/services/core/java/com/android/server/pm/PackageDexOptimizer.java
    
    int performDexOpt(PackageParser.Package pkg, String[] sharedLibraries,
           String[] instructionSets, boolean checkProfiles, String targetCompilationFilter,
           CompilerStats.PackageStats packageStats, boolean isUsedByOtherApps) {
        ...
                return performDexOptLI(pkg, sharedLibraries, instructionSets, checkProfiles,
          ...
    }
    

    继续看performDexOptLI

    /**
    * Performs dexopt on all code paths and libraries of the specified package for specified
    * instruction sets.
    *
    * <p>Calls to {@link com.android.server.pm.Installer#dexopt} on {@link #mInstaller} are
    * synchronized on {@link #mInstallLock}.
    */
    private int performDexOptLI(PackageParser.Package pkg, String[] sharedLibraries,
           String[] targetInstructionSets, boolean checkForProfileUpdates,
           String targetCompilerFilter, CompilerStats.PackageStats packageStats,
           boolean isUsedByOtherApps) {
      ...
            for (String dexCodeIsa : dexCodeInstructionSets) {
                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;
    }
    

    循环执行dexOptPath

    /**
    * Performs dexopt on the {@code path} belonging to the package {@code pkg}.
    *
    * @return
    *      DEX_OPT_FAILED if there was any exception during dexopt
    *      DEX_OPT_PERFORMED if dexopt was performed successfully on the given path.
    *      DEX_OPT_SKIPPED if the path does not need to be deopt-ed.
    */
    @GuardedBy("mInstallLock")
    private int dexOptPath(PackageParser.Package pkg, String path, String isa,
           String compilerFilter, boolean profileUpdated, String sharedLibrariesPath,
           int dexoptFlags, int uid, CompilerStats.PackageStats packageStats) {
    ...
           mInstaller.dexopt(path, uid, pkg.packageName, isa, dexoptNeeded, oatDir, dexoptFlags,
                   compilerFilter, pkg.volumeUuid, sharedLibrariesPath, pkg.applicationInfo.seInfo);
    ...
    }
    
    frameworks/base/services/core/java/com/android/server/pm/Installer.java
    
    private volatile IInstalld mInstalld;
    ...
    IBinder binder = ServiceManager.getService("installd”);
    ...
    mInstalld = IInstalld.Stub.asInterface(binder);
    …
    public void dexopt(String apkPath, int uid, @Nullable String pkgName, String instructionSet,
           int dexoptNeeded, @Nullable String outputPath, int dexFlags,
           String compilerFilter, @Nullable String volumeUuid, @Nullable String sharedLibraries,
           @Nullable String seInfo)
            throws InstallerException {
        assertValidInstructionSet(instructionSet);
       if (!checkBeforeRemote()) return;
       try {
            mInstalld.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded, outputPath,
                   dexFlags, compilerFilter, volumeUuid, sharedLibraries, seInfo);
       } catch (Exception e) {
            throw InstallerException.from(e);
       }
    }
    

    这里installd是init启动的native进程,7.0及之前它与Installer是进行socket通信,8.0之后换成了binder,如上代码也明显能看出。

    frameworks/native/cmds/installd/installd.cpp

    8.0之后也不像7.0的时候在installd.cpp中通过cmds命令对应depot了 { "dexopt", , do_dexopt },现在操作是在dexopt.cpp中进行。

    frameworks/native/cmds/installd/dexopt.cpp
    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) {
    ...
            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);
    ...
        return 0;
    }
    

    最终调用dex2oat进行编译操作。

    好了,3篇文章对PMS的安装过程扫了个盲,非常多的细节没有分析,只简单捋了个框架。想深入学习的可以看看这个系列,总结的还挺全面的:APK安装流程详解

    最后站在巨人的肩膀上盗两张图来总结下:


    安装流程图 整体架构图(与installd通信 8.0之前是socket,之后是binder)

    参考:
    https://blog.csdn.net/shuttlecheng/article/details/79018014

    相关文章

      网友评论

        本文标题:Android PMS(三)-Installd执行dexopt流

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