关于图形显示部分可以参考官网:Graphics
图像显示原理
Linux通常使用Framebuffer来用作显示输出(Framebuffer知识详解在这里),Framebuffer就是一块内存区域,它通常是显示驱动的内部缓冲区在内存中的映射。
一旦用户进程把图像数据复制到Framebuffer中,显示驱动会一个像素一个像素地扫描整个Framebuffer,并根据其中的值更新屏幕上像素点的颜色。
驱动中这个更新屏幕的动作是固定的,它的周期就是我们常说的刷新率
Android关于图像渲染显示的架构图如下:
结合这张图,我们需要重点关注的是:
-
Native Framework中的Surface- 无论开发者使用什么渲染
API,一切内容都会渲染到Surface上 Surface中会关联一个BufferQueue用于提供图像数据缓存- 大多数客户端使用
OpenGL ES或Vulkan渲染到Surface - 有些客户端使用
Canvas渲染到Surface
- 无论开发者使用什么渲染
-
Image Stream Producer的定义是能够生成图形缓冲区以供消耗的任何对象。每个Producer都会关联一个Surface,例如Canvas 2D:Java层主要是通过View中创建的Surface对象来进行操作- 该
Surface对象会与SurfaceFlinger进行关联,并通过lockCanavas()接口获取Canvas对象 lockCanvas()会将CPU渲染程序连接到BufferQueue的生产方,直到Surface被销毁时才会断开连接
- 该
mediaserver视频解码器:通过MediaPlayer的setSurfaceHolder()接口与SurfaceView中的Surface进行绑定
-
对于
Image Stream Consumer来说,主要是SurfaceFlinger,该系统服务会消耗当前可见的Surface,并使用WindowManager中提供的信息将它们合成到显示部分。SurfaceFlinger是可以修改所显示部分内容的唯一服务。SurfaceFlinger使用OpenGL和Hardware Composer来合成一组Surface。- 当应用进入前台时,它会从
WindowManager请求缓冲区。然后,WindowManager会从SurfaceFlinger请求layer。layer是surface(包含BufferQueue)和SurfaceControl(包含屏幕框架等层元数据)的组合。
SurfaceFlinger创建layer并将其发送至WindowManager。- 然后,
WindowManager将Surface发送至应用,但会保留SurfaceControl来操控应用在屏幕上的外观。
-
Window Positioning中的WindowManager主要是用来控制Window对象Window对象是用来存放View对象的容器,每个Window对象都会关联Surface对象WindowManager监视Window对象的生命周期、输入和焦点事件、屏幕方向、转换、动画、位置、变换、z顺序等- 然后将所有
Window元数据发送给SurfaceFlinger,SurfaceFlinger利用这些元数据把自己管理的所有Surface组合成layer - 然后交给
Hardware Composer做进一步处理
-
HAL层中的Hardware Composer(HWC)会根据当前硬件来进一步进行缓冲区的组合,它的具体实现依赖于特定的显示设备- 官网关于
HWC的数据流如下:
SurfaceFlinger作为client向HWC提供一个完整的layer列表,然后询问HWC计划如何处理HWC会将这些layer标记为client合成或者device合成并告知SurfaceFlingerSurfaceFlinger将处理标记为client合成的layer,然后通过BufferQueue传递给HWC- 余下的
layer由HWC自行处理
- 官网关于
网上一篇很有趣的渲染总结(文中有些错误,但瑕不掩瑜):Android渲染原理
VSYNC信号
前面提到Linux使用Framebuffer来用作显示输出。但是,如果在屏幕更新到一半时,用户进程更新了Framebuffer中的数据,将导致屏幕上画面的上半部分是前一帧的画面,下半部分变成了新的画面。当然这种异常会在下次刷新时纠正过来,但是在用户感知上画面会出现闪烁感
- 针对这种情况,早期的解决方法是使用
双缓冲机制,双缓冲就是提供两块Framebuffer,一块用于显示,另一块用于数据更新,数据准备好后,通过ioctl操作告诉显示设备切换用于显示的Framebuffer,这样图像就能快速的显示出来了 - 但是双缓冲并没有完全解决问题,虽然双缓冲切换的速度很快,但是如果切换的时间点不对,在画面更新一半的时候进行切换,还是会出现单缓冲区遇到的闪烁问题
- 当然,可以在底层进行控制,当收到切换请求后内部并不马上执行,而是等到刷新完成后再切换,这样可以完全避免画面重叠的问题
- 但是,这样做会带来新的问题,如果
ioctl操作完成后缓冲区没有切换,应用就不能确定何时可以再使用缓存区,只能通过ioctl不停地查询缓冲区状态,直到切换完成。这种CPU主动查询的方式很低效
为此Android让底层固定地发送信号给用户进程,通知进程切换的时机,这样就避免了用户进程主动查询的操作。而这个信号就是VSYNC信号
官方传送门:
VSYNC
官方描述如下:VSYNC信号用来同步整个显示流程(Display Pipeline)。显示流程包括app渲染、SurfaceFlinger合成、HWC(硬件渲染)组成
(这部分感觉原文更容易理解)VSYNC synchronizes the time apps wake up to start rendering, the time SurfaceFlinger wakes up to composite the screen, and the display refresh cycle.
VSYNC信号应该由显示驱动产生,这样才能达到最佳效果。但是Android为了能运行在不支持VSYNC机制的设备上,也提供了用软件来模拟产生VSYNC信号的手段
官网描述:通过
HWC来产生VSYNC信号,并通过接口回调将事件进行发送(主要是SurfaceFlinger进行事件接收)
基础知识铺垫完成,我们先来看看Surface
Surface
官网对
Surface的描述是:A surface is an interface for a producer to exchange buffers with a consumer.
上面描述的是一种生产者-消费者的模式,而Surface充当了中间衔接的角色。
以Activity中UI显示为例:
-
生产者的任务就是把图形绘制在Surface对象上- 比较出名的生产者就是
SurfaceView组件了
- 比较出名的生产者就是
-
SurfaceFlinger作为消费者会把所有Surface对应的图像层混合在一起 -
最后
消费者将其输出到FrameBuffer中,这样在屏幕上就看到最后合成的图像了
下面我们从Java层开始分析Surface
应用中Surface的创建过程
应用开发中很少直接使用Surface,因为每个Activity中都已经创建好了各自的Surface对象,通常只有一些特殊的应用才需要在Activity之外再去创建Surface,例如相机、视频播放应用。
不过,通常这些应用也是通过创建SurfaceView来使用Surface
需要注意的是,在应用中不能直接去创建一个可用的Surface对象(也可以说直接创建出的对象没什么实际用途),因为这样创建出的Surface对象和SurfaceFlinger之间没有任何关联。
该如何创见一个可用的Surface对象呢?
我们看下Surface类的定义:
public class Surface implements Parcelable {
long mNativeObject;
// 一个无参构造,空实现
public Surface() {
}
public Surface(SurfaceTexture surfaceTexture) {
if (surfaceTexture == null) {
throw new IllegalArgumentException("surfaceTexture must not be null");
}
mIsSingleBuffered = surfaceTexture.isSingleBuffered();
synchronized (mLock) {
mName = surfaceTexture.toString();
setNativeObjectLocked(nativeCreateFromSurfaceTexture(surfaceTexture));
}
}
}
Surface类对外有两个构造方法:
-
一个是无参构造,实现也是空的
- 注释中说这个主要是给
readFromParcel()反序列化用的 - 那我们看下
readFromParcel()方法
public void readFromParcel(Parcel source) { if (source == null) { throw new IllegalArgumentException("source must not be null"); } synchronized (mLock) { mName = source.readString(); mIsSingleBuffered = source.readInt() != 0; setNativeObjectLocked(nativeReadFromParcel(mNativeObject, source)); } } - 注释中说这个主要是给
-
另一个需要传递
SurfaceTexture对象作为参数- 这就复杂了,还要准备一个
SurfaceTexture对象
- 这就复杂了,还要准备一个
聪明的我们会发现,readFromParcel()和new Surface(SurfaceTexture surfaceTexture)都会执行一个setNativeObjectLocked()方法,我们看下方法实现:
private void setNativeObjectLocked(long ptr) {
if (mNativeObject != ptr) {
...
mNativeObject = ptr;
...
}
}
setNativeObjectLocked()方法很简单,只是更新了mNativeObject变量的数值,重点就是参数了:
setNativeObjectLocked(nativeReadFromParcel(mNativeObject, source));setNativeObjectLocked(nativeCreateFromSurfaceTexture(surfaceTexture));
这两个setNativeObjectLocked()方法的调用从参数的命名来看是针对不同数据来源的处理。
看来要看下native的实现了,以nativeReadFromParcel()为例来看下:
static jlong nativeReadFromParcel(JNIEnv* env, jclass clazz,
jlong nativeObject, jobject parcelObj) {
Parcel* parcel = parcelForJavaObject(env, parcelObj);
...
android::view::Surface surfaceShim;
// 解析 Parcel 数据,并填充到 native层 的 Surface对象 surfaceShim
surfaceShim.readFromParcel(parcel, /*nameAlreadyRead*/true);
// 将传入的指针转换为 native层 的 Surface对象 self
sp<Surface> self(reinterpret_cast<Surface *>(nativeObject));
// 比对 surfaceShim 和 self 中的 Binder 对象 IGraphicBufferProducer
if (self != nullptr
&& (IInterface::asBinder(self->getIGraphicBufferProducer()) ==
IInterface::asBinder(surfaceShim.graphicBufferProducer))) {
// 判断是同一个 IGraphicBufferProducer ,直接返回当前指针
return jlong(self.get());
}
sp<Surface> sur;
if (surfaceShim.graphicBufferProducer != nullptr) {
// IGraphicBufferProducer 不同
// 且 surfaceShim 的 IGraphicBufferProducer 不为空
// 创建一个新的 Surface 对象 sur
sur = new Surface(surfaceShim.graphicBufferProducer, true);
sur->incStrong(&sRefBaseOwner);
}
...
// 将 sur 的指针返回给 Java 层
return jlong(sur.get());
}
到这里我们不难看出
Java层的Surface对象最重要的数据是mNativeObject变量mNativeObject是一个指针,指向的native层的Surface对象
native层在判断是否新建Surface对象的逻辑依赖的是IGraphicBufferProducer对象IGraphicBufferProducer对象是一个Binder引用对象
那么接下来我们重点就是这个IGraphicBufferProducer了。
我们先看下native层中Surface类的继承关系:
class Surface
: public ANativeObjectBase<ANativeWindow, Surface, RefBase>
ANativeObjectBase的定义如下:
template <typename NATIVE_TYPE, typename TYPE, typename REF,
typename NATIVE_BASE = android_native_base_t>
class ANativeObjectBase : public NATIVE_TYPE, public REF
{...}
整理成继承关系图就是:
再看下Surface的构造方法:
Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp)
: mGraphicBufferProducer(bufferProducer),
mCrop(Rect::EMPTY_RECT),
mBufferAge(0),
...
mFrameEventHistory(std::make_unique<ProducerFrameEventHistory>()) {
... // 初始化各种成员变量
}
从构造函数的参数可以看到,native层的Surface将IGraphicBufferProducer对象保存到了mGraphicBufferProducer变量中。
暂时还是不清楚mGraphicBufferProducer哪里来的,我们去WMS中看看
WMS中Surface的创建过程
此处要从Activity的onResume()生命周期说起
onResume()到WMS.relayoutWindow()
我们已经知道,当AMS触发onResume()生命周期时会调用到ActivityThread类的handleResumeActivity()方法,代码如下:
public void handleResumeActivity(...) {
...
// 此处会触发 onResume 声明周期回调
final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
...
ViewManager wm = a.getWindowManager();
...// 省略很多 Window 处理逻辑
wm.addView(decor, l);
...
}
从方法中可以看到,执行完onResume()后调用了ViewManager的addView(decor, l)方法
知识点:在
onResume方法调用后才真正进行View的添加
ViewManager是一个接口类,真正的实现类是WindowManagerImpl,addView()方法实现也很简单:
public void addView(...) {
applyDefaultToken(params);
mGlobal.addView(...);
}
调用了mGlobal的addView()方法方法,mGlobal的类型是WindowManagerGlobal,代码如下:
public void addView(...) {
...
ViewRootImpl root;
synchronized (mLock) {
...
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
try {
root.setView(view, wparams, panelParentView);
}
...
}
}
WindowManagerGlobal类的addView()先是创建了一个新的ViewRootImpl对象,然后调用了ViewRootImpl对象的setView()方法。
ViewRootImpl类中setView()调用流程如下:
class ViewRootImpl{
/**
* 这里也是直接 new 出来的对象 Surface
* 前面已经介绍过,这个对象需要和 native层进行绑定后才能正常使用
*/
public final Surface mSurface = new Surface();
ViewRootImpl(Context context, Display display){
...
// 此方法会创建 Session 对象
mWindowSession = WindowManagerGlobal.getWindowSession();
...
}
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;
...
// 内部方法调用
requestLayout();
...
// 此方法会创建 SurfaceSession
res = mWindowSession.addToDisplay(...);
...
}
}
}
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
...
scheduleTraversals();
}
}
void scheduleTraversals() {
if (!mTraversalScheduled) {
...
// 异步执行 mTraversalRunnable
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
...
}
}
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
void doTraversal() {
if (mTraversalScheduled) {
...
performTraversals();
...
}
}
private void performTraversals() {
...
relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
...
}
private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
boolean insetsPending) throws RemoteException {
...
// 调用 mWindowSession 的 relayout 方法,并将 mSurface 对象传递过去
int relayoutResult = mWindowSession.relayout(..., mSurface);
...
return relayoutResult;
}
}
setView()方法最后调用的是mWindowSession的relayout()方法。
mWindowSession类型是IWindowSession,是一个Binder引用对象。真正的Binder服务实现是com.android.server.wm.Session类:
class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
public Session(WindowManagerService service, ...) {
mService = service;
...
}
public int relayout(..., Surface outSurface) {
...
int res = mService.relayoutWindow(..., outSurface);
...
return res;
}
}
终于走到了WMS中,调用的是WMS的relayoutWindow()方法
WMS.relayoutWindow()到SurfaceControl.nativeCreate()
和Surface相关的调用关系如下:
class WindowManagerService{
public int relayoutWindow(..., Surface outSurface) {
...
result = createSurfaceControl(outSurface, ...);
...
return result;
}
private int createSurfaceControl(Surface outSurface, ...) {
...
WindowSurfaceController surfaceController;
...
surfaceController = winAnimator.createSurfaceLocked(win.mAttrs.type, win.mOwnerUid);
...
if (surfaceController != null) {
surfaceController.getSurface(outSurface);
} else {
...
outSurface.release();
}
return result;
}
}
class WindowSurfaceController{
public WindowSurfaceController(...) {
...
final SurfaceControl.Builder b = win.makeSurface()
...
.setMetadata(windowType, ownerUid);
mSurfaceControl = b.build();
}
void getSurface(Surface outSurface) {
outSurface.copyFrom(mSurfaceControl);
}
}
class Surface{
public void copyFrom(SurfaceControl other) {
if (other == null) {
throw new IllegalArgumentException("other must not be null");
}
long surfaceControlPtr = other.mNativeObject;
if (surfaceControlPtr == 0) {
throw new NullPointerException(
"null SurfaceControl native object. Are you using a released SurfaceControl?");
}
long newNativeObject = nativeGetFromSurfaceControl(surfaceControlPtr);
synchronized (mLock) {
if (mNativeObject != 0) {
nativeRelease(mNativeObject);
}
setNativeObjectLocked(newNativeObject);
}
}
}
在上面的relayoutWindow()方法中
WMS先通过winAnimator的createSurfaceLocked()方法得到了一个WindowSurfaceController对象WindowSurfaceController对象封装了SurfaceControl对象
- 然后
WMS调用WindowSurfaceController对象的getSurface()方法来对Surface对象进行填充getSurface()对象只是利用自身保存的mSurfaceControl对象- 通过
Surface的copyFrom()方法对Surface对象进行填充处理
copyFrom()方法- 调用
nativeGetFromSurfaceControl()方法得到一个native层的Surface对象指针 - 然后通过
setNativeObjectLocked()方法将指针保存到成员变量mNativeObject中
- 调用
关键点又回到了native层的nativeGetFromSurfaceControl()方法,它的代码如下:
static jlong nativeGetFromSurfaceControl(JNIEnv* env, jclass clazz,
jlong surfaceControlNativeObj) {
sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(surfaceControlNativeObj));
sp<Surface> surface(ctrl->getSurface());
if (surface != NULL) {
surface->incStrong(&sRefBaseOwner);
}
return reinterpret_cast<jlong>(surface.get());
}
nativeGetFromSurfaceControl()方法是通过native层的SurfaceControl的getSurface()方法来获取Surface对象。我们再看下getSurface()方法:
sp<Surface> SurfaceControl::getSurface() const
{
Mutex::Autolock _l(mLock);
if (mSurfaceData == 0) {
return generateSurfaceLocked();
}
return mSurfaceData;
}
sp<Surface> SurfaceControl::generateSurfaceLocked() const
{
mSurfaceData = new Surface(mGraphicBufferProducer, false);
return mSurfaceData;
}
在SurfaceControl的getSurface()方法中
- 当
mSurfaceData指针为空时才会通过generateSurfaceLocked()方法创建一个新的Surface对象Surface对象中很关键的IGraphicBufferProducer在这里传入的是SurfaceControl的成员变量mGraphicBufferProducer
- 否则直接返回
mSurfaceData指针
从getSurface()方法的逻辑中我们不难看出,SurfaceControl对象和Surface对象是关联在一起的,一对一的关系
更关键的是构造Surface对象的核心参数竟然是SurfaceControl中的成员变量。。。。。。。。
没办法,要先搞定SurfaceControl的创建过程才可以
前面已经讲过,WMS通过winAnimator.createSurfaceLocked()方法创建了WindowSurfaceController对象,WindowSurfaceController对象初始化时就会创建SurfaceControl,我们看下创建过程:
class WindowStateAnimator{
WindowSurfaceController createSurfaceLocked(int windowType, int ownerUid) {
...
// mSession 的类型就是前面提到的 Session 类,IWindowSession Binder服务类
mSurfaceController = new WindowSurfaceController(mSession.mSurfaceSession, ...);
...
return mSurfaceController;
}
}
class WindowSurfaceController{
public WindowSurfaceController(SurfaceSession s, ...) {
...
final SurfaceControl.Builder b = win.makeSurface()
...
.setMetadata(windowType, ownerUid);
// 通过 Builder 模式创建的
mSurfaceControl = b.build();
}
}
class SurfaceControl{
public static class Builder {
...
public SurfaceControl build() {
...
// 调用私有构造方法
return new SurfaceControl(mSession, ...);
}
...
}
private SurfaceControl(SurfaceSession session, ...)
throws OutOfResourcesException, IllegalArgumentException {
...
mNativeObject = nativeCreate(session, ...);
if (mNativeObject == 0) {
throw new OutOfResourcesException(
"Couldn't allocate SurfaceControl native object");
}
...
}
}
可以看到
- 创建
SurfaceControl对象的全程都携带着一个SurfaceSession对象。 - 同时这个
SurfaceSession对象在SurfaceControl的构造方法中通过nativeCreate()传递到了native层,用来创建native层的对象 - 和
Java层的Surface对象一样,SurfaceControl对象也会将native层对象的指针保存到mNativeObject中
关键还是在nativeCreate()方法,我们继续。。
nativeCreate()方法如下:
static jlong nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj, ...) {
ScopedUtfChars name(env, nameStr);
sp<SurfaceComposerClient> client(android_view_SurfaceSession_getClient(env, sessionObj));
...
sp<SurfaceControl> surface;
status_t err = client->createSurfaceChecked(
String8(name.c_str()), w, h, format, &surface, flags, parent, windowType, ownerUid);
...
return reinterpret_cast<jlong>(surface.get());
}
nativeCreate()方法中又出现了一个新的类型SurfaceComposerClient,而且native层的SurfaceControl对象就是通过它的createSurfaceChecked()来创建的
耐心、耐心、耐心。。。。 崩溃的时候多说几次
上面方法中的SurfaceComposerClient对象是通过android_view_SurfaceSession_getClient()方法得到的,看JNI的命名格式可以推算它和SurfaceSession类也有关系,内容如下:
sp<SurfaceComposerClient> android_view_SurfaceSession_getClient(
JNIEnv* env, jobject surfaceSessionObj) {
return reinterpret_cast<SurfaceComposerClient*>(
env->GetLongField(surfaceSessionObj, gSurfaceSessionClassInfo.mNativeClient));
}
android_view_SurfaceSession_getClient()方法中的参数surfaceSessionObj是在Java层调用nativeCreate()方法时传递的参数,类型是SurfaceSession。
这里实际上是将
SurfaceSession对象中成员变量mNativeClient的值取出来后,转换为SurfaceComposerClient对象返回
这说明SurfaceComposerClient对象和SurfaceSession对象也是一起创建出来的,我们继续看下SurfaceSession和SurfaceComposerClient的创建过程
SurfaceControl.nativeCreate到ComposerService
需要知道的一个重要前提:每个用户进程在
WMS中都有且只有一个对应的Session对象,前面已经介绍Session是一个实现了IWindowSession接口的Binder服务类
Session的成员变量mSurfaceSession是在Session对象初始化时创建的,那么Session对象在什么时候创建的呢?
跟踪代码发现流程如下:
ViewRootImpl初始化时会调用WindowManagerGlobal.getWindowSession()方法WindowManagerGlobal.getWindowSession()会调用WMS的openSession()方法openSession()方法中便会在WMS中创建一个新的Session对象
对于SurfaceSession的初始化,是在Session对象的windowAddedLocked()方法中,那么windowAddedLocked()方法又是在哪里调用的呢?
同样,我们跟踪下方法调用:
ViewRootImpl的setView()方法中会调用mWindowSession.addToDisplay(...)方法mWindowSession.addToDisplay(...)方法会调用WMS的addWindow()方法WMS的addWindow()方法会调用WindowState的attach()方法attach()方法会调用Session的windowAddedLocked()方法
这样就串起来了,现在我们可以继续学习SurfaceSession的构造方法了:
/** Create a new connection with the surface flinger. */
public SurfaceSession() {
mNativeClient = nativeCreate();
}
很简洁,源码注释也很关键。我们看下SurfaceSession的nativeCreate()方法:
static jlong nativeCreate(JNIEnv* env, jclass clazz) {
SurfaceComposerClient* client = new SurfaceComposerClient();
// 请注意此方法的调用
// 该方法会触发 onFirstRef() 的执行
client->incStrong((void*)nativeCreate);
return reinterpret_cast<jlong>(client);
}
nativeCreate()直接创建了一个SurfaceComposerClient对象,也没有参数。不过SurfaceComposerClient类是从RefBase类派生出来的,我们看下它的构造函数和onFirstRef函数:
SurfaceComposerClient::SurfaceComposerClient()
: mStatus(NO_INIT)
{
}
// onFirstRef() 是 RefBase 提供的回调接口
// 当首次调用 incStrong() 方法时便会执行此方法
void SurfaceComposerClient::onFirstRef() {
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
if (sf != 0 && mStatus == NO_INIT) {
// 此处 rootProducer 应该为 null
auto rootProducer = mParent.promote();
sp<ISurfaceComposerClient> conn;
// 所以在此处执行的是 sf->createConnection() 方法
conn = (rootProducer != nullptr) ? sf->createScopedConnection(rootProducer) :
sf->createConnection();
if (conn != 0) {
mClient = conn;
mStatus = NO_ERROR;
}
}
}
构造方法很简单,只是将mStatus设置为NO_INIT。
重点是在onFirstRef()方法中
- 先调用了
ComposerService的getComposerService()方法来得到一个ISurfaceComposer的指针 - 然后调用它的
createConnection()方法创建一个ISurfaceComposerClient对象 - 然后将
mClient指向这个ISurfaceComposerClient对象
咳咳咳,按照上面的调用流程我们还没有找到关于
IGraphicBufferProducer的信息,现在又多出来了一个ISurfaceComposerClient。。。
好吧好吧,梳理下这部分关系先
WMS中Surface关系总结
上面介绍的WMS中涉及和Surface有关的类关系如下:
看上去就挺复杂的:
SurfaceControl和Surface是成对创建的,考虑到绘制等需求,它们的数量会比较多Session、SurfaceSession和SurfaceComposerClient对象是和连接WMS的用户进程的数量相同SurfaceComposerClient的作用是创建SurfaceSurfaceControl通过SurfaceComposerClient来获取SurfaceSurfaceComposerClient是ComposerService的具体实现类
ComposerService再到SurfaceFlinger
ComposerService是一个单例模式的普通类,定义如下:
class ComposerService : public Singleton<ComposerService>
{
sp<ISurfaceComposer> mComposerService;
sp<IBinder::DeathRecipient> mDeathObserver;
Mutex mLock;
ComposerService();
void connectLocked();
void composerServiceDied();
friend class Singleton<ComposerService>;
public:
static sp<ISurfaceComposer> getComposerService();
};
前面的onFirstRef()方法中调用了ComposerService类的静态方法getComposerService(),我们看下它的实现:
/*static*/ sp<ISurfaceComposer> ComposerService::getComposerService() {
ComposerService& instance = ComposerService::getInstance();
Mutex::Autolock _l(instance.mLock);
if (instance.mComposerService == NULL) {
ComposerService::getInstance().connectLocked();
...
}
return instance.mComposerService;
}
getComposerService()通过调用父类Singleton的getInstance()方法来取得实例对象,然后调用ComposerService的connectLocked()方法:
void ComposerService::connectLocked() {
const String16 name("SurfaceFlinger");
while (getService(name, &mComposerService) != NO_ERROR) {
usleep(250000);
}
...
}
connectLocked()方法中连接了SurfaceFlinger服务对象,然后把对象指针保存到mComposerService中。
ComposerService其实只是SurfaceFlinger的代理,它把SurfaceFlinger服务接口包装了起来
getComposerService()返回的就是mComposerService对象指针,也就是SurfaceFlinger的Binder对象。
前面提到,SurfaceComposerClient对象的onFirstRef()方法中
- 在通过
ComposerService::getComposerService()获得了mComposerService指针后 - 调用了
mComposerService对象的createConnection()方法。 - 按照刚才的逻辑,其实调用是
SurfaceFlinger服务的相关函数接口。
SurfaceFlinger中接口实现如下:
sp<ISurfaceComposerClient> SurfaceFlinger::createConnection() {
return initClient(new Client(this));
}
static sp<ISurfaceComposerClient> initClient(const sp<Client>& client) {
status_t err = client->initCheck();
if (err == NO_ERROR) {
return client;
}
return nullptr;
}
createConnection()函数中创建了一个Client类型对象,然后将其返回给调用者,关于Client类的定义如下:
class Client : public BnSurfaceComposerClient
Client是一个Binder服务类,虽然叫Client。而mComposerService保存的也就是这个服务对象的指针
我们再回到SurfaceControl的创建过程
nativeCreate()方法中调用了SurfaceComposerClient的createSurfaceChecked()方法
status_t SurfaceComposerClient::createSurfaceChecked(...)
{
sp<SurfaceControl> sur;
status_t err = mStatus;
if (mStatus == NO_ERROR) {
sp<IBinder> handle;
sp<IBinder> parentHandle;
sp<IGraphicBufferProducer> gbp;
if (parent != nullptr) {
parentHandle = parent->getHandle();
}
err = mClient->createSurface(name, w, h, format, flags, parentHandle,
windowType, ownerUid, &handle, &gbp);
ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err));
if (err == NO_ERROR) {
*outSurface = new SurfaceControl(this, handle, gbp, true /* owned */);
}
}
return err;
}
createSurfaceChecked()方法
- 先是调用了
SurfaceFlinger::Client对象的createSurface()方法去进行创建操作- 请留意传递的参数,
handle、gbp、parentHandle都是Binder对象sp<IGraphicBufferProducer> gbp就是我们找寻已久的参数。。。。- 这些参数都会在
SurfaceFlinger中进行设置
- 请留意传递的参数,
- 最后确认
SurfaceFlinger::Client对象的createSurface()执行完成没有错误,创建SurfaceControl对象
SurfaceFlinger中创建Surface
SurfaceFlinger::Client对象的createSurface()方法如下:
status_t Client::createSurface(...,
sp<IGraphicBufferProducer>* gbp)
{
...
return mFlinger->createLayer(..., gbp, &parent);
}
调用的是SurfaceFlinger的createLayer()方法,代码如下:
status_t SurfaceFlinger::createLayer(...,
sp<IGraphicBufferProducer>* gbp, sp<Layer>* parent)
{
...
status_t result = NO_ERROR;
sp<Layer> layer;
String8 uniqueName = getUniqueLayerName(name);
// 这里分成了两种创建模式:Normal 和 Color
switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
case ISurfaceComposerClient::eFXSurfaceNormal: // normal
result = createBufferLayer(client,
uniqueName, w, h, flags, format,
handle, gbp, &layer);
break;
case ISurfaceComposerClient::eFXSurfaceColor: // color
result = createColorLayer(client,
uniqueName, w, h, flags,
handle, &layer);
break;
default:
result = BAD_VALUE;
break;
}
...
return result;
}
createLayer()方法按照两种模式进行创建
-
一种是
eFXSurfaceNormal模式,通过createBufferLayer()方法创建,方法如下:status_t SurfaceFlinger::createBufferLayer(..., sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer) { // initialize the surfaces switch (format) { case PIXEL_FORMAT_TRANSPARENT: case PIXEL_FORMAT_TRANSLUCENT: // 透明或半透明设置格式为 RGBA format = PIXEL_FORMAT_RGBA_8888; break; case PIXEL_FORMAT_OPAQUE: // 不透明设置格式为 RGBX format = PIXEL_FORMAT_RGBX_8888; break; } sp<BufferLayer> layer = new BufferLayer(this, client, name, w, h, flags); status_t err = layer->setBuffers(w, h, format, flags); if (err == NO_ERROR) { *handle = layer->getHandle(); // 我们关注的 IGraphicBufferProducer 在这里赋值了 *gbp = layer->getProducer(); *outLayer = layer; } return err; }- 方法中先是确定相应的像素格式,然后创建新的
BufferLayer对象,调用对象的setBuffers()设置宽高和像素格式 Surface中重要的gdp等参数也会在这里进行设置
- 方法中先是确定相应的像素格式,然后创建新的
-
一种是
eFXSurfaceColor模式,通过createColorLayer()方法创建:看参数传入和gdp没啥关系,不用太过关注status_t SurfaceFlinger::createColorLayer(..., sp<IBinder>* handle, sp<Layer>* outLayer) { *outLayer = new ColorLayer(this, client, name, w, h, flags); *handle = (*outLayer)->getHandle(); return NO_ERROR; }- 方法比较简单只是创建了一个
ColorLayer对象,也没有setBuffers()等操作
- 方法比较简单只是创建了一个
我们重点关注eFXSurfaceNormal模式的创建逻辑
终于,我们找到了
sp<IGraphicBufferProducer>* gbp的来源,是通过layer->getProducer()方法
layer->getProducer()方法如下:
sp<IGraphicBufferProducer> BufferLayer::getProducer() const {
return mProducer;
}
layer->getProducer()方法比较简单,只是返回了一个mProducer对象的指针
mProducer对象的创建是在BufferLayer::onFirstRef()方法中
void BufferLayer::onFirstRef() {
Layer::onFirstRef();
// Creates a custom BufferQueue for SurfaceFlingerConsumer to use
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
// 通过 BufferQueue 的 createBufferQueue 方法创建 producer 和 consumer
BufferQueue::createBufferQueue(&producer, &consumer, true);
// 创建 mProducer
mProducer = new MonitoredProducer(producer, mFlinger, this);
...
}
onFirstRef()方法中
- 通过
BufferQueue::createBufferQueue()方法创建producer和consumervoid BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer, sp<IGraphicBufferConsumer>* outConsumer, bool consumerIsSurfaceFlinger) { sp<BufferQueueCore> core(new BufferQueueCore()); sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core, consumerIsSurfaceFlinger)); sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core)); *outProducer = producer; *outConsumer = consumer; } - 利用创建好的
producer对象创建MonitoredProducer对象
MonitoredProducer头文件定义如下:
class MonitoredProducer : public BnGraphicBufferProducer {
public:
MonitoredProducer(const sp<IGraphicBufferProducer>& producer,
const sp<SurfaceFlinger>& flinger,
const wp<Layer>& layer);
virtual ~MonitoredProducer();
...
private:
// 在 BufferLayer 的 onFirstRef() 中通过 BufferQueue::createBufferQueue() 创建
sp<IGraphicBufferProducer> mProducer;
sp<SurfaceFlinger> mFlinger;
wp<Layer> mLayer;
}
虽然MonitoredProducer是一个Binder实体对象,但从业务上来讲它仅仅是个代理
真正管理图像缓冲区的是通过
BufferQueue::createBufferQueue()方法创建的BufferQueueProducer producer对象
终于接近IGraphicBufferProducer的本质了,到这里我们其实可以结束WMS中Surface的创建流程了。先回顾下整个创建流程:
上图分了三部分
- 绿色部分:
Surface和Session的初始化 - 蓝色部分:
ViewRootImpl的setView()中执行performTraversals()- 这部分主要是创建
SurfaceControl对象 - 然后对
Surface对象进行填充 - 从
scheduleTraversals()调用流程来看,这是一个异步过程
- 这部分主要是创建
- 青色部分:
ViewRootImpl的setView()中执行session.addToDisplay()- 这部分主要是创建
SurfaceSession对象 - 在
native层创建SurfaceComposerClient对象
- 这部分主要是创建
需要注意的一点是SurfaceControl对象的创建需要SurfaceSession对象作为参数。但setView()方法中SurfaceSession对象的创建放在了SurfaceControl对象的后面
一开始其实挺疑惑的,核心还是在scheduleTraversals()的异步调用过程,感兴趣的同学可以参考:scheduleTraversals到底做了什么
管理图像缓冲区IGraphicBufferProducer
我们一直强调Surface中最重要的对象是IGraphicBufferProducer,最后我们也找到了它对应的Binder实体对象MonitoredProducer对象
- 对于
MonitoredProducer对象来说,它又关联了一个sp<IGraphicBufferProducer>对象mProducermProducer对象具体的实现类是BufferQueueProducer
前面说Surface像一张画布,那么Surface为什么要和BufferQueue关联呢?
- 对于图像显示设备而言,它的刷新周期是固定的,必须在它需要图像的时候把数据准备好
- 播放动画时,每秒要播放至少
24帧画面才能形成比较真实的动画效果- 而这些图像数据都是
CPU解码得到的,准备它们需要时间
- 而这些图像数据都是
- 播放视频时的每一帧也需要在指定时间播放
- 因此解码器会提前准备好一批数据,这些数据保存在解码器内部的缓冲区中
- 当时间到达时,解码器会把内部缓冲区的图像数据复制到
Surface中 - 但是显示设备并不能立刻把数据取走,因此
Surface需要缓冲区来临时保存数据
BufferQueue操作官方图解如下:
从前面的BufferQueue::createBufferQueue()中可以看出:
MonitoredProducer对象也只是一个代理,真正的业务处理对象是在createBufferQueue()方法中创建的BufferQueueProducer对象- 除此之外方法中还涉及了
BufferQueueCore和BufferQueueConsumer对象的创建
BufferQueue-Core|Producer|Consumer
前面已经介绍,在BufferLayer的onFirstRef()方法中通过BufferQueue::createBufferQueue()方法创建了三个对象:BufferQueueCore、BufferQueueConsumer和BufferQueueProducer
其中
BufferQueueCore是核心,把BufferQueueConsumer和BufferQueueProducer对象连接在了一起
关于BufferQueue的工作方式,官网有个比较直观的叙述,翻译如下:
Consumer创建并拥有BufferQueue数据结构,并且可存在于与其Producer不同的进程中- 当
Producer需要缓冲区时,它会通过调用dequeueBuffer()从BufferQueue请求一个可用的缓冲区,并指定缓冲区的宽度、高度、像素格式和用法标志。 - 然后,
Producer填充缓冲区并通过调用queueBuffer()将缓冲区返回到队列 - 接下来,
Consumer通过acquireBuffer()获取该缓冲区并使用该缓冲区的内容 - 当
Consumer操作完成后,它会通过调用releaseBuffer()将该缓冲区返回到队列
流程较为清晰,我们从源码层面再看下,首先是BufferQueueCore中的关键定义:
class BufferQueueCore : public virtual RefBase {
friend class BufferQueueProducer;
friend class BufferQueueConsumer;
...
private:
BufferQueueDefs::SlotsType mSlots;
}
C++中的friend在这里用来使Producer和Consumer可以访问Core中的成员变量。mSlots是一个64长度的BufferSlot数组,稍后细讲
再看下BufferQueueProducer类的定义:
class BufferQueueProducer : public BnGraphicBufferProducer,
private IBinder::DeathRecipient {
...
private:
sp<BufferQueueCore> mCore;
}
再看看BufferQueueConsumer类的定义:
class BufferQueueConsumer : public BnGraphicBufferConsumer {
...
private:
sp<BufferQueueCore> mCore;
}
不难看出,Producer对象和Consumer对象通过mCore对象连接在一起,查看Producer和Consumer这两个对象的具体方法我们就会发现,很多操作都是直接通过mCore对象的函数来实现的。
Consumer和Producer的接口定义
继续看下BufferQueueConsumer和BufferQueueProducer的基类,分别是BnGraphicBufferProducer和BnGraphicBufferConsumer,定义如下:
class BnGraphicBufferProducer : public BnInterface<IGraphicBufferProducer>
class BnGraphicBufferConsumer : public SafeBnInterface<IGraphicBufferConsumer>
它们主要是实现了两套IGraphicBufferProducer和IGraphicBufferConsumer的Binder接口,主要都是操作BufferQueue的相关接口,定义如下:
IGraphicBufferProducerclass IGraphicBufferProducer : public IInterface { public: ... virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, uint32_t h, PixelFormat format, uint64_t usage, uint64_t* outBufferAge, FrameEventHistoryDelta* outTimestamps) = 0; ... virtual status_t queueBuffer(int slot, const QueueBufferInput& input, QueueBufferOutput* output) = 0; ... virtual status_t connect(const sp<IProducerListener>& listener, int api, bool producerControlledByApp, QueueBufferOutput* output) = 0; virtual status_t disconnect(int api, DisconnectMode mode = DisconnectMode::Api) = 0; ... };BufferQueueProducer类是IGraphicBufferProducer的实现- 使用
Producer相关功能时需要先通过connect()方法建立连接 Producer使用完毕后需要调用disconnect()断开连接
IGraphicBufferConsumerclass IGraphicBufferConsumer : public IInterface { public: ... virtual status_t acquireBuffer(BufferItem* buffer, nsecs_t presentWhen, uint64_t maxFrameNumber = 0) = 0; virtual status_t detachBuffer(int slot) = 0; virtual status_t attachBuffer(int* outSlot, const sp<GraphicBuffer>& buffer) = 0; virtual status_t releaseBuffer(int buf, uint64_t frameNumber, EGLDisplay display, EGLSyncKHR fence, const sp<Fence>& releaseFence) = 0; virtual status_t consumerConnect(const sp<IConsumerListener>& consumer, bool controlledByApp) = 0; virtual status_t consumerDisconnect() = 0; ... };BufferQueueConsumer是接口IGraphicBufferConsumer的实现- 使用
Consumer相关功能时,需通过consumerConnect()方法建立连接- 这里需传入
IConsumerListener对象,这是一个回调接口 - 当数据准备好了就会调用这个对象的
onFrameAvailable()函数来通知Consumer来取数据
- 这里需传入
- 取数据需要调用函数
acquireBuffer() - 使用完数据后,需调用
releaseBuffer()来把缓冲区归还给BufferQueueCore
BufferQueue的状态转换
前面提到BufferQueueCore类中定义了一个64项的数组mSlots:
static constexpr int NUM_BUFFER_SLOTS = 64;
namespace BufferQueueDefs {
typedef BufferSlot SlotsType[NUM_BUFFER_SLOTS];
}
BufferQueueDefs::SlotsType mSlots;
mSlots数组元素类型是BufferSlot,关键定义如下:
struct BufferSlot {
...
sp<GraphicBuffer> mGraphicBuffer;
...
BufferState mBufferState;
...
};
mGraphicBuffer指向图像缓冲区GraphicBuffer的指针GraphicBuffer对应的便是真正的图像缓存数据
mBufferState表示图像缓冲区的状态
BufferState定义如下:
struct BufferState {
uint32_t mDequeueCount;
uint32_t mQueueCount;
uint32_t mAcquireCount;
bool mShared;
}
BufferState中4个变量对应的状态如下:
| 状态\变量 | mShared | mDequeueCount | mQueueCount | mAcquireCount |
|---|---|---|---|---|
FREE | false | 0 | 0 | 0 |
DEQUEUED | false | 1 | 0 | 0 |
QUEUED | false | 0 | 1 | 0 |
ACQUIRED | false | 0 | 0 | 1 |
SHARED | true | any | any | any |
状态之间的转换关系如下:
结合前面提到的接口,我们看下整个状态转换过程的时序图:
到这里,我们已经大体了解了从Surface到SurfaceFlinger的数据通道,dequeueBuffer()等方法的细节就不深入分析了,其中会涉及GraphicBuffer的初始化过程,不影响我们对整体的掌握(主要是太难了。。。。。),不过以下几点需要注意:
GraphicBuffer初始化时便会执行Gralloc模块的allocate()方法申请共享内存缓冲区- 并且在硬件设备支持
FrameBuffer缓冲区的情况下,申请到的就是FrameBuffer的缓冲区
显示原理和Surface相关的内容到此结束了,还有很多不完善的地方,后面再来找补吧(又挖一坑)
关于Android图形显示的学习还剩下SurfaceFlinger和图像输出过程两部分,希望清明节前搞定,(ง •̀_•́)ง