一、前言
在 Framework 源碼解析知識梳理(1) - 應(yīng)用進(jìn)程與 AMS 的通信實(shí)現(xiàn) 這篇文章中,我們分析了應(yīng)用進(jìn)程和AMS之間的通信實(shí)現(xiàn),我們今天討論一下應(yīng)用進(jìn)程和WindowManagerService之間的通信實(shí)現(xiàn)。
在之前的分析中,我們分兩個部分來介紹了應(yīng)用進(jìn)程與AMS之間的通信:
- 應(yīng)用進(jìn)程發(fā)送消息到
AMS進(jìn)程 -
AMS發(fā)送消息到應(yīng)用進(jìn)程
現(xiàn)在,我們也按照一樣的討論,分為這兩個方向來介紹應(yīng)用進(jìn)程與WMS之間的通信實(shí)現(xiàn),整個通信的過程會涉及到下面的這些類,其中加粗的線就是整個通信實(shí)現(xiàn)的調(diào)用路徑。

二、WindowManagerImpl & WindowManagerGlobal
在AMS的討論中,我們以在應(yīng)用進(jìn)程中啟動Activity為例子進(jìn)行了介紹,今天,我們選取另一個大家很常見的例子:Activity啟動之后,是如何將界面添加到屏幕上的。
2.1 WindowManagerImpl
在 View 繪制體系知識梳理(2) - setContentView 源碼解析 這篇文章中,我們介紹了DecorView的相關(guān)知識,它就對應(yīng)于我們需要添加到屏幕上的View的根節(jié)點(diǎn),而這一添加的過程就需要涉及到和WMS之間的通信,它是在ActivityThread的下面這個方法中實(shí)現(xiàn)的:
<!-- ActivityThread.java -->
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
r = performResumeActivity(token, clearHide, reason);
if (r != null) {
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (r.mPreserveWindow) {
a.mWindowAdded = true;
r.mPreserveWindow = false;
ViewRootImpl impl = decor.getViewRootImpl();
if (impl != null) {
impl.notifyChildRebuilt();
}
}
if (a.mVisibleFromClient && !a.mWindowAdded) {
a.mWindowAdded = true;
wm.addView(decor, l);
}
} else if (!willBeVisible) {
if (localLOGV) Slog.v(
TAG, "Launch " + r + " mStartedActivity set");
r.hideForNow = true;
}
}
}
上面的代碼中,關(guān)鍵的是下面這幾個步驟:
//(1) 通過 Activity 獲得 Window 的實(shí)現(xiàn)類 PhoneWindow
r.window = r.activity.getWindow();
//(2) 通過 PhoneWindow 獲得 DecorView
View decor = r.window.getDecorView();
//(3) 通過 Activity 獲得 ViewManager 的實(shí)現(xiàn)類 WindowManagerImpl
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
//(4) 通過 WindowManagerImpl 添加 DecorView
wm.addView(decor, l);
(1) 通過 Activity 獲得 Window 的實(shí)現(xiàn)類 PhoneWindow
這里首先調(diào)用了Activity的getWindow()方法:
<!-- Activity.java -->
public Window getWindow() {
return mWindow;
}
而這個mWindow是在Activity.attach(xxxx)中被賦值的,它其實(shí)是Window的實(shí)現(xiàn)類PhoneWindow,PhoneWindow的構(gòu)造函數(shù)中傳入了Activity以及parentWindow:
<!-- Activity.java -->
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window) {
//....
mWindow = new PhoneWindow(this, window);
}
第一步的分析就結(jié)束了,大家要記得一個結(jié)論:
通過
Activity的getWindow()返回的是PhoneWindow對象,如果以后需要查看mWindow調(diào)用的函數(shù),那么應(yīng)當(dāng)首先去PhoneWindow.java中查看是否有對應(yīng)的實(shí)現(xiàn),如果沒有,那么再去Window.java中尋找。
對應(yīng)于整個流程圖的中的這個部分:

**(2) 通過 PhoneWindow 獲得 DecorView **
在第二步中,通過第一步返回的PhoneWindow獲得DecorView,這個mDecor就是我們在 View 繪制體系知識梳理(2) - setContentView 源碼解析 所介紹的DecorView:
<!-- PhoneWindow.java -->
@Override
public final View getDecorView() {
if (mDecor == null || mForceDecorInstall) {
installDecor();
}
return mDecor;
}
(3) 通過 Activity 獲得 ViewManager 的實(shí)現(xiàn)類 WindowManagerImpl
下面,我們看第三步,這里通過Activity的getWindowManager()返回了一個ViewManager的實(shí)現(xiàn)類:
<!-- Activity.java -->
public WindowManager getWindowManager() {
return mWindowManager;
}
和mWindow類似,它也是在Activity的attach方法中賦值的:
<!-- Activity.java -->
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window) {
//...
mWindow = new PhoneWindow(this, window);
//...
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken,
mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
mWindowManager = mWindow.getWindowManager();
mCurrentConfig = config;
}
它通過Window的getWindowManager()返回,我們看一下Window的這個方法:
<!-- Window.java -->
public WindowManager getWindowManager() {
return mWindowManager;
}
PhoneWindow和Activity類似,也有一個mWindowManager變量,我們再去看一下它被賦值的地方:
<!-- Activity.java -->
public void setWindowManager(WindowManager wm, IBinder appToken, String appName, boolean hardwareAccelerated) {
mAppToken = appToken;
mAppName = appName;
mHardwareAccelerated = hardwareAccelerated || SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
if (wm == null) {
wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
}
mWindowManager = ((WindowManagerImpl) wm).createLocalWindowManager(this);
}
在createLocalWindowManager返回的是一個WindowManagerImpl對象:
<!-- WindowManagerImpl.java -->
public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
return new WindowManagerImpl(mContext, parentWindow);
}
這樣第三步的結(jié)論就是:
通過
Activity的getWindowManager()方法返回的是它內(nèi)部的mWindowManager對象,而這個對象是通過Window中的mWindowManager得到的,它其實(shí)是ViewManager接口的實(shí)現(xiàn)類WindowManagerImpl。
ViewManager和WindowManagerImpl的關(guān)系為:

(4) 通過 WindowManagerImpl 添加 DecorView
在第四步中,我們通過ViewManager的addView(View, WindowManager.LayoutParams)方法添加DecorView,經(jīng)過前面的分析,我們知道它其實(shí)是一個WindowManagerImpl對象,因此,我們?nèi)タ匆幌滤鶎?shí)現(xiàn)的addView方法:
public final class WindowManagerImpl implements WindowManager {
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
private final Context mContext;
private final Window mParentWindow;
private WindowManagerImpl(Context context, Window parentWindow) {
mContext = context;
mParentWindow = parentWindow;
}
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
}
可以看到WindowManagerImpl什么都沒有做,它只是一個代理類,真正去做工作的是mGlobal,并且這個mGlobal使用了單例模式,也就是說,同一個進(jìn)程中的所有Activity,調(diào)用的是同一個WindowManagerGlobal對象。
那么,我們下面分析的重點(diǎn)就集中在了WindowManagerGlobal上了。
2.2 WindowManagerGlobal
我們來看WindowManagerGlobal的addView方法,這里的第一個參數(shù)就是前面?zhèn)鬟f過來的mDecor:
<!-- WindowManagerGlobal -->
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
//...
ViewRootImpl root;
View panelParentView = null;
//....
synchronized (mLock) {
//...
root = new ViewRootImpl(view.getContext(), display);
mViews.add(view);
mRoots.add(root);
}
try {
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
throw e;
}
}
在addView(xxx)方法中,會生成一個ViewRootImpl對象,并調(diào)用它的setView(xxx)方法把它和DecorView和它關(guān)聯(lián)起來,與WMS通信的邏輯都是由ViewRootImpl負(fù)責(zé)的,WindowManagerGlobal則負(fù)責(zé)用來管理應(yīng)用進(jìn)程當(dāng)中的所有ViewRootImpl,對應(yīng)于整個框架圖的部分為:

在介紹
ViewRootImpl之前,我們還要先講一下在WindowManagerGlobal中比較重要的兩個靜態(tài)變量:
<!-- WindowManagerGlobal.java -->
private static IWindowManager sWindowManagerService;
private static IWindowSession sWindowSession;
(1) sWindowManagerService 為管理者進(jìn)程在應(yīng)用進(jìn)程中的代理對象
<!-- WindowManagerGlobal.java -->
sWindowManagerService = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
(2) sWindowSession 為應(yīng)用進(jìn)程和管理者進(jìn)程之間的會話
<!-- WindowManagerGlobal.java -->
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());
這個會話的方向?yàn)閺膽?yīng)用進(jìn)程到管理者進(jìn)程,通過這個會話,應(yīng)用進(jìn)程就可以向管理者進(jìn)程發(fā)送消息,而發(fā)送消息的邏輯則是通過ViewRootImpl來實(shí)現(xiàn)的,下面我們就來看一下這個最重要的類是如何實(shí)現(xiàn)的。
三、ViewRootImpl
ViewRootImpl實(shí)現(xiàn)了ViewParent接口

在這個類中有三個最關(guān)鍵的變量:
<!-- ViewRootImpl.java -->
View mView;
IWindowSession mWindowSession;
IWindow W;
-
mView(View):這就是我們在WindowManagerGlobal中通過setView()傳遞進(jìn)來的,對應(yīng)于Activity中的DecorView。
<!-- ViewRootImpl.java -->
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;
//....
}
}
}
-
mWindowSession(IWindowSession):代表了從應(yīng)用進(jìn)程到管理者進(jìn)程的會話,它其實(shí)就是WindowManagerGlobal中的sWindowSession,對于同一個進(jìn)程,會復(fù)用同一個會話。
<!-- ViewRootImpl.java -->
public ViewRootImpl(Context context, Display display) {
mWindowSession = WindowManagerGlobal.getWindowSession();
//...
}
-
mWindow(W):代表了從管理者進(jìn)程到應(yīng)用進(jìn)程的會話,是在ViewRootImpl中定義的一個內(nèi)部類。
<!-- ViewRootImpl.java -->
public ViewRootImpl(Context context, Display display) {
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;
}
}
3.1 從應(yīng)用進(jìn)程到管理者進(jìn)程
IWindowSession是應(yīng)用進(jìn)程到管理者進(jìn)程的會話,它定義了管理者進(jìn)程所支持的調(diào)用接口,通過IWindowSession內(nèi)部的管理者進(jìn)程的遠(yuǎn)程代理對象,我們就可以實(shí)現(xiàn)從應(yīng)用進(jìn)程向管理者進(jìn)程發(fā)送消息。
而在管理者進(jìn)程中,通過WindowManagerService來處理來自各個應(yīng)用進(jìn)程的消息,在WMS中有一個Session列表,所有從應(yīng)用進(jìn)程到管理進(jìn)程的會話都保存在該列表中。
<!-- WindowManagerService.java -->
final ArraySet<Session> mSessions = new ArraySet<>();
Session則實(shí)現(xiàn)了IWindowSession.Stub接口:

當(dāng)它收到消息之后,就會回調(diào)
IWindowSession的接口方法。
我們舉一個例子,在ViewRootImpl的setView(xxx)方法中,調(diào)用了IWindowSession的下面這個接口方法:
<!-- ViewRootImpl.java -->
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
//....
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
}
最終這一跨進(jìn)程的調(diào)用會回調(diào)到該應(yīng)用進(jìn)程在管理者進(jìn)程中對應(yīng)的Session對象的回調(diào)方法中:
<!-- Session.java -->
@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);
}
3.2 從管理者進(jìn)程到應(yīng)用進(jìn)程
如果我們希望實(shí)現(xiàn)從管理者進(jìn)程發(fā)送消息到應(yīng)用進(jìn)程,那么也需要一個應(yīng)用進(jìn)程在管理者進(jìn)程的代理對象。
在調(diào)用addToDisplay時,我們傳入的第一個參數(shù)是mWindow,前面我們介紹過,它實(shí)現(xiàn)了IWindow.Stub接口:

這樣管理者進(jìn)程在
Session的addToDisplay方法被回調(diào)時,就可以獲得一個遠(yuǎn)程代理對象,它就可以通過IWindow中定義的接口方法,實(shí)現(xiàn)從管理者進(jìn)程到應(yīng)用進(jìn)程的通信。
在Session的addToDisplay()方法中,會調(diào)用WMS的addWindow方法,而在addWindow方法中,它會創(chuàng)建一個WindowState對象,一個進(jìn)程中的每個ViewRootImpl會對應(yīng)于一個IWindow會話,它們被保存在WMS的下面這個HashMap中:
<!-- WindowManagerService.java -->
final HashMap<IBinder, WindowState> mWindowMap = new HashMap<>();
其中key值就表示應(yīng)用進(jìn)程在管理者進(jìn)程中的遠(yuǎn)程代理對象,例如我們在WMS中調(diào)用了下面這個方法:
<!-- WindowState.java -->
mClient.windowFocusChanged(focused, inTouchMode);
那么應(yīng)用進(jìn)程中IWindow.Stub的實(shí)現(xiàn)的ViewRootImpl.W類的對應(yīng)方法就會被回調(diào),在該回調(diào)方法中又會調(diào)用ViewRootImpl的方法:
<!-- ViewRootImpl.java -->
@Override
public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
viewAncestor.windowFocusChanged(hasFocus, inTouchMode);
}
}
而在ViewRootImpl的windowFocusChanged方法中,會通過它內(nèi)部的一個ViewRootHandler發(fā)送消息,ViewRootHandler的Looper是和應(yīng)用進(jìn)程中的主線程所綁定的,因此它就可以在handleMessage進(jìn)行后續(xù)邏輯處理。
<!-- ViewRootImpl.java -->
final ViewRootHandler mHandler = new ViewRootHandler();
public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
Message msg = Message.obtain();
msg.what = MSG_WINDOW_FOCUS_CHANGED;
msg.arg1 = hasFocus ? 1 : 0;
msg.arg2 = inTouchMode ? 1 : 0;
mHandler.sendMessage(msg);
}
四、小結(jié)
做一個簡單的總結(jié),應(yīng)用進(jìn)程與WMS之間通信是通過WindowManagerGlobal中ViewRootImpl來管理的,ViewRootImpl中的IWindowSession對應(yīng)于從應(yīng)用進(jìn)程到WMS的通信,而IWindow對應(yīng)于從管理者進(jìn)程到應(yīng)用進(jìn)程的通信。
更多文章,歡迎訪問我的 Android 知識梳理系列:
- Android 知識梳理目錄:http://www.itdecent.cn/p/fd82d18994ce
- 個人主頁:http://lizejun.cn
- 個人知識總結(jié)目錄:http://lizejun.cn/categories/