App安裝過(guò)程

這個(gè)系列會(huì)分成《App的安裝過(guò)程》《App桌面圖標(biāo)顯示過(guò)程》《Activity的啟動(dòng)過(guò)程》《Activity渲染過(guò)程》四篇文章扛拨,來(lái)分析從整個(gè)應(yīng)用安裝耘分,到用戶點(diǎn)擊圖標(biāo)并顯示首頁(yè)举塔,整個(gè)源碼流程是如何調(diào)用的绑警。

我們應(yīng)用程序包的安裝需要通過(guò)PackageManagerService來(lái)操作,而它早在系統(tǒng)啟動(dòng)SystemServer時(shí)便注冊(cè)好了央渣,SystemServer則由init進(jìn)程啟動(dòng)计盒。

  public static void main(String[] args) {
        new SystemServer().run();//執(zhí)行run
    }

 //運(yùn)行
  private void run() {
    ......
    //創(chuàng)建系統(tǒng)上下文
    createSystemContext();

  //創(chuàng)建SystemServiceManager,用來(lái)管理各種系統(tǒng)service
   mSystemServiceManager = new SystemServiceManager(mSystemContext);
   LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);

  // 啟動(dòng)服務(wù)
        try {
            //啟動(dòng)服務(wù)芽丹,創(chuàng)建PMS北启,AMS等
            startBootstrapServices();
            // 啟動(dòng)核心服務(wù)
            startCoreServices();
            //啟動(dòng)IputManagerService等
            startOtherServices();
        } catch (Throwable ex) {
            Slog.e("System", "******************************************");
            Slog.e("System", "************ Failure starting system services", ex);
            throw ex;
        }

   }


  //創(chuàng)建系統(tǒng)上下文
  private void createSystemContext() {
        ActivityThread activityThread = ActivityThread.systemMain();
        mSystemContext = activityThread.getSystemContext();
        mSystemContext.setTheme(android.R.style.Theme_DeviceDefault_Light_DarkActionBar);
   }

初始化系統(tǒng)上下文時(shí),生成了ActivityThread 拔第,它相當(dāng)于系統(tǒng)的主線程咕村,我們看systemMain方法。

public static ActivityThread systemMain() {
        if (!ActivityManager.isHighEndGfx()) {
            HardwareRenderer.disable(true);
        } else {
            HardwareRenderer.enableForegroundTrimming();
        }
        //構(gòu)造ActivityThread
        ActivityThread thread = new ActivityThread();
        //true表示系統(tǒng)應(yīng)用
        thread.attach(true);
        return thread;
}

 private void attach(boolean system) {
     sCurrentActivityThread = this;
        mSystemThread = system;
        //不是系統(tǒng)進(jìn)程
        if (!system) {
            ......
        } else {
            android.ddm.DdmHandleAppName.setAppName("system_process",UserHandle.myUserId());
            try {
                //創(chuàng)建Instrumentation
                mInstrumentation = new Instrumentation();
                //創(chuàng)建上下文
                ContextImpl context = ContextImpl.createAppContext(this, getSystemContext().mPackageInfo);
                //創(chuàng)建Application
                mInitialApplication = context.mPackageInfo.makeApplication(true, null);
                mInitialApplication.onCreate();
            } catch (Exception e) {
                throw new RuntimeException(
                        "Unable to instantiate Application():" + e.toString(), e);
            }
        }

當(dāng)調(diào)用為系統(tǒng)線程時(shí)蚊俺,attach會(huì)執(zhí)行else代碼懈涛,創(chuàng)建Instrumentation和上下文,我們接著看啟動(dòng)包管理器服務(wù)的方法startBootstrapServices泳猬。

  private void startBootstrapServices() {
       //該對(duì)象負(fù)責(zé)與底層通信批钠,進(jìn)行具體安裝卸載等操作
        mInstaller = mSystemServiceManager.startService(Installer.class);

        //開(kāi)啟ActivityManagerService,對(duì)比PowerManagerService等得封,實(shí)際上ActivityManagerService不是一個(gè)SystemService埋心,而是Binder,ActivityManagerService.Lifecycle才是SystemService
        mActivityManagerService = mSystemServiceManager.startService(ActivityManagerService.Lifecycle.class).getService();
        mActivityManagerService.setSystemServiceManager(mSystemServiceManager);

        mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);

        mActivityManagerService.initPowerManagement();

       //開(kāi)啟mDisplayManagerService
        mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);
      
        mSystemServiceManager.startBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);

        String cryptState = SystemProperties.get("vold.decrypt");
        if (ENCRYPTING_STATE.equals(cryptState)) {
            Slog.w(TAG, "Detected encryption in progress - only parsing core apps");
            mOnlyCore = true;
        } else if (ENCRYPTED_STATE.equals(cryptState)) {
            Slog.w(TAG, "Device encrypted - only parsing core apps");
            mOnlyCore = true;
        }

        //構(gòu)建PackageManagerService
        mPackageManagerService = PackageManagerService.main(mSystemContext, mInstaller,
                mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);

        mFirstBoot = mPackageManagerService.isFirstBoot();
        mPackageManager = mSystemContext.getPackageManager();
       
        ServiceManager.addService(Context.USER_SERVICE, UserManagerService.getInstance());
       
        AttributeCache.init(mSystemContext);

        mActivityManagerService.setSystemProcess();

    }

SystemServer啟動(dòng)了許多服務(wù)忙上,PackageManagerService通過(guò)main方法創(chuàng)建拷呆,并將系統(tǒng)上下文和mInstaller工具類(lèi)傳遞進(jìn)去。

    public static final PackageManagerService main(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) {
        //構(gòu)造PMS對(duì)象
        PackageManagerService m = new PackageManagerService(context, installer,factoryTest, onlyCore);
        //注冊(cè)到ServiceManager中
        ServiceManager.addService("package", m);
        return m;
    }

構(gòu)造PMS對(duì)象晨横,并將服務(wù)對(duì)象添加到ServiceManager中洋腮。PackageManagerService的構(gòu)造方法代碼比較多田弥,我們分塊分析趾徽。

    //pms啟動(dòng)后對(duì)系統(tǒng)中的特定目錄進(jìn)行掃描,獲取信息以便進(jìn)行應(yīng)用程序安裝
    public PackageManagerService(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) {
        //向事件日志寫(xiě)入事件奶段,標(biāo)識(shí)PackageManagerService啟動(dòng)時(shí)間
        EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,SystemClock.uptimeMillis());
        //版本檢查
        if (mSdkVersion <= 0) {
            Slog.w(TAG, "**** ro.build.version.sdk not set!");
        }

        mContext = context;
        //開(kāi)機(jī)是否工廠模式
        mFactoryTest = factoryTest;
        //是否啟動(dòng)內(nèi)核
        mOnlyCore = onlyCore;
        //如果編譯版本為eng库糠,則不要進(jìn)行dex優(yōu)化
        mLazyDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
        //構(gòu)造DisplayMetrics以便獲得尺寸數(shù)據(jù)
        mMetrics = new DisplayMetrics();
        //構(gòu)造Settings存儲(chǔ)系統(tǒng)安裝時(shí)的信息
        mSettings = new Settings(context);

        //添加一些用戶id
        mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
                ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
                ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.log", LOG_UID,
                ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,
                ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,
                ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,
                ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);

        //是否在不同的進(jìn)程中
        String separateProcesses = SystemProperties.get("debug.separate_processes");
        if (separateProcesses != null && separateProcesses.length() > 0) {
            if ("*".equals(separateProcesses)) {
                mDefParseFlags = PackageParser.PARSE_IGNORE_PROCESSES;
                mSeparateProcesses = null;
                Slog.w(TAG, "Running with debug.separate_processes: * (ALL)");
            } else {
                mDefParseFlags = 0;
                mSeparateProcesses = separateProcesses.split(",");
                Slog.w(TAG, "Running with debug.separate_processes: "
                        + separateProcesses);
            }
        } else {
            mDefParseFlags = 0;
            mSeparateProcesses = null;
        }

當(dāng)一個(gè)新應(yīng)用程序伙狐,要安裝并運(yùn)行在Linux中時(shí),系統(tǒng)需要先為其開(kāi)辟一個(gè)用戶空間瞬欧,并分配Linux獨(dú)立用戶id或共享用戶id贷屎,而這個(gè)創(chuàng)建和分配的業(yè)務(wù)操作,由PackageMangerService來(lái)完成艘虎。

每當(dāng)系統(tǒng)重啟時(shí)唉侄,都需要對(duì)程序做一次重新安裝,為了提高效率野建,程序在第一次安裝時(shí)属划,PackageMangerService會(huì)將安裝信息進(jìn)行保存恬叹,以便再次安裝時(shí)進(jìn)行快速恢復(fù)。Settings就是用來(lái)保存這些信息的對(duì)象同眯。

        //賦值mInstaller 
        mInstaller = installer;

        //測(cè)量顯示對(duì)象
        getDefaultDisplayMetrics(context, mMetrics);

        SystemConfig systemConfig = SystemConfig.getInstance();
        mGlobalGids = systemConfig.getGlobalGids();
        mSystemPermissions = systemConfig.getSystemPermissions();
        mAvailableFeatures = systemConfig.getAvailableFeatures();

        synchronized (mInstallLock) {
        // writer
        synchronized (mPackages) {
            //啟動(dòng)處理線程
            mHandlerThread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
            mHandlerThread.start();
            //啟動(dòng)PackageHandler
            mHandler = new PackageHandler(mHandlerThread.getLooper());
            Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);

            //獲取data目錄
            File dataDir = Environment.getDataDirectory();
            //獲取到/data/data目錄
            mAppDataDir = new File(dataDir, "data");
            //獲取到/data/app目錄绽昼,即第三方應(yīng)用的安裝目錄
            mAppInstallDir = new File(dataDir, "app");
            //獲取到/data/app-lib目錄
            mAppLib32InstallDir = new File(dataDir, "app-lib");
            //獲取到/data/app-asec目錄
            mAsecInternalPath = new File(dataDir, "app-asec").getPath();
            //獲取到/data/user目錄
            mUserAppDataDir = new File(dataDir, "user");
            //獲取到/data/app-private目錄,受DRM保護(hù)
            mDrmAppPrivateInstallDir = new File(dataDir, "app-private");

            //構(gòu)造UserManagerService,mPackages是一個(gè)Map须蜗,存儲(chǔ)了Package
            sUserManager = new UserManagerService(context, this,mInstallLock, mPackages);
  
            //讀取設(shè)置的權(quán)限
            ArrayMap<String, SystemConfig.PermissionEntry> permConfig= systemConfig.getPermissions();
            for (int i=0; i<permConfig.size(); i++) {
                SystemConfig.PermissionEntry perm = permConfig.valueAt(i);
                BasePermission bp = mSettings.mPermissions.get(perm.name);
                if (bp == null) {
                    bp = new BasePermission(perm.name, "android", BasePermission.TYPE_BUILTIN);
                    mSettings.mPermissions.put(perm.name, bp);
                }
                if (perm.gids != null) {
                    bp.gids = appendInts(bp.gids, perm.gids);
                }
            }

            ArrayMap<String, String> libConfig = systemConfig.getSharedLibraries();
            for (int i=0; i<libConfig.size(); i++) {
                mSharedLibraries.put(libConfig.keyAt(i),
                        new SharedLibraryEntry(libConfig.valueAt(i), null));
            }

            //讀取并解析mac_permissions.xml
            mFoundPolicyFile = SELinuxMMAC.readInstallPolicy();

            //讀取到程序上一次的安裝信息
            mRestoredSettings = mSettings.readLPw(this, sUserManager.getUsers(false),
                    mSdkVersion, mOnlyCore);

首先掃描了各類(lèi)型的安裝目錄硅确,以備后面程序的安裝,我們看到構(gòu)造UserManagerService對(duì)象時(shí)明肮,傳入了mPackages對(duì)象菱农,它是一個(gè)Map,保存了安裝應(yīng)用的信息柿估,在readLPw傳給mSettings進(jìn)行讀取恢復(fù)大莫,如果讀取解析失敗,則重新解析安裝并保存以便下一次啟動(dòng)恢復(fù)官份,readLPw讀取只厘,而后面的mSettings.writeLPr則是保存。

那么我們看readLPw是如何來(lái)解析安裝包數(shù)據(jù)的舅巷。先看mSettings的構(gòu)造方法羔味。

    Settings(Context context) {
        //dada/data
        this(context, Environment.getDataDirectory());
    }

    Settings(Context context, File dataDir) {
        mSystemDir = new File(dataDir, "system");
        mSystemDir.mkdirs();
        FileUtils.setPermissions(mSystemDir.toString(),
                FileUtils.S_IRWXU|FileUtils.S_IRWXG
                |FileUtils.S_IROTH|FileUtils.S_IXOTH,
                -1, -1);
        //packages.xml保存了上一次的應(yīng)用安裝信息
        mSettingsFilename = new File(mSystemDir, "packages.xml");
        //對(duì)mSettingsFilename的備份
        mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");
        //存儲(chǔ)包名
        mPackageListFilename = new File(mSystemDir, "packages.list");
        FileUtils.setPermissions(mPackageListFilename, 0660, SYSTEM_UID, PACKAGE_INFO_GID);
        
        mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");
        mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");
    }

安裝包的信息數(shù)據(jù)是通過(guò)xml來(lái)進(jìn)行存儲(chǔ)的,由代碼知道钠右,源文件和備份文件完整的相對(duì)路徑為dada/dada/system/xxx.xml赋元。這里對(duì)緩存又進(jìn)行了一次備份,是起到了雙次檢測(cè)的效果飒房。

  //讀取上一次保存的應(yīng)用安裝信息
  boolean readLPw(PackageManagerService service, List<UserInfo> users, int sdkVersion, boolean onlyCore) {
        FileInputStream str = null;
        //備份文件存在搁凸,即packages-backup.xml文件
        if (mBackupSettingsFilename.exists()) {
            try {
                str = new FileInputStream(mBackupSettingsFilename);//讀取備份文件
                mReadMessages.append("Reading from backup settings file\n");
                PackageManagerService.reportSettingsProblem(Log.INFO, "Need to read from backup settings file");
                //清除源文件,即packages.xml文件
                if (mSettingsFilename.exists()) {                    
                    mSettingsFilename.delete();
                }
            } catch (java.io.IOException e) {
                // We'll try for the normal settings file.
            }
        }
        mPendingPackages.clear();
        mPastSignatures.clear();
        try {
            //備份文件不存在
            if (str == null) {
                //源文件不存在
                if (!mSettingsFilename.exists()) {
                    mReadMessages.append("No settings file found\n");
                    PackageManagerService.reportSettingsProblem(Log.INFO, "No settings file; creating initial state");
                    mInternalSdkPlatform = mExternalSdkPlatform = sdkVersion;
                    mFingerprint = Build.FINGERPRINT;
                    return false;
                }
                str = new FileInputStream(mSettingsFilename);//讀取源文件存在
            }
            XmlPullParser parser = Xml.newPullParser();//開(kāi)始pull解析
            parser.setInput(str, null);

      

對(duì)緩存文件的檢測(cè)可以分為3種情況:

  • 如果備份存在狠毯,源文件也存在护糖,則讀取備份文件并且刪除源文件,后面writeLPr會(huì)重新保存一份新的源文件嚼松;
  • 如果備份不存在嫡良,源文件不存在,則恢復(fù)上一次失敗献酗,結(jié)束事件寝受;
  • 如果備份不存在,源文件存在罕偎,則讀取源文件很澄;

文件讀取成功,會(huì)構(gòu)造XmlPullParser 對(duì)象來(lái)解析xml文件。xml保存了上一次安裝的許多數(shù)據(jù)甩苛,這里貼些關(guān)鍵的標(biāo)簽忙干,其中package和shared-user標(biāo)簽,保存了應(yīng)用程序和LInux用戶Id相關(guān)的信息浪藻。

            int type;
            while ((type = parser.next()) != XmlPullParser.START_TAG
                    && type != XmlPullParser.END_DOCUMENT) {
                ;
            }
            //開(kāi)始標(biāo)簽
            if (type != XmlPullParser.START_TAG) {
                mReadMessages.append("No start tag found in settings file\n");
                PackageManagerService.reportSettingsProblem(Log.WARN,
                        "No start tag found in package manager settings");
                Slog.wtf(PackageManagerService.TAG,
                        "No start tag found in package manager settings");
                return false;
            }
            //開(kāi)始解析
            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();
                //以包名為根標(biāo)簽,保存了每個(gè)應(yīng)用上次安裝的信息
                if (tagName.equals("package")) {
                    //讀取包信息乾翔,獲取上一次分配的Linux用戶id
                    readPackageLPw(parser);
                } else if (tagName.equals("permissions")) {
                    readPermissionsLPw(mPermissions, parser);
                } else if (tagName.equals("permission-trees")) {
                    readPermissionsLPw(mPermissionTrees, parser);
                    //shared-user上一次分配的共享linux用戶
                } else if (tagName.equals("shared-user")) {
                    //獲取上一次分配的共享Linux用戶id
                    readSharedUserLPw(parser);
                } else if (tagName.equals("preferred-packages")) {
                    // no longer used.
                } else if (tagName.equals("preferred-activities")) {

xml以package為根標(biāo)簽保存了一個(gè)應(yīng)用的完整信息爱葵,所以,readPackageLPw從package標(biāo)簽開(kāi)始解析包數(shù)據(jù)反浓。

   //解析package標(biāo)簽
    private void readPackageLPw(XmlPullParser parser) throws XmlPullParserException, IOException {
        String name = null;
        String realName = null;
        String idStr = null;
        String sharedIdStr = null;
        String codePathStr = null;
        String resourcePathStr = null;
        String legacyCpuAbiString = null;
        String legacyNativeLibraryPathStr = null;
        String primaryCpuAbiString = null;
        String secondaryCpuAbiString = null;
        String cpuAbiOverrideString = null;
        String systemStr = null;
        String installerPackageName = null;
        String uidError = null;
        int pkgFlags = 0;
        long timeStamp = 0;
        long firstInstallTime = 0;
        long lastUpdateTime = 0;
        PackageSettingBase packageSetting = null;
        String version = null;
        int versionCode = 0;
        try {
            name = parser.getAttributeValue(null, ATTR_NAME);//ATTR_NAME為name萌丈,應(yīng)用包名
            realName = parser.getAttributeValue(null, "realName");
            idStr = parser.getAttributeValue(null, "userId");//獨(dú)立Linux用戶Id
            uidError = parser.getAttributeValue(null, "uidError");
            sharedIdStr = parser.getAttributeValue(null, "sharedUserId");//共享Linux用戶Id
            codePathStr = parser.getAttributeValue(null, "codePath");
            resourcePathStr = parser.getAttributeValue(null, "resourcePath");

              ......

            if (name == null) { //名字為空,拋出異常雷则,說(shuō)明包名必須有
                PackageManagerService.reportSettingsProblem(Log.WARN,  "Error in package manager settings: <package> has no name at "
                                + parser.getPositionDescription());
            } else if (codePathStr == null) {
                PackageManagerService.reportSettingsProblem(Log.WARN, "Error in package manager settings: <package> has no codePath at "
                                + parser.getPositionDescription());
            } else if (userId > 0) {//說(shuō)明上一次分配了一個(gè)獨(dú)立的Linux用戶Id
                //則將上一次分配的Linux用戶Id保存下來(lái)
                packageSetting = addPackageLPw(name.intern(), realName, new File(codePathStr),
                        new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiString,
                        secondaryCpuAbiString, cpuAbiOverrideString, userId, versionCode, pkgFlags);
                if (PackageManagerService.DEBUG_SETTINGS)
                    Log.i(PackageManagerService.TAG, "Reading package " + name + ": userId="  + userId + " pkg=" + packageSetting);
                if (packageSetting == null) {
                    PackageManagerService.reportSettingsProblem(Log.ERROR, "Failure adding uid "
                            + userId + " while parsing settings at "
                            + parser.getPositionDescription());
                } else {
                    packageSetting.setTimeStamp(timeStamp);
                    packageSetting.firstInstallTime = firstInstallTime;
                    packageSetting.lastUpdateTime = lastUpdateTime;
                }
            } else if (sharedIdStr != null) {//說(shuō)明上一次沒(méi)有分配獨(dú)立的Linux用戶Id辆雾,而是和其他程序共享一個(gè)Linux用戶Id
                userId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0;
                if (userId > 0) {
                    //PendingPackage描述一個(gè)還未確定的應(yīng)用程序
                    packageSetting = new PendingPackage(name.intern(), realName, new File(
                            codePathStr), new File(resourcePathStr), legacyNativeLibraryPathStr,
                            primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString,
                            userId, versionCode, pkgFlags);
                    packageSetting.setTimeStamp(timeStamp);
                    packageSetting.firstInstallTime = firstInstallTime;
                    packageSetting.lastUpdateTime = lastUpdateTime;
                    //將這個(gè)描述對(duì)象保存在mPendingPackages中
                    mPendingPackages.add((PendingPackage) packageSetting);
                    if (PackageManagerService.DEBUG_SETTINGS)
                        Log.i(PackageManagerService.TAG, "Reading package " + name
                                + ": sharedUserId=" + userId + " pkg=" + packageSetting);
                } else {
                    PackageManagerService.reportSettingsProblem(Log.WARN,
                            "Error in package manager settings: package " + name
                                    + " has bad sharedId " + sharedIdStr + " at "
                                    + parser.getPositionDescription());
                }
            } else {
                PackageManagerService.reportSettingsProblem(Log.WARN,
                        "Error in package manager settings: package " + name + " has bad userId "
                                + idStr + " at " + parser.getPositionDescription());
            }
        } catch (NumberFormatException e) {
            PackageManagerService.reportSettingsProblem(Log.WARN,
                    "Error in package manager settings: package " + name + " has bad userId "
                            + idStr + " at " + parser.getPositionDescription());
        }

Linux用戶id分為共享和獨(dú)立,如果此應(yīng)用userId > 0月劈,說(shuō)明上一次分配了一個(gè)獨(dú)立的Linux用戶id度迂,則會(huì)調(diào)用addPackageLPw將獨(dú)立id保存下來(lái),如果不是獨(dú)立的猜揪,而sharedIdStr !=null惭墓,則說(shuō)明是分配的是共享id,則暫時(shí)不保留這個(gè)id而姐,因?yàn)檫@可能是一個(gè)無(wú)效的id腊凶,mPendingPackages會(huì)將此類(lèi)應(yīng)用保存起來(lái),表示還未確定的應(yīng)用拴念。要等到解析完所有安裝信息后才能確定钧萍。

接著看addPackageLPw是如何將Linux用戶id保存下來(lái)的。

  PackageSetting addPackageLPw(String name, String realName, File codePath, File resourcePath,
            String legacyNativeLibraryPathString, String primaryCpuAbiString, String secondaryCpuAbiString,
            String cpuAbiOverrideString, int uid, int vc, int pkgFlags) {

       //緩存Map中獲取PackageSetting
        PackageSetting p = mPackages.get(name);
        //存在這個(gè)包名的應(yīng)用PackageSetting
        if (p != null) {
            //Linux用戶id和appid相同政鼠,說(shuō)明已分配過(guò)风瘦,直接返回PackageSetting
            if (p.appId == uid) {
                return p;
            }
            PackageManagerService.reportSettingsProblem(Log.ERROR, "Adding duplicate package, keeping first: " + name);
            return null;
        }
        //不存在說(shuō)明是第一次安裝,新建一個(gè)PackageSetting對(duì)象
        p = new PackageSetting(name, realName, codePath, resourcePath,
                legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString,
                cpuAbiOverrideString, vc, pkgFlags);
        //將Linux用戶id賦值給appid
        p.appId = uid;
        //保存此用戶id公般,如果保留成功弛秋,則將PackageSetting存到mPackages中
        if (addUserIdLPw(uid, p, name)) {
            mPackages.put(name, p);
            return p;
        }
        return null;
    }

每個(gè)應(yīng)用程序的安裝信息都是用PackageSetting對(duì)象來(lái)存儲(chǔ),并以包名為key俐载,保存在mPackages這個(gè)HashMap中蟹略,如果程序已安裝過(guò),直接從mPackages獲取遏佣。如果第一次安裝挖炬,將構(gòu)建一個(gè)PackageSetting對(duì)象來(lái)保存信息。

addUserIdLPw方法用于在系統(tǒng)中保留分配的uid状婶,如果保留成功意敛,則將PackageSetting保存到mPackages中馅巷,說(shuō)明PMS已經(jīng)為此應(yīng)用分配了Linux用戶id了。

//保存Linux用戶id
    private boolean addUserIdLPw(int uid, Object obj, Object name) {
        //Process.LAST_APPLICATION_UID是19999
        if (uid > Process.LAST_APPLICATION_UID) {
            return false;
        }
        //LAST_APPLICATION_UID是10000
        if (uid >= Process.FIRST_APPLICATION_UID) {
            int N = mUserIds.size();//mUserIds為用戶id列表
            final int index = uid - Process.FIRST_APPLICATION_UID;//當(dāng)前申請(qǐng)的角標(biāo)
            while (index >= N) {//是否超過(guò)列表的角標(biāo)
                mUserIds.add(null);//將中間的置為null
                N++;
            }
            //這個(gè)id被用了草姻,保留失敗
            if (mUserIds.get(index) != null) {
                PackageManagerService.reportSettingsProblem(Log.ERROR,
                        "Adding duplicate user id: " + uid
                        + " name=" + name);
                return false;
            }
            //以pid為角標(biāo)钓猬,添加應(yīng)用程序的PackageSetting
            mUserIds.set(index, obj);
        } else {
          //10000以下給特權(quán)用戶使用
            if (mOtherUserIds.get(uid) != null) {
                PackageManagerService.reportSettingsProblem(Log.ERROR,
                        "Adding duplicate shared id: " + uid
                        + " name=" + name);
                return false;
            }
            mOtherUserIds.put(uid, obj);
        }
        return true;
    }

用戶類(lèi)型的pid都在10000到19999之間,說(shuō)明Android系統(tǒng)只分配9999個(gè)給用戶類(lèi)型的程序撩独,小于10000保留給特權(quán)用戶使用敞曹,但這些id也可以通過(guò)共享的方式給用戶程序使用。獨(dú)立用戶的流程分配完成综膀,我們回到xml解析澳迫,看標(biāo)簽為shared-user的共享用戶,它緊接著調(diào)用了Settings的readSharedUserLPw方法剧劝。

//獲取上一次分配的共享Linux用戶id
    private void readSharedUserLPw(XmlPullParser parser) throws XmlPullParserException,IOException {
        String name = null;
        String idStr = null;
        int pkgFlags = 0;
        SharedUserSetting su = null;
        try {
            name = parser.getAttributeValue(null, ATTR_NAME);//共享用戶名
            idStr = parser.getAttributeValue(null, "userId");//用戶id
            int userId = idStr != null ? Integer.parseInt(idStr) : 0;
            if ("true".equals(parser.getAttributeValue(null, "system"))) {//是給系統(tǒng)類(lèi)型的應(yīng)用還是用戶類(lèi)型的應(yīng)用
                pkgFlags |= ApplicationInfo.FLAG_SYSTEM;//系統(tǒng)用戶為1
            }
            //name,userId必須存在
            if (name == null) {
                PackageManagerService.reportSettingsProblem(Log.WARN,
                        "Error in package manager settings: <shared-user> has no name at "
                                + parser.getPositionDescription());
            } else if (userId == 0) {
                PackageManagerService.reportSettingsProblem(Log.WARN,
                        "Error in package manager settings: shared-user " + name
                                + " has bad userId " + idStr + " at "
                                + parser.getPositionDescription());
            } else {
                //保存這個(gè)共享用戶的id
                if ((su = addSharedUserLPw(name.intern(), userId, pkgFlags)) == null) {
                    PackageManagerService
                            .reportSettingsProblem(Log.ERROR, "Occurred while parsing settings at "
                                    + parser.getPositionDescription());
                }
            }
        } catch (NumberFormatException e) {
            PackageManagerService.reportSettingsProblem(Log.WARN,
                    "Error in package manager settings: package " + name + " has bad userId "
                            + idStr + " at " + parser.getPositionDescription());
        }
        ;

        ......
    }

這里有三個(gè)元素橄登,name、userId和system讥此,前兩個(gè)是共享Linux用戶的名稱(chēng)和id拢锹,最后一個(gè)則用于描述此程序是系統(tǒng)類(lèi)型,還是用戶類(lèi)型的萄喳。
和獨(dú)立用戶流程相似面褐,共享用戶是通過(guò)addSharedUserLPw方法,保存userId為L(zhǎng)inux用戶id的取胎。

 //保存共享用戶的id
    SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags) {
        //SharedUserSetting即一個(gè)共享用戶對(duì)象
        SharedUserSetting s = mSharedUsers.get(name);
        if (s != null) {
            if (s.userId == uid) {
                return s;
            }
            PackageManagerService.reportSettingsProblem(Log.ERROR,
                    "Adding duplicate shared user, keeping first: " + name);
            return null;
        }
        s = new SharedUserSetting(name, pkgFlags);
        s.userId = uid;
        //保存共享用戶的id
        if (addUserIdLPw(uid, s, name)) {
            mSharedUsers.put(name, s);//保存起來(lái)
            return s;
        }
        return null;
    }

獨(dú)立用戶使用PackageSetting對(duì)象來(lái)描述應(yīng)用的安裝信息展哭,而共享用戶則使用SharedUserSetting ,分配和安裝成功的用戶同樣保存到一個(gè)Map中闻蛀,即mSharedUsers匪傍。

同樣,需要調(diào)用addUserIdLPw方法觉痛,來(lái)判斷這個(gè)id是否在系統(tǒng)規(guī)定的范圍役衡,這個(gè)方法上面已做了分析。這個(gè)時(shí)候PMS通過(guò)Settings就已將上一次應(yīng)用程序的安裝信息恢復(fù)完成了薪棒。我們回頭看到PMS的構(gòu)造方法手蝎,它會(huì)掃描各個(gè)安裝目錄。

//Environment.getRootDirectory()為system目錄
            //獲取/system/famework目錄俐芯,保存的是資源型的文件棵介,不包含執(zhí)行代碼
            File frameworkDir = new File(Environment.getRootDirectory(), "framework");
            
            //加載framework資源
            alreadyDexOpted.add(frameworkDir.getPath() + "/framework-res.apk");
            
            //加載核心庫(kù)
            alreadyDexOpted.add(frameworkDir.getPath() + "/core-libart.jar");
           
            String[] frameworkFiles = frameworkDir.list();
            if (frameworkFiles != null) {
              
                for (String dexCodeInstructionSet : dexCodeInstructionSets) {
                    for (int i=0; i<frameworkFiles.length; i++) {
                        File libPath = new File(frameworkDir, frameworkFiles[i]);
                        String path = libPath.getPath();
                        // Skip the file if we already did it.
                        //跳過(guò)已優(yōu)化的文件
                        if (alreadyDexOpted.contains(path)) {
                            continue;
                        }
                        // Skip the file if it is not a type we want to dexopt.
                        //跳過(guò)不是apk或jar的文件
                        if (!path.endsWith(".apk") && !path.endsWith(".jar")) {
                            continue;
                        }
                        try {
                            byte dexoptRequired = DexFile.isDexOptNeededInternal(path, null, dexCodeInstructionSet, false);
                            if (dexoptRequired == DexFile.DEXOPT_NEEDED) {
                                mInstaller.dexopt(path, Process.SYSTEM_UID, true, dexCodeInstructionSet);
                                didDexOptLibraryOrTool = true;
                            } else if (dexoptRequired == DexFile.PATCHOAT_NEEDED) {
                                mInstaller.patchoat(path, Process.SYSTEM_UID, true, dexCodeInstructionSet);
                                didDexOptLibraryOrTool = true;
                            }
                        } catch (FileNotFoundException e) {
                            Slog.w(TAG, "Jar not found: " + path);
                        } catch (IOException e) {
                            Slog.w(TAG, "Exception reading jar: " + path, e);
                        }
                    }
                }
            }

         
            File vendorOverlayDir = new File(VENDOR_OVERLAY_DIR);
            //根據(jù)上面讀取到的安裝信息,通過(guò)scanDirLI來(lái)安裝各個(gè)目錄的程序
            scanDirLI(vendorOverlayDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_TRUSTED_OVERLAY, 0);
         
            scanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR
                    | PackageParser.PARSE_IS_PRIVILEGED,
                    scanFlags | SCAN_NO_DEX, 0);
         
            //系統(tǒng)私有的應(yīng)用程序吧史,如Launcher邮辽、systemui、settings
            final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
            scanDirLI(privilegedAppDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR
                    | PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0);
       
            // /system/app系統(tǒng)的應(yīng)用程序
            final File systemAppDir = new File(Environment.getRootDirectory(), "app");
            //掃描系統(tǒng)應(yīng)用的安裝路徑
            scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);

            File vendorAppDir = new File("/vendor/app");
            try {
                vendorAppDir = vendorAppDir.getCanonicalFile();
            } catch (IOException e) {
                // failed to look up canonical path, continue with original one
            }
            scanDirLI(vendorAppDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);

            final File oemAppDir = new File(Environment.getOemDirectory(), "app");
            scanDirLI(oemAppDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);

            if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");
            mInstaller.moveFiles();

顯然scanDirLI是最關(guān)鍵的方法,通過(guò)掃描5個(gè)安裝目錄吨述,判斷是否存在以".apk"為后綴的文件岩睁,如果存在則對(duì)文件進(jìn)行解析。

   //掃描安裝路徑
    private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime) {
        //遍歷出所有文件
        final File[] files = dir.listFiles();
        if (ArrayUtils.isEmpty(files)) {
            Log.d(TAG, "No files in app dir " + dir);
            return;
        }

        if (DEBUG_PACKAGE_SCANNING) {
            Log.d(TAG, "Scanning app dir " + dir + " scanFlags=" + scanFlags
                    + " flags=0x" + Integer.toHexString(parseFlags));
        }

        //取出所有apk文件進(jìn)行解析
        for (File file : files) {
            final boolean isPackage = (isApkFile(file) || file.isDirectory())
                    && !PackageInstallerService.isStageName(file.getName());
            if (!isPackage) {                
                continue;
            }
            try {
                //解析apk
                scanPackageLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK,
                        scanFlags, currentTime, null);
            } catch (PackageManagerException e) {               
                if ((parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
                        e.error == PackageManager.INSTALL_FAILED_INVALID_APK) {
                    logCriticalInfo(Log.WARN, "Deleting invalid package at " + file);
                    if (file.isDirectory()) {
                        FileUtils.deleteContents(file);
                    }
                    file.delete();
                }
            }
        }
    }

scanPackageLI方法用來(lái)解析.apk文件揣云,解析完會(huì)返回一個(gè)Package對(duì)象pkg給調(diào)用者捕儒。

private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
            long currentTime, UserHandle user) throws PackageManagerException {

        //設(shè)置解析標(biāo)志mDefParseFlags默認(rèn)為0
        parseFlags |= mDefParseFlags;
        //創(chuàng)建一個(gè)包解析器
        PackageParser pp = new PackageParser();
        pp.setSeparateProcesses(mSeparateProcesses);
        pp.setOnlyCoreApps(mOnlyCore);
        pp.setDisplayMetrics(mMetrics);

        if ((scanFlags & SCAN_TRUSTED_OVERLAY) != 0) {
            parseFlags |= PackageParser.PARSE_TRUSTED_OVERLAY;
        }
        //定義包對(duì)象Package 
        final PackageParser.Package pkg;
        try {
            //解析apk文件,獲得Package 
            pkg = pp.parsePackage(scanFile, parseFlags);
        } catch (PackageParserException e) {
            throw PackageManagerException.from(e);
        }

        PackageSetting ps = null;
        PackageSetting updatedPkg;

        synchronized (mPackages) {
       
            String oldName = mSettings.mRenamedPackages.get(pkg.packageName);
            if (pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(oldName)) {
            
                ps = mSettings.peekPackageLPr(oldName);
            }

            if (ps == null) {
                ps = mSettings.peekPackageLPr(pkg.packageName);
            }

            updatedPkg = mSettings.getDisabledSystemPkgLPr(ps != null ? ps.name : pkg.packageName);
            if (DEBUG_INSTALL && updatedPkg != null) Slog.d(TAG, "updatedPkg = " + updatedPkg);
        }
        boolean updatedPkgBetter = false;

        if (updatedPkg != null && (parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
            if (ps != null && !ps.codePath.equals(scanFile)) {
            
                if (pkg.mVersionCode < ps.versionCode) {
                
                    if (!updatedPkg.codePath.equals(scanFile)) {
                    
                        updatedPkg.codePath = scanFile;
                        updatedPkg.codePathString = scanFile.toString();
                   
                        if (locationIsPrivileged(scanFile)) {
                            updatedPkg.pkgFlags |= ApplicationInfo.FLAG_PRIVILEGED;
                        }
                    }
                    updatedPkg.pkg = pkg;
                    throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE, null);
                } else {
                                       synchronized (mPackages) {
                                         mPackages.remove(ps.name);
                    }
    
                    InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
                            ps.codePathString, ps.resourcePathString, ps.legacyNativeLibraryPathString,
                            getAppDexInstructionSets(ps));
                    synchronized (mInstallLock) {
                        args.cleanUpResourcesLI();
                    }
                    synchronized (mPackages) {
                        mSettings.enableSystemPackageLPw(ps.name);
                    }
                    updatedPkgBetter = true;
                }
            }
        }

        if (updatedPkg != null) {
         
            parseFlags |= PackageParser.PARSE_IS_SYSTEM;
            
            if ((updatedPkg.pkgFlags & ApplicationInfo.FLAG_PRIVILEGED) != 0) {
                parseFlags |= PackageParser.PARSE_IS_PRIVILEGED;
            }
        }
  
        collectCertificatesLI(pp, ps, pkg, scanFile, parseFlags);

        boolean shouldHideSystemApp = false;
        if (updatedPkg == null && ps != null
                && (parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0 && !isSystemApp(ps)) {
           
            if (compareSignatures(ps.signatures.mSignatures, pkg.mSignatures)
                    != PackageManager.SIGNATURE_MATCH) {
         
            } else {
             
                if (pkg.mVersionCode < ps.versionCode) {
                    shouldHideSystemApp = true;
                } else {
               
                    InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
                            ps.codePathString, ps.resourcePathString, ps.legacyNativeLibraryPathString,
                            getAppDexInstructionSets(ps));
                    synchronized (mInstallLock) {
                        args.cleanUpResourcesLI();
                    }
                }
            }
        }

        if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
            if (ps != null && !ps.codePath.equals(ps.resourcePath)) {
                parseFlags |= PackageParser.PARSE_FORWARD_LOCK;
            }
        }
     
        String resourcePath = null;
        String baseResourcePath = null;
        if ((parseFlags & PackageParser.PARSE_FORWARD_LOCK) != 0 && !updatedPkgBetter) {
            if (ps != null && ps.resourcePathString != null) {
                resourcePath = ps.resourcePathString;
                baseResourcePath = ps.resourcePathString;
            } else {
            }
        } else {
            resourcePath = pkg.codePath;
            baseResourcePath = pkg.baseCodePath;
        }
   
        pkg.applicationInfo.setCodePath(pkg.codePath);
        pkg.applicationInfo.setBaseCodePath(pkg.baseCodePath);
        pkg.applicationInfo.setSplitCodePaths(pkg.splitCodePaths);
        pkg.applicationInfo.setResourcePath(resourcePath);
        pkg.applicationInfo.setBaseResourcePath(baseResourcePath);
        pkg.applicationInfo.setSplitResourcePaths(pkg.splitCodePaths);
      
        //解析Package
        PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanFlags| SCAN_UPDATE_SIGNATURE, currentTime, user);

        if (shouldHideSystemApp) {
            synchronized (mPackages) {
               
                grantPermissionsLPw(pkg, true, pkg.packageName);
                mSettings.disableSystemPackageLPw(pkg.packageName);
            }
        }

        return scannedPkg;
    }

這里分兩步看邓夕,第一步是創(chuàng)建PackageParser解析器刘莹,通過(guò)parsePackage方法,將apk文件解析成Package對(duì)象翎迁;第二步是使用另一個(gè)重載方法scanPackageLI來(lái)處理這個(gè)Package并返回。我們先看第一步净薛,進(jìn)入PackageParser這個(gè)類(lèi)的parsePackage方法汪榔。

//解析.apk文件
    public Package parsePackage(File packageFile, int flags) throws PackageParserException {
        if (packageFile.isDirectory()) {
            //解析多個(gè)apk
            return parseClusterPackage(packageFile, flags);
        } else {
            //解析單個(gè)
            return parseMonolithicPackage(packageFile, flags);
        }
    }

如果傳入的是一個(gè)目錄文件,被拆分成多個(gè)apk肃拜,由一個(gè)base APK和一個(gè)或多個(gè)split APK痴腌,稱(chēng)為Cluster,單個(gè)稱(chēng)為Monolithic燃领。

兩者解析流程差別不大士聪,我們以parseMonolithicPackage為例分析。

 @Deprecated
    public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
        //是否核心應(yīng)用
        if (mOnlyCoreApps) {
          //輕量級(jí)解析
            final PackageLite lite = parseMonolithicPackageLite(apkFile, flags);
            if (!lite.coreApp) {
                throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
                        "Not a coreApp: " + apkFile);
            }
        }
        //構(gòu)建AssetManager
        final AssetManager assets = new AssetManager();
        try {
            //開(kāi)始解析
            final Package pkg = parseBaseApk(apkFile, assets, flags);
            pkg.codePath = apkFile.getAbsolutePath();
            return pkg;
        } finally {
            IoUtils.closeQuietly(assets);
        }
    }

輕量級(jí)解析是因?yàn)榻馕鯽pk是復(fù)雜耗時(shí)的操作猛蔽,這里的邏輯并不需要所有的信息剥悟,coreApp指的是AndroidManifest中屬性coreApp值為true。繼續(xù)看解析方法parseBaseApk曼库,注意它接收了一個(gè)AssetManager 對(duì)象区岗。

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

        mParseError = PackageManager.INSTALL_SUCCEEDED;
        mArchiveSourcePath = apkFile.getAbsolutePath();
 
        final int cookie = loadApkIntoAssetManager(assets, apkPath, flags);
        //構(gòu)建Resources 
        Resources res = null;
        XmlResourceParser parser = null;
        try {
            //將AssetManager封裝在Resources中
            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);
            //打開(kāi)manifest,構(gòu)造解析器
            parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);

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

            pkg.baseCodePath = apkPath;
            pkg.mSignatures = null;

            return pkg;

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

XmlResourceParser 用于解析編譯后的AndroidManifest毁枯,通過(guò)重載方法parseBaseApk來(lái)解析慈缔。因?yàn)榻馕鰳?biāo)簽很多,所以代碼非常長(zhǎng)种玛,這里貼部分作為示例藐鹤。

    private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags,
            String[] outError) throws XmlPullParserException, IOException {
        final boolean trustedOverlay = (flags & PARSE_TRUSTED_OVERLAY) != 0;
        AttributeSet attrs = parser;
        mParseInstrumentationArgs = null;
        mParseActivityArgs = null;
        mParseServiceArgs = null;
        mParseProviderArgs = null;

        final String pkgName;
        final String splitName;
        try {
            Pair<String, String> packageSplit = parsePackageSplitNames(parser, attrs, flags);
            pkgName = packageSplit.first;//包名
            splitName = packageSplit.second;
        } catch (PackageParserException e) {
            mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
            return null;
        }
        int type;
        if (!TextUtils.isEmpty(splitName)) {
            outError[0] = "Expected base APK, but found split " + splitName;
            mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
            return null;
        }

        //根據(jù)包名構(gòu)建Package對(duì)象,將解析manifest后的信息存到這個(gè)對(duì)象中
        final Package pkg = new Package(pkgName);
        boolean foundApp = false;

        TypedArray sa = res.obtainAttributes(attrs,
                com.android.internal.R.styleable.AndroidManifest);
        pkg.mVersionCode = pkg.applicationInfo.versionCode = sa.getInteger(
                com.android.internal.R.styleable.AndroidManifest_versionCode, 0);//版本號(hào)
        pkg.mVersionName = sa.getNonConfigurationString(
                com.android.internal.R.styleable.AndroidManifest_versionName, 0);//版本名
        if (pkg.mVersionName != null) {
            pkg.mVersionName = pkg.mVersionName.intern();
        }
        String str = sa.getNonConfigurationString(
                com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0);
        if (str != null && str.length() > 0) {
            String nameError = validateName(str, true);
            if (nameError != null && !"android".equals(pkgName)) {
                outError[0] = "<manifest> specifies bad sharedUserId name \""
                    + str + "\": " + nameError;
                mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID;
                return null;
            }
            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);
        pkg.applicationInfo.installLocation = pkg.installLocation;

        pkg.coreApp = attrs.getAttributeBooleanValue(null, "coreApp", false);
        sa.recycle();
       
        if ((flags & PARSE_FORWARD_LOCK) != 0) {
            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FORWARD_LOCK;
        }
     
        if ((flags & PARSE_ON_SDCARD) != 0) {
            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE;
        }
       
        int supportsSmallScreens = 1;
        int supportsNormalScreens = 1;
        int supportsLargeScreens = 1;
        int supportsXLargeScreens = 1;
        int resizeable = 1;
        int anyDensity = 1;
        
        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")) {
                if (foundApp) {
                    if (RIGID_PARSER) {
                        //一個(gè)xml只能包含一個(gè)<application>標(biāo)簽
                        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 (!parseBaseApplication(pkg, res, parser, attrs, flags, outError)) {
                    return null;
                }
            } else if (tagName.equals("overlay")) {
                pkg.mTrustedOverlay = trustedOverlay;

                sa = res.obtainAttributes(attrs,
                        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,
                        -1);
                sa.recycle();

                if (pkg.mOverlayTarget == null) {
                    outError[0] = "<overlay> does not specify a target package";
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return null;
                }
                if (pkg.mOverlayPriority < 0 || pkg.mOverlayPriority > 9999) {
                    outError[0] = "<overlay> priority must be between 0 and 9999";
                    mParseError =
                        PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return null;
                }
                XmlUtils.skipCurrentTag(parser);

            } else if (tagName.equals("key-sets")) {
                if (!parseKeySets(pkg, res, parser, attrs, outError)) {
                    return null;
                }
            } else if (tagName.equals("permission-group")) {
                if (parsePermissionGroup(pkg, flags, res, parser, attrs, outError) == null) {
                    return null;
                }
            } else if (tagName.equals("permission")) {
                if (parsePermission(pkg, res, parser, attrs, outError) == null) {
                    return null;
                }
            } else if (tagName.equals("permission-tree")) {
                if (parsePermissionTree(pkg, res, parser, attrs, outError) == null) {
                    return null;
                }
            //權(quán)限
            } else if (tagName.equals("uses-permission")) {
                if (!parseUsesPermission(pkg, res, parser, attrs, outError)) {
                    return null;
                }

我們看到parseBaseApplication開(kāi)始解析application標(biāo)簽赂韵,它同樣非常長(zhǎng)娱节。

 private boolean parseBaseApplication(Package owner, Resources res,
            XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)
        throws XmlPullParserException, IOException {
        //應(yīng)用信息
        final ApplicationInfo ai = owner.applicationInfo;
        //包名
        final String pkgName = owner.applicationInfo.packageName;

        //標(biāo)簽屬性
        TypedArray sa = res.obtainAttributes(attrs,
                com.android.internal.R.styleable.AndroidManifestApplication);

        //應(yīng)用名
        String name = sa.getNonConfigurationString(
                com.android.internal.R.styleable.AndroidManifestApplication_name, 0);
        if (name != null) {
            ai.className = buildClassName(pkgName, name, outError);
            if (ai.className == null) {
                sa.recycle();
                mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                return false;
            }
        }

        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(
                com.android.internal.R.styleable.AndroidManifestApplication_allowBackup, true);
        if (allowBackup) {
            ai.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP;
            
            String backupAgent = sa.getNonConfigurationString(
                    com.android.internal.R.styleable.AndroidManifestApplication_backupAgent,
                    Configuration.NATIVE_CONFIG_VERSION);
            if (backupAgent != null) {
                ai.backupAgentName = buildClassName(pkgName, backupAgent, outError);
             
                if (sa.getBoolean(
                        com.android.internal.R.styleable.AndroidManifestApplication_killAfterRestore,
                        true)) {
                    ai.flags |= ApplicationInfo.FLAG_KILL_AFTER_RESTORE;
                }
                if (sa.getBoolean(
                        com.android.internal.R.styleable.AndroidManifestApplication_restoreAnyVersion,
                        false)) {
                    ai.flags |= ApplicationInfo.FLAG_RESTORE_ANY_VERSION;
                }
                if (sa.getBoolean(
                        com.android.internal.R.styleable.AndroidManifestApplication_fullBackupOnly,
                        false)) {
                    ai.flags |= ApplicationInfo.FLAG_FULL_BACKUP_ONLY;
                }
            }
        }

        TypedValue v = sa.peekValue(
                com.android.internal.R.styleable.AndroidManifestApplication_label);
        if (v != null && (ai.labelRes=v.resourceId) == 0) {
            ai.nonLocalizedLabel = v.coerceToString();
        }

        //應(yīng)用圖標(biāo)等
        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);

        if ((flags&PARSE_IS_SYSTEM) != 0) {
            if (sa.getBoolean(
                    com.android.internal.R.styleable.AndroidManifestApplication_persistent,
                    false)) {
                ai.flags |= ApplicationInfo.FLAG_PERSISTENT;
            }
        }

        ......
  

       final int innerDepth = parser.getDepth();
        int type;
        //循環(huán)解析Application元素下所有子元素,如activity,service等
        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, attrs, flags, outError, false,
                        owner.baseHardwareAccelerated);
                if (a == null) {
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                }
                //將Activity添加到管理的列表當(dāng)中
                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);

我們看到包名祭示、應(yīng)用名還有4大組件都被解析出來(lái)了括堤。這里注意到有個(gè)owner,它是在parseBaseApk里根據(jù)包名生成的Package對(duì)象,Manifest標(biāo)簽解析后的數(shù)據(jù)都存在此對(duì)象中悄窃。

Package是PackageParser解析器的內(nèi)部類(lèi)讥电,Package用了四個(gè)列表分別保存四大組件。

public final static class Package {

        public String packageName;

        public String[] splitNames;

        public String codePath;
    
        public String baseCodePath;

        public String[] splitCodePaths;
    
        public int[] splitFlags;

        public boolean baseHardwareAccelerated;

        public final ApplicationInfo applicationInfo = new ApplicationInfo();

        public final ArrayList<Permission> permissions = new ArrayList<Permission>(0);
        public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0);
        //保存四大組件
        public final ArrayList<Activity> activities = new ArrayList<Activity>(0);
        public final ArrayList<Activity> receivers = new ArrayList<Activity>(0);
        public final ArrayList<Provider> providers = new ArrayList<Provider>(0);
        public final ArrayList<Service> services = new ArrayList<Service>(0);

到這里第一步就完成了轧抗,得到一個(gè)Package對(duì)象恩敌,它包含了Manifest的所有信息。如上面所提横媚,第二步是調(diào)用重載的scanPackageLI方法纠炮,解析這個(gè)Package。

我們先看下PMS的5個(gè)成員變量灯蝴。

//保存已安裝的程序
 final HashMap<String, PackageParser.Package> mPackages =
            new HashMap<String, PackageParser.Package>();

 //保存每個(gè)應(yīng)用的Activity節(jié)點(diǎn)恢口,一個(gè)應(yīng)用一個(gè)節(jié)點(diǎn),一個(gè)節(jié)點(diǎn)用一個(gè)HashMap存了改應(yīng)用的所有activity
    final ActivityIntentResolver mActivities =
            new ActivityIntentResolver();
    
    //保存所有receiver節(jié)點(diǎn)
    final ActivityIntentResolver mReceivers =
            new ActivityIntentResolver();

    //保存所有Service節(jié)點(diǎn)
    final ServiceIntentResolver mServices = new ServiceIntentResolver();
 
    //保存所有Provider節(jié)點(diǎn)
    final ProviderIntentResolver mProviders = new ProviderIntentResolver();

這些屬性類(lèi)型都采用了自定義類(lèi)去保存相關(guān)信息穷躁,從類(lèi)名上看耕肩,類(lèi)結(jié)構(gòu)都很相似。順便提一下问潭,我們通過(guò)getPackageManager()方法獲得的PackageManager對(duì)象猿诸,只是PackageManagerService的客戶端,PackageManager的子類(lèi)ApplicationPackageManager狡忙,顯然該類(lèi)存在于用戶空間中梳虽。關(guān)于跨進(jìn)程通訊可以看<Binder系列>的分析。

系統(tǒng)中所有已安裝的程序都用Package來(lái)描述灾茁,而這些Package就保存在mPackages 中窜觉,而每一個(gè)應(yīng)用的四大組件都分別保存在mActivities 、mReceivers 北专、mServices 和mProviders 中竖螃。

我們接下去看重載scanPackageLI方法。

private PackageParser.Package scanPackageLI(PackageParser.Package pkg, int parseFlags,
            int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
        boolean success = false;
        try {
            //scanPackageDirtyLI進(jìn)行掃描
            final PackageParser.Package res = scanPackageDirtyLI(pkg, parseFlags, scanFlags,
                    currentTime, user);
            success = true;
            return res;
        } finally {
            if (!success && (scanFlags & SCAN_DELETE_DATA_ON_FAILURES) != 0) {
                removeDataDirsLI(pkg.packageName);
            }
        }
    }
private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg, int parseFlags,
            int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
         ......      

        SharedUserSetting suid = null;
        PackageSetting pkgSetting = null;

        if (!isSystemApp(pkg)) {
            pkg.mOriginalPackages = null;
            pkg.mRealPackage = null;
            pkg.mAdoptPermissions = null;
        }
        
        synchronized (mPackages) {
            //根據(jù)mSettings保存的分配Linux用戶id
            if (pkg.mSharedUserId != null) {
                suid = mSettings.getSharedUserLPw(pkg.mSharedUserId, 0, true);
                if (suid == null) {
                    throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
                            "Creating application package " + pkg.packageName
                            + " for shared user failed");
                }
              
            }
            
            ......

        // writer
        synchronized (mPackages) {
            
            mSettings.insertPackageSettingLPw(pkgSetting, pkg);
      
            //將Package添加到成員變量mPackages中
            mPackages.put(pkg.applicationInfo.packageName, pkg);

            final Iterator<PackageCleanItem> iter = mSettings.mPackagesToBeCleaned.iterator();
            while (iter.hasNext()) {
                PackageCleanItem item = iter.next();
                if (pkgName.equals(item.packageName)) {
                    iter.remove();
                }
            }
       
            if (currentTime != 0) {
                if (pkgSetting.firstInstallTime == 0) {
                    pkgSetting.firstInstallTime = pkgSetting.lastUpdateTime = currentTime;
                } else if ((scanFlags&SCAN_UPDATE_TIME) != 0) {
                    pkgSetting.lastUpdateTime = currentTime;
                }
            } else if (pkgSetting.firstInstallTime == 0) {
        
                pkgSetting.firstInstallTime = pkgSetting.lastUpdateTime = scanFileTime;
            } else if ((parseFlags&PackageParser.PARSE_IS_SYSTEM_DIR) != 0) {
                if (scanFileTime != pkgSetting.timeStamp) {
                 
                    pkgSetting.lastUpdateTime = scanFileTime;
                }
            }

            KeySetManagerService ksms = mSettings.mKeySetManagerService;
            try {
       
                ksms.removeAppKeySetDataLPw(pkg.packageName);
                ksms.addSigningKeySetToPackageLPw(pkg.packageName, pkg.mSigningKeys);
                if (pkg.mKeySetMapping != null) {
                    for (Map.Entry<String, ArraySet<PublicKey>> entry :
                            pkg.mKeySetMapping.entrySet()) {
                        if (entry.getValue() != null) {
                            ksms.addDefinedKeySetToPackageLPw(pkg.packageName,
                                                          entry.getValue(), entry.getKey());
                        }
                    }
                    if (pkg.mUpgradeKeySets != null) {
                        for (String upgradeAlias : pkg.mUpgradeKeySets) {
                            ksms.addUpgradeKeySetToPackageLPw(pkg.packageName, upgradeAlias);
                        }
                    }
                }
            } catch (NullPointerException e) {
                Slog.e(TAG, "Could not add KeySet to " + pkg.packageName, e);
            } catch (IllegalArgumentException e) {
                Slog.e(TAG, "Could not add KeySet to malformed package" + pkg.packageName, e);
            }

            int N = pkg.providers.size();
            StringBuilder r = null;
            int i;
            for (i=0; i<N; i++) {
                PackageParser.Provider p = pkg.providers.get(i);
                p.info.processName = fixProcessName(pkg.applicationInfo.processName,
                        p.info.processName, pkg.applicationInfo.uid);
          //將Provider添加到mProviders
                mProviders.addProvider(p);
                p.syncable = p.info.isSyncable;
                if (p.info.authority != null) {
                    String names[] = p.info.authority.split(";");
                    p.info.authority = null;
                    for (int j = 0; j < names.length; j++) {
                        if (j == 1 && p.syncable) {
                          
                            p = new PackageParser.Provider(p);
                            p.syncable = false;
                        }
                        if (!mProvidersByAuthority.containsKey(names[j])) {
                            mProvidersByAuthority.put(names[j], p);
                            if (p.info.authority == null) {
                                p.info.authority = names[j];
                            } else {
                                p.info.authority = p.info.authority + ";" + names[j];
                            }
                            if (DEBUG_PACKAGE_SCANNING) {
                                if ((parseFlags & PackageParser.PARSE_CHATTY) != 0)
                                 
                            }
                        } else {
                            PackageParser.Provider other = mProvidersByAuthority.get(names[j]);
                         
                        }
                    }
                }
                if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
                    if (r == null) {
                        r = new StringBuilder(256);
                    } else {
                        r.append(' ');
                    }
                    r.append(p.info.name);
                }
            }
            if (r != null) {
                if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Providers: " + r);
            }

            N = pkg.services.size();
            r = null;
            for (i=0; i<N; i++) {
                PackageParser.Service s = pkg.services.get(i);
                s.info.processName = fixProcessName(pkg.applicationInfo.processName,
                        s.info.processName, pkg.applicationInfo.uid);
          //將Service添加到mServices
                mServices.addService(s);
                if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
                    if (r == null) {
                        r = new StringBuilder(256);
                    } else {
                        r.append(' ');
                    }
                    r.append(s.info.name);
                }
            }
            if (r != null) {
                if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Services: " + r);
            }

            N = pkg.receivers.size();
            r = null;
            for (i=0; i<N; i++) {
                PackageParser.Activity a = pkg.receivers.get(i);
                a.info.processName = fixProcessName(pkg.applicationInfo.processName,
                        a.info.processName, pkg.applicationInfo.uid);
              //將Receiver添加到mReceivers
                mReceivers.addActivity(a, "receiver");
                if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
                    if (r == null) {
                        r = new StringBuilder(256);
                    } else {
                        r.append(' ');
                    }
                    r.append(a.info.name);
                }
            }
            if (r != null) {
                if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Receivers: " + r);
            }

            N = pkg.activities.size();
            r = null;
            //將Package所有activity添加到成員變量mActivities的HashMap中
            for (i=0; i<N; i++) {
                PackageParser.Activity a = pkg.activities.get(i);
                a.info.processName = fixProcessName(pkg.applicationInfo.processName,
                        a.info.processName, pkg.applicationInfo.uid);
           //將Activity添加到mActivities
                mActivities.addActivity(a, "activity");
                if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
                    if (r == null) {
                        r = new StringBuilder(256);
                    } else {
                        r.append(' ');
                    }
                    r.append(a.info.name);
                }
            }

          ......

        return pkg;
    }

對(duì)Package的掃描主要任務(wù)是分配Linux用戶id逗余,以及將Package和四大組件分別添加到上面說(shuō)的5成員變量中特咆,前面說(shuō)過(guò)共享用戶都使用一個(gè)SharedUserSetting 對(duì)象來(lái)描述,因此根據(jù)name去mSharedUsers中查找录粱,如果不存在則新建腻格。

 SharedUserSetting getSharedUserLPw(String name,
            int pkgFlags, boolean create) {
        SharedUserSetting s = mSharedUsers.get(name);
        //不存在根據(jù)create判斷是否新建
        if (s == null) {
            if (!create) {
                return null;
            }
            s = new SharedUserSetting(name, pkgFlags);
            s.userId = newUserIdLPw(s);
          //加到mSharedUsers中
            if (s.userId >= 0) {
                mSharedUsers.put(name, s);
            }
        }

        return s;
    }

此時(shí)PMS便為應(yīng)用分配好了Linux用戶id,并把它們緩存到成員變量中啥繁。但成員數(shù)據(jù)會(huì)隨著類(lèi)的回收而銷(xiāo)毀菜职,前面分析時(shí)我們知道,這些數(shù)據(jù)對(duì)應(yīng)的信息會(huì)保存到packages.xml和packages-backup.xml中旗闽,以便下次啟動(dòng)恢復(fù)酬核,這個(gè)保存操作也在PMS構(gòu)造函數(shù)執(zhí)行蜜另,我們?cè)俅位氐絇MS的構(gòu)造方法。

            .....

          //權(quán)限設(shè)置嫡意,檢查sdk版本
            final boolean regrantPermissions = mSettings.mInternalSdkPlatform
                    != mSdkVersion;
            if (regrantPermissions) Slog.i(TAG, "Platform changed from "
                    + mSettings.mInternalSdkPlatform + " to " + mSdkVersion
                    + "; regranting permissions for internal storage");
            mSettings.mInternalSdkPlatform = mSdkVersion;
            //分配權(quán)限
            updatePermissionsLPw(null, null, UPDATE_PERMISSIONS_ALL
                    | (regrantPermissions
                            ? (UPDATE_PERMISSIONS_REPLACE_PKG|UPDATE_PERMISSIONS_REPLACE_ALL)
                            : 0));

            if (!mRestoredSettings && !onlyCore) {
                mSettings.readDefaultPreferredAppsLPw(this, 0);
            }
          
            if (!Build.FINGERPRINT.equals(mSettings.mFingerprint) && !onlyCore) {
                Slog.i(TAG, "Build fingerprint changed; clearing code caches");
                for (String pkgName : mSettings.mPackages.keySet()) {
                    deleteCodeCacheDirsLI(pkgName);
                }
                mSettings.mFingerprint = Build.FINGERPRINT;
            }
         
            mSettings.updateInternalDatabaseVersion();
     
            //將上面讀取到的信息保存成配置举瑰,以便下次啟動(dòng)恢復(fù)
            mSettings.writeLPr();

         EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
                    SystemClock.uptimeMillis());

            mRequiredVerifierPackage = getRequiredVerifierLPr();
        } 
        } 

        mInstallerService = new PackageInstallerService(context, this, mAppInstallDir);
      
        //GC回收資源
        Runtime.getRuntime().gc();
    }

我們?cè)俅芜M(jìn)到Settings類(lèi),看writeLPr方法是如何保存的蔬螟。

//保存上一次的應(yīng)用安裝信息
    void writeLPr() {
        //Debug.startMethodTracing("/data/system/packageprof", 8 * 1024 * 1024);

        // Keep the old settings around until we know the new ones have
        // been successfully written.
        //源文件是否存在
        if (mSettingsFilename.exists()) {
            // Presence of backup settings file indicates that we failed
            // to persist settings earlier. So preserve the older
            // backup for future reference since the current settings
            // might have been corrupted.
            //備份文件不存存在
            if (!mBackupSettingsFilename.exists()) {
                //將源文件重命名為備份文件
                if (!mSettingsFilename.renameTo(mBackupSettingsFilename)) {
                    Slog.wtf(PackageManagerService.TAG,
                            "Unable to backup package manager settings, "
                            + " current changes will be lost at reboot");
                    return;
                }
            } else {
                //刪掉源文件
                mSettingsFilename.delete();
                Slog.w(PackageManagerService.TAG, "Preserving older settings backup");
            }
        }

        mPastSignatures.clear();

        try {
            //初始化文件的一些標(biāo)簽
            FileOutputStream fstr = new FileOutputStream(mSettingsFilename);
            BufferedOutputStream str = new BufferedOutputStream(fstr);

            //XmlSerializer serializer = XmlUtils.serializerInstance();
            XmlSerializer serializer = new FastXmlSerializer();
            serializer.setOutput(str, "utf-8");
            serializer.startDocument(null, true);
            serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);

            serializer.startTag(null, "packages");//包標(biāo)簽

            serializer.startTag(null, "last-platform-version");
            serializer.attribute(null, "internal", Integer.toString(mInternalSdkPlatform));
            serializer.attribute(null, "external", Integer.toString(mExternalSdkPlatform));
            serializer.attribute(null, "fingerprint", mFingerprint);
            serializer.endTag(null, "last-platform-version");

            serializer.startTag(null, "database-version");
            serializer.attribute(null, "internal", Integer.toString(mInternalDatabaseVersion));
            serializer.attribute(null, "external", Integer.toString(mExternalDatabaseVersion));
            serializer.endTag(null, "database-version");

            if (mVerifierDeviceIdentity != null) {
                serializer.startTag(null, "verifier");
                serializer.attribute(null, "device", mVerifierDeviceIdentity.toString());
                serializer.endTag(null, "verifier");
            }

            if (mReadExternalStorageEnforced != null) {
                serializer.startTag(null, TAG_READ_EXTERNAL_STORAGE);
                serializer.attribute(
                        null, ATTR_ENFORCEMENT, mReadExternalStorageEnforced ? "1" : "0");
                serializer.endTag(null, TAG_READ_EXTERNAL_STORAGE);
            }

            serializer.startTag(null, "permission-trees");
            for (BasePermission bp : mPermissionTrees.values()) {
                writePermissionLPr(serializer, bp);
            }
            serializer.endTag(null, "permission-trees");

            serializer.startTag(null, "permissions");
            for (BasePermission bp : mPermissions.values()) {
                writePermissionLPr(serializer, bp);
            }
            serializer.endTag(null, "permissions");

            for (final PackageSetting pkg : mPackages.values()) {
                writePackageLPr(serializer, pkg);
            }

            for (final PackageSetting pkg : mDisabledSysPackages.values()) {
                writeDisabledSysPackageLPr(serializer, pkg);
            }

            for (final SharedUserSetting usr : mSharedUsers.values()) {
                serializer.startTag(null, "shared-user");//共享用戶標(biāo)簽
                serializer.attribute(null, ATTR_NAME, usr.name);
                serializer.attribute(null, "userId",Integer.toString(usr.userId));//獨(dú)立用戶id
                usr.signatures.writeXml(serializer, "sigs", mPastSignatures);
                serializer.startTag(null, "perms");
                for (String name : usr.grantedPermissions) {
                    serializer.startTag(null, TAG_ITEM);
                    serializer.attribute(null, ATTR_NAME, name);
                    serializer.endTag(null, TAG_ITEM);
                }
                serializer.endTag(null, "perms");
                serializer.endTag(null, "shared-user");
            }

            if (mPackagesToBeCleaned.size() > 0) {
                for (PackageCleanItem item : mPackagesToBeCleaned) {
                    final String userStr = Integer.toString(item.userId);
                    serializer.startTag(null, "cleaning-package");
                    serializer.attribute(null, ATTR_NAME, item.packageName);
                    serializer.attribute(null, ATTR_CODE, item.andCode ? "true" : "false");
                    serializer.attribute(null, ATTR_USER, userStr);
                    serializer.endTag(null, "cleaning-package");
                }
            }
            
            if (mRenamedPackages.size() > 0) {
                for (Map.Entry<String, String> e : mRenamedPackages.entrySet()) {
                    serializer.startTag(null, "renamed-package");
                    serializer.attribute(null, "new", e.getKey());
                    serializer.attribute(null, "old", e.getValue());
                    serializer.endTag(null, "renamed-package");
                }
            }
            
            mKeySetManagerService.writeKeySetManagerServiceLPr(serializer);
            //包標(biāo)簽結(jié)束packages
            serializer.endTag(null, "packages");
            //文檔標(biāo)簽結(jié)束
            serializer.endDocument();

            str.flush();
            FileUtils.sync(fstr);
            str.close();
            ......
}

可以看到此迅,每個(gè)程序都是以package標(biāo)簽為單位來(lái)存儲(chǔ)的,name表示了包名旧巾,userId和sharedUserId描述分配給程序的獨(dú)立Linux用戶id和共享Linux用戶id耸序,這兩個(gè)id是互斥的,即要么為獨(dú)立用戶要么為共享用戶鲁猩。

這一步完成坎怪,PMS就將程序所使用的Linux用戶id保存起來(lái)了,當(dāng)重裝一個(gè)應(yīng)用程序時(shí)廓握,它所對(duì)應(yīng)的Linux用戶id是不變的搅窿。

Android系統(tǒng)是類(lèi)Linux系統(tǒng),根據(jù)Linux用戶id來(lái)防止程序的篡改和破壞疾棵,程序的進(jìn)程是AMS向Zygote進(jìn)程請(qǐng)求創(chuàng)建的戈钢,而Zygote正是根據(jù)這個(gè)id來(lái)創(chuàng)建進(jìn)程痹仙。我們可以看下AMS的startProcessLocked方法是尔。

 private final void startProcessLocked(ProcessRecord app, String hostingType,
            String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {

        long startTime = SystemClock.elapsedRealtime();
        //
        if (app.pid > 0 && app.pid != MY_PID) {
            checkTime(startTime, "startProcess: removing from pids map");
            synchronized (mPidsSelfLocked) {
                mPidsSelfLocked.remove(app.pid);
                mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
            }
            checkTime(startTime, "startProcess: done removing from pids map");
            app.setPid(0);
        }
       
        mProcessesOnHold.remove(app);

        checkTime(startTime, "startProcess: starting to update cpu stats");
        updateCpuStats();
        checkTime(startTime, "startProcess: done updating cpu stats");

        try {
            //獲取Linux用戶id
            int uid = app.uid;
      
            int[] gids = null;
            int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
            if (!app.isolated) {
                int[] permGids = null;
                try {
                    checkTime(startTime, "startProcess: getting gids from package manager");
                    final PackageManager pm = mContext.getPackageManager();
                    permGids = pm.getPackageGids(app.info.packageName);

                    if (Environment.isExternalStorageEmulated()) {
                        checkTime(startTime, "startProcess: checking external storage perm");
                        if (pm.checkPermission(
                                android.Manifest.permission.ACCESS_ALL_EXTERNAL_STORAGE,
                                app.info.packageName) == PERMISSION_GRANTED) {
                            mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER_ALL;
                        } else {
                            mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER;
                        }
                    }
                } catch (PackageManager.NameNotFoundException e) {
                    Slog.w(TAG, "Unable to retrieve gids", e);
                }

                if (permGids == null) {
                    gids = new int[2];
                } else {
                    gids = new int[permGids.length + 2];
                    System.arraycopy(permGids, 0, gids, 2, permGids.length);
                }
                gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));
                gids[1] = UserHandle.getUserGid(UserHandle.getUserId(uid));
            }
            ......

            //告訴Zygote子進(jìn)程孵化ActivityThread進(jìn)程后,調(diào)用main方法
            if (entryPoint == null) entryPoint = "android.app.ActivityThread";
            checkTime(startTime, "startProcess: asking zygote to start proc");
            //開(kāi)啟進(jìn)程
            Process.ProcessStartResult startResult = Process.start(entryPoint,
                                            app.processName, uid, uid, gids, debugFlags, mountExternal,
                                            app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
                                            app.info.dataDir, entryPointArgs);
            checkTime(startTime, "startProcess: returned from zygote!");
          
            ......
    }

Process.start用于通知Zygote開(kāi)啟新進(jìn)程开仰,在調(diào)用的過(guò)程會(huì)根據(jù)第3拟枚、4、5個(gè)參數(shù)來(lái)創(chuàng)建進(jìn)程众弓。

到此恩溅,應(yīng)用程序的安裝過(guò)程便分析完畢,這個(gè)分析過(guò)程是從系統(tǒng)啟動(dòng)時(shí)開(kāi)始的谓娃,如果一個(gè)程序在系統(tǒng)啟動(dòng)后在安裝脚乡,它的入口會(huì)是PMS的installPackage,最終也會(huì)執(zhí)行scanPackageLI滨达,其流程是相似的奶稠。

程序安裝完成后,我們看到桌面會(huì)生成一個(gè)圖標(biāo)捡遍,這一流程將在下一篇<<App桌面圖標(biāo)顯示過(guò)程>>中講解锌订。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市画株,隨后出現(xiàn)的幾起案子辆飘,更是在濱河造成了極大的恐慌啦辐,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蜈项,死亡現(xiàn)場(chǎng)離奇詭異芹关,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)战得,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門(mén)充边,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人常侦,你說(shuō)我怎么就攤上這事浇冰。” “怎么了聋亡?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵肘习,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我坡倔,道長(zhǎng)漂佩,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任罪塔,我火速辦了婚禮投蝉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘征堪。我一直安慰自己瘩缆,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布佃蚜。 她就那樣靜靜地躺著庸娱,像睡著了一般。 火紅的嫁衣襯著肌膚如雪谐算。 梳的紋絲不亂的頭發(fā)上熟尉,一...
    開(kāi)封第一講書(shū)人閱讀 49,730評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音洲脂,去河邊找鬼斤儿。 笑死,一個(gè)胖子當(dāng)著我的面吹牛恐锦,可吹牛的內(nèi)容都是我干的往果。 我是一名探鬼主播,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼踩蔚,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼棚放!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起馅闽,我...
    開(kāi)封第一講書(shū)人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤飘蚯,失蹤者是張志新(化名)和其女友劉穎馍迄,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體局骤,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡攀圈,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了峦甩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片赘来。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖凯傲,靈堂內(nèi)的尸體忽然破棺而出犬辰,到底是詐尸還是另有隱情,我是刑警寧澤冰单,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布幌缝,位于F島的核電站,受9級(jí)特大地震影響诫欠,放射性物質(zhì)發(fā)生泄漏涵卵。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一荒叼、第九天 我趴在偏房一處隱蔽的房頂上張望轿偎。 院中可真熱鬧,春花似錦被廓、人聲如沸坏晦。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)英遭。三九已至间护,卻和暖如春亦渗,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背汁尺。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工法精, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人痴突。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓搂蜓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親辽装。 傳聞我的和親對(duì)象是個(gè)殘疾皇子帮碰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容