http://androidxref.com/6.0.1_r10/xref/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
http://androidxref.com/6.0.1_r10/xref/frameworks/base/core/java/android/view/WindowManagerImpl.java
http://androidxref.com/6.0.1_r10/xref/frameworks/base/core/java/android/view/WindowManagerGlobal.java
http://androidxref.com/6.0.1_r10/xref/frameworks/base/core/java/android/view/ViewRootImpl.java
http://androidxref.com/6.0.1_r10/xref/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
http://androidxref.com/6.0.1_r10/xref/frameworks/base/services/core/java/com/android/server/wm/Session.java
http://androidxref.com/6.0.1_r10/xref/frameworks/base/core/java/android/view/IWindow.aidl
WindowManagerService只負責窗口管理,並不負責View的繪制跟圖層混合,本文就來分析WMS到底是怎么管理窗口的。初接觸Android時感覺:Activity似乎就是Google封裝好的窗口,APP只要合理的啟動新的Activity就打開了新窗口,這樣理解沒什么不對,Activity確實可以看做一種窗口及View的封裝,不過從源碼來看,Activity跟Window還是存在不同。本文主要從窗口的添加流程來將APP端、WMS端、SurfaceFlinger端三塊串聯起來,主要說一下幾個方面
- 窗口的分類:Activity、Dialog、PopupWindow、Toast等對應窗口的區別
- Window、IWindow 、WindowState、WindowToken、AppToken等之間的關系
- 窗口的添加及Surface申請與Binder傳遞
窗口的分類簡述
在Android系統中,PopupWindow、Dialog、Activity、Toast等都有窗口的概念,但又各有不同,Android將窗口大致分為三類:應用窗口、子窗口、系統窗口。其中,Activity與Dialog屬於應用窗口、PopupWindow屬於子窗口,必須依附到其他非子窗口才能存在,而Toast屬於系統窗口,Dialog可能比較特殊,從表現上來說偏向於子窗口,必須依附Activity才能存在,但是從性質上來說,仍然是應用窗口,有自己的WindowToken,不同窗口之間的關系后面會更加詳細的分析,這里有一個概念即可。
窗口的添加
Activity並不是View展示的唯一方式,分析窗口添加流程的話,Activity也並不是最好的例子,因為Activity還會牽扯到AMS的知識,這里我們不用Activity,而是用一個懸浮View的展示來分析窗口的添加,代碼入下:
private void addTextViewWindow(Context context){ TextView mview=new TextView(context); ...//設置顏色 樣式 //關鍵點1 WindowManager mWindowManager = (WindowManager) context.getApplicationContext().getSystemService(Context.WINDOW_SERVICE); WindowManager.LayoutParams wmParams = new WindowManager.LayoutParams(); //關鍵點2 wmParams.type = WindowManager.LayoutParams.TYPE_TOAST; wmParams.format = PixelFormat.RGBA_8888; wmParams.width = 800; wmParams.height = 800; //關鍵點3 mWindowManager.addView(mview, wmParams); }
@Override public Object getSystemService(String name) { return SystemServiceRegistry.getSystemService(this, name); }
SystemServiceRegistry類用靜態字段及方法中封裝了一些服務的代理,其中就包括WindowManagerService
public static Object getSystemService(ContextImpl ctx, String name) { ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name); return fetcher != null ? fetcher.getService(ctx) : null; } static { ... registerService(Context.WINDOW_SERVICE, WindowManager.class, new CachedServiceFetcher<WindowManager>() { @Override public WindowManager createService(ContextImpl ctx) { return new WindowManagerImpl(ctx.getDisplay()); }}); ... }
因此context.getApplicationContext().getSystemService()最終可以簡化為new WindowManagerImpl(ctx.getDisplay()),下面看下WindowManagerImpl的構造方法,它有兩個實現方法,對於Activity跟Application其實是有區別的,這點后面分析:
http://androidxref.com/6.0.1_r10/xref/frameworks/base/core/java/android/view/WindowManagerImpl.java
public WindowManagerImpl(Display display) { this(display, null); } private WindowManagerImpl(Display display, Window parentWindow) { mDisplay = display; mParentWindow = parentWindow; }
@Override public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) { applyDefaultToken(params); mGlobal.addView(view, params, mDisplay, mParentWindow); }
不過很明顯WindowManagerImpl最后是委托mGlobal來進行這項操作,WindowManagerGlobal是一個單利,一個進程只有一個:
接着看WindowManagerGlobal的addView,對於添加系統窗口,這里將將代碼精簡一下,不關系子窗口等之類的邏輯public void addView(View view, ViewGroup.LayoutParams params, //... final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params; if (parentWindow != null) { parentWindow.adjustLayoutParamsForSubWindow(wparams); } else { // If there's no parent, then hardware acceleration for this view is // set from the application's hardware acceleration setting. final Context context = view.getContext(); if (context != null && (context.getApplicationInfo().flags & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) { wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; } } ViewRootImpl root; View panelParentView = null; synchronized (mLock) { //... root = new ViewRootImpl(view.getContext(), display); view.setLayoutParams(wparams); mViews.add(view); mRoots.add(root); mParams.add(wparams); } // do this last because it fires off messages to start doing things try { root.setView(view, wparams, panelParentView); } catch (RuntimeException e) { //... } }
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { synchronized (this) { if (mView == null) { mView = view; ... //關鍵點1 // Schedule the first layout -before- adding to the window // manager, to make sure we do the relayout before receiving // any other events from the system. requestLayout(); if ((mWindowAttributes.inputFeatures & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) { mInputChannel = new InputChannel(); } try { //關鍵點2 res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mAttachInfo.mOutsets, mInputChannel); } catch (RemoteException e) { ... } }
public ViewRootImpl(Context context, Display display) { mContext = context; mWindowSession = WindowManagerGlobal.getWindowSession(); mWindow = new W(this); }

static class W extends IWindow.Stub { private final WeakReference<ViewRootImpl> mViewAncestor; private final IWindowSession mWindowSession; W(ViewRootImpl viewAncestor) { mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor); mWindowSession = viewAncestor.mWindowSession; } @Override public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw, Configuration newConfig) { final ViewRootImpl viewAncestor = mViewAncestor.get(); if (viewAncestor != null) { viewAncestor.dispatchResized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets, outsets, reportDraw, newConfig); } } @Override public void moved(int newX, int newY) { final ViewRootImpl viewAncestor = mViewAncestor.get(); if (viewAncestor != null) { viewAncestor.dispatchMoved(newX, newY); } } @Override public void dispatchAppVisibility(boolean visible) { final ViewRootImpl viewAncestor = mViewAncestor.get(); if (viewAncestor != null) { viewAncestor.dispatchAppVisibility(visible); } } @Override public void dispatchGetNewSurface() { final ViewRootImpl viewAncestor = mViewAncestor.get(); if (viewAncestor != null) { viewAncestor.dispatchGetNewSurface(); } } @Override public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) { final ViewRootImpl viewAncestor = mViewAncestor.get(); if (viewAncestor != null) { viewAncestor.windowFocusChanged(hasFocus, inTouchMode); } } private static int checkCallingPermission(String permission) { try { return ActivityManagerNative.getDefault().checkPermission( permission, Binder.getCallingPid(), Binder.getCallingUid()); } catch (RemoteException e) { return PackageManager.PERMISSION_DENIED; } } @Override public void executeCommand(String command, String parameters, ParcelFileDescriptor out) { final ViewRootImpl viewAncestor = mViewAncestor.get(); if (viewAncestor != null) { final View view = viewAncestor.mView; if (view != null) { if (checkCallingPermission(Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Insufficient permissions to invoke" + " executeCommand() from pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()); } OutputStream clientStream = null; try { clientStream = new ParcelFileDescriptor.AutoCloseOutputStream(out); ViewDebug.dispatchCommand(view, command, parameters, clientStream); } catch (IOException e) { e.printStackTrace(); } finally { if (clientStream != null) { try { clientStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } } } @Override public void closeSystemDialogs(String reason) { final ViewRootImpl viewAncestor = mViewAncestor.get(); if (viewAncestor != null) { viewAncestor.dispatchCloseSystemDialogs(reason); } } @Override public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep, boolean sync) { if (sync) { try { mWindowSession.wallpaperOffsetsComplete(asBinder()); } catch (RemoteException e) { } } } @Override public void dispatchWallpaperCommand(String action, int x, int y, int z, Bundle extras, boolean sync) { if (sync) { try { mWindowSession.wallpaperCommandComplete(asBinder(), null); } catch (RemoteException e) { } } } /* Drag/drop */ @Override public void dispatchDragEvent(DragEvent event) { final ViewRootImpl viewAncestor = mViewAncestor.get(); if (viewAncestor != null) { viewAncestor.dispatchDragEvent(event); } } @Override public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility, int localValue, int localChanges) { final ViewRootImpl viewAncestor = mViewAncestor.get(); if (viewAncestor != null) { viewAncestor.dispatchSystemUiVisibilityChanged(seq, globalVisibility, localValue, localChanges); } } @Override public void onAnimationStarted(int remainingFrameCount) { final ViewRootImpl viewAncestor = mViewAncestor.get(); if (viewAncestor != null) { viewAncestor.dispatchWindowAnimationStarted(remainingFrameCount); } } @Override public void onAnimationStopped() { final ViewRootImpl viewAncestor = mViewAncestor.get(); if (viewAncestor != null) { viewAncestor.dispatchWindowAnimationStopped(); } } @Override public void dispatchWindowShown() { final ViewRootImpl viewAncestor = mViewAncestor.get(); if (viewAncestor != null) { viewAncestor.dispatchWindowShown(); } } }
public static IWindowSession getWindowSession() { synchronized (WindowManagerGlobal.class) { if (sWindowSession == null) { try { InputMethodManager imm = InputMethodManager.getInstance(); //關鍵點1 IWindowManager windowManager = getWindowManagerService(); //關鍵點2 sWindowSession = windowManager.openSession( new IWindowSessionCallback.Stub() { @Override public void onAnimatorScaleChanged(float scale) { ValueAnimator.setDurationScale(scale); } }, imm.getClient(), imm.getInputContext()); } catch (RemoteException e) { Log.e(TAG, "Failed to open window session", e); } } return sWindowSession; } }

public static IWindowManager getWindowManagerService() { synchronized (WindowManagerGlobal.class) { if (sWindowManagerService == null) { sWindowManagerService = IWindowManager.Stub.asInterface( ServiceManager.getService("window")); try { sWindowManagerService = getWindowManagerService(); ValueAnimator.setDurationScale(sWindowManagerService.getCurrentAnimatorScale()); } catch (RemoteException e) { Log.e(TAG, "Failed to get WindowManagerService, cannot set animator scale", e); } } return sWindowManagerService; } }
@Override public IWindowSession openSession(IWindowSessionCallback callback, IInputMethodClient client, IInputContext inputContext) { if (client == null) throw new IllegalArgumentException("null client"); if (inputContext == null) throw new IllegalArgumentException("null inputContext"); Session session = new Session(this, callback, client, inputContext); return session; }
到這里看到如何獲取Session,下面就是利用Session來add一個窗口:其實是調用Session.java的addToDisplayWithoutInputChannel函數
final class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { //... @Override public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, InputChannel outInputChannel) { return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outContentInsets, outStableInsets, outOutsets, outInputChannel); } }
在WindowManager的LayoutParams中,與type同等重要的還有token。
上面說到:在源碼中token一般代表的是Binder對象,作用於IPC進程間數據通訊。並且它也包含着此次通訊所需要的信息,在ViewRootImpl里,token用來表示mWindow(W類,即IWindow),並且在WmS中只有符合要求的token才能讓Window正常顯示。
如此一來,Window的添加請求就交給WmS去處理了,在WmS內部會為每一個應用保留一個單獨的Session。在WmS 端會創建一個WindowState對象用來表示當前添加的窗口。 WmS負責管理這里些 WindowState 對象。至此,Window的添加過程就結束了。
至於Window的刪除和更新過程,舉一反三,也是使用WindowManagerGlobal對ViewRootImpl的操作,最終也是通過Session的IPC跨進程通信通知到WmS。整個過程的本質都是同出一轍的。
在WMS中addWindow又做了什么呢,就像名字寫的,負責添加一個窗口,代碼精簡后如下:
public int addWindow(Session session, IWindow client, int seq, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, InputChannel outInputChannel) { ... synchronized(mWindowMap) { ... //關鍵點1 不能重復添加 if (mWindowMap.containsKey(client.asBinder())) { return WindowManagerGlobal.ADD_DUPLICATE_ADD; } //關鍵點2 對於子窗口類型的處理 1、必須有父窗口 2,父窗口不能是子窗口類型 if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) { parentWindow = windowForClientLocked(null, attrs.token, false); if (parentWindow == null) { return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN; } if (parentWindow.mAttrs.type >= FIRST_SUB_WINDOW && parentWindow.mAttrs.type <= LAST_SUB_WINDOW) { return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN; }} ... boolean addToken = false; //關鍵點3 根據IWindow 獲取WindowToken WindowToken是窗口分組的基礎,每個窗口必定有一個分組- WindowToken token = mTokenMap.get(attrs.token); //關鍵點4對於Toast類系統窗口,其attrs.token可以看做是null, 如果目前沒有其他的類似系統窗口展示,token仍然獲取不到,仍然要走新建流程 if (token == null) { ... token = new WindowToken(this, attrs.token, -1, false); addToken = true; } ... //關鍵點5 新建WindowState,WindowState與窗口是一對一的關系,可以看做是WMS中與窗口的抽象實體 WindowState win = new WindowState(this, session, client, token, attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent); ... if (addToken) { mTokenMap.put(attrs.token, token); } win.attach(); mWindowMap.put(client.asBinder(), win); ... //關鍵點6 addWindowToListInOrderLocked(win, true); return res; }
這里有幾個概念需要先了解下:
- IWindow:APP端窗口暴露給WMS的抽象實例,在ViewRootImpl中實例化,與ViewRootImpl一一對應,同時也是WMS向APP端發送消息的Binder通道。
- WindowState:WMS端窗口的令牌,與IWindow,或者說與窗口一一對應,是WMS管理窗口的重要依據。
- WindowToken:窗口的令牌,其實也可以看做窗口分組的依據,在WMS端,與分組對應的數據結構是WindowToken(窗口令牌),而與組內每個窗口對應的是WindowState對象,每塊令牌(AppWindowToken、WindowToken)都對應一組窗口(WindowState),Activity與Dialog對應的是AppWindowToken,PopupWindow對應的是普通的WindowToken。
- AppToken:其實是ActivityRecord里面的IApplicationToken.Stub appToken 代理,也是ActivityClientRecord里面的token,可以看做Activity在其他服務(非AMS)的抽象

那么接着
關鍵點1:一個窗口不能被添加兩次,IWindow是一個Binder代理,在WMS端,一個窗口只會有一個IWindow代理,這是由Binder通信機制保證的,這個對象不能被添加兩次,否則會報錯。
關鍵點2,如果是子窗口的話,父窗口必須已被添加,由於我們分析的是系統Toast窗口,可以先不用關心;
關鍵點3,WindowManager.LayoutParams中有一個token字段,該字段標志着窗口的分組屬性,比如Activity及其中的Dialog是復用用一個AppToken,Activity里的PopupWindow復用一個IWindow類型Token,其實就是Activity的ViewRootImpl里面創建的IWindow,而對於我們現在添加的Toast類系統窗口,並未設置其attrs.token,那即是null,其實所有的Toast類系統窗口的attrs.token都可以看做null,就算不是null,也會在WMS被強制設置為null。所以Toast類系統窗口必定復用一個WindowToken,也可以說所有的Toast類系統窗口都是位於同一分組,這也是因為該類型系統窗口太常用,而且為所有進程服務,直接用一個WindowToken管理更加快捷,畢竟快速新建與釋放WindowToken也算是一種開銷。假設到我們添加系統窗口的時候,沒有任何系統窗口展示,是獲取不到key=null的WindowToken的,要新建WindowToken,並且添加到全局的TokenMap中,
而關鍵點5,其實就是新建窗口在WMS端的抽象實例:WindowState,它同窗口一一對應,詳細記錄了窗口的參數、Z順序、狀態等各種信息,新建只有會被放入全局的Map中,同時也會被附加到相應的WindowToken分組中去,到這里APP端向WMS注冊窗口的流程就算走完了,不過只算完成了前半部分,WMS還需要向SurfaceFlinger申請Surface,才算完成真正的分配了窗口。在向SurfaceFlinger申請Surface之前,WMS端需要獲得SF的代理,在WindowState對象創建后會利用 win.attach()函數為當前APP申請建立SurfaceFlinger的鏈接:
void attach() { if (WindowManagerService.localLOGV) Slog.v( mSession.windowAddedLocked(); } void windowAddedLocked() { if (mSurfaceSession == null) { // SurfaceSession新建 mSurfaceSession = new SurfaceSession(); mService.mSessions.add(this); ... } mNumWindow++; }
可以看到SurfaceSession對於Session來說是單利的,也就是與APP的Seesion一一對應,SurfaceSession所握着的SurfaceFlinger的代理其實就是SurfaceComposerClient,其實現如下:
public SurfaceSession() { mNativeClient = nativeCreate(); } static jlong nativeCreate(JNIEnv* env, jclass clazz) { SurfaceComposerClient* client = new SurfaceComposerClient(); client->incStrong((void*)nativeCreate); return reinterpret_cast<jlong>(client); }

SurfaceComposerClient::SurfaceComposerClient() : mStatus(NO_INIT), mComposer(Composer::getInstance()) { } // 單利的,所以只有第一次的時候采用 void SurfaceComposerClient::onFirstRef() { sp<ISurfaceComposer> sm(ComposerService::getComposerService()); if (sm != 0) { sp<ISurfaceComposerClient> conn = sm->createConnection(); if (conn != 0) { mClient = conn; mStatus = NO_ERROR; } } } sp<ISurfaceComposerClient> SurfaceFlinger::createConnection() { sp<ISurfaceComposerClient> bclient; sp<Client> client(new Client(this)); status_t err = client->initCheck(); if (err == NO_ERROR) { bclient = client; } return bclient; }
void scheduleTraversals() { if (!mTraversalScheduled) { mTraversalScheduled = true; //關鍵點1 添加塞子 mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier(); //關鍵點2 添加異步消息任務 mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); ...
private void performTraversals() { final View host = mView; ... if (mFirst || windowShouldResize || insetsChanged || viewVisibilityChanged || params != null) { //關鍵點1 申請Surface或者重新設置參數 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending); //關鍵點2 測量 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); } //關鍵點3 布局 performLayout(lp, desiredWindowWidth, desiredWindowHeight); //關鍵點4 更新window try { mWindowSession.setInsets(mWindow, insets.mTouchableInsets, contentInsets, visibleInsets, touchableRegion); ... //關鍵點5 繪制 performDraw(); ... }
private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility, boolean insetsPending) throws RemoteException { ... int relayoutResult = mWindowSession.relayout( mWindow, mSeq, params, ... mSurface); ... return relayoutResult; }
public int relayoutWindow(Session session, IWindow client, int seq,... Surface outSurface) { WindowState win = windowForClientLocked(session, client, false); WindowStateAnimator winAnimator = win.mWinAnimator; //關鍵點1 SurfaceControl surfaceControl = winAnimator.createSurfaceLocked(); if (surfaceControl != null) { //關鍵點2 outSurface.copyFrom(surfaceControl); } else { outSurface.release(); }
static jlong nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj, jstring nameStr, jint w, jint h, jint format, jint flags) { ScopedUtfChars name(env, nameStr); //關鍵點1 sp<SurfaceComposerClient> client(android_view_SurfaceSession_getClient(env, sessionObj)); //關鍵點2 sp<SurfaceControl> surface = client->createSurface( String8(name.c_str()), w, h, format, flags); surface->incStrong((void *)nativeCreate); return reinterpret_cast<jlong>(surface.get()); }
關鍵點1是取到SurfaceSession對象中SurfaceComposerClient對象,之后調用SurfaceComposerClient的createSurface方法進一步創建SurfaceControl,
sp<SurfaceControl> SurfaceComposerClient::createSurface( const String8& name, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags) { sp<SurfaceControl> sur; if (mStatus == NO_ERROR) { sp<IBinder> handle; sp<IGraphicBufferProducer> gbp; //關鍵點1 獲取圖層的關鍵信息handle, gbp status_t err = mClient->createSurface(name, w, h, format, flags, &handle, &gbp); //關鍵點2 根據返回的圖層關鍵信息 創建SurfaceControl對象 if (err == NO_ERROR) { sur = new SurfaceControl(this, handle, gbp); } } return sur; }
status_t Client::createSurface( const String8& name, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags, sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp){ ... //關鍵點2 這里並未直接創建 ,而是通過發送了一個MessageCreateLayer消息 sp<MessageBase> msg = new MessageCreateLayer(mFlinger.get(), name, this, w, h, format, flags, handle, gbp); mFlinger->postMessageSync(msg); return static_cast<MessageCreateLayer*>( msg.get() )->getResult(); }
Client 並不會直接新建圖層,而是向SurfaceFlinger發送一個MessageCreateLayer消息,通知SurfaceFlinger服務去執行,其handler代碼如下:
class MessageCreateLayer : public MessageBase { SurfaceFlinger* flinger; Client* client; virtual bool handler() { result = flinger->createLayer(name, client, w, h, format, flags, handle, gbp); return true; } };
其實就是調用SurfaceFlinger的createLayer,創建一個圖層,到這里才是真正的創建圖層:
status_t SurfaceFlinger::createLayer( const String8& name, const sp<Client>& client, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags, sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp) { if (int32_t(w|h) < 0) { return BAD_VALUE; } status_t result = NO_ERROR; sp<Layer> layer; //關鍵點1 新建不同圖層 switch (flags & ISurfaceComposerClient::eFXSurfaceMask) { case ISurfaceComposerClient::eFXSurfaceNormal: result = createNormalLayer(client, name, w, h, flags, format, handle, gbp, &layer); break; case ISurfaceComposerClient::eFXSurfaceDim: result = createDimLayer(client, name, w, h, flags, handle, gbp, &layer); break; default: result = BAD_VALUE; break; } if (result != NO_ERROR) { return result; } ... }
SurfaceFlinger會根據不同的窗口參數,創建不同類型的圖層,這里只看一下createNormalLayer普通樣式的圖層,
status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client, const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format, sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer) { // initialize the surfaces switch (format) { case PIXEL_FORMAT_TRANSPARENT: case PIXEL_FORMAT_TRANSLUCENT: format = PIXEL_FORMAT_RGBA_8888; break; case PIXEL_FORMAT_OPAQUE: format = PIXEL_FORMAT_RGBX_8888; break; } //關鍵點 1 *outLayer = new Layer(this, client, name, w, h, flags); status_t err = (*outLayer)->setBuffers(w, h, format, flags); //關鍵點 2 if (err == NO_ERROR) { *handle = (*outLayer)->getHandle(); *gbp = (*outLayer)->getProducer(); } return err; }
可以看到 圖層最終對應的是Layer,這里會新建一個Layer對象,Layer中包含着與這個圖層對應的Handle及Producer對象,Handle可以看做是Surface的唯一性標識,不過好像沒太大的作用,最多是一個標識,將來清理的時候有用。相比之下gbp = (*outLayer)->getProducer()比較重要,它實際是一個BufferQueueProducer對象,關系到共享內存的分配問題,后面會專門分析,這里到此打住,我們終於得到了一個圖層對象,到這里之后,我們梳理一下,圖層如何建立的:
- 首先APP端新建一個Surface圖層的容器殼子,
- APP通過Binder通信將這個Surface的殼子傳遞給WMS,
- WMS為了填充Surface去向SurfaceFlinger申請真正的圖層,
- SurfaceFlinger收到WMS請求為APP端的Surface分配真正圖層
- 將圖層相關的關鍵信息Handle及Producer傳遞給WMS
Layer建立之后,SurfaceFlinger會將圖層標識信息Handle及Producer傳遞給WMS,WMS利用這兩者創建一個SurfaceControl對象,之后再利用該對象創建Surface,具體代碼如下:
void getSurface(Surface outSurface) { outSurface.copyFrom(mSurfaceControl); } public void copyFrom(SurfaceControl other) { long surfaceControlPtr = other.mNativeObject; long newNativeObject = nativeCreateFromSurfaceControl(surfaceControlPtr); synchronized (mLock) { setNativeObjectLocked(newNativeObject); } }
可以看到Surface的拷貝函數其實就是直接修改Surface native對象指針值,native的Surface對象中包含mGraphicBufferProducer對象,很重要,會被傳遞給APP端。
static jlong nativeCreateFromSurfaceControl(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()); } sp<Surface> SurfaceControl::getSurface() const { Mutex::Autolock _l(mLock); if (mSurfaceData == 0) { mSurfaceData = new Surface(mGraphicBufferProducer, false); } return mSurfaceData; }
到這里WMS端Surface創建及填充完畢,並且Surface其實與WMS的SurfaceControl一一對應,當APP端需要在圖層級別進行操控的時候,其實還是要依靠SurfaceControl的,WMS的Surface創建完畢后,需要傳遞給APP端,之后APP端就獲得直接同SurfaceFlinger通信的能力,比如繪圖與UI更新,怎傳遞的呢?我們知道Surface實現了Parcel接口,因此可以傳遞序列化的數據,其實看一下Surface nativeReadFromParcel就知道到底是怎么傳遞的了,利用readStrongBinder獲取IGraphicBufferProducer對象的句柄,之后轉化為IGraphicBufferProducer代理其實就是BpGraphicBufferProducer,之后利用BpGraphicBufferProducer構建Surface,這樣APP端Surface就被填充完畢,可以同SurfaceFlinger通信了:
static jlong nativeReadFromParcel(JNIEnv* env, jclass clazz, jlong nativeObject, jobject parcelObj) { Parcel* parcel = parcelForJavaObject(env, parcelObj); if (parcel == NULL) { doThrowNPE(env); return 0; } sp<Surface> self(reinterpret_cast<Surface *>(nativeObject)); sp<IBinder> binder(parcel->readStrongBinder()); if (self != NULL && (IInterface::asBinder(self->getIGraphicBufferProducer()) == binder)) { return jlong(self.get()); } sp<Surface> sur; sp<IGraphicBufferProducer> gbp(interface_cast<IGraphicBufferProducer>(binder)); if (gbp != NULL) { sur = new Surface(gbp, true); sur->incStrong(&sRefBaseOwner); } if (self != NULL) { self->decStrong(&sRefBaseOwner); } return jlong(sur.get()); }
到這里為止,APP<->WMS <->WMS 通信申請Surface的流程算走完了

總結
窗口的添加流程簡化如下,這里暫且忽略窗口的分組管理。
- APP首先去WMS登記窗口
- WMS端登記窗口
- APP新建Surface殼子,請求WMS填充Surface
- WMS請求SurfaceFlinger分配窗口圖層
- SurfaceFlinger分配Layer,將結果回傳給WMS
- WMS將窗口信息填充到Surface傳輸到APP
- APP端獲得填充信息,獲取與SurfaceFlinger通信的能力