MessageQueue 동작 변경 안내

Android 17부터 Android 17 (API 수준 37) 이상을 타겟팅하는 앱은 새로운 잠금 없는 구현을 수신합니다. android.os.MessageQueue 새로운 구현은 성능을 개선하고 누락된 프레임을 줄이지만 MessageQueue 비공개 필드 및 메서드를 반영하는 클라이언트를 중단할 수 있습니다.

Android 17에서는 기본 MessageQueue 클래스를 다시 작성하여 LooperHandler의 작동 방식을 크게 개선합니다. Android 운영체제가 처음 출시된 이후로 MessageQueue는 단일 잠금에 의존하여 기본 스레드의 태스크 큐를 관리했습니다. 이 설계로 인해 잠금 경합이 자주 발생했습니다. 기본 스레드가 백그라운드 스레드에 의해 차단되어 프레임이 삭제되고 UI 버벅거림이 발생할 수 있습니다.

영향 완화

앱 또는 종속 항목이 런타임 리플렉션을 사용하여 MessageQueue 내부를 살펴보는 경우 이 변경사항이 앱에 영향을 미칠 수 있습니다. 런타임 리플렉션을 사용하여 MessageQueue를 검사하지 마세요.

이전 구현에서는 개발자가 대기 중인 메시지를 검사하기 위해 MessageQueue.mMessages와 같은 비공개 필드에 액세스하는 경우가 있었습니다. 새로운 잠금 없는 구현에서는 내부 데이터 구조가 완전히 변경되었습니다. Android 17은 바이너리 호환성을 유지하기 위해 mMessages 필드를 유지하지만 새 구현에서는 대기열에 메시지가 있는지 여부와 관계없이 이 필드가 항상 null입니다.

또한 일부 인기 있는 테스트 라이브러리를 사용하는 경우 새 MessageQueue 구현과 호환되도록 라이브러리를 업데이트해야 합니다.

Espresso

Espresso는 일반적으로 UI 테스트에 사용됩니다. Espresso 라이브러리는 UI 상태를 올바르게 어설션하려면 기본 스레드가 유휴 상태일 때를 알아야 합니다. 이전 버전의 Espresso는 더 이상 잠금 없는 MessageQueue와 호환되지 않는 리플렉션 기법에 의존했습니다.

작업

Espresso 3.7.0 이상으로 업데이트합니다. 이 버전은 내부 구현 세부정보에 의존하지 않고 Looper와 안전하게 상호작용하기 위해 TestLooperManager API, 특히 Android 16에서 도입된 새로운 API를 사용합니다.

Robolectric

마찬가지로 Robolectric을 사용하여 단위 테스트를 실행하는 경우 테스트가 이전 Looper 모드에 의존하면 문제가 발생할 수 있습니다.

작업

Robolectric 4.17 이상으로 업데이트합니다. @LooperMode(LEGACY)를 사용하는 경우 테스트를 새 @LooperMode(PAUSED)로 이전해야 합니다. 자세한 내용은 Robolectric의 이전 가이드를 참고하세요.

동작 테스트

다음 명령어를 실행하여 targetSDK를 업데이트하지 않고도 Android 17에서 동작 변경사항으로 앱을 테스트할 수 있습니다.

adb am compat enable USE_NEW_MESSAGEQUEUE <your-package-name>

이 명령어는 디버그 가능한 빌드인 경우 앱에서 잠금 없는 MessageQueue를 사용 설정합니다.

앱이 Android 17 (API 수준 37)을 타겟팅하는 경우 새 동작이 기본적으로 사용 설정됩니다. 이 API 수준을 타겟팅한 후 예기치 않은 동작이나 비정상 종료가 발생하면 새 구현을 일시적으로 사용 중지하여 MessageQueue가 원인인지 확인할 수 있습니다.

다음 두 가지 옵션 중 하나를 사용하여 변경사항을 전환할 수 있습니다.

  1. 개발자 옵션앱 호환성 변경사항 메뉴

  2. 다음 ADB 명령어를 실행합니다.

    adb am compat disable USE_NEW_MESSAGEQUEUE <your-package-name>
    

이렇게 하면 앱이 기존의 잠금 기반 구현으로 되돌아가 메시지 대기열 동작 변경사항으로 인해 문제가 발생했는지 확인할 수 있습니다.