在上篇文章中 初步理解 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);
......
}
- 代碼1處,創建了 InputManagerService 對象,InputManagerService 主要用于接收系統的輸入事件,包括按鍵、觸摸等
- 代碼2處,調用
WindowManager.main()
方法創建 WindowManagerService 對象,并將 WindowManagerService 和 InputManagerService 對象添加到 ServiceManager 中 - 代碼3處,為 ActivityManagerService 對象設置 WindowManagerService 對象
- 代碼4處,為 InputManagerService 設置 WindowManagerService 對象的 InputMonitor 對象,并啟動 InputManagerService 對象
- 代碼5處,調用 WMS 的
displayReady()
方法初始化顯示信息 - 代碼6處,調用 WMS 的
systemReady()
方法通知 WMS 系統的初始化工作完成 - 代碼7處,為 Context 中的 WindowManagerImpl 實例對象設置 DisplayMetrics 對象,并更新當前 Context 的 Resources 中的 Configuration 和 DisplayMetircs 屬性
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 通信,如下圖所示
圖片來源: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
方法中
在 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 方式進行進程間通信的
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 的通信,如下圖所示