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

 

 

    /**
     * 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);//判断拆分包名是否有效
                ......
            }
        }

        return Pair.create(packageName.intern(),
                (splitName != null) ? splitName.intern() : splitName);// 包名及拆分包名
    }

(二)parseBaseAPK

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

        String volumeUuid = null;
        if (apkPath.startsWith(MNT_EXPAND)) {//以“mnt/expand/”开头
            final int end = apkPath.indexOf('/', MNT_EXPAND.length());
            volumeUuid = apkPath.substring(MNT_EXPAND.length(), end);//取出volumeUuid
        }

        mParseError = PackageManager.INSTALL_SUCCEEDED;
        mArchiveSourcePath = apkFile.getAbsolutePath();//获取绝对路径

        ......

        final int cookie = loadApkIntoAssetManager(assets, apkPath, flags);//assets.addAssetPath(apkPath)

        Resources res = null;
        XmlResourceParser parser = null;
        try {
            res = new Resources(assets, mMetrics, null);//Resources对象
            parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);

            final String[] outError = new String[1];
            final Package pkg = parseBaseApk(apkPath, res, parser, flags, outError);//调用parseBaseAPK继续解析
            ......

            pkg.setVolumeUuid(volumeUuid);
            pkg.setApplicationVolumeUuid(volumeUuid);
            pkg.setBaseCodePath(apkPath);
            pkg.setSignatures(null);

            return pkg;

        } catch (PackageParserException e) {
            ......
        } finally {
            IoUtils.closeQuietly(parser);
        }
    }

上面方法主要是解析出volumeUuid,继续调用parseBaseAPK()返回Package对象。

parseBaseApk

    /**
     * Parse the manifest of a <em>base APK</em>. When adding new features you
     * need to consider whether they should be supported by split APKs and child
     * packages.解析基础APK的AndroidManifest。添加新功能时,要考虑是否支持拆分APK和子包。
     */
    private Package parseBaseApk(String apkPath, Resources res, XmlResourceParser parser, int flags,
            String[] outError) throws XmlPullParserException, IOException {
        final String splitName;
        final String pkgName;

        try {
            Pair<String, String> packageSplit = parsePackageSplitNames(parser, parser);//解析包名及拆分包名
            pkgName = packageSplit.first;//包名
            splitName = packageSplit.second;//拆分包名

            ......
        } catch (PackageParserException e) {
            ......
        }

        if (mCallback != null) {
            String[] overlayPaths = mCallback.getOverlayPaths(pkgName, apkPath);
            if (overlayPaths != null && overlayPaths.length > 0) {
                for (String overlayPath : overlayPaths) {
                    res.getAssets().addOverlayPath(overlayPath);
                }
            }
        }

        final Package pkg = new Package(pkgName);//用包名构造一个Package。

        TypedArray sa = res.obtainAttributes(parser,
                com.android.internal.R.styleable.AndroidManifest);//获取资源数组

        pkg.mVersionCode = pkg.applicationInfo.versionCode = sa.getInteger(
                com.android.internal.R.styleable.AndroidManifest_versionCode, 0);//versionCode
        pkg.baseRevisionCode = sa.getInteger(
                com.android.internal.R.styleable.AndroidManifest_revisionCode, 0);//revisionCode
        pkg.mVersionName = sa.getNonConfigurationString(
                com.android.internal.R.styleable.AndroidManifest_versionName, 0);//versionName
        if (pkg.mVersionName != null) {
            pkg.mVersionName = pkg.mVersionName.intern();
        }

        pkg.coreApp = parser.getAttributeBooleanValue(null, "coreApp", false);//coreApp

        sa.recycle();//将TypedArray回收,回收后可被复用。

        return parseBaseApkCommon(pkg, null, res, parser, flags, outError);//调用parseBaseAPKCommon()继续解析Apk
    }

在parseBaseAPK最后调用parseBaseApkCommon(),该方法主要是采用XmlPullParser解析器解析AndroidManifest.xml配置文件;因为配置文件中会描述很多的关于APK的信息。

parseBaseApkCommon

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

        int type;
        boolean foundApp = false;

        TypedArray sa = res.obtainAttributes(parser,
                com.android.internal.R.styleable.AndroidManifest);//获取资源数组

        String str = sa.getNonConfigurationString(
                com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0);//解析sharedUserId
        if (str != null && str.length() > 0) {
            ......
            pkg.mSharedUserId = str.intern();
            pkg.mSharedUserLabel = sa.getResourceId(
                    com.android.internal.R.styleable.AndroidManifest_sharedUserLabel, 0);
        }

        pkg.installLocation = sa.getInteger(
                com.android.internal.R.styleable.AndroidManifest_installLocation,
                PARSE_DEFAULT_INSTALL_LOCATION);//解析installLocation
        pkg.applicationInfo.installLocation = pkg.installLocation;

        final int targetSandboxVersion = sa.getInteger(
                com.android.internal.R.styleable.AndroidManifest_targetSandboxVersion,
                PARSE_DEFAULT_TARGET_SANDBOX);//解析targetSandboxVersion
        pkg.applicationInfo.targetSandboxVersion = targetSandboxVersion;

        /* Set the global "forward lock" flag */
        if ((flags & PARSE_FORWARD_LOCK) != 0) {
            pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK;
        }

        /* Set the global "on SD card" flag */
        if ((flags & PARSE_EXTERNAL_STORAGE) != 0) {
            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE;//外置存储
        }

        if (sa.getBoolean(com.android.internal.R.styleable.AndroidManifest_isolatedSplits, false)) {
            pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING;
        }

        // Resource boolean are -1, so 1 means we don't know the value.
        ......

        int outerDepth = parser.getDepth();
        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {//开始解析xml
            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
                continue;
            }

            String tagName = parser.getName();

            ......
            if (tagName.equals(TAG_APPLICATION)) {//解析<application>标签
                ......//排除异常

                foundApp = true;
                if (!parseBaseApplication(pkg, res, parser, flags, outError)) {//调用parseBaseApplication解析application
                    return null;
                }
            } else if (tagName.equals(TAG_OVERLAY)) {//解析<overlay>标签
                sa = res.obtainAttributes(parser,
                        com.android.internal.R.styleable.AndroidManifestResourceOverlay);
                pkg.mOverlayTarget = sa.getString(
                        com.android.internal.R.styleable.AndroidManifestResourceOverlay_targetPackage);
                pkg.mOverlayPriority = sa.getInt(
                        com.android.internal.R.styleable.AndroidManifestResourceOverlay_priority,
                        0);
                pkg.mIsStaticOverlay = sa.getBoolean(
                        com.android.internal.R.styleable.AndroidManifestResourceOverlay_isStatic,
                        false);
                final String propName = sa.getString(
                        com.android.internal.R.styleable
                        .AndroidManifestResourceOverlay_requiredSystemPropertyName);
                final String propValue = sa.getString(
                        com.android.internal.R.styleable
                        .AndroidManifestResourceOverlay_requiredSystemPropertyValue);
                sa.recycle();//回收

                ......//排除异常
                XmlUtils.skipCurrentTag(parser);

            } else if (tagName.equals(TAG_KEY_SETS)) {
                if (!parseKeySets(pkg, res, parser, outError)) {
                    return null;
                }
            } else if (tagName.equals(TAG_PERMISSION_GROUP)) {//解析<permission-group>
                if (!parsePermissionGroup(pkg, flags, res, parser, outError)) {
                    return null;
                }
            } else if (tagName.equals(TAG_PERMISSION)) {//解析<permission>,APK要使用的权限
                if (!parsePermission(pkg, res, parser, outError)) {
                    return null;
                }
            } else if (tagName.equals(TAG_PERMISSION_TREE)) {
                if (!parsePermissionTree(pkg, res, parser, outError)) {
                    return null;
                }
            } else if (tagName.equals(TAG_USES_PERMISSION)) {//解析<uses-permission>,APK要使用的系统权限声明
                if (!parseUsesPermission(pkg, res, parser)) {
                    return null;
                }
            } else if (tagName.equals(TAG_USES_PERMISSION_SDK_M)
                    || tagName.equals(TAG_USES_PERMISSION_SDK_23)) {
                if (!parseUsesPermission(pkg, res, parser)) {
                    return null;
                }
            } else if (tagName.equals(TAG_USES_CONFIGURATION)) {
                ......

            } else if (tagName.equals(TAG_USES_FEATURE)) {
                ......

            } else if (tagName.equals(TAG_FEATURE_GROUP)) {
                ......

            } else if (tagName.equals(TAG_USES_SDK)) {
                ......

            } else if (tagName.equals(TAG_SUPPORT_SCREENS)) {
                ......

            } else if (tagName.equals(TAG_PROTECTED_BROADCAST)) {
                ......

            } else if (tagName.equals(TAG_INSTRUMENTATION)) {
                ......
            } else if (tagName.equals(TAG_ORIGINAL_PACKAGE)) {
                ......
            } else if (tagName.equals(TAG_ADOPT_PERMISSIONS)) {
                ......
            } else if (tagName.equals(TAG_USES_GL_TEXTURE)) {
                ......
            } else if (tagName.equals(TAG_PACKAGE)) {
                if (!MULTI_PACKAGE_APK_ENABLED) {
                    XmlUtils.skipCurrentTag(parser);
                    continue;
                }
                if (!parseBaseApkChild(pkg, res, parser, flags, outError)) {
                    // If parsing a child failed the error is already set
                    return null;
                }

            } else if (tagName.equals(TAG_RESTRICT_UPDATE)) {
                ......
            } else if (RIGID_PARSER) {
                ......
            } else {
                ......
            }
        }
        ......
        final int NP = PackageParser.NEW_PERMISSIONS.length;
        StringBuilder implicitPerms = null;
        for (int ip=0; ip<NP; ip++) {
            final PackageParser.NewPermissionInfo npi
                    = PackageParser.NEW_PERMISSIONS[ip];
            ......
            if (!pkg.requestedPermissions.contains(npi.name)) {
                ......
                pkg.requestedPermissions.add(npi.name);
            }
        }
        ......

        final int NS = PackageParser.SPLIT_PERMISSIONS.length;
        for (int is=0; is<NS; is++) {
            final PackageParser.SplitPermissionInfo spi
                    = PackageParser.SPLIT_PERMISSIONS[is];
            ......
            for (int in=0; in<spi.newPerms.length; in++) {
                final String perm = spi.newPerms[in];
                if (!pkg.requestedPermissions.contains(perm)) {
                    pkg.requestedPermissions.add(perm);
                }
            }
        }

        ......//设置srceen的flags

        ......
        return pkg;
    }

这里我们主要关注对<application>标签的解析过程,因为我们添加的Android四大组件相关的内容都会在该标签中描述。

parseBaseApplication

    /**
     * Parse the {@code application} XML tree at the current parse location in a
     * <em>base APK</em> manifest.解析AndroidManifest中的<application>标签
     * <p>
     * When adding new features, carefully consider if they should also be
     * supported by split APKs.添加新功能时,要考虑拆分APK是否也应该支持这些功能。
     */
    private boolean parseBaseApplication(Package owner, Resources res,
            XmlResourceParser parser, int flags, String[] outError)
        throws XmlPullParserException, IOException {
        final ApplicationInfo ai = owner.applicationInfo;//从Package对象中获取ApplicationInfo对象
        final String pkgName = owner.applicationInfo.packageName;

        TypedArray sa = res.obtainAttributes(parser,
                com.android.internal.R.styleable.AndroidManifestApplication);//获取资源数组

        if (!parsePackageItemInfo(owner, ai, outError,
                "<application>", sa, false /*nameRequired*/,
                com.android.internal.R.styleable.AndroidManifestApplication_name,//name
                com.android.internal.R.styleable.AndroidManifestApplication_label,//label
                com.android.internal.R.styleable.AndroidManifestApplication_icon,//icon
                com.android.internal.R.styleable.AndroidManifestApplication_roundIcon,//roundIcon
                com.android.internal.R.styleable.AndroidManifestApplication_logo,//logo
                com.android.internal.R.styleable.AndroidManifestApplication_banner)) {//banner
            sa.recycle();
            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
            return false;
        }

        if (ai.name != null) {
            ai.className = ai.name;
        }

        String manageSpaceActivity = sa.getNonConfigurationString(
                com.android.internal.R.styleable.AndroidManifestApplication_manageSpaceActivity,
                Configuration.NATIVE_CONFIG_VERSION);
        if (manageSpaceActivity != null) {
            ai.manageSpaceActivityName = buildClassName(pkgName, manageSpaceActivity,
                    outError);
        }

        boolean allowBackup = sa.getBoolean(//allowBackup
                com.android.internal.R.styleable.AndroidManifestApplication_allowBackup, true);
        if (allowBackup) {
            ai.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP;

            // backupAgent, killAfterRestore, fullBackupContent, backupInForeground,
            // and restoreAnyVersion are only relevant if backup is possible for the
            // given application.
            String backupAgent = sa.getNonConfigurationString(
                    com.android.internal.R.styleable.AndroidManifestApplication_backupAgent,
                    Configuration.NATIVE_CONFIG_VERSION);
            if (backupAgent != null) {
                ai.backupAgentName = buildClassName(pkgName, backupAgent, outError);
                ......//设置ApplicationInfo的flags标记:ApplicationInfo.FLAG_KILL_AFTER_RESTORE等
            }

            TypedValue v = sa.peekValue(
                    com.android.internal.R.styleable.AndroidManifestApplication_fullBackupContent);
            if (v != null && (ai.fullBackupContent = v.resourceId) == 0) {
                ......
                // "false" => -1, "true" => 0
                ai.fullBackupContent = (v.data == 0 ? -1 : 0);
            }
            ......
        }

        ai.theme = sa.getResourceId(
                com.android.internal.R.styleable.AndroidManifestApplication_theme, 0);//theme
        ai.descriptionRes = sa.getResourceId(
                com.android.internal.R.styleable.AndroidManifestApplication_description, 0);//description

        if ((flags&PARSE_IS_SYSTEM) != 0) {//system app
            if (sa.getBoolean(
                    com.android.internal.R.styleable.AndroidManifestApplication_persistent,
                    false)) {//判断是否长期驻留
                // Check if persistence is based on a feature being present
                final String requiredFeature = sa.getNonResourceString(
                    com.android.internal.R.styleable.
                    AndroidManifestApplication_persistentWhenFeatureAvailable);
                if (requiredFeature == null || mCallback.hasFeature(requiredFeature)) {
                    ai.flags |= ApplicationInfo.FLAG_PERSISTENT;
                }
            }
        }

        if (sa.getBoolean(
                com.android.internal.R.styleable.AndroidManifestApplication_requiredForAllUsers,
                false)) {//requiredForAllUsers是否对所有用户可用
            owner.mRequiredForAllUsers = true;
        }

        String restrictedAccountType = sa.getString(com.android.internal.R.styleable
                .AndroidManifestApplication_restrictedAccountType);//设置restrictedAccountType属性
        if (restrictedAccountType != null && restrictedAccountType.length() > 0) {
            owner.mRestrictedAccountType = restrictedAccountType;//允许受限账户访问主账户
        }

        String requiredAccountType = sa.getString(com.android.internal.R.styleable
                .AndroidManifestApplication_requiredAccountType);//设置requiredAccountType
        if (requiredAccountType != null && requiredAccountType.length() > 0) {
            owner.mRequiredAccountType = requiredAccountType;//设置应用程序所需的账户类型。
        }

        if (sa.getBoolean(
                com.android.internal.R.styleable.AndroidManifestApplication_debuggable,
                false)) {//debuggable:可调式
            ai.flags |= ApplicationInfo.FLAG_DEBUGGABLE;
        }

        if (sa.getBoolean(//android:vmSafeMode属性,用来指明该应用是否想让VM虚拟机运行在安全模式,默认为false
                com.android.internal.R.styleable.AndroidManifestApplication_vmSafeMode,
                false)) {
            ai.flags |= ApplicationInfo.FLAG_VM_SAFE_MODE;//true,会禁用ART编译器
        }

        owner.baseHardwareAccelerated = sa.getBoolean(
                com.android.internal.R.styleable.AndroidManifestApplication_hardwareAccelerated,
                owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.ICE_CREAM_SANDWICH);
        if (owner.baseHardwareAccelerated) {
            ai.flags |= ApplicationInfo.FLAG_HARDWARE_ACCELERATED;//硬件加速
        }

        if (sa.getBoolean(
                com.android.internal.R.styleable.AndroidManifestApplication_hasCode,//android:hasCode
                true)) {
            ai.flags |= ApplicationInfo.FLAG_HAS_CODE;//是否包含代码
        }

        if (sa.getBoolean(
                com.android.internal.R.styleable.AndroidManifestApplication_allowTaskReparenting,
                false)) {//是否设置android:allowTaskReparenting
            ai.flags |= ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING;
        }

        if (sa.getBoolean(
                com.android.internal.R.styleable.AndroidManifestApplication_allowClearUserData,
                true)) {//android:allowClearUserData是否给用户删除用户数据的权限
            ai.flags |= ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA;
        }

        // The parent package controls installation, hence specify test only installs.
        if (owner.parentPackage == null) {//父包控制安装,
            if (sa.getBoolean(
                    com.android.internal.R.styleable.AndroidManifestApplication_testOnly,
                    false)) {//android:testOnly是不是仅作为测试
                ai.flags |= ApplicationInfo.FLAG_TEST_ONLY;
            }
        }

        if (sa.getBoolean(//android:largeHeap=boolean,这个应用的进程是否需要最大的运行内存空间,对该应用的所有进程有效
                com.android.internal.R.styleable.AndroidManifestApplication_largeHeap,
                false)) {
            ai.flags |= ApplicationInfo.FLAG_LARGE_HEAP;
        }

        ......//android:permission;android:taskAffinity;android:process;android:enabled;android:isGame;

        ......//android:uiOptions;标示分离式操作栏。

        ......

        sa.recycle();//回收

        ......
        final int innerDepth = parser.getDepth();
        // IMPORTANT: These must only be cached for a single <application> to avoid components
        // getting added to the wrong package.
        final CachedComponentArgs cachedArgs = new CachedComponentArgs();
        int type;

        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")) {//解析Activity
                Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs, false,
                        owner.baseHardwareAccelerated);
                if (a == null) {
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                }

                owner.activities.add(a);

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

                owner.receivers.add(a);

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

                owner.services.add(s);

            } else if (tagName.equals("provider")) {//解析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);

            } else if (tagName.equals("activity-alias")) {//解析activity-alias
                Activity a = parseActivityAlias(owner, res, parser, flags, outError, cachedArgs);
                if (a == null) {
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                }

                owner.activities.add(a);

            } else if (parser.getName().equals("meta-data")) {//解析meta-data
                // note: application meta-data is stored off to the side, so it can
                // remain null in the primary copy (we like to avoid extra copies because
                // it can be large)
                if ((owner.mAppMetaData = parseMetaData(res, parser, owner.mAppMetaData,
                        outError)) == null) {
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                }
            } else if (tagName.equals("static-library")) {
                ......

            } else if (tagName.equals("library")) {
                ......

            } else if (tagName.equals("uses-static-library")) {
                if (!parseUsesStaticLibrary(owner, res, parser, outError)) {
                    return false;
                }

            } else if (tagName.equals("uses-library")) {
                ......

            } else if (tagName.equals("uses-package")) {
                // Dependencies for app installers; we don't currently try to
                // enforce this.
                XmlUtils.skipCurrentTag(parser);

            } else {
                ......
            }
        }

        // Must be ran after the entire {@link ApplicationInfo} has been fully processed and after
        // every activity info has had a chance to set it from its attributes.
        setMaxAspectRatio(owner);

        PackageBackwardCompatibility.modifySharedLibraries(owner);

        if (hasDomainURLs(owner)) {
            owner.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS;
        } else {
            owner.applicationInfo.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS;
        }

        return true;
    }

其实这个方法就是解析了application节点下的所有信息,比如activity、service、receiver、provider、library、users-librayry等信息,同时将解析后的每一个属性生成相应的对象,添加到传入的package里面,这些信息最后都会在PackageManagerService中用到。

我们从代码中看到了对Application中声明的Android四大组件的解析调用,它们的解析过程类似:都是调用XmlPullParser解析器解析各个节点的内容并保存。我们以解析Activity为例,来看它是如何解析<activity>节点、并保存其各个节点的信息的。

parseActivity

    private Activity parseActivity(Package owner, Resources res,
            XmlResourceParser parser, int flags, String[] outError, CachedComponentArgs cachedArgs,
            boolean receiver, boolean hardwareAccelerated)
            throws XmlPullParserException, IOException {
        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestActivity);//<activity>

        if (cachedArgs.mActivityArgs == null) {//初始化解析Activity参数
            cachedArgs.mActivityArgs = new ParseComponentArgs(owner, outError,
                    R.styleable.AndroidManifestActivity_name,
                    R.styleable.AndroidManifestActivity_label,
                    R.styleable.AndroidManifestActivity_icon,
                    R.styleable.AndroidManifestActivity_roundIcon,
                    R.styleable.AndroidManifestActivity_logo,
                    R.styleable.AndroidManifestActivity_banner,
                    mSeparateProcesses,
                    R.styleable.AndroidManifestActivity_process,
                    R.styleable.AndroidManifestActivity_description,
                    R.styleable.AndroidManifestActivity_enabled);
        }

        cachedArgs.mActivityArgs.tag = receiver ? "<receiver>" : "<activity>";//解析receiver或activity
        cachedArgs.mActivityArgs.sa = sa;//初始化这两个属性
        cachedArgs.mActivityArgs.flags = flags;

        Activity a = new Activity(cachedArgs.mActivityArgs, new ActivityInfo());//创建PackageParser的静态内部类对象
        ......//排除异常

        ......//exported,theme,uiOptions,parentActivityName,permission,taskAffinity,splitName,mulitprocess


        if (!receiver) {//不是receiver标签
            if (sa.getBoolean(R.styleable.AndroidManifestActivity_hardwareAccelerated,
                    hardwareAccelerated)) {
                a.info.flags |= ActivityInfo.FLAG_HARDWARE_ACCELERATED;//硬件加速
            }

            a.info.launchMode = sa.getInt(//设置启动模式,对应launchMode
                    R.styleable.AndroidManifestActivity_launchMode, ActivityInfo.LAUNCH_MULTIPLE);
            a.info.documentLaunchMode = sa.getInt(//设置启动模式,对应documentLaunchMode,主要指概览模式
                    R.styleable.AndroidManifestActivity_documentLaunchMode,
                    ActivityInfo.DOCUMENT_LAUNCH_NONE);
            ......//maxRecentes,configChanges,persistableMode,allowEmbedded,autoRemoveFromRecents....

        } else {//receiver标签
            a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE;//启动模式
            a.info.configChanges = 0;

            ......//single_user,exported,encryptionAware,
        }

        ......

        sa.recycle();

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

            if (parser.getName().equals("intent-filter")) {//<intent-filter>
                ActivityIntentInfo intent = new ActivityIntentInfo(a);//传入Activity对象创建ActivityIntentInfo对象
                if (!parseIntent(res, parser, true /*allowGlobs*/, true /*allowAutoVerify*/,
                        intent, outError)) {//解析<intent-filter>
                    return null;
                }
                if (intent.countActions() == 0) {
                    ......
                } else {
                    a.intents.add(intent);//添加intent
                }
                // adjust activity flags when we implicitly expose it via a browsable filter通过可浏览的过滤器调整flags
                ......
            } else if (!receiver && parser.getName().equals("preferred")) {//<activity>下的<preferred>标签
                ActivityIntentInfo intent = new ActivityIntentInfo(a);
                if (!parseIntent(res, parser, false /*allowGlobs*/, false /*allowAutoVerify*/,
                        intent, outError)) {//解析<preferred>标签
                    return null;
                }
                if (intent.countActions() == 0) {
                    ......
                } else {
                    if (owner.preferredActivityFilters == null) {
                        owner.preferredActivityFilters = new ArrayList<ActivityIntentInfo>();
                    }
                    owner.preferredActivityFilters.add(intent);
                }
                // adjust activity flags when we implicitly expose it via a browsable filter
                ......
            } else if (parser.getName().equals("meta-data")) {//<meta-data>
                if ((a.metaData = parseMetaData(res, parser, a.metaData,
                        outError)) == null) {//解析<meta-data>
                    return null;
                }
                // we don't have an attribute [or it's false], but, we have meta-data
                if (!visibleToEphemeral && a.metaData.getBoolean(META_DATA_INSTANT_APPS)) {//即时应用
                    ......
                }
            } else if (!receiver && parser.getName().equals("layout")) {
                parseLayout(res, parser, a);//解析Activity的layout
            } else {
                ......
            }
        }

        if (!setExported) {
            a.info.exported = a.intents.size() > 0;
        }

        return a;
    }

这个方法主要是解析AndroidManifest.xml里面的<activity>标签的内容,并将其映射到PackageParse.Activity对象.

过程解析的结果是以Package实例保存的,它描述了一个单独的APK文件中所声明的绝大部分信息。

上面的整个过程分析了单片样式(单个Apk)的分析方法,整个扫描过程:

 

PackageParser首先解析出了ApkLite,得到每个Apk文件的简化信息(对于具有多个Apk文件的Package来说,将得到多个ApkLite);利用所有的ApkLite及XML中的其它信息,解析出PackageLite;利用PackageLite中的信息及XML中的其它信息,解析出Package信息;Package中就基本上涵盖了AndroidManifest.xml中涉及的所有信息。

二、parseClusterPackage()

我们继续看下群集样式(apk目录)的扫描方式。

    /**
     * 将目录视为一个单独的APK安装包,解析这个目录下的所有APK。同样要执行完整性检查,例如“base APK”和“拆分APK”要求相同的包名,版本号,单一的基本APK,唯一的拆分名。
     */
    private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {
        final PackageLite lite = parseClusterPackageLite(packageDir, 0);//1.解析目录下的多APK文件,获取PackageLite对象
        if (mOnlyCoreApps && !lite.coreApp) {
            ......//非核心应用
        }

        // 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);//创建SplitAssetLoader对象
            } 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);
            final Package pkg = parseBaseApk(baseApk, assets, flags);//2.调用parseBaseAPK获取Package对象
            if (pkg == null) {
                ......//异常排查
            }

            if (!ArrayUtils.isEmpty(lite.splitNames)) {//开始解析拆分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);
                    parseSplitApk(pkg, i, splitAssets, flags);//3.调用parseSplitApk方法解析拆分APK
                }
            }

            pkg.setCodePath(packageDir.getAbsolutePath());
            pkg.setUse32bitAbi(lite.use32bitAbi);
            return pkg;
        } finally {
            IoUtils.closeQuietly(assetLoader);
        }
    }

(一)parseClusterPackageList()

 

    static PackageLite parseClusterPackageLite(File packageDir, int flags)
            throws PackageParserException {
        final File[] files = packageDir.listFiles();//列出所有文件
        ......//非空判断

        String packageName = null;//初始化
        int versionCode = 0;

        ......
        final ArrayMap<String, ApkLite> apks = new ArrayMap<>();//开始验证包名和版本号是否一致
        for (File file : files) {//遍历该目录下的所有文件
            if (isApkFile(file)) {//如果是APK
                final ApkLite lite = parseApkLite(file, flags);//调用parseApkLite方法解析APK,获取轻量级的ApkLite对象

                // Assert that all package names and version codes are
                // consistent with the first one we encounter.
                if (packageName == null) {//只有第一次循环时为空
                    packageName = lite.packageName;
                    versionCode = lite.versionCode;
                } else {
                    ......//对比当前的lite对象的包名和版本号与上一个lite对象的包名和版本号是否一致
                }

                // Assert that each split is defined only once
                if (apks.put(lite.splitName, lite) != null) {//保证不重复添加
                    ......//抛异常
                }
            }
        }
        ......

        final ApkLite baseApk = apks.remove(null);//获取base Apk
        if (baseApk == null) {
            ......//抛异常
        }

        // 始终根据拆分名排序
        final int size = apks.size();

        String[] splitNames = null;
        boolean[] isFeatureSplits = null;
        String[] usesSplitNames = null;
        String[] configForSplits = null;
        String[] splitCodePaths = null;
        int[] splitRevisionCodes = null;
        String[] splitClassLoaderNames = null;
        if (size > 0) {
            splitNames = new String[size];
            isFeatureSplits = new boolean[size];
            usesSplitNames = new String[size];
            configForSplits = new String[size];
            splitCodePaths = new String[size];
            splitRevisionCodes = new int[size];

            splitNames = apks.keySet().toArray(splitNames);//初始化splitNames
            Arrays.sort(splitNames, sSplitNameComparator);//排序

            for (int i = 0; i < size; i++) {//为上述变量赋值
                final ApkLite apk = apks.get(splitNames[i]);
                usesSplitNames[i] = apk.usesSplitName;
                isFeatureSplits[i] = apk.isFeatureSplit;
                configForSplits[i] = apk.configForSplit;
                splitCodePaths[i] = apk.codePath;
                splitRevisionCodes[i] = apk.revisionCode;
            }
        }

        final String codePath = packageDir.getAbsolutePath();
        return new PackageLite(codePath, baseApk, splitNames, isFeatureSplits, usesSplitNames,
                configForSplits, splitCodePaths, splitRevisionCodes);//根据上面获得的变量构建PackageLite对象
    }

上面我们分析了parseBaseAPK()方法,这里我们继续往下看parseSplitApk()方法。

(二)parseSplitApk()

    private void parseSplitApk(Package pkg, int splitIndex, AssetManager assets, int flags)
            throws PackageParserException {
        final String apkPath = pkg.splitCodePaths[splitIndex];//获取Apk的路径

        mParseError = PackageManager.INSTALL_SUCCEEDED;
        mArchiveSourcePath = apkPath;

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

        final int cookie = loadApkIntoAssetManager(assets, apkPath, flags);//1.loadApkIntoAssetManager

        final Resources res;
        XmlResourceParser parser = null;
        try {
            res = new Resources(assets, mMetrics, null);
            assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    Build.VERSION.RESOURCES_SDK_INT);
            parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);//获取XmlResourceParser

            final String[] outError = new String[1];
            pkg = parseSplitApk(pkg, res, parser, flags, splitIndex, outError);//2.parseSplitApk
            if (pkg == null) {
                ......//抛异常
            }

        } 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);//关闭
        }
    }

1. loadApkIntoAssetManager

    private static int loadApkIntoAssetManager(AssetManager assets, String apkPath, int flags)
            throws PackageParserException {
        ......//异常处理

        // AssetManager保证资源路径的唯一性,因此在AssetManager已经存在这个路径,仅返回分配给它的cookie
        int cookie = assets.addAssetPath(apkPath);//设置资源路径
        if (cookie == 0) {
            ......//抛异常
        }
        return cookie;
    }
    /**
     * 向资产管理器添加一组额外资产。可以是目录或ZIP文件,返回添加资源的cookie,如果失败返回0. 
     * {@hide}
     */
    public final int addAssetPath(String path) {
        return  addAssetPathInternal(path, false);
    }

addAssetPath方法将安装包路径和AssetManager关联在一起。

2.parseSplitApk

    /**
     * 解析"拆分 APK"的Manifest文件,由于对"拆分APK"限制比较多,所以像"base APK"的很多功能在"拆分APK"中已经省略了。
     */
    private Package parseSplitApk(Package pkg, Resources res, XmlResourceParser parser, int flags,
            int splitIndex, String[] outError) throws XmlPullParserException, IOException,
            PackageParserException {
        AttributeSet attrs = parser;

        // We parsed manifest tag earlier; just skip past it
        parsePackageSplitNames(parser, attrs);//预解析

        mParseInstrumentationArgs = null;

        int type;

        boolean foundApp = false;

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

            String tagName = parser.getName();
            if (tagName.equals(TAG_APPLICATION)) {//解析<application>标签
                if (foundApp) {//保证只有一个application标签
                    if (RIGID_PARSER) {
                        outError[0] = "<manifest> has more than one <application>";
                        mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                        return null;
                    } else {
                        ......
                    }
                }

                foundApp = true;
                if (!parseSplitApplication(pkg, res, parser, flags, splitIndex, outError)) {
                    return null;//解析parseSplitApplication
                }

            } else if (RIGID_PARSER) {
                ......

            } else {
                ......
            }
        }

        if (!foundApp) {
            ......
        }

        return pkg;
    }

3. parseSplitApplication()


    private boolean parseSplitApplication(Package owner, Resources res, XmlResourceParser parser,
            int flags, int splitIndex, String[] outError)
            throws XmlPullParserException, IOException {
        TypedArray sa = res.obtainAttributes(parser,
                com.android.internal.R.styleable.AndroidManifestApplication);//获取application的数组资源

        if (sa.getBoolean(
                com.android.internal.R.styleable.AndroidManifestApplication_hasCode, true)) {
            owner.splitFlags[splitIndex] |= ApplicationInfo.FLAG_HAS_CODE;
        }

        final String classLoaderName = sa.getString(//拆分APK的classLoader
                com.android.internal.R.styleable.AndroidManifestApplication_classLoader);
        if (classLoaderName == null || ClassLoaderFactory.isValidClassLoaderName(classLoaderName)) {
            owner.applicationInfo.splitClassLoaderNames[splitIndex] = classLoaderName;
        } else {
            ......
        }

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

            ComponentInfo parsedComponent = null;

            // IMPORTANT: These must only be cached for a single <application> to avoid components
            // getting added to the wrong package.
            final CachedComponentArgs cachedArgs = new CachedComponentArgs();
            String tagName = parser.getName();
            if (tagName.equals("activity")) {//解析Activity
                Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs, false,
                        owner.baseHardwareAccelerated);//parseActivity
                if (a == null) {//解析失败
                    ......
                }

                owner.activities.add(a);
                parsedComponent = a.info;

            } else if (tagName.equals("receiver")) {//解析 receiver
                Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs,
                        true, false);
                if (a == null) {
                    ......
                }

                owner.receivers.add(a);
                parsedComponent = a.info;

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

                owner.services.add(s);
                parsedComponent = s.info;

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

                owner.providers.add(p);
                parsedComponent = p.info;

            } else if (tagName.equals("activity-alias")) {
                Activity a = parseActivityAlias(owner, res, parser, flags, outError, cachedArgs);
                if (a == null) {
                    ......
                }

                owner.activities.add(a);
                parsedComponent = a.info;

            } else if (parser.getName().equals("meta-data")) {
                // note: application meta-data is stored off to the side, so it can
                // remain null in the primary copy (we like to avoid extra copies because
                // it can be large)
                if ((owner.mAppMetaData = parseMetaData(res, parser, owner.mAppMetaData,
                        outError)) == null) {
                    ......
                }

            } else if (tagName.equals("uses-static-library")) {
                if (!parseUsesStaticLibrary(owner, res, parser, outError)) {
                    return false;
                }

            } else if (tagName.equals("uses-library")) {
                ......
            } else if (tagName.equals("uses-package")) {
                // Dependencies for app installers; we don't currently try to
                // enforce this.
                XmlUtils.skipCurrentTag(parser);

            } else {
                ......
            }

            if (parsedComponent != null && parsedComponent.splitName == null) {
                // If the loaded component did not specify a split, inherit the split name
                // based on the split it is defined in.
                // This is used to later load the correct split when starting this
                // component.
                parsedComponent.splitName = owner.splitNames[splitIndex];
            }
        }

        return true;
    }

在上面我们就分析了parseActivity方法,这里就忽略了。

三、cacheResult


    /**
     * 缓存packageFile的解析结果.
     */
    private void cacheResult(File packageFile, int flags, Package parsed) {
        if (mCacheDir == null) {
            return;
        }

        try {
            final String cacheKey = getCacheKey(packageFile, flags);
            final File cacheFile = new File(mCacheDir, cacheKey);

            if (cacheFile.exists()) {
                if (!cacheFile.delete()) {
                    Slog.e(TAG, "Unable to delete cache file: " + cacheFile);
                }
            }

            final byte[] cacheEntry = toCacheEntry(parsed);

            if (cacheEntry == null) {
                return;
            }

            try (FileOutputStream fos = new FileOutputStream(cacheFile)) {
                fos.write(cacheEntry);
            } catch (IOException ioe) {
                Slog.w(TAG, "Error writing cache entry.", ioe);
                cacheFile.delete();
            }
        } catch (Throwable e) {
            Slog.w(TAG, "Error saving package cache.", e);
        }
    }

至此,解析流程基本分析完毕。这些解析过程全部都在PackageParser类中处理。

    原文作者:Kitty_London2
    原文地址: https://blog.csdn.net/weixin_41987588/article/details/81093770
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞