日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > Android >内容正文

Android

Android解析WindowManagerService(二)WMS的重要成员和Window的添加过程

發(fā)布時(shí)間:2025/3/20 Android 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android解析WindowManagerService(二)WMS的重要成员和Window的添加过程 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前言

在本系列的上一篇文章中,我們學(xué)習(xí)了WMS的誕生,WMS被創(chuàng)建后,它的重要的成員有哪些?Window添加過(guò)程的WMS部分做了什么呢?這篇文章會(huì)給你解答。

1.WMS的重要成員

所謂WMS的重要成員是指WMS中的重要的成員變量,如下所示。
frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

final WindowManagerPolicy mPolicy; final IActivityManager mActivityManager; final ActivityManagerInternal mAmInternal; final AppOpsManager mAppOps; final DisplaySettings mDisplaySettings; ... final ArraySet<Session> mSessions = new ArraySet<>(); final WindowHashMap mWindowMap = new WindowHashMap(); final ArrayList<AppWindowToken> mFinishedStarting = new ArrayList<>(); final ArrayList<AppWindowToken> mFinishedEarlyAnim = new ArrayList<>(); final ArrayList<AppWindowToken> mWindowReplacementTimeouts = new ArrayList<>(); final ArrayList<WindowState> mResizingWindows = new ArrayList<>(); final ArrayList<WindowState> mPendingRemove = new ArrayList<>(); WindowState[] mPendingRemoveTmp = new WindowState[20]; final ArrayList<WindowState> mDestroySurface = new ArrayList<>(); final ArrayList<WindowState> mDestroyPreservedSurface = new ArrayList<>(); ... final H mH = new H(); ... final WindowAnimator mAnimator; ...final InputManagerService mInputManager

這里列出了WMS的部分成員變量,下面分別對(duì)它們進(jìn)行簡(jiǎn)單的介紹。

mPolicy:WindowManagerPolicy
WindowManagerPolicy(WMP)類(lèi)型的變量。WindowManagerPolicy是窗口管理策略的接口類(lèi),用來(lái)定義一個(gè)窗口策略所要遵循的通用規(guī)范,并提供了WindowManager所有的特定的UI行為。它的具體實(shí)現(xiàn)類(lèi)為PhoneWindowManager,這個(gè)實(shí)現(xiàn)類(lèi)在WMS創(chuàng)建時(shí)被創(chuàng)建。WMP允許定制窗口層級(jí)和特殊窗口類(lèi)型以及關(guān)鍵的調(diào)度和布局。

mSessions:ArraySet
ArraySet類(lèi)型的變量,元素類(lèi)型為Session。在Android解析WindowManager(三)Window的添加過(guò)程這篇文章中我提到過(guò)Session,它主要用于進(jìn)程間通信,其他的應(yīng)用程序進(jìn)程想要和WMS進(jìn)程進(jìn)行通信就需要經(jīng)過(guò)Session,并且每個(gè)應(yīng)用程序進(jìn)程都會(huì)對(duì)應(yīng)一個(gè)Session,WMS保存這些Session用來(lái)記錄所有向WMS提出窗口管理服務(wù)的客戶端。
mWindowMap:WindowHashMap
WindowHashMap類(lèi)型的變量,WindowHashMap繼承了HashMap,它限制了HashMap的key值的類(lèi)型為IBinder,value值的類(lèi)型為WindowState。WindowState用于保存窗口的信息,在WMS中它用來(lái)描述一個(gè)窗口。綜上得出結(jié)論,mWindowMap就是用來(lái)保存WMS中各種窗口的集合。

mFinishedStarting:ArrayList
ArrayList類(lèi)型的變量,元素類(lèi)型為AppWindowToken,它是WindowToken的子類(lèi)。要想理解mFinishedStarting的含義,需要先了解WindowToken是什么。WindowToken主要有兩個(gè)作用:

  • 可以理解為窗口令牌,當(dāng)應(yīng)用程序想要向WMS申請(qǐng)新創(chuàng)建一個(gè)窗口,則需要向WMS出示有效的WindowToken。AppWindowToken作為WindowToken的子類(lèi),主要用來(lái)描述應(yīng)用程序的WindowToken結(jié)構(gòu),
    應(yīng)用程序中每個(gè)Activity都對(duì)應(yīng)一個(gè)AppWindowToken。
  • WindowToken會(huì)將相同組件(比如Acitivity)的窗口(WindowState)集合在一起,方便管理。

mFinishedStarting就是用于存儲(chǔ)已經(jīng)完成啟動(dòng)的應(yīng)用程序窗口(比如Acitivity)的AppWindowToken的列表。
除了mFinishedStarting,還有類(lèi)似的mFinishedEarlyAnim和mWindowReplacementTimeouts,其中mFinishedEarlyAnim存儲(chǔ)了已經(jīng)完成窗口繪制并且不需要展示任何已保存surface的應(yīng)用程序窗口的AppWindowToken。mWindowReplacementTimeout存儲(chǔ)了等待更換的應(yīng)用程序窗口的AppWindowToken,如果更換不及時(shí),舊窗口就需要被處理。

mResizingWindows:ArrayList
ArrayList類(lèi)型的變量,元素類(lèi)型為WindowState。
mResizingWindows是用來(lái)存儲(chǔ)正在調(diào)整大小的窗口的列表。與mResizingWindows類(lèi)似的還有mPendingRemove、mDestroySurface和mDestroyPreservedSurface等等。其中mPendingRemove是在內(nèi)存耗盡時(shí)設(shè)置的,里面存有需要強(qiáng)制刪除的窗口。mDestroySurface里面存有需要被Destroy的Surface。mDestroyPreservedSurface里面存有窗口需要保存的等待銷(xiāo)毀的Surface,為什么窗口要保存這些Surface?這是因?yàn)楫?dāng)窗口經(jīng)歷Surface變化時(shí),窗口需要一直保持舊Surface,直到新Surface的第一幀繪制完成。

mAnimator:WindowAnimator
WindowAnimator類(lèi)型的變量,用于管理窗口的動(dòng)畫(huà)以及特效動(dòng)畫(huà)。

mH:H
H類(lèi)型的變量,系統(tǒng)的Handler類(lèi),用于將任務(wù)加入到主線程的消息隊(duì)列中,這樣代碼邏輯就會(huì)在主線程中執(zhí)行。

mInputManager:InputManagerService
InputManagerService類(lèi)型的變量,輸入系統(tǒng)的管理者。InputManagerService(IMS)會(huì)對(duì)觸摸事件進(jìn)行處理,它會(huì)尋找一個(gè)最合適的窗口來(lái)處理觸摸反饋信息,WMS是窗口的管理者,因此,WMS“理所應(yīng)當(dāng)”的成為了輸入系統(tǒng)的中轉(zhuǎn)站,WMS包含了IMS的引用不足為怪。

2.Window的添加過(guò)程(WMS部分)

我們知道Window的操作分為兩大部分,一部分是WindowManager處理部分,另一部分是WMS處理部分,如下所示。
在Android解析WindowManager(三)Window的添加過(guò)程這篇文章中,我講解了Window的添加過(guò)程的WindowManager處理部分,這一篇文章我們接著來(lái)學(xué)習(xí)Window的添加過(guò)程的WMS部分。
無(wú)論是系統(tǒng)窗口還是Activity,它們的Window的添加過(guò)程都會(huì)調(diào)用WMS的addWindow方法,由于這個(gè)方法代碼邏輯比較多,這里分為3個(gè)部分來(lái)閱讀。
frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

addWindow方法part1

public int addWindow(Session session, IWindow client, int seq,WindowManager.LayoutParams attrs, int viewVisibility, int displayId,Rect outContentInsets, Rect outStableInsets, Rect outOutsets,InputChannel outInputChannel) {int[] appOp = new int[1];int res = mPolicy.checkAddPermission(attrs, appOp);//1if (res != WindowManagerGlobal.ADD_OKAY) {return res;}...synchronized(mWindowMap) {if (!mDisplayReady) {throw new IllegalStateException("Display has not been initialialized");}final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);//2if (displayContent == null) {Slog.w(TAG_WM, "Attempted to add window to a display that does not exist: "+ displayId + ". Aborting.");return WindowManagerGlobal.ADD_INVALID_DISPLAY;}...if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {//3parentWindow = windowForClientLocked(null, attrs.token, false);//4if (parentWindow == null) {Slog.w(TAG_WM, "Attempted to add window with token that is not a window: "+ attrs.token + ". Aborting.");return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;}if (parentWindow.mAttrs.type >= FIRST_SUB_WINDOW&& parentWindow.mAttrs.type <= LAST_SUB_WINDOW) {Slog.w(TAG_WM, "Attempted to add window with token that is a sub-window: "+ attrs.token + ". Aborting.");return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;}}... } ... }

WMS的addWindow返回的是addWindow的各種狀態(tài),比如添加Window成功,無(wú)效的display等等,這些狀態(tài)被定義在WindowManagerGlobal中。
注釋1處根據(jù)Window的屬性,調(diào)用WMP的checkAddPermission方法來(lái)檢查權(quán)限,具體的實(shí)現(xiàn)在PhoneWindowManager的checkAddPermission方法中,如果沒(méi)有權(quán)限則不會(huì)執(zhí)行后續(xù)的代碼邏輯。注釋2處通過(guò)displayId來(lái)獲得窗口要添加到哪個(gè)DisplayContent上,如果沒(méi)有找到DisplayContent,則返回WindowManagerGlobal.ADD_INVALID_DISPLAY這一狀態(tài),其中DisplayContent用來(lái)描述一塊屏幕。注釋3處,type代表一個(gè)窗口的類(lèi)型,它的數(shù)值介于FIRST_SUB_WINDOW和LAST_SUB_WINDOW之間(1000~1999),這個(gè)數(shù)值定義在WindowManager中,說(shuō)明這個(gè)窗口是一個(gè)子窗口,不了解窗口類(lèi)型取值范圍的請(qǐng)閱讀Android解析WindowManager(二)Window的屬性這篇文章。注釋4處,attrs.token是IBinder類(lèi)型的對(duì)象,windowForClientLocked方法內(nèi)部會(huì)根據(jù)attrs.token作為key值從mWindowMap中得到該子窗口的父窗口。接著對(duì)父窗口進(jìn)行判斷,如果父窗口為null或者type的取值范圍不正確則會(huì)返回錯(cuò)誤的狀態(tài)。

addWindow方法part2

...AppWindowToken atoken = null;final boolean hasParent = parentWindow != null;WindowToken token = displayContent.getWindowToken(hasParent ? parentWindow.mAttrs.token : attrs.token);//1final int rootType = hasParent ? parentWindow.mAttrs.type : type;//2boolean addToastWindowRequiresToken = false;if (token == null) {if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {Slog.w(TAG_WM, "Attempted to add application window with unknown token "+ attrs.token + ". Aborting.");return WindowManagerGlobal.ADD_BAD_APP_TOKEN;}if (rootType == TYPE_INPUT_METHOD) {Slog.w(TAG_WM, "Attempted to add input method window with unknown token "+ attrs.token + ". Aborting.");return WindowManagerGlobal.ADD_BAD_APP_TOKEN;}if (rootType == TYPE_VOICE_INTERACTION) {Slog.w(TAG_WM, "Attempted to add voice interaction window with unknown token "+ attrs.token + ". Aborting.");return WindowManagerGlobal.ADD_BAD_APP_TOKEN;}if (rootType == TYPE_WALLPAPER) {Slog.w(TAG_WM, "Attempted to add wallpaper window with unknown token "+ attrs.token + ". Aborting.");return WindowManagerGlobal.ADD_BAD_APP_TOKEN;}...if (type == TYPE_TOAST) {// Apps targeting SDK above N MR1 cannot arbitrary add toast windows.if (doesAddToastWindowRequireToken(attrs.packageName, callingUid,parentWindow)) {Slog.w(TAG_WM, "Attempted to add a toast window with unknown token "+ attrs.token + ". Aborting.");return WindowManagerGlobal.ADD_BAD_APP_TOKEN;}}final IBinder binder = attrs.token != null ? attrs.token : client.asBinder();token = new WindowToken(this, binder, type, false, displayContent,session.mCanAddInternalSystemWindow);//3} else if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {//4atoken = token.asAppWindowToken();//5if (atoken == null) {Slog.w(TAG_WM, "Attempted to add window with non-application token "+ token + ". Aborting.");return WindowManagerGlobal.ADD_NOT_APP_TOKEN;} else if (atoken.removed) {Slog.w(TAG_WM, "Attempted to add window with exiting application token "+ token + ". Aborting.");return WindowManagerGlobal.ADD_APP_EXITING;}} else if (rootType == TYPE_INPUT_METHOD) {if (token.windowType != TYPE_INPUT_METHOD) {Slog.w(TAG_WM, "Attempted to add input method window with bad token "+ attrs.token + ". Aborting.");return WindowManagerGlobal.ADD_BAD_APP_TOKEN;}}...

注釋1處通過(guò)displayContent的getWindowToken方法來(lái)得到WindowToken。注釋2處,如果有父窗口就將父窗口的type值賦值給rootType,如果沒(méi)有將當(dāng)前窗口的type值賦值給rootType。接下來(lái)如果WindowToken為null,則根據(jù)rootType或者type的值進(jìn)行區(qū)分判斷,如果rootType值等于TYPE_INPUT_METHOD、TYPE_WALLPAPER等值時(shí),則返回狀態(tài)值WindowManagerGlobal.ADD_BAD_APP_TOKEN,說(shuō)明rootType值等于TYPE_INPUT_METHOD、TYPE_WALLPAPER等值時(shí)是不允許WindowToken為null的。通過(guò)多次的條件判斷篩選,最后會(huì)在注釋3處隱式創(chuàng)建WindowToken,這說(shuō)明當(dāng)我們添加窗口時(shí)是可以不向WMS提供WindowToken的,前提是rootType和type的值不為前面條件判斷篩選的值。WindowToken隱式和顯式的創(chuàng)建肯定是要加以區(qū)分的,注釋3處的第4個(gè)參數(shù)為false就代表這個(gè)WindowToken是隱式創(chuàng)建的。接下來(lái)的代碼邏輯就是WindowToken不為null的情況,根據(jù)rootType和type的值進(jìn)行判斷,比如在注釋4處判斷如果窗口為應(yīng)用程序窗口,在注釋5處會(huì)將WindowToken轉(zhuǎn)換為專門(mén)針對(duì)應(yīng)用程序窗口的AppWindowToken,然后根據(jù)AppWindowToken的值進(jìn)行后續(xù)的判斷。

addWindow方法part3

... final WindowState win = new WindowState(this, session, client, token, parentWindow,appOp[0], seq, attrs, viewVisibility, session.mUid,session.mCanAddInternalSystemWindow);//1if (win.mDeathRecipient == null) {//2// Client has apparently died, so there is no reason to// continue.Slog.w(TAG_WM, "Adding window client " + client.asBinder()+ " that is dead, aborting.");return WindowManagerGlobal.ADD_APP_EXITING;}if (win.getDisplayContent() == null) {//3Slog.w(TAG_WM, "Adding window to Display that has been removed.");return WindowManagerGlobal.ADD_INVALID_DISPLAY;}mPolicy.adjustWindowParamsLw(win.mAttrs);//4 win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));res = mPolicy.prepareAddWindowLw(win, attrs);//5 ...win.attach();mWindowMap.put(client.asBinder(), win);//6if (win.mAppOp != AppOpsManager.OP_NONE) {int startOpResult = mAppOps.startOpNoThrow(win.mAppOp, win.getOwningUid(),win.getOwningPackage());if ((startOpResult != AppOpsManager.MODE_ALLOWED) &&(startOpResult != AppOpsManager.MODE_DEFAULT)) {win.setAppOpVisibilityLw(false);}}final AppWindowToken aToken = token.asAppWindowToken();if (type == TYPE_APPLICATION_STARTING && aToken != null) {aToken.startingWindow = win;if (DEBUG_STARTING_WINDOW) Slog.v (TAG_WM, "addWindow: " + aToken+ " startingWindow=" + win);}boolean imMayMove = true;win.mToken.addWindow(win);//7if (type == TYPE_INPUT_METHOD) {win.mGivenInsetsPending = true;setInputMethodWindowLocked(win);imMayMove = false;} else if (type == TYPE_INPUT_METHOD_DIALOG) {displayContent.computeImeTarget(true /* updateImeTarget */);imMayMove = false;} else {if (type == TYPE_WALLPAPER) {displayContent.mWallpaperController.clearLastWallpaperTimeoutTime();displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;} else if ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0) {displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;} else if (displayContent.mWallpaperController.isBelowWallpaperTarget(win)) {displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;}}...

在注釋1處創(chuàng)建了WindowState,它存有窗口的所有的狀態(tài)信息,在WMS中它代表一個(gè)窗口。從WindowState傳入的參數(shù),可以發(fā)現(xiàn)WindowState中包含了WMS、Session、WindowToken、父類(lèi)的WindowState、LayoutParams等信息。緊接著在注釋2和3處分別判斷請(qǐng)求添加窗口的客戶端是否已經(jīng)死亡、窗口的DisplayContent是否為null,如果是則不會(huì)再執(zhí)行下面的代碼邏輯。注釋4處調(diào)用了WMP的adjustWindowParamsLw方法,該方法的實(shí)現(xiàn)在PhoneWindowManager中,會(huì)根據(jù)窗口的type對(duì)窗口的LayoutParams的一些成員變量進(jìn)行修改。注釋5處調(diào)用WMP的prepareAddWindowLw方法,用于準(zhǔn)備將窗口添加到系統(tǒng)中。
注釋6處將WindowState添加到mWindowMap中。注釋7處將WindowState添加到該WindowState對(duì)應(yīng)的WindowToken中(實(shí)際是保存在WindowToken的父類(lèi)WindowContainer中),這樣WindowToken就包含了相同組件的WindowState。

addWindow方法總結(jié)

addWindow方法分了3個(gè)部分來(lái)進(jìn)行講解,主要就是做了下面4件事:

  • 對(duì)所要添加的窗口進(jìn)行檢查,如果窗口不滿足一些條件,就不會(huì)再執(zhí)行下面的代碼邏輯。
  • WindowToken相關(guān)的處理,比如有的窗口類(lèi)型需要提供WindowToken,沒(méi)有提供的話就不會(huì)執(zhí)行下面的代碼邏輯,有的窗口類(lèi)型則需要由WMS隱式創(chuàng)建WindowToken。
  • WindowState的創(chuàng)建和相關(guān)處理,將WindowToken和WindowState相關(guān)聯(lián)。
  • 創(chuàng)建和配置DisplayContent,完成窗口添加到系統(tǒng)前的準(zhǔn)備工作。
  • 結(jié)語(yǔ)

    在本篇文章中我們首先學(xué)習(xí)了WMS的重要成員,了解這些成員有利于對(duì)WMS的進(jìn)一步分析。接下來(lái)我們又學(xué)習(xí)了Window的添加過(guò)程的WMS部分,將addWindow方法分為了3個(gè)部分來(lái)進(jìn)行講解,從addWindow方法我們得知WMS有3個(gè)重要的類(lèi)分別是WindowToken、WindowState和DisplayContent,關(guān)于它們會(huì)在本系列后續(xù)的文章中進(jìn)行介紹。

    ?

    轉(zhuǎn)載于:https://www.cnblogs.com/ganchuanpu/p/6864088.html

    總結(jié)

    以上是生活随笔為你收集整理的Android解析WindowManagerService(二)WMS的重要成员和Window的添加过程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。