Android Framework 面试系列(四)Activity 启动原理

Activity 的启动流程

用户点击桌面图标(桌面应用的进程名一般叫做 Launcher),启动 Activity 的流程如下图所示,图片来源 Activity启动过程

启动流程主要分为三部分,分别是 Launcher 进程通知 AMS 服务启动 Activity、AMS 通知 zygote 进程创建新的进程、AMS 与 创建的 App 进程交互启动 Activity。

上图片中出现的类的介绍如下:

  • ActivityManagerService:简称为 AMS,是Android系统中重要的系统服务之一,主要负责Android中四大组件的启动、通信、部分生命周期的管理等等
  • ActivityThread: App的真正入口,通过调用main()App开始真正运行,同时开启消息循环队列,虽然不是一个真正的线程,但一般所在的线程被称为UI线程或主线程。ActivityThread就是专门与AMS的进行外部交互。
  • ApplicationThread: 应用需要和远程服务AMS等通信,而Binder是单向提供服务的,而AMS等服务想控制应用需要应用程序提供一个Binder接口,ApplicationThread就是这个Binder接口,用于通过远程服务调用本地的方法。
  • ActivityManagerProxy: AMS远程服务在本地的代理。
  • ApplicationThreadProxy: ApplicationThread在远程服务AMS的代理。

Launcher 进程通知 AMS 服务启动 Activity

Launcher 进程通知 AMS 的流程如下,对应上图中的步骤1.

  1. 通过 ServiceManager 获取 AMS 服务
  2. 通过 AMS 提供的接口,告诉它要启动的应用

AMS 通知 zygote 进程创建新的进程

AMS 收到启动 Activity 的通知后,会通过 socket 来请求 zygote 进程 fork 新的应用进程,对应上图的步骤2和3。流程如下:

  1. AMS 发生创建进程的请求(调用 startProcessLocked 方法)
  2. zygote 进程 fork 出 app 进程
  3. zygote 创建 App 进程后,使用反射方式,调用 ActivityThread 的 main 方法

AMS 与 创建的 App 进程交互启动 Activity

ActivityThread 的 mian 方法会创建 ApplicationThread ,并且启动 Handler 消息循环机制。然后与 AMS 绑定,最后启动 Activity。具体步骤如下:

  1. 创建 ApplicationThread,内部创建 ActivityManagerProxy 来与 AMS 通信
  2. 通过 ActivityManagerProxy 发送 ATTACH_APPLICATION_TRANSACTION 命令
  3. AMS 接收到命令后,执行 attachApplicationLocked 方法。attachApplicationLocked 方法内会先调用 ApplicationThreadProxy 的 bindApplication 方法,这个方法会传入这个应用的一些信息,如ApplicationInfo,Configuration 等,然后会发送一个 H.BIND_APPLICATION 的消息。Handler 机制处理这个消息时会通过反射创建 Application对象,然后执行 Application 的 attachBaseContext、onCreate 方法。
  4. attachApplicationLocked 方法后面还是执行 realStartActivityLocked 方法,通过 ApplicationThreadProxy 发送 SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION 命令
  5. App 进程接收到 SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION 命令后,会发送 H.LAUNCH_ACTIVITY 消息。Handler 机制处理这个消息时会调用 ActivityThread.handleLaunchActivity 方法,该方法会反射创建 activity 对象,然后执行 Activity的attachBaseContext、onCreate 方法。

面试题

ActivityThread 是什么,它是一个线程吗,如何被启动的?

它不是一个线程,它是运行在 App 进程中的主线程中的一个方法中。当 App 进程创建时会执行 ActivityThread.main(),ActivityThread.main() 首先会创建 Looper 执行 Looper.prepareMainLooper();然后创建 ActivityThread 并调用 ActivityThread.attach() 方法告诉 ActivityManagerService 我们创建了一个应用 并将 ApplicationThread 传给 ActivityManagerService;最后调用 Looper.loop()。

ActivityClientRecord 与 ActivityRecord 是什么?

记录 Activity 相关信息,比如:Window,configuration,ActivityInfo 等。 ActivityClientRecord 是客户端的,ActivityRecord 是 ActivityManagerService 服务端的。

Context 是什么,ContextImpl,ContextWapper 是什么?

Context 定义了 App 进程的相关环境,Context 是一个接口,ContextImpl 是子类,ContextWapper 是具体实现。

应用资源是在 Application 初始化的时候,也就是创建 Application,ContextImpl 的时候,ContextImpl 就包含这个路径,主要就是对就是 ResourcesManager 这个单例的引用。

应用里有多少个 Context?不同的 Context 之间有什么区别?

Activty的数个+Service的个数+Application的个数。应用可能是多进程的,因此Application可能有多个。区别:Activty因为要显示UI,因此它继承了ContextThemeWrapper,而Service和Application这种非UI组件则直接继承ContextWrapper。

Activity 里的 this 和 getBaseContext 有什么区别?

因为Activty是继承了Context,所以this就是返回Activity对象自己;而getBaseContext返回的是ContextWrapper里面的mBase

getApplication 和 getApplicationContext 有什么区别

getApplicationContext() 是context里的一个抽象函数,而getApplication()是Activty和Service里特有的------它在别的地方不能用,比如在广播的onReciever(context)中的context是不能调getApplication()的,只能调getApplicationContext()。

应用组件的构造,onCreate、attachBaseContext 的调用顺序

组件构造函数->attachBaseContext->onCreate

Instrumentation 是什么?

管理着组件 Application,Activity,Service 等的创建,生命周期调用。

Application 是什么,什么时候创建的,每个应用程序有几个 Application?

Application 是在 ActivityThread.handleBindApplication() 中创建的,一个进程只会创建一个 Application,但是一个应用如果有多个进程就会创建多个 Application 对象。

点击 Launcher 启动 Activity 和应用内部启动 Activity 的区别?

点击 Launcher 时会创建一个新进程来开启 Activity,而应用内打开 Activity,如果 Activity 不指定新进程,将在原来进程打开,是否开启新进程实在 ActivityManagerService 进行控制的,上面分析得到,每次开启新进程时会保存进程信息,默认为 应用包名 + 应用UID,打开 Activity 时会检查请求方的信息来判断是否需要新开进程。Launcher 打开 Activity 默认 ACTIVITY_NEW_TASK,新开一个 Activity 栈来保存 Activity 的信息。

Activity 启动过程,onCreate(),onResume() 回调时机及具体作用?

Activity.onCreate() :完成了 App 进程,Application,Activity 的创建,作用是调用 setContentView() 给 Activity 设置了 layout 布局。

Activity.onResume() :完成了 Activity 中 Window 与 WindowManager 的关联,作用是并对所有子 View 进行渲染并显示。

为什么是 zygote 来创建进程,而不是 system_server

AMS 和 zygote 为什么不使用 binder 通信

  1. 先后时序问题: Binder驱动是早于init进程加载的。而init进程是安卓系统启动的第一个进程。安卓中一般使用的Binder引用,都是保存在ServiceManager进程中的,而如果想从ServiceManager中获取到对应的Binder引用,前提是需要注册。init进程是先创建ServiceManager,后创建Zygote进程的。虽然Zygote更晚创建,但是也不能保证Zygote进程去注册binder的时候,ServiceManager已经初始化好了。注册时间点无法保证,AMS无法获取到Zygote的binder引用。
  2. 多线程问题: Linux中fork进程是不推荐fork一个多线程的进程的,因为如果存在锁的情况下,会导致锁异常。而如果自身作为Binder机制的接收者,就会创建一个额外的线程来进行处理(发送者进程是无影响的)。所以,如果使用Binder机制,就会导致去fork一个多线程的进程。

谈谈你对 application 的理解

相关推荐
大胃粥2 小时前
Android V app 冷启动(8) 动画结束
android
ufo00l2 小时前
Kotlin在Android中有哪些重要的应用和知识点是需要学习或者重点关注的
android
AJi2 小时前
Android音视频框架探索(二):Binder——系统服务的通信基础
android·ffmpeg·音视频开发
tjsoft3 小时前
Nginx配置伪静态,URL重写
android·运维·nginx
努力学习的小廉3 小时前
【C++11(中)】—— 我与C++的不解之缘(三十一)
android·java·c++
tangweiguo030519873 小时前
打破界限:Android XML与Jetpack Compose深度互操作指南
android·kotlin·compose
Watink Cpper4 小时前
[MySQL初阶]MySQL(8)索引机制:下
android·数据库·b树·mysql·b+树·myisam·innodedb
一起搞IT吧5 小时前
高通camx IOVA内存不足,导致10-15x持续拍照后,点击拍照键定屏无反应,过一会相机闪退
android·数码相机
前行的小黑炭7 小时前
设计模式:为什么使用模板设计模式(不相同的步骤进行抽取,使用不同的子类实现)减少重复代码,让代码更好维护。
android·java·kotlin
ufo00l7 小时前
2025年了,Rxjava解决的用户痛点,是否kotlin协程也能解决,他们各有什么优缺点?
android