PMS(PackageManagerService)是 Android 提供的包管理系统服务,它用来管理所有的包信息,包括应用安装、卸载、更新以及解析 AndroidManifest.xml。
打开app大致流程
- 遍历/data/app的文件夹
- 解压apk文件
- dom解析AndroidManifest.xml文件
- 定位到入口函数(想象成MainActivity)
- 反射创建MainActivity
- MainActivity对象展示,接下来就是App看到的界面了。
其中,1,2,3步由PMS来处理,4,5,6由AMS处理。
PMS主要功能
- 管理设备上安装的所有应用程序,并在系统启动时加载应用程序;
- 根据请求的Intent匹配到对应的Activity、Provider、Service,提供包含包名和组件的信息对象;
- 调用需要权限的系统函数时,检查程序是否具备相应权限从而保证系统安全;
- 提供应用程序的安装、卸载的接口;
PMS包管理
- 应用程序层:使用getPackageManager()获取包的管理对象PackageManager,PMS使用的也是Binder通信,PackageManager是从ServiceManager中获取注册的Binder对象,具体的实现为 PackageManagerService,PMS实现对所有程序的安装和加载; (所有系统程序的文件处于/system/app/目录下,第三方程序文件处于/data/app/ 目录下,在程序安装过程中PMS会将要安装的apk文件复制到/data/app/目录下)
- PMS服务层:PMS运行在SystemServer进程中,主要使用/system/etc/permissions.xml 和/data/system/packages.xml管理包信息;
- 数据文件管理:PMS负责对系统的配置文件、apk安装文件、apk的数据文件执行管理、读写、创 建和删除等功能;
PMS的启动过程
在Android系统启动过程中,程序会执行到SystemServer中,然后调用startBootstrapServices()方法启,动核心服务,在startBootstrapServices()方法中完成PMS的启动:
1 | startBootstrapServices |
PMS的工作过程
ArrayMap<String, PackageParser.Package> mPackages
在扫描程序文件目录时会将信息保存 在Package对象中,然后将所有程序包名极其的package保存在此集合中;
Settings mSettings
保存整个系统信息的Setting对象;
- 创建Settings对象,将PMS中的mPackage集合传入,此集合保存所有apk的解析数据
- 调用readLPw()方法解析系统配置文件package.xml(mSettings.readLPw() )主要是操作mPackages,保存手机中所有app的应用信息
- 调用scanDirTracedLI()扫描系统app(/system/app/)
- 调用scanDirTracedLI()扫描第三方app(/data/app/)
- 执行mSettings.writeLPr()将扫描后的结果,重新写入配置文件,将mPackages中的数据分别写入package.xml和package.list文件中
简单来说系统在启动会会创建PMS对象,使用PMS对象读取配置文件, 然后扫描手机上所有的app程序,并将所有的程序的内容信息都封装在Package对象中,然后将Package 集合中信息转换为PMS的属性供系统使用,最后并更新配置文件;
PackageInstaller 提供了 应用安装、更新、移除的能力,具体实现是PackageInstallerService
APK的包组成
apk文件本质还是一个zip文件
classes.dex
: Dex是DalvikVM executes的缩写,即Android Dalvik执行文件Androidmanifest.xml
:Project中androidManifest.xml编译后得到的二进制xml文件META-INF
:主要保存各个资源文件的SHA1 hash值,用于校验资源文件是否被修改,防止二次打包时资源文件被替换。该目录下主要包括三个文件:
- MANIFEST.MF:保存了 apk 所有文件的摘要信息(SHA-1+Base64)
- CERT.SF:保存了对 MANIFEST.MF 文件再进行一次 SHA-1 并 Base64 加密的信息,并同时保存了 MANIFEST.MF 文件的摘要信息
- CERT.RSA:使用私钥对CERT.SF签名,保存了签名结果、公钥和所采用的加密算法等信息
res
: Project中res目录下资源文件编译后得到的二进制xml文件resources.arsc
:包含了所有资源文件的映射,可以理解为资源索引,通过该文件能找到对应的资源文件lib
:ndk编译出来的so库
APK打包流程
- 通过aapt2打包res资源文件,生成R.java resources.arsc和res文件
- 通过Javac编译R.java,Java接口文件,java源文件生成.class文件
- 通过d8命令将.class文件和第三方库中的.class文件处理生成classes.dex
- 通过aapt2工具将aapt生成的resources.arsc 和res文件,未编译的资源assets文件和classes.dex 一起打包生成apk(未签名)
- 通过zipalign工具将未签名的apk进行对齐处理
- 通过apksigner工具对上面的apk进行签名
aapt2android
资源打包工具Kotlinc
把.kt文件编译成.class文件javac
把.java文件编译成.class文件d8
新一代.class转化成.dex的工具zipalign
字节码对齐工具apksigner
apk签名工具
apk的安装方式
安装系统APK和预置的APK(第一次开机时安装,没有安装界)
PackageManagerService的构造中会扫描对应目录下的apk,完成安装网络下载应用安装――通过market应用完成,没有安装界面
调用PackageManager的installPackage方法执行安装ADB工具安装,没有安装界面
/repo/system/core/adb/commandline.cpp中install_app方法,该方法调用pm_command通过send_shell_command方法将数据发送到手机端的adbd守护进程中,adbd在收到PC中Console发来的数据之后启动一个Shell,然后执行pm脚本(pm位于/system/bin目录下).
pm脚本通过app_process执行pm.jar包的main函数(\system\framework\pm.jar) 对应源码: /repo/frameworks/base/cmds/pm/src/com/android/commands/pm/Pm.java第三方应用安装,有安装界面
以上几种方式均通过PackageInstallObserver来监听安装是否成功。
安装APK的代码
1 | File file = new File(getExternalFilesDir(null), "xxx.apk"); |
APK安装主体流程
- 复制APK到/data/app目录下,解压并扫描安装包
- 将APP的dex文件拷贝到/data/dalvik-cache目录,再在/data/data/目录下创建应用程序的数据目录(以应用包名命令),用来存放应用的数据库、xml文件、cache、二进制的so动态库等
- 解析apk的AndroidManifest.xml文件,注册四大组件,将apk的权限、应用包名、apk的安装位置、版本、userID等重要信息保存在/data/system/packages.xml文件中。这些操作都是在PackageManagerService中完成。
- 资源管理器解析APK里的资源文件。
- dex2oat操作,对dex文件进行优化,并保存在dalvik-cache目录下。
- 更新权限信息。
- 安装完成后,发送Intent.ACTION_PACKAGE_ADDED广播。
- PMS中先把APK拷贝到 /data/app,然后使用PackageParser2解析APK 获取 四大组件、搜集签名、PackageSetting等信息,并进行校验确保安装成功;
- 接着提交信息包更新系统状态及PMS的内存数据;
- 然后使用 Installer 准备在用户目录/data/user进行 dexOpt;
- 最后发送安装结果通知UI层。
复制
,解析
、验证
、更新信息
,dex优化
PMS和AMS关联
无论是Android系统启动后执行的PMS启动,还是使用PackageInstaller安装APK的过程,最终都会使用PackageParser扫描相应的apk文件,将扫描提取的信息保在Package对象中,扫描完成后会回调PMS中方法将扫描获取的四大组件信息转换保存在PMS属性中,主要使用ActivityIntentResolver(activity和br一样)、ServiceIntentResolver、ProviderIntentResolver保存信息
ActivityIntentResolver mActivities:
遍历所有程序的目录,并解析所有的注册清单文件,将提取 所有的Intent-filter数据保存在对应的集合中;
ActivityIntentResolver mReceivers:同上
ServiceIntentResolver mServices:同上
ProviderIntentResolver mProviders:同上
1 | //ActivityStarter#startActivityMayWait |
activity跳转时,会调用PMS获取对应activity的信息