Android/Activity启动流程相关知识点串通

Android系统启动流程

Android 平台的主要组件

Android采用分层的架构,分为四层,从高层到底层分为应用程序层(app+System apps),应用程序框架层(Java API Framework),系统运行库和运行环境层(Libraries + android Runtime)和Linux核心层(HAL+ Linux Kernel),如下图所示:
在这里插入图片描述
1. 应用层(System Apps)
系统内置的应用或者开发者开发的应用都属于应用层,负责与用户进行直接交互。
2. 应用框架层(Java API Framework)
主要包含了以下一些核心组件:
Activity Manager(活动管理器):管理各个应用程序的生命周期,以及常用的导航回退功能。
Location Manager(位置管理器):提供地理位置及定位功能服务。
Package Manager(包管理器):提供地理位置及定位功能服务。
Notification Manager(通知管理器):使得应用程序可以在状态栏中显示自定义的提示信息。
Resource Manager(通知管理器):提供应用程序使用的各种非代码资源,如本地化字符串、图片、布局文件、颜色文件等。
Telephony Manager(电话管理器):管理所有的移动设备功能。
Window Manager(窗口管理器):管理所有开启的窗口程序。
Content Provider(内容提供者):使得不同应用程序之间可以共享数据。
View System(视图系统):构建应用程序的基本组件。
3. 系统运行库层
系统运行库层又分为了c/c++程序库(Native c/c++ Libraries)和Android运行时库(Android Runtime)。
c/c++ Libraries集合包含包括开源的 Web 浏览器引擎 Webkit ,知名的 libc 库,用于仓库存储和应用数据共享的 SQLite 数据库,用于播放、录制音视频的库,用于网络安全的 SSL 库等。
Android运行时包括核心库和虚拟机两部分。
包含了核⼼库(Core Libraries和 ART)。核⼼库提供了Java语⾔核⼼库的⼤多数功能,这样使得开发者可以使⽤Java语言来编写Android应⽤(是专门为 Android 开发的基于 Java 的程序库)。包含两部分内容,一部分为绝大多数Java程序语言所需要调用的功能函数,如java.io等;另外一部分是Android的核心库,如android.os,android.net、android.database、android.view等。
ART称为虚拟机,Android5.0之前使⽤的是Dalvik之后ART替换了前者。与JVM虚拟机相⽐Dalvik虚拟机专门为移动设备定制,允许在有限的内存运⾏多个虚拟机实例,每⼀个Dalvik应⽤作为⼀个独⽴的Linux进⾏执⾏。独⽴的进程防⽌了虚拟机崩溃的时候所有的程序都关闭。ART和Dalvik不同的是:Dalvik中的应⽤每次运⾏的时候字节码都需要通过即时编译器转换为机器码,这样会使得运⾏效率降低。⽽在ART中,系统安装应⽤的时候会进⾏⼀次预编译,将字节码预编译成机器码,并存在本地,这样应⽤每次执⾏的时候就不需要执⾏编译了。
4. 硬件抽象层(HAL)
硬件抽象层位于操作系统内核与硬件电路之间的接⼝层,⽬的就是将硬件抽象化,通俗来说就是将硬件的动作放在硬件抽象层中。
5. Linux内核层(Linux Kernel)
Android的核心系统服务基于Linux内核。
它包括了显示驱动、摄像头驱动、Flash内存驱动、Binder(IPC)驱动、键盘驱动、WIFI驱动、Audio驱动以及电源管理部分。它作为硬件和软件应用之间的硬件抽象层,使得应用程序开发人员不需关心硬件细节。但是对于硬件开发商而言,如果想要Android平台运行到自己的硬件平台上就必须对Linux内核进行修改,为自己的硬件编写驱动程序。

启动流程

在这里插入图片描述
启动按照一个流程:
Loader->kernel->framework->Application来进行的

1.Bootloader引导
·当电源按下时,引导芯片代码从预定义的地方(固化在ROM)开始执行。Bootloader引导程序把操作系统映像文件拷贝到RAM中去,然后跳转到它的入口处去执行,启动Linux内核。
·Linux kernel 内核启动,会做设置缓存,加载驱动等一些列操作。
·当内核(Kernel)启动完成之后,在用户空间启动init进程,作为第一个系统进程, init 进程从内核态转换成用户态(init进程是Linux(|Android)系统中用户空间的第一个进程)。
2.init进程启动
·fork 出 ServerManager 子进程。 ServerManager主要用于管理我们的系统服务,他内部存在一个server服务列表,这个列表中存储的就是那些已经注册的系统服务。
·解析 init.rc 配置文件并启动 Zygote 进程。
3.Zygote进程启动
·孵化其他应用程序进程,所有的应用的进程都是由zygote进程fork出来的。 通过创建服务端Socket,等待AMS的请求来创建新的应用程序进程。
·创建SystemServer进程,在Zygote进程启动之后,会通过ZygoteInit的main方法fork出SystemServer进程
4.SystemServer进程启动
·创建SystemServiceManager,它用来对系统服务进行创建、启动和生命周期管理。
·ServerManager.startService启动各种系统服务:WMS/PMS/AMS等,调用ServerManager的addService方,将这些Service服务注册到ServerManager里面。
·启动桌面进程,这样才能让用户见到手机的界面。
5.Launcher进程启动
·开启系统Launcher程序来完成系统界面的加载与显示。

扩展:引导程序
引导程序是在Android操作系统开始运行前的一个小程序。引导程序是运行的第一个程序,因此它是针对特定的主板与芯片的。设备制造商要么使用很受欢迎的引导程序比如redboot、uboot、qi bootloader或者开发自己的引导程序,它不是Android操作系统的一部分。引导程序是OEM厂商或者运营商加锁和限制的地方。
引导程序分两个阶段执行。
第一个阶段,检测外部的RAM以及加载对第二阶段有用的程序;
第二阶段,引导程序设置网络、内存等等。这些对于运行内核是必要的,为了达到特殊的目标,引导程序可以根据配置参数或者输入数据设置内核。
Android引导程序可以在\bootable\bootloader\legacy\usbloader找到。传统的加载器包含两个文件,需要在这里说明:
init.s初始化堆栈,清零BBS段,调用main.c的_main()函数;
main.c初始化硬件(闹钟、主板、键盘、控制台),创建linux标签
扩展:内核
Android内核与桌面linux内核启动的方式差不多。内核启动时,设置缓存、被保护存储器、计划列表,加载驱动。

Init进程

init进程是Linux系统中用户空间的第一个进程,进程号固定为1。Kernel启动后,在用户空间启动init进程,并调用init中的main()方法执行init进程的职责。

init进程解析init.rc配置文件并启动zygote等Service进程:
服务Service一般运行在init的一个子进程,所以启动service前需要判断对应的可执行文件是否存在。init生成的子进程,定义在rc文件,其中每一个service在启动时会通过fork方式生成子进程。
在这里插入图片描述
当 init 子进程(Zygote)退出时,会产生 SIGCHLD 信号,并发送给 init 进程,通过 socket 套接字传递数据,调用到 wait_for_one_process()方法,根据是否是oneshot,来决定是重启子进程,还是放弃启动。由于缺省模式 oneshot=false, 因此 Zygote 一旦被杀便会再次由 init 进程拉起.接下来,便是进入了Zygote进程.
在这里插入图片描述

Runtime

Runtime 是支撑程序运行的基础库,它是与语言绑定在一起的。比如:

C Runtime:

就是C standard lib, 也就是我们常说的libc。(有意思的是, Wiki会自动将“C runtime” 重定向到 “C Standard Library”).

Java Runtime:

同样,Wiki将其重定向到” Java Virtual Machine”, 这里当然包括Java 的支撑类库 (.jar).

AndroidRuntime:

显而易见,就是为Android应用运行所需的运行时环境。这个环境包括以下东西:
1.Dalvik VM: Android的Java VM, 解释运行Dex格式Java程序。每个进程运行一个虚拟机(什么 叫运行虚拟机?说白了,就是一些C代码,不停的去解释Dex格式的二进制码(Bytecode),把它们转成机器码(Machine code),然后执行,当然,现在大多数的Java 虚拟机都支持JIT,也
就是说,bytecode可能在运行前就已经被转换成机器码,从而大大提高了性能。过去一个普遍的认识是Java 程序比C,C++等静态编译的语言慢,但随着JIT的介入和发展,这个已经完全是过去时了,JIT的动态性运行允许虚拟机根据运行时环境,优化机器码的生成,在某些情况下,Java甚至可以比C/C++跑得更快,同时又兼具平台无关的特性,这也是为什么Java如今如此流行的原因之一吧)。
2.Android的Java 类库, 大部分来自于 Apache Hamony, 开源的Java API 实现,如 java.lang, java.util, java.net. 但去除了AWT, Swing 等部件。
3.JNI: C和Java互调的接口。
4.Libc: Android也有很多C代码,自然少不了libc,注意的是,Android的libc叫 bionic C。

Zygote

Zygote概述:

所有的Java应用程序进程及系统服务SystemServer进程都由Zygote进程通过Linux的fork()函数孵化出来的,这也就是为什么把它称为Zygote的原因,因为他就像一个受精
卵,孵化出无数子进程,而native程序则由Init程序创建启动。

Zygote 进程创建Java 虚拟机,并注册JNI方法,真正成为Java进程的母体,用于孵化Java进程. 在创建完 system_server 进程后,zygote 功成身退,调用runSelectLoop(),随时待命,当接收到请求创建新进程请求时立即唤醒并执行相应工作。

Zgyote是Android中的第一个art虚拟机,他通过socket的方式与其他进程进行通信。这里的“其他进程”其实主要是系统进程——SystemServer

Zygote是一个C/S模型,Zygote进程作为服务端,它主要负责创建Java虚拟机,加载系统资源,启动SystemServer进程,以及在后续运行过程中启动普通的应用程序,其他进程作为客户端向它发出“孵化”请求,而Zygote接收到这个请求后就“孵化”出一个新的进程。比如,当点击Launcher里的应用程序图标去启动一个新的应用程序进程时,这个请求会到达框架层的核心服务ActivityManagerService中,当AMS收到这个请求后,它通过调用Process类发出一个“孵化”子进
程的Socket请求,而Zygote监听到这个请求后就立刻fork一个新的进程出来

Zygote启动过程图:

在app_main.cpp(\frameworks\base\cmds\app_process\app_main.cpp)的main函数中,主要做的事情就是参数解析. 这个函数有两种启动模式:

  1. 一种是zygote模式,也就是初始化zygote进程,传递的参数有:
    –start-system-server(表示启动SystemServer)
    –socket-name = zygote(用于指定socket的名称)
  2. 一种是application模式,也就是启动普通应用程序,传递的参数有class名字以及class带的参数。

两者最终都是调用AppRuntime对象的start函数,加载ZygoteInit或RuntimeInit两个Java类,并将之前整理的参数传入进去。

AndroidRuntime::start()if (zygote) { 
	//这些Java的应用都是通过 AppRuntime.start(className)开始的 
	//其实AppRuntime是AndroidRuntime的子类,它主要实现了几个回调函数,而start()方法是实现在AndroidRuntime这个方法类里 
	runtime.start("com.android.internal.os.ZygoteInit", args, zygote); 
} else if (className) { 
	runtime.start("com.android.internal.os.RuntimeInit", args, zygote); 
}

startVm():
通过Runtime的create方法创建单例的Runtime对象,runtime负责提供art虚拟机的运行时环境,然后调用其(Runtime对象)init方法来初始化虚拟机

start_reg():
除了系统的JNI接口(”javacore”, “nativehelper”), android framework 还有大量的Native实现, Android将所有这些接口一次性的通过start_reg()来完成。

根据不同情况调用ZygoteInit或者RuntimeInit的main函数。
在这里插入图片描述
在这里插入图片描述

  1. 解析 init.zygote.rc 中的参数,创建 AppRuntime(AppRuntime是AndroidRuntime的子类)并调用AppRuntime.start()方法;
  2. 调用 AndroidRuntime 的 startVM()方法创建虚拟机,再调用 startReg()注册 JNI 函数;
  3. 通过 JNI 方式调用 ZygoteInit.main(),第一次进入 Java 世界;
  4. registerZygoteSocket()建立 socket 通道,zygote 作为通信的服务端,用于响应客户端请求;
  5. preload()预加载通用类、drawable 和 color 资源、openGL 以及共享库以及 WebView,用于提高 app 启动效率;
  6. zygote 完毕大部分工作,接下来再通过 startSystemServer(),fork 得力帮手 system_server 进程,也是上层 framework 的运行载体(ZygoteInit.forkSystemServer())。
  7. zygote 功成身退,调用 runSelectLoop(),随时待命,当接收到请求创建新进程请求时立即唤醒并执行相应工作。

其中ZygotInit.preload()

static void preload() { 
	Log.d(TAG, "begin preload"); 
	preloadClasses(); 
	preloadResources(); 
	preloadOpenGL(); 
	preloadSharedLibraries(); 
	WebViewFactory.prepareWebViewInZygote(); 
	Log.d(TAG, "end preload"); 
}

preload() 的作用就是提前将需要的资源加载到VM中,比如class、resource、openGL、字体等 。
preloadClassess 将framework.jar里的preloaded-classes 定义的所有class load到内存里,
preloaded-classes 编译Android后可以在framework/base下找到。而preloadResources 将系统的Resource(不是在用户apk里定义的resource)load到内存。资源preload到Zygoted的进程地址空间,所有fork的子进程将共享这份空间而无需重新load, 这大大减少了应用程序的启动时间,但反过来增加了系统的启动时间。通过对preload 类和资源数目进行调整可以加快系统启动。Preload也是Android启动最耗时的部分之一。

zygote 进程内加载了 preload()方法中的所有资源,当需要 fork 新进程时,采用copy on write 技术,如下:
在这里插入图片描述

System Server

System Server 是Zygote fork 的第一个Java 进程,进程名为system_server, 这个进程非常重要,因为他们有很多的系统线程,承载着framework的核心服务。
看到大名鼎鼎的WindowManager, ActivityManager了吗?对了,它们都是运行在system_server的进程里。还有很多“Binder-x”的线程,它们是各个Service为了响应应用程序远程调用请求而创建的。除此之外,还有很多内部的线程,比如 ”UI thread”, “InputReader”, “InputDispatch” 等等。
System_server 主线程的启动工作完成后, 进入 Looper.loop()状态,等待其他线程通过 handler 发送消息到主线再处理.

System Server启动流程:

Zygote 启动过程中会调用startSystemServer(),可知startSystemServer()函数是 system_server启动流程的起点,启动流程图如下:
在这里插入图片描述

上图前4步骤(即颜色为紫色的流程)运行在是Zygote 进程,从第5步(即颜色为蓝色的流程)ZygoteInit.handleSystemServerProcess 开始是运行在新创建 的 system_server,这是fork机制实现的。

SystemServer.main(){
	SystemServer.run(){
		//清除 vm 内存增长上限,由于启动过程需要较多的虚拟机内存空间 	
		VMRuntime.getRuntime().clearGrowthLimit();
		
		// 主线程 looper 就在当前线程运行
		Looper.prepareMainLooper();
		
		//初始化系统上下文
		createSystemContext();
		
		//创建系统服务管理 
		mSystemServiceManager = new SystemServiceManager(mSystemContext); 
		//将 mSystemServiceManager 添加到本地服务的成员 sLocalServiceObjects 
		LocalServices.addService(SystemServiceManager.class, mSystemServiceManage r);
		
		//启动各种系统服务
		startBootstrapServices(); //启动引导服务
		startCoreServices(); //启动核心服务
		startOtherServices(); //启动其他服务
		
		//一直循环执行
		Looper.loop();
	}
}

初始化必要的SystemServer环境参数:
比如系统时间、默认时区、语言、load一些Library等等。

初始化Looper
我们在主线程中使用到的looper就是在SystemServer中进行初始化的。

初始化系统上下文
初始化Context,只有初始化一个Context才能进行启动Service等操作。
createSystemContext()过程会创建对象有 ActivityThread,Instrumentation, ContextImpl,LoadedApk,Application。
ContextImpl是Context类的具体实现,里面封装了生成几种常用的createContext的方法:

createSystemContext() / createSystemUiContext() / createAppContext() / createActivityContext()

初始化SystemServiceManager
初始化SystemServiceManager,用来管理启动service,SystemServiceManager中封装了启动Service的startService方法启动系统必要的Service(ActivityManagerService等等)。

startBootstrapServices():
该方法所创建的服务:ActivityManagerService, PowerManagerService, LightsService, DisplayManagerService,PackageManagerService,UserManagerService,sensor 服务.
startCoreServices():
启动服务 BatteryService,UsageStatsService,WebViewUpdateService。

ServiceManager

ServiceManager 是由 init 进程通过解析 init.rc 文件而创建的。

ServiceManager 是 Binder IPC 通信过程中的守护进程,本身也是一个 Binder 服务,但并没有采用 libbinder 中的多线程模型来与 Binder 驱动通信,而是自行编写了 binder.c 直接和 Binder驱动来通信,并且只有一个循环 binder_loop 来 进行读取和处理事务,这样的好处是简单而高效。

ServiceManager 本身工作相对简单,其功能:查询和注册服务。对于 Binder IPC 通信过程中,其实更多的情形是 BpBinder 和 BBinder之间的通信,比如 ActivityManagerProxy 和ActivityManagerService 之间的通信等。

总结:

  1. init 根据init.rc 运行 app_process, 并携带‘–zygote’ 和 ’–startSystemServer’ 参数。
  2. AndroidRuntime.cpp::start() 里将启动JavaVM,并且注册所有framework相关的系统JNI接口。
  3. 第一次进入Java世界,运行ZygoteInit.java::main() 函数初始化Zygote. Zygote 并创建Socket的server 端。
  4. 然后fork一个新的进程并在新进程里初始化SystemServer。Fork之前,Zygote是preload常用的Java类库,以及系统的resources,同时GC()清理内存空间,为子进程省去重复的工作。
  5. SystemServer 里将所有的系统Service初始化,包括ActivityManager 和 WindowManager, 他们是应用程序运行起来的前提。
  6. 依次同时,Zygote监听服务端Socket,等待新的应用启动请求。
  7. ActivityManager ready 之后寻找系统的“Startup” Application, 将请求发给Zygote。
  8. Zygote收到请求后,fork出一个新的进程。
  9. Zygote监听并处理SystemServer 的 SIGCHID 信号,一旦System Server崩溃,立即将自己杀死。init会重启Zygote.

面试题

面试官:你了解 Android 系统启动流程吗?
A:当按电源键触发开机,首先会从 ROM 中预定义的地方加载引导程序 BootLoader 到 RAM 中,并执行 BootLoader 程序启动 Linux Kernel, 然后启动用户级别的第一个进程: init 进程。init 进程会解析init.rc 脚本做一些初始化工作,包括挂载文件系统、创建工作目录以及启动系统服务进程等,其中系统服务进程包括 Zygote、service manager、media 等。在 Zygote 中会进一步去启动 system_server 进程,然后在 system_server 进程中会启动 AMS、WMS、PMS 等服务,等这些服务启动之后,AMS 中就会打开 Launcher 应用的 home Activity,最终就看到了手机的 “桌面”。

面试官:system_server 为什么要在 Zygote 中启动,而不是由 init 直接启动呢?
A:Zygote 作为一个孵化器,可以提前加载一些资源,这样 fork() 时基于 Copy-On-Write 机制创建的其他进程就能直接使用这些资源,而不用重新加载。比如 system_server 就可以直接使用 Zygote 中的 JNI函数、共享库、常用的类、以及主题资源。

面试官:为什么要专门使用 Zygote 进程去孵化应用进程,而不是让 system_server 去孵化呢?
A:首先 system_server 相比 Zygote 多运行了 AMS、WMS 等服务,这些对一个应用程序来说是不需要的。另外进程的 fork() 对多线程不友好,仅会将发起调用的线程拷贝到子进程,这可能会导致死锁,而system_server 中肯定是有很多线程的。

Activity启动流程

在这里插入图片描述

启动流程:

  1. 点击桌面App图标,Launcher进程采用Binder IPC向system_server进程发起startActivity请求;
  2. system_server进程接收到请求后,向zygote进程发送创建进程的请求;
  3. Zygote进程fork出新的子进程,即App进程;
  4. App进程,通过Binder IPC向sytem_server进程发起attachApplication请求;
  5. system_server进程在收到请求后,进行一系列准备工作后,再通过binder IPC向App进程发送scheduleLaunchActivity请求;
  6. App进程的binder线程(ApplicationThread)在收到请求后,通过handler向主线程发送LAUNCH_ACTIVITY消息;
  7. 主线程在收到Message后,通过发射机制创建目标Activity,并回调Activity.onCreate()等方法。

到此,App便正式启动,开始进入Activity生命周期,执行完onCreate/onStart/onResume方法,UI渲染结束后便可以看到App的主界面。

Binder

Android 系统中,每个应用程序是由 Android 的 Activity,Service,Broadcast,ContentProvider 这四剑客的中一个或多个组合而成,这四剑客所涉及的多进程间的通信底层都是依赖于 Binder IPC 机制。例如当进程 A 中的 Activity 要向进程 B 中的 Service 通信,这便需要依赖于 Binder IPC。不仅于此,整个 Android系统架构中,大量采用了 Binder 机制作为 IPC(进程间通信)方案,当然也存在部分其他的 IPC 方式,比如 Zygote 通信便是采用 socket。

Binder本质上只是一种底层通信方式,为了提供具体服务,Server必须提供一套接口函数以便Client通过远程访问使用各种服务。这时通常采用Proxy设计模式:将接口函数定义在一个抽象类中,Server和Client都会以该抽象类为基类实现所有接口函数,所不同的是Server端是真正的功能实现,而Client端是对这些函数远程调用请求的包装。

IBinder :跨进程通信的Base接口,它声明了跨进程通信需要实现的一系列抽象方法,实现了这个接口就说明可以进行跨进程通信,所有的Binder实体都必须实现IBinder接口。
IInterface :这也是一个Base接口,用来表示Server提供了哪些能力,是Client和Server通信的协议,Client和Server都要实现此接口。
Binder : IBinder的子类, Java层提供服务的Server进程持有一个Binder对象从而完成跨进程间通信。
BinderProxy :在Binder.java这个文件中还定义了一个BinderProxy类,这个类表示Binder代理对象它同样实现了IBinder接口。Client中拿到的实际上是这个代理对象。

binder原理

Binder 通信采用 C/S 架构,从组件视角来说,包含 Client、Server、 ServiceManager 以及 binder 驱动,其中 ServiceManager 用于管理系统中的各种服务。架构图如下所示:
在这里插入图片描述

可以看出无论是注册服务和获取服务的过程都需要 ServiceManager,需要注意的是此处的Service Manager 是指 Native 层的 ServiceManager(C++),并非 指 framework 层的ServiceManager(Java)。ServiceManager是整个Binder通信机制的大管家,是 Android 进程间通信机制 Binder 的守护进程。当 Service Manager 启动之后,Client 端和 Server 端通信时都需要先获取Service Manager 接口,才能开始通信服务

1.注册服务 (addService) : Server进程要先注册 Service 到 ServiceManager。该过程:Server 是客户端,ServiceManager是服务端。
2.获取服务(getService) :Client 进程使用某个Service前,须先向ServiceManager中获取相应的 Service。该过程:Client是客户端,ServiceManager 是服务端。
3.使用服务:Client 根据得到的Service信息建立与Service所在的Server进程通信的通路,然后就可以直接与Service交互。该过程:client是客户端,server是服务端。

图中的 Client,Server,Service Manager 之间交互都是虚线表示,是由于它们彼此之间不是直接交互的,而是都通过与 Binder 驱动进行交互的,从而实现 IPC 通信方式。其中 Binder 驱动位于内核空间,Client,Server,Service Manager 位于用户空间。Binder 驱动和 Service Manager可以看做是 Android平台的基础 架构,而 Client 和 Server 是 Android 的应用层,开发人员只需自定义实现 client、Server 端,借助 Android 的基本平台架构便可以直接进行 IPC 通信。

C/S模式

BpBinder(客户端)和 BBinder(服务端)都是Android 中 Binder 通信相关的代表,它们都从IBinder 类中派生而来, 关系图如下:
在这里插入图片描述

•client 端: BpBinder.transact()来发送事务请求;
•server 端: BBinder.onTransact()会接收到相应事务。

AMS

ActivityManagerService和PackageManagerService、WindowManagerService等等,这些基础的
系统服务是被所有的App公用的,当某个App想实现某个操作的时候,要告诉这些系统服务,比如你想打开一个App,那么我们知道了包名和MainActivity类名之后就可以打开。
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
ComponentName cn = new ComponentName(packageName, className);
intent.setComponent(cn);
startActivity(intent);
但是,我们的App通过调用startActivity()并不能直接打开另外一个App ,这个方法会通过一系列的调用,最后还是告诉AMS说: “我要打开这个App ,我知道他的住址和名字,你帮我打开吧! ”所以是AMS来通知zygote进程来fork一个新进程,来开启我们的目标App的。这就像是浏览器想要打开一个超链接一样,浏览器把网页地址发送给服务器,然后还是服务器把需要的资源文件发送给客户端的。

问:App和AMS(SystemServer进程)还有zygote进程分属于三个独立的进程,他们之间如何通信呢?
答:App与AMS通过Binder进行IPC通信, AMS(SystemServer进程)与zygote 通过Socket进行IPC通信。
问:AMS作用?
答:如果想打开一个App的话,需要AMS去通知zygote进程,除此之外,其实所有的Activity的开启、暂停、关闭都需要AMS来控制,所以我们说, AMS负责系统中所有Activity 的生命周期。

在Android系统中,任何一个Activity的启动都是由AMS和应用程序进程(主要是ActivityThread)相互配合来完成的。 AMS服务统一调度系统中所有进程的Activity启动,而每个Activity的启动过程则由其所属的进程具体来完成。

客户端:ActivityManagerProxy =>Binder驱动=> 服务器:ActivityManagerService
在这里插入图片描述

在调用startActivity()的时候,实际上调用的是mInstrumentation.execStartActivity(),里面又调用了ActivityManagerNative.getDefault().startActivity方法。getDefault()返回ActivityManagerService的远程接口,即ActivityManagerProxy。
ActivityManagerProxy.startActivity(),在这里面做的事情就是IPC通信,利用Binder对象,调用transact(),把所有需要的参数封装成Parcel对象,向AMS发送数据进行通信。

class ActivityManagerProxy implements IActivityManager{}//IActivityManager继承了Interface接口,ActivityManagerProxy代理类是ActivityManagerNative的内部类
public abstract class ActivityManagerNative extends Binder implements IActivityManager{}
public final class ActivityManagerService extends ActivityManagerNative{}

ActivityManagerServices和ActivityManagerProxy都实现了同一个接口——IActivityManager。虽然都实现了同一个接口,但是代理对象ActivityManagerProxy并不会对这些方法进行真正地实现,ActivityManagerProxy只是通过这种方式对方法的参数进行打包(因为都实现了相同接口,所以可以保证同一个方法有相同的参数,即对要传输给服务器的数据进行打包),真正实现的是ActivityManagerService。
但是这个地方并不是直接由客户端传递给服务器,而是通过Binder驱动进行中转。客户端调用ActivityManagerProxy接口里面的方法,把数据传送给Binder驱动,然后Binder驱动就会把这些东西转发给服务器的ActivityManagerServices,由ActivityManagerServices去真正的实施具体的操作。
而且由于继承了同样的公共接口类,ActivityManagerProxy提供了与ActivityManagerService一样的函数原型,使用户感觉不出Server是运行在本地还是远端,从而可以更加方便的调用这些重要的系统服务。

但是!这里Binder通信是单方向的,即从ActivityManagerProxy指向ActivityManagerService的,如果AMS想要通知ActivityThread做一些事情,应该咋办呢?
还是通过Binder通信,不过是换了另外一对,换成了ApplicationThread和ApplicationThreadProxy。

客户端:ApplicationThread <=Binder驱动<= 服务器:ApplicationThreadProxy

private class ApplicationThread extends ApplicationThreadNative {}
public abstract class ApplicationThreadNative extends Binder implements IApplicationThread{}
class ApplicationThreadProxy implements IApplicationThread {}

ActivityManager

ActivityManager官方介绍:是与系统所有正在运行着的Acitivity进行交互,对系统所有运行中的Activity相关信息(Task,Memory,Service,App)进行管理和维护。
ActivityManager持有的是ActivityManagerPorxy代理对象,这样,只需要操作这个代理对象就能操作其业务实现的方法。那么真正实现其也业务的则是ActivityManagerService。

Instrumentation

Instrumentation是什么?和ActivityThread是什么关系?
每个Activity都持有Instrumentation对象的一个引用,但是整个进程只会存在一个
Instrumentation对象。当startActivityForResult()调用之后,实际上还是调用了mInstrumentation.execStartActivity()。所以当我们在程序中调用startActivity()的 时候,实际上调用的是Instrumentation的相关的方法。

Instrumentation意为“仪器”,这个类里面的方法大多数和Application和Activity有关,是的,这个类就是完成对Application和Activity初始化和生命周期的工具类。

Instrumentation这个类很重要,对Activity生命周期方法的调用根本就离不开他,他可以说是一个大管家,但是,这个大管家比较害羞,是一个女的,管内不管外,是老板娘~
那么你可能要问了,老板是谁呀?
老板当然是大名鼎鼎的ActivityThread了!
ActivityThread是UI线程。App和AMS是通过Binder传递信息的,那么ActivityThread就是专门与AMS的外交工作的。

AMS说:“ActivityThread,你给我暂停一个Activity!”
ActivityThread就说:“没问题!”然后转身和Instrumentation说:“老婆,AMS让暂停一个Activity,我这里忙着呢,你快去帮我把这事办了把~”
于是,Instrumentation就去把事儿搞定了。

所以说,AMS是董事会,负责指挥和调度的,ActivityThread是老板,虽然说家里的事自己说了算,但是需要听从AMS的指挥,而Instrumentation则是老板娘,负责家里的大事小事,但是一般不抛头露面,听一家之主ActivityThread的安排。

WMS 概述

WMS 是系统的其他服务,无论对于应用开发还是 Framework 开发都是重点的知识,它的职责有很多,主要有以下几点:
窗口管理
WMS 是窗口的管理者,它负责窗口的启动、添加和删除,另外窗口的大小和层级也是由WMS 进行管理的。窗口管理的核心成员有 DisplayContent、WindowToken和WindowState。
窗口动画
窗口间进行切换时,使用窗口动画可以显得更炫一些,窗口动画由 WMS 的动画子系统来负责,动画子系统的管理者为 WindowAnimator。
输入系统的中转站
通过对窗口的触摸从而产生触摸事件,InputManagerService(IMS)会对触摸事件进行处理,它会寻找一个最合适的窗口来处理触摸反馈信息,WMS 是窗口的管理者,因此,WMS“理所应当”的成为了输入系统的中转站。
Surface 管理
窗口并不具备有绘制的功能,因此每个窗口都需要有一块 Surface 来供自己绘制。为每个窗口分配 Surface 是由 WMS 来完成的。WMS 的职责可以简单总结为下图。
在这里插入图片描述

Activity 、Window、View关系

Activity是系统可视化交互组件,四大组件都由AMS统一管理生命周期,事实上它的职责只是生命周期的管理,由设计模式的单一职责的原则,那势必需要将Activity和其上的视图View进行解耦,那么就引入Window的概念,它是个抽象类,对于Activity来说,它的具体实现类是PhoneWindow,在Activity执行attach的时候,会创建一个PhoneWindow对象。PhoneWindow作为装载根视图DecorView的顶级容器,Activity通过setContentView实际上是调用PhoneWindow来创建DecorView,并解析xml布局加载到DecorView的contentView部分。
在这里插入图片描述

WindowManager

在这里插入图片描述

(注意mView和DecoView是同级关系,由不同ViewRootImpl控制,不在同一个View链上,之间没有联系。这个类似于PopupWindow。)

对于我们的View来说,很大程度上和Activity是没有关系的,全依赖于Window/WindowManager去管理。
WindowManager是对悬浮窗进行操作的一个媒介。
WindowManager(具体实现类是 WindowManagerImpl,对比Context和ContextImpl)是一个接口,他是继承了ViewManager接口中的三个方法:

public interface ViewManager {
	//增
	public void addView(View view, ViewGroup.LayoutParams params);
	//删
    public void removeView(View view);
	//改
	public void updateViewLayout(View view, ViewGroup.LayoutParams params);
}

WindowManager 用来管理 Window,而 WindowManager 所提供的功能最终会通过Binder调用到 WMS 来进行处理。
WindowManagerImpl为WindowManager的实现类。WindowManagerImpl内部方法实现都是由代理类WindowManagerGlobal完成,而WindowManagerGlobal是一个单例,也就是一个进程中只有一个WindowManagerGlobal对象服务于所有页面的View。

ViewRootImpl

Activity中有Window对象,一个Window对象对应着一个View(DecorView),ViewRootImpl就是对这个View进行操作的。
举例View的测量:
ViewRootImpl调用performMeasure执行Window对应的View的测量。
ViewRootImpl的performMeasure;
DecorView(FrameLayout)的measure;
DecorView(FrameLayout)的onMeasure;
DecorView(FrameLayout)所有子View的measure。

ViewRootImpl 身负了很多职责:implementing the needed protocol between View* and the WindowManager
• View 树的根并管理 View 树
• 触发 View 的测量、布局和绘制(View.requestLayout() -> ViewRootImpl.requestLayout() -> ViewRootImpl.performTraversals())
• 输入事件的中转站
• 管理 Surface
• 负责与 WMS 进行进程间通信
在android中,无论我们的app界面,还是系统桌面,再或者是手机下方的几个虚拟按键和最上方的状态栏,又或者是一个吐司。。。我们所看到的所有界面,都是由一个个悬浮窗口组成的。对于我们普通的Activity来说是需要管理View的,而对于系统级别来说也需要管理View。如果让你去设计,你会做俩套独立的方案吗?很明显不会,既然都是管理View那就搞一套好了,这也就是ViewRootImpl存在的意义(ViewRootImpl就是这套管理方案)。

ViewRootImpl是个ViewParent,在DecoView添加的View时,就会将View中的ViewParent设为DecoView所在的ViewRootImpl,View的ViewParent相同时,理解为这些View在一个View链上。所以每当调用View的requestLayout()时,其实是调用到ViewRootImpl,ViewRootImpl会控制整个事件的流程。可以看出一个ViewRootImpl对添加到DecoView的所有View进行事件管理。
当我们调用View的requestLayout()这个方法时,调用的仅仅是View中的public的同名方法,并且此方法中会调用ViewParent中的requestLayout()。而ViewParent中requestLayout()的实现是在ViewRootImpl中,又因为ViewRootImpl通过ViewParent将所有的View串了起来,因此ViewRootImpl通过这条链便可以完成所有View从底到上的request。
而我们setContentView的内容,会被包成DecorView,然后通过WindowManager绑到对应的ViewRootImpl上。因此我们的布局,也和整体的View绘制流程绑在一起。
ViewRootImpl是实际管理Window中所以View的类,每个Activity中ViewRootImpl数量取决于调用mWindowManager.addView的调用次数。

添加一个悬浮窗:

WindowManager windowManager = getWindowManager();
windowManager.addView(.....);

在addView之后,通过WindowManagerGlobal进行一些相关配置,传入ViewRootImpl,再通过aidl方式发送给WMS系统服务。

创建时机:
Activity创建的时候会走到WindowManagerGlobal的addView方法,这里面会创建一个ViewRootImpl对象(用于构造ViewRootImpl的参数view是一个DecorView对象)。
在这里插入图片描述

Window分类

window有三种类型,应用window、子window、系统window。应用window对应activity;子window要依附在父window上,如dialog;系统window需要申明权限才能创建,比如toast、系统状态栏。
window是分层的,每个window都有对应的z-ordered,层级大的在层级小的上层。应用window的层级范围是1-99,子window是1000-1999,系统window是2000-2999,即type的值。如果想window位于所有window顶层,那就用系统window。

windowToken

Activity的token,Window中的token,连传入addWindow的attrs.token,都是同一个token,都是ActivityRecord构造函数中创建的Token对象。这样做保证了一致性,主要体现在如下两点:
将AMS中创建的ActivityRecord和Window挂钩,当前的window明确知道自己是哪一个Activity创建的。
Window和AMS有联系,同时又和WMS有关系,appToken则保证了这种同步机制。
Activity提供与AMS通信的Token(IBinder对象),创建Window为View提供显示的地方,而具体的View管理任务由ViewRootImpl来完成。
Window.addView时,需要这个mToken(IBinder对象, WMS就是通过这个IBinder来管理Activity里的View。),而Application 和 Service传入的情况下Token是null。

参考文章

本文大部分内容都来自pdf和bolg的拷贝,目的是为了复习的时候不用各处文章翻找。如有雷同,纯属抄袭。。。

《Android Framework精编内核解析(1)(1).pdf》
《2021年度大厂Android高级开发面试题以及完整答案整理.pdf》
《2022最新Android中高级面试题合集.pdf》
https://developer.android.google.cn/guide/platform?hl=zh-cn
ActivityManager的代理模式 - mingfeng002 - 博客园 (cnblogs.com)
【凯子哥带你学Framework】Activity启动过程全解析_赵凯强的博客-CSDN博客
startActivity启动过程分析 - Gityuan博客 | 袁辉辉的技术博客
面试必备:Android(9.0)Activity启动流程(一) - 掘金 (juejin.cn)
WindowManager与WMS浅析_Zy_JiBai的博客-CSDN博客
Android视图框架Activity,Window,View,ViewRootImpl理解 - 简书 (jianshu.com)
WindowManager - 简书 (jianshu.com)
Android WMS(一)-窗口管理 - 简书 (jianshu.com)
Android进阶基础系列:Window和WindowManager ,全面理解! - 掘金 (juejin.cn)
ViewRootImpl的独白,我不是一个View(布局篇)_静默加载的博客-CSDN博客_viewrootimpl

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值