PackageManagerService 源码分析(2)

一.scanPackageLI

PKMS 中调用scanDirLI来分析APK 文件,如果目录下的是apk文件或者是目录,会继续调用scanPackageLI函数:

    private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
            long currentTime, UserHandle user) throws PackageManagerException {
  ... ...
        parseFlags |= mDefParseFlags;
        PackageParser pp = new PackageParser();
        pp.setSeparateProcesses(mSeparateProcesses);
        pp.setOnlyCoreApps(mOnlyCore);
        pp.setDisplayMetrics(mMetrics);
 
        if ((scanFlags & SCAN_TRUSTED_OVERLAY) != 0) {
            parseFlags |= PackageParser.PARSE_TRUSTED_OVERLAY;
        }
 
        final PackageParser.Package pkg;
        try {
            pkg = pp.parsePackage(scanFile, parseFlags);
        } catch (PackageParserException e) {
            throw PackageManagerException.from(e);
        }
... ...
}

   这段代码主要作用是调用了PackageParser的parsePackage来解析文件,返回Package;

二.PackageParser

PackageParser.parserPackage

    public Package parsePackage(File packageFile, int flags) throws PackageParserException {
        if (packageFile.isDirectory()) {
  
            // 目录
            return parseClusterPackage(packageFile, flags);
        } else {
            //单个APK
            return parseMonolithicPackage(packageFile, flags);
        }
    }

  parseClusterPackage  

    private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {
        final PackageLite lite = parseClusterPackageLite(packageDir, 0);//获取应用目录的PackageLite对象,这个对象分开保存了目录下的核心应用以及非核心应用的名称
 
        if (mOnlyCoreApps && !lite.coreApp) {//如果lite中没有核心应用,退出
            throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
                    "Not a coreApp: " + packageDir);
        }
 
        final AssetManager assets = new AssetManager();
        try {
            // Load the base and all splits into the AssetManager
            // so that resources can be overriden when parsing the manifests.
            loadApkIntoAssetManager(assets, lite.baseCodePath, flags);//装载核心应用的资源
 
            if (!ArrayUtils.isEmpty(lite.splitCodePaths)) {
                for (String path : lite.splitCodePaths) {
                    loadApkIntoAssetManager(assets, path, flags);//再装载非核心应用的资源
                }
            }
 
            final File baseApk = new File(lite.baseCodePath);
            final Package pkg = parseBaseApk(baseApk, assets, flags);//对核心应用解析
... ...
 
            if (!ArrayUtils.isEmpty(lite.splitNames)) {
                final int num = lite.splitNames.length;
                pkg.splitNames = lite.splitNames;
                pkg.splitCodePaths = lite.splitCodePaths;
                pkg.splitRevisionCodes = lite.splitRevisionCodes;
                pkg.splitFlags = new int[num];
 
                for (int i = 0; i < num; i++) {
                    parseSplitApk(pkg, i, assets, flags);//对非核心应用的处理
                }
            }
 
            pkg.codePath = packageDir.getAbsolutePath();
            return pkg;
        } finally {
            IoUtils.closeQuietly(assets);
        }
    }

parseClusterPackage的主要内容,就是用于解析存在多个APK的文件的Package:

  • 1. 调用parseClusterPackageLite解析目录下的多APK文件,获取对应的PackageLite对象lite;
  • 2. 创建AssetManager对象,并调用loadApkIntoAssetManager方法载入"base APK"
  • 3. 调用parseBaseApk方法获取对应的Package对象
  • 4. 遍历所有"拆分APK",然后载入第二步创建的AssetManager对象,这样就实现了资源文件的载入

parseMonolithicPackage

public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
        //如果是核心应用则以更轻量级的方式进行解析后,判断是否是核心应用,非核心应用不执行解析过程
        if (mOnlyCoreApps) {
            final PackageLite lite = parseMonolithicPackageLite(apkFile, flags);
            if (!lite.coreApp) {
                throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
                        "Not a coreApp: " + apkFile);
            }
        }
        
        final AssetManager assets = new AssetManager();
        try {
            //调用parseBaseAPK()继续解析操作
            final Package pkg = parseBaseApk(apkFile, assets, flags);
            pkg.codePath = apkFile.getAbsolutePath();
            return pkg;
        } finally {
            IoUtils.closeQuietly(assets);
        }
    }

解析操作继续由parseBaseApk(apkFile, assets, flags)完成,parseBaseApk(apkFile, assets, flags)最终调用同名函数:

parseBaseApk(Resources res, XmlResourceParser parser, int flags,String[] outError)

private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags,
            String[] outError) throws XmlPullParserException, IOException {
       
             //....省略多行代码....
             
       //循环解析AndroidManifest.xml中的元素
       while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
                if (tagName.equals("application")) {
                    //....省略多行代码,重点关注其中调用的parseBaseApplication()方法
                }else if (tagName.equals("overlay")) {
                    //....省略多行代码....
                }else if (tagName.equals("key-sets")){
                    //paseKeySets()
                }else if (tagName.equals("permission-group")) {
                    parsePermissionGroup(pkg, flags, res, parser, attrs, 
                }else if (tagName.equals("permission")) {
                    //parsePermission
                }else if (tagName.equals("uses-configuration")) {
                    //....省略多行代码....
                }else if (tagName.equals("uses-feature")) {
                    //parseUsesFeature()
                }else if (tagName.equals("feature-group")) {
                    //....省略多行代码....
                }else if (tagName.equals("uses-sdk")) {
                    //....省略多行代码....
                }else if (tagName.equals("supports-screens")) {
                    //....省略多行代码....
                }else if (tagName.equals("protected-broadcast")) {
                    //....省略多行代码....
                }else if (tagName.equals("instrumentation")) {
                    //....省略多行代码....
                }else if (tagName.equals("original-package")) {
                    //....省略多行代码....
                }else if (tagName.equals("adopt-permissions")) {
                    //....省略多行代码....
                }
              //....省略多行代码....
            }
        //....省略多汗代码....
    }

 此函数就是解析APK 的AndroidManifest.xml 文件;

所以,PackageParser.parsePackage() 函数的作用可以简单的看成完成了 dir 下对应APK 的AndroidManifest.xml 的解析,保存在package 对象中并返回;

  1. scanPackageLI(File scanFile,...)该函数负责完成APK的扫描工作,APK的扫描工作具体有PackageParser.parsePackage(*)完成。在扫描过程中,会解析AndroidManifiest.xml文件等信息,并将扫描结果存放在PackageParser.Package对象中。
  2. 在完成包的信息解析之后需要完成包信息同步工作,主要因为:scanPackageLI扫描到的APK可能是已经更名的包、disable的包、需要升级的包、已经安装并且签名冲突的包、被非系统级包替代系统包的情况,需要对这些情况一一处理,保证信息的正确性。
  3. 如果Package需要Rename或者Update则会进行签名比较,以防止签名不一致的情况;
  4. 最终会调用scanPackageLI(PackageParser.Package,....)函数完成实际的Package安装或更新操作。
  5. 在扫描过程中,Package的Rename、Update、Install操作都是由scanPackage(PackageParser,int,int,long,UserHandler)来完成.该函数会调用scanPackageDirtyLI(...)完成具体的操作

scanPackageDirtyLI

需要注意的是:不论是开机扫描安装APK,还是通过adb命令安装APK,最终都会调用scanPackageDirtyLI函数进行APK安装

总结一下:

1 .任一时刻,系统中安装过的apk都会被解析完成,包信息被存放在PackageManagerService中的mPackages,它是以包名为Key,以PackageParser.Package为Value的HashMap。

2 .PMS中scanPackageLI()开机扫描已安装的apk,installPackageLI()安装新apk,最终都会走到PackageParser.parseBaseApplication()解析应用manifest文件,在scanPackageDirtyLI()中添加到mPackages.其它地方获取ApplicationInfo实例,都会间接地调用到PackageParser.generateApplicationInfo().

猜你喜欢

转载自blog.csdn.net/pirionFordring/article/details/83546460