使用 Winscope 追蹤視窗轉換

Winscope 是一項網頁工具,可讓使用者在動畫和轉場期間和之後,記錄、重播及分析多個系統服務的狀態。Winscope 會將所有相關的系統服務狀態記錄到追蹤檔案中。您可以使用 Winscope UI 搭配追蹤檔案,藉由重播、逐步執行及偵錯轉場效果,檢查每個動畫影格中這些服務的狀態 (不論是否有螢幕錄影)。

支援的追蹤記錄

Winscope 可收集及以視覺化方式呈現各種追蹤記錄或系統服務狀態序列。您可以根據特定用途設定這些追蹤記錄,從低負擔到高詳細度皆可。Winscope 支援下列追蹤記錄:

  • EventLog:使用 EventLog 收集系統診斷事件記錄。在 Winscope 中,這項資訊只會用於識別及顯示 CUJ 標記。
  • IME:追蹤輸入法編輯器 (IME) 管道中的事件,包括 IMS、IMMS 和 IME 用戶端。
  • 輸入:追蹤輸入事件管道中的各個部分輸入事件。
  • ProtoLog:從系統服務收集 ProtoLog 訊息,以及在用戶端程序中執行的系統服務程式碼。
  • 螢幕錄影:與追蹤記錄一併收集螢幕錄影。
  • 殼層轉換:記錄視窗和活動轉換系統詳細資料。
  • SurfaceFlinger:收集 SurfaceFlinger 追蹤記錄,其中包含關於表面 (圖層) 的資訊,例如位置、緩衝區和組合。
  • 交易:使用 SurfaceControl 追蹤 SurfaceFlinger 在組合時收到的完整變更集。
  • ViewCapture:擷取支援 ViewCapture 的系統視窗 (例如系統 UI 和啟動器) 中所有檢視畫面的一系列屬性。
  • Window Manager:追蹤 Window Manager 狀態,其中包含與視窗相關的詳細資料,包括輸入和焦點事件、螢幕方向、轉場、動畫、定位和轉換。

支援的傾印

Winscope 可收集及顯示狀態傾印,也就是在使用者指定的特定時刻拍攝的裝置狀態快照。與持續在裝置使用期間收集並可能影響效能的追蹤記錄不同,偵錯工具只會在使用者定義的時刻擷取傾印,確保效能和冗長度不會受到影響。這麼做可在特定時間點,更有效率地分析裝置狀態。Winscope 支援下列傾印:

  • Window Manager:轉儲單一 Window Manager 狀態。
  • SurfaceFlinger:轉儲單一 SurfaceFlinger 快照。
  • 螢幕截圖:收集螢幕截圖和快照。

資源

如要瞭解如何建構及執行 Winscope,請參閱「執行 Winscope」一文。

如要瞭解如何收集追蹤記錄,請參閱「擷取追蹤記錄」。

如要瞭解如何使用 Winscope 網頁版 UI 載入追蹤記錄,請參閱「載入追蹤記錄」一文。

如要進一步瞭解如何分析追蹤記錄,請參閱「分析追蹤記錄」。

範例

以下範例說明如何偵錯閃爍測試失敗和使用者回報的錯誤。

閃爍測試失敗

本例說明如何使用 Winscope 偵錯閃爍測試失敗問題。

檢查測試失敗

請按照下列步驟判斷問題類型,並檢查測試失敗訊息。

  1. 檢查測試和類別名稱,判斷問題類型。

    測試和類別名稱:

    FlickerTestsNotification com.android.server.wm.flicker.notification.OpenAppFromLockscreenNotificationColdTest#appLayerBecomesVisible[ROTATION_0_GESTURAL_NAV]
    

    問題類型:

    • CUJ 是指從螢幕鎖定畫面通知 (OpenAppFromLockscreenNotificationColdTest) 啟動應用程式。

    • 測試預期應用程式會顯示 (#appLayerBecomesVisible)。

  2. 請檢查測試失敗訊息,其中提供失敗的完整資訊,包括:

    • 比較預期結果與實際可見結果
    • 時間戳記,協助找出失敗發生的時間
    • 與失敗相關的構件或檔案名稱
    • 與瞭解及偵錯失敗相關的其他背景資訊
    android.tools.flicker.subject.exceptions.IncorrectVisibilityException: com.android.server.wm.flicker.testapp/com.android.server.wm.flicker.testapp.NotificationActivity# should be visible
    
    Where?
        Timestamp(UNIX=2024-05-10T11:04:14.227572545(1715339054227572545ns), UPTIME=37m21s184ms79178ns(2241184079178ns), ELAPSED=0ns)
    
    What?
        Expected: com.android.server.wm.flicker.testapp/com.android.server.wm.flicker.testapp.NotificationActivity#
        Actual: [e636ecd com.android.server.wm.flicker.testapp/com.android.server.wm.flicker.testapp.NotificationActivity#3457: Buffer is empty, Visible region calculated by Composition Engine is empty, com.android.server.wm.flicker.testapp/com.android.server.wm.flicker.testapp.NotificationActivity#3458: Visible region calculated by Composition Engine is empty]
    
    Other information
        Artifact: FAIL__OpenAppFromLockscreenNotificationColdTest_ROTATION_0_GESTURAL_NAV.zip
    
    Check the test run artifacts for trace files
    
        at android.tools.flicker.subject.layers.LayerTraceEntrySubject.isVisible(LayerTraceEntrySubject.kt:187)
        at android.tools.flicker.subject.layers.LayersTraceSubject$isVisible$1$1.invoke(LayersTraceSubject.kt:151)
        at android.tools.flicker.subject.layers.LayersTraceSubject$isVisible$1$1.invoke(LayersTraceSubject.kt:150)
        at android.tools.flicker.assertions.NamedAssertion.invoke(NamedAssertion.kt:32)
        at android.tools.flicker.assertions.CompoundAssertion.invoke(CompoundAssertion.kt:42)
        at android.tools.flicker.assertions.AssertionsChecker.test(AssertionsChecker.kt:79)
        at android.tools.flicker.subject.FlickerTraceSubject.forAllEntries(FlickerTraceSubject.kt:59)
        at android.tools.flicker.assertions.AssertionDataFactory$createTraceAssertion$closedAssertion$1.invoke(AssertionDataFactory.kt:46)
        at android.tools.flicker.assertions.AssertionDataFactory$createTraceAssertion$closedAssertion$1.invoke(AssertionDataFactory.kt:43)
        at android.tools.flicker.assertions.AssertionDataImpl.checkAssertion(AssertionDataImpl.kt:33)
        at android.tools.flicker.assertions.ReaderAssertionRunner.doRunAssertion(ReaderAssertionRunner.kt:35)
        at android.tools.flicker.assertions.ReaderAssertionRunner.runAssertion(ReaderAssertionRunner.kt:29)
        at android.tools.flicker.assertions.BaseAssertionRunner.runAssertion(BaseAssertionRunner.kt:36)
        at android.tools.flicker.legacy.LegacyFlickerTest.doProcess(LegacyFlickerTest.kt:59)
        at android.tools.flicker.assertions.BaseFlickerTest.assertLayers(BaseFlickerTest.kt:89)
        at com.android.server.wm.flicker.notification.OpenAppTransition.appLayerBecomesVisible_coldStart(OpenAppTransition.kt:51)
        at com.android.server.wm.flicker.notification.OpenAppFromNotificationColdTest.appLayerBecomesVisible(OpenAppFromNotificationColdTest.kt:64)
    

    這個輸出範例表示:

    • 問題發生在 2024-05-10T11:04:14.227572545

    • NotificationActivity 應會顯示,但實際上並未顯示。

    • 包含偵錯追蹤記錄的構件檔案名稱為 FAIL__OpenAppFromLockscreenNotificationColdTest_ROTATION_0_GESTURAL_NAV

偵錯

請按照下列步驟判斷閃爍問題的原因:

  1. 下載追蹤記錄檔,並在 Winscope 中載入。Winscope 開啟時,SurfaceFlinger 會自動選取:

    使用 SurfaceFlinger 檢視畫面的 Winscope 到達網頁

    圖 1. 使用 SurfaceFlinger 檢視畫面的 Winscope 到達網頁。

  2. 複製並貼上例外訊息中的時間戳記,然後前往發生問題的時間戳記,您可以複製人類可讀格式的時間戳記 (2024-05-10T11:04:14.227572545),然後貼到第一個欄位;也可以複製奈秒格式的時間戳記 (1715339054227572545ns),然後貼到第二個欄位。

    時間戳記對話方塊

    圖 2. 時間戳記對話方塊。

  3. 按下向左鍵,即可前往上一個影格。在這個狀態下,NotificationActivity 應用程式會正確顯示在影片中,且應用程式和啟動畫面平台都會顯示,這可從 3D 檢視畫面中的綠色矩形和階層元素上的 V 方塊看出。

    應用程式和啟動畫面途徑名稱如下:

    com.android.server.wm.flicker.testapp/com.android.server.wm.flicker.testapp.NotificationActivity#3458`
    
    Splash Screen com.android.server.wm.flicker.testapp#3453
    

    這表示應用程式是在螢幕變黑時啟動,且此事件發生在應用程式啟動期間,因為啟動畫面仍可見:

    應用程式啟動時

    圖 3. 在應用程式啟動時。

  4. 按下向右箭頭鍵,返回發生閃爍的下一個影格。在矩形檢視畫面中,NotificationShade 會顯示在螢幕上,而非應用程式。這個畫面會顯示下列途徑:

    • 螢幕裝飾疊加層 (頂端和底部)
    • 導覽列
    • 指標位置 (取自螢幕錄影)

      閃爍活動

      圖 4. 閃爍活動。

  5. 在階層檢視畫面中選取應用程式活動。如果找不到,請取消勾選「僅顯示 V」,然後檢查屬性檢視畫面。

    應用程式途徑名稱如下:

    com.android.server.wm.flicker.testapp/com.android.server.wm.flicker.testapp.NotificationActivity#3458`
    

    應用程式資源

    圖 5. 應用程式資源。

    雖然應用程式活動已設為可見且不透明,但由於 Invisible due to: null visible region 錯誤,因此不會顯示介面。這是因為在組合期間,另一個不透明的表面會放在前面。這個假設源自於 NotificationShade 矩形在 3D 檢視畫面中位於 NotificationActivity 矩形前方,且可見 (綠色) NotificationShade 可能為所選圖層。

  6. 如要驗證這個假設,請選取目前影格上可見的 NotificationShade 途徑,並檢查其屬性。旗標設為 OPAQUE|ENABLE_BACKPRESSURE (0x102)NotificationShade 途徑名稱為 NotificationShade#3447。接著,按下左箭頭返回前一個畫面 (閃爍之前),然後再次檢查 NotificationShade 途徑的屬性。請注意,表面只有 ENABLE_BACKPRESSURE (0x100) 旗標,而非 OPAQUE。這可確認 NotificationShade 在應用程式啟動程序完全完成前,會變成不透明。由於 NotificationShade 位於 NotificationActivity 前方,因此不會顯示應用程式。NotificationShade 是黑色,因此螢幕會短暫變黑,導致畫面閃爍。

  7. 在程式碼中找出 NotificationShade 為何過早變成不透明。

使用者回報的錯誤

使用者回報的錯誤通常缺乏詳細資訊,因此很難進行偵錯。與閃爍測試失敗不同,後者會提供特定時間戳記、元素詳細資料和螢幕錄影,而使用者回報的錯誤通常只會簡單說明問題。

在本案例研究中,您只需提供標題「從分割畫面重新開啟應用程式時,螢幕閃爍」和大約的時間戳記「2024 年 4 月 18 日下午 3 點 51 分,協調世界時 -04:00」

如要偵錯使用者回報的錯誤,請按照下列步驟操作:

  1. 在 Winscope 中載入追蹤記錄檔案。Winscope 開啟時,系統會自動選取 SurfaceFlinger。

    使用 SurfaceFlinger 檢視畫面的 Winscope 到達網頁

    圖 6. 使用 SurfaceFlinger 檢視畫面的 Winscope 到達網頁。

  2. 在人類可讀的時間戳記欄位中輸入 15:50:00,即可前往使用者回報的大約時間戳記,在本例中為 3:50 PM GMT-04:00

    時間戳記對話方塊

    圖 7. 時間戳記對話方塊。

  3. 使用 rects 檢視畫面上繪製的內容。為獲得更好的視野,請使用「Rotation」滑桿變更矩形的視角。在「階層」檢視畫面中勾選「僅顯示 V」和「扁平」,即可顯示桌布、螢幕裝飾疊加層、信箱、啟動器、聯絡人和撥號介面。

    套件名稱如下:

    • 啟動器:com.google.android.apps.nexuslauncher/com.google.android.apps.nexuslauncher.NexusLauncherActivity#40602

    • 聯絡人:com.google.android.contacts/com.android.contacts.activities.PeopleActivity#40565

    • 撥號:com.google.android.dialer/com.google.android.dialer.extensions.GoogleDialtactsActivity#40564

    除了可見的途徑 (綠色矩形) 之外,系統也會顯示名為「Unknown display」的灰色矩形,代表顯示區域途徑。如要改善可見度,請按一下 ScreenDecorHwcOverlay#64 途徑旁的 (顯示設定圖示),隱藏對應的矩形,並顯示後方的途徑。我們移除了分析用的疊加層,因為使用者看不到該層,也不會將其回報為閃爍動畫。

    使用者回報

    圖 8. 使用者回報。

  4. 找出分割畫面檢視畫面涉及哪些途徑後,請使用轉場追蹤功能逐步執行各種使用者動作,並找出閃爍現象。按一下 Winscope 中的「Transitions」分頁標籤,即可以圖表形式查看播放過的轉場效果清單:

    轉場效果

    圖 9.轉場。

    這個影格中播放的轉場效果會以藍色標示。在這種情況下,轉場旗標會包含 TRANSIT_FLAG_IS_RECENTS,表示使用者正在進入「最近使用」畫面。

  5. 按一下「Dispatch Time」欄中的連結 (在本例中為 2024-04-18, 15:50:57.205),即可前往該時間點,並在「Surface Flinger」分頁中驗證矩形。在轉場期間,請使用右箭頭鍵逐步執行轉場,並觀察矩形,確認裝置狀態正確無誤。

    啟動器會在 15:50:57.278 顯示,但動畫不會在該時間開始。由於分割畫面應用程式 (分隔線) 之間沒有任何繪製內容,因此可看到桌布。在較早的一個影格 (15:50:57.212) 中,您不會看到桌布,只會看到分隔線,這就是分割畫面在未顯示動畫時的樣子。

    閃爍前螢幕畫面

    圖 10. 閃爍事件前的畫面。

  6. 如要查看下一個轉場效果,請直接點選時間軸。SurfaceFlinger 狀態會以一排淺藍色方塊表示。轉場效果會以一列粉紅色方塊表示。

    第一個轉換結束

    圖 11. 第一個轉場結束。

    按一下下一個轉場效果的起始位置的 SurfaceFlinger 列。在圖 11 中,游標的垂直位置由細藍線表示。SurfaceFlinger 列的淺藍色背景會顯示水平位置。使用向右箭頭鍵逐步執行轉場效果,看看是否會出現閃爍現象。確認裝置在這個轉場效果中顯示正確。

  7. 請略過下一個轉場,因為其時間長度很短,因此不太可能出現閃爍。請改為在下一個較長轉場效果的開始位置,點選 SurfaceFlinger 列中的時間軸,如以下圖片中的游標所示。

    第二次轉換結束

    圖 12. 第二個轉場結束。

    在這個轉換期間,請注意在 15:51:13.239 時,兩個應用程式 (聯絡人和撥號程式) 的 Splash Screen 圖層位於螢幕的同一側:

    啟動畫面

    圖 13. 啟動畫面。

  8. 請說明哪個應用程式出現錯誤。按一下 ns 輸入欄位旁的旗幟圖示,即可在目前位置加入書籤,方便日後返回這個影格。

    新增書籤

    圖 14. 新增書籤。

  9. 直接按一下時間軸 (例如 15:51:13.859),即可前往轉場結束處的畫面。這兩個應用程式現在已在最終位置,左側是撥號程式,右側是聯絡人:

    最終分割畫面

    圖 15. 最終分割畫面。

  10. 按一下時間軸中書籤的標記,返回閃爍的畫面。

    書籤時間軸

    圖 16. 書籤時間軸。

    兩個應用程式都位於右側,表示撥號程式位於錯誤位置。

  11. 按一下撥號介面的啟動畫面,查看相關屬性。請在精選的「屬性」檢視畫面中,特別查看其轉換屬性。

    轉換屬性

    圖 17. 轉換屬性。

    計算的轉換會套用至此途徑,但不會設為此層級。計算和要求的資料欄有不同的值,表示轉換作業是從父項介面繼承而來。

  12. 取消選取階層檢視畫面中的「Flat」,即可顯示整個階層樹狀圖,並前往應用程式介面的父項節點,直到「Calculated」和「Requested」轉換都相同為止,即可在 Surface(name=Task=7934)/@0x1941191_transition-leash#40670 介面上顯示所要求的轉換。

  13. 確認轉換功能首次設定的時間,以及設定的值。按一下標題旁的圖示,即可收合精選房源:

    收合精選屬性

    圖 18. 收合精選的房源。

  14. Proto 傾印檢視畫面中選取「Show diff」,即可醒目顯示在這個影格中變更的屬性。在文字搜尋欄位中輸入 transform,即可篩選屬性:

    顯示差異

    圖 19. 顯示差異比較。

    在這個影格中,轉換作業會從 IDENTITY 設為 SCALE|TRANSLATE|ROT_270,以便處理 transition-leash

    這項資訊顯示,當轉換套用至撥號分割畫面應用程式的動畫繫繩時,就會發生閃爍現象。

    閃爍現象的識別

    圖 20. 閃爍現象的識別。

  15. 在程式碼中找出為何將此轉換設為分割畫面轉場牽繩。