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中。
圖片.png
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<gralloc_module_t*>(
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 和更高版本已發展為更常規的實現。
圖片.png
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<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> 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<const DisplayDevice> 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的緩沖區
圖片.png
2.1 創建BufferQueue用于SurfaceFlinger中的緩沖區(非Layer中的BufferQueue)
void SurfaceFlinger::init() {
for (size_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
wp<IBinder> token = mBuiltinDisplays[i];
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
BufferQueue::createBufferQueue(&producer, &consumer,
new GraphicBufferAlloc()); // 創建BufferQueue
sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, i,
consumer); // 消費者放入FramebufferSurface
int32_t hwcId = allocateHwcDisplayId(type);
sp<DisplayDevice> 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中會響應事件并回調
圖片.png -
Choreographer的VSYNC信號和SurfaceFlinger接收VSYNC信號原理一樣,都是通過注冊一個Connection監聽事件
圖片.png
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<GraphicBuffer> buf;
sp<Fence> 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信號回調,比如尺寸,參數變化,可見性變化,范圍改變,保證顯示實時更新