Android 17부터 Android 17 이상을 타겟팅하는 앱은 android.os.MessageQueue의 새로운 잠금 해제 구현을 수신합니다. 새 구현은 성능을 개선하고 누락된 프레임을 줄이지만 MessageQueue 비공개 필드와 메서드를 반영하는 클라이언트를 중단할 수 있습니다.
Android 17에서는 기본 MessageQueue 클래스를 다시 작성하여 Looper 및 Handler 작동 방식이 크게 개편되었습니다.
Android 운영체제가 처음 출시된 이후 MessageQueue는 단일 잠금을 사용하여 기본 스레드의 작업 대기열을 관리했습니다. 이 설계로 인해 잠금 경합이 발생하는 경우가 많았습니다. 기본 스레드가 백그라운드 스레드에 의해 차단되어 프레임이 누락되고 UI 버벅거림이 발생할 수 있었습니다.
영향 완화
앱 또는 앱의 종속 항목이 MessageQueue 내부를 들여다보기 위해 런타임 리플렉션을 사용하는 경우 이 변경사항이 앱에 영향을 미칠 수 있습니다. 런타임 리플렉션을 사용하여 MessageQueue를 검사하지 마세요.
기존 구현에서는 개발자가 MessageQueue.mMessages와 같은 비공개 필드에 액세스하여 대기 중인 메시지를 검사하는 경우가 있었습니다. 새로운 잠금 없는 구현으로 내부 데이터 구조가 완전히 변경되었습니다.
바이너리 호환성을 유지하기 위해 Android 17에서는 mMessages 필드를 유지하지만 새 구현에서는 대기열에 메시지가 있는지와 관계없이 이 필드가 항상 null입니다.
또한 인기 있는 일부 테스트 라이브러리를 사용하는 경우 새 MessageQueue 구현과 호환되도록 라이브러리를 업데이트해야 합니다.
Espresso
Espresso는 UI 테스트에 일반적으로 사용됩니다. Espresso 라이브러리는 UI 상태를 올바르게 어설션하기 위해 기본 스레드가 유휴 상태인 시점을 알아야 합니다. 이전 버전의 Espresso는 더 이상 잠금 없는 MessageQueue와 호환되지 않는 리플렉션 기법을 사용했습니다.
작업
Espresso 3.7.0 이상으로 업데이트합니다. 이 버전에서는 TestLooperManager API, 특히 Android 16에서 도입된 새로운 API를 사용하여 내부 구현 세부정보에 의존하지 않고 Looper와 안전하게 상호작용합니다.
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 수준을 타겟팅한 후 예기치 않은 동작이나 비정상 종료가 발생하면 새 구현을 일시적으로 사용 중지하여 MessageQueue가 원인인지 확인할 수 있습니다.
다음 두 가지 옵션 중 하나를 사용하여 변경사항을 전환할 수 있습니다.
다음 ADB 명령어를 실행합니다.
adb am compat disable USE_NEW_MESSAGEQUEUE <your-package-name>
이렇게 하면 앱이 기존의 잠금 기반 구현으로 되돌아가므로 문제의 원인이 메시지 대기열 동작 변경인지 확인할 수 있습니다.