核心故事:系统启动时的“包裹”登记大行动
想象一下,Android 系统就是一个巨大的仓库(设备)。当仓库刚启动时(系统启动),有一个非常重要的部门叫 “包裹登记中心” (PackageManagerService) 就要开始工作了。它的任务就是扫描仓库里几个指定的存放区(特定目录),找到所有写着 .apk 的“包裹”(应用程序安装包),拆开它们,仔细检查里面的“身份证” (AndroidManifest.xml),把包裹里的人和货(应用程序信息、四大组件等)登记到仓库的总目录里。这样,仓库管理员 (ActivityManagerService) 和其他部门 (Launcher 等) 才能知道仓库里有什么“货物”(应用),以及怎么找到和使用它们。
故事流程与源码对应:
-
仓库主控室启动 (
SystemServer.main)-
仓库的核心管理系统 (
SystemServer) 启动了。 -
代码体现 (
SystemServer.java):java Copy public static void main(String[] args) { init1(args); // 启动初始化的第一阶段 (Native) ... // 后续初始化 }
-
-
呼叫底层设备专家 (
SystemServer.init1->system_init())-
SystemServer主控室呼叫底层的设备管理专家 (system_init()函数,在 C++ 层)。 -
专家先启动一些基础的设备服务(如显示设备
SurfaceFlinger、传感器SensorService、音频AudioFlinger等),确保仓库的基本设施能用。 -
然后专家说:“基础设备准备好了,现在该启动‘包裹登记中心’这类上层管理系统了!”
-
代码体现 (
com_android_server_SystemServer.cpp/system_init.cpp):java Copy // JNI 桥接:SystemServer.init1 -> system_init() static void android_server_SystemServer_init1(...) { system_init(); } // system_init() 函数 extern "C" status_t system_init() { ... // 启动 SurfaceFlinger, SensorService 等 AndroidRuntime* runtime = AndroidRuntime::getRuntime(); runtime->callStatic("com/android/server/SystemServer", "init2"); // 关键!通知 Java 层继续 ... // 其他处理 }
-
-
主控室启动管理系统线程 (
SystemServer.init2->ServerThread)-
收到底层专家的信号,主控室 (
SystemServer) 启动了一个名为ServerThread的核心管理线程。 -
这个线程专门负责启动仓库里最重要的几个管理部门,包括我们的主角——“包裹登记中心” (
PackageManagerService)。 -
代码体现 (
SystemServer.java):java Copy public static final void init2() { Thread thr = new ServerThread(); // 创建核心管理线程 thr.setName("android.server.ServerThread"); thr.start(); // 启动线程,执行 run() }
-
-
核心线程启动“包裹登记中心” (
ServerThread.run)-
ServerThread线程开始工作,其中一项重要任务就是创建并启动PackageManagerService。 -
代码体现 (
SystemServer.java-ServerThread.run):java Copy public void run() { ... Slog.i(TAG, "Package Manager"); // 日志:开始启动包管理器 pm = PackageManagerService.main(context, ...); // 创建并启动 PMS ... // 注意:这里也会启动 ActivityManagerService (仓库管理员) 等 }
-
-
“包裹登记中心”诞生 (
PackageManagerService.main)-
PackageManagerService.main()方法被调用。 -
它创建了
PackageManagerService的核心实例 (new PackageManagerService(...)),并把这个中心注册到仓库的“部门黄页” (ServiceManager) 里,这样其他部门就知道怎么找到它了。 -
关键! 在创建
PackageManagerService实例的 构造函数 里,就开始了扫描和登记包裹的核心工作。 -
代码体现 (
PackageManagerService.java):java Copy public static final IPackageManager main(Context context, ...) { PackageManagerService m = new PackageManagerService(context, ...); // 创建实例(核心工作在构造里!) ServiceManager.addService("package", m); // 注册到“部门黄页” return m; }
-
-
扫描指定存放区(目录)(
PackageManagerService构造函数)-
新成立的“包裹登记中心” (
PackageManagerService) 知道它要去哪些存放区找.apk包裹:/system/framework/: 放系统核心框架的“包裹”。/system/app/: 放系统预装应用的“包裹”。/vendor/app/: 放设备制造商预装应用的“包裹”。/data/app/: 放用户自己安装的应用的“包裹”。/data/app-private/: 放有特殊保护(如 DRM)的“包裹”。
-
中心立刻派出了几个“目录观察员” (
AppDirObserver),专门盯着这些存放区,以后如果有新包裹放进来(安装 App)或旧包裹被拿走(卸载 App),观察员能及时报告。 -
中心马上开始 第一次大扫荡:调用
scanDirLI()函数扫描每个存放区。 -
代码体现 (
PackageManagerService.java- 构造函数):java Copy public PackageManagerService(Context context, ...) { ... // 设置存放区路径 mFrameworkDir = new File(Environment.getRootDirectory(), "framework"); mSystemAppDir = new File(Environment.getRootDirectory(), "app"); mVendorAppDir = new File("/vendor/app"); mAppInstallDir = new File(Environment.getDataDirectory(), "app"); mDrmAppPrivateInstallDir = new File(Environment.getDataDirectory(), "app-private"); ... // 创建并启动目录观察员 (OBSERVER_EVENTS 监听文件变化) mFrameworkInstallObserver = new AppDirObserver(mFrameworkDir.getPath(), OBSERVER_EVENTS, true); mFrameworkInstallObserver.startWatching(); ... // 对其他目录也创建和启动观察员 // 核心扫描开始! scanDirLI(mFrameworkDir, PackageParser.PARSE_IS_SYSTEM | ..., scanMode, 0); scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM | ..., scanMode, 0); scanDirLI(mVendorAppDir, PackageParser.PARSE_IS_SYSTEM | ..., scanMode, 0); scanDirLI(mAppInstallDir, 0, scanMode, 0); // 用户app目录标志不同 scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK, scanMode, 0); ... }
-
-
扫描存放区,检查包裹 (
scanDirLI)-
scanDirLI()函数负责扫描一个存放区。 -
它列出目录下的所有文件。
-
对每个文件,检查它是不是
.apk包裹(文件名以.apk结尾)。 -
如果是,就交给“包裹解析专员” (
scanPackageLI) 去拆包检查。 -
如果解析失败(比如包裹损坏),在非系统区 (
/data/app) 的包裹会被清理掉(file.delete())。 -
代码体现 (
PackageManagerService.java):java Copy private void scanDirLI(File dir, int flags, int scanMode, long currentTime) { String[] files = dir.list(); // 列出目录下所有文件 for (int i=0; i<files.length; i++) { File file = new File(dir, files[i]); if (!isPackageFilename(files[i])) { // 检查文件名是否是*.apk continue; // 不是apk,跳过 } // 是apk!交给专员解析 PackageParser.Package pkg = scanPackageLI(file, flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime); // 如果不是系统区的包裹且解析失败,清理它 if (pkg == null && (flags & PackageParser.PARSE_IS_SYSTEM) == 0 && ...) { file.delete(); // 删除损坏的apk文件 } } }
-
-
“包裹解析专员”拆包 (
scanPackageLI->PackageParser)-
专员 (
scanPackageLI) 拿到一个.apk文件。 -
它请出专业的“包裹解析器” (
PackageParser)。 -
解析器 (
PackageParser) 会做两件核心事:- 读取包裹内容: 使用
AssetManager打开包裹,找到最重要的“身份证”文件AndroidManifest.xml。 - 解析身份证: 调用
PackageParser.parsePackage()解析AndroidManifest.xml文件。
- 读取包裹内容: 使用
-
代码体现 (
PackageManagerService.java):java Copy private PackageParser.Package scanPackageLI(File scanFile, ...) { ... PackageParser pp = new PackageParser(scanFile.getPath()); // 创建专业解析器 final PackageParser.Package pkg = pp.parsePackage(scanFile, ...); // 解析器开始解析apk ... // 把解析结果交给下一步处理 (登记入库) return scanPackageLI(pkg, ...); }
-
-
解析身份证 (
PackageParser.parsePackage)-
专业的“包裹解析器” (
PackageParser) 开始仔细阅读AndroidManifest.xml(“身份证”)。 -
它首先读取包裹的名字 (
packageName)。这是包裹的唯一标识! -
然后,它逐行扫描身份证上的信息:
-
<application>: 整个应用的信息(如图标、名字、主题、权限)。 -
<activity>: 应用的界面 (UI)。 -
<service>: 应用的后台服务。 -
<receiver>: 应用的广播接收器(接收系统或应用的通知)。 -
<provider>: 应用的数据提供者(允许其他应用共享数据)。 -
<uses-permission>: 应用需要哪些系统权限(访问网络、存储等)。 -
<uses-feature>: 应用需要哪些硬件特性(摄像头、GPS等)。 - 以及其他标签(如
uses-sdk,meta-data等)。
-
-
核心解析 (
PackageParser.parsePackage内部):java Copy private Package parsePackage(...) throws ... { ... String pkgName = parsePackageName(parser, attrs, flags, outError); // 获取包名 final Package pkg = new Package(pkgName); // 创建Package对象存放解析结果 ... while ((type = parser.next()) != ...) { // 循环读取XML标签 String tagName = parser.getName(); if (tagName.equals("application")) { if (!parseApplication(pkg, res, parser, attrs, flags, outError)) { // 解析<application>标签 return null; } } else if (tagName.equals("activity")) { // 解析<activity> Activity a = parseActivity(...); pkg.activities.add(a); } else if (tagName.equals("receiver")) { // 解析<receiver> Activity a = parseActivity(...); // (Receiver也是Activity的一种) pkg.receivers.add(a); } else if (tagName.equals("service")) { // 解析<service> Service s = parseService(...); pkg.services.add(s); } else if (tagName.equals("provider")) { // 解析<provider> Provider p = parseProvider(...); pkg.providers.add(p); } else if ... // 处理其他标签 (uses-permission, uses-feature等) } return pkg; // 返回解析好的Package对象 }
-
-
登记入库 (
scanPackageLI另一版本)-
拿到“包裹解析专员”返回的、包含所有详细信息的
Package对象。 -
登记中心开始正式登记:
-
登记包裹本身:
mPackages.put(pkg.applicationInfo.packageName, pkg)(包名 -> Package对象)。 -
登记四大组件:
- Provider (数据提供者):
mProvidersByComponent.put(new ComponentName(p.info.packageName, p.info.name), p)(组件名 -> Provider对象)。 - Service (后台服务):
mServices.addService(s)(加入服务解析器)。 - Broadcast Receiver (广播接收器):
mReceivers.addActivity(a, "receiver")(加入接收器解析器)。 - Activity (界面):
mActivities.addActivity(a, "activity")(加入活动解析器)。
- Provider (数据提供者):
-
-
同时,会处理组件的进程名 (
fixProcessName),确保它们知道在哪个“工作间”(进程)运行。 -
代码体现 (
PackageManagerService.java):java Copy private PackageParser.Package scanPackageLI(PackageParser.Package pkg, ...) { synchronized (mPackages) { ... // 1. 登记包裹本身 mPackages.put(pkg.applicationInfo.packageName, pkg); // 2. 登记Provider for (int i = 0; i < pkg.providers.size(); i++) { PackageParser.Provider p = pkg.providers.get(i); p.info.processName = fixProcessName(...); // 修正进程名 mProvidersByComponent.put(new ComponentName(p.info.packageName, p.info.name), p); } // 3. 登记Service for (int i = 0; i < pkg.services.size(); i++) { PackageParser.Service s = pkg.services.get(i); s.info.processName = fixProcessName(...); mServices.addService(s); // 加入服务解析器 } // 4. 登记Broadcast Receiver for (int i = 0; i < pkg.receivers.size(); i++) { PackageParser.Activity a = pkg.receivers.get(i); a.info.processName = fixProcessName(...); mReceivers.addActivity(a, "receiver"); // 加入接收器解析器 } // 5. 登记Activity for (int i = 0; i < pkg.activities.size(); i++) { PackageParser.Activity a = pkg.activities.get(i); a.info.processName = fixProcessName(...); mActivities.addActivity(a, "activity"); // 加入活动解析器 } ... return pkg; } }
-
故事结局:
经过这一系列忙碌的操作(系统启动时由 SystemServer 启动 PackageManagerService,PackageManagerService 扫描特定目录,使用 PackageParser 解析 AndroidManifest.xml,并将解析出的应用信息存储在其内部的 mPackages、mActivities、mServices、mReceivers、mProvidersByComponent 等关键集合中),Android 系统就知道了所有安装在 /system、/vendor、/data/app 等目录下的应用程序的完整信息。
关键点总结:
- 时机: 发生在 系统启动过程 中,由
SystemServer触发。 - 主角:
PackageManagerService(PMS) 是核心管理者。 - 扫描目标:
/system/framework,/system/app,/vendor/app,/data/app,/data/app-private这几个固定目录。 - 核心解析器:
PackageParser 负责解析 APK 文件,重点是读取和解析AndroidManifest.xml。 - 解析内容: 包名 (packageName) 是应用的唯一 ID。解析的主要信息包括:四大组件 (Activity, Service, Receiver, Provider)、应用信息 (ApplicationInfo)、权限声明 (uses-permission)、特性要求 (uses-feature)、版本号 等。
- 存储结果: PMS 内部的几个重要集合 (
mPackages,mActivities,mServices,mReceivers,mProvidersByComponent) 保存了所有解析出的信息,成为整个系统查询和应用组件解析的基础。 - 后续: 文章结尾提到,虽然应用信息登记好了(安装了),但要在桌面上看到图标,还需要另一个应用
Launcher从 PMS 这里获取应用列表并展示出来(这是下一篇文章的内容)。
通俗理解: PackageManagerService 在系统启动时做的“安装”,更像是 应用信息的预加载和注册。它解析 APK 的清单文件,把所有重要信息登记在案,为后续应用的启动、组件调用、权限检查等提供依据。它并不是执行用户通常理解的“点击 APK 文件进行安装”的那个过程(虽然核心解析逻辑是类似的),后者通常发生在系统运行后用户主动安装新 App 时。