深度探究apk安装过程
ReubenBattl
8年前
<h2>一.先验知识</h2> <p>0.PcakageaManagerService版本变化</p> <p>1.概述</p> <p>2.PackageManagerService服务启动流程</p> <p>3. PackageManagerService入口</p> <h2>二.四种安装方式</h2> <p>1.系统应用安装</p> <p>2.网络下载应用安装</p> <p>3. ADB工具安装</p> <p>4.第三方应用安装</p> <h2>三.总结</h2> <p><img src="https://simg.open-open.com/show/7ff134922378a196c397a8104d4ce68b.png"></p> <h2>概述</h2> <p>1.1概述</p> <p>众所周知, <a href="/misc/goto?guid=4959719078014872990" rel="nofollow,noindex">Android</a> 应用最终是打包成.apk格式(其实就是一个压缩包),然后安装至手机并运行的。APK即Android Package的缩写。</p> <p>Android系统在启动的过程中,会启动一个应用程序管理服务PackageManagerService,这个服务负责扫描系统中特定的目录,找到里面的应用程序文件,即以Apk为后缀的文件,然后对这些文件进解析,得到应用程序的相关信息,完成应用程序的安装过程。</p> <p>应用程序管理服务PackageManagerService安装应用程序的过程,其实就是解析析应用程序配置文件AndroidManifest.xml的过程,并从里面得到得到应用程序的相关信息,例如得到应用程序的组件Activity、Service、Broadcast Receiver和Content Provider等信息,有了这些信息后,通过ActivityManagerService这个服务,我们就可以在系统中正常地使用这些应用程序了。</p> <h2>Android应用APK安装的方式</h2> <p>一般而言,Android应用安装有如下四种方式:</p> <p>系统应用安装:开机时加载系统的APK和应用,没有安装界面;</p> <p>网络下载应用安装:通过各种market应用完成,没有安装界面;</p> <p>ADB工具安装:即通过Android的SDK开发tools里面的adb.exe程序安装,没有安装界面;</p> <p>第三方应用安装:通过SD卡里的APK文件安装(比如双击APK文件触发),有安装界面,系统默认已经安装了一个安装卸载应用的程序,即由packageinstaller.apk应用处理安装及卸载过程的界面。</p> <h2>应用安装涉及到的目录</h2> <p>/system/app :系统自带的应用程序,获得adb root权限才能删除</p> <p>/data/app :用户程序安装的目录。安装时把apk文件复制到此目录</p> <p>/data/data :存放应用程序的数据</p> <p>/data/dalvik-cache:将apk中的dex文件安装到dalvik-cache目录下(dex文件是dalvik虚拟机的可执行文件,当然,ART–Android Runtime的可执行文件格式为oat,启用ART时,系统会执行dex文件转换至oat文件)</p> <p>/data/system :该目录下的packages.xml文件,类似于Windows的注册表,这个文件是在解析apk时由writeLP()创建的,里面记录了系统的permissions,以及每个apk的name,codePath,flags,ts,version,uesrid等信息,这些信息主要通apk的AndroidManifest.xml解析获取,解析完apk后将更新信息写入这个文件并保存到flash,下次开机直接从里面读取相关信息添加到内存相关列表中。当有apk升级,安装或删除时会更新这个文件。</p> <p>/data/system/packages.xml中内容详解(这里列举的标签内容不一定完整,只是列举核心内容,packages.xml的完整定义详见官方文档):</p> <h2>安装概述</h2> <p>(1) 拷贝apk文件到指定目录</p> <p>在Android系统中,apk安装文件是会被保存起来的,默认情况下,用户安装的apk首先会被拷贝到 /data/app 目录下。</p> <p>/data/app目录是用户有权限访问的目录,在安装apk的时候会自动选择该目录存放用户安装的文件,而系统出厂的apk文件则被放到了 /system 分区下,包括 /system/app,/system/vendor/app,以及 /system/priv-app 等等,该分区只有Root权限的用户才能访问,这也就是为什么在没有Root手机之前,我们无法删除系统出厂的app的原因了。</p> <p>(2) 解压apk,拷贝文件,创建应用的数据目录</p> <p>为了加快app的启动速度,apk在安装的时候,会首先将app的可执行文件(dex)拷贝到 /data/dalvik-cache 目录,缓存起来。</p> <p>然后,在/data/data/目录下创建应用程序的数据目录(以应用的包名命名),存放应用的相关数据,如 <a href="/misc/goto?guid=4959733742410604191" rel="nofollow,noindex">数据库</a> 、xml文件、cache、二进制的so动态库等等。</p> <p>(3) 解析apk的AndroidManifinest.xml文件</p> <p>Android系统中,也有一个类似注册表的东西,用来记录当前所有安装的应用的基本信息,每次系统安装或者卸载了任何apk文件,都会更新这个文件。这个文件位于如下目录:</p> <p>/data/system/packages.xml</p> <p>系统在安装apk的过程中,会解析apk的AndroidManifinest.xml文件,提取出这个apk的重要信息写入到packages.xml文件中,这些信息包括:权限、应用包名、APK的安装位置、版本、userID等等。</p> <p>由此,我们就知道了为啥一些应用市场和软件管理类的app能够很清楚地知道当前手机所安装的所有的app,以及这些app的详细信息了。</p> <p>另外一件事就是 <a href="/misc/goto?guid=4959722320224711561" rel="nofollow,noindex">Linux</a> 的用户Id和用户组Id,以便他可以获得合适的运行权限。</p> <p>以上这些都是由PackageServiceManager完成的,下面我们会重点介绍PackageServiceManager。</p> <p>(4) 显示快捷方式</p> <p>这些应用程序只是相当于在PackageManagerService服务注册好了,如果我们想要在Android桌面上看到这些应用程序,还需要有一个Home应用程序,负责从PackageManagerService服务中把这些安装好的应用程序取出来,并以友好的方式在桌面上展现出来,例如以快捷图标的形式。在Android系统中,负责把系统中已经安装的应用程序在桌面中展现出来的Home应用程序就是Launcher了</p> <h2>1.2 PackageManagerService启动过程</h2> <p><img src="https://simg.open-open.com/show/282316bb80699cbbccfaa79dc33bb73b.png"></p> <h2>1.3 PackageManagerService入口</h2> <p><img src="https://simg.open-open.com/show/605672bd4313541331a18ae51864dd93.png"></p> <h2>2.1系统应用安装方式</h2> <p><img src="https://simg.open-open.com/show/9443a3e5d5a70c2a24f0ee54bf62b02a.png"></p> <h2>2.1系统应用安装方式</h2> <h2>第一步:1.PackageManagerService.main()初始化注册</h2> <p>将PackageManagerService服务初始化并注册到ServiceManager里面进行管理。</p> <h2>第二步:2.建立java层的installer与c层的installd的socket联接</h2> <p>建立 <a href="/misc/goto?guid=4959730847780971835" rel="nofollow,noindex">Java</a> 层的installer与c层的installd的socket联接,使得在上层的install,remove,dexopt等功能最终由installd在底层实现;</p> <h2>第三步:3.建立PackageHandler消息循环</h2> <p>建立PackageHandler消息循环,用于处理外部的apk安装请求消息,如adb install,packageinstaller安装apk时会发送消息;</p> <p>典型的比如INIT_COPY和MCS_BOUND等,在通过网络下载时候会调用。</p> <h2>第四步:4. 成员变量readLp()恢复上一次的安装信息</h2> <p>由于Android每次启动的时候都需要安装一次信息,但是有些信息是保持不变的,例如Linux用户组Id,PackageManagerService 每次安装程序之后,都会把这些程序的信息保存下来,以便下次使用, 恢复上一次程序的安装信息是通过PackageManagerService 的成员变量mSetting的readLP()来实现的,恢复信息之后就开始扫描和安装app了。</p> <p>检查/data/system/packages.xml是否存在,这个文件是在解析apk时由writeLP()创建的,里面记录了系统的permissions,以及每个apk的name,codePath,flags,ts,version,uesrid等信息,这些信息主要通过apk的AndroidManifest.xml解析获取,解析完apk后将更新信息写入这个文件并保存到flash,下次开机直接从里面读取相关信息添加到内存相关列表中。当有apk升级,安装或删除时会更新这个文件。</p> <h2>第五步:5.jar的detopt优化</h2> <p>检查BootClassPath,mSharedLibraries及/system/framework下的jar是否需要dexopt,需要的则通过dexopt进行优化;</p> <h2>第六步:6.scanDirLI函数扫描特定目录的apk文件解析</h2> <p>启动AppDirObserver线程监测/system/framework,/system/app,/data/app,/data/app-private目录的事件,主要监听add和remove事件。对于目录监听底层通过inotify机制实现,inotify 是一种文件系统的变化通知机制,如文件增加、删除等事件可以立刻让用户态得知,它为用户态监视文件系统的变化提供了强大的支持。当有add event时调用scanPackageLI(File , int , int)处理;当有remove event时调用removePackageLI()处理;</p> <p>调用installer.install()进行安装工作,检查apk里的dex文件是否需要再优化,如果需要优化则通过辅助工具dexopt进行优化处理;将解析出的componet添加到pkg的对应列表里;对apk进行签名和证书校验,进行完整性验证。</p> <h2>第七步:7.updatePermmisonLp函数分配权限</h2> <p>这个函数为申请了特定资源访问权限的app,分配相应的用户组ID.</p> <h2>第八步:8.writeLP()函数保存安装信息</h2> <p>mSetting的writeLP()将所获得应用程序的安装信息,保存在一个本地的配置文件中。以便下次安装的时候,将应用的信息回复过来。</p> <h2>2.1系统应用安装方式</h2> <p><img src="https://simg.open-open.com/show/88f93efd24a804fc953d98e39f043d94.png"></p> <h2>2.2网络下载应用安装</h2> <p><img src="https://simg.open-open.com/show/c25f8febbcabc2cdc67a89ed5fdbd8d1.png"></p> <h2>2.3 ADB工具安装</h2> <p><img src="https://simg.open-open.com/show/1ed3acbc6bc235549e443568211f4cdb.png"></p> <h2>2.4第三方应用安装</h2> <p>![这里写图片描述]( <a href="/misc/goto?guid=4959746963589823641" rel="nofollow,noindex">http://img.blog.csdn.net/20170310214918051?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHBqaXNodQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/</a></p> <h2>三.总结</h2> <p>1.安装和卸载都是通过PackageManager,实质上是实现了PackageManager的远程服务PackageManagerService来完成具体的操作,所有细节和逻辑均可以在PackageManagerService中跟踪查看;</p> <p>2.所有安装方式殊途同归,最终就回到PackageManagerService中,然后调用底层本地代码的installd来完成。</p> <p>再看apk 的安装过程。</p> <p>回个我们再看真个apk的安装过程,主要分为如下几部</p> <p>拷贝apk文件到指定目录</p> <p>解压apk,拷贝文件,创建应用的数据目录</p> <p>解析apk的AndroidManifinest.xml文件</p> <p>向Launcher应用申请添加创建快捷方式</p> <h2>参考:</h2> <p>《Android源代码情景分析》</p> <p>《Android内核分析》</p> <p><a href="/misc/goto?guid=4959746963672244761" rel="nofollow,noindex">http://blog.csdn.net/luoshengyang/article/details/6766010</a></p> <p><a href="/misc/goto?guid=4959746963760179021" rel="nofollow,noindex">http://blog.csdn.net/hdhd588/article/details/6739281</a></p> <p><a href="/misc/goto?guid=4959746963844457817" rel="nofollow,noindex">http://ticktick.blog.51cto.com/823160/1669525</a></p> <p><a href="/misc/goto?guid=4959746963926874523" rel="nofollow,noindex">http://www.jianshu.com/p/953475cea991</a></p> <p><a href="/misc/goto?guid=4959746964010660213" rel="nofollow,noindex">http://cstsinghua.github.io/2016/06/13/Android%E5%AE%89%E8%A3%85APK%E8%AF%A6%E8%A7%A3/</a></p> <p><a href="/misc/goto?guid=4959746964092410152" rel="nofollow,noindex">http://junshengluo.com/2016/11/30/android-5-%E6%8E%A2%E7%A9%B6%20Android%20%20apk%20%E5%AE%89%E8%A3%85%E8%BF%87%E7%A8%8B/</a></p> <p> </p> <p>来自:http://www.androidchina.net/6667.html</p> <p> </p>