SurfaceFlinger学习之路(一)View的绘制流程

SurfaceFlinger是Android图像渲染的一个非常重要的模块。

Android 系统启动流程

在这里插入图片描述
我们都知道,Android源自于Linux系统,由bootloader载入linux内核,从Linux内核Kernal启动init进程,解析init.rc文件。

创建Zygote进程:Android世界的开始。启动SystemServer进程,接收着其他进程请求创建负责fork新的子进程。

创建Service_Manager进程:Binder通信过程中的守护进程,本身也是一个Binder服务,提供了查询和注册binder服务。

创建SurfaceFlinger进程:负责接受多个进程来源的图像数据,合成并发送到显示设备。

Window创建过程

我们创建一个activity也会创建window,他是所有的view的载体。
在这里插入图片描述

在Activity的启动过程中,当Zygote 创建了一个新的进程之后执行了ActivityThread的main(),将走到ActivityThread的performLaunchActivity()。

// ActivityThread.java
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
	  
	Application app = r.packageInfo.makeApplication(false, mInstrumentation);
	// 1. 创建window  
	activity.attach(...);
    // 2. 调用oncreate()
	mInstrumentation.callActivityOnCreate(activity, r.state);
}

1.创建window

performLaunchActivity反射实例化activity和创建Application。

调用了activity.attach()函数,内部创建了一个PhoneWindow

// Activity.java
final void attach(...) {
	mWindow = new PhoneWindow(this);
    // 3. 创建并设置WindowManager
    mWindow.setWindowManager(...);
}

2.setContentView()初始化DecorView

// Instrumentation.java
public void callActivityOnCreate(Activity activity, Bundle icicle) {
    prePerformCreate(activity);
    activity.performCreate(icicle);
    postPerformCreate(activity);
}

// Activity.java
final void performCreate(Bundle icicle) {
    onCreate(icicle);
    ...
}

往往我们都在会onCreate()中调用Activity的setContentView(),加载对应的布局文件。

// Activity.java
public void setContentView(@LayoutRes int layoutResID) {
    getWindow().setContentView(layoutResID);
    ....
}

其中getWindow()就是上面的PhoneWindow实例。最后交由PhoneWindow加载布局文件

// PhoneWindow.java
public void setContentView(int layoutResID) {
    installDecor();
    ...
    mLayoutInflater.inflate(layoutResID, mContentParent);
}

phonewindow创建了window最顶层的DecorView,并加载对应的布局文件;

我们都知道Activity只有到onResume()才是真正显示了;

此时,View还是没有渲染,Window也还没被添加。

3.WindowManager的创建

Android的WindowManager和View、Window可以参考《WindowManagerService Window View 关系(一)》

在这里是创建了WindowManagerImpl实例,借助他来管理Window、DecorView、ViewRootImpl三者的关系,并通过Session跟WMS通信。

// WindowManager.java
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
    boolean hardwareAccelerated) {
    if (wm == null) {
        wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
    }
    mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}

// WindowManagerImpl.java
public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
    return new WindowManagerImpl(mDisplay, parentWindow);
}

Window和View的添加

后续,ActivityThread会走到handleResumeActivity()

// ActivityThread.java
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume) {
    r.window = r.activity.getWindow();
    View decor = r.window.getDecorView();
    decor.setVisibility(View.INVISIBLE);
    ViewManager wm = a.getWindowManager();
    WindowManager.LayoutParams l = r.window.getAttributes();
    a.mDecor = decor;
    ...
    wm.addView(decor, l);
}

wm对应上面的WindowManagerImpl,我们都知道事实上WindowManagerImpl是个装饰类。

WindowManagerGlobal执行添加View:addView(),内部做了很多事情。

// WindowManagerGlobal.java
public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
    ViewRootImpl root;
    // 1. ViewRootImpl初始化
    root = new ViewRootImpl(view.getContext(), display);
    
    mViews.add(view);
    mRoots.add(root);
    
    // 2. 关联ViewRootImpl、View
    root.setView(view, wparams, panelParentView);
}

ViewRootImpl是一个非常重要的类,ViewRootImpl,它在View的绘制发挥重要的作用,所有View的绘制以及事件分发等交互都是通过它来执行或传递的。

可参考《View/ViewGroup 绘制流程和疑惑》

1. ViewRootImpl初始化

本文只注重ViewRootImpl跟Window、View绘制方面的关系,但是ViewRootImpl并不止于绘制方面,还负责了input event等事件的处理,这里先不做讨论。

//ViewRootImpl.java
final Surface mSurface = new Surface();

public ViewRootImpl(Context context, Display display) {
    // 1.创建WindowSession,是binder的client端,方便调用WMS的服务
    mWindowSession = WindowManagerGlobal.getWindowSession();
    // 2.创建W,是binder的service端,支持被WMS调用ViewRootImpl
    mWindow = new W(this);
    // 3.创建编舞者
    mChoreographer = Choreographer.getInstance();
}

mWindowSession 是 WMS创建的一个Session,提供给ViewRootImpl调用WMS的服务。

// WindowManagerService.java
 public IWindowSession openSession(...) {
    Session session = new Session(this, callback, client, inputContext);
    return session;
 }

Session 在后面会发挥重要的作用。WMS会为App创建一个Session,App利用Session跟WMS跨进程通信。

Surface是Android提供给上层Activity绘制的一个界面,表面上我们绘制的是View,最后会绘制到Surface,每一个窗口都会有一个Surface。

new Surface()只是创建了一个空的Surface,之后copyFrom()才会真正填充surface。下一节再继续讲述Surface的真正创建。

// Surface.java
public Surface() {
}

我们在调用requestLayout()或者invalidate(),ViewRootImpl并不是马上就开始绘制,得等到一个时机才会执行绘制的三大流程:measure()、layout()、draw();而Choregrapher就是控制什么时候执行绘制流程。

mChoregrapher是编舞者,负责控制ViewRootImpl绘制时机,跟Vsync同步信号相关。

具体可以参考《Android 屏幕刷新机制:ViewRootImpl、Choreographer、Surface、SurfaceFlinger关系》

2. 关联ViewRootImpl和View

前面WindowManagerGlobal的setView(),调用了ViewRootImpl.addView()关联了View、ViewRootImpl

public void setView(View view, WindowManager.LayoutParams attrs, 
	View panelParentView) {
    mView = view;
    ...
    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
        getHostVisibility(), mDisplay.getDisplayId(), mWinFrame,
        mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
        mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel);
    ...
}

ViewRootImpl 借助了上面mWindowSession跟WMS跨进程通信。我们看下binder的服务端Session做了什么工作。

WindowManagerService 真正实现添加一个Window。

// Session.java
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
    int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,
    Rect outStableInsets, Rect outOutsets, DisplayCutout.ParcelableWrapper outDisplayCutout, 
    InputChannel outInputChannel) {
    // mService就是WindowManagerService
    return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
       outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel);
}

// WindowManagerService.java
public int addWindow(Session session, IWindow client, ...) {
     ...
     final WindowState win = new WindowState(...);
     win.attach();
}

// WindowState.java
void attach() {
    mSession.windowAddedLocked(mAttrs.packageName);
}

// Session.java
void windowAddedLocked(String packageName) {
    if (mSurfaceSession == null) {
        mSurfaceSession = new SurfaceSession();
        mService.mSessions.add(this);
    }
}

上述的过程追溯下来就是想说明,WMS添加Window的过程中,Session最后会创建SurfaceSession,而SurfaceSession是什么呢??

通过上面我们知道,每一个窗口在WMS中会有一个对应的Session,而一个Session会创建对应的SurfaceSession,SurfaceSession的作用就是负责跟SurfaceFlinger通信。

后续我们会看到SurfaceSession,发挥怎样的作用。

View的绘制

以上,我们讲述了Window、View、ViewRootImpl、WindowManagerImpl、WMS、Session、SurfaceSession之间大概是怎么样的关系。

View的绘制应该从ViewRootImpl的performTraversal()讲起。下面我们讲,View的绘制流程,但是这里不讲述View的三大绘制历程。

首先我们知道View的绘制都是从ViewRootImpl.performTraversals()讲起。

// ViewRootImpl.java
private void performTraversals() {
    relayoutWindow(params, viewVisibility, insetsPending);
 
    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);

    performLayout(lp, mWidth, mHeight);

    performDraw();
}

relayoutWindow表示让WMS重新布局画布,后续WMS才会给Surface设置属性或者创建新的Surface。

// ViewRootImpl.java
private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
    boolean insetsPending) {
    ...
	int relayoutResult = mWindowSession.relayout(...);
}

//Session.java
public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,
    int requestedWidth, int requestedHeight, int viewFlags, int flags, long frameNumber,
    Rect outFrame, Rect outOverscanInsets, Rect outContentInsets, Rect outVisibleInsets,
    Rect outStableInsets, Rect outsets, Rect outBackdropFrame,
    DisplayCutout.ParcelableWrapper cutout, MergedConfiguration mergedConfiguration, Surface outSurface) {
    int res = mService.relayoutWindow(...);
    return res;
}

后面文章继续讲WMS.relayoutWindow()、SurfaceSession…关系等。

总结

在这里插入图片描述

发布了74 篇原创文章 · 获赞 63 · 访问量 2万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览