专栏名称: 郭霖
Android技术分享平台,每天都有优质技术文章推送。你还可以向公众号投稿,将自己总结的技术心得分享给大家。
目录
相关文章推荐
郭霖  ·  iPhone 到 Android ... ·  3 天前  
郭霖  ·  Android Surface截图方法总结 ·  5 天前  
鸿洋  ·  Android ... ·  2 天前  
郭霖  ·  Android 跨进程+解耦的数据持久化方案 ·  1 周前  
51好读  ›  专栏  ›  郭霖

Android APK安装过程源码解析

郭霖  · 公众号  · android  · 2017-08-24 08:00

正文

今日科技快讯

前段时间刚有消费者从京东自营Gucci买了一款眼镜,眼镜左腿上的英文缩写竟是“GUCC”,京东表示眼镜是正品(只是有瑕疵),并给消费者道歉!而前日“tiger虎牌天猫官方旗舰店”发了一则公告,称有用户近日在“京东全球购等非授权店铺”购买到了假的虎牌保温杯,对此京东全球购否认了其虎牌自营旗舰店售假一事,并表示经过与虎牌方面求证,问题产品出自全球购的第三方店铺“京东福禄嘉全球购”,目前已经将该店铺冻结。

作者简介

本篇来自 lujianxin_ad 的投稿,给大家带来了APK安装的源码分析,希望对大家有所帮助! 

lujianxin_ad 的博客地址:

http://blog.csdn.net/qq_27540131

前言

本文关于 android 系统是如何安装我们apk的流程分析。不过这里仅仅只分析java层面的代码,C层方面的就跳过了。

源码分析

apk安装起始点

apk安装java层的起始位置是在 Pm.java 的 run() 中。

这里有2个重点,第一个红框 可以看到与我们的 PackageManagerService 有关,获取PackageManagerService 的 binder 对象,与 PackageManagerService 进行通信。并且如果这个对象为 null 则输出异常信息直接返回,其实也不难理解,PackageManagerService 把我们的 apk 给扫描了,那安装应该也会在其中。所以这里可以肯定的是 apk 的安装实现就在我们的 PackageManagerService 中;第二点就是根据这个 install 标识来执行安装的方法了。那我们就进入到 runInstall() 中来看下,它的内部是调用了 PackageManagerService 的什么方法来进行apk安装的。

runInstall()

从上面的 runInstall() 方法的代码可以看到有 3个标红框 的地方需要了解,第一个 obs 对象,用于接收 PackageManagerService 安装结果,其实从 第三个红框 就一目了然的了解 INSTALL_SUCCEEDED,安装成功!就输出 Success;第二个红框 就是通过 binder 来调起 PackageManagerService中的installPackageWithVerificationAndEncryption() 方法。

那接下来看下 PackageManagerService 中的 installPackageWithVerificationAndEncryption() 方法是如何操作的

这个方法代码并不是很多,重点在最后一部分,通过 handler 发送一个 INIT_COPY 的消息,消息的内容是一个 InstallParams 对象。(这里要注意下 InstallParams,等下会说下这个)

那我们就只要找到 handleMessage 中处理这个 INIT_COPY 的消息代码就行了

这里值得一提的是,安装 apk 的操作还需要一个服务,只有这个服务被 bind 了,才行进行下一步的工作,也就是通过 handler 继续发送一个消息。(这个服务是 com.android.defcontainer.DefaultContainerService 这里就不深层次分析了,它的作用就是用来解析 APK,以及获取推荐安装路径的,安装的路径与内存情况以及一些标识来决定)

绕来绕去,开启服务之后又发送了一个消息,那只好继续看下这个 MCS_BOUND 消息是如何处理的。

从代码中就能明显看到,这里又对服务进行了一次判断,是否已经连接,所以这个服务于我们的 apk 安装是共存的,其中 mPendingInstalls 就是用于存储需要安装的请求,只有当这个队列为空时才断开连接。(在 INIT_COPY 消息处理中被添加到 mPendingInstalls 中的),然后又调用了 HandlerParams的startCopy() 方法执行安装。


可以看到以下几个重点

  • HandlerParams 是个抽象类

  • 箭头那可以知道,这个安装会尝试4次,超过4次就GG了

  • 执行 handleStartCopy() 方法

  • 执行 handleReturnCode() 方法

在这之前值得一提的是前面 installPackageWithVerificationAndEncryption() 方法中通过 handler 发送消息,消息的内容是 InstallParams,而 InstallParams 又是继承自 HandlerParams 这个抽象类,所以具体执行的是 handleStartCopy() 与 handleReturnCode() 的是 InstallParams。

不过 InstallParams 这个方法的代码很长,这里大致说下,InstallParams 的 handleStartCopy() 的主要内容是通过 com.android.defcontainer.DefaultContainerService 来获取 apk 的推荐安装路径,通过这个路径来确定是内部安装还是SD卡安装,并且在这个方法的末尾,根据路径来创建不同的 InstallArgs,分别是 FileInstallArgs/SdInstallArgs 执行各自的 copyApk() 方法!

这里就从 FileInstallArgs 的 copyApk() 这条路线来分析。

FileInstallArgs.copyApk()

这个方法的重点部分就在红框位置,它的作用就是把我们的 APK 给复制到 /data/app 下,这个的路径可以通过 context.getPackageCodePath() 获取到,命名规则一般都是 XXX.base.apk,不过这里是个临时文件,在安装的时候会对其进行改名操作。

到这就分析完了 InstallParams的handleStartCopy() 方法,还有一个重点部分是 handleReturnCode 方法,所以接着分析 handleReturnCode();

handleReturnCode()

这里很简单,调用了 processPendingInstall() 方法

processPendingInstall()

这里分为两部分:

第一张图可以看到标红框部分执行了 doPreInstall() 和 installPackageLI(),doPostInstall();

doPreInstall 和 doPostInstall 内部很简单,他的作用就是把我们安装过程中的临时文件删除,installPackageLI 就是我们的正真安装操作。

第二张图则是安装之后,发送一个 POST_INTALL 消息,告诉系统是否安装完毕。

一系列的安装流程终于走到最后了,看下最终的 install 操作的方法

installPackageLI

下面两个红框可以看到,分别通过两种不同的方式进行安装,具体的判断逻辑是根据包名来判断的,如果存在包名则是覆盖安装,而不存在就是安装一个新的 apk。

replacePackageLI() 和 installNewPackageLI() 内部就和扫描系统中的 package 信息一样,如果不了解的,可以看下我这篇博客

android解析未安装apk中的AndroidManifest.xml以及系统源码分析

http://blog.csdn.net/qq_27540131/article/details/74938234

它把 APK 进行扫描,然后把apk中的信息存储到 PackageManagerService中。了解4大组件的启动过程就会知道,有一段流程是在 PackageManagerService 中获取四大组件信息,这些信息就是通过把我们 apk 扫描安装然后存储到 PackageMangerService 中的。这样我们的 apk 就已经安装完成了。

图中还有一个红框,args.doRename() 方法(这个 args 就是我们的 FileInstallArgs),前面提到过我们的 apk 文件会被复制到 /data/app 下,当复制进来的时候命名格式不是 xx.apk,而这里的 doRename() 方法就是把这个复制进来的文件改名成 XXXbase.apk。所以我们 context.getPackageCodePath() 获取到的路径就是改名后的信息。

APK 安装的源码分析就分析到这,大致的流程就是获取我们的安装位置,然后复制我们的apk文件到特定目录,然后安装我们的apk把apk的信息存储到 PackageManagerService中。跟着上面的代码走一遍,相信还是很好理解的。

更多

每天学习累了,看些搞笑的段子放松一下吧。关注最具娱乐精神的公众号,每天都有好心情。

如果你有好的技术文章想和大家分享,欢迎向我的公众号投稿,投稿具体细节请在公众号主页点击“投稿”菜单查看。

欢迎长按下图 -> 识别图中二维码或者扫一扫关注我的公众号: