欢迎光临
专注android技术,聚焦行业精粹,我们一直在努力

插件化基础之Activity启动流程

1、前言

本文不同于其它的Activity启动流程的文章:我们会基于Android最新的9.0代码分析Activity的启动流程,同时我们不会贴代码,我们会从偏架构方面切入来介绍Android框架中Activity的启动流程。整体的思路如下:

从前面一篇文章我们学习到Android底层是通过Binder来实现跨进程通信的,那么我们从一个应用的Activity调用它的startActivity来启动另一个应用的Activity,也必然少不了使用到跨进程通信了,也就是使用到Binder了。学习了上一篇文章《插件化基础之Binder和AIDL》为我们更好的理解Activity启动流程会非常有帮助。

2、Activity启动流程——过程视图分析

一个应用的Activity到另一个应用的Activity不是直接调用,而是通过ActivityManagerService(缩写为AMS)中转。也就是说一个Activity到另一个Activity的过程要经过Activity -> AMS -> Activity。

我们拆解一下先介绍Activity到AMS的过程视图:

2.1、Activity到AMS

我们看到一个很熟悉的东西——AIDL。通过前面的学习我们知道“Android为了使用面向对象的方式来实现跨进程通信而使用了AIDL”,这里的Activity和AMS通信就是使用了AIDL的方式通过Binder驱动来实现的。他们的类关系图(即逻辑视图)如下:

这里涉及到一个类:Instrumentation,Android instrumentation是Android系统里面的一套控制方法或者”钩子“。这些钩子可以在正常的生命周期(正常是由操作系统控制的)之外控制Android控件的运行,后面会详细介绍该类。

2.2、AMS到Activity

上面的图描述了AMS -> Activity的启动流程,从startActivityWait到Activity的onCreate生命周期被调用。

如果此时启动Activity在新的进程中,那么此时AMS会启动一个新的进程,并让ActivityThread运行在这个新的进程中,整体流程如下:

流程描述如下:

  1. AMS 通过zygote fork一个进程出来,并在新的进程里面调用app的入口方法(ActivityThread.main)
  2. ActivityThread启动后将自己的ApplicationThread对象的Binder引用通过AIDL接口的attachApplication方法传递给远程服务端的AMS。
  3. 服务端(AMS)通过app端传递过来的ApplicationThread的Binder引用,更新缓存的ProcessRecord对象
  4. 服务端(AMS)通过IApplicationThread的binder引用回调app客户端的bindApplication对象,并最终调用了Application的onCreate方法。

AMS调用app端的bindApplication方法也是通过AIDL实现的,具体的逻辑视图如下:

2.3、AMS到四大组件的进程判断流程如下

2.3.1、Activity新进程判断流程图

2.3.2、Service新进程判断流程图

其它2大组件的判断也是类似的,这里就不一一赘述。我们看到都是用到了AMS的startProcessLocked方法。startProcessLocked的流程在上面2.2节的进程创建流程图中已经描述,可以再回顾一遍。

3、关键类介绍

3.1、ActivityThread

ActivityThread,就是主线程,也就是UI线程,它是在App启动时创建的,它代表了App应用程序。ActivityThread里面有main函数,我们知道java程序的入口函数就是main函数,那么我们可以看到Android的main函数是在ActivityThread里面。

3.2、ApplicationThread

ApplicationThread是ActivityThread的内部类,ActivityThread与启动Activity有关,那么ApplicationThread就与启动Application有关了。它继承自IApplicationThread.Stub,是AMS与app端通信的AIDL服务端,负责接收来自AMS的消息并处理。

3.3、H

ApplicationThread接收到来自AMS的消息后,调用ActivityThread的sendMessage方法,向app的主线程消息队列发送一个消息,前面说过,ActivityThread就是主线程(UI线程)。发消息是通过一个名为H的Handler类完成的。

我们知道继承自Handler类的子类,就要实现handleMessage方法,里面有switch…case语句,处理各种各样的消息。由此也能预见,AMS给Activity发送的所有消息,以及给其它三大组件发送的所有消息,都从H这里经过。为什么要强调这一点呢?既然四大组件都走这条路,那么就可以从这里入手做插件化技术。

它的handleMessage代码如下:

3.4、Instrumentation

官方对Instrumentation的介绍

instrumentation can load both a test package and the application under test into the same process. Since the application components and their tests are in the same process, the tests can invoke methods in the components, and modify and examine fields in the components.

翻译

Instrumentation可以把测试包和目标测试应用加载到同一个进程中运行。既然各个控件和测试代码都运行在同一个进程中了,测试代码当然就可以调用这些控件的方法了,同时修改和验证这些控件的一些数据

Android instrumentation是Android系统里面的一套控制方法或者”钩子“。这些钩子可以在正常的生命周期(正常是由操作系统控制的)之外控制Android控件的运行,其实指的就是Instrumentation类提供的各种流程控制方法,下表展示了部分方法的对应关系

具体源码:

activity.performCreate方法最终会调用activity的onCreate生命周期方法。所以这里就好比Instrumentation勾住了本应该系统调用的onCreate方法,然后由用户自己来控制勾住的这个方法什么时候执行。

3.4.1、Instrumentation的使用

Instrumentation是Android自带一个单元测试框架,不过虽然这么说,其对于大部分应用开发人员来讲,最大的作用反而是用于功能或UI测试。

3.4.1.1、获取Activity中的控件

3.4.1.2、操作Activity中的控件

3.4.1.3、hook instrumentation 监控应用内application及activity的生命周期

4、Context家族

Activity、Service、Application其实是亲戚关系,如图所示:

Activity因为有了一层Theme,所以中间有个ContextThemeWrapper,相当于它是Service和Application的侄子。

ContextWrapper里面有一个Context类型的成员变量mBase,当然它实际的类型是ContextImpl。ContextWrapper只是一个包装类,没有任何具体的实现,真正的逻辑都在ContextImpl里面。

一个应用包含的Context个数=Service个数+Activity个数+1(Application类本身对应一个Context对象)。

应用程序中包含多个ContextImpl对象,而其内部的变量mPackageInfo指向同一个PackageInfo对象。

我们在调用startActivity方法时可以用Activity对象的startActivity,也可以用context的startActivity。通过前面章节的学习我们知道activity的startActivity最终是执行的mInstrumentation的execStartActivity方法。我们看一下ContextImpl的实现,我们发现它也是调用的mInstrumentation的execStartActivity方法:

5、总结

本文从Android架构的角度介绍了Activity的启动流程,其核心是基于Android的Binder的跨进程通信机制。这个启动过程中我们接触到了一些对后续学习插件化非常有帮助的类:ActivityThread,H,Instrumentation,ApplicationThread等。相信有了这些基础,我们能更轻松的揭开插件化神秘的面纱。

赞(1) 打赏
未经允许不得转载:花花鞋 » 插件化基础之Activity启动流程
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

国内精品Android技术社区

联系我们

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏