把这个复杂的 PMS 创建过程想象成一个 Android 世界里的"软件包管理超级工厂"的建设故事,结合代码一步步来揭秘。
故事背景:
Android 世界要运转起来,需要成千上万的服务(工人)。其中最重要的一批,叫"系统服务",它们由一位叫 SystemServer
的大管家负责招募和组织。PackageManagerService
(PMS) 就是这位大管家招募的关键"工厂厂长",它的职责是管理整个 Android 世界里所有 App(软件包)的安装、卸载、信息查询、权限分配等等,相当于一个超级 App 仓库管理员兼质量检查员兼权限发放员。
第一章:大管家 SystemServer 的筹备工作 (SystemServer 处理部分)
-
大管家登场 (
SystemServer.main()
):typescriptjava Copy public static void main(String[] args) { new SystemServer().run(); // 大管家启动,开始干活! }
故事:Android 系统内核启动后,把接力棒交给了
SystemServer
。main
方法是大管家启动的入口,它二话不说就调用了自己的run()
方法。 -
搭建基础 (
SystemServer.run()
):scssjava Copy private void run() { try { Looper.prepareMainLooper(); // 1. 建立消息传递系统(比如工厂内部电话网) System.loadLibrary("android_servers"); // 2. 加载关键工具库(基础施工设备进场) ... // (其他初始化,如关机处理) createSystemContext(); // 3. 创建系统全局上下文环境(给工厂画个规划图) mSystemServiceManager = new SystemServiceManager(mSystemContext); // 4. 创建服务经理(招个HR主管) ... // (把HR主管登记在册) } finally { ... } try { traceBeginAndSlog("StartServices"); startBootstrapServices(); // 5. 启动"奠基性"服务(招核心骨干厂长) startCoreServices(); // 6. 启动"核心"服务(招重要部门主管) startOtherServices(); // 7. 启动"其他"服务(招普通工人) } catch (Throwable ex) { ... } }
故事:
-
(1-4) 大管家
SystemServer
首先要给自己搭好办公环境:建立消息循环系统(Looper
)保证内部指令能传达;加载libandroid_servers.so
这个包含了很多基础工具的库;创建全局的上下文Context
(可以理解为工厂的规划蓝图和基础资源);最重要的是创建SystemServiceManager
(SSM) ------ 相当于人力资源部主管,专门负责招募、启动和管理所有系统服务(厂长们)。 -
(5-7) 环境搭好后,大管家开始分批次招募服务:
startBootstrapServices()
: 招募奠基性服务 。这些服务是系统最底层、最关键的,其他很多服务都依赖它们才能工作。就像工厂需要先有厂长(AMS)、电力主管(PowerManagerService)、原材料仓库主管(PMS)等核心人物,工厂才能开始运转。PMS 就在这里被招募!startCoreServices()
: 招募核心服务。这些服务也很重要,支撑着系统的基础功能,比如日志管理(DropBoxManagerService)、电池管理(BatteryService)等。相当于工厂的质检部、能源监控部。startOtherServices()
: 招募其他服务。这些服务功能相对独立或启动不那么紧急,比如摄像头管理(CameraService)、闹钟服务(AlarmManagerService)等。相当于工厂的食堂、运输队等。
-
-
招募 PMS 厂长 (
startBootstrapServices()
):csharpjava Copy private void startBootstrapServices() { ... // (检查设备加密状态,可能影响后续操作) traceBeginAndSlog("StartPackageManagerService"); // 调用 PMS 的 main 方法!相当于给 PMS 厂长打电话:"快来建厂吧!" mPackageManagerService = PackageManagerService.main( mSystemContext, // 系统蓝图和环境 installer, // 施工队队长(Installer, 负责具体安装卸载操作) mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, // 是否在测试模式 mOnlyCore // 是否只处理核心App(比如加密设备刚启动时) ); mFirstBoot = mPackageManagerService.isFirstBoot(); // 记录是不是第一次开机 ... // (其他操作) }
故事:在招募奠基性服务的环节,大管家
SystemServer
决定创建 PMS 工厂。它没有直接用new
来建,而是调用了 PMS 类自己的main()
方法。这相当于给 PMS 厂长打了个电话:"喂,PMS 吗?现在给你建厂授权(mSystemContext
),给你配个施工队队长(installer
),告诉你现在的模式(测试/正式、核心/全功能),你赶紧来把工厂建起来吧!" -
PMS 厂长报到建厂 (
PackageManagerService.main()
):javajava Copy public static PackageManagerService main(Context context, Installer installer, boolean factoryTest, boolean onlyCore) { ... // (检查编译配置) // 真正开始建设 PMS 工厂! PackageManagerService m = new PackageManagerService(context, installer, factoryTest, onlyCore); ... // (设置多用户支持) // 向 ServiceManager 注册自己:"工厂建好了,以后找我就打这个电话(service name "package")" ServiceManager.addService("package", m); return m; // 把建好的工厂报告给 SystemServer 大管家 }
故事:PMS 厂长接到电话后,立刻行动。
main()
方法做了两件大事:- 建造工厂本体: 调用 PMS 的构造函数
new PackageManagerService(...)
。这是最复杂、最耗时的部分,相当于把工厂的地基、厂房、仓库、质检线、管理系统都建好配置好。我们下一章重点讲这个。 - 开张营业: 工厂建好后,厂长立刻去
ServiceManager
(可以理解为一个全球服务黄页)那里登记:"大家好,我是软件包管理服务,我叫package
,以后谁需要安装、卸载、查询 App,就打这个服务名找我!"。这样,其他系统服务(如 AMS)或 App 就能通过ServiceManager.getService("package")
找到 PMS 来办事了。
- 建造工厂本体: 调用 PMS 的构造函数
第二章:PMS 超级工厂的建设 (PMS 构造方法)
PMS 的构造方法非常庞大(600+行),可以清晰地分为 5 个主要建设阶段,每个阶段开工时都会在工程日志(EventLog
)上记一笔:
-
阶段一:奠基与规划 (BOOT_PROGRESS_PMS_START)
scssjava Copy public PackageManagerService(Context context, Installer installer, boolean factoryTest, boolean onlyCore) { ... // (安装锁、Trace等) EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START, SystemClock.uptimeMillis()); // 1. 准备基础工具和蓝图库 mMetrics = new DisplayMetrics(); // 屏幕规格信息(包装箱尺寸标准) mSettings = new Settings(mPackages); // 核心数据库!存储所有App的安装设置、权限、状态等。相当于工厂的中央档案库。 // 初始化档案库:预置几个核心"共享用户ID"组 (如 android.uid.system) mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID, ...); mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID, ...); ... // (其他共享组) mInstaller = installer; // 施工队队长 (负责调用底层 installd) mPackageDexOptimizer = ... // Dex优化工具(打包优化机) mDexManager = ... // Dex管理器 ... // (其他管理器:文件移动回调、权限监听) getDefaultDisplayMetrics(context, mMetrics); // 获取屏幕信息 // 2. 加载系统全局配置 (SystemConfig) SystemConfig systemConfig = SystemConfig.getInstance(); mGlobalGids = systemConfig.getGlobalGids(); // 全局用户组ID列表 mSystemPermissions = systemConfig.getSystemPermissions(); // 系统定义的权限列表(所有App能申请哪些权限的基础) mAvailableFeatures = systemConfig.getAvailableFeatures(); // 系统支持的功能特性列表 mProtectedPackages = new ProtectedPackages(mContext); // 受保护应用名单(VIP仓库区) // 3. 建立核心工作区和通信机制 synchronized (mInstallLock) { ... } // 安装操作专用锁(仓库装卸区门禁) synchronized (mPackages) { ... } // 内存数据结构锁(中央档案库门禁) mHandlerThread = new ServiceThread(...); // 创建后台工作线程(物流调度中心) mHandlerThread.start(); mHandler = new PackageHandler(mHandlerThread.getLooper()); // PMS主处理器(物流调度主管),绑定到物流中心 Watchdog.getInstance().addThread(mHandler, ...); // 调度主管纳入系统"看门狗"监控(防止死锁) ... // (权限策略、Instant App管理) // 4. 规划Data分区仓库布局 File dataDir = Environment.getDataDirectory(); mAppInstallDir = new File(dataDir, "app"); // 用户App主仓库 (/data/app) mAppLib32InstallDir = new File(dataDir, "app-lib"); // 32位库仓库 mAsecInternalPath = new File(dataDir, "app-asec").getPath(); // 加密App仓库路径 mDrmAppPrivateInstallDir = new File(dataDir, "app-private"); // DRM保护App仓库 // 5. 启动多用户管理系统 (UserManagerService) sUserManager = new UserManagerService(..., this, ...); // 6. 读取上次建厂存档 (packages.xml, packages.list) mFirstBoot = !mSettings.readLPw(sUserManager.getUsers(false)); // 读档成功就不是第一次开机 ... // (如果读档失败或第一次,mFirstBoot=true) }
故事: PMS 厂长拿着蓝图(
context
)和施工队长(installer
)来到工地。- 立档案库 (
mSettings
): 建一个核心的中央档案库Settings
,预先把几个最重要的"工作组"(SharedUserId
,如android.uid.system
)登记进去。这些组里的 App 可以共享数据和进程。 - 配工具和标准: 确定屏幕标准 (
mMetrics
),领取官方颁发的权限清单、功能特性清单、受保护应用名单 (SystemConfig
)。 - 建物流体系: 划分两个关键工作区(安装锁
mInstallLock
保护对施工队installd
的访问;包信息锁mPackages
保护内存中的 App 信息)。创建后勤物流中心 (ServiceThread
) 和物流主管 (PackageHandler
),主管被系统"看门狗"盯着,防止卡车堵死(死锁)。 - 划仓库用地: 在
/data
分区规划好普通 App 仓库 (/data/app
)、32位库仓库、加密 App 仓库、DRM App 仓库的位置。 - 招用户管理员 (
UserManagerService
): Android 支持多用户,每个用户的 App 安装可能不同,需要专人管理。 - 查历史档案: 尝试读取上次工厂关闭时保存的档案 (
packages.xml
,packages.list
)。如果成功读到,说明不是第一次开机 (mFirstBoot=false
),档案里记录了所有已安装 App 的信息、权限授予状态等。如果读不到或文件损坏,那就是第一次开机 (mFirstBoot=true
),档案库是空的。
- 立档案库 (
-
阶段二:扫描系统仓库 (BOOT_PROGRESS_PMS_SYSTEM_SCAN_START)
scssjava Copy EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START, startTime); // 扫描关键系统目录 (相当于扫描预制在手机/system分区里的App) File frameworkDir = new File(Environment.getRootDirectory(), "framework"); // /system/framework (系统核心组件) scanDirTracedLI(frameworkDir, PARSE_IS_SYSTEM | ..., ...); File privilegedAppDir = new File(..., "priv-app"); // /system/priv-app (高权限系统App) scanDirTracedLI(privilegedAppDir, PARSE_IS_SYSTEM | PARSE_IS_PRIVILEGED, ...); File systemAppDir = new File(..., "app"); // /system/app (普通系统App) scanDirTracedLI(systemAppDir, PARSE_IS_SYSTEM, ...); File vendorAppDir = new File("/vendor/app"); // /vendor/app (厂商提供的App) scanDirTracedLI(vendorAppDir, PARSE_IS_SYSTEM, ...); File oemAppDir = new File(..., "app"); // /oem/app (OEM合作伙伴App) scanDirTracedLI(oemAppDir, PARSE_IS_SYSTEM, ...); // 处理可能的OTA升级残留问题 List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<>(); if (!mOnlyCore) { // 如果不是精简模式(加密设备刚启动) // 遍历中央档案库(mSettings)里标记为系统App的记录 for (PackageSetting ps : mSettings.mPackages.values()) { if (不是系统App) continue; // 看看在刚扫描的/system分区里有没有找到这个App的安装文件? PackageParser.Package scannedPkg = mPackages.get(ps.name); if (scannedPkg != null) { if (档案库标记这个系统App被更新过且禁用) { // 场景1:系统App有更新版存在 -> 移除旧版档案,期待在Data分区找到更新版 removePackageLI(scannedPkg, true); mExpectingBetter.put(ps.name, ps.codePath); // 期待在Data仓库找到新版 } } else { if (档案库标记这个系统App没被禁用) { ... // 处理异常 } else { // 场景2:档案库标记有旧版系统App更新包,但扫描没找到文件 -> 可能是OTA后被删除了? possiblyDeletedUpdatedSystemApps.add(ps.name); // 记下来,等扫描Data仓库后再处理 } } } }
故事: 工厂奠基完成,厂长带着质检员 (
scanDirTracedLI
) 去扫描手机出厂时预装好 App 的系统分区 (/system
,/vendor
,/oem
) 里的几个关键仓库:-
/system/framework
: 系统核心组件库。 -
/system/priv-app
: 拥有高权限的系统 App (如设置、电话)。 -
/system/app
: 普通系统 App。 -
/vendor/app
: 芯片厂商或手机厂商提供的 App。 -
/oem/app
: 运营商或合作伙伴预装的 App。质检员 (
scanDirTracedLI
) 的工作:- 进入目录。
- 对每个
.apk
文件进行"解析"(PackageParser
)。 - 提取 App 的名称、版本、权限声明、组件信息等。
- 将这些信息封装成
Package
对象。 - 将
Package
对象放入 PMS 的内存仓库 (mPackages
)。 - 在中央档案库 (
mSettings
) 做相应记录。
处理系统 App 的 OTA 问题: 上次系统升级后,有些系统 App 可能更新了,有些可能被删了。质检员在扫描系统分区时发现:
-
场景1 (找到文件且有更新标记): 在系统分区找到了这个 App,但档案库显示它已被更新(更新包应该在
/data
)。工厂决定:移除 当前在系统分区找到的这个旧版本的信息(removePackageLI
),并期待 稍后在/data
分区(用户仓库)能找到它的更新版(记录到mExpectingBetter
)。 -
场景2 (文件消失且有旧更新包标记): 档案库里记录着这个系统 App 有一个旧版的更新包存在,但这次在系统分区没扫描到 这个更新包文件!质检员怀疑这个更新包是不是在 OTA 后被删除了?先记下来 (
possiblyDeletedUpdatedSystemApps
),等扫描完用户仓库 (/data
) 后再确认处理。
-
-
阶段三:扫描用户仓库 (BOOT_PROGRESS_PMS_DATA_SCAN_START)
scssjava Copy if (!mOnlyCore) { // 如果不是精简模式 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START, ...); // 扫描用户安装的App仓库 (/data/app, /data/app-private) scanDirTracedLI(mAppInstallDir, 0, ...); // /data/app scanDirTracedLI(mDrmAppPrivateInstallDir, ..., ...); // /data/app-private // 处理阶段二遗留的"可能被删除的更新包" for (String deletedAppName : possiblyDeletedUpdatedSystemApps) { // 在用户仓库(/data)扫描后,内存仓库(mPackages)里有没有这个App? PackageParser.Package deletedPkg = mPackages.get(deletedAppName); if (deletedPkg == null) { // 没找到!确认是OTA后残留 -> 从档案库彻底删除记录(后续会清理数据) mSettings.removeDisabledSystemPackageLPw(deletedAppName); Log.w("Updated system package " + deletedAppName + " no longer exists; ..."); } else { // 找到了!但它不应该再享有系统App特权(因为原系统文件没了) Log.w("Updated system app " + deletedAppName + " no longer present; removing system privileges"); deletedPkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM; // 剥夺系统标志 ... // 在档案库也移除系统标志 } } // 处理阶段二记录的"期待找到的更新包" (mExpectingBetter) for (String packageName : mExpectingBetter.keySet()) { if (!mPackages.containsKey(packageName)) { // 在用户仓库没找到期待的更新包! Log.w("Expected better " + packageName + " but never showed up; reverting to system"); File scanFile = mExpectingBetter.get(packageName); // 根据原系统文件位置,重新按系统App解析它(使用对应的特权标志) int reparseFlags = ... | (如果在priv-app目录? PARSE_IS_PRIVILEGED : 0); // 在档案库重新启用这个系统App的原始记录 mSettings.enableSystemPackageLPw(packageName); // 重新扫描解析这个原始系统App文件 scanPackageTracedLI(scanFile, reparseFlags, ...); } } mExpectingBetter.clear(); // 处理完毕,清空期待列表 }
故事: 扫描完工厂自带的系统仓库,质检员们转向用户自己安装 App 的仓库
/data/app
和存放受保护 App 的/data/app-private
。流程和扫描系统仓库类似:解析.apk
,生成Package
对象,放入mPackages
,更新mSettings
。处理遗留问题:
-
处理"可能被删除的更新包" (
possiblyDeletedUpdatedSystemApps
):- 在
/data
也没找到 (deletedPkg == null
): 确认这个更新包被 OTA 删除了 !厂长下令从中央档案库 (mSettings
) 里彻底清除关于这个旧更新包的记录。后续会清理它的残留数据。 - 在
/data
找到了 (deletedPkg != null
): 这个 App 还在,但它失去了作为系统 App 的资格 (因为它的基础系统文件在阶段二扫描时没找到)。厂长下令:剥夺它的FLAG_SYSTEM
标志(不再是系统 App),在档案库里也做相应修改。
- 在
-
处理"期待找到的更新包" (
mExpectingBetter
):-
在
/data
没找到期待的更新包 (!mPackages.containsKey
): 厂长很失望!期待中的更新包没出现。只能回退到使用原始的系统 App 版本。厂长下令:- 根据这个系统 App 原始文件 (
scanFile
) 所在目录 (是/system/priv-app
还是/system/app
),决定重新解析它时应该带哪些特权标志 (reparseFlags
)。 - 在档案库 (
mSettings
) 里重新启用这个原始系统 App 的记录。 - 重新扫描解析 (
scanPackageTracedLI
) 这个原始系统 App 文件,把它当作有效的系统 App 加回来。
- 根据这个系统 App 原始文件 (
-
(如果在
/data
找到了,那阶段二移除旧版+这里扫描到新版的流程就完成了,一切正常)
-
-
清空
mExpectingBetter
列表。
-
-
阶段四:收尾整理与权限更新 (BOOT_PROGRESS_PMS_SCAN_END)
scssjava Copy EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END, ...); Log.i("Time to scan packages: " + (timeTaken) + " seconds"); int updateFlags = UPDATE_PERMISSIONS_ALL; // 检查Android版本是否升级 if (上次记录的SDK版本 != 当前SDK版本) { Log.i("Platform changed; regranting permissions ..."); updateFlags |= UPDATE_PERMISSIONS_REPLACE_PKG | UPDATE_PERMISSIONS_REPLACE_ALL; // 需要全面更新权限 } // 根据情况更新所有App的权限授予状态 updatePermissionsLPw(null, null, StorageManager.UUID_PRIVATE_INTERNAL, updateFlags); // 更新档案库记录的SDK版本 ver.sdkVersion = mSdkVersion; // 如果是第一次启动或特定升级后,初始化默认App设置 if (!onlyCore && (mPromoteSystemApps || mFirstBoot)) { for (UserInfo user : 所有用户) { mSettings.applyDefaultPreferredAppsLPw(this, user.id); // 设置默认浏览器/拨号App等 ... // (其他初始化) } } // 如果是OTA升级后首次启动,清除所有App的代码缓存 if (mIsUpgrade && !onlyCore) { Log.i("Build fingerprint changed; clearing code caches"); for (PackageSetting ps : mSettings.mPackages.values()) { clearAppDataLIF(ps.pkg, ..., Installer.FLAG_CLEAR_CODE_CACHE_ONLY); // 只清代码缓存 } } // 更新档案库记录的设备指纹 ver.fingerprint = Build.FINGERPRINT; // 将内存中的档案库内容(mSettings) 写回磁盘文件 (packages.xml, packages.list) 存档! mSettings.writeLPr();
故事: 所有仓库扫描完毕!
-
记录耗时,宣布扫描结束 (
BOOT_PROGRESS_PMS_SCAN_END
)。 -
处理 Android 版本升级 (
if (ver.sdkVersion != mSdkVersion)
):- 如果发现这次开机的 Android 版本 (
mSdkVersion
) 和上次记录在档案库里的版本 (ver.sdkVersion
) 不同,说明系统升级了。 - 系统升级可能带来权限定义的改变。厂长下令:全面检查并更新 (
updatePermissionsLPw
) 所有已安装 App 的权限授予状态 (granted
)。UPDATE_PERMISSIONS_REPLACE_ALL
标志意味着可能撤销并重新授予权限。
- 如果发现这次开机的 Android 版本 (
-
初始化默认 App (
applyDefaultPreferredAppsLPw
): 如果是第一次开机 (mFirstBoot
) 或者是 Android M (6.0) 大升级后的第一次开机 (mPromoteSystemApps
),厂长需要为每个用户初始化一些默认设置,比如默认的浏览器、拨号 App、短信 App 等。 -
清理 OTA 后的代码缓存 (
clearAppDataLIF
): 如果本次是 OTA 升级后的第一次开机 (mIsUpgrade
),为了防止旧的优化代码 (code_cache
) 引发兼容性问题,厂长下令:清除所有 App 的代码缓存目录 (/data/data/<pkg>/code_cache
)。 -
更新档案库版本信息: 将当前的 Android SDK 版本 (
mSdkVersion
) 和设备指纹 (Build.FINGERPRINT
) 记录到档案库 (ver.sdkVersion
,ver.fingerprint
)。 -
存档!(
mSettings.writeLPr()
): 将内存中辛苦构建好的中央档案库 (mSettings
的所有信息) 永久保存到磁盘文件 (/data/system/packages.xml
,/data/system/packages.list
等)。这样下次工厂启动时就能快速读取恢复状态了。这是极其重要的一步!
-
-
阶段五:开张准备 (BOOT_PROGRESS_PMS_READY)
scssjava Copy EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY, SystemClock.uptimeMillis()); // 创建安装会话管理服务 (相当于工厂的客户服务部/安装预约窗口) mInstallerService = new PackageInstallerService(context, this); ... // (其他服务初始化) Runtime.getRuntime().gc(); // 进行一次大扫除(垃圾回收) // 将 PackageManagerInternalImpl (PMS的内部管理接口) 注册为本地服务 LocalServices.addService(PackageManagerInternal.class, new PackageManagerInternalImpl());
故事: 工厂建设终于完成!
- 宣布准备就绪 (
BOOT_PROGRESS_PMS_READY
)。 - 成立安装预约窗口 (
PackageInstallerService
): 创建PackageInstallerService
。这个服务负责管理 App 的安装和卸载会话 (Session),比如用户从应用商店下载 App 后点击安装,就是由这个服务创建会话并最终交给 PMS 的物流主管 (PackageHandler
) 和施工队长 (Installer
) 去执行。 - 大扫除 (
gc
): 建设过程中产生了很多临时垃圾,进行一次全面的清理 (Java 垃圾回收)。 - 注册内部管理接口 (
PackageManagerInternalImpl
): 将PackageManagerInternalImpl
注册到LocalServices
。这个接口是供运行在 同一进程 (system_server
) 内的其他系统服务 (如 AMS) 高效访问 PMS 内部功能 的通道。比如 AMS 启动 Activity 时需要快速查询 App 信息,通过这个接口调用比通过 Binder (ServiceManager.getService("package")
) 更快。
- 宣布准备就绪 (
大结局:
经过 SystemServer 大管家的召唤 (main()
方法) 和 PMS 厂长在构造函数中五个阶段的艰苦建设 (BOOT_PROGRESS_PMS_*
),PMS 这座管理 Android 世界所有 App 的"超级工厂"