IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android/Activity启动流程相关知识点串通 -> 正文阅读

[移动开发]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》
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

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-06-23 00:58:02  更:2022-06-23 00:58:41 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 2:30:44-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码