忽然有一天,我想要做一件事:去代码中去验证那些曾经被“灌输”的理论。
-- 服装学院的IT男
Surface系统-1-应用与SurfaceFlinger建立链接
Surface系统-2-SurfaceControl的创建(java层)
Surface系统-3-SurfaceControl的创建(native层)
Surface系统-4-BLASTBufferQueue和Surface的创建
Surface系统-5-BLASTBufferQueue工作流程概览
本篇同时已收录于Activity短暂的一生系列
正文
应用在第一个窗口显示的时候会创建出 SurfaceSession 与 SurfaceFlinger 通信。 应用需要显示的一个窗口或者一块区域就是一个 Surface ,一个 SurfaceControl 管理着1个 Surface ,介绍 SurfaceControl 的创建。 为了内容的联系续 java 层的逻辑会与 【窗口显示第二步-relayoutWindow-1】有部分重叠。
1. 流程概览
ViewRootImpl 创建的时候就有 mSurface 和 mSurfaceControl 2个成员变量,但是只是个 java 层的对象实例,目前还没有对应 native 的实现,真正赋值的方式是在 relayoutWindow 流程中。
mSurfaceControl 作为参数传递到 WMS,然后在WMS中作为出参被赋值,这块的代码如下:
# ViewRootImpl
// 成员变量
public final Surface mSurface = new Surface();
private final SurfaceControl mSurfaceControl = new SurfaceControl();
private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
boolean insetsPending) throws RemoteException {
......
// 1. 作为参数传递到 system_sertvice 进程
relayoutResult = mWindowSession.relayout(......, mSurfaceControl,......);
......
// 2. 给 mSurface 赋值
if (!useBLAST()) {
mSurface.copyFrom(mSurfaceControl);
} else {
// 现在都走这给mSurface赋值
updateBlastSurfaceIfNeeded();
}
......
}
-
- mSurfaceControl 作为参数(out参数)传递到 system_server ,执行 relayoutWindow 流程,在这个过程中会创建 native 层的 SurfaceControl 也会对应用端传过去的 mSurfaceControl 进行赋值
-
- 经过 system_server 处理后的 mSurfaceControl 有值了,再给 mSurface 赋值
这块的调用链如下:
ViewRootImpl::init
Surface::init
SurfaceControl::init
ViewRootImpl::relayoutWindow -- SurfaceControl作为出参
Session::relayout
WindowManagerService::relayoutWindow
WindowManagerService::createSurfaceControl -- 创建显示的Surface
WindowStateAnimator::createSurfaceLocked
WindowSurfaceController::init
SurfaceControl.Build::init
SurfaceControl::init
nativeCreate -- native层创建Surface
WindowSurfaceController::getSurfaceControl
SurfaceControl::copyFrom
SurfaceControl::assignNativeObject -- 将Surface的指针和句柄传递给应用端
Surface::updateBlastSurfaceIfNeeded -- 赋值给应用端的Surface
BLASTBufferQueue::init
BLASTBufferQueue::createSurface
Surface::transferFrom
Surface::setNativeObjectLocked
2. java 层 SurfaceControl 的创建
java 层 SurfaceControl 的创建逻辑主要是在 system_server 端处理,处理的终点就是触发 native 的执行。
看一下 WindowManagerService 的相关逻辑:
# WindowManagerService
public int relayoutWindow(Session session, IWindow client, ......
SurfaceControl outSurfaceControl, ......) {
......
// 拿到对应的 WindowState
final WindowState win = windowForClientLocked(session, client, false);
......
WindowStateAnimator winAnimator = win.mWinAnimator;
......
// 当前主线* 创建 system_server 进程对应的SurfaceControl
result = createSurfaceControl(outSurfaceControl, result, win, winAnimator);
......
}
relayoutWindow 流程是在 addWindow 流程之后, addWindow 流程会在 system_server 进程为要显示的窗口创建对应的 WindowState 。所以这里在执行 relayoutWindow 的时候可以通过windowForClientLocked 方法获取到对应的 WindowState ,而 WindowStateAnimator 是在 WindowState 构造方法中创建的。
拿到了 WindowState 和 WindowStateAnimator 就可以创建SurfaceControl了,注意第一个参数,这个 outSurfaceControl 就是在应用端传递过来的,参数前面加上了“out”是 binder 作为出参的方式,也就是说 system_server 进程会对这个参数进行赋值,这样应用端 ViewRootImpl 下的 SurfaceControl 就会持有一个 native 层的 SurfaceControl 指针。
# WindowManagerService
private int createSurfaceControl(SurfaceControl outSurfaceControl, int result,
WindowState win, WindowStateAnimator winAnimator) {
......
// 窗口的Surface管理者
WindowSurfaceController surfaceController;
try {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "createSurfaceControl");
// 1. 创建 WindowSurfaceController
surfaceController = winAnimator.createSurfaceLocked(win.mAttrs.type);
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
if (surfaceController != null) {
// 2. outSurfaceControl
surfaceController.getSurfaceControl(outSurfaceControl);
ProtoLog.i(WM_SHOW_TRANSACTIONS, "OUT SURFACE %s: copied", outSurfaceControl);
}
......
return result;
}
这里分为2步:
-
- 创建 SurfaceControl
-
- 赋值给出参 outSurfaceControl
这里看到 WindowSurfaceController 这个类,它内部有一个 SurfaceController , SurfaceController 内部又操作 Surface 。 之前看过他们之间的关系如下:
2.1 创建 SurfaceController
# WindowStateAnimator
WindowSurfaceController createSurfaceLocked() {
final WindowState w = mWin;
// 如果已经创建过就直接返回
if (mSurfaceController != null) {
return mSurfaceController;
}
w.setHasSurface(false);
ProtoLog.i(WM_DEBUG_ANIM, "createSurface %s: mDrawState=DRAW_PENDING", this);
// mDrawState = DRAW_PENDING
resetDrawState();
......
try {
......
// 重点*2. 创建WindowSurfaceController
mSurfaceController = new WindowSurfaceController(attrs.getTitle().toString(), format,
flags, this, attrs.type);
mSurfaceController.setColorSpaceAgnostic((attrs.privateFlags
& WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC) != 0);
// 标志着 WindowState 已经有 surface 了
w.setHasSurface(true);
......
} catch (OutOfResourcesException e) {
......
}
......
return mSurfaceController;
}
WindowSurfaceController 构造后会创建一个 SurfaceControl 也就意味着创建了一个 Surface 所以这里将 执行了 WindowStateAnimator::resetDrawState 把窗口状态设置为 DRAW_PENDING 表示处于等待绘制的状态。
下面看看 WindowSurfaceController 的构造方法,需要留意下第一个参数,这个就是窗口参数的 title 。
# WindowSurfaceController
// 持有一个SurfaceControl
SurfaceControl mSurfaceControl;
WindowSurfaceController(String name, int format, int flags, WindowStateAnimator animator,
int windowType) {
......
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "new SurfaceControl");
// 构建一个Builder
final SurfaceControl.Builder b = win.makeSurface()
.setParent(win.getSurfaceControl()) // 挂载在windowState下
.setName(name) // 名字就是窗口的name
.setFormat(format)
.setFlags(flags)
.setMetadata(METADATA_WINDOW_TYPE, windowType)
.setMetadata(METADATA_OWNER_UID, mWindowSession.mUid)
.setMetadata(METADATA_OWNER_PID, mWindowSession.mPid)
.setCallsite("WindowSurfaceController");
final boolean useBLAST = mService.mUseBLAST && ((win.getAttrs().privateFlags
& WindowManager.LayoutParams.PRIVATE_FLAG_USE_BLAST) != 0);
// 高版本都为BLAST
if (useBLAST) {
// 注意* 设置为非容器图层
b.setBLASTLayer();
}
// 构建SurfaceControl
mSurfaceControl = b.build();
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
构建了一个 SurfaceControl,这里创建 SurfaceControl 的方式和容器是一样的,但是通过 setBLASTLayer方法将当前 Surface 设置成 Buff 类型的 Surface ,这样就可以显示内容了,这点非常重要。
# SurfaceControl.Build
@NonNull
public SurfaceControl build() {
// 构建一个SurfaceControl
return new SurfaceControl(
mSession, mName, mWidth, mHeight, mFormat, mFlags, mParent, mMetadata,
mLocalOwnerView, mCallsite);
}
# SurfaceControl
// 指针
public long mNativeObject;
// 句柄
private long mNativeHandle;
private SurfaceControl(SurfaceSession session, String name, int w, int h, int format, int flags,
SurfaceControl parent, SparseIntArray metadata, WeakReference<View> localOwnerView,
String callsite)
throws OutOfResourcesException, IllegalArgumentException {
......
// *1. native创建,返回对象指针
mNativeObject = nativeCreate(session, name, w, h, format, flags,
parent != null ? parent.mNativeObject : 0, metaParcel);
if (mNativeObject == 0) {
throw new OutOfResourcesException(
"Couldn't allocate SurfaceControl native object");
}
// 2.根据指针获取SurfaceControl的句柄
mNativeHandle = nativeGetHandle(mNativeObject);
mCloseGuard.openWithCallSite("release", callsite);
}
这里出现了句柄和指针的概念: 指针:指向对象的内存地址 句柄:JNI经常使用句柄来引用本地代码中的对象或资源,以便在Java和本地代码之间传递引用而不暴露底层实现细节。
这里用到的 session 就是 SurfaceSession。
上面这代码是 SurfaceControl 的构造方法,虽然目前还是没看到 Surface 的身影,但是其实在 native 层创建 SurfaceControl 的时候也会创建好一个 Surface 。 native 的处理逻辑后面会单独详细解释,目前就先以黑盒的概念继续往后看。
2.2 应用端 SurfaceController 的赋值
继续看是怎么把创建好的 SurfaceController 传递给应用端的。 回到主流程知道在 WindowManagerService::createSurfaceControl 方法里会先执行 WindowStateAnimator::createSurfaceLocked 创建 SurfaceControl 然后再执行 SurfaceController::getSurfaceControl 方法将新创建的 SurfaceControl 赋值给应用端。
# WindowSurfaceController
void getSurfaceControl(SurfaceControl outSurfaceControl) {
outSurfaceControl.copyFrom(mSurfaceControl, "WindowSurfaceController.getSurfaceControl");
}
这里的参数 outSurfaceControl 是应用端传递过来的, mSurfaceControl 就是前面 WindowStateAnimator::createSurfaceLocked 创建的 SurfaceControl 。
# SurfaceControl
public void copyFrom(@NonNull SurfaceControl other, String callsite) {
mName = other.mName;
mWidth = other.mWidth;
mHeight = other.mHeight;
mLocalOwnerView = other.mLocalOwnerView;
// 注意将刚刚创建的 SurfaceControl 句柄作为参数
assignNativeObject(nativeCopyFromSurfaceControl(other.mNativeObject), callsite);
}
private void assignNativeObject(long nativeObject, String callsite) {
......
// 赋值给 SurfaceControl
mNativeObject = nativeObject;
mNativeHandle = mNativeObject != 0 ? nativeGetHandle(nativeObject) : 0;
}
-
- java 层的 SurfaceControl 通过 mNativeObject 持有 native 层的 SurfaceControl
-
- java 层 SurfaceControl 的赋值只需要把自己的 mNativeObject 赋值给另一个 SurfaceControl 对象即可,这样它们2个就可以持有同一个 native 层的 SurfaceControl
nativeCopyFromSurfaceControl 也是一个 native 方法,将 native 层的 SurfaceControl 进行拷贝然后获取到一个新的指针,将这个指针再传递给应用端的 SurfaceControl 。 这样一来,应用端的 SurfaceControl 就也持有了 native 层的 SurfaceControl 指针和句柄。 后续应用端对 Surface 的操作就可以体现在 native 层的Surface中了。
3. 应用端的 Surface 的赋值
经过前面的分析,现在 ViewRootImpl 下的 mSurfaceControl 已经持有了 native 层 SurfaceControl 的指针,现在看看是如何对 mSurface 赋值的。
# ViewRootImpl
public final Surface mSurface = new Surface();
private final SurfaceControl mSurfaceControl = new SurfaceControl();
private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
boolean insetsPending) throws RemoteException {
......
// 作为参数传递到 system_sertvice进程
relayoutResult = mWindowSession.relayout(......, mSurfaceControl,......);
......
// 经过system_server处理后的mSurfaceControl有值了,再赋值给mSurface
if (!useBLAST()) {
mSurface.copyFrom(mSurfaceControl);
} else {
// 目前版本都走这,内部也是
updateBlastSurfaceIfNeeded();
}
......
}
BLAST 算新特性了,现在的版本都支持,所以走 ViewRootImpl::updateBlastSurfaceIfNeeded 方法,不过也可以确定 Surface::copyFrom 方法也能从一个 SurfaceControl 对象里获取到 Surface 对象。
下面看看 ViewRootImpl::updateBlastSurfaceIfNeeded 方法的实现。
# ViewRootImpl
private BLASTBufferQueue mBlastBufferQueue;
void updateBlastSurfaceIfNeeded() {
// 1. 确认 SurfaceControl 是否有对应的 native 指针
if (!mSurfaceControl.isValid()) {
return;
}
......
// 2. 创建 BLASTBufferQueue
mBlastBufferQueue = new BLASTBufferQueue(mTag, mSurfaceControl,
mSurfaceSize.x, mSurfaceSize.y, mWindowAttributes.format);
mBlastBufferQueue.setTransactionHangCallback(sTransactionHangCallback);
// 3. 通过 BLASTBufferQueue 创建一个 Surface
Surface blastSurface = mBlastBufferQueue.createSurface();
// Only call transferFrom if the surface has changed to prevent inc the generation ID and
// causing EGL resources to be recreated.
// 4. 给当前mSurface赋值
mSurface.transferFrom(blastSurface);
}
逻辑还是比较清晰的,分为4步。 之前分析过在 system_server 执行 relayoutWindow 流程创建 SurfaceControl 的时候 native 层也会创建一个 Surface 。这里又看到通过 BLASTBufferQueue::createSurface 创建了一个 Surface ,这里可能会怀疑为什么又要创建一个 Surface ,这里可以先确定一个结论: 这里“创建”的 Surface 其实和之前创建 SurfaceControl 时创建的 Surface 是一个 native 层的 Surface 。
具体执行后续分析 native 代码会单独详细分析,这里其实也有2个点可以引起猜测:
-
- SurfaceControl::isValid 的实现就是判断是不是有 native 的值,只有满足条件才会根据这个 SurfaceControl 创建 BLASTBufferQueue 。这说明肯定和 relayoutWindow 流程创建 SurfaceControl 有联系
-
- BLASTBufferQueue::createSurface 虽然叫“create” 但是对应的 JNI 方法为 nativeGetSurface (获取)。
先看看 java 层是如何通过 Surface::transferFrom 给另一个 Surface 赋值的。
# Surface
// native 层指针
long mNativeObject; // package scope only for SurfaceControl access
public void transferFrom(Surface other) {
if (other == null) {
throw new IllegalArgumentException("other must not be null");
}
if (other != this) {
final long newPtr;
synchronized (other.mLock) {
// 设置 surface 指针
newPtr = other.mNativeObject;
other.setNativeObjectLocked(0);
}
synchronized (mLock) {
if (mNativeObject != 0) {
// 释放之前的
nativeRelease(mNativeObject);
}
// 设置新的
setNativeObjectLocked(newPtr);
}
}
}
private void setNativeObjectLocked(long ptr) {
if (mNativeObject != ptr) {
if (mNativeObject == 0 && ptr != 0) {
mCloseGuard.open("Surface.release");
} else if (mNativeObject != 0 && ptr == 0) {
mCloseGuard.close();
}
// 设置 native 指针
mNativeObject = ptr;
mGenerationId += 1;
if (mHwuiContext != null) {
mHwuiContext.updateSurface();
}
}
}
可以看到 Java 层的 Surface 中定义了一个变量 mNativeObject ,这个变量和 SurfaceControl 是一样都代表着 native 层的指针。
总之,经过这段调用,应用端的 Surface 也持有了对应的 native 层的 Surface 指针。
3. 结束语
上层的 SurfaceControl、 Surface、BLASTBufferQueue 的创建和赋值逻辑介绍完毕,
在 system_server 触发创建 native 层的 SurfaceControl 和 Surface 将 native 的句柄保存在 java 中。SurfaceControl 这个 Surface 的控制者控制的其实是 native 层的Surface 指针。
对应分析过程中遇到的 native 问题有下面3个,后面会单独分析:
-
- SurfaceControl 对应的 native 创建逻辑
-
- BLASTBufferQueue 的 native 创建逻辑,和 SurfaceControl 有什么联系
-
- BLASTBufferQueue::nativeGetSurface 获取的 Surface 流程