App安装过程

这个系列会分成《App的安装过程》、《App桌面图标显示过程》、《Activity的启动过程》和《Activity渲染过程》四篇文章,来分析从整个应用安装,到用户点击图标并显示首页,整个源码流程是如何调用的。

我们应用程序包的安装需要通过PackageManagerService来操作,而它早在系统启动SystemServer时便注册好了,SystemServer则由init进程启动。

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

 //运行
  private void run() {
    ......
    //创建系统上下文
    createSystemContext();

  //创建SystemServiceManager,用来管理各种系统service
   mSystemServiceManager = new SystemServiceManager(mSystemContext);
   LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);

  // 启动服务
        try {
            //启动服务,创建PMS,AMS等
            startBootstrapServices();
            // 启动核心服务
            startCoreServices();
            //启动IputManagerService等
            startOtherServices();
        } catch (Throwable ex) {
            Slog.e("System", "******************************************");
            Slog.e("System", "************ Failure starting system services", ex);
            throw ex;
        }

   }


  //创建系统上下文
  private void createSystemContext() {
        ActivityThread activityThread = ActivityThread.systemMain();
        mSystemContext = activityThread.getSystemContext();
        mSystemContext.setTheme(android.R.style.Theme_DeviceDefault_Light_DarkActionBar);
   }

初始化系统上下文时,生成了ActivityThread ,它相当于系统的主线程,我们看systemMain方法。

public static ActivityThread systemMain() {
        if (!ActivityManager.isHighEndGfx()) {
            HardwareRenderer.disable(true);
        } else {
            HardwareRenderer.enableForegroundTrimming();
        }
        //构造ActivityThread
        ActivityThread thread = new ActivityThread();
        //true表示系统应用
        thread.attach(true);
        return thread;
}

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

当调用为系统线程时,attach会执行else代码,创建Instrumentation和上下文,我们接着看启动包管理器服务的方法startBootstrapServices。

  private void startBootstrapServices() {
       //该对象负责与底层通信,进行具体安装卸载等操作
        mInstaller = mSystemServiceManager.startService(Installer.class);

        //开启ActivityManagerService,对比PowerManagerService等,实际上ActivityManagerService不是一个SystemService,而是Binder,ActivityManagerService.Lifecycle才是SystemService
        mActivityManagerService = mSystemServiceManager.startService(ActivityManagerService.Lifecycle.class).getService();
        mActivityManagerService.setSystemServiceManager(mSystemServiceManager);

        mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);

        mActivityManagerService.initPowerManagement();

       //开启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;
        }

        //构建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启动了许多服务,PackageManagerService通过main方法创建,并将系统上下文和mInstaller工具类传递进去。

    public static final PackageManagerService main(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) {
        //构造PMS对象
        PackageManagerService m = new PackageManagerService(context, installer,factoryTest, onlyCore);
        //注册到ServiceManager中
        ServiceManager.addService("package", m);
        return m;
    }

构造PMS对象,并将服务对象添加到ServiceManager中。PackageManagerService的构造方法代码比较多,我们分块分析。

    //pms启动后对系统中的特定目录进行扫描,获取信息以便进行应用程序安装
    public PackageManagerService(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) {
        //向事件日志写入事件,标识PackageManagerService启动时间
        EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,SystemClock.uptimeMillis());
        //版本检查
        if (mSdkVersion <= 0) {
            Slog.w(TAG, "**** ro.build.version.sdk not set!");
        }

        mContext = context;
        //开机是否工厂模式
        mFactoryTest = factoryTest;
        //是否启动内核
        mOnlyCore = onlyCore;
        //如果编译版本为eng,则不要进行dex优化
        mLazyDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
        //构造DisplayMetrics以便获得尺寸数据
        mMetrics = new DisplayMetrics();
        //构造Settings存储系统安装时的信息
        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);

        //是否在不同的进程中
        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;
        }

当一个新应用程序,要安装并运行在Linux中时,系统需要先为其开辟一个用户空间,并分配Linux独立用户id或共享用户id,而这个创建和分配的业务操作,由PackageMangerService来完成。

每当系统重启时,都需要对程序做一次重新安装,为了提高效率,程序在第一次安装时,PackageMangerService会将安装信息进行保存,以便再次安装时进行快速恢复。Settings就是用来保存这些信息的对象。

        //赋值mInstaller 
        mInstaller = installer;

        //测量显示对象
        getDefaultDisplayMetrics(context, mMetrics);

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

        synchronized (mInstallLock) {
        // writer
        synchronized (mPackages) {
            //启动处理线程
            mHandlerThread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
            mHandlerThread.start();
            //启动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目录,即第三方应用的安装目录
            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保护
            mDrmAppPrivateInstallDir = new File(dataDir, "app-private");

            //构造UserManagerService,mPackages是一个Map,存储了Package
            sUserManager = new UserManagerService(context, this,mInstallLock, mPackages);
  
            //读取设置的权限
            ArrayMap permConfig= systemConfig.getPermissions();
            for (int i=0; i libConfig = systemConfig.getSharedLibraries();
            for (int i=0; i

首先扫描了各类型的安装目录,以备后面程序的安装,我们看到构造UserManagerService对象时,传入了mPackages对象,它是一个Map,保存了安装应用的信息,在readLPw传给mSettings进行读取恢复,如果读取解析失败,则重新解析安装并保存以便下一次启动恢复,readLPw读取,而后面的mSettings.writeLPr则是保存。

那么我们看readLPw是如何来解析安装包数据的。先看mSettings的构造方法。

    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保存了上一次的应用安装信息
        mSettingsFilename = new File(mSystemDir, "packages.xml");
        //对mSettingsFilename的备份
        mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");
        //存储包名
        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");
    }

安装包的信息数据是通过xml来进行存储的,由代码知道,源文件和备份文件完整的相对路径为dada/dada/system/xxx.xml。这里对缓存又进行了一次备份,是起到了双次检测的效果。

  //读取上一次保存的应用安装信息
  boolean readLPw(PackageManagerService service, List 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();//开始pull解析
            parser.setInput(str, null);

      

对缓存文件的检测可以分为3种情况:

  • 如果备份存在,源文件也存在,则读取备份文件并且删除源文件,后面writeLPr会重新保存一份新的源文件;
  • 如果备份不存在,源文件不存在,则恢复上一次失败,结束事件;
  • 如果备份不存在,源文件存在,则读取源文件;

文件读取成功,会构造XmlPullParser 对象来解析xml文件。xml保存了上一次安装的许多数据,这里贴些关键的标签,其中package和shared-user标签,保存了应用程序和LInux用户Id相关的信息。

            int type;
            while ((type = parser.next()) != XmlPullParser.START_TAG
                    && type != XmlPullParser.END_DOCUMENT) {
                ;
            }
            //开始标签
            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;
            }
            //开始解析
            int outerDepth = parser.getDepth();
            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
                if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
                    continue;
                }

                String tagName = parser.getName();
                //以包名为根标签,保存了每个应用上次安装的信息
                if (tagName.equals("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为根标签保存了一个应用的完整信息,所以,readPackageLPw从package标签开始解析包数据。

   //解析package标签
    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,应用包名
            realName = parser.getAttributeValue(null, "realName");
            idStr = parser.getAttributeValue(null, "userId");//独立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) { //名字为空,抛出异常,说明包名必须有
                PackageManagerService.reportSettingsProblem(Log.WARN,  "Error in package manager settings:  has no name at "
                                + parser.getPositionDescription());
            } else if (codePathStr == null) {
                PackageManagerService.reportSettingsProblem(Log.WARN, "Error in package manager settings:  has no codePath at "
                                + parser.getPositionDescription());
            } else if (userId > 0) {//说明上一次分配了一个独立的Linux用户Id
                //则将上一次分配的Linux用户Id保存下来
                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) {//说明上一次没有分配独立的Linux用户Id,而是和其他程序共享一个Linux用户Id
                userId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0;
                if (userId > 0) {
                    //PendingPackage描述一个还未确定的应用程序
                    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;
                    //将这个描述对象保存在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分为共享和独立,如果此应用userId > 0,说明上一次分配了一个独立的Linux用户id,则会调用addPackageLPw将独立id保存下来,如果不是独立的,而sharedIdStr !=null,则说明是分配的是共享id,则暂时不保留这个id,因为这可能是一个无效的id,mPendingPackages会将此类应用保存起来,表示还未确定的应用。要等到解析完所有安装信息后才能确定。

接着看addPackageLPw是如何将Linux用户id保存下来的。

  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);
        //存在这个包名的应用PackageSetting
        if (p != null) {
            //Linux用户id和appid相同,说明已分配过,直接返回PackageSetting
            if (p.appId == uid) {
                return p;
            }
            PackageManagerService.reportSettingsProblem(Log.ERROR, "Adding duplicate package, keeping first: " + name);
            return null;
        }
        //不存在说明是第一次安装,新建一个PackageSetting对象
        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;
    }

每个应用程序的安装信息都是用PackageSetting对象来存储,并以包名为key,保存在mPackages这个HashMap中,如果程序已安装过,直接从mPackages获取。如果第一次安装,将构建一个PackageSetting对象来保存信息。

addUserIdLPw方法用于在系统中保留分配的uid,如果保留成功,则将PackageSetting保存到mPackages中,说明PMS已经为此应用分配了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;//当前申请的角标
            while (index >= N) {//是否超过列表的角标
                mUserIds.add(null);//将中间的置为null
                N++;
            }
            //这个id被用了,保留失败
            if (mUserIds.get(index) != null) {
                PackageManagerService.reportSettingsProblem(Log.ERROR,
                        "Adding duplicate user id: " + uid
                        + " name=" + name);
                return false;
            }
            //以pid为角标,添加应用程序的PackageSetting
            mUserIds.set(index, obj);
        } else {
          //10000以下给特权用户使用
            if (mOtherUserIds.get(uid) != null) {
                PackageManagerService.reportSettingsProblem(Log.ERROR,
                        "Adding duplicate shared id: " + uid
                        + " name=" + name);
                return false;
            }
            mOtherUserIds.put(uid, obj);
        }
        return true;
    }

用户类型的pid都在10000到19999之间,说明Android系统只分配9999个给用户类型的程序,小于10000保留给特权用户使用,但这些id也可以通过共享的方式给用户程序使用。独立用户的流程分配完成,我们回到xml解析,看标签为shared-user的共享用户,它紧接着调用了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"))) {//是给系统类型的应用还是用户类型的应用
                pkgFlags |= ApplicationInfo.FLAG_SYSTEM;//系统用户为1
            }
            //name,userId必须存在
            if (name == null) {
                PackageManagerService.reportSettingsProblem(Log.WARN,
                        "Error in package manager settings:  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 {
                //保存这个共享用户的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());
        }
        ;

        ......
    }

这里有三个元素,name、userId和system,前两个是共享Linux用户的名称和id,最后一个则用于描述此程序是系统类型,还是用户类型的。
和独立用户流程相似,共享用户是通过addSharedUserLPw方法,保存userId为Linux用户id的。

 //保存共享用户的id
    SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags) {
        //SharedUserSetting即一个共享用户对象
        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);//保存起来
            return s;
        }
        return null;
    }

独立用户使用PackageSetting对象来描述应用的安装信息,而共享用户则使用SharedUserSetting ,分配和安装成功的用户同样保存到一个Map中,即mSharedUsers。

同样,需要调用addUserIdLPw方法,来判断这个id是否在系统规定的范围,这个方法上面已做了分析。这个时候PMS通过Settings就已将上一次应用程序的安装信息恢复完成了。我们回头看到PMS的构造方法,它会扫描各个安装目录。

//Environment.getRootDirectory()为system目录
            //获取/system/famework目录,保存的是资源型的文件,不包含执行代码
            File frameworkDir = new File(Environment.getRootDirectory(), "framework");
            
            //加载framework资源
            alreadyDexOpted.add(frameworkDir.getPath() + "/framework-res.apk");
            
            //加载核心库
            alreadyDexOpted.add(frameworkDir.getPath() + "/core-libart.jar");
           
            String[] frameworkFiles = frameworkDir.list();
            if (frameworkFiles != null) {
              
                for (String dexCodeInstructionSet : dexCodeInstructionSets) {
                    for (int i=0; i

显然scanDirLI是最关键的方法,通过扫描5个安装目录,判断是否存在以".apk"为后缀的文件,如果存在则对文件进行解析。

   //扫描安装路径
    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文件进行解析
        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方法用来解析.apk文件,解析完会返回一个Package对象pkg给调用者。

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

        //设置解析标志mDefParseFlags默认为0
        parseFlags |= mDefParseFlags;
        //创建一个包解析器
        PackageParser pp = new PackageParser();
        pp.setSeparateProcesses(mSeparateProcesses);
        pp.setOnlyCoreApps(mOnlyCore);
        pp.setDisplayMetrics(mMetrics);

        if ((scanFlags & SCAN_TRUSTED_OVERLAY) != 0) {
            parseFlags |= PackageParser.PARSE_TRUSTED_OVERLAY;
        }
        //定义包对象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;
    }

这里分两步看,第一步是创建PackageParser解析器,通过parsePackage方法,将apk文件解析成Package对象;第二步是使用另一个重载方法scanPackageLI来处理这个Package并返回。我们先看第一步,进入PackageParser这个类的parsePackage方法。

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

如果传入的是一个目录文件,被拆分成多个apk,由一个base APK和一个或多个split APK,称为Cluster,单个称为Monolithic。

两者解析流程差别不大,我们以parseMonolithicPackage为例分析。

 @Deprecated
    public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
        //是否核心应用
        if (mOnlyCoreApps) {
          //轻量级解析
            final PackageLite lite = parseMonolithicPackageLite(apkFile, flags);
            if (!lite.coreApp) {
                throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
                        "Not a coreApp: " + apkFile);
            }
        }
        //构建AssetManager
        final AssetManager assets = new AssetManager();
        try {
            //开始解析
            final Package pkg = parseBaseApk(apkFile, assets, flags);
            pkg.codePath = apkFile.getAbsolutePath();
            return pkg;
        } finally {
            IoUtils.closeQuietly(assets);
        }
    }

轻量级解析是因为解析apk是复杂耗时的操作,这里的逻辑并不需要所有的信息,coreApp指的是AndroidManifest中属性coreApp值为true。继续看解析方法parseBaseApk,注意它接收了一个AssetManager 对象。

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);
        //构建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);
            //打开manifest,构造解析器
            parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);

            final String[] outError = new String[1];
            //调用重载方法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,通过重载方法parseBaseApk来解析。因为解析标签很多,所以代码非常长,这里贴部分作为示例。

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

        //根据包名构建Package对象,将解析manifest后的信息存到这个对象中
        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);//版本号
        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] = " 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标签
            if (tagName.equals("application")) {
                if (foundApp) {
                    if (RIGID_PARSER) {
                        //一个xml只能包含一个标签
                        outError[0] = " has more than one ";
                        mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                        return null;
                    } else {
                        Slog.w(TAG, " has more than one ");
                        XmlUtils.skipCurrentTag(parser);
                        continue;
                    }
                }

                foundApp = true;
                //解析Application标签
                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] = " does not specify a target package";
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return null;
                }
                if (pkg.mOverlayPriority < 0 || pkg.mOverlayPriority > 9999) {
                    outError[0] = " 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;
                }
            //权限
            } else if (tagName.equals("uses-permission")) {
                if (!parseUsesPermission(pkg, res, parser, attrs, outError)) {
                    return null;
                }

我们看到parseBaseApplication开始解析application标签,它同样非常长。

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

        //标签属性
        TypedArray sa = res.obtainAttributes(attrs,
                com.android.internal.R.styleable.AndroidManifestApplication);

        //应用名
        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();
        }

        //应用图标等
        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;
        //循环解析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添加到管理的列表当中
                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);

我们看到包名、应用名还有4大组件都被解析出来了。这里注意到有个owner,它是在parseBaseApk里根据包名生成的Package对象,Manifest标签解析后的数据都存在此对象中。

Package是PackageParser解析器的内部类,Package用了四个列表分别保存四大组件。

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 permissions = new ArrayList(0);
        public final ArrayList permissionGroups = new ArrayList(0);
        //保存四大组件
        public final ArrayList activities = new ArrayList(0);
        public final ArrayList receivers = new ArrayList(0);
        public final ArrayList providers = new ArrayList(0);
        public final ArrayList services = new ArrayList(0);

到这里第一步就完成了,得到一个Package对象,它包含了Manifest的所有信息。如上面所提,第二步是调用重载的scanPackageLI方法,解析这个Package。

我们先看下PMS的5个成员变量。

//保存已安装的程序
 final HashMap mPackages =
            new HashMap();

 //保存每个应用的Activity节点,一个应用一个节点,一个节点用一个HashMap存了改应用的所有activity
    final ActivityIntentResolver mActivities =
            new ActivityIntentResolver();
    
    //保存所有receiver节点
    final ActivityIntentResolver mReceivers =
            new ActivityIntentResolver();

    //保存所有Service节点
    final ServiceIntentResolver mServices = new ServiceIntentResolver();
 
    //保存所有Provider节点
    final ProviderIntentResolver mProviders = new ProviderIntentResolver();

这些属性类型都采用了自定义类去保存相关信息,从类名上看,类结构都很相似。顺便提一下,我们通过getPackageManager()方法获得的PackageManager对象,只是PackageManagerService的客户端,PackageManager的子类ApplicationPackageManager,显然该类存在于用户空间中。关于跨进程通讯可以看的分析。

系统中所有已安装的程序都用Package来描述,而这些Package就保存在mPackages 中,而每一个应用的四大组件都分别保存在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进行扫描
            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) {
            //根据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 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> 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

对Package的扫描主要任务是分配Linux用户id,以及将Package和四大组件分别添加到上面说的5成员变量中,前面说过共享用户都使用一个SharedUserSetting 对象来描述,因此根据name去mSharedUsers中查找,如果不存在则新建。

 SharedUserSetting getSharedUserLPw(String name,
            int pkgFlags, boolean create) {
        SharedUserSetting s = mSharedUsers.get(name);
        //不存在根据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;
    }

此时PMS便为应用分配好了Linux用户id,并把它们缓存到成员变量中。但成员数据会随着类的回收而销毁,前面分析时我们知道,这些数据对应的信息会保存到packages.xml和packages-backup.xml中,以便下次启动恢复,这个保存操作也在PMS构造函数执行,我们再次回到PMS的构造方法。

            .....

          //权限设置,检查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;
            //分配权限
            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();
     
            //将上面读取到的信息保存成配置,以便下次启动恢复
            mSettings.writeLPr();

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

            mRequiredVerifierPackage = getRequiredVerifierLPr();
        } 
        } 

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

我们再次进到Settings类,看writeLPr方法是如何保存的。

//保存上一次的应用安装信息
    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 {
            //初始化文件的一些标签
            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");//包标签

            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");//共享用户标签
                serializer.attribute(null, ATTR_NAME, usr.name);
                serializer.attribute(null, "userId",Integer.toString(usr.userId));//独立用户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 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);
            //包标签结束packages
            serializer.endTag(null, "packages");
            //文档标签结束
            serializer.endDocument();

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

可以看到,每个程序都是以package标签为单位来存储的,name表示了包名,userId和sharedUserId描述分配给程序的独立Linux用户id和共享Linux用户id,这两个id是互斥的,即要么为独立用户要么为共享用户。

这一步完成,PMS就将程序所使用的Linux用户id保存起来了,当重装一个应用程序时,它所对应的Linux用户id是不变的。

Android系统是类Linux系统,根据Linux用户id来防止程序的篡改和破坏,程序的进程是AMS向Zygote进程请求创建的,而Zygote正是根据这个id来创建进程。我们可以看下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子进程孵化ActivityThread进程后,调用main方法
            if (entryPoint == null) entryPoint = "android.app.ActivityThread";
            checkTime(startTime, "startProcess: asking zygote to start proc");
            //开启进程
            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开启新进程,在调用的过程会根据第3、4、5个参数来创建进程。

到此,应用程序的安装过程便分析完毕,这个分析过程是从系统启动时开始的,如果一个程序在系统启动后在安装,它的入口会是PMS的installPackage,最终也会执行scanPackageLI,其流程是相似的。

程序安装完成后,我们看到桌面会生成一个图标,这一流程将在下一篇<>中讲解。

你可能感兴趣的:(App安装过程)