本文是基于api 25(Android 7.1.1),主要是安装保存在sd 卡的应用apk 的流程。
基础知识
两种不同的应用
/system/app/
目录下代表的是系统应用。/data/app/
目录下代表的是安装的应用。
安装的方式
- 保存在sd 卡以后安装
- 通过
adb
脚本安装 - 通过应用市场安装
本文的流程是保存在sd 卡以后安装的流程。
PMS 代码注意点
PackageManagerService
(后续用PMS 表示)的最上方注释需要仔细阅读(不然看源码可能有点懵)。
这里稍微的解释下注释的内容。PMS 中有很多方法的后缀是LI、LIF、LPr、LPw。需要理解是什么意思就需要知道PMS 中有两个很重要的锁mPackages
和mInstallLock
以及一个mFrozenPackages
变量。还要了解一个注解的使用com.android.internal.annotations.GuardedBy
(这个注解可以被Method
和Field
使用,意思是使用相应的Method
或Field
的时候一定需要拥有相应的锁)。
方法 | 意义 |
---|---|
fooLI | 需要mInstallLock 锁 |
fooLIF | 需要mInstallLock 锁,并且需要包是frozen |
fooLPr | 需要mPackages 锁以后读 |
fooLPw | 需要mPackages 锁以后写 |
mPackages
使用的非常频繁(例如:四大组建的调用)但是占用的时间比较短。mInstallLock
则只在‘安装’(与sd 卡交互等等)的时候才会使用,并且执行内容比较耗时。在synchronized(mPackages)
的代码块中不允许出现synchronized(mInstallLock)
客户端调用安装的代码
|
|
客户端可能需要手动调用安装的apk 的逻辑。
其他
adb shell dumpsys package p
查看安装的包信息。从PackageManagerService#dump
代码可以看到相应的打印信息- 从
com.android.packageinstaller
进程开始,这个进程代表的就是安装Apk 的功能。 aosp/frameworks/base/core/res/res/values/attrs_manifest.xml
对应的是AndroidManifest 中声明的信息
安装流程
安装的总体时序图
第1步,已经将apk 拷贝到了/data/app/vmdlxxxxx.tmp/PackageInstaller
(这里没有详细看vmdlxxxxx.tmp 的命名规则)
第2不,会命名出base.apk。
第3步,简要的解析了manifest 和application 标签中的信息,然后生成了ApkLite。
第4步,提取so 文件。这个过程其实有一点细节是怎么去判断是当前手机的架构的。
第5步,app 已经拷贝到了data/apk/base.apk
,此时知道了包名、文件的路径等。这个时候才开始安装的流程。
第7-10步,可以放在一起。调用Service
去解析apk 信息以及getMinimalPackageInfo
这里会返回一些数据,包含很多安装出错的数据。这里的流程是执行DefaultContainerService
的一个内部类的getMinimalPackageInfo
方法。
|
|
定义的一些安装的错误信息,可以在PackageHelper
中找到。
|
|
具体看一个比较容易出现的错误RECOMMEND_FAILED_VERSION_DOWNGRADE
,代码比较容易看懂。
|
|
第13步,installPackageLI
的时候已经过滤错误,这里是开始安装了。有一个小细节是rename 的时候会出现名称是包名-1
或者包名-2
。看下面的代码其实就是在packageName-1
和packageName-2
之间一直切换。
|
|
第14步,解析出包信息。这里面就是详细的解析出数据的。这里给出解析activity
、receiver
、service
、provider
的逻辑(可以看出activity
和receiver
其实保存的是同一个对象)。直到这一个步骤完成才真正的解析出了AndroidManifest.xml
中的所有信息,并且这里并没有将信息保存在PMS 中。
|
|
第17步,会在data/appvmdlxxxxx.tmp/
生成oat 文件夹。
ART 推出了预先 (AOT) 编译,可提高应用的性能。在安装时,ART 使用设备自带的 dex2oat 工具来编译应用。
第19步,freezePackageForInstall
会将当前安装的包加入到mFrozenPackages。这里前面的逻辑已经说明过,LIF。
第22步,scanPackageLI
会从AndroidManifest.xml
中扫描出信息,保存在PMS#mPackages
、PMS#mActivities
、PMS#mReceivers
、PMS#mServices
、PMS#mProviders
等里面。下面给出的是解析Service
和Activity
。
|
|
第23-28步,可以放在一起,主要是生成/data/data/
目录下的数据。第26步的createAppData
会在data/data
目录下生成相应的用户数据(似乎仅仅生成了文件夹cache
和code_cache
)。第28步的linkNativeLibraryDirectory
处理so 文件。到这里完成了data/data
中相关信息创建。
到此就结束了应用apk 的安装过程(执行完installPackageLI
后),此时可以通过adb
打开相应的Activity
了,但是没有创建桌面图标。
所以安装的整个逻辑可以总结为:
- 将应用apk 拷贝到
data/apk
目录,以便能够找到代码。 - dex2oat 优化操作。
- 解析AndroidManifest.xml 中的信息,然后保存在PMS 中供以后使用。
- 生成相应的
data/data/包名
信息。
安装后的处理逻辑
上面安装流程里面的第12步,后续还会处理安装以后的逻辑,最后会调用到PMS#finishPackageInstall
,然后会处理到PMS#handlePackagePostInstall
。(这里的代码没有跟踪下去了😳)
问题
- 应用安装的入口在哪?应用卸载的入口在哪?卸载的入口可以查看PMS中的deleteXX 或者removeXX 方法。
- apk 的信息安装以后放在哪了。
- 安装出错是在哪里提示的。
- 应用图标生成的过程在哪?跟
android.intent.action.PACKAGE_ADDED
这个广播有关系。