Winscope 是一項網頁工具,可供使用者在動畫和轉場效果期間及之後,記錄、重播及分析多項系統服務的狀態。Winscope 會將所有相關的系統服務狀態記錄到追蹤記錄檔。使用 Winscope UI 和追蹤記錄檔,您可以重播、逐步執行及偵錯轉場效果,檢查每個動畫影格的服務狀態,無論是否錄製螢幕畫面都適用。
支援的追蹤
Winscope 可收集並以視覺化方式呈現各種「追蹤記錄」或系統服務狀態序列。您可以設定這些追蹤記錄,以配合特定用途,範圍從低負荷到高詳細程度。Winscope 支援下列追蹤記錄:
- EventLog:使用
EventLog
收集系統診斷事件記錄。 在 Winscope 中,這項資訊只會用於識別及顯示 CUJ 標記。 - 輸入法編輯器:追蹤輸入法編輯器 (IME) 管道的事件,包括 IMS、IMMS 和 IME 用戶端。
- 輸入:追蹤輸入事件管道各部分的輸入事件。
- ProtoLog:收集來自系統服務的 ProtoLog 訊息,以及在用戶端程序中執行的系統服務程式碼。
- 螢幕錄影:收集螢幕錄影畫面和追蹤記錄。
- 殼層轉場效果:記錄視窗和活動轉場效果的系統詳細資料。
- SurfaceFlinger:收集包含 Surface (圖層) 相關資訊 (例如位置、緩衝區和組合) 的 SurfaceFlinger 追蹤記錄。
- 交易:使用
SurfaceControl
追蹤 SurfaceFlinger 收到的原子變更集,以進行組合。 - ViewCapture:擷取系統 Windows 中所有支援 ViewCapture 的檢視區塊屬性範圍,例如系統 UI 和啟動器。
- 視窗管理員:追蹤視窗管理員狀態,其中包含與視窗相關的詳細資料,包括輸入和焦點事件、螢幕方向、轉場效果、動畫、定位和轉換。
支援的傾印
Winscope 可以收集及顯示狀態傾印,也就是使用者在特定時間點擷取的裝置狀態快照。與在裝置使用期間持續收集且可能影響效能的追蹤記錄不同,傾印只會在使用者定義的時刻擷取,確保效能和詳細程度不會受到影響。這樣就能在特定時間點更有效率地分析裝置狀態。Winscope 支援下列傾印:
- 視窗管理員:傾印單一視窗管理員狀態。
- SurfaceFlinger:傾印單一 SurfaceFlinger 快照。
- 螢幕截圖:連同傾印檔案一併收集螢幕截圖。
資源
如要瞭解如何建構及執行 Winscope,請參閱「執行 Winscope」。
如要瞭解如何收集追蹤記錄,請參閱「擷取追蹤記錄」。
如要瞭解如何使用 Winscope 網頁版 UI 載入追蹤記錄,請參閱「載入追蹤記錄」。
如要瞭解如何分析追蹤記錄,請參閱「分析追蹤記錄」。
範例
以下範例說明如何偵錯閃爍測試失敗和使用者回報的錯誤。
閃爍測試失敗
這個範例說明如何使用 Winscope 偵錯閃爍測試失敗問題。
檢查測試失敗
請按照下列步驟判斷問題類型,並檢查測試失敗訊息。
檢查測試和類別名稱,判斷問題類型。
測驗和課程名稱:
FlickerTestsNotification com.android.server.wm.flicker.notification.OpenAppFromLockscreenNotificationColdTest#appLayerBecomesVisible[ROTATION_0_GESTURAL_NAV]
問題類型:
CUJ 是指從螢幕鎖定畫面通知啟動應用程式 (
OpenAppFromLockscreenNotificationColdTest
)。這項測試預期應用程式會顯示 (
#appLayerBecomesVisible
)。
檢查測試失敗訊息,其中提供失敗的完整資訊,包括:
- 預期結果與實際顯示結果的比較
- 時間戳記,有助於找出失敗發生時間
- 與失敗相關的構件或檔案名稱
- 有助於瞭解及偵錯失敗情形的其他背景資訊
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
」。
偵錯
請按照下列步驟判斷閃爍原因:
下載追蹤記錄檔,並載入 Winscope。Winscope 會開啟,並自動選取 SurfaceFlinger:
圖 1. Winscope 到達網頁,顯示 SurfaceFlinger 檢視畫面。
將例外狀況訊息中的時間戳記複製並貼到時間戳記欄位,即可前往發生問題的時間戳記。您可以複製使用者可解讀格式的時間戳記 (
2024-05-10T11:04:14.227572545
) 並貼到第一個欄位,也可以複製奈秒格式的時間戳記 (1715339054227572545ns
) 並貼到第二個欄位。圖 2. 時間戳記對話方塊。
按向左鍵即可前往上一個影格。在此狀態下,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. 應用程式啟動時。
按向右鍵返回下一個影格,該影格會發生閃爍情形。在矩形檢視畫面中,畫面上會顯示
NotificationShade
,而非應用程式。這個影格會顯示下列介面:- 螢幕裝飾疊加層 (頂端和底部)
- 導覽列
指標位置 (來自螢幕錄影)
圖 4. 閃爍活動。
在階層檢視中選取應用程式活動。如果找不到,請取消勾選「僅顯示 V」,然後檢查屬性檢視畫面。
應用程式介面名稱為:
com.android.server.wm.flicker.testapp/com.android.server.wm.flicker.testapp.NotificationActivity#3458`
圖 5. 應用程式屬性。
雖然應用程式活動設為可見且不透明,但由於發生
Invisible due to: null visible region
錯誤,因此系統不會顯示介面。這是因為在組合期間,另一個不透明的表面放置在該表面前方。這項假設的依據是 3D 檢視畫面中的NotificationShade
矩形位於NotificationActivity
矩形前方,且可見 (綠色) 的NotificationShade
可能是所選圖層。如要驗證這項假設,請選取目前影格中可見的
NotificationShade
表面,然後檢查其屬性。旗標已設為OPAQUE|ENABLE_BACKPRESSURE (0x102)
。NotificationShade
介面名稱為NotificationShade#3447
。接著,按下向左箭頭,返回上一個影格 (閃爍前),然後再次檢查NotificationShade
表面屬性。請注意,介面只有ENABLE_BACKPRESSURE (0x100)
旗標,而非OPAQUE
。這會確認NotificationShade
在應用程式啟動完全完成前會變成不透明。由於NotificationShade
位於NotificationActivity
前方,因此應用程式不會顯示。NotificationShade
為黑色,因此螢幕會短暫變黑,導致閃爍。找出程式碼中
NotificationShade
過早變成不透明的原因。
使用者回報的錯誤
使用者回報的錯誤通常缺乏詳細資訊,因此很難進行偵錯。與閃爍測試失敗不同,使用者回報的錯誤通常只包含問題的簡短說明,而閃爍測試失敗則會提供具體的時間戳記、元素詳細資料和螢幕錄影。
在本案例研究中,我們只提供「從分割畫面重新開啟應用程式時,螢幕會閃爍」這個標題,以及「2024 年 4 月 18 日下午 3:51 (GMT-04:00)」這個大約的時間戳記。
如要偵錯使用者回報的錯誤,請按照下列步驟操作:
在 Winscope 中載入追蹤記錄檔案。Winscope 會開啟,並自動選取 SurfaceFlinger。
圖 6. Winscope 到達網頁,顯示 SurfaceFlinger 檢視畫面。
在可讀的時間戳記欄位中輸入
15:50:00
,即可前往使用者回報的大約時間戳記,在本例中為3:50 PM GMT-04:00
。圖 7. 時間戳記對話方塊。
使用矩形檢視畫面,找出螢幕上繪製的內容。如要調整矩形視角,請使用「旋轉」滑桿,在「階層」檢視畫面中標示「僅顯示 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. 使用者回報。
找出參與分割畫面檢視的介面後,請使用 Transitions 追蹤記錄逐步執行各種使用者動作,找出閃爍問題。在 Winscope 中按一下「Transitions」分頁,即可查看播放的轉場效果清單:
圖 9.轉場效果。
這個影格播放的轉場效果會以藍色醒目顯示。在本例中,轉換旗標包含
TRANSIT_FLAG_IS_RECENTS
,表示使用者要進入「最近使用」畫面。點選「Dispatch Time」(調度時間) 欄中的連結 (在本例中為
2024-04-18, 15:50:57.205
),即可前往該時間點,並在「Surface Flinger」分頁中驗證矩形。使用向右箭頭鍵逐步完成轉場效果,並觀察矩形,確認轉場期間裝置狀態是否正確。啟動器會在 15:50:57.278 出現,但動畫不會在此時啟動。 由於分割畫面應用程式之間沒有繪製任何內容 (分隔線),因此桌布已顯示。前一影格 (15:50:57.212) 看不到桌布,但會顯示分隔線,這就是未動畫化時的分割畫面。
圖 10. 閃爍事件發生前的畫面。
如要查看下一個轉場效果,請直接點選時間軸。 SurfaceFlinger 狀態會以一列淺藍色方塊表示。 轉場效果會以一列粉紅色方塊表示。
圖 11. 第一次轉換結束。
在下一個轉場效果的開始位置,按一下 SurfaceFlinger 列。在圖 11 中,游標的垂直位置以細藍線表示。淺藍色背景的 SurfaceFlinger 列會顯示水平位置。使用向右箭頭鍵逐步瀏覽轉場效果,看看是否發生閃爍。確認裝置是否適合這項轉換。
略過下一個轉場效果,因為其時間長度很短,不太可能包含閃爍。請改為點選 SurfaceFlinger 列中的時間軸,位置是下一個較長轉場效果的開始位置,如下圖游標所示。
圖 12. 第二次轉換結束。
在此期間,請觀察兩個應用程式、聯絡人和撥號程式的圖層是否位於螢幕的同一側:
15:51:13.239
Splash Screen
圖 13. 啟動畫面。
請說明哪一個應用程式顯示在錯誤的一側。按一下 ns 輸入欄位旁的旗幟圖示,即可在目前位置新增書籤,方便日後返回這個影格。
圖 14. 新增書籤。
直接點選時間軸,例如
15:51:13.859
,即可前往轉場效果結尾的影格。現在這兩個應用程式已就位,左側是撥號程式,右側是聯絡人:圖 15. 最終分割畫面。
按一下時間軸中的書籤旗標,返回閃爍的影格。
圖 16. 為時間軸加上書籤。
兩個應用程式都位於右側,表示撥號程式的位置不正確。
按一下撥號器的啟動畫面,即可查看其屬性。請特別查看精選「屬性」檢視畫面中的轉換屬性。
圖 17. 轉換屬性。
計算出的轉換會套用至這個介面,但不會設為這個層級。「計算」和「要求」欄的值不同,表示轉換是從上層介面沿用。
在階層檢視中取消選取「Flat」,顯示整個階層樹狀結構,然後前往應用程式介面的父節點,直到「Calculated」和「Requested」轉換相同為止,顯示在
Surface(name=Task=7934)/@0x1941191_transition-leash#40670
介面上要求的轉換。確認轉換的首次設定時間和值。按一下標題旁的圖示,即可收合精選屬性:
圖 18. 收合精選屬性。
在「Proto Dump」檢視畫面中選取「Show diff」,即可醒目顯示這個影格中變更的屬性。在文字搜尋欄位中輸入
transform
,即可篩選屬性:圖 19. 顯示差異。
在此影格中,轉換會從
IDENTITY
設為SCALE|TRANSLATE|ROT_270
。transition-leash
這項資訊顯示,當轉換套用至撥號程式分割畫面應用程式的動畫牽繩時,發生了閃爍情形。
圖 20. 閃爍的識別資訊。
在程式碼中找出這個轉換設定為分割畫面轉場動畫的原因。