深刻Android系统(十)PMS-1-服务初始化

导读

PMS笔记大小写到106kb时,就知大事不妙,导读叒叒叒来了java

不得已,将本来计划一篇结束的文章分为了以下三部分:android

前两篇主要梳理了PMS初始化的流程和初始化的一些细节;最后一篇对应用的安装过程进行了简单梳理。shell

有没有注意梳理字眼,关于想要深刻全面学习PMS的同窗只能很是抱歉,本系列文章也仅仅是起到的主要流程的梳理做用。缓存

咱们先从总体上掌握,等后面遇到相关需求再来仔细研究吧(这波安慰很及时。。。。)markdown

整个模块学习下来,简单对PackageManagerService吐槽一下:app

  • PMS中涉及的类比较多,真正掌握须要一番时间和精力
    • 相关的类像:Package相关、Session相关、Settings等等
  • 阅读PMS的方法有点拆俄罗斯套娃的感受,一层又一层。。。。
  • 业务逻辑复杂,几乎每一个方法的执行会夹杂着各类权限用户的逻辑判断

有了上面的预期,欢迎来到PackageManagerService的世界ide

了解PackageManagerService

PackageManagerService代码行数在24000行。。。。。函数

Android的应用管理主要是经过PackageManagerService来完成的。PackageManagerService负责各类APK包的安装、卸载、优化和查询。oop

Android中的应用能够简单分为两大类:系统应用普通应用post

  • 系统应用是指位于/system/app/system/priv-app目录下的应用
    • /system/priv-app是从Android 4.4开始出现的目录,存放的是一些系统底层的应用,如:SettingsSystemUI
    • /system/app存放的则是一些系统级的应用,如CalendarContacts
  • 普通应用是用户安装的应用,位于目录/data/app

PackageManagerService在启动时会扫描全部APK文件和Jar包,而后把它们的信息读取到内存中,这样系统在运行时就能迅速找到各类应用和组件信息。

  • 扫描过程若是遇到没有优化的文件,还要执行优化操做。

    Android 5.0开始引入了ARTART 使用预先 (AOT) 编译,而且从 Android 7.0开始结合使用 AOT即时 (JIT) 编译配置文件引导型编译来优化应用的启动和执行效率

不着急直接分析源代码,咱们先从使用的角度简单了解下

在应用中,若是要使用PackageManagerService服务,一般是调用ContextgetPackageManager()方法,内容以下:

public PackageManager getPackageManager() {
        if (mPackageManager != null) {
            return mPackageManager;
        }
        IPackageManager pm = ActivityThread.getPackageManager();
        if (pm != null) {
            // Doesn't matter if we make more than one instance.
            return (mPackageManager = new ApplicationPackageManager(this, pm));
        }

        return null;
    }
复制代码

调用到了ActivityThread.getPackageManager()的方法:

public static IPackageManager getPackageManager() {
        if (sPackageManager != null) {
            return sPackageManager;
        }
        IBinder b = ServiceManager.getService("package");
        sPackageManager = IPackageManager.Stub.asInterface(b);
        return sPackageManager;
    }
复制代码

从这两个getPackageManager()方法的代码中能够看到:

  • 返回的是ApplicationPackageManager对象,这个对象建立时使用了IPackageManager对象做为参数

    • IPackageManager对象是PackageManagerServiceBinder代理对象
  • ApplicationPackageManager继承自PackageManager,在PackageManager中定义了应用能够访问PackageManagerService的全部接口

PackageManager关系图以下:

image

而对于PackageManagerService类来讲,有两个重要成员变量:

  • mInstallerService:类PackageInstallerService的实例对象。Android经过PackageInstallerService来管理应用的安装过程。

    • PackageInstallerService也是一个Binder服务,对应的代理对象是PackageInstaller
  • mInstaller:类Installer的实例对象。类结构相对简单,有一个IInstalld mInstalld变量,经过Binder调用来和installd进程通讯

    • 实际上系统中进行apk文件格式转换、创建数据目录等工做最后都是由installd进程来完成的

上述这几个对象之间的关系图以下:

image

Settings类和packages.xml

在开始分析PackageManagerService前,咱们要先看下Settings类,这个类用来保存和PackageManagerService相关的一些设置,它保存的内容在解析应用时会用到。

先看看com.android.server.pm.Settings类的构造方法:

Settings(File dataDir, PermissionSettings permission, Object lock) {
        // 省略权限相关的处理
        ......
        // 在data目录下建立system目录
        mSystemDir = new File(dataDir, "system");
        mSystemDir.mkdirs();
        // 设置目录的属性为0775
        FileUtils.setPermissions(mSystemDir.toString(),
                FileUtils.S_IRWXU|FileUtils.S_IRWXG
                |FileUtils.S_IROTH|FileUtils.S_IXOTH,
                -1, -1);
        mSettingsFilename = new File(mSystemDir, "packages.xml");
        mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");
        mPackageListFilename = new File(mSystemDir, "packages.list");
        FileUtils.setPermissions(mPackageListFilename, 0640, SYSTEM_UID, PACKAGE_INFO_GID);
        ......
        // Deprecated: Needed for migration
        mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");
        mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");
    }
复制代码

Settings类的构造方法会在/data目录下建立system目录用来保存一些系统配置文件。建立了5个位于目录/data/systemFile对象:

  • packages.xml:记录系统中全部安装的应用信息,包括基本信息、签名和权限。
  • packages-backup.xmlpackages.xml文件的备份
  • packages.list:保存普通应用的数据目录和uid等信息
  • packages-stopped.xml:记录系统中被强制中止运行的应用信息。系统在强制中止某个应用时,会将应用的信息记录到文件中
  • packages-stopped-backup.xmlpackages-stopped.xml文件的备份

packages-backup.xmlpackages-stopped-backup.xml是备份文件。关于备份文件的逻辑是:

  • 当Android对文件packages.xmlpackages-stopped.xml写以前,会把他们备份
  • 若是文件写成功了,再把备份文件删除掉
  • 若是写的时候系统出了问题,重启后再须要读取这两个文件时,若是发现备份文件存在,会使用备份文件的内容,由于原文件可能已经损坏了。

packages.xmlPackageManagerService启动时须要用到的文件,咱们先看看文件的格式:

<package name="com.android.providers.telephony" codePath="/system/priv-app/TelephonyProvider" nativeLibraryPath="/system/priv-app/TelephonyProvider/lib" publicFlags="1007402501" privateFlags="8" ft="11e8dc5d800" it="11e8dc5d800" ut="11e8dc5d800" version="28" sharedUserId="1001" isOrphaned="true">
        <sigs count="1" schemeVersion="3">
            <cert index="0" />
        </sigs>
        <perms>
            <item name="android.permission.USE_RESERVED_DISK" granted="true" flags="0" />
            <item name="android.permission.INTERACT_ACROSS_USERS_FULL" granted="true" flags="0" />
            <item name="android.permission.INTERACT_ACROSS_USERS" granted="true" flags="0" />
            <item name="android.permission.MODIFY_PHONE_STATE" granted="true" flags="0" />
        </perms>
        <proper-signing-keyset identifier="1" />
    </package>
复制代码

上面是文件中的一个<package/>标签,表示一个应用的基本信息、签名和声明的权限,从内容来看基本都是解析AndroidManifest.xml的内容。

咱们看下主要属性和标签:

  • name表示应用的包名
  • codePath表示apk文件的位置
  • nativeLibraryPath表示应用的native库的储存路径
  • it表示应用安装时间
  • ut表示最后一次修改的时间
  • version表示应用的版本号
  • sharedUserId表示应用用来共享的用户ID
  • userId表示应用所属的用户ID
  • <sign/>表示应用的签名
    • 属性count表示标签中包含有多少个证书
    • 标签<cert/>表示具体证书的值
  • <perms/>表示应用声明使用的权限
    • 每一个子标签<item/>表明一项权限

除了<package/>标签,packages.xml中还可能存在一下标签:

  • <updated-package/>:记录系统应用升级的状况。当安装了一个包名相同、版本号更高的应用后,Android 会经过此标签记录被覆盖的系统应用的信息。
  • <renamed-package/>:记录变动应用包名的状况。
    • 应用的包名一般是在AndroidManifest.xml中使用属性package来指定,同时在AndroidManifest.xml中还能够用<original-package>来指定原始包名,对于这种状况:
      • 当设备上存在低版本且包名与原始包名相同的应用时,会升级覆盖原始应用。
      • 最后运行的是新安装的应用,可是运行时应用的包名仍是原始的包名。Android会经过<renamed-package/>标签来记录这种更名的状况。
  • <cleaning-package/>:用来记录那些已经删除,可是数据目录还暂时保留的应用的信息

对于<package/><updated-package/>标签,解析后的数据将保存在PackageSetting的对象中。PackageSetting类的继承关系图以下:

image

  • PackageSetting继承了PackageSettingBase类,PackageSettingBase又继承了SettingBase
    • 应用的基本信息保存在PackageSettingBase类的成员变量中
    • 申明的权限保存在SettingBasemPermissionState
  • 签名信息保存在SharedUserSetting类的成员变量signatures
  • SharedUserSetting用来描述具备相同sharedUserId的应用信息
    • 它的成员变量packages是用来保存全部具备相同sharedUserId应用对象的集合
    • 这些应用的签名是相同的,所以只须要经过一个成员变量signatures保存便可

表明标签<package/>PackageSetting对象都会保存在Settings的成员变量mPackages中,定义以下:

final ArrayMap<String, PackageSetting> mPackages = new ArrayMap<>();
复制代码

表明标签<updated-package/>PackageSetting对象都会保存在Settings的成员变量mDisabledSysPackages中,定义以下:

private final ArrayMap<String, PackageSetting> mDisabledSysPackages = new ArrayMap<String, PackageSetting>();
复制代码

表明标签<cleaning-package/>PackageSetting对象都会保存在Settings的成员变量mPackagesToBeCleaned中,定义以下:

final ArrayList<PackageCleanItem> mPackagesToBeCleaned = new ArrayList<PackageCleanItem>();
复制代码

表明标签<renamed-package/>PackageSetting对象都会保存在Settings的成员变量mRenamedPackages中,定义以下:

private final ArrayMap<String, String> mRenamedPackages = new ArrayMap<String, String>();
复制代码

这四个对象在PackageManagerService中会常常遇到,为了方便后面的理解,请记一下哈

PackageManagerService的初始化

有了前面的铺垫,咱们来看下PackageManagerService的初始化过程。

PackageManagerService是在SystemServer中初始化的,分别在startBootstrapServices()startOtherServices()中都进行了一些处理。相关代码以下:

private void startBootstrapServices() {
    ......
    // 启动 installd,PMS依赖此服务
    Installer installer = mSystemServiceManager.startService(Installer.class);
    ......
    // 判断vold.decrypt是否被设定为加密状态
    // mOnlyCore=true表示加密状态,只能处理系统应用
    // 通常状况mOnlyCore为false
    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;
    }
    // 调用main()初始化PMS
    mPackageManagerService = PackageManagerService.main(mSystemContext, installer, mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
    mFirstBoot = mPackageManagerService.isFirstBoot();
    ......
    // 若是设备没有加密,尝试启动 OtaDexoptService
    // OtaDexoptService 是用于A/B更新的一个服务,会用到PMS
    if (!mOnlyCore) {
        boolean disableOtaDexopt = SystemProperties.getBoolean("config.disable_otadexopt",
                    false);
        if (!disableOtaDexopt) {
                OtaDexoptService.main(mSystemContext, mPackageManagerService);
        }
    }
    ......
}
private void startOtherServices() {
    if (!mOnlyCore) {
        ......
        // 进行dex优化
        mPackageManagerService.updatePackagesIfNeeded();
    }
    ......
    // 进行磁盘维护
    mPackageManagerService.performFstrimIfNeeded();
    ......
    // PMS 准备就绪
    mPackageManagerService.systemReady();
}
复制代码

上面就是SystemServer中和PackageManagerService启动相关的操做, 咱们先看下PackageManagerServicemain()方法

PackageManagerServicemain()方法

main()方法内容以下:

public static PackageManagerService main(Context context, Installer installer, boolean factoryTest, boolean onlyCore) {
        // Self-check for initial settings.
        PackageManagerServiceCompilerMapping.checkProperties();
        // 建立 PackageManagerService 对象
        PackageManagerService m = new PackageManagerService(context, installer, factoryTest, onlyCore);
        // 启用部分系统应用
        m.enableSystemUserPackages();
        // 将服务添加到ServiceManager
        // 包括package和package_native
        ServiceManager.addService("package", m);
        final PackageManagerNative pmn = m.new PackageManagerNative();
        ServiceManager.addService("package_native", pmn);
        return m;
    }
复制代码

main()方法比较简单,主要进行了:

  • 建立PackageManagerService对象
    • 核心对象,须要详细分析
  • 建立PackageManagerNative对象,只是简单提供了三个功能接口
    • String[] getNamesForUids
    • String getInstallerForPackage
    • long getVersionCodeForPackage
  • 而后将两个对象添加到ServiceManager

咱们来重点看下PackageManagerService的建立过程,也就是构造方法。

PackageManagerService的构造方法

PackageManagerService的构造方法比较长,根据构造方法中的EventLogTags咱们能够划分为5个阶段:

public PackageManagerService(Context context, Installer installer, boolean factoryTest, boolean onlyCore) {
        ......
        EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,SystemClock.uptimeMillis());
        ......
        EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START, startTime);
        ......
        EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START, SystemClock.uptimeMillis());
        ......
        EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END, SystemClock.uptimeMillis());
        ......
        EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY, SystemClock.uptimeMillis());
        ......
    }
复制代码

BOOT_PROGRESS_PMS_START

BOOT_PROGRESS_PMS_START阶段主要进行了:

  • 建立DisplayMetrics对象、设置Installer引用
  • 建立PermissionManager对象
  • 根据permission信息建立Settings对象,并添加部分uid信息
  • 建立DexManager对象跟踪dex使用状况
  • 建立SystemConfig对象用来获取系统配置信息,如:共享库列表、权限等
  • 建立PackageHandler对象,实际上是一个HandlerThread类,并添加到Watchdog
  • 对于首次启动,将预编译文件拷贝到data分区

具体代码以下:

// ###### BOOT_PROGRESS_PMS_START 阶段 ###### 
    EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,SystemClock.uptimeMillis());
    // 检测SDK版本
    if (mSdkVersion <= 0) {
        Slog.w(TAG, "**** ro.build.version.sdk not set!");
    }
    mContext = context;
    // 是否为工厂模式,工厂模式主要用于系统功能检测
    // 能够进行一些按键转义等操做,正式产品通常都为false
    mFactoryTest = factoryTest;
    // 是否只处理系统应用,通常为false
    mOnlyCore = onlyCore;
    // 建立DisplayMetrics对象储存屏幕显示信息
    mMetrics = new DisplayMetrics();
    // 设置installer
    mInstaller = installer;
    // Create sub-components that provide services / data. Order here is important.
    synchronized (mInstallLock) {
    synchronized (mPackages) {
        // Expose private service for system components to use.
        // 添加PackageManagerInternal到本地服务
        LocalServices.addService(PackageManagerInternal.class, new PackageManagerInternalImpl());
        // 初始化多用户管理服务
        sUserManager = new UserManagerService(......);
        // 初始化权限管理服务
        mPermissionManager = PermissionManagerService.create(......);
        mDefaultPermissionPolicy = mPermissionManager.getDefaultPermissionGrantPolicy();
        // 建立Settings对象
        mSettings = new Settings(mPermissionManager.getPermissionSettings(), mPackages);
    }
    }
    // 经过addSharedUserLPw方法添加SharedUserSetting对象到Settings中
    // sharedUserId 属性相同的包能够运行在同一个进程,或者能够相互读取资源
    // 这里添加了一共是7种系统的 uid:system、phone、log、nfc、bluetooth、shell、se
    mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
            ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
            ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    ......
    // 建立dexopt命令的帮助类
    mPackageDexOptimizer = new PackageDexOptimizer(installer, mInstallLock, context,
            "*dexopt*");
    DexManager.Listener dexManagerListener = DexLogger.getListener(this,
            installer, mInstallLock);
    // 建立 DexManager 用来跟踪dex文件的使用状况
    mDexManager = new DexManager(mContext, this, mPackageDexOptimizer, installer, mInstallLock, dexManagerListener);
    // 建立ART管理服务
    mArtManagerService = new ArtManagerService(mContext, this, installer, mInstallLock);
    mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());
    ......
    // 获取默认屏幕参数
    getDefaultDisplayMetrics(context, mMetrics);
    // 建立 SystemConfig 对象,用来保存系统全局配置信息
    SystemConfig systemConfig = SystemConfig.getInstance();
    mAvailableFeatures = systemConfig.getAvailableFeatures();
    ......
    synchronized (mInstallLock) {
    // writer
    synchronized (mPackages) {
        // 建立用来处理消息的线程,并添加到Watchdog中监控
        mHandlerThread = new ServiceThread(TAG,
                Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
        mHandlerThread.start();
        mHandler = new PackageHandler(mHandlerThread.getLooper());
        ......
        Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);
        // 建立即时应用管理模块
        mInstantAppRegistry = new InstantAppRegistry(this);
        // 经过 systemConfig 获取系统中的共享库列表
        ArrayMap<String, String> libConfig = systemConfig.getSharedLibraries();
        final int builtInLibCount = libConfig.size();
        for (int i = 0; i < builtInLibCount; i++) {
            String name = libConfig.keyAt(i);
            String path = libConfig.valueAt(i);
            addSharedLibraryLPw(path, null, name, SharedLibraryInfo.VERSION_UNDEFINED,
                    SharedLibraryInfo.TYPE_BUILTIN, PLATFORM_PACKAGE_NAME, 0);
        }
        // 打开 SELinux 的 Policy 文件:
        // 1. /security/mac_permissions.xml
        // 2. /etc/security/mac_permissions.xml
        SELinuxMMAC.readInstallPolicy();
        ......
        // 读取packages.xml文件,解析后将数据存放到mSettings中
        mFirstBoot = !mSettings.readLPw(sUserManager.getUsers(false));
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);

        // Clean up orphaned packages for which the code path doesn't exist
        ......
        if (mFirstBoot) {
            // 若是是首次启动
            // 向Init进程请求(经过setProp的方式)
            // 将预编译dex拷贝到data分区
            requestCopyPreoptedFiles();
        }
    }
    }
复制代码

BOOT_PROGRESS_PMS_SYSTEM_SCAN_START

BOOT_PROGRESS_PMS_SYSTEM_SCAN_START阶段主要进行:

  • 获取环境变量BOOTCLASSPATHSYSTEMSERVERCLASSPATH以及系统版本信息
  • 根据版本信息确认升级策略
    • Android M以前版本需调整逻辑为运行时获取
    • Android N以前版本须要调整为首次启动
  • 扫描vendor,productoverlay目录,收集文件信息
  • 扫描vendor,product,system,oem等分区下的apppriv-app目录,收集应用信息,并将搜集到的信息保存到mPackages
  • PMS中的mPackages集合与mSettings中的mPackages集合进行比对,过滤掉无效的应用
  • 删除临时文件和未使用到的SharedUserSetting对象

相关代码以下:

// ###### BOOT_PROGRESS_PMS_SYSTEM_SCAN_START 阶段 ###### 
        long startTime = SystemClock.uptimeMillis();
        EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START, startTime);

        final String bootClassPath = System.getenv("BOOTCLASSPATH");
        final String systemServerClassPath = System.getenv("SYSTEMSERVERCLASSPATH");
        ......
        File frameworkDir = new File(Environment.getRootDirectory(), "framework");
        final VersionInfo ver = mSettings.getInternalVersion();
        mIsUpgrade = !Build.FINGERPRINT.equals(ver.fingerprint);
        ......
        // 对于Android M以前版本升级上来的状况,需将系统应用程序权限从安装升级到运行时
        mPromoteSystemApps = mIsUpgrade && ver.sdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1;
        // 对于Android N以前版本升级上来的状况,需像首次启动同样处理package 
        mIsPreNUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N;
        mIsPreNMR1Upgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N_MR1;
        // 扫描前保存已经存在的系统 packages,系统升级后需从新申请权限
        // 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);
                }
            }
        }
        // 准备解析package缓存
        mCacheDir = preparePackageParserCache(mIsUpgrade);
        ......
        // 经过scanDirTracedLI扫描指定目录的应用信息,包括:
        // vendor/overlay、/product/overlay
        // system/framework、system/priv-app、/system/app
        // vendor/priv-app、/vendor/app
        // odm/priv-app、/odm/app、
        // product/priv-app、/product/app
        // 并将相关的应用信息保存到mPackages中
        scanDirTracedLI(new File(VENDOR_OVERLAY_DIR),...);
        scanDirTracedLI(new File(PRODUCT_OVERLAY_DIR),...);
        .....
        // Prune any system packages that no longer exist.
        final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<>();
        // Stub packages must either be replaced with full versions in the /data
        // partition or be disabled.
        final List<String> stubSystemApps = new ArrayList<>();
        if (!mOnlyCore) {
            // do this first before mucking with mPackages for the "expecting better" case
            final Iterator<PackageParser.Package> pkgIterator = mPackages.values().iterator();
            while (pkgIterator.hasNext()) {
                final PackageParser.Package pkg = pkgIterator.next();
                if (pkg.isStub) {
                    stubSystemApps.add(pkg.packageName);
                }
            }
            // 循环处理mSettings.mPackages中的应用信息
            final Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
            while (psit.hasNext()) {
                PackageSetting ps = psit.next();
                if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
                    // 忽略普通应用
                    continue;
                }
                // 请注意,此处的mPackages是在PMS中的成员变量
                // 里面存放的是scanDir扫描目录后获得的应用信息
                final PackageParser.Package scannedPkg = mPackages.get(ps.name);
                if (scannedPkg != null) {
                    // 若是mPackages的系统应用是待升级包的,把它从mPackages中移除
                    // disable说明是<update-package/>标签表示的应用
                    if (mSettings.isDisabledSystemPackageLPr(ps.name)) {
                        // 从扫描表mPackages中移除
                        removePackageLI(scannedPkg, true);
                        // 将其添加到mExpectingBetter集合中
                        // 在下一阶段会处理
                        mExpectingBetter.put(ps.name, ps.codePath);
                    }
                    continue;
                }
                // 执行到此处说明mPackages中没有ps应用信息
                // 也就是系统中不存在该应用
                // 检查是否属于<update-package/>标签
                if (!mSettings.isDisabledSystemPackageLPr(ps.name)) {
                    // 不属于<update-package/>标签,说明是残留在packages.xml中的
                    // 移除,后面还会进行数据清理
                    psit.remove();
                } else {
                    // 应用属于<update-package/>标签
                    // 添加到 possiblyDeletedUpdatedSystemApps 集合中
                    ......
                    possiblyDeletedUpdatedSystemApps.add(ps.name);
                }
            }
        }
        //delete tmp files
        deleteTempPackageFiles();
        final int cachedSystemApps = PackageParser.sCachedPackageReadCount.get();
        // 删除mSettings中没有关联任何应用的SharedUserSetting对象
        mSettings.pruneSharedUsersLPw();
        final long systemScanTime = SystemClock.uptimeMillis() - startTime;
        ......
复制代码

BOOT_PROGRESS_PMS_DATA_SCAN_START

BOOT_PROGRESS_PMS_DATA_SCAN_START主要进行了:

  • 扫描用户目录/data/app/data/app-private下的应用信息,并添加到mPackages
  • 遍历possiblyDeletedUpdatedSystemApps集合,并逐一将其从Settings的中disabledSystemPackage集合中删除
    • possiblyDeletedUpdatedSystemApps集合中存放的是在packages.xml文件中被标记成了<update-package/>,可是应用文件还未找到的应用
    • 若是在用户目录下存在该应用升级文件,调整应用的权限为普通应用
    • 若是不存在,清除应用相关数据
  • 遍历mExpectingBetter集合。
    • mExpectingBetter集合中存放的是在packages.xml文件中被标记成了<update-package/>,资料数据齐全,不能直接启动,须要配合用户目录下的完整版应用才能启动
    • 此时根据集合中的应用名称,从/data/vendor/system等目录查找,找到后将其扫描到mPackages集合中
  • 读取StorageManagerSetupWizard包名,更新全部应用的动态库路径

具体代码以下:

if (!mOnlyCore) {
        EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START, SystemClock.uptimeMillis());
        // 扫描 /data/app 目录,收集应用信息
        scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);
        // 扫描 /data/app-private 目录,收集应用信息
        scanDirTracedLI(sDrmAppPrivateInstallDir, mDefParseFlags
                | PackageParser.PARSE_FORWARD_LOCK,
                scanFlags | SCAN_REQUIRE_KNOWN, 0);
        // possiblyDeletedUpdatedSystemApps中存放的应用是在packages.xml文件中被标记成了已升级的系统应用,可是文件却不在了
        // 所以这里检查用户目录下的升级文件是否存在,而后进行处理
        for (String deletedAppName : possiblyDeletedUpdatedSystemApps) {
            PackageParser.Package deletedPkg = mPackages.get(deletedAppName);
            // 先将应用从<update-package/>集合中移除
            mSettings.removeDisabledSystemPackageLPw(deletedAppName);
            final String msg;
            if (deletedPkg == null) {
                // 用户安装目录也不存在该升级文件
                msg = "Updated system package " + deletedAppName
                        + " no longer exists; removing its data";
            } else {
                // 用户空间找到了升级文件,说明系统目录下的文件可能被删除了
                // 所以,把应用的系统属性去掉,以普通应用的方式运行
                msg = "Updated system package + " + deletedAppName
                        + " no longer exists; revoking system privileges";
                final PackageSetting deletedPs = mSettings.mPackages.get(deletedAppName);
                deletedPkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;
                deletedPs.pkgFlags &= ~ApplicationInfo.FLAG_SYSTEM;
            }
            ......
        }
        // 放到 mExpectingBetter 列表中的应用是带有升级包的
        // 在上一阶段解析时把它们从 mPackages 列表中已经移除并放到了 mExpectingBetter 列表中
        for (int i = 0; i < mExpectingBetter.size(); i++) {
            final String packageName = mExpectingBetter.keyAt(i);
            if (!mPackages.containsKey(packageName)) {
                final File scanFile = mExpectingBetter.valueAt(i);
                final @ParseFlags int reparseFlags;
                final @ScanFlags int rescanFlags;
                // 从下面路径中查找应用
                if (FileUtils.contains(privilegedAppDir, scanFile)) {
                    .....
                } else if (FileUtils.contains(systemAppDir, scanFile)) {
                    ......
                } else if (FileUtils.contains(privilegedVendorAppDir, scanFile)
                        || FileUtils.contains(privilegedOdmAppDir, scanFile)) {
                    ......
                } else if (FileUtils.contains(vendorAppDir, scanFile)
                        || FileUtils.contains(odmAppDir, scanFile)) {
                    ......
                } else if (FileUtils.contains(oemAppDir, scanFile)) {
                    ......
                } else if (FileUtils.contains(privilegedProductAppDir, scanFile)) {
                    ......
                } else if (FileUtils.contains(productAppDir, scanFile)) {
                    ......
                } else {
                    // 若是没找到,不作任何处理
                    continue;
                }
                mSettings.enableSystemPackageLPw(packageName);
                try {
                    // 扫描并处理该应用
                    scanPackageTracedLI(scanFile, reparseFlags, rescanFlags, 0, null);
                } catch (PackageManagerException e) {
                    Slog.e(TAG, "Failed to parse original system package: " + e.getMessage());
                }
            }
        }
        // 此时用户空间的扫描基本都已经完成
        // 解压安装 stub system app
        decompressSystemApplications(stubSystemApps, scanFlags);
        ......
    }
    mExpectingBetter.clear();
    // 获取StorageManager包名
    mStorageManagerPackage = getStorageManagerPackageName();
    // 获取SetupWizard 包名(开机引导)
    mSetupWizardPackage = getSetupWizardPackageName();
    ......
    // 更新全部应用的动态库路径
    updateAllSharedLibrariesLPw(null);
    ......
    // Now that we know all the packages we are keeping,
    // read and update their last usage times.
    mPackageUsage.read(mPackages);
    mCompilerStats.read();
复制代码

BOOT_PROGRESS_PMS_SCAN_END

BOOT_PROGRESS_PMS_SCAN_END阶段的主要进行了:

  • 检查SDK版本,更新应用权限
  • 检查启动条件(首次正常启动、基于Android M升级后正常启动)设置默认首选应用
  • 获取UUID_DEFAULT卷上的核心系统应用包名,并准备相关的应用数据
  • 检查是否为OTA后首次启动,是:进行cache清理
  • 最后,将mSetting中的数据更新到packages.xml

主要代码以下:

EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END, SystemClock.uptimeMillis());
    // 若是平台的SDK版本和上次启动时相比发生了变化,可能permission的定义也改变了
    // 所以须要从新赋予应用权限
    final boolean sdkUpdated = (ver.sdkVersion != mSdkVersion);
    mPermissionManager.updateAllPermissions(
            StorageManager.UUID_PRIVATE_INTERNAL, sdkUpdated, mPackages.values(),
            mPermissionCallback);
    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);
        }
    }
    ......
    // 获取 UUID_DEFAULT 上的核心系统应用包名集合
    List<String> deferPackages = reconcileAppsDataLI(StorageManager.UUID_PRIVATE_INTERNAL,  UserHandle.USER_SYSTEM, storageFlags, true /* migrateAppData */, true /* onlyCoreApps */);
    // 为deferPackages集合中的应用准备应用数据
    mPrepareAppDataFuture = SystemServerInitThreadPool.get().submit(...);
    ......
    // 若是是执行OTA后的首次启动,须要清除cache
    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(...);
            }
        }
        ver.fingerprint = Build.FINGERPRINT;
    }
    ......
    // 把 mSettings 内容保存到 packages.xml
    mSettings.writeLPr();
复制代码

BOOT_PROGRESS_PMS_READY

BOOT_PROGRESS_PMS_READY阶段内容比较简单,方法内容以下:

EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY, SystemClock.uptimeMillis());
        ......
        // 建立 PackageInstallerService 
        mInstallerService = new PackageInstallerService(context, this);
        ......
        // 获取每一个user对应的已安装应用信息,填充到userPackages中
        final Map<Integer, List<PackageInfo>> userPackages = new HashMap<>();
        final int[] currentUserIds = UserManagerService.getInstance().getUserIds();
        for (int userId : currentUserIds) {
            userPackages.put(userId, getInstalledPackages(/*flags*/ 0, userId).getList());
        }
        // 将userPackages添加到 mDexManager 中用来跟踪dex使用信息
        mDexManager.load(userPackages);
        ......
        // 触发垃圾回收
        Runtime.getRuntime().gc();
        ......
复制代码

PMS构造方法总结

PackageManagerService构造方法的执行过程就是:

  • 先读取packages.xml文件内容,解析并保存在成员变量mSettings中。
    • 这至关于加载设备上次运行时的应用状态信息
  • 而后扫描设备中的几个分区目录下的应用文件,把扫描结果保存到PMSmPackages中。
    • 这记录的是当前系统中的应用状态信息
  • 后面就是对两次的应用状态信息进行:比对、从新调整、扫描特定目录。
  • 最后将应用信息从新写回packages.xml文件

调用时序图以下(为了简洁,移除了部分方法):

image

startOtherServices()中的PMS操做

前面已经介绍,在startOtherServices()中,PMS还进行了以下三个操做:

  • mPackageManagerService.updatePackagesIfNeeded():检查是否须要更新package
  • mPackageManagerService.performFstrimIfNeeded():执行磁盘清理,释放空间
  • mPackageManagerService.systemReady():执行一些默认权限的检查和package信息更新操做以及进行一些相关服务的状态通知(*.systemReady())

咱们简单来看下

updatePackagesIfNeeded()

updatePackagesIfNeeded()用来检查是否须要去更新packages并进行dex优化

方法内容以下,注释比较详细:

public void updatePackagesIfNeeded() {
        enforceSystemOrRoot("Only the system can request package update");

        // We need to re-extract after an OTA.
        boolean causeUpgrade = isUpgrade();

        // First boot or factory reset.
        boolean causeFirstBoot = isFirstBoot() || mIsPreNUpgrade;

        // We need to re-extract after a pruned cache, as AoT-ed files will be out of date.
        boolean causePrunedCache = VMRuntime.didPruneDalvikCache();
        
        // 若是不是:OTA、首次启动、升级到Android N、虚拟机缓存调整
        // 直接返回
        if (!causeUpgrade && !causeFirstBoot && !causePrunedCache) {
            return;
        }
        List<PackageParser.Package> pkgs;
        synchronized (mPackages) {
            // 获取安装的Package集合
            pkgs = PackageManagerServiceUtils.getPackagesForDexopt(mPackages.values(), this);
        }
        final long startTime = System.nanoTime();
        // 执行升级操做
        final int[] stats = performDexOptUpgrade(pkgs, mIsPreNUpgrade /* showDialog */,
                    causeFirstBoot ? REASON_FIRST_BOOT : REASON_BOOT,
                    false /* bootComplete */);
        ......
    }
复制代码

真正执行升级的方法是performDexOptUpgrade(),咱们看下:

private int[] performDexOptUpgrade(List<PackageParser.Package> pkgs, ...) {
        ......
        final int numberOfPackagesToDexopt = pkgs.size();
        for (PackageParser.Package pkg : pkgs) {
            numberOfPackagesVisited++;
            boolean useProfileForDexopt = false;
            if ((isFirstBoot() || isUpgrade()) && isSystemApp(pkg)) {
                // 针对系统app,若是是首次启动或者升级的状态
                // 先检测应用的initial preopt profiles是否存在
                if (profileFile.exists()) {
                    ......
                    // 文件存在的话,经过Installer拷贝文件
                    mInstaller.copySystemProfile(profileFile.getAbsolutePath(), ...);
                } else {
                    // 文件不存在,检查<update-package/>标签中的应用
                    PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(pkg.packageName);
                    if (disabledPs != null && disabledPs.pkg.isStub) {
                        // 若是标签中存在,而且应用类型是Stub,查找特殊路径
                        String systemProfilePath = getPrebuildProfilePath(disabledPs.pkg).replace(STUB_SUFFIX, "");
                        profileFile = new File(systemProfilePath);
                        ......
                        mInstaller.copySystemProfile(profileFile.getAbsolutePath(),...);
                    }
                }
            }
            if (!PackageDexOptimizer.canOptimizePackage(pkg)) {
                ......
                // 若是应用不支持优化,直接跳过
                continue;
            }
            ......
            // performDexOptTraced的调用关系及其恶心
            // 跟踪代码,最后调用的是
            // PackageDexOptimizer 类 dexOptPath 函数
            // 函数经过mInstaller.dexopt()函数来进行转化
            // mInstaller.dexopt() 经过 Binder 远程调用installd服务
            performDexOptTraced(new DexoptOptions(
                    pkg.packageName,
                    pkgCompilationReason,
                    dexoptFlags));
            ......
        }
        ......
    }
复制代码

performFstrimIfNeeded()

performFstrimIfNeeded()用来进行磁盘清理工做,相关代码以下:

public void performFstrimIfNeeded() {
        enforceSystemOrRoot("Only the system can request fstrim");

        // Before everything else, see whether we need to fstrim.
        try {
            // 获取StorageManagerService对象
            IStorageManager sm = PackageHelper.getStorageManager();
            if (sm != null) {
                boolean doTrim = false;
                // 读取fstrim的间隔,默认3天
                final long interval = android.provider.Settings.Global.getLong(
                        mContext.getContentResolver(),
                        android.provider.Settings.Global.FSTRIM_MANDATORY_INTERVAL,
                        DEFAULT_MANDATORY_FSTRIM_INTERVAL);
                if (interval > 0) {
                    // 判断间隔
                    final long timeSinceLast = System.currentTimeMillis() - sm.lastMaintenance();
                    if (timeSinceLast > interval) {
                        doTrim = true;
                    }
                }
                if (doTrim) {
                    ......
                    // runMaintenance先经过sm的发送H_FSTRIM消息给Handler
                    // 而后mVold对象经过binder调用vold进程的fstrim函数
                    sm.runMaintenance();
                }
            } else {
                Slog.e(TAG, "storageManager service unavailable!");
            }
        } catch (RemoteException e) {
            // Can't happen; StorageManagerService is local
        }
    }
复制代码

systemReady()

systemReady()主要进行的是权限相关的更新操做,以及一些服务状态的变动。

相关代码以下:

@Override
    public void systemReady() {
        enforceSystemOrRoot("Only the system can claim the system is ready");
        mSystemReady = true;
        ...... // 省略一个和InstantApp相关的 ContentObserver
        CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(), this, mContext.getContentResolver(), UserHandle.USER_SYSTEM);
        ......
        // 获取并设置 compatibilityModeEnabled 兼容模式
        boolean compatibilityModeEnabled = android.provider.Settings.Global.getInt(
                mContext.getContentResolver(),
                android.provider.Settings.Global.COMPATIBILITY_MODE, 1) == 1;
        PackageParser.setCompatibilityModeEnabled(compatibilityModeEnabled);
        ......
        int[] grantPermissionsUserIds = EMPTY_INT_ARRAY;
        synchronized (mPackages) {
            // 检查PreferredActivity是否存在,及时清理不存在的
            ArrayList<PreferredActivity> removed = new ArrayList<PreferredActivity>();
            for (int i=0; i<mSettings.mPreferredActivities.size(); i++) {
                ......
            }
            // 检查用户权限,将不是默认权限的userID添加到 grantPermissionsUserIds 集合中
            for (int userId : UserManagerService.getInstance().getUserIds()) {
                if (!mSettings.areDefaultRuntimePermissionsGrantedLPr(userId)) {
                    grantPermissionsUserIds = ArrayUtils.appendInt(
                            grantPermissionsUserIds, userId);
                }
            }
        }
        sUserManager.systemReady();
        // 设置为默认权限
        for (int userId : grantPermissionsUserIds) {
            mDefaultPermissionPolicy.grantDefaultPermissions(userId);
        }
        ......
        // 更新权限
        synchronized (mPackages) {
            mPermissionManager.updateAllPermissions(
                    StorageManager.UUID_PRIVATE_INTERNAL, false, mPackages.values(),
                    mPermissionCallback);
        }
        // 发送systemReady通知
        if (mPostSystemReadyMessages != null) {
            for (Message msg : mPostSystemReadyMessages) {
                msg.sendToTarget();
            }
            mPostSystemReadyMessages = null;
        }
        // 注册外部储存设备监听
        final StorageManager storage = mContext.getSystemService(StorageManager.class);
        storage.registerListener(mStorageListener);
        // 发送关联服务的 systemReady 通知
        mInstallerService.systemReady();
        mDexManager.systemReady();
        mPackageDexOptimizer.systemReady();
        // 获取 StorageManager 服务并添加相关的状态通知策略
        StorageManagerInternal StorageManagerInternal = LocalServices.getService(
                StorageManagerInternal.class);
        StorageManagerInternal.addExternalStoragePolicy(...);
        // Now that we're mostly running, clean up stale users and apps
        sUserManager.reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL);
        reconcileApps(StorageManager.UUID_PRIVATE_INTERNAL);
        // 发送 PermissionManager 的 systemReady 通知
        mPermissionManager.systemReady();
        ......
    }
复制代码

到这里,PMS的初始化主要过程就梳理完了,整个流程仍是比较长的,不少细节作了忽略,接下来咱们从三个方面来看下PMS初始化细节:

  • permission文件处理
  • 应用目录的扫描过程
  • APK文件的解析过程

下一篇深刻Android系统(十)PMS-2-初始化的一些细节

相关文章
相关标签/搜索