Android 9.0 源码_核心篇 -- 深入研究 PMS 系列(8)之 PackageParser

开篇

核心源码

关键类 路径
PackageParser.java frameworks/base/core/java/android/content/pm/PackageParser.java
PackageManagerService.java frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

PackageParser

创建解析器

    private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
        ... ...

        PackageParser pp = new PackageParser();    // 创建 PackageParser
        
        pp.setSeparateProcesses(mSeparateProcesses);
        pp.setDisplayMetrics(mMetrics);
        pp.setCallback(mPackageParserCallback);

        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
        final PackageParser.Package pkg;
        try {
            pkg = pp.parsePackage(tmpPackageFile, parseFlags);    // 解析APK
            DexMetadataHelper.validatePackageDexMetadata(pkg);
        } catch (PackageParserException e) {
            res.setError("Failed parse during installPackageLI", e);
            return;
        } finally {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }
        ... ...
    }

解析APK

在分析 PackageParser 解析 APK 之前,我们先要了解一下 Split APK 机制!

Split APK机制

Split APK 是 Google 为解决 65536 上限,以及 APK 安装包越来越大等问题,在 Android L 中引入的机制。
Split APK 可以将一个庞大的 APK,按屏幕密度,ABI 等形式拆分成多个独立的 APK,在应用程序更新时,不必下载整个 APK,只需单独下载某个模块即可安装更新。
Split APK 将原来一个 APK 中多个模块共享同一份资源的模型分离成多个 APK 使用各自的资源,并且可以继承 Base APK 中的资源,多个 APK 有相同的 data,cache 目录。

在引入了 Split APK 机制后,APK 有两种分类

Single APK:安装文件为一个完整的 APK,即 Base APK。Android 称其为 Monolithic。
Mutiple APK:安装文件在一个文件目录中,其内部有多个被拆分的 APK,这些 APK 由一个 Base APK 和一个或多个Split APK组成。Android 称其为 Cluster。

parsePackage

    /**
     * Equivalent to {@link #parsePackage(File, int, boolean)} with {@code useCaches == false}.
     */
    public Package parsePackage(File packageFile, int flags) throws PackageParserException {
        return parsePackage(packageFile, flags, false /* useCaches */);
    }

新增一个 useCaches 参数:

    public Package parsePackage(File packageFile, int flags, boolean useCaches)
            throws PackageParserException {
        Package parsed = useCaches ? getCachedResult(packageFile, flags) : null;
        if (parsed != null) {
            return parsed;
        }

        long parseTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
        // 如果解析的 packageFile 是一个目录,则调用 parseClusterPackage
        if (packageFile.isDirectory()) {
            parsed = parseClusterPackage(packageFile, flags);
        } else {
            // 如果是单个 APK 文件,则调用 parseMonolithicPackage
            parsed = parseMonolithicPackage(packageFile, flags);
        }

        long cacheTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
        cacheResult(packageFile, flags, parsed);
        if (LOG_PARSE_TIMINGS) {
            parseTime = cacheTime - parseTime;
            cacheTime = SystemClock.uptimeMillis() - cacheTime;
            if (parseTime + cacheTime > LOG_PARSE_TIMINGS_THRESHOLD_MS) {
                Slog.i(TAG, "Parse times for '" + packageFile + "': parse=" + parseTime
                        + "ms, update_cache=" + cacheTime + " ms");
            }
        }
        return parsed;
    }

我们这边选取 parseClusterPackage 作为分析的分支,当你搞懂这个方法的具体逻辑,单个 APK 的分析自然更简单了。

parseClusterPackage

一起来瞅瞅源码:

    private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {
        /*
         * 调用 parseClusterPackageLite 方法用于轻量级解析目录文件,
         * 之所以要轻量级解析是因为解析APK是一个复杂耗时的操作,这里的逻辑并不需要APK所有的信息。
         */
        final PackageLite lite = parseClusterPackageLite(packageDir, 0);
        
        /*
         * mOnlyCoreApps 用来指示 PackageParser 是否只解析“核心”应用,
         * “核心”应用指的是 AndroidManifest 中属性 coreApp 值为 true,只解析“核心”应用是为了创建一个极简的启动环境,
         * 可以通过 PackageParser 的 setOnlyCoreApps 方法来设置 mOnlyCoreApps 的值。
         *
         * lite.coreApp 表示当前包是否包含“核心”应用,如果不满足条件就会抛出异常。
         */
        if (mOnlyCoreApps && !lite.coreApp) {
            throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
                    "Not a coreApp: " + packageDir);
        }

        // Build the split dependency tree.
        SparseArray<int[]> splitDependencies = null;
        final SplitAssetLoader assetLoader;
        if (lite.isolatedSplits && !ArrayUtils.isEmpty(lite.splitNames)) {
            try {
                splitDependencies = SplitAssetDependencyLoader.createDependenciesFromPackage(lite);
                assetLoader = new SplitAssetDependencyLoader(lite, splitDependencies, flags);
            } catch (SplitAssetDependencyLoader.IllegalDependencyException e) {
                throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, e.getMessage());
            }
        } else {
            assetLoader = new DefaultSplitAssetLoader(lite, flags);
        }

        try {
            final AssetManager assets = assetLoader.getBaseAssetManager();
            final File baseApk = new File(lite.baseCodePath);
            // 解析 base APK
            final Package pkg = parseBaseApk(baseApk, assets, flags);
            if (pkg == null) {
                throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
                        "Failed to parse base APK: " + baseApk);
            }

            if (!ArrayUtils.isEmpty(lite.splitNames)) {
                // 获取 split APK 的数量
                final int num = lite.splitNames.length;

                pkg.splitNames = lite.splitNames;
                pkg.splitCodePaths = lite.splitCodePaths;
                pkg.splitRevisionCodes = lite.splitRevisionCodes;
                pkg.splitFlags = new int[num];
                pkg.splitPrivateFlags = new int[num];
                pkg.applicationInfo.splitNames = pkg.splitNames;
                pkg.applicationInfo.splitDependencies = splitDependencies;
                pkg.applicationInfo.splitClassLoaderNames = new String[num];

                for (int i = 0; i < num; i++) {
                    final AssetManager splitAssets = assetLoader.getSplitAssetManager(i);
                    // 解析每个 split APK
                    parseSplitApk(pkg, i, splitAssets, flags);
                }
            }

            pkg.setCodePath(packageDir.getCanonicalPath());
            pkg.setUse32bitAbi(lite.use32bitAbi);
            return pkg;
        } catch (IOException e) {
            throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
                    "Failed to get path: " + lite.baseCodePath, e);
        } finally {
            IoUtils.closeQuietly(assetLoader);
        }
    }

parseClusterPackageLite

    static PackageLite parseClusterPackageLite(File packageDir, int flags)
            throws PackageParserException {
        ... ...

        for (File file : files) {
            if (isApkFile(file)) {
                // 通过 parseApkLite 方法解析每个 Mutiple APK,得到每个 Mutiple APK 对应的 ApkLite(轻量级 APK 信息)
                final ApkLite lite = parseApkLite(file, flags);
                ... ...
            }
        }
        ... ...

        final String codePath = packageDir.getAbsolutePath();
        // 将这些 ApkLite 封装为一个 PackageLite(轻量级包信息)并返回
        return new PackageLite(codePath, baseApk, splitNames, isFeatureSplits, usesSplitNames,
                configForSplits, splitCodePaths, splitRevisionCodes);
    }

parseBaseApk

    private static final String MNT_EXPAND = "/mnt/expand/";

    private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
            throws PackageParserException {
        final String apkPath = apkFile.getAbsolutePath();

        String volumeUuid = null;
        if (apkPath.startsWith(MNT_EXPAND)) {
            final int end = apkPath.indexOf('/', MNT_EXPAND.length());
            // 如果 APK 的路径以 /mnt/expand/ 开头,就截取该路径获取 volumeUuid
            volumeUuid = apkPath.substring(MNT_EXPAND.length(), end);
        }

        mParseError = PackageManager.INSTALL_SUCCEEDED;
        mArchiveSourcePath = apkFile.getAbsolutePath();

        if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);

        XmlResourceParser parser = null;
        try {
            final int cookie = assets.findCookieForPath(apkPath);
            if (cookie == 0) {
                throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
                        "Failed adding asset path: " + apkPath);
            }
            parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
            final Resources res = new Resources(assets, mMetrics, null);

            final String[] outError = new String[1];
            // 再次调用 parseBaseApk 方法
            final Package pkg = parseBaseApk(apkPath, res, parser, flags, outError);
            if (pkg == null) {
                throw new PackageParserException(mParseError,
                        apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]);
            }

            pkg.setVolumeUuid(volumeUuid);             // 用于以后标识这个解析后的 Package
            pkg.setApplicationVolumeUuid(volumeUuid);  // 用于标识该 App 所在的存储卷 UUID
            pkg.setBaseCodePath(apkPath);
            pkg.setSigningDetails(SigningDetails.UNKNOWN);

            return pkg;

        } catch (PackageParserException e) {
            throw e;
        } catch (Exception e) {
            throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
                    "Failed to read manifest from " + apkPath, e);
        } finally {
            IoUtils.closeQuietly(parser);
        }
    }

我们发现,上面代码中再次调用了 parseBaseApk 的重载方法,可以看出当前的 parseBaseApk 方法主要是为了获取和设置 volumeUuid。

parseBaseApk重载

    private Package parseBaseApk(String apkPath, Resources res, XmlResourceParser parser, int flags,
            String[] outError) throws XmlPullParserException, IOException {
        final String splitName;
        final String pkgName;
        ... ...

        // 创建 Package 对象
        final Package pkg = new Package(pkgName);
       
        //从资源中提取自定义属性集 com.android.internal.R.styleable.AndroidManifest 得到 TypedArray 
        TypedArray sa = res.obtainAttributes(parser,
                com.android.internal.R.styleable.AndroidManifest);

        // 使用 typedarray 获取 AndroidManifest 中的 versionCode 赋值给 Package 的对应属性
        pkg.mVersionCode = sa.getInteger(
                com.android.internal.R.styleable.AndroidManifest_versionCode, 0);
        pkg.mVersionCodeMajor = sa.getInteger(
                com.android.internal.R.styleable.AndroidManifest_versionCodeMajor, 0);
        pkg.applicationInfo.setVersionCode(pkg.getLongVersionCode());
        pkg.baseRevisionCode = sa.getInteger(
                com.android.internal.R.styleable.AndroidManifest_revisionCode, 0);
        pkg.mVersionName = sa.getNonConfigurationString(
                com.android.internal.R.styleable.AndroidManifest_versionName, 0);
        if (pkg.mVersionName != null) {
            pkg.mVersionName = pkg.mVersionName.intern();
        }

        // 读取 APK 的 AndroidManifest 中的 coreApp 的值
        pkg.coreApp = parser.getAttributeBooleanValue(null, "coreApp", false);

        pkg.mCompileSdkVersion = sa.getInteger(
                com.android.internal.R.styleable.AndroidManifest_compileSdkVersion, 0);
        pkg.applicationInfo.compileSdkVersion = pkg.mCompileSdkVersion;
        pkg.mCompileSdkVersionCodename = sa.getNonConfigurationString(
                com.android.internal.R.styleable.AndroidManifest_compileSdkVersionCodename, 0);
        if (pkg.mCompileSdkVersionCodename != null) {
            pkg.mCompileSdkVersionCodename = pkg.mCompileSdkVersionCodename.intern();
        }
        pkg.applicationInfo.compileSdkVersionCodename = pkg.mCompileSdkVersionCodename;

        // 获取资源后要回收
        sa.recycle();

        return parseBaseApkCommon(pkg, null, res, parser, flags, outError);
    }

parseBaseApkCommon

最终调用了 parseBaseApkCommon 方法,这个方法主要用来解析APK的AndroidManifest中的各个标签,比如 application、permission、uses-sdk、feature-group 等等。

    private Package parseBaseApkCommon(Package pkg, Set<String> acceptedTags, Resources res,
            XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException,
            IOException {
        ... ...

        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
            ... ...

            // private static final String TAG_APPLICATION = "application";
            if (tagName.equals(TAG_APPLICATION)) {
                if (foundApp) {
                    if (RIGID_PARSER) {
                        outError[0] = "<manifest> has more than one <application>";
                        mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                        return null;
                    } else {
                        Slog.w(TAG, "<manifest> has more than one <application>");
                        XmlUtils.skipCurrentTag(parser);
                        continue;
                    }
                }

                foundApp = true;
                // 其中四大组件的标签在 application 标签下,解析 application 标签的方法为 parseBaseApplication。
                if (!parseBaseApplication(pkg, res, parser, flags, outError)) {
                    return null;
                }
            } else if (tagName.equals(TAG_OVERLAY)) {
            ... ...
        }
        ... ...
    }

parseBaseApplication

    // parseBaseApplication 方法很长,我们这里只截取了解析四大组件相关的代码。
    private boolean parseBaseApplication(Package owner, Resources res,
            XmlResourceParser parser, int flags, String[] outError)
        throws XmlPullParserException, IOException {
        ... ...

        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
                continue;
            }

            String tagName = parser.getName();
            if (tagName.equals("activity")) {
                // 调用 parseActivity 方法解析 activity 标签并得到一个 Activity 对象(PackageParser 的静态内部类)
                Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs, false,
                        owner.baseHardwareAccelerated);
                if (a == null) {
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                }

                hasActivityOrder |= (a.order != 0);
                // 将解析得到的 Activity 对象保存在 Package 的列表 activities 中
                owner.activities.add(a);

            } else if (tagName.equals("receiver")) {
                Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs,
                        true, false);
                if (a == null) {
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                }

                hasReceiverOrder |= (a.order != 0);
                owner.receivers.add(a);

            } else if (tagName.equals("service")) {
                Service s = parseService(owner, res, parser, flags, outError, cachedArgs);
                if (s == null) {
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                }

                hasServiceOrder |= (s.order != 0);
                owner.services.add(s);

            } else if (tagName.equals("provider")) {
                Provider p = parseProvider(owner, res, parser, flags, outError, cachedArgs);
                if (p == null) {
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                }

                owner.providers.add(p);
            }
            ... ...
        }
        ... ...
    }

PackageParser 解析 APK 的代码逻辑非常庞大,基本了解本文所讲的就足够了,如果有兴趣可以自行看源码。

parseBaseApk方法主要的解析结构可以理解为以下简图:
1417629-1a9039e0ad81bf21.png

参考

 01. http://liuwangshu.cn/framewor...

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章