Jimmy Chen

A Programmer

(原创)基于Android 8.1之PackageInstaller源码分析(一)

前言

  前面两篇文章简单讲述了PackageManagerService的启动过程,和APK安装的内容一直都没有涉及到。APK可以通过多种方式安装,例如通过adb install安装、系统开机会默认安装系统应用、将apk放到手机通过PackageInstaller交互安装等等。安装APK的方式很多,但是这里选择用户使用最多的安装方式进行讲解,即通过PackageInstaller交互式安装。PackageInstaller是Android系统的默认程序,源码路劲为packages/app/PackageInstaller,同样我们的代码基于Android 8.1

PackageInstaller分析起点

  在Android 7.0以前,我们可以通过下面的方式来调用PackageInstaller进行程序的安装

  而在Android 7.0及以上版本,上面的代码会出现FileUriExposedException的异常,导致整个的原因是因为Android 7.0中有如下行为变更

For apps targeting Android 7.0, the Android framework enforces the StrictMode API policy that prohibits exposing file:// URIs outside your app. If an intent containing a file URI leaves your app, the app fails with a FileUriExposedException exception.

翻译过来的意思大概就是:对于面向 Android 7.0 的应用,Android 框架执行的 StrictMode API 政策禁止在您的应用外部公开 file:// URI。如果一项包含文件 URI 的 intent 离开您的应用,则应用出现故障,并出现 FileUriExposedException 异常。

所以在Android 7.0及以上的版本普遍会使用如下代码调用PackageInstaller进行APK的安装:

总结一下这两段代码的共同之处就是:1)设置Intent的action为ACTION_VIEW;2)设置Intent TYPE为application/vnd.android.package-archive; 3)隐式启动activity

接下来我们查看PackageInstaller的AndroidManifest.xml看是否有Activity能够对得上上面的条件

如上是PackageInstaller的AndroidManifest.xml的部分内容,其中红色部分真好匹配Action和mimeType。

Installstart.java

  代码中的解释写得挺详细的了,这里就不多做解释。onCreate最后显示的设置跳转到InstallStaging Activity中。下面我们接着分析InstallStaging。

InstallStaging.java

  InstallStaging启动后的调用路径是onCreate->onResume。

  install_staging的界面如下:

《(原创)基于Android 8.1之PackageInstaller源码分析(一)》

  其次就是上面代码中并没有太多的实际内容,主要内容还是通过StagingAsyncTask异步调用进行的,下面接着看StagingAsyncTask完成什么操作。

  上面的代码在doInBackground中,将content协议的Uri的内容读取出来然后写入到mStagedFile中,然后接着在onPostExcute中从mStagedFile产生file协议的Uri,然后使用给Uri来调用PackageInstallerActivity。这里感觉就像是启用了StrideMode后,绕了一个大圈,最后还是通过file协议的Uri来调用PackageInstaller。

PackageInstallerActivity.java

  这里首先会先获取到各种各样的管理类,列举如下:

《(原创)基于Android 8.1之PackageInstaller源码分析(一)》

  接着通过processPackageUri对packageUri进行解析

上面的代码通过解析file协议的Uri获取到文件相关信息保存到pased和mPkgInfo中。现在返回到PackageInstallerActivity的onCreate方法中,现在onCreate还剩下最后一个函数checkIfAllowedAndInitiateInstall还没有看,我们接着分析这个函数

这里我们的应用程序属于未知源安装包,所以如果我们在setting中选择了允许未知源安装,那么这里会直接走initiateInstall。如果为从未知源安装应用功能被限制的话,就会显示相关的提示信息。所以接下来我们查看initiateInstall的代码。

好了,到这里终于到了显示确认安装信息的界面了。

小结

这一篇先到这里了,下一篇我们将从startInstallConfirm。这里我们先做一下这篇文章的小结吧:

  1. 根据Uri的scheme不同,跳转到不同的界面,Android 7.0及以上的版本通过FilePorvider来提供Uri的话,起scheme是content,这里会跳转到InstallStart activity。其余的会跳转到PackageInstallerActivity
  2. InstallStart完成的工作主要就是讲content协议的Uri转换为file协议的Uri,然后见该信息传递给PackageInstallerActivity,然后在跳转到该Activity。
  3. PackageInstallerActivity会对package洗衣和file洗衣的Uri进行处理,如果是file协议的话会解析得到应用的PackageInfo信息
  4. 接着PackageInstallerActivity会对应用的来源进行判断,如果Package的来源于未知源并且系统设置了允许安装未知源的APK就会执行安装,否则显示弹出相关安装未知源应用的提示框

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注