Android系统图形框架
Android系统图形框架由下往上主要的包括HAL(HWComposer和Gralloc两个moudle),SurfaceFlinger(BufferQueue的消费者),WindowManagerService(窗口管理者),View(BufferQueue的生产者)四大模块。
- HAL: 包括HWComposer和Gralloc两个moudle,Android N上由SurfaceFlinger打开,因此在同一进程。 gralloc 用于BufferQueue的内存分配,同时也有fb的显示接口,HWComposer作为合成SurfaceFlinger里面的Layer,并显示(通过gralloc的post函数)
- SurfaceFlinger也叫LayerFlinger,作为Layer的管理着,同是也是BufferQueue的消费者,当每个Layer的生产者draw完完整的一帧时,会通知SurfaceFlinger,通知的方式采用BufferQueue。
- WindowManagerService: 作为Window的管理者,掌管着计算窗口大小,窗口切换等任务,同时也会将相应的参数设置给SurfaceFlinger,比如Window的在z-order,和窗口的大小。
- View: 作为BufferQueue的生产者,没当执行lockCanvas->draw->unlockCanvas,之后会存入一帧数据进入BufferQueue中。
1、低级别组件
- BufferQueue 和 gralloc。
BufferQueue 将可生成图形数据缓冲区的组件(生产者)连接到接受数据以便进行显示或进一步处理的组件(消费者)。通过供应商专用 HAL 接口实现的 gralloc 内存分配器将用于执行缓冲区分配任务。 - SurfaceFlinger、Hardware Composer 和虚拟显示屏。
SurfaceFlinger 接受来自多个源的数据缓冲区,然后将它们进行合成并发送到显示屏。Hardware Composer HAL (HWC) 确定使用可用硬件合成缓冲区的最有效的方法,虚拟显示屏使合成输出可在系统内使用(录制屏幕或通过网络发送屏幕)。 - Surface、Canvas 和 SurfaceHolder。
Surface 可生成一个通常由 SurfaceFlinger 使用的缓冲区队列。当渲染到 Surface 上时,结果最终将出现在传送给消费者的缓冲区中。Canvas API 提供一种软件实现方法(支持硬件加速),用于直接在 Surface 上绘图(OpenGL ES 的低级别替代方案)。与视图有关的任何内容均涉及到 SurfaceHolder,其 API 可用于获取和设置 Surface 参数(如大小和格式)。 - EGLSurface 和 OpenGL ES。
OpenGL ES (GLES) 定义了用于与 EGL 结合使用的图形渲染 API。EGI 是一个规定如何通过操作系统创建和访问窗口的库(要绘制纹理多边形,请使用 GLES 调用;要将渲染放到屏幕上,请使用 EGL 调用)。此页还介绍了 ANativeWindow,它是 Java Surface 类的 C/C++ 等价类,用于通过原生代码创建 EGL 窗口表面。 - Vulkan。
Vulkan 是一种用于高性能 3D 图形的低开销、跨平台 API。与 OpenGL ES 一样,Vulkan 提供用于在应用中创建高质量实时图形的工具。Vulkan 的优势包括降低 CPU 开销以及支持 SPIR-V 二进制中间语言。
1.1 Gralloc
gralloc 用于BufferQueue的内存分配,同时也有fb的显示接口
- gralloc_alloc:用于分配一个显示显示缓冲区,分配好只有会返回缓冲区的handle(缓冲区buffer不会拷贝,所有的操作都是传handle)
static int gralloc_alloc_buffer(alloc_device_t* dev,
size_t size, int /*usage*/, buffer_handle_t* pHandle)
{
int err = 0;
int fd = -1;
size = roundUpToPageSize(size);
fd = ashmem_create_region("gralloc-buffer", size); // 创建匿名共享内存
if (fd < 0) {
ALOGE("couldn't create ashmem (%s)", strerror(-errno));
err = -errno;
}
if (err == 0) {
private_handle_t* hnd = new private_handle_t(fd, size, 0);
gralloc_module_t* module = reinterpret_cast(
dev->common.module);
err = mapBuffer(module, hnd); // 同时将创建好的内存映射进入当前进程,返回handle
if (err == 0) {
*pHandle = hnd;
}
}
return err;
}
- gralloc_free :释放缓冲区内存
- fb_post :更新fb显示
1.2 BufferQueue
- BufferQueue 类是 Android 中所有图形处理操作的核心。它的作用很简单:将生成图形数据缓冲区的一方(生产方)连接到接受数据以进行显示或进一步处理的一方(消耗方)。几乎所有在系统中移动图形数据缓冲区的内容都依赖于 BufferQueue。
- BufferQueue 包含将图像流生产方与图像流消耗方结合在一起的逻辑。图像生产方的一些示例包括由相机 HAL 或 OpenGL ES 游戏生成的相机预览。图像消耗方的一些示例包括 SurfaceFlinger 或显示 OpenGL ES 流的另一个应用,如显示相机取景器的相机应用。
- BufferQueue 永远不会复制缓冲区内容(移动如此多的数据是非常低效的操作)。相反,缓冲区始终通过句柄进行传递。
-
生产方和消耗方可以存在于不同的进程中。目前,消耗方始终创建和拥有数据结构。在旧版本的 Android 中,只有生产方才进行 Binder 处理(即生产方可能在远程进程中,但消耗方必须存在于创建队列的进程中)。Android 4.4 和更高版本已发展为更常规的实现。
1.3 BufferQueue生产者与消费者分析
当应用add一个window到WMS时,WMS会调用SurfaceFlinger为这个window创建一个BufferQueue,BufferQueue的消费者留在了SurfaceFlinger中,而生产者会返回到View中,View中采用Canvas或者GL绘图,用于消费者
// ViewRootImpl.java
private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
boolean insetsPending) throws RemoteException {
int relayoutResult = mWindowSession.relayout(
mWindow, mSeq, params,
(int) (mView.getMeasuredWidth() * appScale + 0.5f),
(int) (mView.getMeasuredHeight() * appScale + 0.5f),
viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingConfiguration,
mSurface);
}
其中的
mWindow即每个应用窗口所创建的window,和ActivityRecord、DecorView一一对应
mSurface即为当前这个Layer的BufferQueue生产者
void Layer::onFirstRef() {
// Creates a custom BufferQueue for SurfaceFlingerConsumer to use
sp producer;
sp consumer;
BufferQueue::createBufferQueue(&producer, &consumer);
mProducer = new MonitoredProducer(producer, mFlinger);
mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(consumer, mTextureName,
this);
mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
mSurfaceFlingerConsumer->setContentsChangedListener(this);
mSurfaceFlingerConsumer->setName(mName);
#ifdef TARGET_DISABLE_TRIPLE_BUFFERING
#warning "disabling triple buffering"
#else
mProducer->setMaxDequeuedBufferCount(2);
#endif
const sp hw(mFlinger->getDefaultDisplayDevice());
updateTransformHint(hw);
}
createBufferQueue即为创建BufferQueue的地方,同时通过setContentsChangedListener将this注册到消费者中去,当生产者mSurface有新的帧生成后,会通知到Layer中的onFrameAvailable
// Layer.cpp
void Layer::onFrameAvailable(const BufferItem& item) {
// Add this buffer from our internal queue tracker
{ // Autolock scope
Mutex::Autolock lock(mQueueItemLock);
mQueueItems.push_back(item);
android_atomic_inc(&mQueuedFrames);
// Wake up any pending callbacks
mLastFrameNumberReceived = item.mFrameNumber;
mQueueItemCondition.broadcast();
}
mFlinger->signalLayerUpdate();
}
2、 SurfaceFlinger
- 管理Layer的创建与销毁,同时单个Layer又要接收来自WMS的设置参数(setLayer, setPosition , setSize setAlpha, createLayer, removeLayer等)
- Layer的可见区域计算,合成Layer
- 渲染合成图像到fb
- 管理VSYNC信号
-
创建BufferQueue用于SurfaceFlinger的缓冲区
2.1 创建BufferQueue用于SurfaceFlinger中的缓冲区(非Layer中的BufferQueue)
void SurfaceFlinger::init() {
for (size_t i=0 ; i token = mBuiltinDisplays[i];
sp producer;
sp consumer;
BufferQueue::createBufferQueue(&producer, &consumer,
new GraphicBufferAlloc()); // 创建BufferQueue
sp fbs = new FramebufferSurface(*mHwc, i,
consumer); // 消费者放入FramebufferSurface
int32_t hwcId = allocateHwcDisplayId(type);
sp hw = new DisplayDevice(this,
type, hwcId, mHwc->getFormat(hwcId), isSecure, token,
fbs, producer,
mRenderEngine->getEGLConfig()); // 生产者是DisplayDevice,本质是合成只有的图像
if (i > DisplayDevice::DISPLAY_PRIMARY) {
ALOGD("marking display %zu as acquired/unblanked", i);
hw->setPowerMode(HWC_POWER_MODE_NORMAL);
}
mDisplays.add(token, hw);
}
}
2.2 Layer更新
前面讲BufferQueue时,每当Layer中有新的buffer准备好了,一定会通知相应Layer的onFrameAvailable,从而通过signalLayerUpdate通知SurfaceFlinger,这就是开始处理Layer的入口
void SurfaceFlinger::signalLayerUpdate() {
mEventQueue.invalidate();
}
void MessageQueue::invalidate() {
mEvents->requestNextVsync();
}
但是onMessageReceived并不会立即收到消息去执行handleMessageTransaction、handleMessageRefresh,而是等到下一个VSYNC信号到来
void SurfaceFlinger::onMessageReceived(int32_t what) {
ATRACE_CALL();
switch (what) {
case MessageQueue::INVALIDATE: {
bool refreshNeeded = handleMessageTransaction();
refreshNeeded |= handleMessageInvalidate();
refreshNeeded |= mRepaintEverything;
if (refreshNeeded) {
// Signal a refresh if a transaction modified the window state,
// a new buffer was latched, or if HWC has requested a full
// repaint
signalRefresh();
}
break;
}
case MessageQueue::REFRESH: {
handleMessageRefresh();
break;
}
}
}
2.3 VSYNC信号
-
SurfaceFlinger负责在收到的硬件VSYNC信号,通知EventThread,EventThread存放着所有注册过的Connection,只要有Connection存在,就会触发相应的事件,Looper中会响应事件并回调
-
Choreographer的VSYNC信号和SurfaceFlinger接收VSYNC信号原理一样,都是通过注册一个Connection监听事件
2.4 Layer可见性计算与合成显示
void SurfaceFlinger::handleMessageRefresh() {
ATRACE_CALL();
nsecs_t refreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
preComposition(); //
rebuildLayerStacks(); // 计算可见区域,主要的依据就是z-order大的覆盖有重叠区域z-order小的
setUpHWComposer();
doDebugFlashRegions();
doComposition(); // 合成图像,并调用swapBuffers,这样消费者FramebufferSurface就会被回调onFrameAvailable
postComposition(refreshStartTime);
}
消费者FramebufferSurface收到onFrameAvailable后就会将新的图像post到fb(通过gralloc的post函数)
// Overrides ConsumerBase::onFrameAvailable(), does not call base class impl.
void FramebufferSurface::onFrameAvailable(const BufferItem& /* item */) {
sp buf;
sp acquireFence;
status_t err = nextBuffer(buf, acquireFence);
if (err != NO_ERROR) {
return;
}
err = mHwc.fbPost(mDisplayType, acquireFence, buf); // 调用gralloc的post
}
3、WindowManagerService框架
职责
计算窗口大小
计算窗口Z轴位置
管理输入法窗口
管理壁纸窗口
执行窗口切换
3.1 addWindow
在Activity的启动中当执行到performLaunchActivity
// ActivityThread.java
final void handleResumeActivity(IBinder token,
boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
ActivityClientRecord r = mActivities.get(token);
r = performResumeActivity(token, clearHide, reason);
if (r != null) {
final Activity a = r.activity;
boolean willBeVisible = !a.mStartedActivity;
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow(); // Window指的是PhoneWindow,在performLaunchActivity中attch函数中创建
View decor = r.window.getDecorView(); // decor是在onCreate中用户主动调用setContentView时创建
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager(); // 实质是ViewManagerImpl
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION; //APP的type都是TYPE_BASE_APPLICATION
l.softInputMode |= forwardBit;
if (r.mPreserveWindow) {
a.mWindowAdded = true;
r.mPreserveWindow = false;
// Normally the ViewRoot sets up callbacks with the Activity
// in addView->ViewRootImpl#setView. If we are instead reusing
// the decor view we have to notify the view root that the
// callbacks may have changed.
ViewRootImpl impl = decor.getViewRootImpl();
if (impl != null) {
impl.notifyChildRebuilt();
}
}
if (a.mVisibleFromClient && !a.mWindowAdded) {
a.mWindowAdded = true;
wm.addView(decor, l); // 向WindowManagerGlobal中添加当前Activity的DecorView
}
}
decor是在onCreate中用户主动调用setContentView时创建
Window指的是PhoneWindow,在performLaunchActivity中attch函数中创建
ActivityClientRecord是在App进程中的和AMS中的ActivityRecord一一对应的对象
WindowManagerGlobal.java
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
if (parentWindow != null) {
parentWindow.adjustLayoutParamsForSubWindow(wparams);
} else {
}
ViewRootImpl root;
View panelParentView = null;
synchronized (mLock) {
// Start watching for system property changes.
if (mSystemPropertyUpdater == null) {
mSystemPropertyUpdater = new Runnable() {
@Override public void run() {
synchronized (mLock) {
for (int i = mRoots.size() - 1; i >= 0; --i) {
mRoots.get(i).loadSystemProperties();
}
}
}
};
SystemProperties.addChangeCallback(mSystemPropertyUpdater);
}
int index = findViewLocked(view, false);
if (index >= 0) {
if (mDyingViews.contains(view)) {
// Don't wait for MSG_DIE to make it's way through root's queue.
mRoots.get(index).doDie();
} else {
throw new IllegalStateException("View " + view
+ " has already been added to the window manager.");
}
// The previous removeView() had not completed executing. Now it has.
}
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
}
root.setView(view, wparams, panelParentView);
}
可以看出WindowManagerGlobal是管理view(DecorView),ViewRootImpl,参数的管家,他们都是一对一的关系
ViewRootImpl.java
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
}
}
开始向WMS添加当前mWindow(W),mWindow继承于IWindow.Stub,也是个binder的对象,WMS可以通过这个binder回调ViewRootImpl
WindowManagerService.java
public int addWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
InputChannel outInputChannel) {
boolean addToken = false;
WindowToken token = mTokenMap.get(attrs.token);
AppWindowToken atoken = null;
boolean addToastWindowRequiresToken = false;
...
WindowState win = new WindowState(this, session, client, token,
attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
mPolicy.adjustWindowParamsLw(win.mAttrs); // new 一个新的WindowState
win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));
res = mPolicy.prepareAddWindowLw(win, attrs);
if (res != WindowManagerGlobal.ADD_OKAY) {
return res;
}
final boolean openInputChannels = (outInputChannel != null
&& (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
if (openInputChannels) {
// 创建一个Input的双向进程间管道,并将read端的fd通过outInputChannel返回,用于ViewRootImpl中创建Input的监听Receiver,管道的write端registerInputChannel注册进入了InputDispatcher,然后加入了InputDispatcher线程的Looper,用于发送事件信号
// 这就成功的建立了InputDispatcher与当前应用ViewRootImpl进程间双向通讯
win.openInputChannel(outInputChannel);
}
if (addToken) {
mTokenMap.put(attrs.token, token);
}
win.attach();
mWindowMap.put(client.asBinder(), win); // 将创建的WindowState存入WMS
if (focusChanged) {
mInputMonitor.setInputFocusLw(mCurrentFocus, false /*updateInputWindows*/); // 检查焦点窗口是否发生变化,如果发生了变化就要通知InputDispatcher更新焦点窗口
}
mInputMonitor.updateInputWindowsLw(false /*force*/); // 将WMS中所有的InputWindowHandles都更新到InputDispatcher中去,方便InputDispatcher根据触摸坐标寻找相应的window
3.2 relayoutWindow
ViewRootImpl.java
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
scheduleTraversals()中利用Choreographer向SurfaceFlinger注册一个vsync信号接收回调,收到回调后会执行performTraversals(),这个函数是对view进行measure,layout,draw的核心函数,当执行performTraversals时发生以下条件事会调用WMS的relayoutWindow,通知WMS window发生的变化
- 第一次performTraversals调用的时候
- 当window需要resize(改变尺寸)的时候
- view可见性发生变化时
- 其他一些条件
ViewRootImpl.java
private void performTraversals() {
if (mFirst || windowShouldResize || insetsChanged ||
viewVisibilityChanged || params != null || mForceNextWindowRelayout) {
relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
}
}
3.3 SurfaceFlinger Z order顺序确定
openGlobalTransaction --> setLayer --> closeGlobalTransaction -->closeGlobalTransactionImpl --> setTransactionState --> setClientStateLocked --> mCurrentState.layersSortedByZ.add
layersSortedByZ是一个LayerVector的结构,继承于SortedVector,在add的同时会用二分法则排序插入
Z order 的值越大显示越靠前,但是最终显示的判定还要结合layer的可见区域Region visibleRegion来显示,一般情况可见区域只有Navgation Bar + Status Bar + Activity,有些软件播放视频会全屏,那么Navgation Bar + Status Bar 也就不可见了
SurfaceComposerClient::openGlobalTransaction();
control->setLayer(0x40000000);
SurfaceComposerClient::closeGlobalTransaction();
4、 窗口(Window)的结构
ViewRootImpl是一个虚拟根View,用来控制窗口的渲染,以及用来与WindowManagerService、SurfaceFlinger通信
DecorView是窗口的真正根View,用户在Activity的onCreate中setContentView中创建
ContentView描述窗口的主题风格
4.1 ViewRootImpl
Window的虚拟根View,一个Aactivity对应一个DecorView,对应一个ActivityClientRecord,对应一个ViewRootImpl,ViewRootImpl的作用:
与WMS交互:将window(W:继承于IWindow.Stub)加入到WMS(addToDispaly)
与SurfaceFlinger交互: 因为ViewRootImpl中layout,measure,draw是Surface的的生产者,因此当draw完成以后SurfaceFlinger回取出相应的buffer进行合成显示
注册一个InputEventReceiver :基于WMS返回的InputChannel创建一个Callback,用于监听输入事件mInputEventReceiver一旦被创建,就已经在监听输入事件了
performTraversals() : 执行画图三个重要操作measure,layout,draw,主要是在scheduleTraversals()中用Choreographer注册系统刷新下一帧回调。
Choreographer:当window有任何改变的时候就会利用Choreographer注册一个vsync信号回调,比如尺寸,参数变化,可见性变化,范围改变,保证显示实时更新
5、参考
SurfaceFlinger Z order顺序确定