Winscope를 사용하여 창 전환을 추적하세요.

Winscope는 사용자가 애니메이션 및 전환 중과 전환 후에 여러 시스템 서비스의 상태를 기록, 재생, 분석할 수 있는 웹 도구입니다. Winscope는 관련된 모든 시스템 서비스 상태를 트레이스 파일에 기록합니다. 추적 파일과 함께 Winscope UI를 사용하면 전환을 재생, 단계별로 실행, 디버그하여 화면 녹화 여부와 관계없이 각 애니메이션 프레임의 이러한 서비스 상태를 검사할 수 있습니다.

지원되는 트레이스

Winscope는 다양한 트레이스 또는 시스템 서비스 상태의 시퀀스를 수집하고 시각적으로 표현하는 기능을 제공합니다. 이러한 트레이스는 오버헤드가 낮은 트레이스부터 상세 트레이스까지 특정 사용 사례에 맞게 구성할 수 있습니다. Winscope에서 지원하는 트레이스는 다음과 같습니다.

  • EventLog: EventLog를 사용하여 시스템 진단 이벤트 레코드를 수집합니다. Winscope에서는 이 정보가 CUJ 마크를 식별하고 표시하는 데만 사용됩니다.
  • IME: IMS, IMMS, IME 클라이언트를 비롯한 입력 방식 편집기 (IME) 파이프라인의 이벤트를 추적합니다.
  • 입력: 입력 이벤트 파이프라인의 여러 부분에서 입력 이벤트를 추적합니다.
  • ProtoLog: 시스템 서비스 및 클라이언트 프로세스에서 실행되는 시스템 서비스 코드에서 ProtoLog 메시지를 수집합니다.
  • 화면 녹화: 트레이스와 함께 화면 녹화를 수집합니다.
  • 셸 전환: 창 및 활동 전환 시스템 세부정보를 기록합니다.
  • SurfaceFlinger: 위치, 버퍼, 컴포지션과 같은 노출 영역 (레이어)에 관한 정보가 포함된 SurfaceFlinger 트레이스를 수집합니다.
  • 트랜잭션: 구성에 SurfaceControl를 사용하여 SurfaceFlinger가 수신한 전체 변경사항 집합을 추적합니다.
  • ViewCapture: 시스템 UI 및 런처와 같이 ViewCapture를 지원하는 시스템 창에서 모든 뷰의 다양한 속성을 캡처합니다.
  • Window Manager: 입력 및 포커스 이벤트, 화면 방향, 전환, 애니메이션, 위치 지정, 변환 등 창과 관련된 세부정보가 포함된 Window Manager 상태를 추적합니다.

지원되는 덤프

Winscope는 사용자가 정의한 특정 시점에 촬영된 기기 상태의 스냅샷인 상태 덤프를 수집하고 표시할 수 있습니다. 기기 사용 중에 연속으로 수집되고 성능에 영향을 줄 수 있는 트레이스와 달리 덤프는 이러한 사용자 정의 순간에만 찍히므로 성능과 상세도가 손상되지 않습니다. 이를 통해 특정 시점의 기기 상태를 더 집중적이고 효율적으로 분석할 수 있습니다. Winscope에서 지원하는 덤프는 다음과 같습니다.

  • 창 관리자: 단일 창 관리자 상태를 덤프합니다.
  • SurfaceFlinger: 단일 SurfaceFlinger 스냅샷을 덤프합니다.
  • 스크린샷: 덤프와 함께 스크린샷을 수집합니다.

리소스

Winscope 빌드 및 실행에 관한 자세한 내용은 Winscope 실행을 참고하세요.

트레이스 수집에 관한 자세한 내용은 트레이스 캡처를 참고하세요.

Winscope 웹 UI를 사용하여 트레이스를 로드하는 방법은 트레이스 로드를 참고하세요.

trace 분석에 관한 자세한 내용은 trace 분석을 참고하세요.

다음 예에서는 플리커 테스트 실패 및 사용자가 신고한 버그를 디버그하는 방법을 설명합니다.

플리커 테스트 실패

이 예에서는 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 노출 영역의 속성을 다시 검사합니다. 노출 영역이 OPAQUE이 아닌 ENABLE_BACKPRESSURE (0x100) 플래그만 가지고 있습니다. 이렇게 하면 앱 실행이 완전히 완료되기 전에 NotificationShade가 불투명해집니다. NotificationShadeNotificationActivity 앞에 있으므로 앱이 표시되지 않습니다. NotificationShade는 검은색이므로 화면이 잠시 검은색으로 바뀌면서 깜박임이 발생합니다.

  7. 코드에서 NotificationShade가 너무 일찍 불투명해지는 이유를 파악합니다.

사용자가 신고한 버그

사용자 신고 버그는 세부정보가 부족한 경우가 많아 디버그하기 어려울 수 있습니다. 특정 타임스탬프, 요소 세부정보, 화면 녹화 파일을 제공하는 플리커 테스트 실패와 달리 사용자 신고 버그에는 일반적으로 문제에 관한 간단한 설명만 포함됩니다.

이 사례에서는 화면 분할에서 앱을 다시 열 때 화면이 깜박임이라는 제목과 2024년 4월 18일 오후 3시 51분(PDT)이라는 대략적인 타임스탬프만 제공되었습니다.

사용자 신고 버그를 디버그하려면 다음 단계를 따르세요.

  1. Winscope에 트레이스 파일을 로드합니다. Winscope가 SurfaceFlinger가 자동으로 선택된 상태로 열립니다.

    SurfaceFlinger 뷰가 있는 Winscope 방문 페이지

    그림 6. SurfaceFlinger 뷰가 있는 Winscope 방문 페이지

  2. 사람이 읽을 수 있는 타임스탬프 필드에 15:50:00를 입력하여 사용자가 보고한 대략적인 타임스탬프(이 경우 3:50 PM GMT-04:00)로 이동합니다.

    타임스탬프 대화상자

    그림 7. 타임스탬프 대화상자

  3. 직사각형 뷰를 사용하여 화면에 그려진 항목을 식별합니다. 더 나은 뷰를 보려면 회전 슬라이더를 사용하여 직사각형의 관점을 변경합니다. 계층 구조 보기에서 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

    표시 노출 영역(녹색 직사각형) 외에도 디스플레이 영역 노출 영역을 나타내는 회색 직사각형(알 수 없는 디스플레이)이 표시됩니다. 가시성을 개선하려면 ScreenDecorHwcOverlay#64 노출 영역 옆에 있는 (공개 상태 아이콘) 아이콘을 클릭하여 해당 직사각형을 숨기고 뒤에 있는 노출 영역을 표시합니다. 오버레이는 사용자에게 표시되지 않으며 깜박이는 애니메이션으로 보고되지 않으므로 분석을 위해 삭제됩니다.

    사용자 신고

    그림 8. 사용자 신고

  4. 화면 분할 보기에 관여하는 노출 영역을 파악한 후 전환 트레이스를 사용하여 다양한 사용자 작업을 단계별로 살펴보고 플리커를 찾습니다. Winscope에서 전환 탭을 클릭하여 재생된 전환 목록을 시각화합니다.

    전환

    그림 9. 전환입니다.

    이 프레임 중에 재생된 전환이 파란색으로 강조표시됩니다. 이 경우 전환 플래그에는 사용자가 최근 화면에 진입하고 있음을 나타내는 TRANSIT_FLAG_IS_RECENTS가 포함됩니다.

  5. Dispatch Time 열 (이 경우 2024-04-18, 15:50:57.205)의 링크를 클릭하여 해당 시점으로 이동하고 Surface Flinger 탭에서 직사각형을 확인합니다. 오른쪽 화살표 키를 사용하여 전환을 단계별로 진행하고 직사각형을 관찰하여 전환 중에 기기 상태의 정확성을 확인합니다.

    15:50:57.278에 런처가 표시되지만 애니메이션이 시작되지 않습니다. 화면 분할 앱 (분할선) 사이에 아무것도 그려지지 않으므로 배경화면이 이미 표시됩니다. 1프레임 전 (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. 계층 구조 보기에서 평면을 선택 해제하여 전체 계층 구조 트리를 표시하고 앱 노출 영역의 상위 노드로 이동하여 계산됨요청됨 변환이 모두 동일해질 때까지 이동합니다. 그러면 Surface(name=Task=7934)/@0x1941191_transition-leash#40670 노출 영역에서 요청된 변환이 표시됩니다.

  13. 변환이 처음 설정된 시점과 값을 확인합니다. 제목 옆에 있는 아이콘을 클릭하여 선별된 숙박 시설을 접습니다.

    선별된 속성 접기

    그림 18. 선별된 숙박 시설을 접습니다.

  14. Proto Dump 뷰에서 Show diff를 선택하여 이 프레임에서 변경되는 속성을 강조 표시합니다. 텍스트 검색창에 transform를 입력하여 속성을 필터링합니다.

    show diff

    그림 19. 차이점 표시

    이 프레임에서 transition-leash의 변환이 IDENTITY에서 SCALE|TRANSLATE|ROT_270로 설정됩니다.

    이 정보는 변환이 다이얼러 스크린 분할 앱의 애니메이션 리시에 적용될 때 플리커링이 발생했음을 보여줍니다.

    플리커 식별

    그림 20. 플리커 식별

  15. 코드에서 이 변환이 스크린 분할 전환 리쉬로 설정된 이유를 확인합니다.