深入理解 Android:PackageManagerService
SystemServer 创建 PackageManagerService:
调用
PackageManagerService
的main()
方法,得到IPackageManager
对象;调用
IPackageManager.isFirstBoot()
判断是否开机后第一次启动(Zygote
或SystemServer
退出后,init
会再次启动它们);调用
IPackageManager.performBootDexOpt()
执行 dex 优化;调用
IPackageManager.systemReady()
通知系统已进入就绪状态;
PackageManagerService 构造方法:
创建
Settings
对象,并调用其addSharedUserLPw()
方法,保存SharedUserSetting
信息;创建
Installer
对象,用于和 Native 进程installd
交互;创建
ThreadHandler
线程,并以其Looper
为参数创建PackageHandler
对象,用于程序的安装和卸载;根据
Installer
对象和 /data/user 文件对象创建UserManager
对象,用于多用户管理;调用
readPermissions()
方法,从 /system/etc/permissions 目录下的 XML 文件读取权限信息;调用
Settings
对象的readLPw()
方法解析 /data/system 目录下的文件;扫描 /system/frameworks 目录以及
BOOTCLASSPATH
和 platform.xml 定义的系统库目录下的 jar 和 APK 文件是否需要 dex 优化,如果需要则调用Installer.dexopt()
方法发消息给installd
让它优化;如果任意一个文件执行了 dex 优化操作,删除 /data/dalvik-cache 目录下的缓存文件;创建
AppDirObserver
对象监听 /system/frameworks、/system/app、/vendor/app (厂商定制)、/data/app、/data/app-private 5 个目录,并调用scanDirLI()
方法扫描其中的 APK 文件;汇总上面扫描 XML 和 APK 得到的信息,并写入文件;
Settings:
Settings
类定义了一个HashMap
类型的mSharedUsers
成员,以字符串(如 “android.uid.system” )为 Key,以SharedUserSetting
对象为 Value;SharedUserSetting
类从GrantedPermissions
类派生,内部包含一个HashSet
类型的packages
成员,用于保存声明了相同sharedUserId
的Package
的权限设置信息(PackageSetting
);每个
Package
有自己的PackageSetting
,该类继承自GrantedPermissions
的子类PackageSettingBase
;Settings
还有一个ArrayList
类型的mUserIds
成员和一个SparseArray
类型的mOtherUserIds
成员,它们的目的是以 UID 为索引,得到对应的SharedUserSetting
对象;
解析权限相关 XML 文件 readPermissions():
/system/etc/permission 目录下的文件是硬件厂商根据设备配置信息拷贝、编译为 system 镜像,最后烧录到设备上的;
先调用
readPermissionsFromXml()
读取除 platform.xml 以外的所有文件;最后调用readPermissionsFromXml()
读取该文件;platform.xml 主要使用了四个标签:
permission
和group
用于建立 Linux 层 gid 和 Android 层 Permission 的映射关系;assign-permission
用于向指定的 uid 赋予相应的权限;library
用于指定系统库;
其他 XML 文件主要包含
feature
标签,用于描述屏幕、相机、蓝牙、传感器等硬件特性;readPermissionFromXml()
实际上就是从 XML 文件将各种标签及映射关系转换为相应的数据结构;
解析 PMS 启动后生成的 XML 文件 readLPw():
主要有三个文件:
packages.xml:
PackageManagerService
启动完成后会生成该文件,当安装/卸载/更新等操作均会修改该文件;packages.list: 描述所有非系统自带 APK 信息,当这些程序有变动时会更新该文件;
packages-stopped.xml: 保存被用户强制停止的应用信息;
与
readPermissionFromXml()
方法类似,也是将 XML 数据转换为相应的数据结构;
扫描包路径 APK 文件 scanDirLI():
内部调用
scanPackageLI()
,返回PackageParser.Package
对象,它是和 APK 文件对应的数据结构;创建
PackageParser
对象,调用其parsePackage()
方法解析 AndroidManifest.xml 中的各种标签,参数传入了扫描标志和Metrics
屏幕信息;调用
collectCertificatesLI()
方法收集APK签名信息;将上面扫描得到的
PackageParser.Package
信息加入系统,其中单独处理packcage
为android
的包,即 framework-res.apk,它包含系统资源和ChooserActivity
、ShutdownActivity
、RingtonePickerActivity
等常用页面;检查 Library、settings 和签名信息;
调用
Installer.install()
和UserManager.installPackageForAllUsers()
安装 APK;如果 APK 包含 Native 库,则解压并复制到相应目录;从 Android 2.3 开始,系统包的 Native 库统一放在 /system/lib 目录,所以它们不用复制;
如果该 APK 已存在,杀掉该进程;
adb install 命令 commandline.c::install_app():
调用
do_sync_push()
将 host 中的 APK 拷贝到手机指定目录(内部存储为 /data/local/tmp,外部储存为 /sdcard/tmp);Android 4.0 新增了 APK 验证,其实就是将相关信息发送给 Verification 程序(另一个 APK);
调用
pm_command()
将pm install
命令和参数发送给 adbd,执行 pm 脚本安装 APK:在编译 system.image 时,Android.mk 会将 pm 脚本复制到 /system/bin 目录;
pm 脚本通过 Native 的
app_process
进程 (Zygote
创建者) 创建虚拟机并执行 pm.jar 中的main()
函数;
删除 tmp 目录下的 APK 文件,因为安装后 APK 会被复制到 /data/app 目录;
pm.java:
获取
PackageManagerService
的 Binder 客户端;处理命令(以
install
命令为例):创建
PackageInstallObserver
用于接收PackageManagerService
安装结果;调用
PackageManagerService.installPackageWithVerification()
完成安装;同步机制等待安装结果;
PackageManagerService.installPackageWithVerification():
检查客户端进程是否具有安装 Package 的权限,如果是通过 shell 安装,则增加
INSTALL_FROM_ADB
标记;调用
bindService()
启动 DefaultContainerService.apk 提供的DefaultContainerService
;调用
HandlerParams.startCopy()
;
HandlerParams:
HandlerParams
有三个子类:InstallParams
(处理 APK 安装)、MoveParams
(处理已安装的 APK 位置移动)、MeasureParams
(查询已安装 APK 存储和缓存等);根据
adb install
参数得到待安装 APK 位置;获取
DeviceStorageMonitorService
的 Binder 客户端,查询内部存储空间最小余量(默认是总存储 10%);调用
DefaultContainerService.getMinimalPackageInfo()
得到一个PackageInfoLite
对象;内部调用PackageParser.parsePackageLite()
解析 APK,返回PackageParser.PackageLite
对象;调用
DefaultContainerService.recommendApInstallLocation()
得到推荐安装位置:设置
prefer
值为PREFER_INTERNAL
,即倾向于内部存储空间;查询
Settings
数据库中的secure
表,获取用户设置的安装路径;判断外部存储空间是否是模拟的;
检查内部和外部存储空间是否足够;
如果内部空间满足条件,直接返回;如果外部空间也不满足,返回错误;
调用
installLocationPolicy()
检查推荐安装位置(比如系统 Package 不允许安装在 SD 卡);调用
createInstallArgs()
创建不同的InstallArgs
:内部存储返回FileInstallArgs
,外部存储返回SdInstallArgs
;对 APK 进行检查(Verification):
创建
Intent
对象,调用queryIntentReceivers()
查找满足条件的广播接收者,筛选后发送广播;调用
PackageManagerService.verifyPendingInstall()
通知校验结果;
调用
InstallArgs.copyApk()
进行安装:将 /data/local/tmp 中的 APK 复制到 /data/app 目录,生成 “vmdl-随机数.tmp” 的临时文件,因为
PackageManagerService
通过 Linux 的 inotify 机制监控了 /data/app 目录,如果新文件后缀为 APK 会触发扫描;创建
PackageInstalledInfo
对象;调用
InstallArgs.doPreInstall()
;调用
installPackageLI()
执行安装,内部对文件重命名(包名-数字.apk),并扫描 APK,将信息注册到系统;调用
InstallArgs.doPostInstall()
;发送
PACKAGE_ADDED
广播,如果是 APK 更新,发送PACKAGE_REPLACE
和MY_PACKAGE_REPLACED
广播;调用 GC,并调用
InstallArgs.doPostDeleteLI()
进行资源清理;通知 pm 安装的结果;
installd.c:
Java 层的
Installer
通过 Socket 和 Native 层的installd
进程进行交互;installd
的main()
函数调用android_get_control_socket()
创建 socket,处理各种Installer
的命令;处理
dexopt
命令:委派给dexopt
进程(/dalvik/dexopt/OptMain.cpp)实现,生成的 dex 文件一般位于 /data/dalvik-cache 目录;
参考: