Android绘制流程 —— View、Window、SurfaceFlinger

3,338 阅读10分钟

前言

上篇分析了Activity的启动流程

那么在启动之后,通过setContentView设置的布局文件又是如何被排版绘制并显示到设备的呢?

同样是老生常谈的问题,网上查阅了很多相关的资料,在此来做个复习总结记录。

计划分为三篇文章,在大体上分析梳理一遍Android绘制的主要流程。

目标是建立起对绘制流程的整体认识,为后续深入理解内部细节做铺垫。

如果有误,欢迎指出,共同进步

源码分析

Window连接流程

先上一个Window的创建并与SurfaceFlinger建立连接的简要关系图。

基于Android 11 (Andoird R),不同版本间可能有细节差异。

在需要显示功能的进程上,都要首先与SurfaceFlinger建立联系才能开始绘制操作。

本篇将从Activity的布局设置开始,对View是如何与Window、SurfaceFlinger关联,进行一个粗略的流程上的探究。

1. 构建视图树

实际开发中,我们通常会在Activity.onCreate()方法内,通过setContentView()来将布局文件加载导入,我们就以此作为切入点展开分析。

以Android 11 (Andoird R)为例,限于篇幅有限,且实际源码流程相当复杂,这里只保留重要核心代码。

// android.app.Activity
public class Activity extends ContextThemeWrapper ...{
   	private Window mWindow;
    
    public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);
        ...
    }
    
    public Window getWindow() {
        return mWindow;
    }
}

而这里的Window是一个抽象类,我们需要看Activity从哪里获取到了Window对象。

还记得在Activity启动流程中,创建Activity时调用的Activity.attach()方法吗?

Window对象就是在这里的被创建为其子类com.android.internal.policy.PhoneWindow

// android.app.Activity
public class Activity extends ContextThemeWrapper ...{
    private WindowManager mWindowManager;
    
    final void attach(Context context, ActivityThread aThread, ... ,
                      Window window, ActivityConfigCallback activityConfigCallback, ...){
        attachBaseContext(context);
        ...
        mWindow = new PhoneWindow(this, window, activityConfigCallback);
        ...
        //设置windowManager(注意这个WindowManager)
        mWindow.setWindowManager((WindowManager)context.getSystemService(Context.WINDOW_SERVICE),...);
        ...
        //赋值activity内部变量
        mWindowManager = mWindow.getWindowManager();
        ...

    }
}

//com.android.internal.policy.PhoneWindow
public class PhoneWindow extends Window ...{
    ViewGroup mContentParent;
    
    @Override
    public void setContentView(int layoutResID) {
        if (mContentParent == null) {
            //mContentParent为空,会创建顶层DecorView
            installDecor();
        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            //已存在ContentParent容器,清空所有子View
            mContentParent.removeAllViews();
        }
        ...
        //将content布局文件解析层对应的控件,添加到ContentParent容器中
        mLayoutInflater.inflate(layoutResID, mContentParent);
        ...
    }
    
    private void installDecor() {
        if (mDecor == null) {
            //创建顶层View对象
            mDecor = generateDecor(-1);
            ...
        } else {
            mDecor.setWindow(this);
        }
        
        if (mContentParent == null) {
            //在顶层View下添加一个存放View的root容器
            mContentParent = generateLayout(mDecor);
            ...
        }
    }
    
    //创建DecorView
    protected DecorView generateDecor(int featureId) {
        ...
        return new DecorView(context,...);    
    }
    
    //父类Window内的作为root容器中content部分的view id
    public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content;
    
    protected ViewGroup generateLayout(DecorView decor) {
        //根据主题Theme样式来加载对应的顶层View布局
        int layoutResource;
        ...
        //最简单的根布局,如
        layoutResource = R.layout.screen_simple;    
        //向顶层View添加子View,设置对应的布局    
        mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
        ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
        ...
        return contentParent
    }
    
    //父类Window的方法,通过DecorView内设置的布局,获取content部分容器ViewGroup
    @Nullable
    public <T extends View> T findViewById(@IdRes int id) {
        return getDecorView().findViewById(id);
    }
    
}

PhoneWindow内部创建了DecorView,作为最顶层的View容器,嵌套包裹其他所有View,本身继承自FrameLayout

public class DecorView extends FrameLayout ...{

	void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {
        ...
        final View root = inflater.inflate(layoutResource, null);
        ...
        //将content布局添加到ViewGroup
        addView(root, 0, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));  
        ...
	}
}
  • 那么从DecorView中通过findViewById获取到的contentParent又是什么呢?

以 其中最简单的R.layout.screen_simple布局为例

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical">
<ViewStub android:id="@+id/action_mode_bar_stub"
        android:inflatedId="@+id/action_mode_bar"
        android:layout="@layout/action_mode_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="?attr/actionBarTheme" />
<FrameLayout
   android:id="@android:id/content"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:foregroundInsidePadding="false"
   android:foregroundGravity="fill_horizontal|top"
   android:foreground="?android:attr/windowContentOverlay" />
</LinearLayout>

PhoneWindow中获取的com.android.internal.R.id.content就是其中的FrameLayout

所以我们平常setContent,就是,默认就已经有了这些基础的视图层级。

  • 小结

setContentView()的过程其实就是将布局inflate加载解析xml后的View,嵌套到DecorView为根节点的视图树内的过程。

关于LayoutInflater.inflat参见[Android | 带你探究 LayoutInflater 布局解析原理](

2. Window建立连接

前面分析了视图树的构建,下面我们先回到ActivityThread,来看看视图树是何时与Window产生联系的。

还记得在Activity启动流程中调用的handleResumeActivity方法吗?

// ============== android.app.ActivityThread ================
public final class ActivityThread extends ClientTransactionHandler {
    
    public void handleResumeActivity(IBinder token, boolean finalStateRequest, ...) {
        ...
        //内部执行了Activity.onResume()方法    
        final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
        ...
        if (r.window == null && !a.mFinished && willBeVisible) {
            //属于新启动Activity
            r.window = r.activity.getWindow();
            View decor = r.window.getDecorView();
            //将DecorView视图树设置为不可见
            decor.setVisibility(View.INVISIBLE);
            ViewManager wm = a.getWindowManager();
            ...
            if (a.mVisibleFromClient) {
                if (!a.mWindowAdded) {
                    a.mWindowAdded = true;
                    //将视图树添加到WindowManager
                    wm.addView(decor, l);
                }else{
                    ...
                }
            }
        }
        ...
        if (r.activity.mVisibleFromClient) {
            //将DecorView视图设置为可见状态
         	r.activity.makeVisible();
        }
        ...
    }
}

在第一次启动Activity时,在执行完onResume()才会将视图添加到WindowManager后,调用Activity.makeVisible方法切换为可见状态

这也就是在onCreate()onResume中,都获取不到View的尺寸的原因。毕竟根本就还没有执行UI绘制操作,怎么可能有尺寸。

// =========== android.app.Activity ==================
public class Activity extends ContextThemeWrapper...{
    View mDecor = null;
    
    void makeVisible() {
        if (!mWindowAdded) {
            ViewManager wm = getWindowManager();
            wm.addView(mDecor, getWindow().getAttributes());
            mWindowAdded = true;
        }
        mDecor.setVisibility(View.VISIBLE);
    }
    
    public WindowManager getWindowManager() {
        return mWindowManager;
    }
}

WindowManager是个接口,同时继承了ViewManager,那么其实现类的实例又在哪里呢?

// ============= android.view.WindowManager ===============
public interface WindowManager extends ViewManager {
    ...
}

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

前面提到Activity.getWindowManager(),最终也是通过Window.getWindowManager()的来获取的。

而在Window里,则是由前面提到过的Activity.attch()方法中通过调用Window.setWindowManager来赋值的。

// ============= android.view.Window ==============
public abstract class Window {
    public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
            boolean hardwareAccelerated) {
        mAppToken = appToken;
        mAppName = appName;
        mHardwareAccelerated = hardwareAccelerated;
        if (wm == null) {
            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
        }
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    }
}

可以看到实际赋值给mWindowManager的是其实现子类android.view.WindowManagerImpl

// ============ android.view.WindowManagerImpl ===================
public final class WindowManagerImpl implements WindowManager {
    
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
    
    private WindowManagerImpl(Context context, Window parentWindow) {
        mContext = context;
        mParentWindow = parentWindow;
    }
    
    public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
        return new WindowManagerImpl(mContext, parentWindow);
    }
    
    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        //代理给单例类执行添加操作
        mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
                mContext.getUserId());
    }
    
}

而在WindowManagerImpl中则是由WindowManagerGlobal代为执行addView操作,创建一个新的ViewRootImpl对象。

// =========== android.view.WindowManagerGlobal =================

public final class WindowManagerGlobal {
    private static WindowManagerGlobal sDefaultWindowManager;
    
    private WindowManagerGlobal() {
    }
    //全局的单例类
    public static WindowManagerGlobal getInstance() {
        synchronized (WindowManagerGlobal.class) {
            if (sDefaultWindowManager == null) {
                sDefaultWindowManager = new WindowManagerGlobal();
            }
            return sDefaultWindowManager;
        }
    }
    
    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow, int userId) {
        ...
        ViewRootImpl root;
        ...
        // 创建新的ViewRootImpl    
        root = new ViewRootImpl(view.getContext(), display);
        ...
        //将DecorView添加到ViewRootImpl    
        root.setView(view, wparams, panelParentView, userId);
    }
    
}

WindowManagerGlobal是应用进程中的全局单例,负责管理进程内的所有Window。

通过ViewRootImpl.setViewDecorView视图树设置给ViewRootImpl

// ============ android.view.ViewRootImpl =================

public final class ViewRootImpl implements ViewParent,...{
    // WindowManagerService的Binder代理类
    final IWindowSession mWindowSession;
    final W mWindow;
    
    View mView;
    
    public ViewRootImpl(Context context, Display display) {
        //构造函数多态下的默认值,非实际代码
        mWindowSession = WindowManagerGlobal.getWindowSession();
    }
    
	public void setView(View view, WindowManager.LayoutParams attrs, 
                        View panelParentView,int userId) {
        synchronized (this) {
            if (mView == null) {
                //赋值DecorView
                mView = view;
            }
            ...
            //请求绘制视图,详见下一篇继续分析
            requestLayout();    
            ...            
            int res; /* = WindowManagerImpl.ADD_OKAY; */
            ...
            // 跨进程Binder代理调用,通过系统进程的WindowManagerService建立连接
            res = mWindowSession.addToDisplayAsUser(mWindow,...);    
            ...
        }
        
    }
}

2.1 WindowState与SurfaceSession

ViewRootImpl中的Binder代理对象是通过WindowManagerGlobal的静态方法获取的。

其中IWindowManager的代理实现类是system_server进程中的WindowManagerService

IWindowSession是由WindowManagerService代理类通过openSession方法创建的com.android.server.wm.Session

// ============ android.view.WindowManagerGlobal ===================

public final class WindowManagerGlobal {
    //静态方法,获取WindowManagerService的Binder代理类的单例对象
    public static IWindowManager getWindowManagerService() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowManagerService == null) {
                sWindowManagerService = IWindowManager.Stub.asInterface(
                        ServiceManager.getService("window"));
                try {
                    if (sWindowManagerService != null) {
                        ValueAnimator.setDurationScale(
                                sWindowManagerService.getCurrentAnimatorScale());
                        sUseBLASTAdapter = sWindowManagerService.useBLAST();
                    }
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
            return sWindowManagerService;
        }
    }
    
    //静态方法,获取Session代理类的单例对象
    public static IWindowSession getWindowSession() {
        synchronized (WindowManagerGlobal.class) {
            if(sWindowSession == null){
            	//初始化 
                InputMethodManager.ensureDefaultInstanceForDefaultDisplayIfNecessary();    
                //获取 WindowManagerService 的代理类
                IWindowManager windowManager = getWindowManagerService();
                //通过WindowManagerService,开启会话,获取Session的代理类对象
                sWindowSession = windowManager.openSession(
                    new IWindowSessionCallback.Stub() {
                        @Override
                        public void onAnimatorScaleChanged(float scale) {
                            ValueAnimator.setDurationScale(scale);
                        }
                    });
                ...
            }
            return sWindowSession    
        }
    }
}

// ============ com.android.server.wm.WindowManagerService ==============

public class WindowManagerService extends IWindowManager.Stub ...{
    
    @Override
    public IWindowSession openSession(IWindowSessionCallback callback) {
        return new Session(this, callback);
    }
    
}

// ============== com.android.server.wm ================
class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
    final WindowManagerService mService;
    
    @Override
    public int addToDisplayAsUser(IWindow window, int seq, WindowManager.LayoutParams attrs,
            int viewVisibility, int displayId, int userId, ...) {
        return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,...);
    }
        
}

Session更多还是个传递的中间类,实际最后工作的还是回到了WindowManagerService

// ============== com.android.server.wm.WindowManagerService =================

/** Mapping from an IWindow IBinder to the server's Window object. */
final HashMap<IBinder, WindowState> mWindowMap = new HashMap<>();

public int addWindow(Session session, IWindow client, int seq,
            LayoutParams attrs, ...,int displayId,...) {
   	...   
    //创建了Window的状态类,WindowManagerService内管理的也是WindowState
    final WindowState win = new WindowState(this, session, client , ...);
    ...
    win.attach();    
    mWindowMap.put(client.asBinder(), win);
    win.initAppOpsState();
    ...
}

addWindow中,会新创建一个WindowState对象,也就是抽象概念的Window容器,并执行其attach方法。

attach操作还是由内部持有的Session来执行,并在内部创建SurfaceSession对象。

// ============= com.android.server.wm.WindowState ==================

class WindowState extends WindowContainer<WindowState> ...{
    final Session mSession;
    final WindowStateAnimator mWinAnimator;
    
    WindowState(WindowManagerService service, Session s, IWindow c, ...) {
     	mSession = s;
        mWinAnimator = new WindowStateAnimator(this);
        ...
    }
    
    void attach() {
        mSession.windowAddedLocked(mAttrs.packageName);
    }
}

// ================ com.android.server.wm.Session =================

class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
    SurfaceSession mSurfaceSession;
    final WindowManagerService mService;
    
    void windowAddedLocked(String packageName) {
        ...
        if (mSurfaceSession == null) {
            ...
            //关键代码
            mSurfaceSession = new SurfaceSession();
            ...
            //添加当前Session对象到关联Session列表
            mService.mSessions.add(this);
            ...
        }
        mNumWindow++;
    }
}

但实际上SurfaceSession是一个空壳,内部仅持有一个由nativeCreate创建的native对象引用地址

// ============ android.view.SurfaceSession ===============
public final class SurfaceSession {
    // Note: This field is accessed by native code.
    private long mNativeClient; // SurfaceComposerClient*

    private static native long nativeCreate();
    
    /** Create a new connection with the surface flinger. */
    public SurfaceSession() {
        mNativeClient = nativeCreate();
    }
}

2.2 SurfaceComposerClient

SurfaceSession.nativeCreate是一个native方法,我们尝试继续向下探究

关于查看native方法,参见Android JNI原理分析

以下native方法是通过Android Search Code查看,需要翻墙。

代码基于Android11-rc3,限于篇幅有限,同样只保留关键核心代码。

native方法所在的C文件名通常为java类的全限定名android.view.SurfaceSession中,将.改为_,即android_view_SurfaceSession.cpp

// ============== frameworks/base/core/jni/android_view_SurfaceSession.cpp ==============
static jlong nativeCreate(JNIEnv* env, jclass clazz) {
    SurfaceComposerClient* client = new SurfaceComposerClient();
    //增加一次强引用计数
    client->incStrong((void*)nativeCreate);
    return reinterpret_cast<jlong>(client);
}

这里是实际是创建了SurfaceComposerClient,实际在java源码中也注释了这个类。

// ============ frameworks/native/libs/gui/SurfaceComposerClient.cpp ===============
SurfaceComposerClient::SurfaceComposerClient()
    : mStatus(NO_INIT)
{       
}

SurfaceComposerClient构造函数是个空实现。但在nativeCreate()中创建完实例后,还通过incStrong增加一次强引用计数。

关于incStrong增加引用次数,参见:

Android framwork 分析之智能指针LightRefBase ,sp,wp,RefBase

Android系统智能指针的设计思路(轻量级指针、强指针、弱指针)

// ============ frameworks/native/libs/gui/include/gui/SurfaceComposerClient.h ===============
class SurfaceComposerClient : public RefBase
{
    ...
}

SurfaceComposerClient继承自RefBase,在第一次增加强引用后会执行onFirstRef()方法。

// ========== frameworks/native/libs/gui/SurfaceComposerClient.cpp ================
void SurfaceComposerClient::onFirstRef() {
    //获取到SurfaceFlinger的Binder代理类对象
    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
    if (sf != nullptr && mStatus == NO_INIT) {
        sp<ISurfaceComposerClient> conn;
        //与SurfaceFlinger建立连接,创建一个Client
        conn = sf->createConnection();
        if (conn != nullptr) {
            mClient = conn;
            mStatus = NO_ERROR;
        }
    }
}

/*
 * This class defines the Binder IPC interface for accessing various
 * SurfaceFlinger features.
 */
class ISurfaceComposer: public IInterface {
    /*
     * Create a connection with SurfaceFlinger.
     */
    virtual sp<ISurfaceComposerClient> createConnection() = 0;
}

这里的ISurfaceComposer实际上就是SurfaceFlinger的Binder代理类,去Binder代理调用位于独立进程内的SurfaceFlinger方法。

我们直接来看SurfaceFlinger.createConnection

// ======== frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp =============

sp<ISurfaceComposerClient> SurfaceFlinger::createConnection() {
    const sp<Client> client = new Client(this);
    return client->initCheck() == NO_ERROR ? client : nullptr;
}

// frameworks/native/libs/gui/include/gui/ISurfaceComposerClient.h
class ISurfaceComposerClient : public IInterface {
    ...
}

// ========== frameworks/native/services/surfaceflinger/Client.cpp ================
Client::Client(const sp<SurfaceFlinger>& flinger)
    : mFlinger(flinger)
{
}

status_t Client::createSurface(...) {
    // We rely on createLayer to check permissions.
    return mFlinger->createLayer(...);
}

内部创建的Client对象是ISurfaceComposerClient的Binder代理实现类,其内部操作还是转交给SurfaceFlinger调用。

每次建立连接时都会创建一个新的Client对象。

从而使SurfaceSession能够通过SurfaceComposerClientSurfaceFlinger建立连接。

引用官方文档的描述:

SurfaceFlinger 接受来自多个来源的数据缓冲区,对它们进行合成,然后发送到显示设备。

当应用进入前台时,WindowManager 服务会向 SurfaceFlinger 请求一个绘图 Surface。SurfaceFlinger 会创建一个其主要组件为 BufferQueue 的层,而 SurfaceFlinger 是其消耗方。生产方端的 Binder 对象通过 WindowManager 传递到应用,然后应用可以开始直接将帧发送到 SurfaceFlinger。

所以SurfaceFlinger是作为与显示设备关联,最终合成Layer渲染并显示到设备的关键节点。

个人能力有限,更多关于SurfaceFlinger参见:

Android Systrace 基础知识(5) - SurfaceFlinger 解读

Android-SurfaceFlinger启动与绘图原理

一篇文章看明白 Android 图形系统 Surface 与 SurfaceFlinger 之间的关系

Android 图形架构 之二—— SurfaceFlinger 启动和连接

对Binder机制跨进程通信的认识还是有些模糊,暂且粗略的将其看作简单的代理模式的运用,待后续再深入研究一番。

总结

最后概括总结一下这部分的大致过程:

  1. DecorView经由WindowManagerGlobal通过addView()方法创建了一个新的ViewRootImpl,同时将上一节构建的视图树也一并添加到ViewRootImpl内。

  2. ViewRootImpl在一系列的调用后,最终通过跨进程Binder代理调用WindowManagerService.addWindow(),创建新的WindowState

  3. Session创建新的native层SurfaceComposerClient,持有新创建的Client的Binder代理类对象,与SurfaceFlinger建立连接。

    SurfaceFlinger位于一个独立的进程内,只有与其建立连接后,App才能进行视图绘制任务

下一篇继续对视图绘制流程进行分析。

参考资料

DecorView介绍

一篇文章看明白 Activity 与 Window 与 View 之间的关系

Android 图形架构 之二—— SurfaceFlinger 启动和连接

Android的UI显示原理之Surface的创建

图解 | 一图摸清Android系统服务