新聞中心
[[423965]]
前言
WindowManagerService是位于Framework層的窗口管理服務,它的職責是管理系統(tǒng)中的所有窗口,也就是Window,關(guān)于Window的介紹,通俗來說,Window就是手機上一塊顯示區(qū)域,也就是Android中的繪制畫布Surface,添加一個Window的過程,也就是申請分配一塊Surface的過程,而整個流程的管理者正是WindowManagerService;

創(chuàng)新互聯(lián)建站專注于企業(yè)全網(wǎng)營銷推廣、網(wǎng)站重做改版、伊犁網(wǎng)站定制設計、自適應品牌網(wǎng)站建設、H5場景定制、商城系統(tǒng)網(wǎng)站開發(fā)、集團公司官網(wǎng)建設、外貿(mào)網(wǎng)站建設、高端網(wǎng)站制作、響應式網(wǎng)頁設計等建站業(yè)務,價格優(yōu)惠性價比高,為伊犁等各大城市提供網(wǎng)站開發(fā)制作服務。
今天我們來分析下窗口WMS相關(guān)的知識點;
一、窗口相關(guān)概念
1、WindowManagerService概念
(1)WindowManagerService概念
Framework層的窗口管理服務,職責是管理Android系統(tǒng)中所有window。窗口管理服務,繼承IWindowManager.Stub,Binder服務端,因此WM與WMS的交互也是一個IPC過程。WMS主要做的事情如下:
- Z-ordered的維護函數(shù)
- 輸入法管理
- AddWindow/RemoveWindow
- Layerout
- Token管理,AppToken
- 活動窗口管理(FocusWindow)
- 活動應用管理(FocusApp)
- 轉(zhuǎn)場動畫
- 系統(tǒng)消息收集線程
- 系統(tǒng)消息分發(fā)線程
(2)WindowManager
應用與窗口管理服務WindowManagerService交互的接口;
(3)PhoneWindowManager
實現(xiàn)了窗口的各種策略,定義了窗口相關(guān)策略,比如:告訴WMS某一個類型Window的Z-Order的值是多少,幫助WMS矯正不合理的窗口屬性,為WMS監(jiān)聽屏幕旋轉(zhuǎn)的狀態(tài),預處理一些系統(tǒng)按鍵事件;
(4)Choreographer
用戶控制窗口動畫、屏幕選擇等操作,它擁有從顯示子系統(tǒng)獲取Vsync同步事件的能力,從而可以在合適的時機通知渲染動作,避免在渲染的過程中因為發(fā)生屏幕重繪而導致的畫面撕裂。WMS使用Choreographer負責驅(qū)動所有的窗口動畫、屏幕旋轉(zhuǎn)動畫、墻紙動畫的渲染;
(5)DisplayContent
用于描述多屏輸出相關(guān)信息;
根據(jù)窗口的顯示位置將其分組。隸屬于同一個DisplayContent的窗口將會被顯示在同一個屏幕中。每個DisplayContent都對應著唯一ID,在添加窗口的時候可以通過指定這個ID決定其將顯示在哪個屏幕中;
DisplayContent是一個非常具有隔離性的一個概念。處于不同DisplayContent的兩個窗口在布局、顯示順序以及動畫處理上不會產(chǎn)生任何耦合;
(6)WindowState
描述窗口的狀態(tài)信息以及和WindowManagerService進行通信,一般一個窗口對應一個WindowState。它用來表示一個窗口的所有屬性;
(7)WindowToken
- 窗口Token,用來做Binder通信;同時也是一種標識;
- 在進行窗口Zorder排序時,屬于同一個WindowToken的窗口會被安排在一起,而且在其中定義的一些屬性將會影響所有屬于此WindowToken的窗口,這些都表明了屬于同一個WindowToken的窗口之間的緊密聯(lián)系;
- 應用組件在需要新的窗口時,必須提供WindowToken以表明自己的身份,并且窗口的類型必須與所持有的WindowToken的類型一致;
- 在創(chuàng)建系統(tǒng)類型的窗口時不需要提供一個有效的Token,WMS會隱式地為其聲明一個WindowToken,看起來誰都可以添加個系統(tǒng)級的窗口。難道Android為了內(nèi)部使用方便而置安全于不顧嗎?非也,addWindow()函數(shù)一開始的mPolicy.checkAddPermission()的目的就是如此。它要求客戶端必須擁有SYSTEM_ALERT_WINDOW或INTERNAL_SYSTEM_WINDOW權(quán)限才能創(chuàng)建系;
(8)Session
App進程通過建立Session代理對象和Session對象通信,進而和WMS建立連接;
(9)SurfaceFlinger
SurfaceFlinger負責管理Android系統(tǒng)的幀緩沖區(qū)(Frame Buffer),Android設備的顯示屏被抽象為一個幀緩沖區(qū),而Android系統(tǒng)中的SurfaceFlinger服務就是通過向這個幀緩沖區(qū)寫入內(nèi)容來繪制應用程序中的用戶界面的;
(10)InputManager
管理每個窗口的輸入事件通道(InputChannel)以及向通道上派發(fā)事件;
(11)Animator
所有窗口動畫的總管(WindowStateAnimator對象)。在Choreographer的驅(qū)動下,逐個渲染所有的動畫;
2、Window
- 表示一個窗口的概念,是所有View的直接管理者,任何視圖都通過Window呈現(xiàn)(點擊事件由Window->DecorView->View;Activity的setContentView底層通過Window完成)
- Window是一個抽象類,具體實現(xiàn)是PhoneWindow;
- 創(chuàng)建Window需要通過WindowManager創(chuàng)建;
- WindowManager是外界訪問Window的入口;
- Window的具體實現(xiàn)位于WindowManagerService中;
- WindowManager和WindowManagerService的交互是通過IPC進程間通信完成的;
- 定義窗口樣式和行為的抽象基類,用于作為頂層的View加到WindowManager中,其實現(xiàn)類是PhoneWindow;
- 每個Window都需要指定一個Type(應用窗口、子窗口、系統(tǒng)窗口)。Activity對應的窗口是應用窗口;PhoneWindow,ContextMenu,OptionMenu是常用的子窗口;像Toast和系統(tǒng)警告提示框(如ANR)就是系統(tǒng)窗口,還有很多應用的懸浮窗也屬于系統(tǒng)窗口;
3、Surface
- 在Android中,一個窗口會獨占一個Surface,Surface其實就是一個畫布,應用程序通過Canvas或者OpenGL在Surface上繪制內(nèi)容;
- 在Surface上繪制后,通過SurfaceFlinger將多塊Surface的內(nèi)容按照Z-order進行混合并輸出到FrameBuffer,從而將Android頁面展示給用戶;
- 每個窗口都有一塊Surface用于顯示自己的ui,必然需要一個角色對窗口進行統(tǒng)一管理,這個時候,WMS應運而生。WMS為所有窗口分配Surface,掌管z-order以及位置、尺寸、窗口的進場出場動畫,并且還是輸入系統(tǒng)的中轉(zhuǎn)站;
- 布局系統(tǒng):計算管理窗口的位置和層次;
- 動畫系統(tǒng):根據(jù)布局系統(tǒng)的計算渲染窗口動畫;
4、Window的Type
- 應用窗口:層級范圍是1~99
- 子窗口:層級范圍是1000~1999
- 系統(tǒng)窗口:層級范圍是2000~2999
5、窗口flags顯示屬性
- // 窗口特征標記
- public int flags;
- // 當該window對用戶可見時,允許鎖屏
- public static final int FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001;
- // 窗口后面的所有內(nèi)容都變暗
- public static final int FLAG_DIM_BEHIND = 0x00000002;
- // 窗口后面的所有內(nèi)容都變模糊
- public static final int FLAG_BLUR_BEHIND = 0x00000004;
- // 窗口不能獲得焦點
- public static final int FLAG_NOT_FOCUSABLE = 0x00000008;
- // 窗口不接受觸摸屏事件
- public static final int FLAG_NOT_TOUCHABLE = 0x00000010;
- // 即使在該window可獲得焦點情況下,允許該窗口之處的點擊事件傳遞到當前窗口后面的窗口去
- public static final int FLAG_NOT_TOUCH_MODAL = 0x00000020;
- // 當手機處于睡眠狀態(tài),如果屏幕被按下,那么該window將第一個收到觸摸事件
- public static final int FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040;
- // 當該window對用戶可見時,屏幕處于常亮狀態(tài)
- public static final int FLAG_KEEP_SCREEN_ON = 0x00000080;
- // 讓window占滿整個屏幕,不留任何邊界
- public static final int FLAG_LAYOUT_IN_SCREEN = 0x00000100;
- // 允許窗口超出整個手機屏幕
- public static final int FLAG_LAYOUT_NO_LIMITS = 0x00000200;
- // window全名顯示
- public static final int FLAG_FULLSCREEN = 0x00000400;
- // 恢復window非全屏顯示
- public static final int FLAG_FORCE_NOT_FULLSCREEN = 0x00000800;
- // 開啟窗口抖動
- public static final int FLAG_DITHER = 0x00001000;
- // 安全內(nèi)容窗口,該窗口顯示時不允許截屏
- public static final int FLAG_SECURE = 0x00002000;
- // 一種特殊模式,在該模式下,布局參數(shù)用于在將表面合成到屏幕時執(zhí)行縮放。
- public static final int FLAG_SCALED = 0x00004000;
- public static final int FLAG_IGNORE_CHEEK_PRESSES = 0x00008000;
- public static final int FLAG_LAYOUT_INSET_DECOR = 0x00010000;
- public static final int FLAG_ALT_FOCUSABLE_IM = 0x00020000;
- // 接收單個特殊的MotionEvent,以應對窗口外發(fā)生的觸摸。
- // 不會收到完整的向下/向上/向上手勢,而只會收到第一次向下的位置作為ACTION_OUTSIDE。
- public static final int FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000;
- // 鎖屏時顯示該窗口
- public static final int FLAG_SHOW_WHEN_LOCKED = 0x00080000;
- // 系統(tǒng)的墻紙顯示在該窗口之后
- public static final int FLAG_SHOW_WALLPAPER = 0x00100000;
- // 當window被顯示的時候,系統(tǒng)將把它當做一個用戶活動事件,以點亮手機屏幕
- public static final int FLAG_TURN_SCREEN_ON = 0x00200000;
- // 該窗口顯示,消失鍵盤
- public static final int FLAG_DISMISS_KEYGUARD = 0x00400000;
- // 當window在可以接受觸摸屏情況下,讓因在該window之外,而發(fā)送到后面的window的
- // 觸摸屏可以支持split touch
- public static final int FLAG_SPLIT_TOUCH = 0x00800000;
- // 對該window進行硬件加速,該flag必須在activity或者dialog的content view之前進行設置
- public static final int FLAG_HARDWARE_ACCELERATED = 0x01000000;
- // 讓該window占滿整個手機屏幕,不留任何邊界
- public static final int FLAG_LAYOUT_IN_OVERSCAN = 0x02000000;
- // 透明狀態(tài)欄
- public static final int FLAG_TRANSLUCENT_STATUS = 0x04000000;
- // 透明導航欄
- public static final int FLAG_TRANSLUCENT_STATUS = 0x04000000;
二、 Window的添加流程
- public final class WindowManagerGlobal {
- public void addView(View view, ViewGroup.LayoutParams params,
- Display display, Window parentWindow) {
- //校驗參數(shù)的合法性
- ...
- //ViewRootImpl封裝了View與WindowManager的交互力促
- ViewRootImpl root;
- View panelParentView = null;
- synchronized (mLock) {
- // Start watching for system property changes.
- if (mSystemPropertyUpdater == null) {
- mSystemPropertyUpdater = new Runnable() {
- @Override public void run() {
- synchronized (mLock) {
- for (int i = mRoots.size() - 1; i >= 0; --i) {
- mRoots.get(i).loadSystemProperties();
- }
- }
- }
- };
- SystemProperties.addChangeCallback(mSystemPropertyUpdater);
- }
- int index = findViewLocked(view, false);
- if (index >= 0) {
- if (mDyingViews.contains(view)) {
- // Don't wait for MSG_DIE to make it's way through root's queue.
- mRoots.get(index).doDie();
- } else {
- throw new IllegalStateException("View " + view
- + " has already been added to the window manager.");
- }
- // The previous removeView() had not completed executing. Now it has.
- }
- // If this is a panel window, then find the window it is being
- // attached to for future reference.
- if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
- wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
- final int count = mViews.size();
- for (int i = 0; i < count; i++) {
- if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
- panelParentView = mViews.get(i);
- }
- }
- }
- //通過上下文構(gòu)建ViewRootImpl
- root = new ViewRootImpl(view.getContext(), display);
- view.setLayoutParams(wparams);
- //mViews存儲著所有Window對應的View對象
- mViews.add(view);
- //mRoots存儲著所有Window對應的ViewRootImpl對象
- mRoots.add(root);
- //mParams存儲著所有Window對應的WindowManager.LayoutParams對象
- mParams.add(wparams);
- }
- // do this last because it fires off messages to start doing things
- try {
- //調(diào)用ViewRootImpl.setView()方法完成Window的添加并更新界面
- root.setView(view, wparams, panelParentView);
- } catch (RuntimeException e) {
- // BadTokenException or InvalidDisplayException, clean up.
- synchronized (mLock) {
- final int index = findViewLocked(view, false);
- if (index >= 0) {
- removeViewLocked(index, true);
- }
- }
- throw e;
- }
- }
- }
在這個方法里有三個重要的成員變量:
- mViews 存儲著所有Window對應的View對象;
- mRoots 存儲著所有Window對應的ViewRootImpl對象;
- mParams 存儲著所有Window對應的WindowManager.LayoutParams對象;
- 這里面提到了一個我們不是很熟悉的類ViewRootImpl,它其實就是一個封裝類,封裝了View與WindowManager的交互方式,它是View與WindowManagerService通信的橋梁;
- 最后也是調(diào)用ViewRootImpl.setView()方法完成Window的添加并更新界面;
我們來看看這個方法的實現(xiàn)
- public final class ViewRootImpl implements ViewParent,
- View.AttachInfo.Callbacks, ThreadedRenderer.HardwareDrawCallbacks {
- public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
- synchronized (this) {
- if (mView == null) {
- mView = view;
- //參數(shù)校驗與預處理
- ...
- // 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.
- //1. 調(diào)用requestLayout()完成界面異步繪制的請求
- 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();
- //2. 創(chuàng)建WindowSession并通過WindowSession請求WindowManagerService來完成Window添加的過程
- //這是一個IPC的過程。
- 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();
- }
- }
- ...
- }
- }
- }
- 調(diào)用requestLayout()完成界面異步繪制的請求,requestLayout()會去調(diào)用scheduleTraversals()來完成View的繪制,scheduleTraversals()方法將一個TraversalRunnable提交到工作隊列中執(zhí)行View的繪制。而TraversalRunnable最終調(diào)用了performTraversals()方法來完成實際的繪制操作。提到performTraversals()方法我們已經(jīng)很熟悉了;
- 創(chuàng)建WindowSession并通過WindowSession請求WindowManagerService來完成Window添加的過程這是一個IPC的過程,WindowManagerService作為實際的窗口管理者,窗口的創(chuàng)建、刪除和更新都是由它來完成的,它同時還負責了窗口的層疊排序和大小計算等工作;
performTraversals()方法的實現(xiàn):
- 獲取Surface對象,用于圖形繪制;
- 調(diào)用performMeasure()方法測量視圖樹各個View的大小;
- 調(diào)用performLayout()方法計算視圖樹各個View的位置,進行布局;
- 調(diào)用performMeasure()方法對視圖樹的各個View進行繪制;
WindowManager與WindowManagerService的跨進程通信。Android的各種服務都是基于C/S結(jié)構(gòu)來設計的,系統(tǒng)層提供服務,應用層使用服務。WindowManager也是一樣,它與
WindowManagerService的通信是通過WindowSession來完成的;
首先調(diào)用ServiceManager.getService("window")獲取WindowManagerService,該方法返回的是IBinder對象,然后調(diào)用IWindowManager.Stub.asInterface()方法將WindowManagerService轉(zhuǎn)換為一個IWindowManager對象;
然后調(diào)用openSession()方法與WindowManagerService建立一個通信會話,方便后續(xù)的跨進程通信。這個通信會話就是后面我們用到的WindowSession;
基本上所有的Android系統(tǒng)服務都是基于這種方式實現(xiàn)的,它是一種基于AIDL實現(xiàn)的IPC的過程;
- public final class WindowManagerGlobal {
- public static IWindowSession getWindowSession() {
- synchronized (WindowManagerGlobal.class) {
- if (sWindowSession == null) {
- try {
- InputMethodManager imm = InputMethodManager.getInstance();
- //獲取WindowManagerService對象,并將它轉(zhuǎn)換為IWindowManager類型
- IWindowManager windowManager = getWindowManagerService();
- //調(diào)用openSession()方法與WindowManagerService建立一個通信會話,方便后續(xù)的
- //跨進程通信。
- 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;
- }
- }
- public static IWindowManager getWindowManagerService() {
- synchronized (WindowManagerGlobal.class) {
- if (sWindowManagerService == null) {
- //調(diào)用ServiceManager.getService("window")獲取WindowManagerService,該方法返回的是IBinder對象
- //,然后調(diào)用IWindowManager.Stub.asInterface()方法將WindowManagerService轉(zhuǎn)換為一個IWindowManager對象
- sWindowManagerService = IWindowManager.Stub.asInterface(
- ServiceManager.getService("window"));
- try {
- if (sWindowManagerService != null) {
- ValueAnimator.setDurationScale(sWindowManagerService.getCurrentAnimatorScale());
- }
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
- return sWindowManagerService;
- }
- }
- }
三、 Window的刪除流程
Window的刪除流程也是在WindowManagerGlobal里完成
- public final class WindowManagerGlobal {
- public void removeView(View view, boolean immediate) {
- if (view == null) {
- throw new IllegalArgumentException("view must not be null");
- }
- synchronized (mLock) {
- //1. 查找待刪除View的索引
- int index = findViewLocked(view, true);
- View curView = mRoots.get(index).getView();
- //2. 調(diào)用removeViewLocked()完成View的刪除, removeViewLocked()方法
- //繼續(xù)調(diào)用ViewRootImpl.die()方法來完成View的刪除。
- removeViewLocked(index, immediate);
- if (curView == view) {
- return;
- }
- throw new IllegalStateException("Calling with view " + view
- + " but the ViewAncestor is attached to " + curView);
- }
- }
- private void removeViewLocked(int index, boolean immediate) {
- ViewRootImpl root = mRoots.get(index);
- View view = root.getView();
- if (view != null) {
- InputMethodManager imm = InputMethodManager.getInstance();
- if (imm != null) {
- imm.windowDismissed(mViews.get(index).getWindowToken());
- }
- }
- boolean deferred = root.die(immediate);
- if (view != null) {
- view.assignParent(null);
- if (deferred) {
- mDyingViews.add(view);
- }
- }
- }
- }
我們再來看看ViewRootImpl.die()方法的實現(xiàn);
- public final class ViewRootImpl implements ViewParent,
- View.AttachInfo.Callbacks, ThreadedRenderer.HardwareDrawCallbacks {
- boolean die(boolean immediate) {
- // Make sure we do execute immediately if we are in the middle of a traversal or the damage
- // done by dispatchDetachedFromWindow will cause havoc on return.
- //根據(jù)immediate參數(shù)來判斷是執(zhí)行異步刪除還是同步刪除
- if (immediate && !mIsInTraversal) {
- doDie();
- return false;
- }
- if (!mIsDrawing) {
- destroyHardwareRenderer();
- } else {
- Log.e(mTag, "Attempting to destroy the window while drawing!\n" +
- " window=" + this + ", title=" + mWindowAttributes.getTitle());
- }
- //如果是異步刪除,則發(fā)送一個刪除View的消息MSG_DIE就會直接返回
- mHandler.sendEmptyMessage(MSG_DIE);
- return true;
- }
- void doDie() {
- checkThread();
- if (LOCAL_LOGV) Log.v(mTag, "DIE in " + this + " of " + mSurface);
- synchronized (this) {
- if (mRemoved) {
- return;
- }
- mRemoved = true;
- if (mAdded) {
- //調(diào)用dispatchDetachedFromWindow()完成View的刪除
- dispatchDetachedFromWindow();
- }
- if (mAdded && !mFirst) {
- destroyHardwareRenderer();
- if (mView != null) {
- int viewVisibility = mView.getVisibility();
- boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
網(wǎng)頁名稱:Android進階:深入理解Android窗口管理框架機制
文章地址:http://www.dlmjj.cn/article/ccopjeg.html


咨詢
建站咨詢
