美文网首页
PMS解析AndroidManifest.xml详解

PMS解析AndroidManifest.xml详解

作者: 天上飘的是浮云 | 来源:发表于2021-11-06 09:46 被阅读0次

主要遍历data/app system/app文件夹,然后通过线程解析apk中的androidMainfest.xml文件生产一个Package缓存对象(javabean)保持apk在manifest.xml配置应用相关内容,如版本号,包名,权限,四大组件等等

Android 9.0做的优化
1、PackageParser 增加缓存,有的话从缓存中读取
2、 ParallelPackageParser.java submit()中加入线程池进行解析

基于Android 30梳理

1. SystemServer.java 调起PackageManagerService.main(***)方法

//在main方法中实例化PackageManagerService
2598 PackageManagerService m = new PackageManagerService(injector, onlyCore, factoryTest);

2. 在PackageManagerService构造函数中做了很多事情,初始化了PackageParser2对象,为解析做准备

  3075行         PackageParser2 packageParser = new PackageParser2(mSeparateProcesses, mOnlyCore,
                    mMetrics, mCacheDir, mPackageParserCallback);

在3096行调用scanDirTracedLI扫描app目录
sAppInstallDir systemAppDir

android-29版本
2675行   scanDirTracedLI(systemAppDir,mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM_DIR,
                    scanFlags
                    | SCAN_AS_SYSTEM,
                    0);
2921行 scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);


android-30b版本  可能位置不太对 但是都是同一个方法
  3096行          scanDirTracedLI(frameworkDir, systemParseFlags,
  3225行                  systemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED, 0,
                    packageParser, executorService);

3. 在scanDirLI()函数 开始去app目录解析.apk文件,如/system/app 、/data/app目录

 9053行   private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime,
            PackageParser2 packageParser, ExecutorService executorService) {
            }

3.1 在scanDirLI()方法中在9066行,通过parallelPackageParser开启线程来解析apk包
9066行        ParallelPackageParser parallelPackageParser =
                new ParallelPackageParser(packageParser, executorService);

        // Submit files for parsing in parallel
        int fileCount = 0;
        for (File file : files) {
            final boolean isPackage = (isApkFile(file) || file.isDirectory())
                    && !PackageInstallerService.isStageName(file.getName());
            if (!isPackage) {
                // Ignore entries which are not packages
                continue;
            }
            parallelPackageParser.submit(file, parseFlags);
            fileCount++;
        }
3.2 在ParallelPackageParser.java submit()方法中,将每个apk文件放入线程中解析,结果保存在ParseResult中,类似一个entity,保存一些参数。结果保存在mQueue队列中(这也是相对于Android7.0 8.0的优化点之一)
102行    public void submit(File scanFile, int parseFlags) {
        mExecutorService.submit(() -> {
            ParseResult pr = new ParseResult();
            try {
                pr.scanFile = scanFile;
                pr.parsedPackage = parsePackage(scanFile, parseFlags);
            } catch (Throwable e) {
                pr.throwable = e;
            } 
            
            try {
                mQueue.put(pr);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                mInterruptedInThread = Thread.currentThread().getName();
            }
        });
    }
3.3 在ParallelPackageParser.java submit()方法中,调用了parsePackage()函数去解析,实际是调用在构造方法传过来的mPackageParser.parsePackage()去解析,实际为PackageParser2.java
127行    protected ParsedPackage parsePackage(File scanFile, int parseFlags)
            throws PackageParser.PackageParserException {
        return mPackageParser.parsePackage(scanFile, parseFlags, true);
    }

4. 在PackageParser2.java中开启真正的解析apk操作,141行 parsePackage()方法

4.1 首先,判断是否优先使用缓存和缓存是否为空,此为优化之一(缓存)
ParsedPackage实际为一个配置集合类,保存很多apk相关信息
 143行       if (useCaches && mCacher != null) {
            ParsedPackage parsed = mCacher.getCachedResult(packageFile, flags);
            if (parsed != null) {
                return parsed;
            }
        }
4.2 如果没有缓存的话,就开启解析
151行 ParseInput input = mSharedResult.get().reset();
        ParseResult<ParsingPackage> result = parsingUtils.parsePackage(input, packageFile, flags);
        if (result.isError()) {
            throw new PackageParserException(result.getErrorCode(), result.getErrorMessage(),
                    result.getException());
        }

        ParsedPackage parsed = (ParsedPackage) result.getResult().hideAsParsed();
        //最后返回parsed
        return parsed

5. 进入ParsingPackageUtils.java parsePackage()方法中进行解析, 根据判断file.isDirectory来进入不同解析函数

228行    public ParseResult<ParsingPackage> parsePackage(ParseInput input, File packageFile,
            int flags)
            throws PackageParserException {
        if (packageFile.isDirectory()) {
            return parseClusterPackage(input, packageFile, flags);
        } else {
            return parseMonolithicPackage(input, packageFile, flags);
        }
    }
5.1 先瞧瞧parseClusterPackage()函数

它有两个重要的地方

1. 249行 ApkLiteParseUtils.parseClusterPackageLite()函数(主要解析AndroidManifest.xml文件中的一些信息)
2. parseBaseApk()函数
    private ParseResult<ParsingPackage> parseClusterPackage(ParseInput input, File packageDir,
            int flags) {
249行        ParseResult<PackageParser.PackageLite> liteResult =
                ApkLiteParseUtils.parseClusterPackageLite(input, packageDir, 0);
      ...

278行            ParseResult<ParsingPackage> result = parseBaseApk(input, baseApk,
                    lite.codePath, assets, flags);
    ...

}
5.1.1 ApkLiteParseUtils.java中 104行parseClusterPackageLite()函数

它将轻量级解析单个包的详细信息。PackageParser.PackageLite

    public static ParseResult<PackageParser.PackageLite> parseClusterPackageLite(ParseInput input,
            File packageDir, int flags) {

123 行   
判断是否是apk文件
for (File file : files) {
  if (PackageParser.isApkFile(file)) {
    ParseResult<PackageParser.ApkLite> result = parseApkLite(input, file, flags);
  }
}
...
        final String codePath = packageDir.getAbsolutePath();
        return input.success(new PackageParser.PackageLite(codePath, baseApk, splitNames,
                isFeatureSplits, usesSplitNames, configForSplits, splitCodePaths,
                splitRevisionCodes));
}

在123行 循环遍历文件夹判断是否是apk文件,是的话使用parseApkLite()函数进行解析,解析完了后,通过获取一些属性拼装new PackageParser.PackageLite返回

看看parseApkLite()函数, 其实真正调用了parseApkLiteInner()函数
    public static ParseResult<PackageParser.ApkLite> parseApkLite(ParseInput input, File apkFile,
            int flags) {
        return parseApkLiteInner(input, apkFile, null, null, flags);
    }

//在parseApkLiteInner()函数中通过获取Mainifest.xml的XmlResourceParser,最终调用了parseApkLite(input, apkPath, parser, attrs, signingDetails)去解析
    private static ParseResult<PackageParser.ApkLite> parseApkLiteInner(ParseInput input,
            File apkFile, FileDescriptor fd, String debugPathName, int flags) {
        final String apkPath = fd != null ? debugPathName : apkFile.getAbsolutePath();

        XmlResourceParser parser = null;
        ApkAssets apkAssets = null;
      ...
237行                apkAssets = fd != null
                        ? ApkAssets.loadFromFd(fd, debugPathName, 0 /* flags */, null /* assets */)
                        : ApkAssets.loadFromPath(apkPath);
               ...

245行            parser = apkAssets.openXml(PackageParser.ANDROID_MANIFEST_FILENAME);
...
return parseApkLite(input, apkPath, parser, attrs, signingDetails);

在parseApkLiteInner()函数中通过获取Mainifest.xml的XmlResourceParser,最终调用了parseApkLite(input, apkPath, parser, attrs, signingDetails)去解析, 他通过一些标签获取一些属性,最终拼装成PackageParser.ApkLite 返回

5.1.2 看完了 ApkLiteParseUtils.parseClusterPackageLite(input, packageDir, 0);之后,再回过头来瞧瞧parseBaseApk()函数

ParsingPackageUtils.java
parseBaseApk(5个参数) --> 372行 parseBaseApk(6个参数) --> parseBaseApkTags() ---> parseBaseApplication()(后面还有parseBaseApkTag()函数)

372行 ParsingPackageUtils.parseBaseApk(6个参数)
372行 ParsingPackageUtils.parseBaseApk(6个参数)
    private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, String apkPath,
            String codePath, Resources res, XmlResourceParser parser, int flags)
            throws XmlPullParserException, IOException, PackageParserException {

        ...
  //没啥好看的,就是解析一些xml的标签
        ParseResult<Pair<String, String>> packageSplitResult =
                ApkLiteParseUtils.parsePackageSplitNames(input, parser, parser);
     ...
  //实际上就是回调了PackageParser2.java 多的startParsingPackage方法,其实就是new了一个PackageImpl对象,它继承至ParsingPackage
//PackageImpl extends ParsingPackageImpl implements ParsedPackage, AndroidPackage
            final ParsingPackage pkg = mCallback.startParsingPackage(
                    pkgName, apkPath, codePath, manifestArray, isCoreApp);
//调用parseBaseApkTags()
            final ParseResult<ParsingPackage> result =
                    parseBaseApkTags(input, pkg, manifestArray, res, parser, flags);


            return input.success(pkg);
        
    }
ParsingPackageUtils.parseBaseApkTags()函数
    private ParseResult<ParsingPackage> parseBaseApkTags(...){
        ...
        while (...) {
            // 解析AndroidManifest.xml文件,的Application标签,不能有多个Application
 743行       if (PackageParser.TAG_APPLICATION.equals(tagName)) {
                if (foundApp) {
                        result = input.error("<manifest> has more than one <application>");
                } else {
                    foundApp = true;
                    //解析
                    result = parseBaseApplication(input, pkg, res, parser, flags);
                }
            } else {
                //解析不是Application标签的子标签
                result = parseBaseApkTag(tagName, input, pkg, res, parser, flags);
            }
        }
        ...
        return input.success(pkg);
    }
这下终于到了真正解析AndroidManifest.xml的地方了ParsingPackageUtils.parseBaseApplication()和ParsingPackageUtils.parseBaseApkTag()函数

就是解析xml,简单看看就行了~

    private ParseResult<ParsingPackage> parseBaseApplication(...) {
        ...
        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
            && (type != XmlPullParser.END_TAG
                    || parser.getDepth() > depth)) {
            
            switch (tagName) {
                case "activity":
                isActivity = true;
                // fall-through
                case "receiver":
                ParseResult<ParsedActivity> activityResult =
                ParsedActivityUtils.parseActivityOrReceiver(mSeparateProcesses, pkg,
                    res, parser, flags, PackageParser.sUseRoundIcon, input);
                ...
                result = activityResult;
                break;
                case "service":
                ParseResult<ParsedService> serviceResult =
                ParsedServiceUtils.parseService(mSeparateProcesses, pkg, res, parser,
                    flags, PackageParser.sUseRoundIcon, input);
                ...
                result = serviceResult;
                break;
                case "provider":
                ParseResult<ParsedProvider> providerResult =
                ParsedProviderUtils.parseProvider(mSeparateProcesses, pkg, res, parser,
                    flags, PackageParser.sUseRoundIcon, input);
                ...
                result = providerResult;
                break;
                case "activity-alias":
                activityResult = ParsedActivityUtils.parseActivityAlias(pkg, res,
                    parser, PackageParser.sUseRoundIcon, input);
                ...
                result = activityResult;
                break;
            }

        }
        ...
        return input.success(pkg);
    }
private ParseResult parseBaseApkTag(String tag, ParseInput input,
            ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags)
            throws IOException, XmlPullParserException {
        switch (tag) {
            case PackageParser.TAG_OVERLAY:
                return parseOverlay(input, pkg, res, parser);
            case PackageParser.TAG_KEY_SETS:
                return parseKeySets(input, pkg, res, parser);
            case "feature": // TODO moltmann: Remove
            ...
            default:
                return ParsingUtils.unknownTag("<manifest>", pkg, parser, input);
        }
    }
5.2 回到最开始的ParsingPackageUtils.java 中的parsePackage()函数,我们上面走完了isDirectory()的分支,接下里走走parseMonolithicPackage()分支
  public ParseResult<ParsingPackage> parsePackage(ParseInput input, File packageFile,
            int flags)
            throws PackageParserException {
        if (packageFile.isDirectory()) {
            return parseClusterPackage(input, packageFile, flags);
        } else {
            return parseMonolithicPackage(input, packageFile, flags);
        }
    }
看了下parseMonolithicPackage()和parseClusterPackage()其实内部底层逻辑基本一致,所以这里就略过了 ~
   private ParseResult<ParsingPackage> parseMonolithicPackage(ParseInput input, File apkFile,
            int flags) throws PackageParserException {
        ParseResult<PackageParser.PackageLite> liteResult =
                ApkLiteParseUtils.parseMonolithicPackageLite(input, apkFile, flags);


        ...
        try {
            ParseResult<ParsingPackage> result = parseBaseApk(input,
                    apkFile,
                    apkFile.getCanonicalPath(),
                    assetLoader.getBaseAssetManager(), flags);


            return input.success(result.getResult()
                    .setUse32BitAbi(lite.use32bitAbi));
        } 
    }
六、我们主标题3-5中把解析AndroidMainfest.xml走了一遍,接着PackageManagerService.java scanDirLI()函数 9083行往后走,在9078行parallelPackageParser.submit(file, parseFlags);解析完了之后,

#######PackageManagerService.scanDirLI()

    private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime,
            PackageParser2 packageParser, ExecutorService executorService) {
        ...
        // Process results one by one
        for (; fileCount > 0; fileCount--) {
            ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();

9095行                    addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags,
                            currentTime, null);
                



            // Delete invalid userdata apps
            if ((scanFlags & SCAN_AS_SYSTEM) == 0)){
                ...
                removeCodePathLI(parseResult.scanFile);
            }
        }
    }
9297行 PackageManagerService.addForInitLI()

这里我们就不用看这个方法了,通过描述得知

  1. 在平台init阶段,会想内部数据结构添加一个新的package
  2. 添加后系统就会知道,并且可以被查询到
  3. 对于app,需要进行一些额外检测,如签名、版本号等等
  4. 如与之前的包相同,如果package未通过签名检查,将会被removed,还有版本号小于当前安装的也会被remove掉
  5. Regardless of the package location, the results are applied to the internal structures and the package is made available to the rest of the system.
    /**
     * Adds a new package to the internal data structures during platform initialization.
     * <p>After adding, the package is known to the system and available for querying.
     * <p>For packages located on the device ROM [eg. packages located in /system, /vendor,
     * etc...], additional checks are performed. Basic verification [such as ensuring
     * matching signatures, checking version codes, etc...] occurs if the package is
     * identical to a previously known package. If the package fails a signature check,
     * the version installed on /data will be removed. If the version of the new package
     * is less than or equal than the version on /data, it will be ignored.
     * <p>Regardless of the package location, the results are applied to the internal
     * structures and the package is made available to the rest of the system.
     * <p>NOTE: The return value should be removed. It's the passed in package object.
     */
    @GuardedBy({"mInstallLock", "mLock"})
    private AndroidPackage addForInitLI(ParsedPackage parsedPackage,
            @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
            @Nullable UserHandle user)
                    throws PackageManagerException {
...
}

相关文章

网友评论

      本文标题:PMS解析AndroidManifest.xml详解

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