APK安裝流程詳解10——PackageParser解析APK(下)

APK安裝流程系列文章整體內(nèi)容如下:

本片文章的主要內(nèi)容如下:

  • 12、PackageParse#parseBaseApplication(Package, Resources,XmlPullParser, AttributeSet, int, String[])方法解析
  • 13、PackageParse#parseClusterPackage(File,int)方法解析
  • 14、PackageParse#parseClusterPackageLite(File,int)方法解析
  • 15、PackageParse#loadApkIntoAssetManager(AssetManager, String, int)方法解析
  • 16、PackageParse#parseSplitApk(Package, int, AssetManager, int)方法解析
  • 17、PackageParse#parseSplitApk(Package, Resources, XmlResourceParser, int,int, String[])方法解析
  • 18、PackageParse#parseSplitApplication(Package, Resources, XmlResourceParser, int, int, String[]) 方法解析
  • 19、PackageParse#parseActivity(Package, Resources,XmlPullParser, AttributeSet, int, String[],boolean, boolean)方法解析
  • 20、總結(jié)

十二、PackageParse#parseBaseApplication(Package, Resources,XmlPullParser, AttributeSet, int, String[])方法解析

代碼在PackageParser.java 2406行

/**
     * Parse the {@code application} XML tree at the current parse location in a
     * <em>base APK</em> manifest.
     * <p>
     * When adding new features, carefully consider if they should also be
     * supported by split APKs.
     */
    private boolean parseBaseApplication(Package owner, Resources res,
            XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)
        throws XmlPullParserException, IOException {
        // 獲取ApplicationInfo對(duì)象ai
        final ApplicationInfo ai = owner.applicationInfo;
        // 獲取包名
        final String pkgName = owner.applicationInfo.packageName;
         // 從資源里面獲取AndroidManifest的數(shù)組 
        TypedArray sa = res.obtainAttributes(attrs,
                com.android.internal.R.styleable.AndroidManifestApplication);
         // 獲取Application的名字
        String name = sa.getNonConfigurationString(
                com.android.internal.R.styleable.AndroidManifestApplication_name, 0);
        if (name != null) {
             // 如果有設(shè)置過Application,則設(shè)置ApplicationInfo的類名
            ai.className = buildClassName(pkgName, name, outError);
            if (ai.className == null) {
                // 如果設(shè)置過Application則直接返回
                sa.recycle();
                mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                return false;
            }
        }
        // 在AndroidManifest里面是否設(shè)置了android:manageSpaceActivity屬性,如果設(shè)置了則manageSpaceActivity不為空,沒有設(shè)置manageSpaceActivity為空
        String manageSpaceActivity = sa.getNonConfigurationString(
                com.android.internal.R.styleable.AndroidManifestApplication_manageSpaceActivity,
                Configuration.NATIVE_CONFIG_VERSION);
        if (manageSpaceActivity != null) {
             // 如果設(shè)置了,則添加類名
            ai.manageSpaceActivityName = buildClassName(pkgName, manageSpaceActivity,
                    outError);
        }
        // 是否設(shè)置了androidMannifest.xml文件中android:allowBackup屬性;
        boolean allowBackup = sa.getBoolean(
                com.android.internal.R.styleable.AndroidManifestApplication_allowBackup, true);
        // 如果設(shè)置了 允許備份
        if (allowBackup) {
            ai.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP;

            // backupAgent, killAfterRestore, fullBackupContent and restoreAnyVersion are only
            // relevant if backup is possible for the given application.
            // 獲取backupAgent,如果在AndroidManifest里面設(shè)置了android:backupAgent屬性,則backupAgent不為空,否則backupAgent為空
            String backupAgent = sa.getNonConfigurationString(
                    com.android.internal.R.styleable.AndroidManifestApplication_backupAgent,
                    Configuration.NATIVE_CONFIG_VERSION);
            if (backupAgent != null) {
                // 設(shè)置了backupAgent,這構(gòu)建類名
                ai.backupAgentName = buildClassName(pkgName, backupAgent, outError);
                if (DEBUG_BACKUP) {
                    Slog.v(TAG, "android:backupAgent = " + ai.backupAgentName
                            + " from " + pkgName + "+" + backupAgent);
                }

                 //是否設(shè)置了killAfterRestore屬性,即在AndroidManfest中是否設(shè)置了android:killAfterRestore=true,如果設(shè)置了,配置相應(yīng)標(biāo)志
                if (sa.getBoolean(
                        com.android.internal.R.styleable.AndroidManifestApplication_killAfterRestore,
                        true)) {
                    ai.flags |= ApplicationInfo.FLAG_KILL_AFTER_RESTORE;
                }

                //是否設(shè)置了restoreAnyVersion屬性,即在AndroidManfest中是否設(shè)置了restoreAnyVersion=boolean,如果設(shè)置了,配置相應(yīng)標(biāo)志
                // 這里restoreAnyVersion屬性 是指是否允許回復(fù)任意版本的本分?jǐn)?shù)據(jù)來恢復(fù)應(yīng)用程序的數(shù)據(jù)。
                //將該屬性設(shè)置為true,則將允許本分管理器嘗試恢復(fù)操作,有的時(shí)候版本不匹配表明數(shù)據(jù)是不兼容的,
                // 這個(gè)時(shí)候如果可以恢復(fù)到不同的版本的數(shù)據(jù),那么應(yīng)用程序?qū)⒊惺芎艽箫L(fēng)險(xiǎn),所以請(qǐng)謹(jǐn)慎使用此屬性。
                if (sa.getBoolean(
                        com.android.internal.R.styleable.AndroidManifestApplication_restoreAnyVersion,
                        false)) {
                    ai.flags |= ApplicationInfo.FLAG_RESTORE_ANY_VERSION;
                }

                 // 是否開啟[Auto Backup for Apps](https://developer.android.com/guide/topics/data/autobackup.html)功能
                if (sa.getBoolean(
                        com.android.internal.R.styleable.AndroidManifestApplication_fullBackupOnly,
                        false)) {
                    ai.flags |= ApplicationInfo.FLAG_FULL_BACKUP_ONLY;
                }
            }

            // 獲取android:fullBackupContent的屬性,這個(gè)標(biāo)示用來指明備份數(shù)據(jù)的規(guī)則,該標(biāo)示是配合[Auto Backup for Apps](https://developer.android.com/guide/topics/data/autobackup.html)來使用的
            TypedValue v = sa.peekValue(
                    com.android.internal.R.styleable.AndroidManifestApplication_fullBackupContent);
            if (v != null && (ai.fullBackupContent = v.resourceId) == 0) {
                if (DEBUG_BACKUP) {
                    Slog.v(TAG, "fullBackupContent specified as boolean=" +
                            (v.data == 0 ? "false" : "true"));
                }
                // "false" => -1, "true" => 0
                ai.fullBackupContent = (v.data == 0 ? -1 : 0);
            }
            if (DEBUG_BACKUP) {
                Slog.v(TAG, "fullBackupContent=" + ai.fullBackupContent + " for " + pkgName);
            }
        }

         // 獲取<Application> 里面的"label"屬性,并設(shè)置相應(yīng)的屬性
        TypedValue v = sa.peekValue(
                com.android.internal.R.styleable.AndroidManifestApplication_label);
        if (v != null && (ai.labelRes=v.resourceId) == 0) {
            ai.nonLocalizedLabel = v.coerceToString();
        }
        // 設(shè)置icon、logo、banner、theme、descriptionRes屬性
        ai.icon = sa.getResourceId(
                com.android.internal.R.styleable.AndroidManifestApplication_icon, 0);
        ai.logo = sa.getResourceId(
                com.android.internal.R.styleable.AndroidManifestApplication_logo, 0);
        ai.banner = sa.getResourceId(
                com.android.internal.R.styleable.AndroidManifestApplication_banner, 0);
        ai.theme = sa.getResourceId(
                com.android.internal.R.styleable.AndroidManifestApplication_theme, 0);
        ai.descriptionRes = sa.getResourceId(
                com.android.internal.R.styleable.AndroidManifestApplication_description, 0);

        // 判斷是否是系統(tǒng)APP
        if ((flags&PARSE_IS_SYSTEM) != 0) {
            // 判斷是否長期駐留
            if (sa.getBoolean(
                    com.android.internal.R.styleable.AndroidManifestApplication_persistent,
                    false)) {
                ai.flags |= ApplicationInfo.FLAG_PERSISTENT;
            }
        }

        // 獲取應(yīng)用的android:requiredForAllUsers屬性,是否設(shè)置該應(yīng)用是否需要對(duì)所有用戶可用
        if (sa.getBoolean(
                com.android.internal.R.styleable.AndroidManifestApplication_requiredForAllUsers,
                false)) {
            owner.mRequiredForAllUsers = true;
        }
   
        // 設(shè)置android:restrictedAccountType屬性
         // 是否允許受限用戶訪問機(jī)主的該賬戶,如果應(yīng)用程序要使用Account 并且允許受限用戶訪問主賬戶
         // 本屬性值必須與應(yīng)用程序賬戶認(rèn)證類型(由AuthenticatorDescription)定義吻合。
        // 如果設(shè)置了本屬性將允許受限用戶通過主賬戶使用你的應(yīng)用程序,這可能會(huì)泄露個(gè)人身份信息。
        String restrictedAccountType = sa.getString(com.android.internal.R.styleable
                .AndroidManifestApplication_restrictedAccountType);
        if (restrictedAccountType != null && restrictedAccountType.length() > 0) {
            owner.mRestrictedAccountType = restrictedAccountType;
        }

         // 設(shè)置 android:restrictedAccountType中的值
         // 設(shè)置應(yīng)用程序所需的賬戶類型。如果應(yīng)用程序需要一個(gè)Account才能運(yùn)行,本屬性必須與賬戶認(rèn)證類型(由AuthenticatorDescription 定義)吻合。 
        String requiredAccountType = sa.getString(com.android.internal.R.styleable
                .AndroidManifestApplication_requiredAccountType);
        if (requiredAccountType != null && requiredAccountType.length() > 0) {
            owner.mRequiredAccountType = requiredAccountType;
        }

       // 是否設(shè)置了 android:debuggable
        if (sa.getBoolean(
                com.android.internal.R.styleable.AndroidManifestApplication_debuggable,
                false)) {
            ai.flags |= ApplicationInfo.FLAG_DEBUGGABLE;
        }

        // 是否設(shè)置了 android:vmSafeMode屬性
        // 這個(gè)表示用來指明這個(gè)應(yīng)用是否想讓 VM虛擬機(jī)運(yùn)行在安全模式,默認(rèn)值為false
        //這個(gè)標(biāo)示是API 18版本添加,如果設(shè)置 true 將會(huì)禁用 Dalvik just-in-time(JIT)編譯器,
        // 這個(gè)標(biāo)示在 API 22 版本之后為新版本做了改進(jìn),因?yàn)?.4 之后 Dalvik 虛擬機(jī)就被廢棄
        // 在22版本 之后這個(gè)標(biāo)示如果設(shè)置 為true 將會(huì)禁用ART ahead-of-time(AOT) 編譯器
        if (sa.getBoolean(
                com.android.internal.R.styleable.AndroidManifestApplication_vmSafeMode,
                false)) {
            ai.flags |= ApplicationInfo.FLAG_VM_SAFE_MODE;
        }

        // 設(shè)置 是否硬件加速
        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;
        }

        // 是否包含代碼 對(duì)應(yīng)AndroidManifest里面的android:hasCode
        if (sa.getBoolean(
                com.android.internal.R.styleable.AndroidManifestApplication_hasCode,
                true)) {
            ai.flags |= ApplicationInfo.FLAG_HAS_CODE;
        }
        // 是否設(shè)置了"android:allowTaskReparenting=boolean",這個(gè)標(biāo)示和Application 的 標(biāo)示意義一樣,
        // 所以如果同時(shí)聲明該標(biāo)示,這個(gè)標(biāo)示會(huì)覆蓋Application 的標(biāo)示
        if (sa.getBoolean(
                com.android.internal.R.styleable.AndroidManifestApplication_allowTaskReparenting,
                false)) {
            ai.flags |= ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING;
        }
  
       // 是否設(shè)置了android:allowClearUserData=boolean。是否給用戶刪除用戶數(shù)據(jù)的權(quán)限,
       // 如果為true應(yīng)用管理者就擁有了清楚數(shù)據(jù)的權(quán)限;false沒有。默認(rèn)為true
        if (sa.getBoolean(
                com.android.internal.R.styleable.AndroidManifestApplication_allowClearUserData,
                true)) {
            ai.flags |= ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA;
        }

        // 是否設(shè)置"android:testOnly=boolean",這個(gè)標(biāo)示用來指明這個(gè)應(yīng)用是不是僅僅作為測(cè)試的用戶,
        // 比如本應(yīng)用程序可能會(huì)暴露一些不屬于自己的功能或數(shù)據(jù),這將引發(fā)安全漏洞,
        // 但對(duì)測(cè)試而言這又非常有用,而且這種應(yīng)用程序只能通過 adb 進(jìn)行安全
        if (sa.getBoolean(
                com.android.internal.R.styleable.AndroidManifestApplication_testOnly,
                false)) {
            ai.flags |= ApplicationInfo.FLAG_TEST_ONLY;
        }

        // 對(duì)應(yīng)"android:largeHeap=boolean"屬性,這個(gè)標(biāo)示用來表明這個(gè)應(yīng)用的進(jìn)程是否需要更大的運(yùn)行內(nèi)存空間,這個(gè)標(biāo)示對(duì)該應(yīng)用的所有進(jìn)程有效
        if (sa.getBoolean(
                com.android.internal.R.styleable.AndroidManifestApplication_largeHeap,
                false)) {
            ai.flags |= ApplicationInfo.FLAG_LARGE_HEAP;
        }

        // 對(duì)應(yīng)"android:usesCleartextTraffic=boolean"屬性。默認(rèn)值為true
        //  它用來指明應(yīng)用是否需要使用明文的網(wǎng)絡(luò)連接,例如明文的HTTP連接
        if (sa.getBoolean(
                com.android.internal.R.styleable.AndroidManifestApplication_usesCleartextTraffic,
                true)) {
            ai.flags |= ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC;
        }

       // 對(duì)應(yīng)"android:supportsRtl=boolean",這個(gè)標(biāo)示是用來聲明應(yīng)用是否支持從右到左的布局方式
        if (sa.getBoolean(
                com.android.internal.R.styleable.AndroidManifestApplication_supportsRtl,
                false /* default is no RTL support*/)) {
            ai.flags |= ApplicationInfo.FLAG_SUPPORTS_RTL;
        }

        // 是否支持多平臺(tái)
        if (sa.getBoolean(
                com.android.internal.R.styleable.AndroidManifestApplication_multiArch,
                false)) {
            ai.flags |= ApplicationInfo.FLAG_MULTIARCH;
        }

        // 對(duì)應(yīng)AndroidManifest的"android:extractNativeLibs=boolean",這個(gè)標(biāo)示是Android 6.0引入。
        // 該屬性如果設(shè)置了 false,則系統(tǒng)在安裝系統(tǒng)的時(shí)候不會(huì)把so文件從apk中解壓出來了
        // 同時(shí)修改了System.loadLibrary 直接打開調(diào)用apk中的.so文件。但是,目前要讓該熟悉感生效還有兩個(gè)條件:
        // 一是apk中的.so文件不能被壓縮;二是.so必須是用zipalign -p 4來對(duì)齊。該標(biāo)示的默認(rèn)值為true。
        if (sa.getBoolean(
                com.android.internal.R.styleable.AndroidManifestApplication_extractNativeLibs,
                true)) {
            ai.flags |= ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS;
        }

        String str;
        // 對(duì)應(yīng)"android:permission=string"屬性
        str = sa.getNonConfigurationString(
                com.android.internal.R.styleable.AndroidManifestApplication_permission, 0);
        ai.permission = (str != null && str.length() > 0) ? str.intern() : null;

        // 解析"android:allowTaskReparenting=boolean" 設(shè)置吸附質(zhì),影響Activity的啟動(dòng)模式
        if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {
            str = sa.getNonConfigurationString(
                    com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity,
                    Configuration.NATIVE_CONFIG_VERSION);
        } else {
            // Some older apps have been seen to use a resource reference
            // here that on older builds was ignored (with a warning).  We
            // need to continue to do this for them so they don't break.
            str = sa.getNonResourceString(
                    com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity);
        }
        // 設(shè)置吸附質(zhì)
        ai.taskAffinity = buildTaskAffinityName(ai.packageName, ai.packageName,
                str, outError);

        if (outError[0] == null) {
            CharSequence pname;
     
            // 對(duì)應(yīng)"android:process"屬性。
            if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {
                pname = sa.getNonConfigurationString(
                        com.android.internal.R.styleable.AndroidManifestApplication_process,
                        Configuration.NATIVE_CONFIG_VERSION);
            } else {
                // Some older apps have been seen to use a resource reference
                // here that on older builds was ignored (with a warning).  We
                // need to continue to do this for them so they don't break.
                pname = sa.getNonResourceString(
                        com.android.internal.R.styleable.AndroidManifestApplication_process);
            }

            // 設(shè)置進(jìn)程名
            ai.processName = buildProcessName(ai.packageName, null, pname,
                    flags, mSeparateProcesses, outError);
android:enabled

            // 對(duì)應(yīng)"android:enable=boolean"屬性,這個(gè)標(biāo)識(shí)用來表明系統(tǒng)能否實(shí)例化這個(gè)應(yīng)用的組件。
            ai.enabled = sa.getBoolean(
                    com.android.internal.R.styleable.AndroidManifestApplication_enabled, true);

            // 對(duì)應(yīng) "android:isGame=boolean" 屬性,這個(gè)標(biāo)識(shí)用來表明應(yīng)用是否是游戲,這樣就能夠?qū)⒃搼?yīng)用和其他應(yīng)用分離開,默認(rèn)值為false
            if (sa.getBoolean(
                    com.android.internal.R.styleable.AndroidManifestApplication_isGame, false)) {
                ai.flags |= ApplicationInfo.FLAG_IS_GAME;
            }
            
            //  這里注意,if(false) 是一定不執(zhí)行的 
            if (false) {
                // 對(duì)應(yīng)的android:cantSaveState屬性, 設(shè)置了則APP就可視為heavy-weight process
                if (sa.getBoolean(
                        com.android.internal.R.styleable.AndroidManifestApplication_cantSaveState,
                        false)) {
                    ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE;

                    // A heavy-weight application can not be in a custom process.
                    // We can do direct compare because we intern all strings.
                    if (ai.processName != null && ai.processName != ai.packageName) {
                        outError[0] = "cantSaveState applications can not use custom processes";
                    }
                }
            }
        }

        // 對(duì)應(yīng)"android:uiOptions",標(biāo)識(shí)分離式操作欄
        ai.uiOptions = sa.getInt(
                com.android.internal.R.styleable.AndroidManifestApplication_uiOptions, 0);

        // 回收
        sa.recycle();

        if (outError[0] != null) {
            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
            return false;
        }

        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;
            }

            String tagName = parser.getName();
            // 解析activity
            if (tagName.equals("activity")) {
                Activity a = parseActivity(owner, res, parser, attrs, flags, outError, 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, attrs, flags, outError, 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, attrs, flags, outError);
                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, attrs, flags, outError);
                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, attrs, flags, outError);
                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, attrs, owner.mAppMetaData,
                        outError)) == null) {
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                }

            } else if (tagName.equals("library")) {
                // 解析<library>標(biāo)簽
                sa = res.obtainAttributes(attrs,
                        com.android.internal.R.styleable.AndroidManifestLibrary);
                // Note: don't allow this value to be a reference to a resource
                // that may change.
                String lname = sa.getNonResourceString(
                        com.android.internal.R.styleable.AndroidManifestLibrary_name);

                sa.recycle();

                if (lname != null) {
                    lname = lname.intern();
                    if (!ArrayUtils.contains(owner.libraryNames, lname)) {
                        owner.libraryNames = ArrayUtils.add(owner.libraryNames, lname);
                    }
                }

                XmlUtils.skipCurrentTag(parser);

            } else if (tagName.equals("uses-library")) {
                // 解析<uses-library>標(biāo)簽
                sa = res.obtainAttributes(attrs,
                        com.android.internal.R.styleable.AndroidManifestUsesLibrary);

                // Note: don't allow this value to be a reference to a resource
                // that may change.
                String lname = sa.getNonResourceString(
                        com.android.internal.R.styleable.AndroidManifestUsesLibrary_name);
                boolean req = sa.getBoolean(
                        com.android.internal.R.styleable.AndroidManifestUsesLibrary_required,
                        true);

                sa.recycle();

                if (lname != null) {
                    lname = lname.intern();
                    if (req) {
                        owner.usesLibraries = ArrayUtils.add(owner.usesLibraries, lname);
                    } else {
                        owner.usesOptionalLibraries = ArrayUtils.add(
                                owner.usesOptionalLibraries, lname);
                    }
                }

                XmlUtils.skipCurrentTag(parser);

            } else if (tagName.equals("uses-package")) {
                // 解析<uses-package>標(biāo)簽
                // Dependencies for app installers; we don't currently try to
                // enforce this.
                XmlUtils.skipCurrentTag(parser);

            } else {
                if (!RIGID_PARSER) {
                    Slog.w(TAG, "Unknown element under <application>: " + tagName
                            + " at " + mArchiveSourcePath + " "
                            + parser.getPositionDescription());
                    XmlUtils.skipCurrentTag(parser);
                    continue;
                } else {
                    outError[0] = "Bad element under <application>: " + tagName;
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                }
            }
        }

        modifySharedLibrariesForBackwardCompatibility(owner);

        // 檢查IntentFilter之一是否包含DEFAULT / VIEW和HTTP / HTTPS數(shù)據(jù)URI
        if (hasDomainURLs(owner)) {
            owner.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS;
        } else {
            owner.applicationInfo.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS;
        }

        return true;
    }

先來翻譯下注釋:

解析"base APK" 的manifest的XML樹中
添加新特性的時(shí)候,請(qǐng)仔細(xì)思考是否支持"拆分APK"。

其實(shí)這個(gè)方法就是解析了application節(jié)點(diǎn)下的所有信息,比如activity、service、receiver、provider、library、users-librayry等信息,同時(shí)將解析后的每一個(gè)屬性生成相應(yīng)的對(duì)象,添加到傳入的package里面,這些信息最后都會(huì)在PackageManagerService中用到。

十三、PackageParse#parseClusterPackage(File,int)方法解析

代碼在PackageParser.java 769行

    /**
     * Parse all APKs contained in the given directory, treating them as a
     * single package. This also performs sanity checking, such as requiring
     * identical package name and version codes, a single base APK, and unique
     * split names.
     * <p>
     * Note that this <em>does not</em> perform signature verification; that
     * must be done separately in {@link #collectCertificates(Package, int)}.
     */
    private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {
        // ************ 第一步 *************
        // 解析目錄,并獲取對(duì)應(yīng)的PackageLite
        final PackageLite lite = parseClusterPackageLite(packageDir, 0);
         // 核心應(yīng)用的判斷
        if (mOnlyCoreApps && !lite.coreApp) {
            throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
                    "Not a coreApp: " + packageDir);
        }

         // ************ 第二步 *************
        // 獲取AssetManager對(duì)象
        final AssetManager assets = new AssetManager();
        try {
            // Load the base and all splits into the AssetManager
            // so that resources can be overriden when parsing the manifests.
             // 載入AssetManager到base APK中
            loadApkIntoAssetManager(assets, lite.baseCodePath, flags);
            // 把AssetManager 載入到每個(gè)"拆分APK"中
            if (!ArrayUtils.isEmpty(lite.splitCodePaths)) {
                for (String path : lite.splitCodePaths) {
                    loadApkIntoAssetManager(assets, path, flags);
                }
            }
             // ************ 第三步 *************
            final File baseApk = new File(lite.baseCodePath);
            // 開始解析"base" APK文件,并獲得對(duì)應(yīng)的Package 對(duì)象
            final Package pkg = parseBaseApk(baseApk, assets, flags);
            if (pkg == null) {
                throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
                        "Failed to parse base APK: " + baseApk);
            }
            // ************ 第四步 *************
           // 開始解析"拆分APK"。
            if (!ArrayUtils.isEmpty(lite.splitNames)) {
                final int num = lite.splitNames.length;
                pkg.splitNames = lite.splitNames;
                pkg.splitCodePaths = lite.splitCodePaths;
                pkg.splitRevisionCodes = lite.splitRevisionCodes;
                pkg.splitFlags = new int[num];
                pkg.splitPrivateFlags = new int[num];

                for (int i = 0; i < num; i++) {
                    parseSplitApk(pkg, i, assets, flags);
                }
            }
            // 設(shè)置相應(yīng)屬性
            pkg.setCodePath(packageDir.getAbsolutePath());
            pkg.setUse32bitAbi(lite.use32bitAbi);
            return pkg;
        } finally {
           // 關(guān)閉
            IoUtils.closeQuietly(assets);
        }
    }

該方法有注釋,先來看下方法的注釋:

將目錄視為一個(gè)單獨(dú)的APK安裝包,解析這個(gè)目錄下的所有APK安裝包。同樣也執(zhí)行例行檢查,比如檢查"base APK"和"拆分APK"是否有相同的安裝包包名和版本號(hào)。
注意:這個(gè)方法執(zhí)行簽名驗(yàn)證,所以要單獨(dú)的調(diào)用collectCertificates(Package,int)方法

這個(gè)方法我的理解:

parseClusterPackage的主要內(nèi)容,就是用于解析存在多個(gè)APK的文件的Package。我將本方法分為四個(gè)步驟:

  • 第一步:調(diào)用parseClusterPackageLite解析目錄下的多APK文件,獲取對(duì)應(yīng)的PackageLite對(duì)象lite
  • 第二步:創(chuàng)建AssetManager對(duì)象,并調(diào)用loadApkIntoAssetManager方法載入"base APK"。?
  • 第三步:調(diào)用parseBaseApk方法獲取對(duì)應(yīng)的Package對(duì)象
  • 第四步:遍歷所有"拆分APK",然后載入第二步創(chuàng)建的AssetManager對(duì)象,這樣就實(shí)現(xiàn)了資源文件的載入。

這里面涉及到了幾個(gè)方法:

  • parseBaseApk(File, AssetManager, int)方法
  • parseClusterPackageLite(File,int)方法
  • loadApkIntoAssetManager(AssetManager,String,int)方法
  • parseSplitApk(Package, int, AssetManager, int)方法

其中第一個(gè)parseBaseApk(File, AssetManager, int)方法,已經(jīng)講解過了,請(qǐng)參考APK安裝流程詳解9——PackageParser解析APK(上)五、PackageParse#parseMonolithicPackage(File, int)方法解析

下面我們依次講解下上面的其他三個(gè)方法

十四、PackageParse#parseClusterPackageLite(File,int)方法解析

代碼在PackageParser.java 664行

    private static PackageLite parseClusterPackageLite(File packageDir, int flags)
            throws PackageParserException {
        // ************** 第一步 **************
        // 獲取目錄下的所有文件
        final File[] files = packageDir.listFiles();
        // 非空判斷
        if (ArrayUtils.isEmpty(files)) {
            throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
                    "No packages found in split");
        }
        // 初始化
        String packageName = null;
        int versionCode = 0;
       
        // 開始驗(yàn)證包名和版本號(hào)是否一致
        final ArrayMap<String, ApkLite> apks = new ArrayMap<>();
        // 遍歷所有文件
        for (File file : files) {
            if (isApkFile(file)) {
                //解析單個(gè)APK文件成ApkLite對(duì)象
                final ApkLite lite = parseApkLite(file, flags);

                // Assert that all package names and version codes are
                // consistent with the first one we encounter.
                // 遍歷的時(shí)候只有第一個(gè)文件的時(shí)候packageName為null
                if (packageName == null) {
                    packageName = lite.packageName;
                    versionCode = lite.versionCode;
                } else {
                    // 對(duì)比當(dāng)前的lite對(duì)象和上一個(gè)lite對(duì)象的包名是否一致
                    if (!packageName.equals(lite.packageName)) {
                        throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
                                "Inconsistent package " + lite.packageName + " in " + file
                                + "; expected " + packageName);
                    }
                    // 對(duì)比當(dāng)前的lite對(duì)象和上一個(gè)lite對(duì)象的版本號(hào)是否一致
                    if (versionCode != lite.versionCode) {
                        throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
                                "Inconsistent version " + lite.versionCode + " in " + file
                                + "; expected " + versionCode);
                    }
                }

                // Assert that each split is defined only once
                // 保證不重復(fù)添加
                if (apks.put(lite.splitName, lite) != null) {
                    throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
                            "Split name " + lite.splitName
                            + " defined more than once; most recent was " + file);
                }
            }
        }
        // ************** 第二步 **************
        // 獲取base APK
        final ApkLite baseApk = apks.remove(null);
        if (baseApk == null) {
            throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
                    "Missing base APK in " + packageDir);
        }

        // Always apply deterministic ordering based on splitName

        final int size = apks.size();

        
        String[] splitNames = null;
        String[] splitCodePaths = null;
        int[] splitRevisionCodes = null;
        if (size > 0) {
            splitNames = new String[size];
            splitCodePaths = new String[size];
            splitRevisionCodes = new int[size];
            // 初始化 splitNames
            splitNames = apks.keySet().toArray(splitNames);
             //  splitNames排序
            Arrays.sort(splitNames, sSplitNameComparator);
            // 初始化splitCodePaths和splitRevisionCodes
            for (int i = 0; i < size; i++) {
                splitCodePaths[i] = apks.get(splitNames[i]).codePath;
                splitRevisionCodes[i] = apks.get(splitNames[i]).revisionCode;
            }
        }

        final String codePath = packageDir.getAbsolutePath();
        // ************** 第三步 **************
        return new PackageLite(codePath, baseApk, splitNames, splitCodePaths,
                splitRevisionCodes);
    }

我將這個(gè)方法分為3個(gè)步驟:

  • 第一步:理性校驗(yàn),主要是校驗(yàn)包名和版本號(hào)是否一致
  • 第二步:給baseApk、splitNames、splitCodePaths、splitRevisionCodes、codePath完成初始化
  • 第三步:根據(jù)第二步給出的變量,new一個(gè)PackageLite對(duì)象

十五、PackageParse#loadApkIntoAssetManager(AssetManager, String, int)方法解析

代碼在PackageParser.java 846行

    private static int loadApkIntoAssetManager(AssetManager assets, String apkPath, int flags)
            throws PackageParserException {
        // 簡單的檢查
        if ((flags & PARSE_MUST_BE_APK) != 0 && !isApkPath(apkPath)) {
            throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
                    "Invalid package file: " + apkPath);
        }

        // The AssetManager guarantees uniqueness for asset paths, so if this asset path
        // already exists in the AssetManager, addAssetPath will only return the cookie
        // assigned to it.
        // 添加路徑
        // **************** 核心方法 ********************
        int cookie = assets.addAssetPath(apkPath);
        if (cookie == 0) {
            throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
                    "Failed adding asset path: " + apkPath);
        }
        return cookie;
    }

這個(gè)方法主要讓AssetManager和安裝包的路徑的關(guān)聯(lián),主要是調(diào)用AssetManager的addAssetPath方法進(jìn)行關(guān)聯(lián)。

這里大家重點(diǎn)關(guān)注下 addAssetPath 方法,在Android系統(tǒng)中安裝包路徑和AssetManager的關(guān)聯(lián)是使用AssetManager#addAssetPath(String)

十六、PackageParse#parseSplitApk(Package, int, AssetManager, int)方法解析

代碼在PackageParser.java 913行

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

        mParseError = PackageManager.INSTALL_SUCCEEDED;
        mArchiveSourcePath = apkPath;

        if (DEBUG_JAR) Slog.d(TAG, "Scanning split APK: " + apkPath);
        // 關(guān)聯(lián)AssetManager與路徑
        final int cookie = loadApkIntoAssetManager(assets, apkPath, flags);
        // 獲取資源
        Resources res = null;
        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,
                    Build.VERSION.RESOURCES_SDK_INT);
            // 初始化Xml解析器
            parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);

            final String[] outError = new String[1];
            // 解析"拆分APK"
            pkg = parseSplitApk(pkg, res, parser, flags, splitIndex, outError);
            // 解析失敗
            if (pkg == null) {
                throw new PackageParserException(mParseError,
                        apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]);
            }

        } 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);
        }
    }

這個(gè)方法不復(fù)雜,主要為了調(diào)用parseSplitApk(Package, Resources, XmlResourceParser, int,int, String[])方法而初始化相關(guān)參數(shù)而已。

那我們來看下parseSplitApk(Package, Resources, XmlResourceParser, int,int, String[])方法

十七、PackageParse#parseSplitApk(Package, Resources, XmlResourceParser, int,int, String[])方法解析

代碼在PackageParser.java 957行

    /**
     * Parse the manifest of a <em>split APK</em>.
     * <p>
     * Note that split APKs have many more restrictions on what they're capable
     * of doing, so many valid features of a base APK have been carefully
     * omitted here.
     */
    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
         // 預(yù)解析
        parsePackageSplitNames(parser, attrs);

        mParseInstrumentationArgs = null;
        mParseActivityArgs = null;
        mParseServiceArgs = null;
        mParseProviderArgs = null;

        int type;

        boolean foundApp = false;
        
        // 解析 AndroidManifest里面的<Application> 標(biāo)簽
        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();
             //遇到<application> 標(biāo)簽
            if (tagName.equals("application")) {
                 // 保證只有一個(gè)<application> 標(biāo)簽
                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> 標(biāo)簽
                if (!parseSplitApplication(pkg, res, parser, flags, splitIndex, outError)) {
                    return null;
                }

            } else if (RIGID_PARSER) {
                outError[0] = "Bad element under <manifest>: "
                    + parser.getName();
                mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                return null;

            } else {
                Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName()
                        + " at " + mArchiveSourcePath + " "
                        + parser.getPositionDescription());
                XmlUtils.skipCurrentTag(parser);
                continue;
            }
        }

        if (!foundApp) {
            outError[0] = "<manifest> does not contain an <application>";
            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY;
        }

        return pkg;
    }

有注釋,先來翻譯一下注釋:

解析"拆分APK"的manifest
注意:由于對(duì)"拆分APK"限制比較多,所以像"base APK"的很多功能在"拆分APK"中已經(jīng)省略了。

這個(gè)方法內(nèi)部主要是解析"拆分APK"的AndroidManifest 文件,如果遇到<application> 標(biāo)簽,則調(diào)用parseSplitApplication(Package, Resources, XmlResourceParser, int, int, String[]) 方法進(jìn)行解析

那我們就來看下這個(gè)方法

十八、PackageParse#parseSplitApplication(Package, Resources, XmlResourceParser, int, int, String[]) 方法解析

代碼在PackageParser.java 2854行

    /**
     * Parse the {@code application} XML tree at the current parse location in a
     * <em>split APK</em> manifest.
     * <p>
     * Note that split APKs have many more restrictions on what they're capable
     * of doing, so many valid features of a base APK have been carefully
     * omitted here.
     */
    private boolean parseSplitApplication(Package owner, Resources res, XmlResourceParser parser,
            int flags, int splitIndex, String[] outError)
            throws XmlPullParserException, IOException {
        // 獲取TypedArray對(duì)象
        TypedArray sa = res.obtainAttributes(parser,
                com.android.internal.R.styleable.AndroidManifestApplication);

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

        final int innerDepth = parser.getDepth();
        int type;
       // 開始解析manifest的XML
        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
                continue;
            }
            // 獲取標(biāo)簽名
            String tagName = parser.getName();
            // 如果標(biāo)簽是<activity>
            if (tagName.equals("activity")) {
                // 解析<activity>標(biāo)簽
                Activity a = parseActivity(owner, res, parser, flags, outError, false,
                        owner.baseHardwareAccelerated);
               // 解析失敗
                if (a == null) {
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                }
                // 將解析出來的activity添加到activities中
                owner.activities.add(a);

            } else if (tagName.equals("receiver")) {
                 // 解析<receiver>標(biāo)簽
                Activity a = parseActivity(owner, res, parser, flags, outError, true, false);
                // 解析失敗
                if (a == null) {
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                }
                // 將解析出來的activity添加到activities中
                owner.receivers.add(a);

            } else if (tagName.equals("service")) {
                // 解析<service>標(biāo)簽
                Service s = parseService(owner, res, parser, flags, outError);
                 // 解析失敗
                if (s == null) {
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                }
                // 將解析出來的service添加到services中
                owner.services.add(s);

            } else if (tagName.equals("provider")) {
                // 解析<provider>標(biāo)簽
                Provider p = parseProvider(owner, res, parser, flags, outError);
                // 解析事變
                if (p == null) {
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                }
                // 將解析出來的providers添加到providers中
                owner.providers.add(p);

            } else if (tagName.equals("activity-alias")) {
                // 解析<activity-alias>標(biāo)簽
                Activity a = parseActivityAlias(owner, res, parser, flags, outError);
                 // 解析失敗
                if (a == null) {
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                }
                // 將解析出來的activity添加到activities中
                owner.activities.add(a);

            } 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)
                 // 解析<meta-data>標(biāo)簽
                if ((owner.mAppMetaData = parseMetaData(res, parser, owner.mAppMetaData,
                        outError)) == null) {
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                }

            } else if (tagName.equals("uses-library")) {
                 // 如果標(biāo)簽是<uses-library>
                 // 重新獲取TypedArray對(duì)象sa
                sa = res.obtainAttributes(parser,
                        com.android.internal.R.styleable.AndroidManifestUsesLibrary);

                // Note: don't allow this value to be a reference to a resource
                // that may change.
                // 獲取庫名字
                String lname = sa.getNonResourceString(
                        com.android.internal.R.styleable.AndroidManifestUsesLibrary_name);
                // 是否設(shè)置了required=true
                boolean req = sa.getBoolean(
                        com.android.internal.R.styleable.AndroidManifestUsesLibrary_required,
                        true);
                //  回收 sa
                sa.recycle();

                if (lname != null) {
                    // 獲取字符串常量池的值
                    lname = lname.intern();
                    if (req) {
                        // 如果設(shè)置了required=true
                        // Upgrade to treat as stronger constraint
                        則將這庫添加進(jìn)usesLibraries去
                        owner.usesLibraries = ArrayUtils.add(owner.usesLibraries, lname);
                        owner.usesOptionalLibraries = ArrayUtils.remove(
                                owner.usesOptionalLibraries, lname);
                    } else {
                         // 如果沒有設(shè)置required=true并且則將這庫不在usesLibraries中,則將這個(gè)庫添加到usesOptionalLibraries中
                        // Ignore if someone already defined as required
                        if (!ArrayUtils.contains(owner.usesLibraries, lname)) {
                            owner.usesOptionalLibraries = ArrayUtils.add(
                                    owner.usesOptionalLibraries, lname);
                        }
                    }
                }

                XmlUtils.skipCurrentTag(parser);

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

            } else {
                // RIGID_PARSER為常量一直未false
                if (!RIGID_PARSER) {
                    Slog.w(TAG, "Unknown element under <application>: " + tagName
                            + " at " + mArchiveSourcePath + " "
                            + parser.getPositionDescription());
                    XmlUtils.skipCurrentTag(parser);
                    continue;
                } else {
                    outError[0] = "Bad element under <application>: " + tagName;
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                }
            }
        }

        return true;
    }

有注釋,先來翻譯一下注釋:

解析"拆分APK"的XML樹中的< application >標(biāo)簽節(jié)點(diǎn)。
注意:由于對(duì)"拆分APK"限制比較多,所以像"base APK"的很多功能在"拆分APK"中已經(jīng)省略了。

這個(gè)方法主要就是解析幾個(gè)對(duì)應(yīng)的標(biāo)簽。

十九、PackageParse#parseActivity(Package, Resources,XmlPullParser, AttributeSet, int, String[],boolean, boolean)方法解析

代碼在PackageParser.java 3026行

    private Activity parseActivity(Package owner, Resources res,
            XmlPullParser parser, AttributeSet attrs, int flags, String[] outError,
            boolean receiver, boolean hardwareAccelerated)
            throws XmlPullParserException, IOException {
        // 獲取資源數(shù)組
        TypedArray sa = res.obtainAttributes(attrs, R.styleable.AndroidManifestActivity);
        // 初始化解析Activity參數(shù)
        if (mParseActivityArgs == null) {
            mParseActivityArgs = new ParseComponentArgs(owner, outError,
                    R.styleable.AndroidManifestActivity_name,
                    R.styleable.AndroidManifestActivity_label,
                    R.styleable.AndroidManifestActivity_icon,
                    R.styleable.AndroidManifestActivity_logo,
                    R.styleable.AndroidManifestActivity_banner,
                    mSeparateProcesses,
                    R.styleable.AndroidManifestActivity_process,
                    R.styleable.AndroidManifestActivity_description,
                    R.styleable.AndroidManifestActivity_enabled);
        }
       
         // 判斷標(biāo)簽類型是 receiver還是activity
        mParseActivityArgs.tag = receiver ? "<receiver>" : "<activity>";

        // 初始化mParseActivityArgs的兩個(gè)屬性
        mParseActivityArgs.sa = sa;
        mParseActivityArgs.flags = flags;
       
        // 創(chuàng)建一個(gè)Activity(這里的Activity不是我們平時(shí)說的Activity,而是PackageParse的靜態(tài)內(nèi)部類Activity)
        Activity a = new Activity(mParseActivityArgs, new ActivityInfo());
        if (outError[0] != null) {
            // 沒有出現(xiàn)問題,則回收
            sa.recycle();
            return null;
        }
        // 是否在AndroidManifest中設(shè)置了"android:exported"屬性
        boolean setExported = sa.hasValue(R.styleable.AndroidManifestActivity_exported);
        if (setExported) {
            // 如果設(shè)置了,則進(jìn)行配置
            a.info.exported = sa.getBoolean(R.styleable.AndroidManifestActivity_exported, false);
        }
        // 設(shè)置AndroidManifest里面對(duì)應(yīng)的theme的值
        a.info.theme = sa.getResourceId(R.styleable.AndroidManifestActivity_theme, 0);
        // 設(shè)置AndroidManifest里面對(duì)應(yīng)的uiOptions的值
        a.info.uiOptions = sa.getInt(R.styleable.AndroidManifestActivity_uiOptions,
                a.info.applicationInfo.uiOptions);
        // 獲取AndroidManifest里面"android:parentActivityName=String"的值
        String parentName = sa.getNonConfigurationString(
                R.styleable.AndroidManifestActivity_parentActivityName,
                Configuration.NATIVE_CONFIG_VERSION);
        // 如果設(shè)置了android:parentActivityName
        if (parentName != null) {
            // 構(gòu)建parent的類名
            String parentClassName = buildClassName(a.info.packageName, parentName, outError);
            if (outError[0] == null) {
                a.info.parentActivityName = parentClassName;
            } else {
                Log.e(TAG, "Activity " + a.info.name + " specified invalid parentActivityName " +
                        parentName);
                outError[0] = null;
            }
        }

        // 獲取權(quán)限permission
        String str;
        str = sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_permission, 0);
        if (str == null) {
            a.info.permission = owner.applicationInfo.permission;
        } else {
            a.info.permission = str.length() > 0 ? str.toString().intern() : null;
        }
  
       // 獲取是否有在這個(gè)Activity中配置了taskAffinity(吸附值)這個(gè)屬性
        str = sa.getNonConfigurationString(
                R.styleable.AndroidManifestActivity_taskAffinity,
                Configuration.NATIVE_CONFIG_VERSION);
        // 設(shè)置吸附值
        a.info.taskAffinity = buildTaskAffinityName(owner.applicationInfo.packageName,
                owner.applicationInfo.taskAffinity, str, outError);
      
        // 是否在AndroidManfest里面這個(gè)activity是否配置了"android:multiprocess=boolean" 屬性,如果設(shè)置了true,則該activity支持多進(jìn)程
        a.info.flags = 0;
        if (sa.getBoolean(
                R.styleable.AndroidManifestActivity_multiprocess, false)) {
            a.info.flags |= ActivityInfo.FLAG_MULTIPROCESS;
        }

        // 是否在AndroidManfest里面這個(gè)activity是否配置了"android:finishOnTaskLaunch=boolean" 屬性
        // 該標(biāo)識(shí)用來標(biāo)識(shí)每當(dāng)用戶再次啟動(dòng)其任務(wù)(在主屏幕上選擇任務(wù))時(shí),是否應(yīng)該關(guān)閉現(xiàn)有Activity實(shí)例。
        // "true"表示應(yīng)該關(guān)閉,"false"表示不關(guān)閉。默認(rèn)值為"false"。(sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnTaskLaunch, false)) {
            a.info.flags |= ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH;
        }

        //是否在AndroidManfest里面這個(gè)activity是否配置了"android:clearTaskOnLaunch=boolean" 屬性
        // 這個(gè)標(biāo)識(shí)用來指明當(dāng)前應(yīng)用從主屏幕重新啟動(dòng)時(shí)是否都從中移除根Activity之外的所有Activity。
        //"true"表示始終將任務(wù)清楚到只剩根Activity,"false"表示不清楚,默認(rèn)值為false
        if (sa.getBoolean(R.styleable.AndroidManifestActivity_clearTaskOnLaunch, false)) {
            a.info.flags |= ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH;
        }

        // 是否在AndroidManfest里面這個(gè)activity是否配置了"android:noHistory=boolean" 屬性
        // 該標(biāo)示用來指定 當(dāng)用戶離開Activity,并且其再屏幕上不在可見時(shí),是否應(yīng)從Activity 堆棧中將其移除并完成finish()操作
        // "true"表示應(yīng)該將其finish,"false"表示不應(yīng)該將其finish。默認(rèn)值為false。
        if (sa.getBoolean(R.styleable.AndroidManifestActivity_noHistory, false)) {
            a.info.flags |= ActivityInfo.FLAG_NO_HISTORY;
        }

        // 是否在AndroidManfest里面這個(gè)activity是否配置了"android:alwaysRetainTaskState=boolean" 屬性
       // 這個(gè)標(biāo)示用來指示系統(tǒng)是否始終保持Activity所在的任務(wù)的狀態(tài)。
        // "true" 表示支持,"false"表示允許系統(tǒng)在特定的情況下將任務(wù)重置到初始狀態(tài)。默認(rèn)值是false。
        if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysRetainTaskState, false)) {
            a.info.flags |= ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE;
        }

        // 是否在AndroidManfest里面這個(gè)activity是否配置了"android:stateNotNeeded=boolean" 屬性
        // 該標(biāo)識(shí)用來指明能否在不保存Activity的情況下將其終止并成功重啟
        // "true" 表示可在不考慮其之前狀態(tài)情況下重新啟動(dòng),"false"表示需要之前的狀態(tài),默認(rèn)值"false"。
        if (sa.getBoolean(R.styleable.AndroidManifestActivity_stateNotNeeded, false)) {
            a.info.flags |= ActivityInfo.FLAG_STATE_NOT_NEEDED;
        }

        // 是否在AndroidManifest里面設(shè)置"android:excludeFromRecents=boolean"
         // 該標(biāo)識(shí)用來表示是否應(yīng)該將Activity啟動(dòng)的任務(wù)是否排除在最近使用的應(yīng)用列表之外。
         // "true"表示將任務(wù)排除在列表之外,"false"表示包含在內(nèi)。默認(rèn)值為"false"
        if (sa.getBoolean(R.styleable.AndroidManifestActivity_excludeFromRecents, false)) {
            a.info.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
        }

        // 是否在AndroidManifest里面設(shè)置"android:allowTaskReparenting=boolean"
        // 表明這個(gè)應(yīng)用在reset task時(shí),是不是關(guān)聯(lián)對(duì)應(yīng)的taskAffinity值。true,關(guān)聯(lián);false,不關(guān)聯(lián)
        if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowTaskReparenting,
                (owner.applicationInfo.flags&ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING) != 0)) {
            a.info.flags |= ActivityInfo.FLAG_ALLOW_TASK_REPARENTING;
        }

        // 是否在AndroidManifest里面設(shè)置"android:finishOnCloseSystemDialogs=boolean"
         // 表示 當(dāng)"關(guān)閉系統(tǒng)窗口"請(qǐng)求出現(xiàn)時(shí),是否銷毀Activity,true銷毀,false不銷毀
        if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnCloseSystemDialogs, false)) {
            a.info.flags |= ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
        }

        // 是否在AndroidManifest里面設(shè)置"android:showOnLockScreen=boolean"
         // 指定該Activity是否顯示在解鎖界面,true顯示,false 不顯示
        // 是否在AndroidManifest里面設(shè)置"android:showOnLockScreen=boolean"
         // 指定該Activity是否可以顯示給所有用戶,true可以,false 不可以
        if (sa.getBoolean(R.styleable.AndroidManifestActivity_showOnLockScreen, false)
                || sa.getBoolean(R.styleable.AndroidManifestActivity_showForAllUsers, false)) {
            a.info.flags |= ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
        }

        // 是否在AndroidManifest里面設(shè)置"android:immersive=boolean" 是否設(shè)置沉浸式顯示,true是,false不是
        if (sa.getBoolean(R.styleable.AndroidManifestActivity_immersive, false)) {
            a.info.flags |= ActivityInfo.FLAG_IMMERSIVE;
        }

        // 是否在AndroidManifest里面設(shè)置"android:primaryUserOnly=boolean"
        // 是否設(shè)置視為系統(tǒng)組件,true是,false不是
        if (sa.getBoolean(R.styleable.AndroidManifestActivity_primaryUserOnly, false)) {
            a.info.flags |= ActivityInfo.FLAG_PRIMARY_USER_ONLY;
        }

        // 如果不是receiver標(biāo)簽,同時(shí)是否設(shè)置了硬件加速
        if (!receiver) {
            if (sa.getBoolean(R.styleable.AndroidManifestActivity_hardwareAccelerated,
                    hardwareAccelerated)) {
                a.info.flags |= ActivityInfo.FLAG_HARDWARE_ACCELERATED;
            }

           // 設(shè)置對(duì)應(yīng)的啟動(dòng)模式,對(duì)應(yīng)launchMode
            a.info.launchMode = sa.getInt(
                    R.styleable.AndroidManifestActivity_launchMode, ActivityInfo.LAUNCH_MULTIPLE);

           // 設(shè)置對(duì)應(yīng)的啟動(dòng)模式,對(duì)應(yīng)documentLaunchMode,主要指概覽屏幕(recent app)
            a.info.documentLaunchMode = sa.getInt(
                    R.styleable.AndroidManifestActivity_documentLaunchMode,
                    ActivityInfo.DOCUMENT_LAUNCH_NONE);

            // 概覽屏幕中此Activity的根位置的任務(wù)數(shù)上線
            a.info.maxRecents = sa.getInt(
                    R.styleable.AndroidManifestActivity_maxRecents,
                    ActivityManager.getDefaultAppRecentsLimitStatic());

            // 是否設(shè)置了android:configChanges
            a.info.configChanges = sa.getInt(R.styleable.AndroidManifestActivity_configChanges, 0);
            a.info.softInputMode = sa.getInt(
                    R.styleable.AndroidManifestActivity_windowSoftInputMode, 0);

            a.info.persistableMode = sa.getInteger(
                    R.styleable.AndroidManifestActivity_persistableMode,
                    ActivityInfo.PERSIST_ROOT_ONLY);

            // 是否設(shè)置了android:allowEmbedded=boolean,true表示該Activity可以作為另一個(gè)Activity的的嵌入式子項(xiàng)啟動(dòng)。
             //主要適用于可穿戴設(shè)備。
            if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowEmbedded, false)) {
                a.info.flags |= ActivityInfo.FLAG_ALLOW_EMBEDDED;
            }

            // 是否設(shè)置了android:autoRemoveFromRecents=boolean
            //  表示是否Activity一直保留在概覽屏幕中,直到任務(wù)中的最后一個(gè)Activity finish為止。
            // true,則自動(dòng)從概覽屏幕中移除任務(wù)
            if (sa.getBoolean(R.styleable.AndroidManifestActivity_autoRemoveFromRecents, false)) {
                a.info.flags |= ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS;
            }


            // 是否設(shè)置了android:relinquishTaskIdentity=boolean
            // 是否將其任務(wù)的標(biāo)識(shí)符交給任務(wù)棧中在其之上的Activity。如果任務(wù)根Activity的該屬性設(shè)置"true",
            // 則任務(wù)會(huì)用其內(nèi)的下一個(gè)Activity的Intent替換基本的Intent,直到某個(gè)Activity將其屬性設(shè)置為"false"為止。
            if (sa.getBoolean(R.styleable.AndroidManifestActivity_relinquishTaskIdentity, false)) {
                a.info.flags |= ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
            }

            // 是否設(shè)置了android:resumeWhilePausing=boolean
            // 表示前一個(gè)Activity執(zhí)行onPause的時(shí)候,當(dāng)前是否Activity繼續(xù)顯示
            if (sa.getBoolean(R.styleable.AndroidManifestActivity_resumeWhilePausing, false)) {
                a.info.flags |= ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
            }

            // 是否設(shè)置了android:resizeableActivity=boolean
            // 這個(gè)標(biāo)識(shí)表示 是否支持分屏
            a.info.resizeable = sa.getBoolean(
                    R.styleable.AndroidManifestActivity_resizeableActivity, false);

            if (a.info.resizeable) {
                // Fixed screen orientation isn't supported with resizeable activities.
                a.info.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
            } else {
                a.info.screenOrientation = sa.getInt(
                        R.styleable.AndroidManifestActivity_screenOrientation,
                        ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
            }

             // 獲取對(duì)應(yīng)的鎖屏模式
            a.info.lockTaskLaunchMode =
                    sa.getInt(R.styleable.AndroidManifestActivity_lockTaskMode, 0);
        } else {
            // 如果是receiver標(biāo)簽
            // 設(shè)置啟動(dòng)模式 
            a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
            a.info.configChanges = 0;

            if (sa.getBoolean(R.styleable.AndroidManifestActivity_singleUser, false)) {
                a.info.flags |= ActivityInfo.FLAG_SINGLE_USER;
                if (a.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) {
                    Slog.w(TAG, "Activity exported request ignored due to singleUser: "
                            + a.className + " at " + mArchiveSourcePath + " "
                            + parser.getPositionDescription());
                    a.info.exported = false;
                    setExported = true;
                }
            }
        }

        sa.recycle();
         // 判斷是否是重量級(jí)的APP。如果是重量級(jí)的APP,則不應(yīng)該有receiver
        if (receiver && (owner.applicationInfo.privateFlags
                &ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
            // A heavy-weight application can not have receives in its main process
            // We can do direct compare because we intern all strings.
            if (a.info.processName == owner.packageName) {
                outError[0] = "Heavy-weight applications can not have receivers in main process";
            }
        }

        if (outError[0] != null) {
            return null;
        }

        int outerDepth = parser.getDepth();
        int type;
        // 開始解析<activity></activity>的內(nèi)部標(biāo)簽
        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
               && (type != XmlPullParser.END_TAG
                       || parser.getDepth() > outerDepth)) {
            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
                continue;
            }

             //如果解析到<ntent-filter>標(biāo)簽
            if (parser.getName().equals("intent-filter")) {
                ActivityIntentInfo intent = new ActivityIntentInfo(a);
                 // 解析<ntent-filter>標(biāo)簽
                if (!parseIntent(res, parser, attrs, true, true, intent, outError)) {
                    return null;
                }
                if (intent.countActions() == 0) {
                    Slog.w(TAG, "No actions in intent filter at "
                            + mArchiveSourcePath + " "
                            + parser.getPositionDescription());
                } else {
                   // 添加進(jìn)去
                    a.intents.add(intent);
                }
            } else if (!receiver && parser.getName().equals("preferred")) {
                // 如果是<activity>,且遇到<preferred> 標(biāo)簽
                ActivityIntentInfo intent = new ActivityIntentInfo(a);
                 // 解析<preferred> 標(biāo)簽
                if (!parseIntent(res, parser, attrs, false, false, intent, outError)) {
                    return null;
                }
                if (intent.countActions() == 0) {
                    Slog.w(TAG, "No actions in preferred at "
                            + mArchiveSourcePath + " "
                            + parser.getPositionDescription());
                } else {
                    if (owner.preferredActivityFilters == null) {
                        owner.preferredActivityFilters = new ArrayList<ActivityIntentInfo>();
                    }
                    // 添加
                    owner.preferredActivityFilters.add(intent);
                }
            } else if (parser.getName().equals("meta-data")) {
                //遇到<meta-data> 標(biāo)簽
                // 解析<meta-data> 標(biāo)簽
                if ((a.metaData=parseMetaData(res, parser, attrs, a.metaData,
                        outError)) == null) {
                    return null;
                }
            } else {
                 // 如果遇到其他的 莫名其妙的標(biāo)簽
                if (!RIGID_PARSER) {
                    Slog.w(TAG, "Problem in package " + mArchiveSourcePath + ":");
                    if (receiver) {
                        Slog.w(TAG, "Unknown element under <receiver>: " + parser.getName()
                                + " at " + mArchiveSourcePath + " "
                                + parser.getPositionDescription());
                    } else {
                        Slog.w(TAG, "Unknown element under <activity>: " + parser.getName()
                                + " at " + mArchiveSourcePath + " "
                                + parser.getPositionDescription());
                    }
                    XmlUtils.skipCurrentTag(parser);
                    continue;
                } else {
                    if (receiver) {
                        outError[0] = "Bad element under <receiver>: " + parser.getName();
                    } else {
                        outError[0] = "Bad element under <activity>: " + parser.getName();
                    }
                    return null;
                }
            }
        }
        if (!setExported) {
            a.info.exported = a.intents.size() > 0;
        }
        return a;
    }

這個(gè)方法主要是解析AndroidManifest.xml里面的<activity>標(biāo)簽的內(nèi)容,并將其映射到PackageParse.Activity對(duì)象

image.png

掃描Package的第一部分工作,難度不大,但極其的繁瑣,跟著流程走一邊真是想死的心都有了。不過正如Torvalds大神所說的,”RTFSC, read the fucking source code”,耐著性子多看看,是提高的基礎(chǔ)條件。

上圖畫出了PackageParser解析Apk文件,得到的主要的數(shù)據(jù)結(jié)構(gòu),實(shí)際的內(nèi)容遠(yuǎn)多于這些,我們僅保留了四大組件和權(quán)限相關(guān)的內(nèi)容。

上面這些類,全部是定義于PackageParser中的內(nèi)部類,這些內(nèi)部類主要的作用就是保存AndroidManifest.xml解析出的對(duì)應(yīng)信息。
以PackageParser.Activity為例,注意到該類持有ActivityInfo類,繼承自Component< ActivityIntentInfo>。其中,ActivityInfo用于保存Activity的信息;Component類是一個(gè)模板,對(duì)應(yīng)元素類型是ActivityIntentInfo,頂層基類為IntentFilter。四大組件中的其它成員,也有類似的繼承結(jié)構(gòu)。

這種設(shè)計(jì)的原因是:Package除了保存信息外,還需要支持Intent匹配查詢。例如,當(dāng)收到某個(gè)Intent后,由于ActivityIntentInfo繼承自IntentFilter,因此它能判斷自己是否滿足Intent的要求。如果滿足,則返回對(duì)應(yīng)的ActivityInfo。

二十、總結(jié)

最后,我們結(jié)合上圖回憶一下整個(gè)掃描過程:

  • PackageParser首先解析出了ApkLite,得到每個(gè)Apk文件的簡化信息(對(duì)于具有多個(gè)Apk文件的Package來說,將得到多個(gè)ApkLite);
  • 利用所有的ApkLite及XML中的其它信息,解析出PackageLite;
  • 利用PackageLite中的信息及XML中的其它信息,解析出Package信息;Package中就基本上涵蓋了AndroidManifest.xml中涉及的所有信息。

注意在上述的解析過程中,PackageParser利用AssetManager存儲(chǔ)了Package中資源文件的地址。

上一篇文章 APK安裝流程詳解9——PackageParser解析APK(上)
下一篇文章 APK安裝流程詳解11——普通應(yīng)用安裝簡介

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容