前言
上篇分析了Activity的启动流程。
那么在启动之后,通过setContentView
设置的布局文件又是如何被排版绘制并显示到设备的呢?
同样是老生常谈的问题,网上查阅了很多相关的资料,在此来做个复习总结记录。
计划分为三篇文章,在大体上分析梳理一遍Android绘制的主要流程。
目标是建立起对绘制流程的整体认识,为后续深入理解内部细节做铺垫。
如果有误,欢迎指出,共同进步
源码分析
先上一个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.setView
将DecorView
视图树设置给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
增加引用次数,参见:
// ============ 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
能够通过SurfaceComposerClient
与SurfaceFlinger
建立连接。
引用官方文档的描述:
SurfaceFlinger
接受来自多个来源的数据缓冲区,对它们进行合成,然后发送到显示设备。当应用进入前台时,WindowManager 服务会向 SurfaceFlinger 请求一个绘图 Surface。SurfaceFlinger 会创建一个其主要组件为 BufferQueue 的层,而 SurfaceFlinger 是其消耗方。生产方端的 Binder 对象通过 WindowManager 传递到应用,然后应用可以开始直接将帧发送到 SurfaceFlinger。
所以
SurfaceFlinger
是作为与显示设备关联,最终合成Layer渲染并显示到设备的关键节点。
个人能力有限,更多关于
SurfaceFlinger
参见:Android Systrace 基础知识(5) - SurfaceFlinger 解读
一篇文章看明白 Android 图形系统 Surface 与 SurfaceFlinger 之间的关系
Android 图形架构 之二—— SurfaceFlinger 启动和连接
对Binder机制跨进程通信的认识还是有些模糊,暂且粗略的将其看作简单的代理模式的运用,待后续再深入研究一番。
总结
最后概括总结一下这部分的大致过程:
DecorView
经由WindowManagerGlobal
通过addView()
方法创建了一个新的ViewRootImpl
,同时将上一节构建的视图树也一并添加到ViewRootImpl
内。
ViewRootImpl
在一系列的调用后,最终通过跨进程Binder代理调用WindowManagerService.addWindow()
,创建新的WindowState
。
Session
创建新的native层SurfaceComposerClient
,持有新创建的Client
的Binder代理类对象,与SurfaceFlinger
建立连接。
SurfaceFlinger
位于一个独立的进程内,只有与其建立连接后,App才能进行视图绘制任务
下一篇继续对视图绘制流程进行分析。
参考资料
一篇文章看明白 Activity 与 Window 与 View 之间的关系