一腌巾、前言
在 Framework 源碼解析知識梳理(1) - 應(yīng)用進程與 AMS 的通信實現(xiàn) 這篇文章中鲫竞,我們分析了應(yīng)用進程和AMS
之間的通信實現(xiàn)辐怕,我們今天討論一下應(yīng)用進程和WindowManagerService
之間的通信實現(xiàn)。
在之前的分析中从绘,我們分兩個部分來介紹了應(yīng)用進程與AMS
之間的通信:
- 應(yīng)用進程發(fā)送消息到
AMS
進程 -
AMS
發(fā)送消息到應(yīng)用進程
現(xiàn)在寄疏,我們也按照一樣的討論,分為這兩個方向來介紹應(yīng)用進程與WMS
之間的通信實現(xiàn)僵井,整個通信的過程會涉及到下面的這些類陕截,其中加粗的線就是整個通信實現(xiàn)的調(diào)用路徑。
二批什、WindowManagerImpl & WindowManagerGlobal
在AMS
的討論中农曲,我們以在應(yīng)用進程中啟動Activity
為例子進行了介紹,今天驻债,我們選取另一個大家很常見的例子:Activity
啟動之后乳规,是如何將界面添加到屏幕上的。
2.1 WindowManagerImpl
在 View 繪制體系知識梳理(2) - setContentView 源碼解析 這篇文章中合呐,我們介紹了DecorView
的相關(guān)知識暮的,它就對應(yīng)于我們需要添加到屏幕上的View
的根節(jié)點,而這一添加的過程就需要涉及到和WMS
之間的通信淌实,它是在ActivityThread
的下面這個方法中實現(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 的實現(xiàn)類 PhoneWindow
r.window = r.activity.getWindow();
//(2) 通過 PhoneWindow 獲得 DecorView
View decor = r.window.getDecorView();
//(3) 通過 Activity 獲得 ViewManager 的實現(xiàn)類 WindowManagerImpl
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
//(4) 通過 WindowManagerImpl 添加 DecorView
wm.addView(decor, l);
(1) 通過 Activity 獲得 Window 的實現(xiàn)類 PhoneWindow
這里首先調(diào)用了Activity
的getWindow()
方法:
<!-- Activity.java -->
public Window getWindow() {
return mWindow;
}
而這個mWindow
是在Activity.attach(xxxx)
中被賦值的猖腕,它其實是Window
的實現(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)的實現(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 的實現(xiàn)類 WindowManagerImpl
下面,我們看第三步犁享,這里通過Activity
的getWindowManager()
返回了一個ViewManager
的實現(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
得到的凤巨,它其實是ViewManager
接口的實現(xiàn)類WindowManagerImpl
视乐。
ViewManager
和WindowManagerImpl
的關(guān)系為:
(4) 通過 WindowManagerImpl 添加 DecorView
在第四步中,我們通過ViewManager
的addView(View, WindowManager.LayoutParams)
方法添加DecorView
敢茁,經(jīng)過前面的分析佑淀,我們知道它其實是一個WindowManagerImpl
對象,因此彰檬,我們?nèi)タ匆幌滤鶎崿F(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
使用了單例模式捧颅,也就是說,同一個進程中的所有Activity
较雕,調(diào)用的是同一個WindowManagerGlobal
對象碉哑。
那么,我們下面分析的重點就集中在了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
負責(zé)的,WindowManagerGlobal
則負責(zé)用來管理應(yīng)用進程當(dāng)中的所有ViewRootImpl
凄吏,對應(yīng)于整個框架圖的部分為:
在介紹
ViewRootImpl
之前远舅,我們還要先講一下在WindowManagerGlobal
中比較重要的兩個靜態(tài)變量:
<!-- WindowManagerGlobal.java -->
private static IWindowManager sWindowManagerService;
private static IWindowSession sWindowSession;
(1) sWindowManagerService 為管理者進程在應(yīng)用進程中的代理對象
<!-- WindowManagerGlobal.java -->
sWindowManagerService = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
(2) sWindowSession 為應(yīng)用進程和管理者進程之間的會話
<!-- 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īng)用進程到管理者進程,通過這個會話痕钢,應(yīng)用進程就可以向管理者進程發(fā)送消息图柏,而發(fā)送消息的邏輯則是通過ViewRootImpl
來實現(xiàn)的,下面我們就來看一下這個最重要的類是如何實現(xiàn)的任连。
三蚤吹、ViewRootImpl
ViewRootImpl
實現(xiàn)了ViewParent
接口
在這個類中有三個最關(guān)鍵的變量:
<!-- ViewRootImpl.java -->
View mView;
IWindowSession mWindowSession;
IWindow W;
-
mView(View)
:這就是我們在WindowManagerGlobal
中通過setView()
傳遞進來的,對應(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)用進程到管理者進程的會話裁着,它其實就是WindowManagerGlobal
中的sWindowSession
,對于同一個進程拱她,會復(fù)用同一個會話二驰。
<!-- ViewRootImpl.java -->
public ViewRootImpl(Context context, Display display) {
mWindowSession = WindowManagerGlobal.getWindowSession();
//...
}
-
mWindow(W)
:代表了從管理者進程到應(yīng)用進程的會話,是在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)用進程到管理者進程
IWindowSession
是應(yīng)用進程到管理者進程的會話桶雀,它定義了管理者進程所支持的調(diào)用接口,通過IWindowSession
內(nèi)部的管理者進程的遠程代理對象唬复,我們就可以實現(xiàn)從應(yīng)用進程向管理者進程發(fā)送消息魂拦。
而在管理者進程中威恼,通過WindowManagerService
來處理來自各個應(yīng)用進程的消息,在WMS
中有一個Session
列表,所有從應(yīng)用進程到管理進程的會話都保存在該列表中抛杨。
<!-- WindowManagerService.java -->
final ArraySet<Session> mSessions = new ArraySet<>();
Session
則實現(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);
}
最終這一跨進程的調(diào)用會回調(diào)到該應(yīng)用進程在管理者進程中對應(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 從管理者進程到應(yīng)用進程
如果我們希望實現(xiàn)從管理者進程發(fā)送消息到應(yīng)用進程丰包,那么也需要一個應(yīng)用進程在管理者進程的代理對象禁熏。
在調(diào)用addToDisplay
時,我們傳入的第一個參數(shù)是mWindow
邑彪,前面我們介紹過瞧毙,它實現(xiàn)了IWindow.Stub
接口:
這樣管理者進程在
Session
的addToDisplay
方法被回調(diào)時,就可以獲得一個遠程代理對象寄症,它就可以通過IWindow
中定義的接口方法宙彪,實現(xiàn)從管理者進程到應(yīng)用進程的通信。
在Session
的addToDisplay()
方法中有巧,會調(diào)用WMS
的addWindow
方法释漆,而在addWindow
方法中,它會創(chuàng)建一個WindowState
對象篮迎,一個進程中的每個ViewRootImpl
會對應(yīng)于一個IWindow
會話男图,它們被保存在WMS
的下面這個HashMap
中:
<!-- WindowManagerService.java -->
final HashMap<IBinder, WindowState> mWindowMap = new HashMap<>();
其中key
值就表示應(yīng)用進程在管理者進程中的遠程代理對象示姿,例如我們在WMS
中調(diào)用了下面這個方法:
<!-- WindowState.java -->
mClient.windowFocusChanged(focused, inTouchMode);
那么應(yīng)用進程中IWindow.Stub
的實現(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)用進程中的主線程所綁定的,因此它就可以在handleMessage
進行后續(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)用進程與WMS
之間通信是通過WindowManagerGlobal
中ViewRootImpl
來管理的乃戈,ViewRootImpl
中的IWindowSession
對應(yīng)于從應(yīng)用進程到WMS
的通信褂痰,而IWindow
對應(yīng)于從管理者進程到應(yīng)用進程的通信。
更多文章症虑,歡迎訪問我的 Android 知識梳理系列:
- Android 知識梳理目錄:http://www.reibang.com/p/fd82d18994ce
- 個人主頁:http://lizejun.cn
- 個人知識總結(jié)目錄:http://lizejun.cn/categories/