android 安装系统级服务,Android PKMS服务

它的作用?

关于PKMS的全称是啥应该咱们不陌生,PackageManagerService,和AMS一样是Android系统的核心服务,它主要负责系统中Package的管理,应用程序的安装、卸载、信息查询等工作。几乎每个实际项目都会使用它,最典型的就是APP的更新安装。

服务何时启动?

那PKMS是在何时进行的启动了,其实是在SystemServer.main()中进行的,下面来直接看一下源码,其源码还是基于8.0,如下:

e57037928f38084fe49ab9aa8fb571a4.png

然后在它的run()方法中看一下启动细节,看核心:

749a96e71e7f38100e7ffcab54d069d2.png

然后接下来就启动各种服务了:

f70b89b3ec75111fe6d682c9f963357a.png

那么问题来了?PKMS服务的启动是在哪个方法中来执行的呢?咱先先来看第一个启动引导服务方法:

ab70655aea47c61c30e36db4cf03c916.png

接下来就可以看到启动AMS服务了,也就是上次咱们所析的,这里再来回顾一下:

0de6f2b55b3f1d77a785fc5533dfde8f.png

接下来还有一系列系统服务的启动,如:PowerManagerService:

9aeed791fe0d76a87c81d62803b6701d.png

DisplayManagerService:

f70aa51bfc6a69c976e55cc4501f4fa1.png

好,接下来我们想要的答案的代码来了:

b9a304e988881132ec08590d6f7c2e92.png

由于已经看到了咱们所要看到的服务的启动,对于其它2个启动服务的方法就暂且不看了,得集中精力分析我们想分析的PKMS,免得精力分散了:

8263d843849a7020ef9f7f80d5e379e4.png

好,咱们来分析一下PKMS的main()方法,既然在注册它时调用了它:

e5042697d1f5ee8176e3b6b27f126af7.png

ede31266a72303253b00743c0fb172ec.png

0b4bda8ffe8c033245d14d7db3881190.png

上面来将其整个PKMS启动的流程用图来表述一下:

213c97e6bc85a06fc2571dafa2da9ba3.png

然后最后将其注册到ServiceManager当中:

eb193ec848126dcc30dcf489148c1c29.png

好,既然构造了PKMS,那下面来看一下它里面的构造细节。

构造方法:

该构造方法代码量很大:

cc321931b2215f3176be7dba807d3b35.png

5c9df9aa6426434d9d042f9d0ad78ff9.png

700多行。。当然也只能顺着核心流程来分析喽,其实分为如下五个阶段。

第一阶段:

构造函数在第一阶段的工作,主要是扫描并解析 ,XML 文件,将其中的信息保存到特定的数据结构中。看下代码:

9b908a09f16c4a681fbfd895c99a0924.png

c1d82b46eb41549e3396b89837727b7a.png

14cf04264102541069511333dc366c30.png

43b47c76098c14692c93ca356c42ffc6.png

2d5ae73821ec39c7c1b06a29c80beaf4.png

第二阶段:

该阶段主要是扫描系统文件。

1、创建/system的子目录,比如/system/framework、system/priv-app和/system/app等等。

瞅下代码:

8929cb50759a2fbe4cb13b83ba0e6aa2.png

2、扫描系统文件,比如/vendor/overlay、/system/framework、/system/app等等目录下的文件,对扫描到的系统文件做后续处理。

其中:

/system/frameworks:该目录中的文件都是系统库,例如:framework.jar、services.jar、framework-res.apk。不过 scanDirLI 只扫描APK文件,所以 framework-res.apk 是该目录中唯一“受宠”的文件。

该目录下全是默认的系统应用,例如:Browser.apk、SettingsProvider.apk 等。

/vendor/app:该目录中的文件由厂商提供,即厂商特定的 APK 文件,不过目前市面上的厂商都把自己的应用放在 /system/app 目录下。

瞅下代码:

178309f60d70c8767dbd6b308709a2ba.png

e3fbd3e2eb6ce3d342ac116a2f2275fa.png

275ead5c03e47789e5ada6dfe29c7642.png

76d8bf700e1e46e589280e39dd5496cf.png

第三阶段:

它是属于扫描data分区阶段,扫描/data/app和/data/app-private目录下的文件:

64f45a1e520d06a4c6628a01be781030.png

,具体细节为:

1、遍历possiblyDeletedUpdatedSystemApps列表,如果这个系统App的包信息不在PMS的变量mPackages中,说明是残留的App信息,后续会删除它的数据。说明是存在于Data分区,不属于系统App,那么移除其系统权限。

看下代码:

27787aa5d63008201f99da35d2bdee73.png

其中可以看到是利用PackageParser.Package来对包进行扫描的:

c3a34d97a44576bba363d752a3f64e94.png

咱们点进去看一下大概扫描的细节:

89c60838aa9ec3e539329265da9f2463.png

然后看一下它里面定义的成员变量,就知道它的大概作用了:

ef6d98e13bdd25f9864683f3b7d5f85c.png

也就是会扫描manifest文件,然后将其扫描的信息存储到对应的集合当中了。

2、遍历mExpectingBetter列表,根据系统App所在的目录设置扫描的解析参数,内部会将packageName对应的包设置数据(PackageSetting)添加到mSettings的mPackages中。扫描系统App的升级包,最后清除mExpectingBetter列表。

看下代码:

3174bad045f9c26b844f540a7130ef00.png

5ec81650fe5cb5a73b65f0ae23e08ba7.png

第四阶段:

扫描结束阶段主要是做了以下事情:

1、如果当前平台SDK版本和上次启动时的SDK版本不同,重新更新APK的授权;

4ac5e47a4a415b4bc4fd667185176b0b.png

2、如果是第一次启动或者是Android M升级后的第一次启动,需要初始化所有用户定义的默认首选App;

4842c75735eed6e50b231a80fad7a3d2.png

3、OTA升级后的第一次启动,会清除代码缓存目录。

067b0615a886f02d81af859c85a09dcd.png

4、把Settings的内容保存到packages.xml中,这样此后PMS再次创建时会读到此前保存的Settings的内容。

f48f875a5d20d1e6000f3bec401d83f4.png

第五阶段:

此时就进入了准备安装的阶段了:

b59ecacde2472c36c3fe96de47827852.png

以上五个阶段走完之后,咱们再来完善之前的图:

b13c5ac482198e59812b7407d7fd703d.png

installd进程:

我们在之前分析PKMS服务启动时知道在它之前会创建一个这样的服务:

dcd6fdf2f1c6e70fd3d6a3b5834fe692.png

而它是运行在installd进程中的,看一下Installer.java类的注释:

ce0d046b02f7c0e5ddeaca5ba482f440.png

那么该进程是何时启动的呢?这里就得从开机到app启动的流程进行梳理一下,其创建结点这在其中,下面来梳理一下:

c55572bfbf66d7d245c2b8d8163ecd52.png

也就是installd 是由 Android 系统的 init 进程(pid=1),在解析 init.rc 文件的如下代码块时,通过 fork 创建的用户空间的守护进程 installd,

而该进程的代码对应于这样cpp:

c24fcbd41adada29fc9d9b0ac6f11acc.png

而installd 是随着系统启动过程中 main class 而启动的,并启动InstalldNativeService服务发布到native层的ServiceManager中,通过IPC机制跟上层的 installer服务进行交互。下面来看一下它的main入口函数:

fd972850dfba06b026fcf6c91a43312b.png

9b571f7a92ab48185828a3cb5a1758b0.png

然后咱们再来跟到InstalldNativeService.cpp中来看一下它启动的细节:

fb8654d0cc6c3d2e8ad2d27d1fcf8357.png

而它里面都是跟一些app的操作相关的服务,大致瞅一下提供的函数:

9cea3de636cf96aa211b78375aef14a2.png

96b1cfe896b5a63823dac3bb5b5736dc.png

c583d271ad36ae5cb0653735b06f1fe1.png

系统内置应用程序安装app:

对于应用的安装我们在应用时会这样来写:

e50d83364871daa002bb85085519edf2.png

咱们接下来就来分析一下它的整个安装过程,最终就是会用到PKMS来进行安装,先贴一张整个安装的流程图:

0936d93cfda47503d139f384daabea36.png

下面根据上面的流程来看一下具体的代码,对于上面的调用安装是最终会到PackageInstallerActivity这个界面上来,也就是安装确定界面,这个是大家再熟悉不过的了,下面打开看一下这个类的源码:

cb2a4d6e30d64d32a903504fdee02164.png

然后在onCreate()的最后会有一句这个代码:

f0d386c5dacea478bcdf2851d72da284.png

判断是否是未知来源的应用,如果开启允许安装未知来源选项则直接初始化安装,这个在实际咱们在安装时也是经常会出现的,此时就需要到设置里去把未知来源勾选一下就可以正常安装了,好下面再来看一下检测方法:

eb3fdb63c8d2b29c71312b1cee724a40.png

好,下面直接来看一下直接安装的方法:

5f2b7988ec28537c7e30356cb59a346d.png

c94f61ffd52589fd90fe3febea14221d.png

dbd2a4ba822bc478e9ec3a0434aeb69f.png

然后具体UI的细节就不看了,直接看到用户点了“安装”的事件:

b953623a32602fa1bad30c970ca98647.png

fabdc323af87e93f92cbf6d397b6fc57.png

此时就会跳到安装中的InstallInstalling的Acitivity界面了,跟进去看一下细节:

559a0b81882818863c2f3a91f4a84864.png

5e1b97f2f463360130dbd7dbdef5b415.png

然后在安装后台线程中看一下真正执行安装的逻辑:

97706d8853ba98a849ac0144c4845518.png

40f7b7c1a4e85760ac68327a2ba09e11.png

此时就转到PackageInstaller.Session.commit()方法来瞅一下:

d8049eca3d0a8ddff6e2314b00df1271.png

2bd76f1889fc2c51b9aed5a9883c7a18.png

bdc0384cb0decfb5ec963f40c6372b25.png

而它的具体实现类则为PackageInstallerSession.java,所以看一下它的细节:

8491dbdadde09bfb0b080561be1640f1.png

9626e46b0733fda00fb1804ec1d9cad2.png

此时看一下这个消息处理逻辑:

9ca6ef4d98540e8dfaa81b7b72ab480e.png

cd226f818a3b4b0d3d763f4fb0dd5582.png

而mPm就是PKMS:

43bc61b3b597c46a2ac7bff236e6a4aa.png

所以又转到PKMS.installStage()方法中来瞅一下,最终的执行是通过消息处理:

7c1411c9058c377c5d7cb64c0dd75376.png

最终的安装就会还是用installer服务来进行安装,也就是对于安装是底层来完成的。也就是这块:

766f8ac5bb6d640206fe46d395ecc5a6.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值