要理解Android系统服务提供的服务的运行逻辑,必须要首先充分了解Binder提供的支持,以及对C/C++有一定的熟悉程度。一旦理解了Binder并且能够熟练阅读C++代码,阅读系统服务源码就和阅读普通应用代码一样,能够梳理出一套清晰的脉络,否则读系统源码时就会举步维艰。
在目前的Android系统中,SurfaceFlinger和其他常见系统服务没有运行在同一个进程,SurfaceFlinger运行在单独的surfaceflinger进程内,其他系统服务运行在system_server进程内。
也就是说,在研究窗口相关的逻辑时,要明确这里面至少涉及了三个进程:App进程、system_server进程(包含AMS和WMS)、SurfaceFlinger进程。
之前记录Android笔记时记录过Activity启动过程中和Window有关的时序:https://www.yuque.com/gaolf/ipvf6y/mozgw7
应用侧
对象间关系整理
aidl接口定义:
搜索framework中的java源码时,部分接口定义Java源文件是搜索不到的,因为它们实际上是通过aidl动态生成的,和窗口系统相关的几个aidl定义如下:
IWindowManager aidl接口定义:http://aosp.opersys.com/xref/android-10.0.0_r47/xref/frameworks/base/core/java/android/view/IWindowManager.aidl
IWindowSession aidl接口定义:http://aosp.opersys.com/xref/android-10.0.0_r47/xref/frameworks/base/core/java/android/view/IWindowSession.aidl
**
窗口创建逻辑
创建用于和WMS通信的Session:
在ViewRootImpl的构造方法中,通过WindowManagerService#openSession获取到了IWindowSession,后续通过这个Session和WindowManagerService通信,当调用Session的方法时,Session会将自己(this)作为参数调用WMS,这样WMS就知道是哪个客户端在调用自己了;
Session构造时,传入了由应用进程传来的IMM相关对象和一个IWindowSessionCallback回调对象,它们都是Binder,可以利用它们来回调应用进程。
创建应用端的IWindow Binder Stub:
在ViewRootImpl的构造方法中,创建了IWindow Bidner的Stub对象:mWindow = new W(this),这个对象在ViewRootImpl#setView被调用,即应用设置decor view时,通过IWindowSession#addToDisplay方法被传递给WMS,WMS用它来回调应用进程。
此外,在addToDisplay方法中,WMS创建了一系列数据结构,包括:WindowState、WindowToken,
准备应用绘制的画布:准备Surface
在ViewRootImpl初始化时,Surface类型的mSurface属性已经被赋值为通过new Surface()创建出来的空Surface对象。这个Surface对象是一个Parcelable对象,能够在进程间传递,其中最重要的属性是mNativeObject属性,这个属性代表一个WMS所处进程内的C层对象的指针地址。
在ViewRootImpl#relayoutWindow方法中,调用了IWindowSession#relayout方法,这里传入了mSurface属性作为参数,回过头看看IWindowSession的aidl定义,可以看到surface参数是由out来修饰的,这表示WMS进程对surface对象的任何修改都会经过Parcel序列化反映到这个对象上,应用进程可以拿到被修改后的surface对象,这个对象里的mNativeObject实际上指向的是cpp层的android::Surface对象。
至此,应用已经拿到了就绪的Surface,可以使用OpenGL API或者Canvas API在Surface上进行绘制了。
ViewRootImpl在拿到Surface后,会遍历当前窗口的View Tree,对整个Tree进行measure、layout、draw,最终将收集到的绘制指令收集下来,翻译成OpenGL指令(HWUI渲染模式下)绘制到Surface上。
SurfaceFlinger侧
SurfaceFlinger侧的逻辑不太好理解,因为涉及到了hal接口,到了这一层就是每个OEM来自行实现了,SurfaceFlinger、图形相关hal、OpenGL ES三者配合提供图形服务。在AOSP代码里没有找到hal实现源码,不知道是的确没有,还是我没找对地方。因此,下面的内容是我查阅资料后总结的,并不一定准确。
大体来说,Gralloc负责创建窗口缓冲区,OpenGL ES则负责向窗口缓冲区输出渲染结果,以及将渲染好的缓冲区提交给SurfaceFlinger,SurfaceFlinger再利用Gralloc和HWC将绘制好的内容显示到屏幕上。
Gralloc
Gralloc负责分配图形缓冲区,将分配好的缓冲区通过一个句柄表示(native_handle_t,或者它的别名buffer_handle_t),这个句柄可以通过binder机制传递到不同的进程,不同的进程利用该句柄可以写同一片缓冲区。
在向Gralloc请求创建图形缓冲区时,要给Gralloc传递一个表示缓冲区用途的标记,如果标记表明缓冲区是用CPU渲染的,那么Gralloc会确保将缓冲区分配到普通内存区域中,这样CPU才能够直接访问缓冲区;如果缓冲区是用GPU渲染的,Gralloc就可以将缓冲区分配到framebuffer内存区域中,这种缓冲区只有通过OEM提供的图形驱动,如OpenGL ES、Valkan、Camera等才能够访问。
OpenGL ES
OpenGL ES在初始化Context时要求提供一个本地窗口句柄,所谓的本地窗口句柄其实是Surface,OpenGL ES拿到Surface后利用Surface向SurfaceFlinger请求缓冲区句柄,将渲染结果输出到缓冲区句柄对应的缓冲区中。