深入理解 WindowManagerService
在上篇文章中初步理解 Window 體系,我們初步分析了 Window 的體系,這篇文章我們分析一下 WindowManagerService(以下簡稱 WMS)。WMS 錯綜負責,與 ActivityManagerService、InputManagerService、SurfaceFlinger 關係也很緊密,如果想分析的清楚徹底,恐怕是一兩篇文章難以做到的。本篇文章初步分析 WMS 的建立,以及應用程序中的 WindowManager 與 WMS 通訊。
一. 理解 WindowManagerService 相關知識
1.1 WindowManagerService 的誕生
1.1.1 在 SystemServer 中的建立
WMS 是在 SystemServer 程序中啟動的,SystemServer 程序是 Android 系統啟動的時候初始化的,我們首先來看一下 SystemServer 的入口函式 main()
public final class SystemServer { /** * The main entry point from zygote. */ public static void main(String[] args) { new SystemServer().run(); } }
從上述程式碼可見,是建立了一個 SystemServer 物件並呼叫了 run()
方法
private void run() { ...... mSystemServiceManager = new SystemServiceManager(mSystemContext);// 程式碼 1 // Start services. try { traceBeginAndSlog("StartServices"); startBootstrapServices();// 程式碼 2 startCoreServices();// 程式碼 3 startOtherServices();// 程式碼 4 SystemServerInitThreadPool.shutdown(); } catch (Throwable ex) { Slog.e("System", "******************************************"); Slog.e("System", "************ Failure starting system services", ex); throw ex; } finally { traceEnd(); } }
- 程式碼1處,建立了一個 SystemServiceManager 物件,用於建立各種系統服務並管理他們的生命週期
- 程式碼2處,呼叫
startBootstrapServices()
啟動 ActivityManagerService、PackageManagerService 等服務程序 - 程式碼3處,呼叫
startCoreServices()
啟動BatteryService、WebViewUpdateService 等服務程序startOtherServices()
啟動 - 程式碼4處,呼叫
startOtherServices()
啟動 WindowManagerService、InputManagerService 等服務程序
startOtherServices()
方法很長,我們分析下其中和 WMS 相關的部分
private void startOtherServices() { final Context context = mSystemContext; WindowManagerService wm = null; InputManagerService inputManager = null; ...... try { // 程式碼 1 traceBeginAndSlog("StartInputManagerService"); inputManager = new InputManagerService(context); traceEnd(); // 程式碼 2 traceBeginAndSlog("StartWindowManagerService"); // WMS needs sensor service ready ConcurrentUtils.waitForFutureNoInterrupt(mSensorServiceStart, START_SENSOR_SERVICE); mSensorServiceStart = null; wm = WindowManagerService.main(context, inputManager, mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL, !mFirstBoot, mOnlyCore, new PhoneWindowManager()); ServiceManager.addService(Context.WINDOW_SERVICE, wm); ServiceManager.addService(Context.INPUT_SERVICE, inputManager); traceEnd(); // 程式碼 3 traceBeginAndSlog("SetWindowManagerService"); mActivityManagerService.setWindowManager(wm); traceEnd(); // 程式碼 4 traceBeginAndSlog("StartInputManager"); inputManager.setWindowManagerCallbacks(wm.getInputMonitor()); inputManager.start(); traceEnd(); ...... } catch (RuntimeException e) { Slog.e("System", "******************************************"); Slog.e("System", "************ Failure starting core service", e); } ...... // 程式碼 5 traceBeginAndSlog("MakeDisplayReady"); try { wm.displayReady(); } catch (Throwable e) { reportWtf("making display ready", e); } traceEnd(); ...... // 程式碼 6 traceBeginAndSlog("MakeWindowManagerServiceReady"); try { wm.systemReady(); } catch (Throwable e) { reportWtf("making Window Manager Service ready", e); } traceEnd(); if (safeMode) { mActivityManagerService.showSafeModeOverlay(); } // 程式碼 7 // Update the configuration for this context by hand, because we're going // to start using it before the config change done in wm.systemReady() will // propagate to it. final Configuration config = wm.computeNewConfiguration(DEFAULT_DISPLAY); DisplayMetrics metrics = new DisplayMetrics(); WindowManager w = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); w.getDefaultDisplay().getMetrics(metrics); context.getResources().updateConfiguration(config, metrics); ...... }
WindowManager.main() displayReady() systemReady()
1.1.2 WMS 的建構函式
在上面一段程式碼中,最重要的莫過於呼叫 WMS 的 main()
方法建立一個 WindowManagerService 物件了,我們來分析下這個方法
public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs { private static WindowManagerService sInstance; static WindowManagerService getInstance() { return sInstance; } public static WindowManagerService main(final Context context, final InputManagerService im, final boolean haveInputMethods, final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy) { DisplayThread.getHandler().runWithScissors(() -> sInstance = new WindowManagerService(context, im, haveInputMethods, showBootMsgs, onlyCore, policy), 0); return sInstance; } }
- 我們看到在
main()
方法中,在 DisplayThread 執行緒中通過 WMS 的構造方法建立一個 WMS 例項物件 - DisplayThread 執行緒是一個系統前臺執行緒,用於執行一些延時要非常小的關於顯示的操作,一般只會在 WindowManager、DisplayManager 和 InputManager 中使用,程式碼也比較簡單,如下所示:
/** * Shared singleton foreground thread for the system.This is a thread for * operations that affect what's on the display, which needs to have a minimum * of latency.This thread should pretty much only be used by the WindowManager, * DisplayManager, and InputManager to perform quick operations in real time. */ public final class DisplayThread extends ServiceThread { private static DisplayThread sInstance; private static Handler sHandler; private DisplayThread() { // DisplayThread runs important stuff, but these are not as important as things running in // AnimationThread. Thus, set the priority to one lower. super("android.display", Process.THREAD_PRIORITY_DISPLAY + 1, false /*allowIo*/); } private static void ensureThreadLocked() { if (sInstance == null) { sInstance = new DisplayThread(); sInstance.start(); sInstance.getLooper().setTraceTag(Trace.TRACE_TAG_ACTIVITY_MANAGER); sHandler = new Handler(sInstance.getLooper()); } } public static DisplayThread get() { synchronized (DisplayThread.class) { ensureThreadLocked(); return sInstance; } } public static Handler getHandler() { synchronized (DisplayThread.class) { ensureThreadLocked(); return sHandler; } } }
我們接著上面的 main()
方法分析,上面程式碼呼叫了 WMS 的構造方法建立了 WMS 例項物件,我們來看一下 WMS 中的一些重要的成員屬性和構造方法,如下所示:
public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs { final WindowManagerPolicy mPolicy; final ArraySet<Session> mSessions = new ArraySet<>(); final WindowHashMap mWindowMap = new WindowHashMap(); final ArrayList<AppWindowToken> mFinishedStarting = new ArrayList<>(); final H mH = new H(); final InputManagerService mInputManager; final WindowAnimator mAnimator; private WindowManagerService(Context context, InputManagerService inputManager, boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore, WindowManagerPolicy policy) { ...... // 程式碼 1 mInputManager = inputManager; // Must be before createDisplayContentLocked. // 程式碼 2 mPolicy = policy; if(mInputManager != null) { final InputChannel inputChannel = mInputManager.monitorInput(TAG_WM); mPointerEventDispatcher = inputChannel != null ? new PointerEventDispatcher(inputChannel) : null; } else { mPointerEventDispatcher = null; } ...... // 程式碼 3 mAnimator = new WindowAnimator(this); ...... // 程式碼 4 initPolicy(); // 程式碼 5 // Add ourself to the Watchdog monitors. Watchdog.getInstance().addMonitor(this); ...... } }
- 程式碼1 處,儲存 SystemServer 中傳入的 InputManagerService 例項物件,輸入事件最終要分發給具有焦點的視窗,而 WMS 是視窗的管理者。
mInputManager
用於管理每個視窗的輸入事件通道,並向通道上派發事件 - 程式碼2 處,
mPolicy
物件是 WMS 中非常重要的一個物件,是 WindowManagerPolicy 型別的,WindowManagerPolicy(簡稱 WMP) 是一個介面,具體的實現類是PhoneWindowManager
。mPolicy
物件可以說是 WMS 的首席顧問,WMS 的許多操作都是需要 WMP 規定的,比如:多個視窗的上下順序,監聽螢幕旋轉的狀態,預處理一些系統按鍵事件(例如HOME、BACK鍵等的預設行為就是在這裡實現的) - 程式碼3 處,建立一個
WindowAnimator
物件,用於管理所有視窗的動畫 - 程式碼4 處,初始化
mPolicy
物件 - 程式碼5 處,將 WMS 例項物件本身新增到 Watchdog 中,WMS 類實現了
Watchdog.Monitor
介面。Watchdog 用於監控系統的一些關鍵服務
1.2 WMS 中的幾個重要概念
除開上面構造方法中提到的一些成員屬性之外,還有一些非常重要的概念需要理解
1.2.1 Session
在上篇文章初步理解 Window 體系 中,我們提到 ViewRootImpl 和 WMS 之間的通訊就是通過 Session 物件完成的。
Session 類繼承自 IWindowSession.Stub
,每一個應用程序都有一個唯一的 Session 物件與 WMS 通訊,如下圖所示

Session.png
圖片來源:Window與WMS通訊過程
在 WMS 中的 mSessions
成員屬性,是 ArraySet 型別,其中儲存著 Session 型的物件。
public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs { /** * All currently active sessions with clients. */ final ArraySet<Session> mSessions = new ArraySet<>(); ...... @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; } }
public class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { final WindowManagerService mService; private int mNumWindow = 0;// 程式碼 1 ...... // 程式碼 2 public Session(WindowManagerService service, IWindowSessionCallback callback, IInputMethodClient client, IInputContext inputContext) { mService = service; ...... } void windowAddedLocked(String packageName) { mPackageName = packageName; mRelayoutTag = "relayoutWindow: " + mPackageName; if (mSurfaceSession == null) { if (WindowManagerService.localLOGV) Slog.v( TAG_WM, "First window added to " + this + ", creating SurfaceSession"); mSurfaceSession = new SurfaceSession(); if (SHOW_TRANSACTIONS) Slog.i( TAG_WM, "NEW SURFACE SESSION " + mSurfaceSession); // 程式碼 3 mService.mSessions.add(this); if (mLastReportedAnimatorScale != mService.getCurrentAnimatorScale()) { mService.dispatchNewAnimatorScaleLocked(this); } } mNumWindow++; } void windowRemovedLocked() { mNumWindow--; killSessionLocked(); } private void killSessionLocked() { if (mNumWindow > 0 || !mClientDead) { return; } // 程式碼 4 mService.mSessions.remove(this); ...... } }
- 程式碼 1 處,
mNumWindow
變數記錄著此 Session 中共有多少個 Window - 程式碼 2 處的
Session
的構造方法中,mService
儲存著 WMS 的例項物件 - 程式碼 3 處,將此
Session
物件新增進 WMS 的mSessions
佇列中 - 程式碼 4 處,將此
Session
物件從 WMS 的mSessions
佇列中移除
1.2.2 WindowState
WindowState 是 WMS 中一個重要的概念,在 WMS 中的一個 WindowState 物件就對應著一個應用程序中的 Window 物件。
我們在上篇文章初步理解 Window 體系 最後,在呼叫 WindowManagerGlobal.addView
方法時,經過一系列的方法呼叫,最後走到了 WindowManagerService.addWindow
方法中

addWindow.png
在 WindowManagerService.addWindow 方法中,會建立一個與 Window 物件對應的 WindowState 物件並呼叫 WindowState.attach
方法,然後將該 WindowState 物件新增到 WMS 的 mWindowMap
Map 中
public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs { final WindowHashMap mWindowMap = new WindowHashMap(); public int addWindow(Session session, IWindow client, int seq, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, InputChannel outInputChannel) { ...... final WindowState win = new WindowState(this, session, client, token, parentWindow, appOp[0], seq, attrs, viewVisibility, session.mUid, session.mCanAddInternalSystemWindow); ...... win.attach(); mWindowMap.put(client.asBinder(), win); ...... win.mToken.addWindow(win); } }
class WindowState extends WindowContainer<WindowState> implements WindowManagerPolicy.WindowState { final WindowManagerService mService; final WindowManagerPolicy mPolicy; final Context mContext; final Session mSession; final IWindow mClient; WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token, WindowState parentWindow, int appOp, int seq, WindowManager.LayoutParams a, int viewVisibility, int ownerId, boolean ownerCanAddInternalSystemWindow) { mService = service; mSession = s; mClient = c; mAppOp = appOp; mToken = token; mAppToken = mToken.asAppWindowToken(); ...... } void attach() { if (localLOGV) Slog.v(TAG, "Attaching " + this + " token=" + mToken); mSession.windowAddedLocked(mAttrs.packageName); } ...... }
在 WindowState 中儲存了 WMS 物件、WMP 物件、Session 物件和 IWindow 物件,IWindow 物件就是與此 WindowState 物件相對應的在應用程序中的 Window 物件。
final WindowHashMap mWindowMap = new WindowHashMap();
是一個 HashMap 的子類,key 是 IBinder
,value 是 WindowState
,用於儲存 WMS 中所有的 WindowState 物件,
/** * Subclass of HashMap such that we can instruct the compiler to boost our thread priority when * locking this class. See makefile. */ class WindowHashMap extends HashMap<IBinder, WindowState> { }
mWindowMap.put(client.asBinder(), win);
IWindow client
物件,其實是 ViewRootImpl 中的 final W mWindow
成員,如下所示:
public final class ViewRootImpl implements ViewParent, View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks { final W mWindow; ...... static class W extends IWindow.Stub { ...... } ...... }
1.2.3 WindowToken
簡單的理解,WindowToken 有兩個作用:
- 在 WMS 中,一個 WindowToken 就代表著一個應用元件,應用元件包括:Activity、InputMethod 等。在 WMS 中,會將屬於同一 WindowToken 的做統一處理,比如在對視窗進行 ZOrder 排序時,會將屬於統一 WindowToken 的排在一起。
- WindowToken 也具有令牌的作用。應用元件在建立 Window 時都需要提供一個有效的 WindowToken 以表明自己的身份,並且視窗的型別必須與所持有的 WindowToken 型別保持一致。如果是系統型別的視窗,可以不用提供 WindowToken,WMS 會自動為該系統視窗隱式的建立 WindowToken,但是要求應用必須具有建立該系統型別視窗的許可權
概念上有了初步的理解,我們來看下 WindowToken 的程式碼,如下所示,在 WindowToken 類中,最重要的其實是其中的成員屬性
/** * Container of a set of related windows in the window manager. Often this is an AppWindowToken, * which is the handle for an Activity that it uses to display windows. For nested windows, there is * a WindowToken created for the parent window to manage its children. */ class WindowToken extends WindowContainer<WindowState> { private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowToken" : TAG_WM; // The window manager! protected final WindowManagerService mService; // The actual token. final IBinder token; // The type of window this token is for, as per WindowManager.LayoutParams. final int windowType; ...... // The display this token is on. protected DisplayContent mDisplayContent; ...... WindowToken(WindowManagerService service, IBinder _token, int type, boolean persistOnEmpty, DisplayContent dc, boolean ownerCanManageAppTokens) { mService = service; token = _token; windowType = type; mPersistOnEmpty = persistOnEmpty; mOwnerCanManageAppTokens = ownerCanManageAppTokens; onDisplayChanged(dc); } void onDisplayChanged(DisplayContent dc) { dc.reParentWindowToken(this); mDisplayContent = dc; // TODO(b/36740756): One day this should perhaps be hooked // up with goodToGo, so we don't move a window // to another display before the window behind // it is ready. SurfaceControl.openTransaction(); for (int i = mChildren.size() - 1; i >= 0; --i) { final WindowState win = mChildren.get(i); win.mWinAnimator.updateLayerStackInTransaction(); } SurfaceControl.closeTransaction(); super.onDisplayChanged(dc); } ...... }
其實,對於 WMS 來講,只要是一個 IBinder 物件都可以作為 Token,比如在之前分析新增 Window 時,呼叫 WindowManagerService.addWindow
方法時,傳入的 Token 物件就是一個 IWindow.Stub
的物件。我們來看一下 WMS 中的 addWindowToken
方法,如下所示:
@Override public void addWindowToken(IBinder binder, int type, int displayId) { if (!checkCallingPermission(MANAGE_APP_TOKENS, "addWindowToken()")) { throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); } synchronized(mWindowMap) { final DisplayContent dc = mRoot.getDisplayContentOrCreate(displayId); // 程式碼 1 WindowToken token = dc.getWindowToken(binder); // 程式碼 2 if (token != null) { Slog.w(TAG_WM, "addWindowToken: Attempted to add binder token: " + binder + " for already created window token: " + token + " displayId=" + displayId); return; } // 程式碼 3 if (type == TYPE_WALLPAPER) { new WallpaperWindowToken(this, binder, true, dc, true /* ownerCanManageAppTokens */); } else { new WindowToken(this, binder, type, true, dc, true /* ownerCanManageAppTokens */); } } }
- 程式碼 1 處,從 DisplayContent 中取一個 WindowToken 物件。從這兒可以看出每一個 WindowToken 又具體是屬於每個 DisplayContent 物件的,DisplayContent 物件可以理解為一塊螢幕的對應,這個概念在之後詳細介紹。
class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowContainer> { WindowManagerService mService; // mTokenMap 一個 HashMap 物件,用於對映 IBinder 和 WindowToken 物件 // Mapping from a token IBinder to a WindowToken object on this display. private final HashMap<IBinder, WindowToken> mTokenMap = new HashMap(); ...... // 從 mTokenMap 取出對應於 IBinder 的 WindowToken 物件 WindowToken getWindowToken(IBinder binder) { return mTokenMap.get(binder); } // 在建立 WindowToken 物件時,會通過此方法將 WindowToken 從屬於此 DisplayContent 物件,並新增到 mTokenMap 中 /** Changes the display the input window token is housed on to this one. */ void reParentWindowToken(WindowToken token) { final DisplayContent prevDc = token.getDisplayContent(); if (prevDc == this) { return; } if (prevDc != null && prevDc.mTokenMap.remove(token.token) != null && token.asAppWindowToken() == null) { // Removed the token from the map, but made sure it's not an app token before removing // from parent. token.getParent().removeChild(token); } addWindowToken(token.token, token); } private void addWindowToken(IBinder binder, WindowToken token) { final DisplayContent dc = mService.mRoot.getWindowTokenDisplay(token); if (dc != null) { // We currently don't support adding a window token to the display if the display // already has the binder mapped to another token. If there is a use case for supporting // this moving forward we will either need to merge the WindowTokens some how or have // the binder map to a list of window tokens. throw new IllegalArgumentException("Can't map token=" + token + " to display=" + getName() + " already mapped to display=" + dc + " tokens=" + dc.mTokenMap); } if (binder == null) { throw new IllegalArgumentException("Can't map token=" + token + " to display=" + getName() + " binder is null"); } if (token == null) { throw new IllegalArgumentException("Can't map null token to display=" + getName() + " binder=" + binder); } mTokenMap.put(binder, token); if (token.asAppWindowToken() == null) { // Add non-app token to container hierarchy on the display. App tokens are added through // the parent container managing them (e.g. Tasks). switch (token.windowType) { case TYPE_WALLPAPER: mBelowAppWindowsContainers.addChild(token); break; case TYPE_INPUT_METHOD: case TYPE_INPUT_METHOD_DIALOG: mImeWindowsContainers.addChild(token); break; default: mAboveAppWindowsContainers.addChild(token); break; } } } // 通過此方法,將 IBinder 所對應的 WindowToken 物件從此 DisplayContent 中的 mTokenMap 移除 WindowToken removeWindowToken(IBinder binder) { final WindowToken token = mTokenMap.remove(binder); if (token != null && token.asAppWindowToken() == null) { token.setExiting(); } return token; } ...... }
- 程式碼 2 處,若該 IBinder 物件對應的 WindowToken 不為空,則返回,可見 一個 IBinder 物件只能建立一個對應的 WindowToken 物件。
- 程式碼 3 處,根據 Window 的 type 型別建立對應的 WindowToken 物件。
AppWindowToken 是 WindowToken 的子類,與 WindowToken 不同的是,AppWindowToken 只可以用於 Activity 中的 Window 的 WindowToken。
1.2.4 DisplayContent
DisplayContent 是 Android 4.2 中支援 WiFi Display 多螢幕顯示提出的一個概念,一個 DisplayContent 物件就代表著一塊螢幕資訊,一個 DisplayContent 物件用一個整型變數作為其 ID,系統預設螢幕所對應的 DisplayContent 物件 ID 是 Display.DEFAULT_DISPLAY。
屬於同一個 DisplayContent 物件的 Window 物件會被繪製到同一塊螢幕上,在新增視窗時可以指定對應的 DisplayContent 的 id,從而指定被新增到哪個 DisplayContent 上面。
DisplayContent 物件是由 DisplayManagerService 統一管理的,在此只做概念性的介紹,詳細的關於 DisplayContent 和 DisplayManagerService 知識請查閱相關文件和資料
二. WMS 與 WindowManager 的通訊
在上篇文章初步理解 Window 體系 中,我們最後分析到了 ViewRootImpl,ViewRootImpl 是連線 WindowManager 和 WMS 的橋樑,自然他們之間的通訊也是通過 ViewRootImpl 完成的。
2.1 ViewRootImpl 的成員變數
在 ViewRootImpl 中有兩個個非常重要的成員變數: mWindowSession
和 mWindow
,這兩個變數都是用於 ViewRootImpl 和 WMS 通訊使用的
public final class ViewRootImpl implements ViewParent, View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks { ...... final IWindowSession mWindowSession; final W mWindow; ...... public ViewRootImpl(Context context, Display display) { mContext = context; // 程式碼 1,通過 WindowManagerGlobal.getWindowSession() 方法得到一個 IWindowSession 物件 mWindowSession = WindowManagerGlobal.getWindowSession(); ...... // 程式碼 2,通過 W 構造方法直接建立一個新的 W 物件 mWindow = new W(this); ...... } ...... }
2.1.1 IWindowSession
IWindowSession 是一個 AIDL 介面,其服務端程序是 WMS,客戶端程序是應用程序,IWindowSession 的建立是在 WindowManagerGlobal 中,如下所示:
public final class WindowManagerGlobal { private static IWindowManager sWindowManagerService; private static IWindowSession sWindowSession; ...... public static IWindowManager getWindowManagerService() { synchronized (WindowManagerGlobal.class) { if (sWindowManagerService == null) { sWindowManagerService = IWindowManager.Stub.asInterface( ServiceManager.getService("window")); try { if (sWindowManagerService != null) { ValueAnimator.setDurationScale( sWindowManagerService.getCurrentAnimatorScale()); } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } return sWindowManagerService; } } public static IWindowSession getWindowSession() { synchronized (WindowManagerGlobal.class) { if (sWindowSession == null) { try { InputMethodManager imm = InputMethodManager.getInstance(); IWindowManager windowManager = getWindowManagerService(); sWindowSession = windowManager.openSession( new IWindowSessionCallback.Stub() { @Override public void onAnimatorScaleChanged(float scale) { ValueAnimator.setDurationScale(scale); } }, imm.getClient(), imm.getInputContext()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } return sWindowSession; } } ...... }
- 從
getWindowSession()
方法中我們可以看出,IWindowSession 物件的建立依賴於 IWindowManager 物件 - IWindowManager 也是一個 AIDL 介面,通過
getWindowManagerService()
方法得到其物件,在getWindowManagerService()
方法中,可以看到是典型的 Android 中 Binder 通訊得到服務端在客戶端程序中的代理物件的方式,遠端端的物件即是 WMS,WMS 實現了 IWindowManager 介面public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor,WindowManagerPolicy.WindowManagerFuncs { ...... }
- 在
getWindowSession()
方法中,我們可以看到是呼叫了 IWindowManager 的openSession
方法,其實際的實現是在 WMS 中,WMS 中的openSession
方法如下所示public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor,WindowManagerPolicy.WindowManagerFuncs { @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; } }
可以看到,其實 ViewRootImpl 中的 IWindowSession 物件實際對應著 WMS 中的 Session 物件。
WindowManagerGlobal 和 WMS 實現的是單方向的通訊,都是通過如下圖所示的 Binder 方式進行程序間通訊的

WindowManagerGlobal.png
2.1.2 W
W 類是 ViewRootImpl 的一個內部類,實現了 IWindow 介面,IWindow 也是一個 AIDL 介面,可以猜想到,IWindow 介面是供 WMS 使用的,WSM 通過呼叫 IWindow 一些方法,通過 Binder 通訊的方式,最後執行到了 W 中對應的方法中
public final class ViewRootImpl implements ViewParent, View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks { 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, MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout, boolean alwaysConsumeNavBar, int displayId) { final ViewRootImpl viewAncestor = mViewAncestor.get(); if (viewAncestor != null) { viewAncestor.dispatchResized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets, outsets, reportDraw, mergedConfiguration, backDropFrame, forceLayout, alwaysConsumeNavBar, displayId); } } @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 ActivityManager.getService().checkPermission( permission, Binder.getCallingPid(), Binder.getCallingUid()); } catch (RemoteException e) { return PackageManager.PERMISSION_DENIED; } } ...... } }
比如在 ViewRootImpl#setView
方法中,有如下程式碼,在程式碼 1 處通過 mWindowSession 呼叫 addToDisplay 方法時,會將 mWindow 傳入,最後傳給 WMS,這樣 WMS 便得到了一個 W 物件的例項物件。
public final class ViewRootImpl implements ViewParent, View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks { public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { synchronized (this) { if (mView == null) { ...... int res; /* = WindowManagerImpl.ADD_OKAY; */ // 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(); } mForceDecorViewVisibility = (mWindowAttributes.privateFlags & PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0; try { mOrigWindowType = mWindowAttributes.type; mAttachInfo.mRecomputeGlobalAttributes = true; collectViewAttributes(); // 程式碼 1 res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mAttachInfo.mOutsets, mInputChannel); } catch (RemoteException e) { mAdded = false; mView = null; mAttachInfo.mRootView = null; mInputChannel = null; mFallbackEventHandler.setView(null); unscheduleTraversals(); setAccessibilityFocus(null, null); throw new RuntimeException("Adding window failed", e); } finally { if (restore) { attrs.restore(); } } ...... } } } }
從上面程式碼可以看到,在 ViewRootImpl 中不僅實現了從 ViewRootImpl 向 WMS 的通訊,也實現了從 WMS 向 ViewRootImpl 的通訊,如下圖所示

ViewRootImpl.png