梳理流程和图形参考Stan_Z的博客:
Android图形系统篇总结:https://www.jianshu.com/p/180e1b6d0dcd
Android 系统显示原理简介:https://www.jianshu.com/p/a978a6250f9e
一、Android显示系统整体框架介绍
1.1 显示系统关键组件:Activity、window、view、surface、canvas、surfaceflinger、layer、Choreographer、Vsync
- Activity:是APP与用户进行交互的入口,一个Activity对应着一个窗口(window),完成用户的key、touch事件的相应处理和对window生命周期进行管理。
- Window:window是视图(view)的容器,Window有唯一的实现类:PhoneWindow。Window受WindowManager统一管理,对window管理通过WindowWtate,该变量是系统对Window管理的一个封装类,与window一一对应。
- view:视图,承载着将要显示的内容,其中DecorView(顶级视图)是当前Activity的根View,它里面管理着当前界面的View树,包含着标题栏titleBar和内容栏contentView。
- surface:每个Window对应一个surface,作为View显示的载体,图形的传递通过buffer作为载体,因此surface是对buffer的封装,对图形的操作其实就是对suface中buffer的操作。
- canvas:画布,任何的view都需要画在surface的canvas上。
- SurfaceFlinger:作为一个service,接收所有的surface作为输入,创建layer,把不同的layer进行裁剪等合成操作来显示。
- layer:由surfaceFlinger进行创建,是surfaceFlinger进行合成的基本单位(一个surface对应一个layer),layer其实是一个FrameBuffer(帧buffer),每个FrameBuffer中有两个GraphicBuffer(图形buffer,因为Android为了将系统操作buffer和硬件显示buffer分开,所以设置了两个buffer),记为FrontBuffer和BackBuffer。
从图中可以看出,最终显示在屏幕上的内容由多个surface(layer)通过SurfaceFlinger进行合成,surface上中不同的view都画在surface的canvas上。
- choreographer:处于上层,接收VSync信号,同Vsync配合,统一Android显示中的动画、输入和绘制时机。
- Vsync:让CPU、GPU和Buffer进行同步的一个信号。
1.2 显示流程概述:
将前面内容进行串联,Android应用程序的显示过程包含了两个部分(应用侧绘制、系统侧渲染)、两个机制(进程间通讯机制、显示刷新机制)。
应用层负责绘制(UI的测量、布局,即显示View的类型和Window对View的布局),系统层负责渲染(SurfaceFlinger对layer的合成和屏幕上的显示);
通过进程间通信(binder)把应用层需要绘制的数据传递给系统层服务,系统层服务通过刷新机制(Vsync、choreography)把数据更新到屏幕上。
显示流程具体细节:
- Android启动后,在init.rc解析时创建SurfaceFlinger实例并向serviceManager注册,启动SurfaceFlinger服务。
- Activity在启动过程中会创建PhoneWindow并且与之建立回调关系(用于接收touch等消息);在PhoneWindow中创建顶级视图DecorView。
- Activity调用函数setView(),里面有两个重要的函数:
requestlayout()
和mWindowSession.addtoDisplay()
。后者完成view的添加、app与surfaceFlinger的服务的连接;前者完成了view的绘制、view画在surface的canvas上并把surface传入SurfaceFlinger。 - SurfaceFlinger创建layer并将传入的Surface进行合成,最后将合成后的数据通过
SurfaceFlinger::postComposition()
函数画在屏幕上。 - 为了让CPU/GPU的合成帧率和Display的刷新率同步,使用了Choreographer,接收Vsync信号,让底层与上层进行同步。
二、Activity创建Window和加载view过程
解决问题:1. Window创建和建立回调过程;2. View是如何加载到Window中的
2.0 Activity的启动
Activity启动流程参考:一篇文章看明白 Android 从点击应用图标到界面显示的过程
在Android启动后,点击app图标,Launcher进程(就是一个Activity)通过Binder向系统服务(systemserver)ActivityManagerService(AMS)发起startActivity()请求;
PS:Launcher通过PMS来解析AM.xml配置文件得到组件信息,系统启动后就会启动Launcher组件,启动后向PMS查询所有Action名称和Category,为每个Acitivity组件创建快捷图标,方便下面点击启动。
AMS收到请求后向zygote进程发送创建进程请求并fork一个新的子进程(app进程);进入 app 进程后创建 ActivityThread 类并加载,并调用 ActivityThread.main() 方法。
ActivityThread.main()通过Binder向AMS发起attachApplication请求对app进行一些初始化;AMS经过一系列准备后向App进程发送scheduleLaunchActivity请求,app进程的binder线程(ApplicationThread)收到请求后通过由bindapplication()封装一些重要的信息,如appinfo、config等handler消息并向主线程发送LAUNCH_ACTIVITY消息;
主线程收到启动activity消息后,执行handleLaunchActivity()方法,通过Instrumentation()(Intrumentation:用来监控app和系统之间的交互操作。)创建Activity,然后调用Activity.attact().onCreate()方法进入Activity生命周期。
2.1 window的创建 、View创建和添加
Activity启动时会创建Window,从上面可以看出,Activity启动过程中有重要的函数ActivityThread.handleLaunchActivity()
,该函数中有三个重要的函数调用:
handlelaunchactivity()
{
...
windowManagerGlobal.initialize() //获得 WMS的Binder引用
performLaunchActivity() //创建要启动的Activity组件,创建窗口对象和视图对象
handleResumeActivity() //将Activity组件进行激活
...
}
第二个函数performLaunchActivity()
完成了PhoneWindow和View的创建,第三个函数handleResumeActivity()
负责将组件进行激活。
看一下window创建函数performLaunchActivity()
performlaunchActivity()
{
Activity activity = null;
//创建目标Activity对象和app对象
activity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent);
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
activity.attach(...)
//回调 Activity.onCreate(),onCreate()里面有setContentView(),我们自己设计的UI界面
mInstrumentation.callActivityOnCreate(activity, ...);
}
attach(...)
{
mWindow = new phoneWindow() //创建Window,PhoneWindow是Window的唯一具体实现类
//设置回调函数,实现了Window的callback接口,这样Activity就与Window关联起来
mWindow.setCallback(this)
//初始化并且设置WindowManager,获取WindowManagerImpl对象。每一个activity都有一个WM对象。
//mToken是IBinder类型,WMS就是通过这个 IBinder 来管理 Activity 里的 View
mwindow.setWindowManager(...,mToken,...)
//mWindowManager与WMS进行通信,也是WMS识别View属于哪个Activity的关键
mWindowManager = mWindow.getWindowManager()
}
在performLaunchActivity().attach()
中创建了一个PhoneWindow对象,实现了Window的创建和与Activity的关联,并且创建了WindowManager(WindowManager 是一个抽象类,具体实现是在 WindowManagerImpl 中).由前面已知Window是View的载体,Window将view添加到WMS过程就是由WindowManager实现的。
回调 Activity.onCreate() 后,会执行 setContentView() 方法将我们写的 Layout 布局页面设置给 Activity,即加载顶级视图DecorView。
//Activity.java
public void setContentView()
{
getWindow().setContentView(layoutResID); //window的一个抽象方法 ,实现类是PhoneWindow
initWindowDecorActionBar();
}
// PhoneWindow
public void setContentView(int layoutResID)
{
...
installDecor(); //初始化Decor,将mContentParent关联到DecorView上
mLayoutInflater.inflate();//填充Layout,将Activity设置的布局文件,加载到mContentParent中
final Callback cb = getCallback();//通知Activity布局改变
cb.onContentChanged();
...
}
private void installDecor()
{
//根据不同的 Theme,创建不同的 DecorView,DecorView 是一个 FrameLayout
}
PhoneWindow.setContentView()完成 初始化(创建DecorView对象和mContentParent对象)、 填充Layout(将Activity布局文件添加到DecorView里)、 通知Activity 进行布局改变。整个布局加载流程为:创建DecorView,把xml的View树解析出来,加到DecorView上。
创建完成后他们之间没有关系和联系,需要对组件进行激活并建立联系,需要将DecorView添加到window上。ActivityThread.handleLaunchActivity().handleResumeActivity()
函数调用performResumeActivity().performResume()
函数回调onResume()实现组件的激活。
//ActivityThread.java
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume) {
//将Activity数据记录到ActivityClientRecord中,执行到 onResume()
ActivityClientRecord r = performResumeActivity(token, clearHide);
if (r != null) {
final Activity a = r.activity;
boolean willBeVisible = !a.mStartedActivity;
...
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();//定义一个顶级视图decor
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();// 定义一个ViewManager类型的变量 wm
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (a.mVisibleFromClient) {
a.mWindowAdded = true;
wm.addView(decor, l);// 将Decor添加到窗口上
}
}
...
if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow)
{
...
mNumVisibleActivities++;
if (r.activity.mVisibleFromClient) {
//添加视图,详见下面分析,
r.activity.makeVisible();
}
}
//resume 完成
if (reallyResume) {
ActivityManagerNative.getDefault().activityResumed(token);
}
} else {
...
}
}
void makeVisible() {
if (!mWindowAdded) {
ViewManager wm = getWindowManager();
wm.addView(mDecor, getWindow().getAttributes());
mWindowAdded = true;
}
mDecor.setVisibility(View.VISIBLE);
}
通过getWindowManager()
创建的wm的类方法addview()
添加了decorView,addview()
经过多次函数调用最终得到类ViewRootImpl的setView()
方法,该方法十分重要,是所有工作的起点,不仅把View添加到window上,而且触发了绘制流程,完成了请求SurfaceFlinger创建Surface、View显示在GraphicFrame上、建立app与SurfaceFlinger之间的服务连接等任务。
//frameworks/base/core/java/android/view/ViewRootImpl.java
public final class ViewRootImpl(View.Context context, Display display)
{
setView();
mChoreographer = Choreographer.getInstance(); // choreographer的启动和服务
}
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView)
{
// 把传进去的DecorView赋值给mView
mView = view;
requestLayout(); // View的绘制流程(PS:在执行addview()之前需要将UI布局绘制完成)
//mWindowSession类型是interface WindowSession,在getWindowSession()中实现
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel,
mTempInsets);
//处理触摸事件回调
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel, Looper.myLooper());
}
public static IWindowSession getWindowSession()
{
// 获取了WMS,openSession返回值是sWindowSession
IWindowManager windowManager = getWindowManagerService();
// sWindowSession的具体实现在windowManager中。
sWindowSession = windowManager.openSession();
return sWindowSession;
}
// 到这里可以看到, IWindowSession接口真正实现类是Session,它是一个Binder。
public IWindowSession openSession()
{
Session session = new Session;
}
//frameworks/base/services/core/java/com/android/server/wm/Session.java
class Session(){
final WindowManagerService mService;
addToDisplay()
{
return mService.addWindow()
}
}
//frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
// addwindow()代码太多,具体的实现可以看博客中的那张图
2.2 View的绘制流程
在方法setView()
中requestLayout()实现了View的绘制,从Activity到View绘制的函数调用如下图:
从图中可以看出,ViewRootImpl.performTraversals()方法是View绘制的执行起点。ViewRootImpl则肩负着View的标准三步曲(测量、布局、绘制)。
private void performTraversals()
{
//执行测量操作
performMeasure(childWidthMeasureSpec,childHeightMeasureSpec);
//执行布局操作
performLayout(lp, Width, mHeight);
//执行绘制操作
performDraw();
}
实际上,view绘制一共有5个阶段,多了预测量阶段和窗口布局阶段:
预测量阶段: 这是绘制的第一个阶段,对View树进行第一次预测量,计算View树的显示内容所需的尺寸(View树期望的尺寸,是否满足不一定)。通过方法measureHierarchy()
实现 ( PS: measureHierarchy()
方法最终也是调用了performMeasure()
方法对View树进行测量)
窗口布局: 根据预测量的结果,调用IwindowSession.relayout()来请求WindowManagerService服务调整window的大小等属性并对window重新布局,布局结果返回给ViewRootImpl,保存在mWinFrame中。
测量过程: 预测量结果只是View树期待的窗口尺寸,具体大小需要WMS的布局(WMS布局的结果可能不满足预测量的期望尺寸,但是View树必须依据WMS的布局结果)。WMS布局结果出来后,调用performMeasure()
对View树进行最终测量。
开始布局: 在测量阶段对窗口中的view进行了最终测量,然后根据测量结果,调用performLayout()
开始对View树进行布局。
绘制过程:这是View三部曲的最后一步,确定了window上控件的位置和尺寸后(已经完成布局操作),通过调用performDraw()
,最终调用到 drawBackground(canvas)
方法,实现View的绘制(上面提到过,所有的View都是画在Canvas上的)
到这里,已经介绍了Window的创建、View的创建和添加、View的绘制等内容,应用侧工作已经完成,还有一个系统侧工作。
三、Surface与SurfaceFlinger
在上面提到Window、View的创建和绘制,这些都是上层的一些操作,那么如何将上层的内容显示到硬件的显示屏上呢? 这部分将介绍SurfaceFlinger创建Surface、surfaceFlinger合成Layer和送显过程。
3.0 SurfaceFlinger服务启动概述
SurfaceFlinger系统服务在init阶段启动,主要实现了Surface的建立、控制、管理等功能,能够将各种应用程序的2D、3D surface进行组合。
启动SurfaceFlinger时在main_surfaceflinger.cpp里 main()中实例化一个SurfaceFlinger,第一次实例化会执行onFirstRef()创建MessageQueue的对象Handler和消息循环looper,然后初始化右边的EGL等内容。HWC代表着硬件显示设备,注册了 VSYNC 信号的回调。当硬件产生VSYNC信号时,则会发送消息,handler 收到消息进行处理。当 SurfaceFlinger 进程收到 VSync 信号后经层层调用,最终调用到该对象的 handleMessageRefresh() 方法。
SurfaceFlinger.cpp:
void SurfaceFlinger::handleMessageRefresh()
{
ATRACE_CALL();
preComposition();//处理显示设备与 layers 的改变,更新光标
rebuildLayerStacks();//重建所有可见 Layer 列表,根据Z轴排序
setUpHWComposer();//更新 HWComposer 图层
doDebugFlashRegions();
doComposition();//生成 OpenGL 纹理图像
postComposition();//将图像传递到物理屏幕
}
OpenGL:open graphics library,用于渲染2D、3D矢量图形的、操作GPU的API,通过驱动向GPU发送相关指令。
EGL:作为 OpenGL 和原生窗口系统之间的桥梁,用于opengl与本地窗口交互时的中间层,与平台无关。具体作用是为openGL指令创建context、绘制目标surface、配置FrameBuffer属性、Swap提交绘制结果。
HWC:Hardware Composer HAL (HWC) 是 SurfaceFlinger 用来将 Surface 合成到屏幕,介于SurfaceFlinger和HAL之间,用于处理部分SurfaceFlinger的合成任务和产生vsync信号。
3.1 app与SurfaceFlinger服务连接过程
ViewRootImpl.setView()中mWindowSession.addToDisplay()
实现了app与SurfaceFlinger的连接。
在addToDisplay()方法中执行win.attach()(类WindowState的方法attach()),然后在attach()方法中通过mSession.windowaddedlocked()
创建SurfaceSession对象(Session的成员变量SurfaceSession通过windowAddedLocked()方法进行初始化),并将Session实例添加到WMS.mSessions中,这样实现了与WMS进行通信。SurfaceSession的创建会调用JNI中的nativeCreate()
函数。(从上层到了下层)
//WindowState.java
void attach() {
mSession.windowAddedLocked();
}
//Session.java
void windowAddedLocked() {
if (mSurfaceSession == null) {
mSurfaceSession = new SurfaceSession();
mService.mSessions.add(this);
if (mLastReportedAnimatorScale != mService.getCurrentAnimatorScale()) {
mService.dispatchNewAnimatorScaleLocked(this);
}
}
mNumWindow++;
}
// ./frameworks/base/core/java/android/view/SurfaceSession.java
public SurfaceSession()
{
mNativeClient = nativeCreate():
}
下面是app与SurfaceFlinger建立连接的关键点:
在nativeCreate()中创建了SurfaceComposerClinent对象 client,作为跟 SurfaceFlinger 通信的代理对象。
并且client被赋值给了mSession(因为调用的是 mSession.windowAddedLocked()),
//android_view_SurfaceSession.cpp
static jlong nativeCreate(JNIEnv* env, jclass clazz)
{
SurfaceComposerClient* client = new SurfaceComposerClient();
}
// 在赋值时,SurfaceComposerClient类成员函数onFirstRef将被调用
// frameworks/native/libs/gui/SurfaceComposerClient.cpp
void SurfaceComposerClient::onFirstRef() {
sp sf(ComposerService::getComposerService());
if (sf != nullptr && mStatus == NO_INIT) {
sp conn;
conn = sf->createConnection();
if (conn != nullptr) {
mClient = conn;
mStatus = NO_ERROR;
}
}
}
sp SurfaceFlinger::createConnection() {
return initClient(new Client(this));
}
static sp initClient(const sp& client) {
status_t err = client->initCheck();
if (err == NO_ERROR) {
return client;
}
return nullptr;
}
到这里,方法onFirstRef()中创建了spcreateConnection()
建立SurfaceComposerClinet与SurfaceComposer的连接。
ComposerService作为client与SurfaceFlinger 作为 server进行binder IPC,获得SurfaceFlinger创建的Client对象,拿到SurfaceFlinger服务;与此同时,ComposerService创建的Client(server端)与SurfaceComposerClient(client端)又互为binder IPC的两端。
从代码中理解,sf是一个指针,获得了CompoesrService,然后sf与SurfaceFlinger创建的Client建立连接;
sf然后返回给conn,conn是SurfaceComposerClient类型。
3.2 app请求surfaceFlinger创建Surface
在请求建立服务的过程中,ViewRootImpl.setView()中mWindowSession.addToDisplay()
实现了app与SurfaceFlinger的连接。ViewRootImpl.setView()还有一个重要的函数requestLayout()
。该函数实现了surface的创建。
requestLayout()
经过多层调用到WMS.relayoutWindow()方法
//WindowManagerSerview
public int relayoutWindow(..., Surface outSurface)
{
synchroized(mWindowMap)
{
WindowState win = windowForClientLocked();
Surface surface = win.createSurfaceLocked();
if(surface != null) { outSurface.copyForm(surface); ...}
}
}
在WindoManagerService中createSurfaceLocked()
方法new了一个surface(这里是java层的surface),并且将创建的内容拷贝到outSurface中(ViewRootImpl传进来的参数),用作返回给APP使用。
那么创建出来的surface对象是什么样子呢?其实surface主要包含三个变量
Surface {
private int mSurfaceControl //保存C++层的一个SurfaceControl对象的地址值
private Canvas mCanvas //描述一块类型为CompativleCanvas的画布(Canvas)
private String mName //描述当前正在创建的一个绘图surface的名称
}
这里的mSurfaeControl是java层的,控制底层的surface。在类surface 的成员函数中有名为init()的JNI方法(Surface_init()),可以创建C++层SurfaceControl对象。
Surface_init{
// 从 SurfaceSession 对象中取出之前创建的那个 SurfaceComposerClient 对象
SurfaceComposerClient* client = (SurfaceComposerClient*) env ->GetIntField(session,sso.client)
sp surface;//注意它的类型是 SurfaceControl
// 调用SurfaceComposerClient的createsurface函数,这个surface类型是surfacecontrol类型,为WMS服务
surface = client ->createSurface();
...
//把这个 surfaceControl 对象设置到 Java 层的 Surface 对象中
setSurfaceControl(env, clazz, surface);
}
在SurfaceComposerClient类型的client中创建surface,在3.1中所描述的,SurfaceComposerClient通过Binder获取到ComposerService的对象,ComposerService最后到SurfaceFlinger中执行createSurface(本地surface)。
在 createSurface 内部会使用 Binder 通信将请求发给 SurfaceFlinger
spSurfaceFlinger::createSurface()
{
sp layer;//LayerBaseClient 是 Layer 家族的基类
//LayerBaseClient 的内部类,它也叫Surface
sp surfaceHandle;
//根据 clientId 找到 createConnection 时加入的那个 Client 对象
sp client = mClientsMap.valueFor(clientId);
//注意这个 id,它的值表示 Client 创建的是第几个显示层
//同时也表示将使用 SharedBufferStatck 数组的第 id 个元素
int32_t id = client->generateId(pid);
//根据 flags 参数来创建不同类型的显示层
switch(flags & eFXSurfaceMask)
case ...
layer = createNormalSurfaceLocked(client, d, id, w, h, flags, format);
break;
...
//从显示层对象中取一个ISurface对象赋值给SurfaceHandle
surfaceHandle = layer ->getSurface();
return surfaceHandle;//ISurface 的 Bn 端就是这个对象
}
前面所说,每一个surface对应着一个layer,所以createSurface主要是创建了一个layer(可根据不同的参数创建不同的layer),然后layer初始化一些参数。
spSurfaceFlinger::createNormalSurfaceLocked()
{
//创建一个 Layer 类型的对象
sp layer = new Layer(this, display,client, id);
//设置 Buffer
status_t err = layer->setBuffers(w, h, format, flags);
if (LIKELY(err == NO_ERROR)) {
//初始化这个新 layer 的一些状态
layer->initStates(w, h, flags);
//下面这个函数把这个 layer 加入到 Z 轴集合中
addLayer_l(layer);
}
...
return layer;
}
在 上面的surfaceHandle = layer ->getSurface();
可以获取SurfaceFlinger创建的Surface对象,然后该变量返回给sp
Surface类成员mClient(SurfaceClient::getInstance())
指向了app进程中的一个SurfaceClient单例,mSharedBufferClien指向了SharedBufferClient对象
void Surface::init()
{
int32_t token = mClient.getTokenForSurface(mSurface);
mSharedBufferClient = new SharedBufferClient(mClient.getSharedClient(),token,2,mIdentity);
}
// getTokenForSurface()调用setToken()
status_t Layer::setToken()
{
//new 一个SharedBufferServer
sp lcblk = new SharedBufferServer();
}
总结:
将APP window绘制在屏幕的载体是Surface,因此需要在app和底层都创建Surface承载各自的内容,并且需要控制变量SurfaceControl。
APP:在WindoManagerService中创建surface,并且将创建的内容拷贝到outSurface中(ViewRootImpl传进来的参数),用作返回给APP使用,这样app层的surface与WMS层的Surface就建立了联系。此外,app创建的surface与C++层管理一个Surface对象用来绘制APP UI,WMS创建的Surface在C++关联一个SurfaceControl对象,用来设置app window属性。
底层:SurfaceFlinger服务中创建了surfaceHandle,这样surfaceControl就与底层的surfacehandle建立了链接,并且能够控制底层surface。创建Surface过程就是创建Layer、buffer。
3.3 app中的view如何画在surface的canvas上
还是3.2中的requestLayout()函数,一直调用到drawSoftware(surface,...)
drawSoftware(surface,...)
{
canvas = mSurface.lockCanvas(dirty);#获取canvas
mView.draw(canvas); #通过Canvas绘制view,是具体的绘制实现
surface.unlockCanvasAndPost(canvas); #绘制结束
}
重点看一下mView.draw(canvas).
onDraw(Canvas canvas)
{
canvas.save(); // 坐标系原点,坐标轴方向等信息
canvas.translate();//开始绘制
}
onDraw()
中的translate()与jni中的native_translate()相关联,native_translate()然后调用SKCanvas.cpp中的translate(),开始由底层SKCanvas来完成真正的绘制工作。
总结:绘制view时,首先获取一块存放绘制数据的buffer,然后传入canvas进行绘制,绘制其实是调用底层的SKia引擎进行绘制,包含画家SKCanvas和画布SKBitmap;绘制结束后调用unlockCanvasAndPost(canvas)
,让surface通过queueBuffer将数据投放到queue中,通知SurfaceFlinger进行使用。
3.4 surfaceFlinger合成多个layer
每个Android app都有很多window,每个window都有自己的UI元数据,因此不能使用binder在app和surfaceflinger之间传递UI数据,因为数据量太大,复制效率不高,所以选择使用Android os的匿名共享内存方案(SharedClient)。
sharedclient 里面有最多31个sharedbufferstack,每个stack里面有N个buffer(共享缓冲区堆栈,每一个stack与一个surface对应,一个surface与一个window对应)。因此一个app内部最多有31个window。
SurfaceFlinger进程是init进程通过Init.rc创建的,然后独立运行在系统中。创建SurfaceFlinger由main_surfaceflinger.cpp中的main函数来实现
main {
flinger = new SurfaceFlinger ;# 实例化SurfaceFlinger
sp flinger ->init #把实例化的SurfaceFlinger初始化
sp sm ->addService() #把SurfaceFlinger注册到ServiceManager
}
图层合成就是把多个图层,按照既定的显示区域,展现到显示屏上。
在创建SurfaceFlinger时会调用onFirstRef()函数,然后创建looper对象和handler对象,handle对象实现消息的接收和根据消息类型进行图形处理
handleMessage
{ case INVALIDATE #用于处理Layer或display属性变化和layer对应buffer的更新
..........onMessageReceived()
case REFRESH #表示SurfaceFlinger需要一次合成(Refresh)操作
..........onMessageReceived()
}
onMessageReceived()
{
case MessageQueue::INVALIDATE
.... if layer属性变化:handleMessageTransation()处理;
.... else buffer更新:handleMessageInvaliate()处理
case MessageQueue::REFRESH
....handleMessageRefresh()处理
}
SurfaceFlinger合成和投递共有5个步骤:
详细的内容可以参考Android图形显示,详细讲了HWC、SurfaceFlinger合成。
3.5 surface显示过程
在 App 进程中创建 PhoneWindow 后会创建 ViewRoot(ViewRootImpl())。ViewRoot 的创建会创建一个 Surface(ViewRootImpl().requestLayout().createSurfaceLocked()),这个 Surface 其实是空的,通过与 WindowManagerService 通信 copyFrom() 一个 NativeSurface。在与 SurfaceFlinger 通信时,会创建 SharedClient(匿名共享内存) 一段共享内存,里面存放的是 SharedBufferStack(最多31个) 对应 SurfaceFlinger 中的 SurfaceLayer ,每个 Layer 其实是一个 FrameBuffer,每个 FrameBuffer 中有两个 GraphicBuffer 记作 FrontBuffer 和 BackBuffer。在 SurfaceFlinger 中 SharedBufferServer 来管理 FrameBuffer。同时在 App 端 copyFrom() 出来 NativeSurface 时会创建一个 SharedBufferClient 与 SharedClient 共享内存进行关联。当客户端 addView() 或者需要更新 View 时,会通过 SharedBufferClient 写入数据到 ShareClient 中,SurfaceFlinger 中的 SharedBufferServer 接收到通知会将 FrameBuffer 中的数据传输到屏幕上。
在SurfaceFlinger和app端分别对应Layer对象和Surface对象,用SharedBufferServer对象和SharedBufferClient来操作。app想要更新surface时,找到对应的SharedBufferClient对象找到它对应的SharedBufferStack,从bufferqueue尾部找到一个空闲的buffer,然后app请求为这个buffer分配GraphicBuffer,然后把GraphicBuffer返回给app访问。app得到就写入UI数据并插入到对应的SharedBufferStack,然后通知SurfaceFlinger去消费。SurfaceFlinger找到SharedBufferServer对应的成员函数queue去获得待渲染的buffer。
四、Vsync与Choreographer
在上面介绍了window的创建、view的绘制(对窗口的测量和绘制)、surface的创建和关联、view画到canvas、将画好的canvas通过SurfaceFlinger进行合成投递,如此显示系统从Activity到屏幕就介绍完毕。
但是,如何协调CPU/GPU和显示帧之间的关系呢。在Android4.1之后增加了Choreographer机制,用于同Vsync机制配合,统一动画、输入和绘制的时机。
VSYNC是Vertical Synchronized的缩写,是一种定时中断,即当收到Vsync通知时,CPU和GPU立即开始计算数据然后写入buffer中,避免绘制的随机性。Choreographer起调度作用,将绘制工作统一到VSYNC的某个时间点上,使应用的绘制工作有序进行。引入VSYNC核心目的就是解决刷新不同步的问题;
Choreographer:一个java类,是个消息处理器,根据vsync 信号 来计算frame,而计算frame的方式就是处理三种回调,包括事件回调、动画回调、绘制回调。这三种事件在消息输入、加入动画、准备绘图layout 等动作时均会发给Choreographer。收到VSYNC信号时,调用用户设置的回调函数,三种类型的回调为:
CALLBACK_INPUT:优先级最高,与输入事件有关;
CALLBACK_ANIMATON:第二优先级,与动画有关;
CALLBACK_TRAVERSAL:最低优先级,与UI控件绘制有关;
View的onclick、onDraw等等都是从Choreographer.doFrame开始执行的;关于Choreographer可以参考Android Choreographer 源码分析;
引入Vsync同步机制,可以使得CPU/GPU和display按照一个规定时机进行帧制作和显示。
4.1 Choreographer 启动
首先介绍Choreographer,其构造在ViewRootImpl中
public ViewRootImpl()
{
...
// 这里获取了Choreographer的实例
mChoreographer = Choreographer.getInstance();
...
}
public static Choreographer getInstance()
{
//sThreadInstance是一个ThreadLocal对象,ThreadLocal 是线程的局部变量, 是每一个线程所单独持有的
return sThreadInstance.get();
}
private static final ThreadLocal sThreadInstance = new ThreadLocal()
{
@Override
protected Choreographer initialValue() {
Looper looper = Looper.myLooper();
return new Choreographer(looper, VSYNC_SOURCE_APP);
}
}
Choreographer是 线程单例的。接着我们来看一下
private Choreographer(Looper looper) {
mLooper = looper;
//使用当前线程looper创建 mHandler,接受处理消息
mHandler = new FrameHandler(looper);
// 用来接收垂直同步脉冲 vsync,用来控制系统的同步操作
//可以通过读取系统属性debug.choreographer.vsync来获取
//VSync事件接收器就是FrameDisplayEventReceiver(重要)
mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper) : null;
// 标记上一个frame的渲染
mLastFrameTimeNanos = Long.MIN_VALUE;
// 计算一帧的时间,Android手机屏幕是60Hz的刷新频率,就是16ms
mFrameIntervalNanos = (long)(1000000000 / getRefreshRate()); //屏幕刷新周期
// 初始化callbackQueue,ballback队列将在下一帧开始渲染时回调,创建一个大小为5的数组
mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
// 初始化回调任务链表数组
for (int i = 0; i <= CALLBACK_LAST; i++) {
mCallbackQueues[i] = new CallbackQueue();
}
}
sp SurfaceFlinger::createConnection()
{
return initClient(new Client(this));
}
static sp initClient(const sp& client)
{
status_t err = client->initCheck();
if (err == NO_ERROR) {
return client;
}
return nullptr;
}
4.2 Choreographer 执行流程
Activity启动 走完onResume方法后,会进行window的添加。window添加过程会 调用ViewRootImpl的setView()方法,setView()方法会调用requestLayout()方法来请求绘制布局,requestLayout()方法内部又会走到scheduleTraversals()方法,最后会走到performTraversals()方法,接着到了我们熟知的测量、布局、绘制三大流程了。所有UI的变化都是走到ViewRootImpl的scheduleTraversals()方法
scheduleTraversals() 到 performTraversals() ,根据我们上面的介绍,在VSync信号到来时才会执行绘制,即performTraversals()方法。
// ViewRootImpl.java
void scheduleTraversals() {
if (!mTraversalScheduled) {
//此字段保证同时间多次更改只会刷新一次,例如TextView连续两次setText(),也只会走一次绘制流程
mTraversalScheduled = true;
//添加同步屏障,屏蔽同步消息,保证VSync到来立即执行绘制
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
//mTraversalRunnable是TraversalRunnable实例,最终走到run(),也即doTraversal();
//第一个参数三种回调类型,第二个参数添加了Runnable,第三个参数表示是否需要延时
mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
void doTraversal() {
if (mTraversalScheduled)
{
mTraversalScheduled = false;
//移除同步屏障
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
...
//开始三大绘制流程
performTraversals();
...
}
}
在上面的代码中,scheduleTraversals()调用了mChoreographer.postCallback()方法,发送一个会在下一帧执行的回调,即在下一个VSync到来时会执行TraversalRunnable–>doTraversal()—>performTraversals()–>绘制流程。
//输入事件,首先执行
public static final int CALLBACK_INPUT = 0;
//动画,第二执行
public static final int CALLBACK_ANIMATION = 1;
//插入更新的动画,第三执行
public static final int CALLBACK_INSETS_ANIMATION = 2;
//绘制,第四执行
public static final int CALLBACK_TRAVERSAL = 3;
//提交,最后执行,
public static final int CALLBACK_COMMIT = 4;
安排任务—postCallback
public void postCallback(int callbackType, Runnable action, Object token)
{
postCallbackDelayed(callbackType, action, token, 0);
}
public void postCallbackDelayed()
{
...
postCallbackDelayedInternal(callbackType, action, token, delayMillis);
}
private void postCallbackDelayedInternal()
{
synchronized (mLock) {
//当前时间
final long now = SystemClock.uptimeMillis();
//回调执行时间,为当前时间+延迟时间
final long dueTime = now + delayMillis;
//取对应类型的CallbackQueue添加任务
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
if (dueTime <= now) {
//如果delayMillis = 0s,就是没有延迟时,duetime == now,马上执行
scheduleFrameLocked(now);
} else {
//如果有延迟,发送有一个msg定时消息,等时间到了再处理,
//最终也是执行上面一个步骤,scheduleFrameLocked(now)
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
msg.arg1 = callbackType;
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, dueTime);
}
}
}
此处获取当前时间,然后加上要延迟的时间,作为当前Callback的时间点,以这个时间点作为标准,把Callback对象添加到mCallbackQueues[callbackType]队列当中.当执行时间还没到时,往当前的队列中添加一个Message,那么通过Handler机制就会进行处理,此处的mHandler是一个FrameHandler对象
private final class FrameHandler extends Handler {
public FrameHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
执行doFrame,即绘制过程,开始渲染下一帧的操作
case MSG_DO_FRAME:
doFrame(System.nanoTime(), 0);
break;
//申请VSYNC信号,例如当前需要绘制任务时
case MSG_DO_SCHEDULE_VSYNC:
doScheduleVsync();
break;
//需要延迟的任务,最终还是执行上述两个事件
case MSG_DO_SCHEDULE_CALLBACK:
doScheduleCallback(msg.arg1);
break;
}
}
}
如果时间还没有,会判断消息,最后还是会走到下面这个方法:doScheduleCallback().scheduleFrameLocked()
private void scheduleFrameLocked(long now) {
if (!mFrameScheduled) {
mFrameScheduled = true;
//检查是否使用了Vsync机制,通过检查系统值进行确定
if (USE_VSYNC) {
//当前执行的线程,是否是mLooper所在线程
if (isRunningOnLooperThreadLocked()) {
//请求vsync信号,最终调到native层,native处理后出发FramedisplayEventReceiver
//的onVsync()回调,然后执行doFrame()
scheduleVsyncLocked();
} else {
// 若不在,就用mHandler发送消息到原线程,最后还是调用scheduleVsyncLocked方法
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
msg.setAsynchronous(true);//异步
mHandler.sendMessageAtFrontOfQueue(msg);
}
} else {
//如果系统没有使用VSync机制,则使用异步消息延时执行屏幕刷新(4.1后默认开启)
final long nextFrameTime = Math.max(
mLastFrameTimeNanos / NANOS_PER_MS + sFrameDelay, now);
Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, nextFrameTime);
}
}
}
到这里,FrameHandler的作用很明显里了:发送异步消息(因为前面设置了同步屏障)。有延迟的任务发延迟消息、不在原线程的发到原线程、没开启VSYNC的直接走 doFrame 方法取执行绘制。
申请和接受VSync
调用mDisplayEventReceiver的scheduleVsync()方法,mDisplayEventReceiver是Choreographer构造方法中创建,是FrameDisplayEventReceiver 的实例。 FrameDisplayEventReceiver是 DisplayEventReceiver 的子类,DisplayEventReceiver 是一个 abstract class
// mDisplayEventReceiver类变量是在Choreographer的构造方法中赋值的
private void scheduleVsyncLocked() {
//申请Vsync信号
mDisplayEventReceiver.scheduleVsync();
}
public void scheduleVsync() {
nativeScheduleVsync(mReceiverPtr);
}
底层的 nativeScheduleVsync()向surfaceflinger服务注册,即在下一次脉冲接受后调用DisplayEventReceiver的dispatchVsync()方法。(每次调用只有一次dispatchVsync()方法回调)
底层向应用层发送VSYNC信号,java层通过dispatchVsync()接受,最后的回调在FrameDisplayEventReceiver()的onVsync()中
private final class FrameDisplayEventReceiver extends DisplayEventReceiver
implements Runnable {
private boolean mHavePendingVsync;
private long mTimestampNanos;
private int mFrame;
public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
super(looper, vsyncSource);
}
@Override
public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
if (builtInDisplayId != SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {
scheduleVsync();
return;
}
mTimestampNanos = timestampNanos;
mFrame = frame;
//将本身作为runnable传入msg, 发消息后 会走run(),即doFrame(),也是异步消息
Message msg = Message.obtain(mHandler, this);
msg.setAsynchronous(true);
//此处的mHandler为FrameHandler
mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
}
@Override
public void run() {
mHavePendingVsync = false;
doFrame(mTimestampNanos, mFrame);
}
}
onVsync()方法通过FrameHandler向主线程looper发送callback消息,当looper执行到该消息时调用run()方法,然后调用doFrame()。然后doFrame()在Vsync事件到来时顺序执行CallbackQueue队列中注册的回调,调用doCallbacks().CallbackRecord对应的run()方法。
void doFrame(long frameTimeNanos, int frame) {
...
try {
// 按类型顺序 执行任务
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");
AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
mFrameInfo.markInputHandlingStart();
doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
mFrameInfo.markAnimationsStart();
doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos);
mFrameInfo.markPerformTraversalsStart();
doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
} finally {
AnimationUtils.unlockAnimationClock();
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
void doCallbacks(int callbackType, long frameTimeNanos) {
CallbackRecord callbacks;
synchronized (mLock) {
final long now = System.nanoTime();
// 根据指定的类型CallbackkQueue中查找到达执行时间的CallbackRecord
callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(now / TimeUtils.NANOS_PER_MS);
try {
// 迭代执行队列所有任务
for (CallbackRecord c = callbacks; c != null; c = c.next) {
// 回调CallbackRecord的run,其内部回调Callback的run
c.run(frameTimeNanos);
}
} finally {
synchronized (mLock) {
mCallbacksRunning = false;
do {
final CallbackRecord next = callbacks.next;
//回收CallbackRecord
recycleCallbackLocked(callbacks);
callbacks = next;
} while (callbacks != null);
}
}
}
//上面主要内容就是取对应任务类型的队列,遍历队列执行所有任务
//执行任务是 CallbackRecord的 run 方法:
private static final class CallbackRecord {
...
@UnsupportedAppUsage
public void run(long frameTimeNanos) {
if (token == FRAME_CALLBACK_TOKEN) {
// 通过postFrameCallback 或 postFrameCallbackDelayed,会执行这里
((FrameCallback)action).doFrame(frameTimeNanos);
} else {
//取出Runnable执行run()
((Runnable)action).run();
}
}
}
前面看到mChoreographer.postCallback传的token是null,所以取出action,就是Runnable,执行run()。这里的action就是 ViewRootImpl 发起的绘制任务mTraversalRunnable了,那么这样整个逻辑就闭环了.
run()方法被执行,所以doTraversal()被执行,调用performTraversals开启View的绘制流程。
4.3 Choreographer小结
使用Choreographer的postCallback()、postFrameCallback() 作用理解:发送任务 存队列中,监听VSync信号,当前VSync到来时 会使用mHandler发送异步message,这个message的Runnable就是队列中的所有任务。
参考博客:Android屏幕刷新机制—VSync、Choreographer 全面理解!
VSYNC,这个具体指啥?在屏幕刷新中如何工作的?
答:当扫描完一个屏幕后,设备需要重新回到第一行以进入下一次的循环,此时会出现的vertical sync pulse(垂直同步脉冲)来保证双缓冲在最佳时间点才进行交换。并且Android4.1后 CPU/GPU的绘制是在VSYNC到来时开始。