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 偵錯閃爍測試失敗問題。
檢查測試失敗
請按照下列步驟判斷問題類型,並檢查測試失敗訊息。
檢查測試和類別名稱,判斷問題類型。
測試和類別名稱:
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. 使用 SurfaceFlinger 檢視畫面的 Winscope 到達網頁。
複製並貼上例外訊息中的時間戳記,然後前往發生問題的時間戳記,您可以複製人類可讀格式的時間戳記 (
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
錯誤,因此不會顯示介面。這是因為在組合期間,另一個不透明的表面會放在前面。這個假設源自於NotificationShade
矩形在 3D 檢視畫面中位於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 分,協調世界時 -04:00」。
如要偵錯使用者回報的錯誤,請按照下列步驟操作:
在 Winscope 中載入追蹤記錄檔案。Winscope 開啟時,系統會自動選取 SurfaceFlinger。
圖 6. 使用 SurfaceFlinger 檢視畫面的 Winscope 到達網頁。
在人類可讀的時間戳記欄位中輸入
15:50:00
,即可前往使用者回報的大約時間戳記,在本例中為3:50 PM GMT-04:00
。圖 7. 時間戳記對話方塊。
使用 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. 使用者回報。
找出分割畫面檢視畫面涉及哪些途徑後,請使用轉場追蹤功能逐步執行各種使用者動作,並找出閃爍現象。按一下 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 傾印檢視畫面中選取「Show diff」,即可醒目顯示在這個影格中變更的屬性。在文字搜尋欄位中輸入
transform
,即可篩選屬性:圖 19. 顯示差異比較。
在這個影格中,轉換作業會從
IDENTITY
設為SCALE|TRANSLATE|ROT_270
,以便處理transition-leash
。這項資訊顯示,當轉換套用至撥號分割畫面應用程式的動畫繫繩時,就會發生閃爍現象。
圖 20. 閃爍現象的識別。
在程式碼中找出為何將此轉換設為分割畫面轉場牽繩。