欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

深入理解窗口令牌WindowToken

 更新時(shí)間:2021年08月20日 16:47:51   作者:15130140362  
這篇文章主要介紹了窗口令牌WindowToken的概念與作用,它是對(duì)應(yīng)用組件的行為進(jìn)行規(guī)范管理的一個(gè)手段。WindowToken由應(yīng)用組件或其管理者負(fù)責(zé)向WMS聲明并持有

1.WindowToken的意義

為了搞清楚WindowToken的作用是什么,看一下其位于WindowToken.java中的定義。雖然它沒(méi)有定義任何函數(shù),但其成員變量的意義卻很重要。

  • WindowToken將屬于同一個(gè)應(yīng)用組件的窗口組織在了一起。所謂的應(yīng)用組件可以是Activity、InputMethod、Wallpaper以及Dream。在WMS對(duì)窗口的管理過(guò)程中,用WindowToken指代一個(gè)應(yīng)用組件。例如在進(jìn)行窗口ZOrder排序時(shí),屬于同一個(gè)WindowToken的窗口會(huì)被安排在一起,而且在其中定義的一些屬性將會(huì)影響所有屬于此WindowToken的窗口。這些都表明了屬于同一個(gè)WindowToken的窗口之間的緊密聯(lián)系。
  • WindowToken具有令牌的作用,是對(duì)應(yīng)用組件的行為進(jìn)行規(guī)范管理的一個(gè)手段。WindowToken由應(yīng)用組件或其管理者負(fù)責(zé)向WMS聲明并持有。應(yīng)用組件在需要新的窗口時(shí),必須提供WindowToken以表明自己的身份,并且窗口的類型必須與所持有的WindowToken的類型一致。從上面的代碼可以看到,在創(chuàng)建系統(tǒng)類型的窗口時(shí)不需要提供一個(gè)有效的Token,WMS會(huì)隱式地為其聲明一個(gè)WindowToken,看起來(lái)誰(shuí)都可以添加個(gè)系統(tǒng)級(jí)的窗口。難道Android為了內(nèi)部使用方便而置安全于不顧嗎?非也,addWindow()函數(shù)一開始的mPolicy.checkAddPermission()的目的就是如此。它要求客戶端必須擁有SYSTEM_ALERT_WINDOW或INTERNAL_SYSTEM_WINDOW權(quán)限才能創(chuàng)建系統(tǒng)類型的窗口。

2.向WMS聲明WindowToken

既然應(yīng)用組件在創(chuàng)建一個(gè)窗口時(shí)必須指定一個(gè)有效的WindowToken才行,那么WindowToken究竟該如何聲明呢?

在SampleWindow應(yīng)用中,使用wms.addWindowToken()函數(shù)聲明mToken作為它的令牌,所以在添加窗口時(shí),通過(guò)設(shè)置lp.token為mToken向WMS進(jìn)行出示,從而獲得WMS添加窗口的許可。這說(shuō)明,只要是一個(gè)Binder對(duì)象(隨便一個(gè)),都可以作為Token向WMS進(jìn)行聲明。對(duì)于WMS的客戶端來(lái)說(shuō),Token僅僅是一個(gè)Binder對(duì)象而已。

為了驗(yàn)證這一點(diǎn),來(lái)看一下addWindowToken的代碼,如下所示:

WindowManagerService.java::WindowManagerService.addWindowToken()

   @Override
    publicvoid addWindowToken(IBinder token, int type) {
        // 需要聲明Token的調(diào)用者擁有MANAGE_APP_TOKENS的權(quán)限
        if(!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
               "addWindowToken()")) {
            thrownew SecurityException("Requires MANAGE_APP_TOKENS permission");
        }
        synchronized(mWindowMap){
            ......
           // 注意其構(gòu)造函數(shù)的參數(shù)與addWindow()中不同,最后一個(gè)參數(shù)為true,表明這個(gè)Token
           // 是顯式申明的
            wtoken= new WindowToken(this, token, type, true);
            mTokenMap.put(token,wtoken);
            ......
        }
    }

使用addWindowToken()函數(shù)聲明Token,將會(huì)在WMS中創(chuàng)建一個(gè)WindowToken實(shí)例,并添加到mTokenMap中,鍵值為客戶端用于聲明Token的Binder實(shí)例。與addWindow()函數(shù)中隱式地創(chuàng)建WindowToken不同,這里的WindowToken被聲明為顯式的。隱式與顯式的區(qū)別在于,當(dāng)隱式創(chuàng)建的WindowToken的最后一個(gè)窗口被移除后,此WindowToken會(huì)被一并從mTokenMap中移除。顯式創(chuàng)建的WindowToken只能通過(guò)removeWindowToken()顯式地移除。

addWindowToken()這個(gè)函數(shù)告訴我們,WindowToken其實(shí)有兩層含義:

  • 對(duì)于顯示組件(客戶端)而言的Token,是任意一個(gè)Binder的實(shí)例,對(duì)顯示組件(客戶端)來(lái)說(shuō)僅僅是一個(gè)創(chuàng)建窗口的令牌,沒(méi)有其他的含義。
  • 對(duì)于WMS而言的WindowToken這是一個(gè)WindowToken類的實(shí)例,保存了對(duì)應(yīng)于客戶端一側(cè)的Token(Binder實(shí)例),并以這個(gè)Token為鍵,存儲(chǔ)于mTokenMap中??蛻舳艘粋?cè)的Token是否已被聲明,取決于其對(duì)應(yīng)的WindowToken是否位于mTokenMap中。

注意 在一般情況下,稱顯示組件(客戶端)一側(cè)Binder的實(shí)例為Token,而稱WMS一側(cè)的WindowToken對(duì)象為WindowToken。但是為了敘述方便,在沒(méi)有歧義的前提下不會(huì)過(guò)分仔細(xì)地區(qū)分這兩個(gè)概念。

接下來(lái),看一下各種顯示組件是如何聲明WindowToken的。

(1) Wallpaper和InputMethod的Token
Wallpaper的Token聲明在WallpaperManagerService中。參考以下代碼:

WallpaperManagerService.java::WallpaperManagerService.bindWallpaperComponentLocked()

BooleanbindWallpaperComponentLocked(......) {
    ......
   WallpaperConnection newConn = new WallpaperConnection(wi, wallpaper);
    ......
    mIWindowManager.addWindowToken(newConn.mToken,
                         WindowManager.LayoutParams.TYPE_WALLPAPER);
    ......
}

WallpaperManagerService是Wallpaper管理器,它負(fù)責(zé)維護(hù)系統(tǒng)已安裝的所有的Wallpaper并在它們之間進(jìn)行切換,而這個(gè)函數(shù)的目的是準(zhǔn)備顯示一個(gè)Wallpaper。newConn.mToken與SampleWindow例子一樣,是一個(gè)簡(jiǎn)單的Binder對(duì)象。這個(gè)Token將在即將顯示出來(lái)的Wallpaper被連接時(shí)傳遞給它,之后Wallpaper即可通過(guò)這個(gè)Token向WMS申請(qǐng)創(chuàng)建繪制壁紙所需的窗口了。

注意 :WallpaperManagerService向WMS聲明的Token類型為TYPE_WALLPAPER,所以,Wallpaper僅能本分地創(chuàng)建TYPE_WALLPAPER類型的窗口。

相應(yīng)的,WallpaperManagerService會(huì)在detachWallpaperLocked()函數(shù)中取消對(duì)Token的聲明:

WallpaperManagerService.java::WallpaperManagerService.detachWallpaperLocked()

booleandetachWallpaperLocked(WallpaperData wallpaper){
    ......
    mIWindowManager.removeWindowToken(wallpaper.connection.mToken);
    ......
}

再此之后,如果這個(gè)被detach的Wallpaper想再要?jiǎng)?chuàng)建窗口便不再可能了。

WallpaperManagerService使用WindowToken對(duì)一個(gè)特定的Wallpaper做出了如下限制:

  • Wallpaper只能創(chuàng)建TYPE_WALLPAPER類型的窗口。
  • Wallpaper顯示的生命周期由WallpaperManagerService牢牢地控制著。僅有當(dāng)前的Wallpaper才能創(chuàng)建窗口并顯示內(nèi)容。其他的Wallpaper由于沒(méi)有有效的Token,而無(wú)法創(chuàng)建窗口。

InputMethod的Token的來(lái)源與Wallpaper類似,其聲明位于InputMethodManagerService的startInputInnerLocked()函數(shù)中,取消聲明的位置在InputmethodManagerService的unbindCurrentMethodLocked()函數(shù)。InputMethodManagerService通過(guò)Token限制著每一個(gè)InputMethod的窗口類型以及顯示生命周期。

(2) Activity的Token
Activity的Token的使用方式與Wallpaper和InputMethod類似,但是其包含更多的內(nèi)容。畢竟,對(duì)于Activity,無(wú)論是其組成還是操作都比Wallpaper以及InputMethod復(fù)雜得多。對(duì)此,WMS專為Activity實(shí)現(xiàn)了一個(gè)WindowToken的子類:AppWindowToken。

既然AppWindowToken是為Activity服務(wù)的,那么其聲明自然在ActivityManagerService中。具體位置為ActivityStack.startActivityLocked(),也就是啟動(dòng)Activity的時(shí)候。相關(guān)代碼如下:

ActivityStack.java::ActivityStack.startActivityLocked()

private final void startActivityLocked(......) {
    ......
    mService.mWindowManager.addAppToken(addPos,r.appToken, r.task.taskId,
                               r.info.screenOrientation, r.fullscreen);
    ......
}

startActivityLocked()向WMS聲明r.appToken作為此Activity的Token,這個(gè)Token是在ActivityRecord的構(gòu)造函數(shù)中創(chuàng)建的。隨然后在realStartActivityLocked()中將此Token交付給即將啟動(dòng)的Activity。

ActivityStack.java::ActivityStack.realStartActivityLocked()

final boolean realStartActivityLocked(......) {
    ......
    app.thread.scheduleLaunchActivity(newIntent(r.intent), **r.appToken,**
                System.identityHashCode(r), r.info,
                newConfiguration(mService.mConfiguration),
                r.compat, r.icicle, results, newIntents,!andResume,
    mService.isNextTransitionForward(),profileFile, profileFd,
                profileAutoStop);
    ......
}

啟動(dòng)后的Activity即可使用此Token創(chuàng)建類型為TYPE_APPLICATION的窗口了。

取消Token的聲明則位于ActivityStack.removeActivityFromHistoryLocked()函數(shù)中。

Activity的Token在客戶端是否和Wallpaper一樣,僅僅是一個(gè)基本的Binder實(shí)例呢?其實(shí)不然。看一下r.appToken的定義可以發(fā)現(xiàn),這個(gè)Token的類型是IApplicationToken.Stub。其中定義了一系列和窗口相關(guān)的一些通知回調(diào),它們是:

  • windowsDrawn(),當(dāng)窗口完成初次繪制后通知AMS。
  • windowsVisible(),當(dāng)窗口可見時(shí)通知AMS。
  • windowsGone(),當(dāng)窗口不可見時(shí)通知AMS。
  • keyDispatchingTimeout(),窗口沒(méi)能按時(shí)完成輸入事件的處理。這個(gè)回調(diào)將會(huì)導(dǎo)致ANR。
  • getKeyDispatchingTimeout(),從AMS處獲取界定ANR的時(shí)間。

AMS通過(guò)ActivityRecord表示一個(gè)Activity。而ActivityRecord的appToken在其構(gòu)造函數(shù)中被創(chuàng)建,所以每個(gè)ActivityRecord擁有其各自的appToken。而WMS接受AMS對(duì)Token的聲明,并為appToken創(chuàng)建了唯一的一個(gè)AppWindowToken。因此,這個(gè)類型為IApplicationToken的Binder對(duì)象appToken粘結(jié)了AMS的ActivityRecord與WMS的AppWindowToken,只要給定一個(gè)ActivityRecord,都可以通過(guò)appToken在WMS中找到一個(gè)對(duì)應(yīng)的AppWindowToken,從而使得AMS擁有了操縱Activity的窗口繪制的能力。例如,當(dāng)AMS認(rèn)為一個(gè)Activity需要被隱藏時(shí),以Activity對(duì)應(yīng)的ActivityRecord所擁有的appToken作為參數(shù)調(diào)用WMS的setAppVisibility()函數(shù)。此函數(shù)通過(guò)appToken找到其對(duì)應(yīng)的AppWindowToken,然后將屬于這個(gè)Token的所有窗口隱藏。

注意: 每當(dāng)AMS因?yàn)槟承┰颍ㄈ鐔?dòng)/結(jié)束一個(gè)Activity,或?qū)ask移到前臺(tái)或后臺(tái))而調(diào)整ActivityRecord在mHistory中的順序時(shí),都會(huì)調(diào)用WMS相關(guān)的接口移動(dòng)AppWindowToken在mAppTokens中的順序,以保證兩者的順序一致。在后面講解窗口排序規(guī)則時(shí)會(huì)介紹到,AppWindowToken的順序?qū)Υ翱诘捻樞蛴绊懛浅4蟆?/p>

到此這篇關(guān)于深入理解窗口令牌WindowToken的文章就介紹到這了,更多相關(guān)窗口令牌WindowToken內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 3分鐘純 Java 注解搭個(gè)管理系統(tǒng)的示例代碼

    3分鐘純 Java 注解搭個(gè)管理系統(tǒng)的示例代碼

    這篇文章主要介紹了3分鐘純 Java 注解搭個(gè)管理系統(tǒng)的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • 詳解Java 中的嵌套類與內(nèi)部類

    詳解Java 中的嵌套類與內(nèi)部類

    這篇文章主要介紹了詳解Java 中的嵌套類與內(nèi)部類的相關(guān)資料,希望通過(guò)本文大家能掌握J(rèn)ava 嵌套類與內(nèi)部類的使用方法,需要的朋友可以參考下
    2017-09-09
  • Java數(shù)組,去掉重復(fù)值、增加、刪除數(shù)組元素的方法

    Java數(shù)組,去掉重復(fù)值、增加、刪除數(shù)組元素的方法

    下面小編就為大家?guī)?lái)一篇Java數(shù)組,去掉重復(fù)值、增加、刪除數(shù)組元素的方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-10-10
  • java使用smortupload上傳和下載文件

    java使用smortupload上傳和下載文件

    這篇文章主要介紹了java使用smortupload上傳和下載文件實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07
  • Java  Object類中的常用API介紹

    Java  Object類中的常用API介紹

    這篇文章主要介紹了Java  Object類中的常用API介紹,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-11-11
  • 基于HashMap遍歷和使用方法(詳解)

    基于HashMap遍歷和使用方法(詳解)

    下面小編就為大家?guī)?lái)一篇基于HashMap遍歷和使用方法(詳解)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-08-08
  • java數(shù)據(jù)庫(kù)連接、查詢、更新等

    java數(shù)據(jù)庫(kù)連接、查詢、更新等

    這篇文章主要介紹了java數(shù)據(jù)庫(kù)連接、查詢、更新等,需要的朋友可以參考下
    2018-05-05
  • 通過(guò)源代碼分析Mybatis的功能流程詳解

    通過(guò)源代碼分析Mybatis的功能流程詳解

    這篇文章主要介紹了通過(guò)源代碼分析Mybatis的功能,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-08-08
  • 使用springboot通過(guò)spi機(jī)制加載mysql驅(qū)動(dòng)的過(guò)程

    使用springboot通過(guò)spi機(jī)制加載mysql驅(qū)動(dòng)的過(guò)程

    這篇文章主要介紹了使用springboot通過(guò)spi機(jī)制加載mysql驅(qū)動(dòng)的過(guò)程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • java中Class.forName的作用淺談

    java中Class.forName的作用淺談

    這篇文章介紹了java中Class.forName的作用,有需要的朋友可以參考一下
    2013-11-11

最新評(píng)論