面试官: AMS 在 Android 起到什么作用, 简单的分析下 Android 的源码
心理分析: 这道题在发生在大多数场景下. 面对这道题 很多求职很茫然, 不知道该如何说起. AMS 本身比较复杂难以理解. 工作多年也很难弄清 AMS 的作用, 其实我们大可从以下几点入手组件启动, 进程切换, Crash 异常入手
求职者: AMS 难以表述 我们就从最熟知 的 Activity 启动入手, 逐步深入和分析, 用定力告诉面试官, 我层深入研究过. 接下来我们从五条线分析 AMS 作用及机制
概述
相信大多数动脑同学对文章中提到的 ActivityManagerService(以后简称 AMS)都有所耳闻.
AMS 是 Android 中最核心的服务, 主要负责系统中四大组件的启动, 切换, 调度及应用进程的管理和调度等工作, 其职责与操作系统中的进程管理和调度模块相类似, 因此它在 Android 中非常重要. AMS 是碰到的第一块难啃的骨头[1], 涉及的知识点较多. 为了帮助读者更好地理解 AMS, 接下来将带小伙伴么按五条不同的线来分析它.
第一条线: 同其他服务一样, 将分析 SystemServer 中 AMS 的调用轨迹.
第二条线: 以 am 命令启动一个 Activity 为例, 分析应用进程的创建, Activity 的启动, 以及它们和 AMS 之间的交互等知识.
第三条线和第四条线: 分别以 Broadcast 和 Service 为例, 分析 AMS 中 Broadcast 和 Service 的相关处理流程.
第五条线: 以一个 Crash 的应用进程为出发点, 分析 AMS 如何打理该应用进程的身后事. 除了这五条线外, 还将统一分析在这五条线中频繁出现的与 AMS 中应用进程的调度, 内存管理等相关的知识. 提示 ContentProvider 将放到下一章分析, 不过本章将涉及和 ContentProvider 有关的知识点. 先来看 AMS 的家族图谱:
由图可知:
AMS 由 ActivityManagerNative(以后简称 AMN)类派生, 并实现 Watchdog.Monitor 和 BatteryStatsImpl.BatteryCallback 接口. 而 AMN 由 Binder 派生, 实现了 IActivityManager 接口.
客户端使用 ActivityManager 类. 由于 AMS 是系统核心服务, 很多 API 不能开放供客户端使用, 所以设计者没有让 ActivityManager 直接加入 AMS 家族. 在 ActivityManager 类内部通过调用 AMN 的 getDefault 函数得到一个 ActivityManagerProxy 对象, 通过它可与 AMS 通信.
AMS 由 SystemServer 的 ServerThread 线程创建;
1. 初识 ActivityManagerService 总结
本节所分析的 4 个关键函数均较复杂, 与之相关的知识点总结如下:
AMS 的 main 函数: 创建 AMS 实例, 其中最重要的工作是创建 Android 运行环境, 得到一个 ActivityThread 和一个 Context 对象.
AMS 的 setSystemProcess 函数: 该函数注册 AMS 和 meminfo 等服务到 ServiceManager 中. 另外, 它为 SystemServer 创建了一个 ProcessRecord 对象. 由于 AMS 是 Java 世界的进程管理及调度中心, 要做到对 Java 进程一视同仁, 尽管 SystemServer 贵为系统进程, 此时也不得不将其并入 AMS 的管理范围内.
AMS 的 installSystemProviders: 为 SystemServer 加载 SettingsProvider.
AMS 的 systemReady: 做系统启动完毕前最后一些扫尾工作. 该函数调用完毕后, HomeActivity 将呈现在用户面前. 对 AMS 调用轨迹分析是我们破解 AMS 的第一条线, 希望读者反复阅读, 以真正理解其中涉及的知识点, 尤其是和 Android 运行环境及 Context 相关的知识.
2. startActivity
总结 本文详细 startActivity 的整个启动流程,
流程[2.1 ~2.4]: 运行在调用者所在进程, 比如从桌面启动 Activity, 则调用者所在进程为 launcher 进程, launcher 进程利用 ActivityManagerProxy 作为 Binder Client, 进入 system_server 进程(AMS 相应的 Server 端).
流程[2.5 ~2.18]: 运行在 system_server 系统进程, 整个过程最为复杂, 核心的过程, 下面其中部分步骤:
流程[2.7]: 会调用到 resolveActivity(), 借助 PackageManager 来查询系统中所有符合要求的 Activity, 当存在多个满足条件的 Activity 则会弹框让用户来选择;
流程[2.8]: 创建 ActivityRecord 对象, 并检查是否运行 App 切换, 然后再处理 mPendingActivityLaunches 中的 activity;
流程[2.9]: 为 Activity 找到或创建新的 Task 对象, 设置 flags 信息;
流程 [2.13]: 当没有处于非 finishing 状态的 Activity, 则直接回到桌面; 否则, 当 mResumedActivity 不为空则执行 startPausingLocked() 暂停该 activity; 然后再进入 startSpecificActivityLocked()环节;
流程[2.14]: 当目标进程已存在则直接进入流程[2.17], 当进程不存在则创建进程, 经过层层调用还是会进入流程[2.17];
流程[2.17]:system_server 进程利用的 ATP(Binder Client), 经过 Binder, 程序接下来进入目标进程.
流程 [2.19 ~2.18]: 运行在目标进程, 通过 Handler 消息机制, 该进程中的 Binder 线程向主线程发送 H.LAUNCH_ACTIVITY, 最终会通过反射创建目标 Activity, 然后进入 onCreate() 生命周期. 从另一个角度下图来概括:
启动流程:
点击桌面 App 图标, Launcher 进程采用 Binder IPC 向 system_server 进程发起 startActivity 请求;
system_server 进程接收到请求后, 向 zygote 进程发送创建进程的请求;
Zygote 进程 fork 出新的子进程, 即 App 进程;
App 进程, 通过 Binder IPC 向 sytem_server 进程发起 attachApplication 请求;
system_server 进程在收到请求后, 进行一系列准备工作后, 再通过 binder IPC 向 App 进程发送 scheduleLaunchActivity 请求;
App 进程的 binder 线程 (ApplicationThread) 在收到请求后, 通过 handler 向主线程发送 LAUNCH_ACTIVITY 消息;
主线程在收到 Message 后, 通过发射机制创建目标 Activity, 并回调 Activity.onCreate()等方法. 到此, App 便正式启动, 开始进入 Activity 生命周期, 执行完 onCreate/onStart/onResume 方法, UI 渲染结束后便可以看到 App 的主界面.
startActivity 后半程总结
starActivity 总结
Activity 的启动就介绍到这里. 这一路分析下来, 相信读者也和笔者一样觉得此行绝不轻松. 先回顾一下此次旅程:
行程的起点是 am.am 是 Android 中很重要的程序, 读者务必要掌握它的用法. 我们利用 am start 命令, 发起本次目标 Activity 的启动请求.
接下来进入 ActivityManagerService 和 ActivityStack 这两个核心类. 对于启动 Activity 来说, 这段行程又可分细分为两个阶段: 第一阶段的主要工作就是根据启动模式和启动标志找到或创建 ActivityRecord 及对应的 TaskRecord; 第二阶段工作就是处理 Activity 启动或切换相关的工作.
首先讨论了 AMS 直接创建目标进程并运行 Activity 的流程, 其中涉及目标进程的创建, 在目标进程中 Android 运行环境的初始化, 目标 Activity 的创建以及触发 onCreate,onStart 及 onResume 等其生命周期中重要函数调用等相关知识点.
接着又讨论了 AMS 先 pause 当前 Activity, 然后再创建目标进程并运行 Activity 的流程. 其中牵扯到两个应用进程和 AMS 的交互, 其难度之大可见一斑. 读者在阅读本节时, 务必要区分此旅程中两个阶段工作的重点: 其一是找到合适的 ActivityRecord 和 TaskRecord; 其二是调度相关进程进行 Activity 切换. 在 SDK 文档中, 介绍最为详细的是第一阶段中系统的处理策略, 例如启动模式, 启动标志的作用等. 第二阶段工作其实是与 Android 组件调度相关的工作. SDK 文档只是针对单个 Activity 进行生命周期方面的介绍. 坦诚地说, 这次旅程略过不少逻辑情况. 原因有二, 一方面受限于精力和篇幅, 另方面是作为调度核心类, 和 AMS 相关的代码及处理逻辑非常复杂, 而且其间还夹杂了与 WMS 的交互逻辑, 使复杂度更甚. 再者, 笔者个人感觉这部分代码绝谈不上高效, 严谨和美观, 甚至有些丑陋(在分析它们的过程中, 远没有研究 Audio,Surface 时那种畅快淋漓的感觉). 此处列出几个供读者深入研究的点:
各种启动模式, 启动标志的处理流程.
Configuration 发生变化时 Activity 的处理, 以及在 Activity 中对状态保存及恢复的处理流程.
Activity 生命周期各个阶段的转换及相关处理. Android 2.3 以后新增的与 Fragment 的生命周期相关的转换及处理.
3. 广播处理总结
4. startService 流程图
总结 5.1 流程说明 在整个 startService 过程, 从进程角度看服务启动过程
Process A 进程: 是指调用 startService 命令所在的进程, 也就是启动服务的发起端进程, 比如点击桌面 App 图标, 此处 Process A 便是 Launcher 所在进程.
system_server 进程: 系统进程, 是 java framework 框架的核心载体, 里面运行了大量的系统服务, 比如这里提供 ApplicationThreadProxy(简称 ATP),ActivityManagerService(简称 AMS), 这个两个服务都运行在 system_server 进程的不同线程中, 由于 ATP 和 AMS 都是基于 IBinder 接口, 都是 binder 线程, binder 线程的创建与销毁都是由 binder 驱动来决定的, 每个进程 binder 线程个数的上限为 16.
Zygote 进程: 是由 init 进程孵化而来的, 用于创建 Java 层进程的母体, 所有的 Java 层进程都是由 Zygote 进程孵化而来;
Remote Service 进程: 远程服务所在进程, 是由 Zygote 进程孵化而来的用于运行 Remote 服务的进程. 主线程主要负责 Activity/Service 等组件的生命周期以及 UI 相关操作都运行在这个线程; 另外, 每个 App 进程中至少会有两个 binder 线程 ApplicationThread(简称 AT)和 ActivityManagerProxy(简称 AMP), 当然还有其他线程, 这里不是重点就不提了.
图中涉及 3 种 IPC 通信方式: Binder,Socket 以及 Handler, 在图中分别用 3 种不同的颜色来代表这 3 种通信方式. 一般来说, 同一进程内的线程间通信采用的是 Handler 消息队列机制, 不同进程间的通信采用的是 binder 机制, 另外与 Zygote 进程通信采用的 Socket.
启动流程:
Process A 进程采用 Binder IPC 向 system_server 进程发起 startService 请求;
system_server 进程接收到请求后, 向 zygote 进程发送创建进程的请求;
zygote 进程 fork 出新的子进程 Remote Service 进程;
Remote Service 进程, 通过 Binder IPC 向 sytem_server 进程发起 attachApplication 请求;
system_server 进程在收到请求后, 进行一系列准备工作后, 再通过 binder IPC 向 remote Service 进程发送 scheduleCreateService 请求;
Remote Service 进程的 binder 线程在收到请求后, 通过 handler 向主线程发送 CREATE_SERVICE 消息;
主线程在收到 Message 后, 通过发射机制创建目标 Service, 并回调 Service.onCreate()方法. 到此, 服务便正式启动完成. 当创建的是本地服务或者服务所属进程已创建时, 则无需经过上述步骤 2,3, 直接创建服务即可.
5. AMS 中的进程管理
前面曾反复提到, Android 平台中很少能接触到进程的概念, 取而代之的是有明确定义的四大组件. 但是作为运行在 Linux 用户空间内的一个系统或框架, Android 不仅不能脱离进程, 反而要大力利用 Linux OS 提供的进程管理机制和手段, 更好地为自己服务. 作为 Android 平台中组件运行管理的核心服务, ActivityManagerService 当仁不让地接手了这方面的工作. 目前, AMS 对进程的管理仅涉及两个方面:
调节进程的调度优先级和调度策略.
调节进程的 OOM 值.
6. App 的 Crash 处理总结
应用进程进行 Crash 处理的流程.[[图片上传失败...(image-bd3406-1561648443575)]
一, 概述
ActivityManagerService 是 Framework 层的核心服务之一, ActivityManagerService 是 Binder 的子类, 它的功能主要以下三点:
四大组件的统一调度
进程管理
内存管理
二, ActivityManagerService 的启动过程
ActivityManagerService 的启动是在 systemserver 进程的 startBootstrapServices 方法中启动的. SystemServiceManager.startService(ActivityManagerService.Lifecycle.class) 功能主要: 创建 ActivityManagerService.Lifecycle 对象; 调用 Lifecycle.onStart()方法.
三, 主要功能之一的四大组件的统一调度
ActivityManagerService 最主要的功能就是统一的管理者 activity,service,broadcast,provider 的创建, 运行, 关闭. 我们在应用程序中启动 acitivity, 关闭 acitiviy 等操作最终都是要通过 ams 来统一管理的. 这个过程非常的复杂, 不是一下子可以讲的清楚的, 我这里推荐老罗的博客来讲解四大组件的启动过程:
Android 应用程序内部启动 Activity 过程 (startActivity) 的源代码分析 Android 系统在新进程中启动自定义服务过程 (startService) 的原理分析 Android 应用程序注册广播接收器 (registerReceiver) 的过程分析 Android 应用程序发送广播 (sendBroadcast) 的过程分析 Android 应用程序组件 Content Provider 简要介绍和学习计划
四, 主要功能之一的内存管理
我们知道当一个进程中的 acitiviy 全部都关闭以后, 这个空进程并不会立即就被杀死, 而是要等到系统内存不够时才会杀死. 但是实际上 ActivityManagerService 并不能够管理内存, Android 的内存管理是 Linux 内核中的内存管理模块和 OOM 进程一起管理的.
Android 进程在运行的时候, 会通过 Ams 把每一个应用程序的 oom_adj 值告诉 OOM 进程, 这个值的范围在 - 16-15, 值越低说明越重要, 越不会被杀死. 当发生内存低的时候, Linux 内核内存管理模块会通知 OOm 进程根据 AMs 提供的优先级强制退出值较高的进程. 因此 Ams 在内存管理中只是扮演着一个提供进程 oom_adj 值的功能. 真正的内存管理还是要调用 OOM 进程来完成, 下面通过调用 Activity 的 finish()方法来看看内存释放的情况.
当我们手动调用 finish()方法或者按 back 键时都是会关闭 activity 的, 在调用 finish 的时候只是会先调用 ams 的 finishActivityLocked 方法将当前要关闭的 acitiviy 的 finish 状态设置为 true, 然后就会先去启动新的 acitiviy, 当新的 acitiviy 启动完成以后就会通过消息机制通知 Ams,Ams 在调用 activityIdleInternalLocked 方法来关闭之前的 acitiviy.
福利时间:
好了, 今天的分享就到这里, 如果你对在面试中遇到的问题, 或者刚毕业及工作几年迷茫不知道该如何准备面试并突破现状提升自己, 对于自己的未来还不够了解不知道给如何规划, 可以加一下下面的技术群. 来看看同行们都是如何突破现状, 怎么学习的, 来吸收他们的面试以及工作经验完善自己的之后的面试计划及职业规划.
这里放上一个两千人的技术交流大群: Android 架构设计(185873940)
面试相关资料的也可以加这个群免费领取的~
PS: 群内有许多技术大牛, 有任何问题, 欢迎广大网友一起前来交流吐槽
这里放上一部分我工作以来以及参与过的大大小小的面试收集总结出来的一套进阶学习的视频及面试专题资料包, 在这里免费分享给大家, 主要还是希望大家在如今大环境不好的情况下面试能够顺利一点, 希望可以帮助到大家~ 领取方式文末有分享的~
来源: http://www.jianshu.com/p/abe135febc44