二、程序安装过程
1.使用adb install执行安装过程
使用adb install执行安装过程整体流程图如下:
一、使用adb install命令安装apk
1.adb指令对应源文件system/core/adb/commandline.c
。
2.指令参数解析:根据传入参数install判断是安装指令,直接调用到install_app();
3.执行文件拷贝:在install_app()中:
- 首先定义两个拷贝位置:分别对应拷贝到内部或者外部存储。这里需要根据传入参数确定拷贝位置。默认是拷贝到内部存储中。
- 执行拷贝:将制定的apk文件从电脑端拷贝到制定的目录处。
- 执行安装:调用pm_command()函数开始去安装。
- 删除文件:当安装结束时删除该apk文件。
4.开始去安装:在pm_command()中:
- 构造shell指令:将参数凭借成为shell指令。
- 去执行shell:使用send_shellcommand()去执行pm脚本,使用app_process运行pm.jar。
二、跨进程去执行安装
1.执行前准备:
- 获取Binder:首先获取PKMS对应的Binde对象。
- 解析传入参数:判断是install指令确定是安装指令。调用runinstall()。
2.准备跨进程安装:在runinstall()中:
- 解析参数:while循环依次解析参数确定installFlags,接着获取apk文件路径构造apkURI通过它读取文件。
- 跨进程调用:首先新建PackageInstallObserver回调接收PKMS安装结果,然后使用mPm.installPackageWithVerificationAndEncryption()跨进程调用到PKMS该函数执行。
- 等待安装结果:循环判断PackageInstallObserver.finished状态,等待安装结果根据结果提示用户信息。
三、PKMS执行具体安装
1.执行安装准备工作:在installPackageWithVerificationAndEncryption()中:
- 检查权限:首先检查调用者进程是否存在安装应用的权限。
- 获取uid,设置filteredFlags:获取调用者uid根据uid做后续判断。如果uid是SHELL_UID为filteredFlags设置INSTALL_FROM_ADB表示否则取消该表示,这里是需要设置该标识。
- 发生异步消息:获取INIT_COPY标识的Message对象,设置obj为新建对象InstallParams,该对象分装了安装需要的参数及信息。然后发送该Message。
- InstallParams类图关系如下:
2.执行异步消息:在PackageHandler中:
- 处理消息:异步消息都会调用doHandleMessage()处理具体逻辑。
- 判断在INIT_COPY标识下:
- 首先获取安装请求对象:obj即HandlerParams的子类InstallParams。
- 判断是否启动服务:mBound表示是否启动DefaultContainerService服务,该服务由DefaultContainerService.apk提供,主要作用是拷贝文件到应用程序目录。如果已启动则将该安装请求对象添加到队列mPendingInstalls中该队列如果为空则发生消息MCS_BOUND执行安装。如果未启动调用connectToService()启动该服务。
- 判断在MCS_BOUND标识下:该标识在DefaultContainerService启动成功后也会回调。
- 获取mContainerService对象:如果是DefaultContainerService启动成功后的回调,直接获取obj即为该对象。判断mContainerService是否为空,如果为空代表DefaultContainerService服务未启动不能执行安装操作,不为空判断如果mPendingInstalls队列存在请求则开始执行。
- 获取安装请求:使用mPendingInstalls.get(0)获取一个待安装请求HandlerParams。
- 执行安装请求:调用该HandlerParams.startCopy()函数,判断函数返回结果,返回为true代表处理成功。
- 请求处理成功:请求处理成功时,首先从mPendingInstalls队列中移除该请求,如果mPendingInstalls队列此时大小为0代表所有请求已完成则回调MCS_UNBIND断开服务。如果还存在请求则继续回调MCS_BOUND消息执行安装请求。
3.执行安装请求逻辑:HandlerParams.startCopy()中:
- 尝试次数判断:安装请求执行失败后有重试机制。判断mRetries是否大于最大尝试次数,超过最大次数发生异步消息MCS_GIVE_UP放弃执行返回false。未超过则执行安装行为。
- 执行拷贝操作:调用handleStartCopy()执行拷贝请求,具体是实现在InstallParams中。
- 执行安装操作:调用handleReturnCode()执行安装请求,具体是实现在InstallParams中。
4.执行apk的拷贝:在HandlerParams.handleStartCopy()中:
- 获取指定的安装位置:首先从flags中获取指定的安装位置,这里的flags来自于之前解析参数传入的filteredFlags。判断如果同时指定既在sd卡安装又在内部存储安装则赋值ret安装失败。
- 获取手机存储状况:通过dsm服务调用getMemoryLowThreshold()获取当前内部存储最小余量。小于这个值就是空间不足。
- 授予apk读取权限:授予DefContainerService URI读权限,使其可以执行apk的拷贝操作。
- 获取PackageInfoLite对象并判断:首先获取待安装apk的packageFile对象,根据该对象调用mContainerService.getMinimalPackageInfo()获取其对应的PackageInfoLite对象,该对象描述apk的包名、版本、推荐安装位置、签名等信息。然后判断该apk的安装推荐位置是RECOMMEND_FAILED_INSUFFICIENT_STORAGE代表当前存储空间不足需要释放空间,计算该apk安装需要的空间然后使用mInstaller.freeCache()释放空间,之后在尝试获取一次PackageInfoLite对象。
- 撤销apk读取权限:撤销对uri的读取权限mContext.revokeUriPermission()。
- 确定最终安装的位置:根据pkgLite.recommendedInstallLocation确定ret值,并且最终确定安装位置sd卡或者是内部存储,并设置flags值。
- 新建安装参数对象InstallArgs:调用createInstallArgs(this)创建一个安装参数对象,根据flag对安装位置区别处理。这里如果是安装在sd卡上返回AsecInstallArgs对象,反之是FileInstallArgs对象。它们都继承自InstallArgs。注意这里构造的时候传入的是当前的安装请求对象HandlerParams,该对象分装了这次请求需要的所有信息参数。
- 判断一系列验证检查:如果设置了包验证开启,则收集信息发送广播给包校验器检查,检查通过才能接着进行安装。如果未设置则直接调用安装参数对象InstallArgs.copyApk()执行拷贝apk。
5.具体开始执行apk的拷贝操作:在InstallArgs.copyApk()中,假设安装位置在内部存储则该方法具体实现在FileInstallArgs中:
- 判断temp:temp代表拷贝到/data/app下的文件名是否需要随机,这里我们传入的true是要随机,因为如果不随机以apk结尾,PKMS会监听到该文件之后直接执行安装操作,我们不需要直接进行该安装操作,所以设置随机名。
- 执行apk拷贝操作:首先获取创建apk对应File对象codeFile,为DCM服务授权读取权限。接着使用imcs.copyResource()拷贝资源到codeFile文件。同时为该apk创建native目录并且拷贝native库到该位置。最后返回安装结果ret。
至此安装操作完成HandlerParams.handleStartCopy()执行完毕赋值安装结果给mRet变量。
6.拷贝完成执行安装操作:在HandlerParams.handleReturnCode()中:
- 判断安装参数对象InstallArgs:首先判断InstallArgs对象如果不为null则开始执行安装流程,调用processPendingInstall()。安装结束之后删除临时文件,如果未开启包验证则该文件不存在不需要删除。
- 执行安装操作:使用Hanlder发布异步任务,新建安装结果对象PackageInstalledInfo,接着调用installPackageLI()执行安装操作,传入安装参数对象InstallArgs及PackageInstalledInfo获取安装结果。安装完成之后新建对象PostInstallData分装InstallArgs及PackageInstalledInfo然后放入mRunningInstalls这个map中,新建一个token为索引。最后发生一个异步消息POST_INSTALL并携带索引token,通知安装结果。
7.安装完成执行通知操作:在PackageHandler中:
- 判断在POST_INSTALL标识下:
- 获取安装结果对象:在mRunningInstalls中根据token获取安装结果PostInstallData。如果存在则分别取出对应的InstallArgs和PackageInstalledInfo。
- 处理安装成功情况:判断PackageInstalledInfo.returnCode是安装成功,首先发送安装成功广播ACTION_PACKAGE_ADDED,如果是应用更新操作还要发送ACTION_PACKAGE_REPLACED广播。然后进行资源清理,接着取出InstallArgs.observer不为空代表存在安装结果回调对象,则回调其对应结果。
至此adb install安装程序流程完成。
简单总结流程:
- 将电脑端apk资源拷贝到制定的临时文件夹下。
- 将apk拷贝到/data/app目录下,但是文件名需要随机处理。
- 调用PKMS函数执行apk安装。
- 回调安装结果给监听器。