前言
包管理机制是Android中的重要机制,是应用开发和系统开发需要掌握的知识点之一。
包指的是Apk、jar和so文件等等,它们被加载到Android内存中,由一个包转变成可执行的代码,这就需要一个机制来进行包的加载、解析、管理等操作,这就是包管理机制。
包管理机制由许多类一起组成,其中核心为PackageManagerService(PMS),它负责对包进行管理,如果直接讲PMS会比较难以理解,因此我们需要一个切入点,这个切入点就是常见的APK的安装。
讲到APK的安装之前,先了解下PackageManager、APK文件结构和安装方式。
1.PackageManager简介
与ActivityManager和AMS的关系类似,PMS也有一个对应的管理类PackageManager,用于向应用程序进程提供一些功能。PackageManager是一个抽象类,它的具体实现类为ApplicationPackageManager,ApplicationPackageManager中的方法会通过IPackageManager与AMS进行进程间通信,因此PackageManager所提供的功能最终是由PMS来实现的,这么设计的主要用意是为了避免系统服务PMS直接被访问。PackageManager提供了一些功能,主要有以下几点:
- 获取一个应用程序的所有信息(ApplicationInfo)。
- 获取四大组件的信息。
- 查询permission相关信息。
- 获取包的信息。
- 安装、卸载APK。
2.APK文件结构和安装方式
APK是AndroidPackage的缩写,即Android安装包,它实际上是zip格式的压缩文件,一般情况下,解压后的文件结构如下表所示。
APK的安装场景主要有以下几种:
- 通过adb命令安装:adb 命令包括adb push/install
- 用户下载的Apk,通过系统安装器packageinstaller安装该Apk。packageinstaller是系统内置的应用程序,用于安装和卸载应用程序。
- 系统开机时安装系统应用。
- 电脑或者手机上的应用商店自动安装。
这4种方式最终都是由PMS来进行处理,在此之前的调用链是不同的,本篇文章会介绍第二种方式,对于用户来说,这是比较常用的安装方式;对于开发者来说,这是调用链比较长的安装方式,能学到的更多。其他的安装场景会在本系列的后续文章进行讲解。
3.寻找PackageInstaller入口
在Android7.0之前我们可以通过如下代码安装指定路径中的APK。
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType(Uri.parse("file://" + path),"application/vnd.android.package-archive");
context.startActivity(intent);
但是Android7.0或更高版本再这么做,就会报FileUriExposedException异常。这是因为StrictMode API 政策禁止应用程序将file:// Uri暴露给另一个应用程序,如果包含file:// Uri的 intent 离开你的应用,就会报FileUriExposedException 异常。为了解决这个问题,谷歌提供了FileProvider,FileProvider继承自ContentProvider ,使用它可以将file://Uri替换为content://Uri,具体怎么使用FileProvider并不是本文的重点,只要知道无论是Android7.0之前还是Android7.0以及更高版本,都会调用如下代码:
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(xxxxx, "application/vnd.android.package-archive");
Intent的Action属性为ACTION_VIEW,Type属性指定Intent的数据类型为application/vnd.android.package-archive。
能隐式匹配的Activity为InstallStart,需要注意的是,这里分析的源码基于Android9.0,7.0能隐式匹配的Activity为PackageInstallerActivity。
7.0 : packages/apps/PackageInstaller/AndroidManifest.xml
8.0,9.0:packages/apps/PackageInstaller/AndroidManifest.xml
InstallStart是PackageInstaller中的入口Activity,其中PackageInstaller是系统内置的应用程序,用于安装和卸载应用。当我们调用PackageInstaller来安装应用时会跳转到InstallStart,并调用它的onCreate方法:
9.0 : packages/apps/PackageInstaller/src/com/android/packageinstaller/InstallStart.java
@Override
55 protected void onCreate(@Nullable Bundle savedInstanceState) {
...
106 if (PackageInstaller.ACTION_CONFIRM_PERMISSIONS.equals(intent.getAction())) {
{
//1
107 nextActivity.setClass(this, PackageInstallerActivity.class);
108 } else {
109 Uri packageUri = intent.getData();
111 if (packageUri != null && (packageUri.getScheme().equals(ContentResolver.SCHEME_FILE)
112 || packageUri.getScheme().equals(ContentResolver.SCHEME_CONTENT))) {
113 // Copy file to prevent it from being changed underneath this process
114 nextActivity.setClass(this, InstallStaging.class);
115 } else if (packageUri != null && packageUri.getScheme().equals(
116 PackageInstallerActivity.SCHEME_PACKAGE)) {
117 nextActivity.setClass(this, PackageInstallerActivity.class);
118 } else {
119 Intent result = new Intent(); {
120 result.putExtra(Intent.EXTRA_INSTALL_RESULT,
121 PackageManager.INSTALL_FAILED_INVALID_URI);
122 setResult(RESULT_FIRST_USER, result);
123
124 nextActivity = null;
125 }
126 }
127
128 if (nextActivity != null) {
129 startActivity(nextActivity);
130 }
131 finish(