Android M PackageManager对于应用程序apk的安装流程分析

上篇文章我们分析了android M PackageManagerService 启动过程,今天我们继续深入了解下对于apk的安装,PackageManager又是怎样做的呢?

应用程序安装有很多种方法,开发者最常见的就是使用adb install命令或者pm install脚本命令。

很多的应用市场也都有自己的封装,android原生的安装应用为PackageInsteller。


本篇涉及源码路径:

system/core/adb/ commandline.cpp
frameworks/base/cmds/pm/src/com/android/commands/pm/Pm.java
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
frameworks/base/services/core/java/com/android/server/pm/PackageInstallerService.java
frameworks/base/packages/DefaultContainerService/
frameworks/base/core/java/android/content/pm/PackageParser.java

adb install原理

我们先看adb install原理


adb install命令来源于/android/system/core/adb工具,从上面的代码看到,adb install实际执行的是install_app()。



Install_app会根据存储路径将apk文件copy到/data/local/temp或者sd卡中的路径,后面进行apk复制时会从这个路径里面取。

这里我们可以看到adb命令最终调用的是pm脚本来进行apk的安装。

PM脚本

pm是android中的一个脚本,由pm.java编译生成,最终被放到system/bin下的,其代码路径为:

frameworks/base/cmds/pm


pm脚本的main方法中创建一个Pm对象,然后调用其run方法跑起来。

run方法中获取到package包管理器的binder客户端本地代理Proxy,就可以和IPackageManager服务端通信了。

 

这里还通过binder通信获取到之前在PKMS构造函数最后完成时创建的PackageInstallerService服务,后面安装时会用到它。

接着,解析arg参数,匹配到install时,会执行runInstall。

这里先创建了一个LocalPackageInstallObserver,这个obs将用于接收PKMS返回的安装消息。

最终,我们通过installPackageAsUser调用到了PKMS中。

怎么过去的?


this指的是mRemote, mRemote即是package的服务端PKMS。

installPackageAsUser方法

前面讲到PM脚本通过binder将安装命令发送到了PKMS中,接下来看PKMS是怎样进行apk安装的。

说明:

  • 检查是否具有安装权限,或者是否用户禁止安装等;
  • 封装一个INIT_COPY的消息,并且创建InstallParams对象,然后把消息通过handler发送出去;

根据PKMS启动过程,我们知道,之前创建了PackageHandler,且其消息处理线程已经运行起来,很确定,INIT_COPY就是在PackageHandler的handleMessage中处理的。

PackageHandler的handleMessage方法直接调用的是doHandleMessage,根据msg类型匹配到INIT_COPY分支。

Apk的安装需要依赖一个apk提供的服务来支持,这个服务就是DefaultContainerService,即源码中的DefaultCotainerService.apk。

第一次安装的时候,由于服务还未启动,需要bindService来启动该服务,如果已经启动,则将安装信息通过MCS_BOUND触发。

关于DefaultContainerService怎么启动就不说了哈,我们直接看对MCS_BOUND消息的处理。


在MCS_BOUND中,调用了startCopy方法。

startCopy方法中会紧接着调用handleStartCopy,这个方法是个抽象方法,具体的实现由子类完成,之前我们创建的handleParams为InstallParams,所以这里会调用到InstallParams的handleStartCopy方法中,如果安装完成,则调用handleReturnCode,返回处理结果。

handleStartCopy

 


说明:

  • DCS的getMinimalPackageInfo方法会去解析apk文件,得到一个PackageLite对象,该对象是一个轻量级(相对于pkg)的用于描述APK的结构,这里面会取到recommendedInstallLocation,表示apk推荐的安装路径。
  • 计算apk的大小,检查存储空间是否足够;
  • installLocationPolicy检查检查推荐的安装路径,例如系统apk不允许安装在SD卡上;
  • createInstallArgs将根据不同的安装位置创建不同的InstallArgs,如果是内部存储则返回FileInstallArgs,外部则是AsecInstallArgs(SD卡),其中还有负责移动的MoveInstallArgs;
  • 最后调用args的copyApk开始进行apk的拷贝;

copyApk

通过前面的分析,我们已经得到apk适合的安装位置,接下来就由copyApk来完成apk的复制工作。

说明:

  • 首先会通过installService的方法allocateStageDirLegacy在/data/app下创建临时文件,临时文件名为 临时文件名为vmdl-随机数.tmp;
  • 调用DCS的copyFile执行复制操作,最终将/data/local/temp下的apk文件复制到/data/app/下,文件名为base.apk, 然后修改相关文件的读写权限等。
  • 调用copyNativeBinariesWithOverride对lib库进行复制;
DefContainer:Copying /data/app/com.iflytek.inputmethod.gionee-1/base.apk to base.apk

至此,handleStartCopy就完成了,apk拷贝完了,其实apk并没有完全解析并且归档到PKMS的数据结构中,因此,接下来我们还要对apk文件解析归档。

handleReturnCode

由于最初创建的handleParams为InstallParams,所以handleReturnCode也是installParams的子类方法。

该方法中mArgs为FileInstallArgs,所以会直接调用processPendingInstall进行接下来的处理。

 

说明:

  • 在mHandler中抛一个Runnable对象,如果之前handleStartCopy中没有出现问题,则返回码应该是INSTALL_SUCCEEDED,就会调用doPreInstall对安装路径进行清理,如果是success,则什么都不做;
  • 调用installPackageLI进行扫描安装,即我们之前的scanPackageLI ==> parsePackage==> parseBaseApk ==> parseBaseApplication…
  • 最后会调用doRename对文件进行命名;
  • 调用doPostInstall进行安装文件的处理。
  • 如果允许backup则通过BackupManager对其进行备份处理;
  • 向handr抛一个POST_INSTALL消息;

进入POST_INSTALL消息处理环节:

说明:

  • 依次发送PACKAGE_ADDED,ACTION_PACKAGE_REPLACED广播;
  • 强制执行依次GC进行资源回收;
  • 调用FileInstallArgs的doPostDeleteLI进行资源清理;
  • 调用onPackageInstalled向PM通知安装的结果(obs);

之前的obs在调用完install请求后,进入wait状态等待PKMS的返回,在onPackageInstalled方法中notifyAll将其唤醒输出安装结果。


安装返回值结果

常见的APK安装结果(返回值)通常有以下几种。

返回值

说明

解决方式

INSTALL_SUCCEEDED

安装成功

-

INSTALL_FAILED_ALREADY_EXISTS

apk已经安装过

加-r参数

INSTALL_FAILED_INVALID_APK

apk安装包无效

确认apk文件是否有效

INSTALL_FAILED_INVALID_URI

uri无效,路径不对..

确认apk的绝对路径

INSTALL_FAILED_INSUFFICIENT_STORAGE

空间不足,中间文件vmdl无法创建

清除空间

INSTALL_FAILED_DUPLICATE_PACKAGE

主要检查版本号

 

INSTALL_FAILED_NO_SHARED_USER

请求的SharedUserId不存在

 

INSTALL_FAILED_UPDATE_INCOMPATIBLE

与之前安装的签名不对

将之前的app删除后再安装

INSTALL_FAILED_SHARED_USER_INCOMPATIBLE

与sharedUserId的签名不匹配

 

INSTALL_FAILED_MISSING_SHARED_LIBRARY

使用的共享库不存在

 确认所使用的共享库系统是否已支持。

INSTALL_FAILED_OLDER_SDK

INSTALL_FAILED_NEWER_SDK

Sdk版本不匹配<uses-sdk>

 请使用正确的targetsdk

INSTALL_FAILED_CONFLICTING_PROVIDER

provider冲突

确认manifest中使用的provider

INSTALL_FAILED_TEST_ONLY

android:testOnly="true"

Android studio中请使用build生成apk安装,或者adb install –t参数

INSTALL_FAILED_VERSION_DOWNGRADE

VersionCode低了

 

………………

 

 

安装流程小结 

此,apk的安装流程就基本上完成了,下面的流程图可以完整展现该过程。


后续将会继续分析权限管理部分,欢迎关注。


posted @ 2018-06-14 14:47  mail181  阅读(65)  评论(0编辑  收藏  举报