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를 지원하는 시스템 창에서 모든 뷰의 속성 범위를 캡처합니다.
  • 창 관리자: 입력 및 포커스 이벤트, 화면 방향, 전환, 애니메이션, 위치 지정, 변환 등 창과 관련된 세부정보가 포함된 창 관리자 상태를 추적합니다.

지원되는 덤프

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에 로드합니다. SurfaceFlinger가 자동으로 선택된 상태로 Winscope가 열립니다.

    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. 오른쪽 화살표 키를 눌러 깜박임이 발생하는 다음 프레임으로 다시 이동합니다. rects 뷰에서는 앱 대신 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 오류로 인해 화면이 표시되지 않습니다. 이는 컴포지션 중에 불투명한 다른 서페이스가 앞에 배치되었기 때문에 발생합니다. 이 가설은 3D 뷰에서 NotificationShade rect가 NotificationActivity rect 앞에 있고 표시되는 (녹색) 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분 GMT-04:00뿐입니다.

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

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

    SurfaceFlinger 뷰가 있는 Winscope 방문 페이지

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

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

    타임스탬프 대화상자

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

  3. rects 뷰를 사용하여 화면에 그려진 항목을 식별합니다. 더 나은 보기를 위해 회전 슬라이더를 사용하여 직사각형 관점을 변경합니다. 계층 구조 보기에서 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. 발송 시간 열 (이 경우 2024-04-18, 15:50:57.205)의 링크를 클릭하여 해당 시점으로 이동하고 Surface Flinger 탭에서 사각형을 확인합니다. 오른쪽 화살표 키로 전환을 단계별로 실행하고 rect를 관찰하여 전환 중에 기기 상태가 올바른지 확인합니다.

    런처는 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. 계층 구조 보기에서 플랫을 선택 해제하여 전체 계층 구조 트리를 표시하고 계산됨요청됨 변환이 동일해질 때까지 앱 노출 영역의 상위 노드로 이동하여 Surface(name=Task=7934)/@0x1941191_transition-leash#40670 노출 영역에서 요청된 변환을 표시합니다.

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

    선별된 속성을 접습니다.

    그림 18. 선별된 속성을 접습니다.

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

    차이점 표시

    그림 19. 차이점을 표시합니다.

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

    이 정보는 다이얼러 분할 화면 앱의 애니메이션 리드줄에 변환이 적용되었을 때 깜박임이 발생했음을 보여줍니다.

    깜박임 식별

    그림 20. 깜박임 식별자입니다.

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