写给Android App开发人员看的Android底层知识(3)
(七)App启动流程第2篇
书接上文,App启动一共有七个阶段,上篇文章篇幅所限,我们只看了第一阶段,接下来讲剩余的六个阶段,仍然是拿斗鱼App举例子。
简单回顾一下第一阶段的流程,就是Launcher向AMS发送一个跨进程通信,通过AMN/AMP,告诉AMS,我要启动斗鱼App。
画一个图,描述一下启动App所经历的7个阶段:

第2阶段 AMS处理Launcher传过来的信息

这个阶段主要是Binder的Server端在做事情。因为我们是没有机会修改Binder的Server端逻辑的,所以这个阶段看起来非常枯燥,我尽量说的简单些。
- 首先Binder,也就是AMN/AMP,和AMS通信,肯定每次是做不同的事情,就比如说这次Launcher要启动斗鱼App,那么会发送类型为START_ACTIVITY——TRANSACTION的请求给AMS,同时会告诉AMS要启动哪个Activity。
- AMS说,好,我知道了,然后它会干一件很有趣的事情,就是检查斗鱼App中的Manifest文件,是否存在要启动的Activity。如果不存在,就抛出Activity not found的错误,各位做App的同学对这个异常应该再熟悉不过了,经常写了个Activity而忘记在Manifest中声明了,就报这个错,就是因为AMS在这里做检查。不管是新启动一个App的首页,还是在App内部跳转到另一个Activity,都会做这个检查。
- 但是Launcher还活着啊,所以接下来AMS会通知Launcher,哥们儿没你什么事了,你“停薪留职”吧。那么AMS是通过什么途径告诉Launcher的呢?
前面讲过,Binder的双方进行通信是平等的,谁发消息,谁就是Client,接收的一方就是Server。Client这边会调用Server的代理对象。
对于从Launcher发来的消息,通过AMS的代理对象AMP,发送给AMS。
那么当AMS想给Launcher发消息,又该怎么办呢?前面不是把Launcher以及它所在的进程给传过来了吗?它在AMS这边保存为一个ActivityRecord对象,这个对象里面有一个ApplicationThreadProxy,单单从名字看就出卖了它,这就是一个Binder代理对象。它的Binder真身,也就是ApplicationThread。
站在AIDL的角度,来画这张图,是这样的:

所以结论是,AMS通过ApplicationThreadProxy发送消息,而App端则是通过ApplicationThread来接收这个消息。
第3阶段 Launcher去休眠,然后通知AMS,我真的已经“停薪留职”了,没有吃空饷

ApplicationThread(简称APT),它和ApplicationThreadProxy(简称ATP)的关系,我们在第三阶段已经介绍过了。
APT接收到来自AMS的消息后,就调用ActivityThread的sendMessage方法,向Launcher的主线程消息队列发送一个PAUSE_ACTIVITY消息。
前面说过,ActivityThread就是主线程(UI线程)
看到下面的代码是不是很亲切?

发送消息是通过一个名为H的Handler类的完成的,这个H类的名字真特么有个性,想记不住都难。
做App的同学都知道,继承自Handler类的子类,就要实现handleMessage方法,这里是一个switch…case语句,处理各种各样的消息,PAUSE_ACTIVITY消息只是其中一种,由此也能预见到,AMS给Activity发送的所有消息,以及给其它三大组件发送的所有消息,都从H这里经过,为什么要强调这一点呢,既然四大组件都走这条路,那么这里就可以做点手脚,从而做插件化技术,这个我们以后介绍插件化技术的时候会讲到。

H对于PAUSE_ACTIVITY消息的处理,如上面的代码,是调用ActivityThread的handlePauseActivity方法。这个方法干两件事:
- ActivityThread里面有一个mActivities集合,保存当前App也就是Launcher中所有打开的Activity,把它找出来,让它休眠。
- 通过AMP通知AMS,我真的休眠了。
你可能会找不到H和APT这两个类文件,那是因为它们都是ActivityThread的内嵌类。
至此,Launcher的工作完成了。你可以看到在这个过程中,各个类都起到了什么作用。芸芸众生,粉墨登场:
- APT
- ActivityThread
- H
第4阶段 AMS启动新的进程
接下来又轮到AMS做事了,你们会发现我不太喜欢讲解AMS的流程,甚至都不画UML图,因为这部分逻辑和App开发人员关系不是很大,我尽量说的简单一些,把流程说清楚就好。
AMS接下来要启动斗鱼App的首页,因为斗鱼App不在后台进程中,所以要启动一个新的进程。这里调用的是Process.start方法,并且指定了ActivityThread的main函数为入口函数。

第5阶段 新的进程启动,以ActivityThread的main函数作为入口

启动新进程,其实就是启动一个新的App。
在启动新进程的时候,为这个进程创建ActivityThread对象,这就是我们耳熟能详的主线程(UI线程)。
创建好UI线程后,立刻进入ActivityThread的main函数,接下来要做2件具有重大意义的事情:
1)创建一个主线程Looper,也就是MainLooper。看见没,MainLooper就是在这里创建的。
2)创建Application。记住,Application是在这里生成的。
- - - - - - - - - - - - - -华丽的分割线 开始- - - - - - - - - - - - - - -
App开发人员对Application非常熟悉,因为我们可以在其中写代码,进行一些全局的控制,所以我们通常认为Application是掌控全局的,其实Application的地位在App中并没有那么重要,它就是一个Context上下文,仅此而已。
App中的灵魂是ActivityThread,也就是主线程,只是这个类对于App开发人员是访问不到的——使用反射倒是可以修改这个类的一些行为。
- - - - - - - - - - - - - - -华丽的分割线 结束- - - - - - - - - - - - - - -
创建新App的最后,就是告诉AMS,我启动好了,同时把自己的ActivityThread对象发送给AMS,从此以后,AMS的电话簿中就多了这个新的App的登记信息,AMS以后向这个App发送消息,就通过这个ActivityThread对象。
第6阶段 AMS告诉新App启动哪个Activity
AMS把传入的ActivityThread对象,转为一个ApplicationThread对象,用于以后和这个App跨进程通信。还记得APT和ATP的关系吗?这就又回到第2阶段的那张关系图了。
还记得第1阶段,Launcher发送给AMS要启动斗鱼App的哪个Activity吗?这个信息被AMS存下来了。
那么在第6阶段,AMS从过去的记录中翻出来要启动哪个Activity,然后通过ATP告诉App。
第7阶段 启动斗鱼首页Activity

毕其功于一役,尽在第7阶段。这是最后一步。
App,这个Binder的另一端,通过APT接收到AMS的消息,仍然是在H的handleMessage方法的switch语句中处理,只不过,这次消息的类型是LAUNCH_ACTIVITY:

ActivityClientRecord是什么?这是AMS传递过来的要启动的Activity。
还是这里,我们仔细看那个getPackageInfoNoCheck方法,这个方法会提取Apk中的所有资源,然后设置给r的packageInfo属性。这个属性的类型很有名,叫做LoadedApk。各位记住这里,这个地方可以干坏事,也是插件化技术渗入的一个点。
在H的这个分支中,又反过来回调ActivityThread的handleLaunchActivity方法,你要是觉得很绕那就对了。其实我一直觉得,ActivityThread和H合并成一个类也没问题。

重新看一下这个过程,每次都是APT执行ActivityThread的sendMessage方法,在这个方法中,把消息拼装一下,然后扔个H的swicth语句去分析,来决定要执行ActivityThread的那个方法。每次都是这样,习惯就好了。
handleLaunchActivity方法都做哪些事呢?
1)通过Instrumentation的newActivity方法,创建出来要启动的Activity实例。
2)为这个Activity创建一个上下文Context对象,并与Activity进行关联。
3)通过Instrumentation的callActivityOnCreate方法,执行Activity的onCreate方法,从而启动Activity。看到这里是不是很熟悉很亲切?
至此,App启动完毕。这个流程是经过了很多次握手, App和ASM,频繁的向对方发送消息,而发送消息的机制,是建立在Binder的基础之上的。
下一篇文章,我们讲Context家族。
写给Android App开发人员看的Android底层知识(3)的更多相关文章
- 写给Android App开发人员看的Android底层知识(1)
这个系列的文章一共8篇,我酝酿了很多年,参考了很多资源,查看了很多源码,直到今天把它写出来,也是战战兢兢,生怕什么地方写错了,贻笑大方. (一)引言 早在我还是Android菜鸟的时候,有很多技术我都 ...
- 写给Android App开发人员看的Android底层知识(2)
(五)AMS 如果站在四大组件的角度来看,AMS就是Binder中的Server. AMS全称是ActivityManagerService,看字面意思是管理Activity的,但其实四大组件都归它管 ...
- 写给Android App开发人员看的Android底层知识(6)
(十一)BroadcastReceiver BroadcastReceiver,也就是广播,简称Receiver. 很多App开发人员表示,从来没用过Receiver.其实吧,对于音乐播放类App,用 ...
- 写给Android App开发人员看的Android底层知识(5)
(十)Service Service有两套流程,一套是启动流程,另一套是绑定流程.我们做App开发的同学都应该知道. 1)在新进程启动Service 我们先看Service启动过程,假设要启动的Ser ...
- 写给Android App开发人员看的Android底层知识(7)
(十二)ContentProvider (1)ContentProvider是什么? ContentProvider,简称CP. 做App开发的同学,尤其是电商类App,对CP并不熟悉,对这个概念的最 ...
- 写给Android App开发人员看的Android底层知识(8)
(十)PMS及App安装过程 PMS,全称PackageManagerService,是用来获取Apk包的信息的. 在前面分析四大组件与AMS通信的时候,我们介绍过,AMS总是会使用PMS加载包的信息 ...
- 写给Android App开发人员看的Android底层知识(4)
(八)App内部的页面跳转 在介绍完App的启动流程后,我们发现,其实就是启动一个App的首页. 接下来我们看App内部页面的跳转. 从ActivityA跳转到ActivityB,其实可以把Activ ...
- 一看就懂的Android APP开发入门教程
一看就懂的Android APP开发入门教程 作者: 字体:[增加 减小] 类型:转载 这篇文章主要介绍了Android APP开发入门教程,从SDK下载.开发环境搭建.代码编写.APP打包等步骤 ...
- 谋哥:App开发人员的苦逼不值得怜悯!!
[谋哥每天一干货,第四十篇] 为什么取这个标题呢?由于昨天一些本来"支持"谋哥的人看到谋哥搞收费VIP群,认为谋哥赚苦逼开发人员的钱非常不道德,且说谋哥我写的东西都 ...
随机推荐
- 提高 webpack 构建 Vue 项目的速度
前言 最近有人给我的 Vue2 后台管理系统解决方案 提了 issue ,说执行 npm run build 构建项目的时候极其慢,然后就引起我的注意了.在项目中,引入了比较多的第三方库,导致项目大, ...
- Git安装与上传代码至Github
转载请注明出处:http://www.cnblogs.com/cnwutianhao/p/6642887.html 这篇文章应该是全网最新,最全,最靠谱的Github安装到上传代码的流程. 1.Git ...
- Entity Framework Code First在Oracle下的伪实现
为什么要说是伪实现,因为还做不到类似MsSql中那样完全的功能.Oralce中的数据库还是要我们自己手动去创建的.这里,我们舍掉了Model First中的EDMX文件,自己在代码里面写模型与映射关系 ...
- 利用伪元素和css3实现鼠标移入下划线向两边展开效果
一.思路: 将伪元素:before和:after定位到元素底部中间,设置宽度从0变成100%达到目的. 二.实现: 1.首先定义一个块状元素(行内元素没有宽高)并修改样式为一个背景色为浅灰色的矩形,设 ...
- php 启动过程 - sapi MSHUTDOWN 过程
php 启动过程 - sapi MSHUTDOWN 过程 概述 当服务器关闭时, 会走到 sapi MSHUTDOWN 过程 注册过程 本次内容是在 php 启动过程 - sapi MINIT 过程 ...
- 微信开发(2)---微信小程序开发实战part1
微信开发现在来说,简单可以概括为两部分,微信公众号和微信小程序. 微信公众号的技术已经非常成熟.分为服务号和订阅号.简单的.可以弄一个个人订阅号,在编辑模式下就可以实现推送图文.自动回复.自定义菜单的 ...
- 主机ping通虚拟机,虚拟机ping通主机解决方法(NAT模式)
有时候需要用虚拟机和宿主机模拟做数据交互,ping不通是件很烦人的事,本文以net模式解决这一问题. 宿主机系统:window7 虚拟机系统:CentOs7 连接方式:NAT模式 主机ping通虚拟机 ...
- 2017/4/27-Gradle的配置与Spring的下载
Gradle的配置与Spring的下载 1.Gradle 1) 介绍 Gradle是一个基于Groovy的构建工具,类似Maven,但是比其更加简单轻便.它可以自动化地进行软件构建.测试.发布.部署. ...
- Linux 练习(1)
1) 新建用户natasha,uid为1000,gid为555,备注信息为"master" useradd -u 1000 -g 555 -c 'master' natasha2) ...
- [第一阶段] Python学习
首先声明一下,我这个学习计划是关于学习Python的. 先说一下起因:我自己接触Python算是很久了,目前仍没学会,很失败,很惭愧.所以这次一方面简单分析一下自学会碰到的问题:另一方便,我想到了一种 ...