深入理解 Android:PackageManagerService

SystemServer 创建 PackageManagerService:

  1. 调用 PackageManagerServicemain() 方法,得到 IPackageManager 对象;

  2. 调用 IPackageManager.isFirstBoot() 判断是否开机后第一次启动(ZygoteSystemServer 退出后,init 会再次启动它们);

  3. 调用 IPackageManager.performBootDexOpt() 执行 dex 优化;

  4. 调用 IPackageManager.systemReady() 通知系统已进入就绪状态;

PackageManagerService 构造方法:

  1. 创建 Settings 对象,并调用其 addSharedUserLPw() 方法,保存 SharedUserSetting 信息;

  2. 创建 Installer 对象,用于和 Native 进程 installd 交互;

  3. 创建 ThreadHandler 线程,并以其 Looper 为参数创建 PackageHandler 对象,用于程序的安装和卸载;

  4. 根据 Installer 对象和 /data/user 文件对象创建 UserManager 对象,用于多用户管理;

  5. 调用 readPermissions() 方法,从 /system/etc/permissions 目录下的 XML 文件读取权限信息;

  6. 调用 Settings 对象的 readLPw() 方法解析 /data/system 目录下的文件;

  7. 扫描 /system/frameworks 目录以及 BOOTCLASSPATH 和 platform.xml 定义的系统库目录下的 jar 和 APK 文件是否需要 dex 优化,如果需要则调用 Installer.dexopt() 方法发消息给 installd 让它优化;如果任意一个文件执行了 dex 优化操作,删除 /data/dalvik-cache 目录下的缓存文件;

  8. 创建 AppDirObserver 对象监听 /system/frameworks、/system/app、/vendor/app (厂商定制)、/data/app、/data/app-private 5 个目录,并调用 scanDirLI() 方法扫描其中的 APK 文件;

  9. 汇总上面扫描 XML 和 APK 得到的信息,并写入文件;

Settings:

  1. Settings 类定义了一个 HashMap 类型的 mSharedUsers 成员,以字符串(如 “android.uid.system” )为 Key,以 SharedUserSetting 对象为 Value;

  2. SharedUserSetting 类从 GrantedPermissions 类派生,内部包含一个 HashSet 类型的 packages 成员,用于保存声明了相同 sharedUserIdPackage 的权限设置信息(PackageSetting);

  3. 每个 Package 有自己的 PackageSetting,该类继承自 GrantedPermissions 的子类 PackageSettingBase

  4. Settings 还有一个 ArrayList 类型的 mUserIds 成员和一个 SparseArray 类型的 mOtherUserIds 成员,它们的目的是以 UID 为索引,得到对应的 SharedUserSetting 对象;

解析权限相关 XML 文件 readPermissions():

  1. /system/etc/permission 目录下的文件是硬件厂商根据设备配置信息拷贝、编译为 system 镜像,最后烧录到设备上的;

  2. 先调用 readPermissionsFromXml() 读取除 platform.xml 以外的所有文件;最后调用 readPermissionsFromXml() 读取该文件;

  3. platform.xml 主要使用了四个标签:

    • permissiongroup 用于建立 Linux 层 gid 和 Android 层 Permission 的映射关系;

    • assign-permission 用于向指定的 uid 赋予相应的权限;

    • library 用于指定系统库;

  4. 其他 XML 文件主要包含 feature 标签,用于描述屏幕、相机、蓝牙、传感器等硬件特性;

  5. readPermissionFromXml() 实际上就是从 XML 文件将各种标签及映射关系转换为相应的数据结构;

解析 PMS 启动后生成的 XML 文件 readLPw():

  1. 主要有三个文件:

    • packages.xml: PackageManagerService 启动完成后会生成该文件,当安装/卸载/更新等操作均会修改该文件;

    • packages.list: 描述所有非系统自带 APK 信息,当这些程序有变动时会更新该文件;

    • packages-stopped.xml: 保存被用户强制停止的应用信息;

  2. readPermissionFromXml() 方法类似,也是将 XML 数据转换为相应的数据结构;

扫描包路径 APK 文件 scanDirLI():

  1. 内部调用 scanPackageLI(),返回 PackageParser.Package 对象,它是和 APK 文件对应的数据结构;

  2. 创建 PackageParser 对象,调用其 parsePackage() 方法解析 AndroidManifest.xml 中的各种标签,参数传入了扫描标志和 Metrics 屏幕信息;

  3. 调用 collectCertificatesLI() 方法收集APK签名信息;

  4. 将上面扫描得到的 PackageParser.Package 信息加入系统,其中单独处理 packcageandroid 的包,即 framework-res.apk,它包含系统资源和 ChooserActivityShutdownActivityRingtonePickerActivity 等常用页面;

  5. 检查 Library、settings 和签名信息;

  6. 调用 Installer.install()UserManager.installPackageForAllUsers() 安装 APK;

  7. 如果 APK 包含 Native 库,则解压并复制到相应目录;从 Android 2.3 开始,系统包的 Native 库统一放在 /system/lib 目录,所以它们不用复制;

  8. 如果该 APK 已存在,杀掉该进程;

adb install 命令 commandline.c::install_app():

  1. 调用 do_sync_push() 将 host 中的 APK 拷贝到手机指定目录(内部存储为 /data/local/tmp,外部储存为 /sdcard/tmp);

  2. Android 4.0 新增了 APK 验证,其实就是将相关信息发送给 Verification 程序(另一个 APK);

  3. 调用 pm_command()pm install 命令和参数发送给 adbd,执行 pm 脚本安装 APK:

    • 在编译 system.image 时,Android.mk 会将 pm 脚本复制到 /system/bin 目录;

    • pm 脚本通过 Native 的 app_process 进程 ( Zygote 创建者) 创建虚拟机并执行 pm.jar 中的 main() 函数;

  4. 删除 tmp 目录下的 APK 文件,因为安装后 APK 会被复制到 /data/app 目录;

pm.java:

  1. 获取 PackageManagerService 的 Binder 客户端;

  2. 处理命令(以 install 命令为例):

    1. 创建 PackageInstallObserver 用于接收 PackageManagerService 安装结果;

    2. 调用 PackageManagerService.installPackageWithVerification() 完成安装;

    3. 同步机制等待安装结果;

PackageManagerService.installPackageWithVerification():

  1. 检查客户端进程是否具有安装 Package 的权限,如果是通过 shell 安装,则增加 INSTALL_FROM_ADB 标记;

  2. 调用 bindService() 启动 DefaultContainerService.apk 提供的 DefaultContainerService

  3. 调用 HandlerParams.startCopy()

HandlerParams:

  1. HandlerParams 有三个子类:InstallParams (处理 APK 安装)、MoveParams (处理已安装的 APK 位置移动)、MeasureParams (查询已安装 APK 存储和缓存等);

  2. 根据 adb install 参数得到待安装 APK 位置;

  3. 获取 DeviceStorageMonitorService 的 Binder 客户端,查询内部存储空间最小余量(默认是总存储 10%);

  4. 调用 DefaultContainerService.getMinimalPackageInfo() 得到一个 PackageInfoLite 对象;内部调用 PackageParser.parsePackageLite() 解析 APK,返回 PackageParser.PackageLite 对象;

  5. 调用 DefaultContainerService.recommendApInstallLocation() 得到推荐安装位置:

    1. 设置 prefer 值为 PREFER_INTERNAL,即倾向于内部存储空间;

    2. 查询 Settings 数据库中的 secure 表,获取用户设置的安装路径;

    3. 判断外部存储空间是否是模拟的;

    4. 检查内部和外部存储空间是否足够;

    5. 如果内部空间满足条件,直接返回;如果外部空间也不满足,返回错误;

  6. 调用 installLocationPolicy() 检查推荐安装位置(比如系统 Package 不允许安装在 SD 卡);

  7. 调用 createInstallArgs() 创建不同的 InstallArgs:内部存储返回 FileInstallArgs,外部存储返回 SdInstallArgs

  8. 对 APK 进行检查(Verification):

    1. 创建 Intent 对象,调用 queryIntentReceivers() 查找满足条件的广播接收者,筛选后发送广播;

    2. 调用 PackageManagerService.verifyPendingInstall() 通知校验结果;

  9. 调用 InstallArgs.copyApk() 进行安装:

    1. 将 /data/local/tmp 中的 APK 复制到 /data/app 目录,生成 “vmdl-随机数.tmp” 的临时文件,因为 PackageManagerService 通过 Linux 的 inotify 机制监控了 /data/app 目录,如果新文件后缀为 APK 会触发扫描;

    2. 创建 PackageInstalledInfo 对象;

    3. 调用 InstallArgs.doPreInstall()

    4. 调用 installPackageLI() 执行安装,内部对文件重命名(包名-数字.apk),并扫描 APK,将信息注册到系统;

    5. 调用 InstallArgs.doPostInstall()

    6. 发送 PACKAGE_ADDED 广播,如果是 APK 更新,发送 PACKAGE_REPLACEMY_PACKAGE_REPLACED 广播;

    7. 调用 GC,并调用 InstallArgs.doPostDeleteLI() 进行资源清理;

    8. 通知 pm 安装的结果;

installd.c:

  1. Java 层的 Installer 通过 Socket 和 Native 层的 installd 进程进行交互;installdmain() 函数调用 android_get_control_socket() 创建 socket,处理各种 Installer 的命令;

  2. 处理 dexopt 命令:委派给 dexopt 进程(/dalvik/dexopt/OptMain.cpp)实现,生成的 dex 文件一般位于 /data/dalvik-cache 目录;


参考:

《深入理解 Android: 卷 II》