Android应用管理六 -- 解析包的详细流程(Android8.0)

本文详细介绍了Android应用解析过程,从parseMonolithicPackage()开始,解析APK信息并创建PackageLite对象,接着深入parseBaseAPK和parseSplitApk(),解析AndroidManifest.xml中的组件信息。解析流程包括ApkLite、PackageLite和Package的生成,最终完成对Android四大组件的解析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

 

    /**
     * Parse the package at the given location. Automatically detects if the
     * package is a monolithic style (single APK file) or cluster style
     * (directory of APKs).在指定位置解析包,自动检测包是单片样式(单个APK)还是群集样式(APK的目录)。
     * <p>
     * This performs sanity checking on cluster style packages, such as
     * requiring identical package name and version codes, a single base APK,
     * and unique split names.这将对群集样式包执行完整性检查,例如要求相同的包名,版本号,单个基本APK,唯一的拆分名称。
     * <p>
     * Note that this <em>does not</em> perform signature verification; that
     * must be done separately in {@link #collectCertificates(Package, int)}.
     *不会执行签名认证,必须在collectCertificates方法中单独完成。
     * 如果useCaches为true,则包解析器可能会从具有相同packageFile相同flags
     * 的先前解析结果中返回缓存数据。
     * Note that this method does not check whether {@code packageFile}
     * has changed since the last parse, it's up to callers to do so.
     *
     * @see #parsePackageLite(File, int)
     */
    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;
        if (packageFile.isDirectory()) {
            parsed = parseClusterPackage(packageFile, flags);//1.群集样式
        } else {
            parsed = parseMonolithicPackage(packageFile, flags);//2.单片样式
        }

        long cacheTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
        cacheResult(packageFile, flags, parsed);//3.cacheResult
        ......
        return parsed;
    }

一、先看单片样式parseMonolithicPackage()方法。

    /**
     * Parse the given APK file, treating it as as a single monolithic package.
     * <p>
     * Note that this <em>does not</em> perform signature verification; that
     * must be done separately in {@link #collectCertificates(Package, int)}.
     *
     * @deprecated external callers should move to
     *             {@link #parsePackage(File, int)}. Eventually this method will
     *             be marked private.
     */
    @Deprecated
    public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
        final AssetManager assets = newConfiguredAssetManager();//构建AssetManager对象
        final PackageLite lite = parseMonolithicPackageLite(apkFile, flags);//1.解析后获得PackageLite对象
        if (mOnlyCoreApps) {
            if (!lite.coreApp) {
                ......
            }
        }

        try {
            final Package pkg = parseBaseApk(apkFile, assets, flags);//2.解析base APK,返回Package对象
            pkg.setCodePath(apkFile.getAbsolutePath());
            pkg.setUse32bitAbi(lite.use32bitAbi);
            return pkg;
        } finally {
            IoUtils.closeQuietly(assets);
        }
    }

(一)parseMonolithicPackageLite()解析APK信息,并返回一个PackageLite对象

    private static PackageLite parseMonolithicPackageLite(File packageFile, int flags)
            throws PackageParserException {
        ......
        final ApkLite baseApk = parseApkLite(packageFile, flags);//1. parseApkLite解析APK
        final String packagePath = packageFile.getAbsolutePath();
        ......
        return new PackageLite(packagePath, baseApk, null, null, null, null, null, null);//2.创建PackageLite,表示轻量级解析单个包的详细信息
    }

parseApkLite()方法解析APK文件,只是解析一下AndroidManifest.xml中的信息,用ApkLite来表示解析出的关于apk的轻量级信息对象。最后将获得的ApkLite对象和packagePath对象最为参数,创建PackageLite对象并返回。

parseApkLite()

    /**
     * Utility method that retrieves lightweight details about a single APK
     * file, including package name, split name, and install location.
     * 检索单个APK文件的轻量级详细信息,包括包名,拆分名,安装位置。
     * @param apkFile path to a single APK
     * @param flags optional parse flags, such as
     *            {@link #PARSE_COLLECT_CERTIFICATES}
     */
    public static ApkLite parseApkLite(File apkFile, int flags)
            throws PackageParserException {
        final String apkPath = apkFile.getAbsolutePath();

        AssetManager assets = null;
        XmlResourceParser parser = null;
        try {
            assets = newConfiguredAssetManager();//构建AssetManager对象
            int cookie = assets.addAssetPath(apkPath);//设置assetPath
            if (cookie == 0) {
                ......
            }

            final DisplayMetrics metrics = new DisplayMetrics();//创建DisplayMetrics对象
            metrics.setToDefaults();

            parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);//获取XmlResourceParser对象

            final Signature[] signatures;
            final Certificate[][] certificates;
            if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) {
                // TODO: factor signature related items out of Package object
                final Package tempPkg = new Package((String) null);
                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
                try {
                    collectCertificates(tempPkg, apkFile, flags);//收集证书,获取应用的签名信息
                } finally {
                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                }
                signatures = tempPkg.mSignatures;
                certificates = tempPkg.mCertificates;
            } else {
                signatures = null;
                certificates = null;
            }

            final AttributeSet attrs = parser;
            return parseApkLite(apkPath, parser, attrs, signatures, certificates);//调用parseApkLite继续解析

        } catch (XmlPullParserException | IOException | RuntimeException e) {
            ......
        } finally {
            IoUtils.closeQuietly(parser);
            IoUtils.closeQuietly(assets);
        }
    }
    private static ApkLite parseApkLite(String codePath, XmlPullParser parser, AttributeSet attrs,
            Signature[] signatures, Certificate[][] certificates)
            throws IOException, XmlPullParserException, PackageParserException {
        final Pair<String, String> packageSplit = parsePackageSplitNames(parser, attrs);//解析AndroidManifest中的包名和拆分报名

        int installLocation = PARSE_DEFAULT_INSTALL_LOCATION;
        int versionCode = 0;
        int revisionCode = 0;
        boolean coreApp = false;
        boolean debuggable = false;
        boolean multiArch = false;
        boolean use32bitAbi = false;
        boolean extractNativeLibs = true;
        boolean isolatedSplits = false;
        boolean isFeatureSplit = false;
        String configForSplit = null;
        String usesSplitName = null;

        for (int i = 0; i < attrs.getAttributeCount(); i++) {//从AndroidManifest中解析下面的属性
            final String attr = attrs.getAttributeName(i);
            if (attr.equals("installLocation")) {
                installLocation = attrs.getAttributeIntValue(i,
                        PARSE_DEFAULT_INSTALL_LOCATION);
            } else if (attr.equals("versionCode")) {
                versionCode = attrs.getAttributeIntValue(i, 0);
            } else if (attr.equals("revisionCode")) {
                revisionCode = attrs.getAttributeIntValue(i, 0);
            } else if (attr.equals("coreApp")) {
                coreApp = attrs.getAttributeBooleanValue(i, false);
            } else if (attr.equals("isolatedSplits")) {
                isolatedSplits = attrs.getAttributeBooleanValue(i, false);
            } else if (attr.equals("configForSplit")) {
                configForSplit = attrs.getAttributeValue(i);
            } else if (attr.equals("isFeatureSplit")) {
                isFeatureSplit = attrs.getAttributeBooleanValue(i, false);
            }
        }

        // Only search the tree when the tag is directly below <manifest>
        int type;
        final int searchDepth = parser.getDepth() + 1;

        final List<VerifierInfo> verifiers = new ArrayList<VerifierInfo>();
        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                && (type != XmlPullParser.END_TAG || parser.getDepth() >= searchDepth)) {
            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
                continue;
            }

            if (parser.getDepth() != searchDepth) {
                continue;
            }

            if (TAG_PACKAGE_VERIFIER.equals(parser.getName())) {//“package-verifier”
                final VerifierInfo verifier = parseVerifier(attrs);
                if (verifier != null) {
                    verifiers.add(verifier);
                }
            } else if (TAG_APPLICATION.equals(parser.getName())) {//解析“application”标签
                for (int i = 0; i < attrs.getAttributeCount(); ++i) {
                    final String attr = attrs.getAttributeName(i);
                    if ("debuggable".equals(attr)) {
                        debuggable = attrs.getAttributeBooleanValue(i, false);
                    }
                    if ("multiArch".equals(attr)) {
                        multiArch = attrs.getAttributeBooleanValue(i, false);
                    }
                    if ("use32bitAbi".equals(attr)) {
                        use32bitAbi = attrs.getAttributeBooleanValue(i, false);
                    }
                    if ("extractNativeLibs".equals(attr)) {
                        extractNativeLibs = attrs.getAttributeBooleanValue(i, true);
                    }
                }
            } else if (TAG_USES_SPLIT.equals(parser.getName())) {//uses-split
                if (usesSplitName != null) {
                    Slog.w(TAG, "Only one <uses-split> permitted. Ignoring others.");
                    continue;
                }

                usesSplitName = attrs.getAttributeValue(ANDROID_RESOURCES, "name");
                if (usesSplitName == null) {
                    ......
                }
            }
        }

        return new ApkLite(codePath, packageSplit.first, packageSplit.second, isFeatureSplit,
                configForSplit, usesSplitName, versionCode, revisionCode, installLocation,
                verifiers, signatures, certificates, coreApp, debuggable, multiArch, use32bitAbi,
                extractNativeLibs, isolatedSplits);//根据解析的参数,创建一个ApkLite(对APK的轻量级解析)对象
    }
    private static Pair<String, String> parsePackageSplitNames(XmlPullParser parser,
            AttributeSet attrs) throws IOException, XmlPullParserException,
            PackageParserException {//该方法主要就是解析AndroidManifest.xml中的包名和拆分包名

        int type;
        while ((type = parser.next()) != XmlPullParser.START_TAG
                && type != XmlPullParser.END_DOCUMENT) {
        }

        ......

        final String packageName = attrs.getAttributeValue(null, "package");//解析出包名
        if (!"android".equals(packageName)) {//非系统应用
            final String error = validateName(packageName, true, true);//判断包名是否有效
            if (error != null) {
                ......
            }
        }

        String splitName = attrs.getAttributeValue(null, "split");//拆分APK
        if (splitName != null) {
            if (splitName.length() == 0) {
                splitName = null;
            } else {
                final String error = validateName(splitName, false, false);//判断
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值