Android -- PackageManagerService初始化分析

Android — PackageManagerService初始化分析

PackageManagerService主要负责Android系统的应用管理,它提供对各种APK文件的安装、卸载、优化和查询服务。PackageManagerService在系统启动时会扫描所有存在的APK文件和Jar包信息,并将它们读取、保存起来;这样系统在运行时,就能很快的查询到各种应用和相关组件的信息。扫描时,如果得到的文件需要优化,它还会执行优化工作。

我们知道,Android中存在两类应用:系统应用和普通应用。系统应用一般都指系统预置的应用,它们会存放在/system/目录下的应用存放路径中:/system/app/和/system/priv-app/。/priv-app/目录从4.4版本开始出现,它存放的系统应用功能较为底层,如SystemUI,对外提供的都是一些基础服务等。普通应用一般是指用户手动安装的应用,它们一般会被安装到/data/app/目录下。而系统目录/data/dalvik-cache下保存的是apk文件和jar包的odex版本。odex是一种优化的格式,相对apk中的dex格式,它执行更快。

由于系统应用很可能会涉及到系统内部的服务和关键功能,所以它们一般情况下是不能被删除的,但是可以被升级。升级系统应用的手段就是安装一个包名相同、但版本更高的应用在/data/app/下。Android系统为了区分这种升级关系,内部维护了一个package.xml文件,它会记录系统每次开机时,当前所有APK的关键信息;如前面介绍的系统应用升级的情况,在packages.xml下,就会用一个特殊的标签<updated-package>来标识这种被升级的系统应用。下次系统再次启动时,还会再扫描系统中的APK信息,将当前扫描的信息与上一次APK扫描的信息(存放在packages.xml中)进行对比,就能得知APK的变化信息;系统再根据这些变化信息来做具体的APK的升级、删除等处理。

当然,应用升级还有一种更复杂的情况:掺杂了”original-package”属性的APK文件的升级,这种情况虽然特殊,但对应用升级本身来说并没有什么影响。

PackageManageService本身的实现很复杂,它所提供的服务也较为重要。这里我们分析的侧重点还是它的构造过程,特别是这个过程中涉及到的APK扫描、安装流程。只有先了解PackageManagerService的大致、基本的工作流程,我们才好去更深入地分析其他更高级、更复杂的特性。

PackageManagerService对外提供的初始化接口是main()函数:

    public static PackageManagerService main(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) {
        // Self-check for initial settings.
        PackageManagerServiceCompilerMapping.checkProperties();

        PackageManagerService m = new PackageManagerService(context, installer,
                factoryTest, onlyCore);
        m.enableSystemUserPackages();
        ServiceManager.addService("package", m);
        return m;
    }

处理很清晰:创建PackageManagerService实例,并将它发布到系统中。所以重要的工作,就是去分析它的构造函数了。

PackageManagerService的构造函数实现复杂、代码较多,我们分段来分析其中的主要实现部分。

   public PackageManagerService(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore)

参数installer是与守护进程installd交互的实例,主要负责APK、jar包的安装、优化等内容;factoryTest决定当前是否是工厂测试模式,这里我们假设为false;onlyCore决定当前是否只处理系统应用,我们也假设为false。

我们首先看PackageManagerService()函数的第一块重要内容:

       mContext = context;
        mFactoryTest = factoryTest;
        mOnlyCore = onlyCore;//是否只处理系统应用,通常为false
        mMetrics = new DisplayMetrics();//DisplayMetrics实例存储屏幕显示的信息

		//添加几种SharedUserId对象到Settings中,sharedUserId属性相同的package可以运行在同一个进程中,或者相互读取资源
		//Settings可以看做是一个数据动态管理类,它主要会管理packages.xml文件中的信息
		//PackageManagerService::mPackages以包名为key,以包的实例为value;保存扫描的apk信息
        mSettings = new Settings(mPackages);
        mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID/*系统进程的Uid值*/,
                ApplicationInfo.FLAG_SYSTEM/*系统App的标志*/, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED/*是否具有特权*/);
        mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.log", LOG_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_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;
        }

        mInstaller = installer;//应用安装对象,与installd交互
        mPackageDexOptimizer = new PackageDexOptimizer(installer, mInstallLock, context,
                "*dexopt*");//对应用进行dexopt优化的辅助类
        mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());

        mOnPermissionChangeListeners = new OnPermissionChangeListeners(
                FgThread.get().getLooper());

        getDefaultDisplayMetrics(context, mMetrics);//初始化DisplayMetrics对象

		//通过SystemConfig读取系统的feature、permession等配置,并初始化mGlobalGids/mSystemPermissions/mAvailableFeatures等成员
        SystemConfig systemConfig = SystemConfig.getInstance();
        mGlobalGids = systemConfig.getGlobalGids();
        mSystemPermissions = systemConfig.getSystemPermissions();
        mAvailableFeatures = systemConfig.getAvailableFeatures();

        mProtectedPackages = new ProtectedPackages(mContext);

除了一些PackageManagerService(PMS)中成员变量的创建、赋值操作外,较为重要的处理跟Settings、SystemConfig这两个类相关。

Settings类可以看做是一个数据封装类,它动态地保存了系统解析APK时的一些应用信息。首先创建Settings实例,我们传入了PakcageManagerService::mPacages字段。mPackages字段的定义如下:

    // Keys are String (package name), values are Package.  This also serves
    // as the lock for the global state.  Methods that must be called with
    // this lock held have the prefix "LP".
    @GuardedBy("mPackages")
    final ArrayMap<String, PackageParser.Package> mPackages =
            new ArrayMap<String, PackageParser.Package>();

它是一个集合变量,用于保存PMS当前扫描过程中所有经过处理地APK信息。它以APK的包名键,以代表一个APK(package)对象的代码封装类Package实例为值,来保存信息。

Settings类的构造函数如下:

    Settings(Object lock) {
        this(Environment.getDataDirectory(), lock);
    }

    Settings(File dataDir, Object lock) {
        mLock = lock;

        mRuntimePermissionsPersistence = new RuntimePermissionPersistence(mLock);

        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和pacages-stopped.xml内容之前,会先对它们进行备份(backup标识);
		//如果对文件的写入操作成功,则会删除backup文件,并用写成功后的文件;如果写的时候,发生了异
		//常,系统再次读取这些文件时,发现备份文件还在,则会读取备份文件的内容;因为这时,原文件可能已经损坏了.
        mSettingsFilename = new File(mSystemDir, "packages.xml");//记录系统中所有安装应用的信息,如签名/权限和其他一些基本信息
        mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");//packages.xml的备份信息
        mPackageListFilename = new File(mSystemDir, "packages.list");//保存普通应用的数据目录和uid信息
        FileUtils.setPermissions(mPackageListFilename, 0640, SYSTEM_UID, PACKAGE_INFO_GID);

        final File kernelDir = new File("/config/sdcardfs");
        mKernelMappingFilename = kernelDir.exists() ? kernelDir : null;

        // Deprecated: Needed for migration
        mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");//记录系统中被强制停止运行的App信息,如有App被强制停止运行,会将应用的一些信息记录到该文件中
        mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");//packages-stopped.xml的备份信息
    }

Settings的构造函数的主要工作就是就是建立与某些系统配置文件、目录的关联。首先,它会创建指向/data/system/目录的File实例,这个目录下会保存很多系统文件。其次,就是创建/data/system/目录下的某些.xml文件或其他文件的File实例。这里主要涉及到5个文件,下面一一介绍:

  1. packages.xml:记录了系统中所有安装应用的基本信息,如果签名、权限等等
  2. packages-backup.xml:packages.xml文件的备份
  3. packages-stopped.xml:记录系统中所有被强制停止运行的应用的信息(如我们在系统设置中,选择某个应用,并将它强制停止)
  4. packages-stopped-back.xml:packages-stopped.xml文件的备份
  5. packages.list:保存了应用的数据目录和UID等信息

我们注意到,上面的介绍中涉及到了两个back-up文件,它们是做什么的呢?原来,Android系统在修改packages.xml、packages-stopped.xml之前,会先对它们进行备份。

当对它们的修改操作正常完成,则会删掉之前建立的备份文件。如果,在修改过程中系统出现问题重启了,会再次去读取这两个文件;如果此时发现它们的备份文件还存在,则说明上一次对两文件的修改操作发生了异常,这两个文件的内容可能已经不准确了;这时,系统会去使用之前备份的文件的内容。这可以看做是Android系统的一种容错机制。

在创建完了上面涉及到的系统文件的File实例时,Settings的构造工作就结束了。

创建完Settings实例后,接着会调用addSharedUserLPw()函数,它的实现如下:

	//以要添加的sharedUserId属性为key,创建的SharedUserSetting对象为value;保存到Settings::mSharedUsers集合中
    SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags, int pkgPrivateFlags) {
        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, pkgPrivateFlags);
        s.userId = uid;
        if (addUserIdLPw(uid, s, name)) {
            mSharedUsers.put(name, s);
            return s;
        }
        return null;
    }
	//Settings::mUserIds和Settings::mOtherUserIds可以让我们通过Uid相关的信息获取某个SharedUserSetting对象;这样获取较HashMap更快
    private boolean addUserIdLPw(int uid, Object obj, Object name) {
        if (uid > Process.LAST_APPLICATION_UID) {
            return false;
        }

        if (uid >= Process.FIRST_APPLICATION_UID) {
            int N = mUserIds.size();
            final int index = uid - Process.FIRST_APPLICATION_UID;
            while (index >= N) {
                mUserIds.add(null);
                N++;
            }
            if (mUserIds.get(index) != null) {
                PackageManagerService.reportSettingsProblem(Log.ERROR,
                        "Adding duplicate user id: " + uid
                        + " name=" + name);
                return false;
            }
            mUserIds.set(index, obj);
        } else {
            if (mOtherUserIds.get(uid) != null) {
                PackageManagerService.reportSettingsProblem(Log.ERROR,
                        "Adding duplicate shared id: " + uid
                                + " name=" + name);
                return false;
            }
            mOtherUserIds.put(uid, obj);
        }
        return true;
    }

addSharedUserLPw()函数的作用是添加几种SharedUserId到SharedUserSetting对象中。我们知道,sharedUserId属性相同的package可以运行在同一个进程,或者相互读取资源。这里添加了6中SharedUserID,供后续查找使用。SharedUserSetting描述具有相同sharedUserId的应用信息,它内部会保存APK的信息实例(以PackageSetting封装)。我们看下SharedUserSettings涉及到的一些类型:

《Android -- PackageManagerService初始化分析》

从图中所示的整个类型关系,我们可以看到后续要经常接触的PackageParser.Package、PackageSetting等类型,以及它们的基本含义。

PackageParser.Package是我们解析APK阶段经常碰到的封装APK信息的类型,PackageSetting类型是对packages.xml中<package>系列标签的APK信息的封装。它们互相组合,就能基本描述APK中涉及的所有重要信息。

另外,Settings类会负责读取上一次启动后形成的packages.xml文件,并解析内容,将各类信息整合封装到它内部的几个集合对象中;这部分内容稍后再读取packages.xml文件时会介绍。

SystemConfig是一个工具类,它负责读取系统中全局的某些权限、特性信息。SystemConfig的初始化是:

	//单例设计模式
    public static SystemConfig getInstance() {
        synchronized (SystemConfig.class) {
            if (sInstance == null) {
                sInstance = new SystemConfig();
            }
            return sInstance;
        }
    }
    SystemConfig() {//通过readPermissions()读取指定/system/etc/、/oem/etc/等目录下的permission xml文件,解析其中的内容
        // Read configuration from system
        readPermissions(Environment.buildPath(
                Environment.getRootDirectory(), "etc", "sysconfig"), ALLOW_ALL);
        // Read configuration from the old permissions dir
        readPermissions(Environment.buildPath(
                Environment.getRootDirectory(), "etc", "permissions"), ALLOW_ALL);
        // Allow ODM to customize system configs around libs, features and apps
        int odmPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_APP_CONFIGS;
        readPermissions(Environment.buildPath(
                Environment.getOdmDirectory(), "etc", "sysconfig"), odmPermissionFlag);
        readPermissions(Environment.buildPath(
                Environment.getOdmDirectory(), "etc", "permissions"), odmPermissionFlag);
        // Only allow OEM to customize features
        readPermissions(Environment.buildPath(
                Environment.getOemDirectory(), "etc", "sysconfig"), ALLOW_FEATURES);
        readPermissions(Environment.buildPath(
                Environment.getOemDirectory(), "etc", "permissions"), ALLOW_FEATURES);
    }

从它的实例化代码可以看到,SystemConfig采用了单例设计模式,在创建实例时,会去读取/system/ec/、/oem/etc/等目录下的配置文件,这部分由readPermissions()函数完成。

这里先看下我从模拟器中看到的/system/ect/permissions/目录下的配置文件列表,并其中的一些文件为例,来分析配置文件的解析流程。

/system/ect/permissions/目录中的文件列表如下:

《Android -- PackageManagerService初始化分析》

我们列举一些其中的文件的内容,来大致看下配置文件的内容:

1、android.software.live_wallpaper.xml:

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
  
          http://www.apache.org/licenses/LICENSE-2.0
  
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->

<!-- This feature should be defined for devices that support live wallpapers.
     There are minimum hardware requirements to be able to support this
     feature: robust multiple GL context support, fast enough CPU, enough
     RAM to allow the wallpaper to be running all of the time. -->
<permissions>
    <feature name="android.software.live_wallpaper" />
</permissions>

2、platefrom.xml:

<permissions>

    <!-- ================================================================== -->
    <!-- ================================================================== -->
    <!-- ================================================================== -->

    <!-- The following tags are associating low-level group IDs with
         permission names.  By specifying such a mapping, you are saying
         that any application process granted the given permission will
         also be running with the given group ID attached to its process,
         so it can perform any filesystem (read, write, execute) operations
         allowed for that group. -->

    <permission name="android.permission.BLUETOOTH_ADMIN" >
        <group gid="net_bt_admin" />
    </permission>

    <permission name="android.permission.BLUETOOTH" >
        <group gid="net_bt" />
    </permission>

......

    <!-- The following tags are assigning high-level permissions to specific
         user IDs.  These are used to allow specific core system users to
         perform the given operations with the higher-level framework.  For
         example, we give a wide variety of permissions to the shell user
         since that is the user the adb shell runs under and developers and
         others should have a fairly open environment in which to
         interact with the system. -->

    <assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="media" />
    <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="media" />
    <assign-permission name="android.permission.WAKE_LOCK" uid="media" />
    <assign-permission name="android.permission.UPDATE_DEVICE_STATS" uid="media" />
    <assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="media" />

    <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="graphics" />

    <!-- This is a list of all the libraries available for application
         code to link against. -->

    <library name="android.test.runner"
            file="/system/framework/android.test.runner.jar" />
    <library name="javax.obex"
            file="/system/framework/javax.obex.jar"/>

......

</permissions>

我们看到了配置文件中的几种标签格式。列出的第一段配置文件信息,它里面只是声明了一些<feature>特性,而这也是除了plateform.xml文件之外的其他文件中所声明的信息。这些feature特性反映出了当前设备所支持的一些硬件功能等。

而plateform.xml中出现的标签种类则较为多样,它们的含义分别是:

  • <permission >标签:把属性name所描述的权限赋予给<group>标签中属性gid所表示的用户组
  • <assign-permission>标签:把属性name所描述的权限赋予给uid属性所表示的用户
  • <library>标签:除framework中动态库以外的,所有系统会自动加载的动态库

了解完这些内容后,我们接着去看这些xml文件的解析过程:

    void readPermissions(File libraryDir, int permissionFlag) {
        // Read permissions from given directory.
        if (!libraryDir.exists() || !libraryDir.isDirectory()) {//只读取存在的目录
            if (permissionFlag == ALLOW_ALL) {
                Slog.w(TAG, "No directory " + libraryDir + ", skipping");
            }
            return;
        }
        if (!libraryDir.canRead()) {//目录不可读,则直接退出
            Slog.w(TAG, "Directory " + libraryDir + " cannot be read");
            return;
        }

        // Iterate over the files in the directory and scan .xml files
        File platformFile = null;
        for (File f : libraryDir.listFiles()) {
            // We'll read platform.xml last
            if (f.getPath().endsWith("etc/permissions/platform.xml")) {//最后读取platform.xml
                platformFile = f;
                continue;
            }

            if (!f.getPath().endsWith(".xml")) {//读取.xml文件
                Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring");
                continue;
            }
            if (!f.canRead()) {
                Slog.w(TAG, "Permissions library file " + f + " cannot be read");
                continue;
            }

            readPermissionsFromXml(f, permissionFlag);
        }

        // Read platform permissions last so it will take precedence
        if (platformFile != null) {//读取platform.xml
            readPermissionsFromXml(platformFile, permissionFlag);
        }
    }

从代码流程可知,最后才会去解析plateform.xml;实际负责解析工作的函数是readPermissionsFromXml(),它的处理如下:

	/*
	*解析的一般的.xml文件中,大多只是定义了feature名称,来描述某个设备应该支持的一些硬件特性,如蓝牙等;
	*
	*platform.xml中,则定义了一些权限授予、动态库信息.其中,涉及的主要标签有:
	*
	*<permission>表示把描述的权限赋予<group>中的gid属性表示的用户组.
	*
	*<assign-permission>表示把描述的属性赋予其属性uid表示的用户.
	*
	*<library>表示出了framework中的动态库以外,系统将为应用自动加载的动态库.
	*
	*/
    private void readPermissionsFromXml(File permFile, int permissionFlag) {
        FileReader permReader = null;
        try {
            permReader = new FileReader(permFile);
        } catch (FileNotFoundException e) {
            Slog.w(TAG, "Couldn't find or open permissions file " + permFile);
            return;
        }

        final boolean lowRam = ActivityManager.isLowRamDeviceStatic();

        try {
            XmlPullParser parser = Xml.newPullParser();
            parser.setInput(permReader);

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

            if (type != parser.START_TAG) {
                throw new XmlPullParserException("No start tag found");
            }

            if (!parser.getName().equals("permissions") && !parser.getName().equals("config")) {
                throw new XmlPullParserException("Unexpected start tag in " + permFile
                        + ": found " + parser.getName() + ", expected 'permissions' or 'config'");
            }

            boolean allowAll = permissionFlag == ALLOW_ALL;
            boolean allowLibs = (permissionFlag & ALLOW_LIBS) != 0;
            boolean allowFeatures = (permissionFlag & ALLOW_FEATURES) != 0;
            boolean allowPermissions = (permissionFlag & ALLOW_PERMISSIONS) != 0;
            boolean allowAppConfigs = (permissionFlag & ALLOW_APP_CONFIGS) != 0;
            while (true) {
                XmlUtils.nextElement(parser);
                if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
                    break;
                }

                String name = parser.getName();
                if ("group".equals(name) && allowAll) {//解析<group>标签gid属性的值,得到的值存放在mGlobalGids数组;
                    String gidStr = parser.getAttributeValue(null, "gid");
                    if (gidStr != null) {
                        int gid = android.os.Process.getGidForName(gidStr);
                        mGlobalGids = appendInt(mGlobalGids, gid);
                    } else {
                        Slog.w(TAG, "<group> without gid in " + permFile + " at "
                                + parser.getPositionDescription());
                    }

                    XmlUtils.skipCurrentTag(parser);
                    continue;
                } else if ("permission".equals(name) && allowPermissions) {//解析<permission>标签,得到的值存放在mPermissions集合中
                    String perm = parser.getAttributeValue(null, "name");
                    if (perm == null) {
                        Slog.w(TAG, "<permission> without name in " + permFile + " at "
                                + parser.getPositionDescription());
                        XmlUtils.skipCurrentTag(parser);
                        continue;
                    }
                    perm = perm.intern();
                    readPermission(parser, perm);

                } else if ("assign-permission".equals(name) && allowPermissions) {//解析<assign-permission>标签,得到的值存放在mSystemPermissions
                    String perm = parser.getAttributeValue(null, "name");
                    if (perm == null) {
                        Slog.w(TAG, "<assign-permission> without name in " + permFile + " at "
                                + parser.getPositionDescription());
                        XmlUtils.skipCurrentTag(parser);
                        continue;
                    }
                    String uidStr = parser.getAttributeValue(null, "uid");
                    if (uidStr == null) {
                        Slog.w(TAG, "<assign-permission> without uid in " + permFile + " at "
                                + parser.getPositionDescription());
                        XmlUtils.skipCurrentTag(parser);
                        continue;
                    }
                    int uid = Process.getUidForName(uidStr);
                    if (uid < 0) {
                        Slog.w(TAG, "<assign-permission> with unknown uid \""
                                + uidStr + "  in " + permFile + " at "
                                + parser.getPositionDescription());
                        XmlUtils.skipCurrentTag(parser);
                        continue;
                    }
                    perm = perm.intern();
                    ArraySet<String> perms = mSystemPermissions.get(uid);
                    if (perms == null) {
                        perms = new ArraySet<String>();
                        mSystemPermissions.put(uid, perms);
                    }
                    perms.add(perm);
                    XmlUtils.skipCurrentTag(parser);

                } else if ("library".equals(name) && allowLibs) {//解析<library>标签,得到的值存放在mSharedLibraries
                    String lname = parser.getAttributeValue(null, "name");
                    String lfile = parser.getAttributeValue(null, "file");
                    if (lname == null) {
                        Slog.w(TAG, "<library> without name in " + permFile + " at "
                                + parser.getPositionDescription());
                    } else if (lfile == null) {
                        Slog.w(TAG, "<library> without file in " + permFile + " at "
                                + parser.getPositionDescription());
                    } else {
                        //Log.i(TAG, "Got library " + lname + " in " + lfile);
                        mSharedLibraries.put(lname, lfile);
                    }
                    XmlUtils.skipCurrentTag(parser);
                    continue;

                } else if ("feature".equals(name) && allowFeatures) {//解析<feature>标签,得到的值存放在mAvailableFeatures,表示系统的某些特性
                    String fname = parser.getAttributeValue(null, "name");
                    int fversion = XmlUtils.readIntAttribute(parser, "version", 0);
                    boolean allowed;
                    if (!lowRam) {
                        allowed = true;
                    } else {
                        String notLowRam = parser.getAttributeValue(null, "notLowRam");
                        allowed = !"true".equals(notLowRam);
                    }
                    if (fname == null) {
                        Slog.w(TAG, "<feature> without name in " + permFile + " at "
                                + parser.getPositionDescription());
                    } else if (allowed) {
                        addFeature(fname, fversion);
                    }
                    XmlUtils.skipCurrentTag(parser);
                    continue;

                } /*......*/ else {
                    XmlUtils.skipCurrentTag(parser);
                    continue;
                }
            }
        } catch (XmlPullParserException e) {
            Slog.w(TAG, "Got exception parsing permissions.", e);
        } catch (IOException e) {
            Slog.w(TAG, "Got exception parsing permissions.", e);
        } finally {
            IoUtils.closeQuietly(permReader);
        }

        // Some devices can be field-converted to FBE, so offer to splice in
        // those features if not already defined by the static config
        if (StorageManager.isFileEncryptedNativeOnly()) {
            addFeature(PackageManager.FEATURE_FILE_BASED_ENCRYPTION, 0);
            addFeature(PackageManager.FEATURE_SECURELY_REMOVES_USERS, 0);
        }

        for (String featureName : mUnavailableFeatures) {
            removeFeature(featureName);
        }
    }

我们略去了一部分标签的解析过程,只侧重看前面列举出的标签的解析过程。从代码可知,整个解析流程就是一个标准的xml文件的解析过程,没什么特殊的。我们主要关心这些文件解析完,其中的内容是如何存储的。对照代码可知:

  • <group>标签gid属性的值会存放在mGlobalGids数组中;
  • <permission>标签,解析得到的值会存放在mPermissions集合中;
  • <assign-permission>标签解析得到的值会存放在mSystemPermissions中;
  • <library>标签解析得到的值会存放在mSharedLibraries中;

存储数据的字段要么是链表,要么是键值对:

    // Group-ids that are given to all packages as read from etc/permissions/*.xml.
    int[] mGlobalGids;

    // These are the built-in uid -> permission mappings that were read from the
    // system configuration files.
    final SparseArray<ArraySet<String>> mSystemPermissions = new SparseArray<>();

    // These are the built-in shared libraries that were read from the
    // system configuration files.  Keys are the library names; strings are the
    // paths to the libraries.
    final ArrayMap<String, String> mSharedLibraries  = new ArrayMap<>();

    // These are the features this devices supports that were read from the
    // system configuration files.
    final ArrayMap<String, FeatureInfo> mAvailableFeatures = new ArrayMap<>();

SystemConfig解析完这些配置文件后,它的工作也就告一段落了。随后,PackageManagerService会取出SystemConfig解析的这些信息,存放到自己维护的字段中,用于后续处理,如:

  • PackageManagerService::mGlobalGids存储SystemConfig::mGlobalGids的信息
  • PackageManagerService::mSystemPermissions存储SystemConfig::mSystemPermissions的信息
  • PackageManagerService::mAvailableFeatures存储SystemConfig::mAvailableFeatures的信息

SystemConfig::mSharedLibraries中解析的一些系统库的内容,在PackageManagerService做dexopt优化的时候会被用到,最后会被保存到PMS::mSharedLibraries中。

我们接着看PackageManagerService()构造函数中的第二段重要处理代码:

            mHandlerThread = new ServiceThread(TAG,
                    Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
            mHandlerThread.start();
            mHandler = new PackageHandler(mHandlerThread.getLooper());
            mProcessLoggingHandler = new ProcessLoggingHandler();
            Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);

            mDefaultPermissionPolicy = new DefaultPermissionGrantPolicy(this);

			//为data/目录下的某些子目录生成File实例
            File dataDir = Environment.getDataDirectory();
            mAppInstallDir = new File(dataDir, "app"); // data/app 存放第三方应用
            mAppLib32InstallDir = new File(dataDir, "app-lib"); 
            mEphemeralInstallDir = new File(dataDir, "app-ephemeral");
            mAsecInternalPath = new File(dataDir, "app-asec").getPath();
            mDrmAppPrivateInstallDir = new File(dataDir, "app-private"); // data/app-private 存放drm保护的应用

            sUserManager = new UserManagerService(context, this, mPackages);

            // Propagate permission configuration in to package manager.
            //获取SystemConfig中解析到的<permission>标签标识的permission信息,保存到Settings::mPermissions
            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.setGids(perm.gids, perm.perUser);
                }
            }

			//得到除framework之外的系统中的共享库列表,从SystemConfig获取解析到的数据
            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));
            }

            mFoundPolicyFile = SELinuxMMAC.readInstallPolicy();

			//读取packages.xml的内容,并对mSettings::mPackages等成员进行赋值;packages.xml文件中的内容是上一次扫描apk目录的结果
			//当前这一次扫描的结果是保存在PackageManagerService::mPackages列表中
			//对比上次扫描的结果来检查本次扫描到的应用中是否有被升级包覆盖的系统应用,如果有则从PackageManagerService::mPackages中移除;
			//这样,PackageManagerService::mPackages的记录就和mSettings::mPackages的一致了
			//系统最终会将本次apk扫描的结果重新写入packages.xml中
            mFirstBoot = !mSettings.readLPw(sUserManager.getUsers(false));

            // Clean up orphaned packages for which the code path doesn't exist
            // and they are an update to a system app - caused by bug/32321269
            final int packageSettingCount = mSettings.mPackages.size();
            for (int i = packageSettingCount - 1; i >= 0; i--) {//清理那些代码路径不存在的异常package
                PackageSetting ps = mSettings.mPackages.valueAt(i);
                if (!isExternal(ps) && (ps.codePath == null || !ps.codePath.exists())
                        && mSettings.getDisabledSystemPkgLPr(ps.name) != null) {
                    mSettings.mPackages.removeAt(i);
                    mSettings.enableSystemPackageLPw(ps.name);
                }
            }

            if (mFirstBoot) {
                requestCopyPreoptedFiles();
            }

			//设置模块来代替framework-res.apk中缺省的ResolverActivity
            String customResolverActivity = Resources.getSystem().getString(
                    R.string.config_customResolverActivity);
            if (TextUtils.isEmpty(customResolverActivity)) {
                customResolverActivity = null;
            } else {
                mCustomResolverComponentName = ComponentName.unflattenFromString(
                        customResolverActivity);
            }

            long startTime = SystemClock.uptimeMillis();//记录开始扫描时间

            EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
                    startTime);

            // Set flag to monitor and not change apk file paths when
            // scanning install directories.
            final int scanFlags = SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING | SCAN_INITIAL;//设置扫描模式

            final String bootClassPath = System.getenv("BOOTCLASSPATH");//需要系统提前加载的一些jar
            final String systemServerClassPath = System.getenv("SYSTEMSERVERCLASSPATH");

            if (bootClassPath == null) {
                Slog.w(TAG, "No BOOTCLASSPATH found!");
            }

            if (systemServerClassPath == null) {
                Slog.w(TAG, "No SYSTEMSERVERCLASSPATH found!");
            }

            final List<String> allInstructionSets = InstructionSets.getAllInstructionSets();
            final String[] dexCodeInstructionSets =
                    getDexCodeInstructionSets(
                            allInstructionSets.toArray(new String[allInstructionSets.size()]));

            /**
             * Ensure all external libraries have had dexopt run on them.
             */
            if (mSharedLibraries.size() > 0) {//遍历所有系统共享库路径,确保它们进行过dexopt优化
                // NOTE: For now, we're compiling these system "shared libraries"
                // (and framework jars) into all available architectures. It's possible
                // to compile them only when we come across an app that uses them (there's
                // already logic for that in scanPackageLI) but that adds some complexity.
                for (String dexCodeInstructionSet : dexCodeInstructionSets) {
                    for (SharedLibraryEntry libEntry : mSharedLibraries.values()) {
                        final String lib = libEntry.path;
                        if (lib == null) {
                            continue;
                        }

                        try {
                            // Shared libraries do not have profiles so we perform a full
                            // AOT compilation (if needed).
                            int dexoptNeeded = DexFile.getDexOptNeeded(
                                    lib, dexCodeInstructionSet,
                                    getCompilerFilterForReason(REASON_SHARED_APK),
                                    false /* newProfile */);
                            if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
                                mInstaller.dexopt(lib, Process.SYSTEM_UID, dexCodeInstructionSet,
                                        dexoptNeeded, DEXOPT_PUBLIC /*dexFlags*/,
                                        getCompilerFilterForReason(REASON_SHARED_APK),
                                        StorageManager.UUID_PRIVATE_INTERNAL,
                                        SKIP_SHARED_LIBRARY_CHECK);
                            }
                        } catch (FileNotFoundException e) {
                            Slog.w(TAG, "Library not found: " + lib);
                        } catch (IOException | InstallerException e) {
                            Slog.w(TAG, "Cannot dexopt " + lib + "; is it an APK or JAR? "
                                    + e.getMessage());
                        }
                    }
                }
            }

            File frameworkDir = new File(Environment.getRootDirectory(), "framework");// /system/framework/目录下有framework-res.apk

            final VersionInfo ver = mSettings.getInternalVersion();
            mIsUpgrade = !Build.FINGERPRINT.equals(ver.fingerprint);

            // when upgrading from pre-M, promote system app permissions from install to runtime
            mPromoteSystemApps =
                    mIsUpgrade && ver.sdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1;

            // When upgrading from pre-N, we need to handle package extraction like first boot,
            // as there is no profiling data available.
            mIsPreNUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N;

            mIsPreNMR1Upgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N_MR1;

            // save off the names of pre-existing system packages prior to scanning; we don't
            // want to automatically grant runtime permissions for new system apps
            if (mPromoteSystemApps) {//是否需要提升权限
                Iterator<PackageSetting> pkgSettingIter = mSettings.mPackages.values().iterator();
                while (pkgSettingIter.hasNext()) {
                    PackageSetting ps = pkgSettingIter.next();
                    if (isSystemApp(ps)) {
                        mExistingSystemPackages.add(ps.name);//遍历Settings::mPackages集合,将系统APP加入到PackageManagerService::mExistingSystemPackages
                    }
                }
            }

首先会为/data/目录下的一些子文件夹创建File实例,这些文件实例在后续的APK扫描工作中会最被作为目标地址进行扫描,获取该目录下的APK信息。其次,系统还会从SystemConfig中获取之前解析的permission信息,并保存到Settings中。接着,还会从SystemConfig中获取之前解析的共享库信息,并加入到PMS::mSharedLibraries,后续做dexopt优化时,会遍历该集合对象。之后还会有一些系统信息的清理工作。

前面的处理中,涉及到一个很重要的解析工作:Settings类解析packages.xml文件,得到上一次APK扫描的各种信息。它的处理依赖函数调用如下:

			//读取packages.xml的内容,并对mSettings::mPackages等成员进行赋值;packages.xml文件中的内容是上一次扫描apk目录的结果
			//当前这一次扫描的结果是保存在PackageManagerService::mPackages列表中
			//对比上次扫描的结果来检查本次扫描到的应用中是否有被升级包覆盖的系统应用,如果有则从PackageManagerService::mPackages中移除;
			//这样,PackageManagerService::mPackages的记录就和mSettings::mPackages的一致了
			//系统最终会将本次apk扫描的结果重新写入packages.xml中
mFirstBoot = !mSettings.readLPw(sUserManager.getUsers(false));

接着系统会对需要做dexopt优化的共享库进行优化。最后还会做一些权限相关的工作,其他的一些内容可以参考代码中的注释。

接下来我们简略分析前面提到的Settings类对packages.xml文件的解析过程,我们要特别注意Settings中存储<package>相关标签信息的集合对象是什么样的:

{
        FileInputStream str = null;
        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");
                if (mSettingsFilename.exists()) {
                    // If both the backup and settings file exist, we
                    // ignore the settings since it might have been
                    // corrupted.
                    Slog.w(PackageManagerService.TAG, "Cleaning up settings file "
                            + mSettingsFilename);
                    mSettingsFilename.delete();
                }
            } catch (java.io.IOException e) {
                // We'll try for the normal settings file.
            }
        }

        ......

        try {
            if (str == null) {
                if (!mSettingsFilename.exists()) {
                    mReadMessages.append("No settings file found\n");
                    PackageManagerService.reportSettingsProblem(Log.INFO,
                            "No settings file; creating initial state");
                    // It's enough to just touch version details to create them
                    // with default values
                    findOrCreateVersion(StorageManager.UUID_PRIVATE_INTERNAL);
                    findOrCreateVersion(StorageManager.UUID_PRIMARY_PHYSICAL);
                    return false;
                }
                str = new FileInputStream(mSettingsFilename);
            }
            XmlPullParser parser = Xml.newPullParser();
            parser.setInput(str, StandardCharsets.UTF_8.name());

            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")) {//解析<package>标签
                    readPackageLPw(parser);
                } else if (tagName.equals("permissions")) {
                    readPermissionsLPw(mPermissions, parser);
                } else if (tagName.equals("permission-trees")) {
                    readPermissionsLPw(mPermissionTrees, parser);
                } else if (tagName.equals("shared-user")) {
                    readSharedUserLPw(parser);
                } else if (tagName.equals("preferred-packages")) {
                    // no longer used.
                } else if (tagName.equals("preferred-activities")) {
                    // Upgrading from old single-user implementation;
                    // these are the preferred activities for user 0.
                    readPreferredActivitiesLPw(parser, 0);
                } else if (tagName.equals(TAG_PERSISTENT_PREFERRED_ACTIVITIES)) {
                    // TODO: check whether this is okay! as it is very
                    // similar to how preferred-activities are treated
                    readPersistentPreferredActivitiesLPw(parser, 0);
                } else if (tagName.equals(TAG_CROSS_PROFILE_INTENT_FILTERS)) {
                    // TODO: check whether this is okay! as it is very
                    // similar to how preferred-activities are treated
                    readCrossProfileIntentFiltersLPw(parser, 0);
                } else if (tagName.equals(TAG_DEFAULT_BROWSER)) {
                    readDefaultAppsLPw(parser, 0);
                } else if (tagName.equals("updated-package")) {//解析<updated-package>标签
                    readDisabledSysPackageLPw(parser);
                } else if (tagName.equals("cleaning-package")) {//解析<cleaning-package>标签
                    String name = parser.getAttributeValue(null, ATTR_NAME);
                    String userStr = parser.getAttributeValue(null, ATTR_USER);
                    String codeStr = parser.getAttributeValue(null, ATTR_CODE);
                    if (name != null) {
                        int userId = UserHandle.USER_SYSTEM;
                        boolean andCode = true;
                        try {
                            if (userStr != null) {
                                userId = Integer.parseInt(userStr);
                            }
                        } catch (NumberFormatException e) {
                        }
                        if (codeStr != null) {
                            andCode = Boolean.parseBoolean(codeStr);
                        }
                        addPackageToCleanLPw(new PackageCleanItem(userId, name, andCode));
                    }
                } else if (tagName.equals("renamed-package")) {//解析<renamed-package>标签
                    String nname = parser.getAttributeValue(null, "new");
                    String oname = parser.getAttributeValue(null, "old");
                    if (nname != null && oname != null) {
                        mRenamedPackages.put(nname, oname);
                    }
                } /*......*/{
                    Slog.w(PackageManagerService.TAG, "Unknown element under <packages>: "
                            + parser.getName());
                    XmlUtils.skipCurrentTag(parser);
                }
            }

            str.close();

        } catch (XmlPullParserException e) {
            mReadMessages.append("Error reading: " + e.toString());
            PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e);
            Slog.wtf(PackageManagerService.TAG, "Error reading package manager settings", e);

        } catch (java.io.IOException e) {
            mReadMessages.append("Error reading: " + e.toString());
            PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e);
            Slog.wtf(PackageManagerService.TAG, "Error reading package manager settings", e);
        }
        ......
        return true;
    }

分析这一部分内容时,我们只需着重了解各个标签的含义,及保存这些标签信息的各个集合实例即可;分清楚Settings中几个主要集合保存的是什么样的package信息,对分析PackageManagerService后续的APK扫描流程具有重要作用。

  • <package>:标签package记录了一个应用的基本信息、签名和权限等内容
  • <updated-package>:开头介绍的系统APP升级的情况,会用<updated-package>标签记录这种被覆盖的系统应用的信息;它的内容和<package>类似
  • <cleaning-package>:该标签用来记录那些已经删除,但数据目录还暂时保留的应用的信息
  • <renamed-package>:对于开头介绍的APP升级的情况,还有一种特殊的例子。通常应用的包名都用”package”属性来指定,同时系统应用也可以使用”original-package”来指定原始包名的名称。这就有可能一个APK指定了两个包名,那我们真实看到的包名是什么呢?如果安装的设备中不存在和原始包名相同的系统应用,这时看到的包名将是”package”属性指定的名称。如果设备上存在低版本的,而且包名和原始包名相同的应用,这样虽然最后运行的还是新安装的应用,但是,我们看到的应用的名称将还是原始的包名。因为,这样也构成了升级关系。而在packages.xml中,就使用<renamed-package>标签来记录APK改名的情况

<renamed-package>标签的描述是一本书中看到的,但我没验证到这种情况;<cleaning-package>也是如此。剩余的两个标签很好验证,系统APK升级就能看到。

我们看下一个系统APK升级后,与它有关的package标签:

    <package name="com.test.launcher" codePath="/data/app/com.test.launcher-1.apk" nativeLibraryPath="/data/app-lib/com.test.launcher-1" flags="1621703" ft="15c5c664810" it="15c5c64f270" ut="15c5c664e24" version="3" userId="10018">
         <sigs count="1">
       <cert index="4" key="30504061......51ed779c239ac8d" />
     </sigs>
        <signing-keyset identifier="1" />
    </package>

......

    <updated-package name="com.test.launcher" codePath="/system/app/Launcher.apk" ft="15c3e937088" it="15c5c64f270" ut="15c5c64f270" version="1" nativeLibraryPath="/data/app-lib/Launcher" userId="10018">
        <perms>
            <item name="android.permission.READ_EXTERNAL_STORAGE" />
            <item name="android.permission.ACCESS_WIFI_STATE" />
            <item name="android.permission.GET_TASKS" />
            <item name="android.permission.WRITE_EXTERNAL_STORAGE" />
            <item name="android.permission.ACCESS_NETWORK_STATE" />
            <item name="android.permission.INTERNET" />
        </perms>
    </updated-package>

如前所述,升过级的系统APK会被<updated-package>标签描述;另外,升级后安装在/data/目录下的当前新版APK信息也会被<package>描述。

对于这些标签的解析过程,这里不做分析;因为都是一些标准的XML解析过程。我们直接列举出Settings类中,这4个标签被解析后,用于信息存储的集合对象:

  • 	//packages.xml中<package>标签所标识的应用;以包名为键,信息的代码封装PackageSetting实例为值
        final ArrayMap<String, PackageSetting> mPackages = new ArrayMap<>();
  •     // List of replaced system applications
        //packages.xml中<updated-package>标签所标识的应用;以包名为键,信息的代码封装PackageSetting实例为值
        private final ArrayMap<String, PackageSetting> mDisabledSysPackages =
            new ArrayMap<String, PackageSetting>();
  •     // Packages that have been uninstalled and still need their external
        // storage data deleted.
        //packages.xml中<cleaning-package>标签所标识的应用;那些已经删除,但数据目录还暂时保留的应用信息;PackageCleanItem也是一个数剧封装类
        final ArrayList<PackageCleanItem> mPackagesToBeCleaned = new ArrayList<PackageCleanItem>();
  •     // Packages that have been renamed since they were first installed.
        // Keys are the new names of the packages, values are the original
        // names.  The packages appear everwhere else under their original
        // names.
        //packages.xml中<renamed-package>标签所标识的应用;记录系统中改名应用的新旧包名;以new name为键,old name为值
        final ArrayMap<String, String> mRenamedPackages = new ArrayMap<String, String>();
    

至此,这一部分代码的分析就结束了,我们需要关心的内容就是Settings类内部是如何组织、维护这些<package>标签信息的。

接着,我们再看下PackageManagerService构造函数下一部分的处理:

   // Collect vendor overlay packages.
            // (Do this before scanning any apps.)
            // For security and version matching reason, only consider
            // overlay packages if they reside in VENDOR_OVERLAY_DIR.
            File vendorOverlayDir = new File(VENDOR_OVERLAY_DIR);
            scanDirTracedLI(vendorOverlayDir, mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR
                    | PackageParser.PARSE_TRUSTED_OVERLAY, scanFlags | SCAN_TRUSTED_OVERLAY, 0);//扫描/vendor/overlay/录下的APK

            // Find base frameworks (resource packages without code).
            scanDirTracedLI(frameworkDir, mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR
                    | PackageParser.PARSE_IS_PRIVILEGED,
                    scanFlags | SCAN_NO_DEX, 0);

            // Collected privileged system packages.
            final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");//扫描指/system/priv-app/目录下的APK
            scanDirTracedLI(privilegedAppDir, mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR
                    | PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0);

            // Collect ordinary system packages.
            final File systemAppDir = new File(Environment.getRootDirectory(), "app");//扫描/system/app/目录下的APK
            scanDirTracedLI(systemAppDir, mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);

            // Collect all vendor packages.
            File vendorAppDir = new File("/vendor/app");
            try {
                vendorAppDir = vendorAppDir.getCanonicalFile();
            } catch (IOException e) {
                // failed to look up canonical path, continue with original one
            }
            scanDirTracedLI(vendorAppDir, mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);//扫描/vendro/app/目录下的APK

            // Collect all OEM packages.
            final File oemAppDir = new File(Environment.getOemDirectory(), "app");
            scanDirTracedLI(oemAppDir, mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);//扫描/oem/app/目录下的APK

            // Prune any system packages that no longer exist.
            //系统应用升级是这样的,/system/app/下面的预置的应用还会保存;升级后的apk会被安装在/data/app/目录下
            //即一个系统应用被升级后,系统中实际是存在两个不同版本的该应用的apk文件的:/system/app/目录下的被保存,可以用来还原该应用(如果恢复出厂)
            ///data/app/下安装的应用(版本较新的那个应用),则是用户实际使用的更新过的应用
            final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<String>();//记录可能有升级包的应用,具体指/data/app/下的版本较新的应用
            if (!mOnlyCore) {
                Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
                while (psit.hasNext()) {
                    PackageSetting ps = psit.next();

                    /*
                     * If this is not a system app, it can't be a
                     * disable system app.
                     */
                    if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
                        continue;
                    }//忽略普通应用/非系统应用

                    /*
                     * If the package is scanned, it's not erased.
                     */
                    final PackageParser.Package scannedPkg = mPackages.get(ps.name);//PackageManagerService::mPackages
                    if (scannedPkg != null) {
                        /*
                         * If the system app is both scanned and in the
                         * disabled packages list, then it must have been
                         * added via OTA. Remove it from the currently
                         * scanned package so the previously user-installed
                         * application can be scanned.
                         */
                        //如果扫描的应用是带升级包的系统应用,则需要将它从PackageManagerService::mPackages中移除;并插入到mExpectingBetter列表中
                        if (mSettings.isDisabledSystemPackageLPr(ps.name)) {//mDisabledSysPackages记录packages.xml中<updated-package>标签所标识的应用
                            logCriticalInfo(Log.WARN, "Expecting better updated system app for "
                                    + ps.name + "; removing system app.  Last known codePath="
                                    + ps.codePathString + ", installStatus=" + ps.installStatus
                                    + ", versionCode=" + ps.versionCode + "; scanned versionCode="
                                    + scannedPkg.mVersionCode);
                            removePackageLI(scannedPkg, true);
                            mExpectingBetter.put(ps.name, ps.codePath);//mExpectingBetter列表中保存的是带有升级包的系统应用,升级包即指/data/app/下的版本较新的应用
                        }

                        continue;//忽略PackageSetting::ps代表的已经存在于PackageManagerService::mPackages列表中的包
                    }

					//至此,说明PackageSetting::ps代表的应用不在PackageManagerService::mPackages中
                    if (!mSettings.isDisabledSystemPackageLPr(ps.name)) {//如果该应用不是<updated-package>标签标识的应用,则说明它可能是残留在packages.xml中的,可能会有数据目录需要删除
                        psit.remove();
                        logCriticalInfo(Log.WARN, "System package " + ps.name
                                + " no longer exists; it's data will be wiped");
                        // Actual deletion of code and data will be handled by later
                        // reconciliation step
                    } else {//至此,说明PackageSetting::ps代表的应用不在系统目录下,但是它被<updated-package>标签标识,则添加到possiblyDeletedUpdatedSystemApps列表
                        final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps.name);
                        if (disabledPs.codePath == null || !disabledPs.codePath.exists()) {
                            possiblyDeletedUpdatedSystemApps.add(ps.name);
                        }
                    }
                }
            }

            //look for any incomplete package installations
            //删除那些没有安装成功的包的数据
            ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();
            for (int i = 0; i < deletePkgsList.size(); i++) {
                // Actual deletion of code and data will be handled by later
                // reconciliation step
                final String packageName = deletePkgsList.get(i).name;
                logCriticalInfo(Log.WARN, "Cleaning up incompletely installed app: " + packageName);
                synchronized (mPackages) {
                    mSettings.removePackageLPw(packageName);
                }
            }

            //delete tmp files
            deleteTempPackageFiles();//删除零时文件

            // Remove any shared userIDs that have no associated packages
            mSettings.pruneSharedUsersLPw();//把mSettings中没有雨任何apk关联的SharedUserSetting对象删除

            if (!mOnlyCore) { //扫描非系统应用,即/data/app/和/data/priv-app/等目录下的应用
                EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
                        SystemClock.uptimeMillis());
                scanDirTracedLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);//扫描/data/app/目录下的APK

                scanDirTracedLI(mDrmAppPrivateInstallDir, mDefParseFlags
                        | PackageParser.PARSE_FORWARD_LOCK,
                        scanFlags | SCAN_REQUIRE_KNOWN, 0);//扫描/data/app-private/目录下的APK

                scanDirLI(mEphemeralInstallDir, mDefParseFlags
                        | PackageParser.PARSE_IS_EPHEMERAL,
                        scanFlags | SCAN_REQUIRE_KNOWN, 0);//扫描/data/app-ephemeral/目录下的APK

                /**
                 * Remove disable package settings for any updated system
                 * apps that were removed via an OTA. If they're not a
                 * previously-updated app, remove them completely.
                 * Otherwise, just revoke their system-level permissions.
                 */
                //possiblyDeletedUpdatedSystemApps列表中存储的是文件不在系统目录下,但是被<updated-package>标签标识的应用;
                //扫描完/data/目录后,遍历该列表是为了处理文件是否在data目录下的情形
                for (String deletedAppName : possiblyDeletedUpdatedSystemApps) {
                    PackageParser.Package deletedPkg = mPackages.get(deletedAppName);
                    mSettings.removeDisabledSystemPackageLPw(deletedAppName);

                    String msg;
                    if (deletedPkg == null) {//用户安装目录下没有该文件,说明肯定是残留的应用信息,需要清除它的遗留数据
                        msg = "Updated system package " + deletedAppName
                                + " no longer exists; it's data will be wiped";
                        // Actual deletion of code and data will be handled by later
                        // reconciliation step
                    } else {//用户安装目录有该文件, 则说明系统目录下的文件被删除了,因此需要去掉该应用的系统属性标志,以普通的应用模式运行
                        msg = "Updated system app + " + deletedAppName
                                + " no longer present; removing system privileges for "
                                + deletedAppName;

                        deletedPkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;

                        PackageSetting deletedPs = mSettings.mPackages.get(deletedAppName);
                        deletedPs.pkgFlags &= ~ApplicationInfo.FLAG_SYSTEM;
                    }
                    logCriticalInfo(Log.WARN, msg);
                }

                /**
                 * Make sure all system apps that we expected to appear on
                 * the userdata partition actually showed up. If they never
                 * appeared, crawl back and revive the system version.
                 */
                for (int i = 0; i < mExpectingBetter.size(); i++) {
                    final String packageName = mExpectingBetter.keyAt(i);
                    if (!mPackages.containsKey(packageName)) {//往mExpectingBetter列表中添加元素时,会在PakcageManagerService::mPackages相应地移除它
                        final File scanFile = mExpectingBetter.valueAt(i);

                        logCriticalInfo(Log.WARN, "Expected better " + packageName
                                + " but never showed up; reverting to system");
						//处理的应用必须是在以下几个系统目录下;否则不处理
                        int reparseFlags = mDefParseFlags;
                        if (FileUtils.contains(privilegedAppDir, scanFile)) {
                            reparseFlags = PackageParser.PARSE_IS_SYSTEM
                                    | PackageParser.PARSE_IS_SYSTEM_DIR
                                    | PackageParser.PARSE_IS_PRIVILEGED;
                        } else if (FileUtils.contains(systemAppDir, scanFile)) {
                            reparseFlags = PackageParser.PARSE_IS_SYSTEM
                                    | PackageParser.PARSE_IS_SYSTEM_DIR;
                        } else if (FileUtils.contains(vendorAppDir, scanFile)) {
                            reparseFlags = PackageParser.PARSE_IS_SYSTEM
                                    | PackageParser.PARSE_IS_SYSTEM_DIR;
                        } else if (FileUtils.contains(oemAppDir, scanFile)) {
                            reparseFlags = PackageParser.PARSE_IS_SYSTEM
                                    | PackageParser.PARSE_IS_SYSTEM_DIR;
                        } else {
                            Slog.e(TAG, "Ignoring unexpected fallback path " + scanFile);
                            continue;
                        }

                        mSettings.enableSystemPackageLPw(packageName);

                        try {
							//扫描并处理应用
                            scanPackageTracedLI(scanFile, reparseFlags, scanFlags, 0, null);
                        } catch (PackageManagerException e) {
                            Slog.e(TAG, "Failed to parse original system package: "
                                    + e.getMessage());
                        }
                    }
                }
            }
            mExpectingBetter.clear();

这一段处理的代码较长,但最主要的处理包含两部分:

  • 调用PackageManagerService::scanDirTracedLI()函数扫描某个目录下存在的所有APK,并解析它的信息;处理过后,各Package的信息会保存到PackageManagerService::mPacages中
  • 处理升过级的系统APK

PackageManagerService会扫描多个目录下的APK文件,我们最熟悉的应该就是/data/app/和/system/app/了。PackageManagerService::scanDirTracedLI()函数的处理很复杂,它的函数调用关系较深,处理内容较多;后续也许会单独介绍该函数的基本处理流程,来了解一个APK的扫描过程到底什么样的。这里我们只需要了解它是用来扫描APK文件,并会将信息保存到PMS::mPackages中就行了。

接着分析,PMS处理升过级的系统APK的过程是这样的:

            //扫描系统应用目录  
      
            // Prune any system packages that no longer exist.
            //系统应用升级是这样的,/system/app/下面的预置的应用还会保存;升级后的apk会被安装在/data/app/目录下
            //即一个系统应用被升级后,系统中实际是存在两个不同版本的该应用的apk文件的:/system/app/目录下的被保存,可以用来还原该应用(如果恢复出厂)
            ///data/app/下安装的应用(版本较新的那个应用),则是用户实际使用的更新过的应用
            final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<String>();//记录可能有升级包的应用,具体指/data/app/下的版本较新的应用
            if (!mOnlyCore) {
                Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
                while (psit.hasNext()) {
                    PackageSetting ps = psit.next();

                    /*
                     * If this is not a system app, it can't be a
                     * disable system app.
                     */
                    if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
                        continue;
                    }//忽略普通应用/非系统应用

                    /*
                     * If the package is scanned, it's not erased.
                     */
                    final PackageParser.Package scannedPkg = mPackages.get(ps.name);//PackageManagerService::mPackages
                    if (scannedPkg != null) {
                        /*
                         * If the system app is both scanned and in the
                         * disabled packages list, then it must have been
                         * added via OTA. Remove it from the currently
                         * scanned package so the previously user-installed
                         * application can be scanned.
                         */
                        //如果扫描的应用是带升级包的系统应用,则需要将它从PackageManagerService::mPackages中移除;并插入到mExpectingBetter列表中
                        if (mSettings.isDisabledSystemPackageLPr(ps.name)) {//mDisabledSysPackages记录packages.xml中<updated-package>标签所标识的应用
                            logCriticalInfo(Log.WARN, "Expecting better updated system app for "
                                    + ps.name + "; removing system app.  Last known codePath="
                                    + ps.codePathString + ", installStatus=" + ps.installStatus
                                    + ", versionCode=" + ps.versionCode + "; scanned versionCode="
                                    + scannedPkg.mVersionCode);
                            removePackageLI(scannedPkg, true);
                            mExpectingBetter.put(ps.name, ps.codePath);//mExpectingBetter列表中保存的是带有升级包的系统应用,升级包即指/data/app/下的版本较新的应用
                        }

                        continue;//忽略PackageSetting::ps代表的已经存在于PackageManagerService::mPackages列表中的包
                    }

					//至此,说明PackageSetting::ps代表的应用不在PackageManagerService::mPackages中
                    if (!mSettings.isDisabledSystemPackageLPr(ps.name)) {//如果该应用不是<updated-package>标签标识的应用,则说明它可能是残留在packages.xml中的,可能会有数据目录需要删除
                        psit.remove();
                        logCriticalInfo(Log.WARN, "System package " + ps.name
                                + " no longer exists; it's data will be wiped");
                        // Actual deletion of code and data will be handled by later
                        // reconciliation step
                    } else {//至此,说明PackageSetting::ps代表的应用不在系统目录下,但是它被<updated-package>标签标识,则添加到possiblyDeletedUpdatedSystemApps列表
                        final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps.name);
                        if (disabledPs.codePath == null || !disabledPs.codePath.exists()) {
                            possiblyDeletedUpdatedSystemApps.add(ps.name);
                        }
                    }
                }
            }            
      

           //look for any incomplete package installations
            //删除那些没有安装成功的包的数据
            ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();
            for (int i = 0; i < deletePkgsList.size(); i++) {
                // Actual deletion of code and data will be handled by later
                // reconciliation step
                final String packageName = deletePkgsList.get(i).name;
                logCriticalInfo(Log.WARN, "Cleaning up incompletely installed app: " + packageName);
                synchronized (mPackages) {
                    mSettings.removePackageLPw(packageName);
                }
            }

             //扫描普通应用目录

               /**
                 * Remove disable package settings for any updated system
                 * apps that were removed via an OTA. If they're not a
                 * previously-updated app, remove them completely.
                 * Otherwise, just revoke their system-level permissions.
                 */
                //possiblyDeletedUpdatedSystemApps列表中存储的是文件不在系统目录下,但是被<updated-package>标签标识的应用;
                //扫描完/data/目录后,遍历该列表是为了该应用文件是否在data目录下的情形
                for (String deletedAppName : possiblyDeletedUpdatedSystemApps) {
                    PackageParser.Package deletedPkg = mPackages.get(deletedAppName);
                    mSettings.removeDisabledSystemPackageLPw(deletedAppName);

                    String msg;
                    if (deletedPkg == null) {//用户安装目录下没有该文件,说明肯定是残留的应用信息,需要清除它的遗留数据
                        msg = "Updated system package " + deletedAppName
                                + " no longer exists; it's data will be wiped";
                        // Actual deletion of code and data will be handled by later
                        // reconciliation step
                    } else {//用户安装目录有该文件, 则说明系统目录下的文件被删除了,因此需要去掉该应用的系统属性标志,以普通的应用模式运行
                        msg = "Updated system app + " + deletedAppName
                                + " no longer present; removing system privileges for "
                                + deletedAppName;

                        deletedPkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;

                        PackageSetting deletedPs = mSettings.mPackages.get(deletedAppName);
                        deletedPs.pkgFlags &= ~ApplicationInfo.FLAG_SYSTEM;
                    }
                    logCriticalInfo(Log.WARN, msg);
                }

                /**
                 * Make sure all system apps that we expected to appear on
                 * the userdata partition actually showed up. If they never
                 * appeared, crawl back and revive the system version.
                 */
                for (int i = 0; i < mExpectingBetter.size(); i++) {
                    final String packageName = mExpectingBetter.keyAt(i);
                    if (!mPackages.containsKey(packageName)) {//往mExpectingBetter列表中添加元素时,会在PakcageManagerService::mPackages相应地移除它
                        final File scanFile = mExpectingBetter.valueAt(i);

                        logCriticalInfo(Log.WARN, "Expected better " + packageName
                                + " but never showed up; reverting to system");
		        //处理的应用必须是在以下几个系统目录下;否则不处理
                        int reparseFlags = mDefParseFlags;
                        if (FileUtils.contains(privilegedAppDir, scanFile)) {
                            reparseFlags = PackageParser.PARSE_IS_SYSTEM
                                    | PackageParser.PARSE_IS_SYSTEM_DIR
                                    | PackageParser.PARSE_IS_PRIVILEGED;
                        } else if (FileUtils.contains(systemAppDir, scanFile)) {
                            reparseFlags = PackageParser.PARSE_IS_SYSTEM
                                    | PackageParser.PARSE_IS_SYSTEM_DIR;
                        } else if (FileUtils.contains(vendorAppDir, scanFile)) {
                            reparseFlags = PackageParser.PARSE_IS_SYSTEM
                                    | PackageParser.PARSE_IS_SYSTEM_DIR;
                        } else if (FileUtils.contains(oemAppDir, scanFile)) {
                            reparseFlags = PackageParser.PARSE_IS_SYSTEM
                                    | PackageParser.PARSE_IS_SYSTEM_DIR;
                        } else {
                            Slog.e(TAG, "Ignoring unexpected fallback path " + scanFile);
                            continue;
                        }

                        mSettings.enableSystemPackageLPw(packageName);

                        try {
							//扫描并处理应用
                            scanPackageTracedLI(scanFile, reparseFlags, scanFlags, 0, null);
                        } catch (PackageManagerException e) {
                            Slog.e(TAG, "Failed to parse original system package: "
                                    + e.getMessage());
                        }
                    }
                }
            }
            mExpectingBetter.clear();

首先扫描系统APK目录,

  1. 代码中的possiblyDeletedUpdatedSystemApps集合保存的是那些系统APK目录中已经不存在该APK的文件,但该APK又在packages.xml中被<updated-package>标识的应用。
  2. 代码中的mExpectingBetter集合保存的是那些带有升级包的系统APK;这里升级包指的就是/data/等非系统APK目录下该APK的较新版本。

再扫描非系统APK目录,接着:

  1. 遍历possiblyDeletedUpdatedSystemApps集合,如果该集合中存储的某个APK也不在非系统APK目录中,那说明这个APK就没有文件存在于系统中,则需要删除它有关的所有信息;否则,表明它有APK文件存在于非系统APK目录,那我们需要清除它的系统标志,让它以普通APK的模式运行;
  2. 遍历mExpectingBetter集合,处理所有已经升过级的系统APK,并调用scanPackageTracedLI()对它的非系统APK目录下的新版本APK进行扫描处理;处理完成后,清空该集合;

这一部分的内容应该是PMS启动过程的核心内容。

再接着看PMS构造的最后一部分内容:

// Resolve the storage manager.
            mStorageManagerPackage = getStorageManagerPackageName();

            // Resolve protected action filters. Only the setup wizard is allowed to
            // have a high priority filter for these actions.
            mSetupWizardPackage = getSetupWizardPackageName();//处理开机向导,获取它的包名
            if (mProtectedFilters.size() > 0) {
                if (DEBUG_FILTERS && mSetupWizardPackage == null) {
                    Slog.i(TAG, "No setup wizard;"
                        + " All protected intents capped to priority 0");
                }
                for (ActivityIntentInfo filter : mProtectedFilters) {
                    if (filter.activity.info.packageName.equals(mSetupWizardPackage)) {
                        if (DEBUG_FILTERS) {
                            Slog.i(TAG, "Found setup wizard;"
                                + " allow priority " + filter.getPriority() + ";"
                                + " package: " + filter.activity.info.packageName
                                + " activity: " + filter.activity.className
                                + " priority: " + filter.getPriority());
                        }
                        // skip setup wizard; allow it to keep the high priority filter
                        continue;
                    }
                    Slog.w(TAG, "Protected action; cap priority to 0;"
                            + " package: " + filter.activity.info.packageName
                            + " activity: " + filter.activity.className
                            + " origPrio: " + filter.getPriority());
                    filter.setPriority(0);
                }
            }
            mDeferProtectedFilters = false;
            mProtectedFilters.clear();

            // Now that we know all of the shared libraries, update all clients to have
            // the correct library paths.
            updateAllSharedLibrariesLPw();//更新所有动态库的路径

            for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) {
                // NOTE: We ignore potential failures here during a system scan (like
                // the rest of the commands above) because there's precious little we
                // can do about it. A settings error is reported, though.
                adjustCpuAbisForSharedUserLPw(setting.packages, null /* scanned package */,
                        false /* boot complete */);
            }

            // Now that we know all the packages we are keeping,
            // read and update their last usage times.
            mPackageUsage.read(mPackages);
            mCompilerStats.read();

            EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
                    SystemClock.uptimeMillis());
            Slog.i(TAG, "Time to scan packages: "
                    + ((SystemClock.uptimeMillis()-startTime)/1000f)
                    + " seconds");

            // If the platform SDK has changed since the last time we booted,
            // we need to re-grant app permission to catch any new ones that
            // appear.  This is really a hack, and means that apps can in some
            // cases get permissions that the user didn't initially explicitly
            // allow...  it would be nice to have some better way to handle
            // this situation.
            //如果前后平台的SDK版本发生了变化,可能permission的定义也发生了变化;这里需要重新赋予应用权限
            int updateFlags = UPDATE_PERMISSIONS_ALL;
            if (ver.sdkVersion != mSdkVersion) {
                Slog.i(TAG, "Platform changed from " + ver.sdkVersion + " to "
                        + mSdkVersion + "; regranting permissions for internal storage");
                updateFlags |= UPDATE_PERMISSIONS_REPLACE_PKG | UPDATE_PERMISSIONS_REPLACE_ALL;
            }
            updatePermissionsLPw(null, null, StorageManager.UUID_PRIVATE_INTERNAL, updateFlags);
            ver.sdkVersion = mSdkVersion;

            // If this is the first boot or an update from pre-M, and it is a normal
            // boot, then we need to initialize the default preferred apps across
            // all defined users.
            if (!onlyCore && (mPromoteSystemApps || mFirstBoot)) {
                for (UserInfo user : sUserManager.getUsers(true)) {
                    mSettings.applyDefaultPreferredAppsLPw(this, user.id);
                    applyFactoryDefaultBrowserLPw(user.id);
                    primeDomainVerificationsLPw(user.id);
                }
            }

            // Prepare storage for system user really early during boot,
            // since core system apps like SettingsProvider and SystemUI
            // can't wait for user to start
            final int storageFlags;
            if (StorageManager.isFileEncryptedNativeOrEmulated()) {
                storageFlags = StorageManager.FLAG_STORAGE_DE;
            } else {
                storageFlags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
            }
            reconcileAppsDataLI(StorageManager.UUID_PRIVATE_INTERNAL, UserHandle.USER_SYSTEM,
                    storageFlags);

            // If this is first boot after an OTA, and a normal boot, then
            // we need to clear code cache directories.
            // Note that we do *not* clear the application profiles. These remain valid
            // across OTAs and are used to drive profile verification (post OTA) and
            // profile compilation (without waiting to collect a fresh set of profiles).
            if (mIsUpgrade && !onlyCore) {
                Slog.i(TAG, "Build fingerprint changed; clearing code caches");
                for (int i = 0; i < mSettings.mPackages.size(); i++) {
                    final PackageSetting ps = mSettings.mPackages.valueAt(i);
                    if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, ps.volumeUuid)) {
                        // No apps are running this early, so no need to freeze
                        clearAppDataLIF(ps.pkg, UserHandle.USER_ALL,
                                StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE
                                        | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
                    }
                }
                ver.fingerprint = Build.FINGERPRINT;
            }

            checkDefaultBrowser();

            // clear only after permissions and other defaults have been updated
            mExistingSystemPackages.clear();
            mPromoteSystemApps = false;

            // All the changes are done during package scanning.
            ver.databaseVersion = Settings.CURRENT_DATABASE_VERSION;

            // can downgrade to reader
            mSettings.writeLPr();//将本次apk的扫描结果写入到packagex.xml中,供下一次对比

            // Perform dexopt on all apps that mark themselves as coreApps. We do this pretty
            // early on (before the package manager declares itself as early) because other
            // components in the system server might ask for package contexts for these apps.
            //
            // Note that "onlyCore" in this context means the system is encrypted or encrypting
            // (i.e, that the data partition is unavailable).
            if ((isFirstBoot() || isUpgrade() || VMRuntime.didPruneDalvikCache()) && !onlyCore) {
                long start = System.nanoTime();
                List<PackageParser.Package> coreApps = new ArrayList<>();
                for (PackageParser.Package pkg : mPackages.values()) {
                    if (pkg.coreApp) {
                        coreApps.add(pkg);
                    }
                }

                int[] stats = performDexOptUpgrade(coreApps, false,
                        getCompilerFilterForReason(REASON_CORE_APP));

                final int elapsedTimeSeconds =
                        (int) TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - start);
                MetricsLogger.histogram(mContext, "opt_coreapps_time_s", elapsedTimeSeconds);

                if (DEBUG_DEXOPT) {
                    Slog.i(TAG, "Dex-opt core apps took : " + elapsedTimeSeconds + " seconds (" +
                            stats[0] + ", " + stats[1] + ", " + stats[2] + ")");
                }


                // TODO: Should we log these stats to tron too ?
                // MetricsLogger.histogram(mContext, "opt_coreapps_num_dexopted", stats[0]);
                // MetricsLogger.histogram(mContext, "opt_coreapps_num_skipped", stats[1]);
                // MetricsLogger.histogram(mContext, "opt_coreapps_num_failed", stats[2]);
                // MetricsLogger.histogram(mContext, "opt_coreapps_num_total", coreApps.size());
            }

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

            if (!mOnlyCore) {
                mRequiredVerifierPackage = getRequiredButNotReallyRequiredVerifierLPr();
                mRequiredInstallerPackage = getRequiredInstallerLPr();
                mRequiredUninstallerPackage = getRequiredUninstallerLPr();
                mIntentFilterVerifierComponent = getIntentFilterVerifierComponentNameLPr();
                mIntentFilterVerifier = new IntentVerifierProxy(mContext,
                        mIntentFilterVerifierComponent);
                mServicesSystemSharedLibraryPackageName = getRequiredSharedLibraryLPr(
                        PackageManager.SYSTEM_SHARED_LIBRARY_SERVICES);
                mSharedSystemSharedLibraryPackageName = getRequiredSharedLibraryLPr(
                        PackageManager.SYSTEM_SHARED_LIBRARY_SHARED);
            } else {
                mRequiredVerifierPackage = null;
                mRequiredInstallerPackage = null;
                mRequiredUninstallerPackage = null;
                mIntentFilterVerifierComponent = null;
                mIntentFilterVerifier = null;
                mServicesSystemSharedLibraryPackageName = null;
                mSharedSystemSharedLibraryPackageName = null;
            }

            mInstallerService = new PackageInstallerService(context, this);//创建PackageInstallerService实例

            final ComponentName ephemeralResolverComponent = getEphemeralResolverLPr();
            final ComponentName ephemeralInstallerComponent = getEphemeralInstallerLPr();
            // both the installer and resolver must be present to enable ephemeral
            if (ephemeralInstallerComponent != null && ephemeralResolverComponent != null) {
                if (DEBUG_EPHEMERAL) {
                    Slog.i(TAG, "Ephemeral activated; resolver: " + ephemeralResolverComponent
                            + " installer:" + ephemeralInstallerComponent);
                }
                mEphemeralResolverComponent = ephemeralResolverComponent;
                mEphemeralInstallerComponent = ephemeralInstallerComponent;
                setUpEphemeralInstallerActivityLP(mEphemeralInstallerComponent);
                mEphemeralResolverConnection =
                        new EphemeralResolverConnection(mContext, mEphemeralResolverComponent);
            } else {
                if (DEBUG_EPHEMERAL) {
                    final String missingComponent =
                            (ephemeralResolverComponent == null)
                            ? (ephemeralInstallerComponent == null)
                                    ? "resolver and installer"
                                    : "resolver"
                            : "installer";
                    Slog.i(TAG, "Ephemeral deactivated; missing " + missingComponent);
                }
                mEphemeralResolverComponent = null;
                mEphemeralInstallerComponent = null;
                mEphemeralResolverConnection = null;
            }

            mEphemeralApplicationRegistry = new EphemeralApplicationRegistry(this);
        } // synchronized (mPackages)
        } // synchronized (mInstallLock)

        // Now after opening every single application zip, make sure they
        // are all flushed.  Not really needed, but keeps things nice and
        // tidy.
        Runtime.getRuntime().gc();//启动垃圾回收

        // The initial scanning above does many calls into installd while
        // holding the mPackages lock, but we're mostly interested in yelling
        // once we have a booted system.
        mInstaller.setWarnIfHeld(mPackages);

        // Expose private service for system components to use.
        LocalServices.addService(PackageManagerInternal.class, new PackageManagerInternalImpl());
   

由于PMS构造的主要工作都在前一部分完成了,所以这一块都是在做一些扫尾、信息更新和清理工作。其中重要的,我们已经获取到了系统中所有共享库的信息,这里需要对外全部更新一次这些内容;另外,因为当前所有APK的扫描、处理工作已经完成,我们需要将当前扫描过程得到的APK信息写入到/data/system/packages.xml中,供下次系统启动时PMS再进行对比。其他的内容可以参看代码中的注释分析。

至此,PackageManagerService的构造流程就分析完了;APK的具体扫描流程,我们在后续再单独分析。

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