동작 변경사항: 모든 앱

Android 10에는 앱에 영향을 줄 수 있는 동작 변경사항이 포함되어 있습니다. 이 페이지에 나열된 변경사항은 앱의 targetSdkVersion과 관계없이 Android 10에서 실행될 때 앱에 적용됩니다. 이러한 변경사항을 제대로 지원하려면 앱을 테스트하고 필요에 따라 수정해야 합니다.

앱의 targetSdkVersion이 29 이상인 경우 추가 변경사항도 지원해야 합니다. 자세한 내용은 29를 타겟팅하는 앱의 동작 변경사항을 참고하세요.

참고: Android 10에는 이 페이지에 나열된 변경사항 외에도 다음을 비롯한 많은 개인 정보 보호 기반 변경사항 및 제한사항이 도입되었습니다.

  • 기기 위치에 대한 백그라운드 액세스
  • 백그라운드 활동 시작
  • 관심 연락처 정보
  • 무작위 MAC 주소
  • 카메라 메타데이터
  • 권한 모델

이러한 변경사항은 모든 앱에 영향을 미치며 사용자 개인 정보 보호를 강화합니다. 이러한 변경사항을 지원하는 방법에 관한 자세한 내용은 개인 정보 보호 변경사항 페이지를 참고하세요.

비 SDK 인터페이스 제한사항

앱 안정성과 호환성을 보장하기 위해 플랫폼에서는 Android 9 (API 수준 28)에서 앱이 사용할 수 있는 비 SDK 인터페이스를 제한하기 시작했습니다. Android 10에는 Android 개발자와의 공동작업 및 최신 내부 테스트를 기반으로 제한된 비 SDK 인터페이스의 업데이트된 목록이 포함되어 있습니다. Google의 목표는 비 SDK 인터페이스를 제한하기 전에 공개 대안을 사용할 수 있도록 하는 것입니다.

Android 10 (API 수준 29)을 타겟팅하지 않을 경우 이러한 변경사항 중 일부는 개발자에게 곧바로 영향을 주지 않을 수도 있습니다. 그러나 앱의 대상 API 수준에 따라 현재 일부 비 SDK 인터페이스를 사용할 수 있지만 비 SDK 메서드 또는 필드를 사용하면 언제든지 앱이 중단될 위험이 있습니다.

앱에서 비 SDK 인터페이스를 사용하는지 확실하지 않으면 앱을 테스트하여 확인할 수 있습니다. 앱에서 비 SDK 인터페이스를 사용하는 경우 대안 SDK로의 이전을 계획해야 합니다. 일부 앱의 경우 비 SDK 인터페이스 사용에 관한 유효한 사용 사례가 있음을 알고 있습니다. 앱 기능을 구현하기 위해 비 SDK 인터페이스 대신 무엇을 사용해야 할지 알 수 없다면 새 공개 API를 요청해야 합니다.

자세한 내용은 Android 10의 비 SDK 인터페이스 제한사항 업데이트비 SDK 인터페이스 제한사항을 참고하세요.

동작 탐색

Android 10부터 사용자는 기기 전체에서 동작 탐색을 사용 설정할 수 있습니다. 사용자가 동작 탐색을 사용 설정하면 앱이 API 수준 29를 타겟팅하는지와 관계없이 기기의 모든 앱에 영향을 미칩니다. 예를 들어 사용자가 화면 가장자리에서 안쪽으로 스와이프하면 앱이 화면의 일부에 관해 해당 동작을 특별히 재정의하지 않는 한 시스템이 해당 동작을 뒤로 탐색으로 해석합니다.

앱이 동작 탐색과 호환되도록 하려면 앱 콘텐츠를 가장자리에서 가장자리로 확장하고 충돌하는 동작을 적절하게 처리하는 것이 좋습니다. 자세한 내용은 동작 탐색 문서를 참고하세요.

NDK

Android 10에는 다음과 같은 NDK 변경사항이 있습니다.

공유 객체에는 텍스트 재배치가 포함될 수 없습니다.

Android 6.0 (API 수준 23)은 공유 객체에서 텍스트 재배치 사용을 허용하지 않습니다. 코드는 있는 그대로 로드해야 하며 수정해서는 안 됩니다. 이러한 변경으로 인해 앱 로드 시간이 단축되고 보안이 향상됩니다.

SELinux는 Android 10 이상을 타겟팅하는 앱에 이 제한사항을 적용합니다. 이러한 앱에서 텍스트 재배치가 포함된 공유 객체를 계속 사용하면 중단될 위험이 높습니다.

Bionic 라이브러리 및 동적 링커 경로 변경사항

Android 10부터 일부 경로는 일반 파일이 아닌 심볼릭 링크입니다. 일반 파일인 경로를 사용하던 앱은 중단될 수 있습니다.

  • /system/lib/libc.so -> /apex/com.android.runtime/lib/bionic/libc.so
  • /system/lib/libm.so -> /apex/com.android.runtime/lib/bionic/libm.so
  • /system/lib/libdl.so -> /apex/com.android.runtime/lib/bionic/libdl.so
  • /system/bin/linker -> /apex/com.android.runtime/bin/linker

이러한 변경사항은 lib/lib64/로 대체된 파일의 64비트 변형에도 적용됩니다.

호환성을 위해 이전 경로에서 심볼릭 링크가 제공됩니다. 예를 들어 /system/lib/libc.so/apex/com.android.runtime/lib/bionic/libc.so의 심볼릭 링크입니다. 따라서 dlopen(“/system/lib/libc.so”)는 계속 작동하지만 앱이 /proc/self/maps 또는 이와 유사한 항목을 읽어 로드된 라이브러리를 검사하려고 하면 실제로 차이를 발견합니다. 이는 일반적인 경우는 아니지만 일부 앱은 해킹 방지 프로세스의 일부로 검사하는 것으로 확인되었습니다. 이 경우 /apex/… 경로가 Bionic 파일의 유효한 경로로 추가되어야 합니다.

실행 전용 메모리에 매핑된 시스템 바이너리/라이브러리

Android 10부터 시스템 바이너리와 라이브러리의 실행 가능 세그먼트가 코드 재사용 공격에 대비한 강화 기술인 메모리 실행 전용 (읽기 불가능)으로 매핑됩니다. 앱이 버그나 취약점 검사에서든, 의도적인 메모리 검사에서든 실행 전용으로 표시된 메모리 세그먼트에서 읽기 작업을 실행하면 시스템은 앱에 SIGSEGV 신호를 보냅니다.

/data/tombstones/에서 관련 Tombstone 파일을 검사하여 이 동작으로 인해 비정상 종료가 발생했는지 식별할 수 있습니다. 실행 전용 관련 비정상 종료에는 다음과 같은 취소 메시지가 포함됩니다.

Cause: execute-only (no-read) memory access error; likely due to data in .text.

이 문제를 해결하여 메모리 검사와 같은 작업을 실행하려면 mprotect()를 호출하여 실행 전용 세그먼트를 읽기+실행으로 표시하면 됩니다. 그러나 이 액세스 권한 설정은 앱과 사용자를 더 안전하게 보호하므로 나중에 다시 실행 전용으로 설정하는 것이 좋습니다.

보안

Android 10의 보안 변경사항은 다음과 같습니다.

TLS 1.3 기본 사용 설정

Android 10 이상에서는 모든 TLS 연결에 TLS 1.3이 기본적으로 사용 설정됩니다. 다음은 TLS 1.3 구현에 관한 몇 가지 중요한 세부정보입니다.

  • TLS 1.3 암호화 스위트는 맞춤설정할 수 없습니다. TLS 1.3을 사용 설정하면 지원되는 TLS 1.3 암호화 스위트가 항상 사용 설정됩니다. setEnabledCipherSuites()를 호출하여 이를 사용 중지하려는 시도는 모두 무시됩니다.
  • TLS 1.3이 협상되면 세션이 세션 캐시에 추가되기 전에 HandshakeCompletedListener 객체가 호출됩니다. (TLS 1.2 및 기타 이전 버전에서는 세션이 세션 캐시에 추가된 후에 이러한 객체가 호출됩니다.)
  • 이전 버전의 Android에서 SSLEngine 인스턴스가 SSLHandshakeException을 발생시키는 일부 상황에서 이러한 인스턴스는 Android 10 이상에서 대신 SSLProtocolException을 발생시킵니다.
  • 0-RTT 모드는 지원되지 않습니다.

원하는 경우 SSLContext.getInstance("TLSv1.2")를 호출하여 TLS 1.3이 사용 중지된 SSLContext를 가져올 수 있습니다. 또한 적절한 객체에서 setEnabledProtocols()를 호출하여 연결별로 프로토콜 버전을 사용 설정 또는 중지할 수 있습니다.

SHA-1로 서명된 인증서가 TLS에서 신뢰되지 않음

Android 10에서 SHA-1 해시 알고리즘을 사용하는 인증서는 TLS 연결에서 신뢰되지 않습니다. 루트 CA는 2016년부터 이러한 인증서를 발급하지 않았으며 Chrome 또는 기타 주요 브라우저에서 더 이상 신뢰되지 않습니다.

SHA-1을 사용하여 인증서를 제공하는 사이트에 연결하려는 경우 연결 시도가 실패합니다.

KeyChain 동작 변경사항 및 개선사항

Chrome과 같은 일부 브라우저에서는 TLS 서버가 TLS 핸드셰이크의 일부로 인증서 요청 메시지를 보낼 때 인증서를 선택할 수 있습니다. Android 10부터 KeyChain 객체는 KeyChain.choosePrivateKeyAlias()를 호출하여 사용자에게 인증서 선택 메시지를 표시할 때 발급기관과 키 사양 매개변수를 준수합니다. 특히 이 메시지에는 서버 사양을 준수하지 않는 선택사항이 포함되어 있지 않습니다.

서버 사양과 일치하는 인증서가 없거나 기기에 인증서가 설치되지 않은 경우와 같이 사용자가 선택할 수 있는 사용 가능한 인증서가 없는 경우 인증서 선택 메시지가 아예 표시되지 않습니다.

또한 Android 10 이상에서는 키 또는 CA 인증서를 KeyChain 객체로 가져오기 위해 기기 화면 잠금이 필요하지 않습니다.

기타 TLS 및 암호화 변경사항

Android 10에 적용되는 TLS 및 암호화 라이브러리에서 사소한 몇 가지 사항이 변경되었습니다.

  • AES/GCM/NoPadding 및 ChaCha20/Poly1305/NoPadding 암호화는 getOutputSize()에서 더 정확한 버퍼 크기를 반환합니다.
  • TLS_FALLBACK_SCSV 암호화 제품군은 최대 프로토콜 TLS 1.2 이상의 연결 시도에서 생략됩니다. TLS 서버 구현이 개선되었으므로 TLS 외부 대체를 시도하지 않는 것이 좋습니다. 대신 TLS 버전 협상에 의존하는 것이 좋습니다.
  • ChaCha20-Poly1305는 ChaCha20/Poly1305/NoPadding의 별칭입니다.
  • 끝에 점이 있는 호스트 이름은 유효한 SNI 호스트 이름으로 간주되지 않습니다.
  • 인증서 응답용 서명 키를 선택할 때 CertificateRequest의 supported_signature_algorithms 확장이 존중됩니다.
  • TLS에서 RSA-PSS 서명과 함께 불투명한 서명 키(예: Android 키 저장소의 서명 키)를 사용할 수 있습니다.

Wi-Fi Direct 방송

Android 10에서는 Wi-Fi Direct와 관련된 다음 브로드캐스트가 고정되지 않습니다.

브로드캐스트가 고정되었기 때문에 등록 시 앱에서 이러한 브로드캐스트를 수신하는 데 의존했다면 대신 초기화 시 적절한 get() 메서드를 사용하여 정보를 가져옵니다.

Wi-Fi Aware 기능

Android 10에는 Wi-Fi Aware 데이터 경로를 사용하여 TCP/UDP 소켓을 간편하게 만드는 지원이 추가되었습니다. ServerSocket에 연결되는 TCP/UDP 소켓을 만들려면 클라이언트 기기가 서버의 IPv6 주소와 포트를 알아야 합니다. 이전에는 BT 또는 Wi-Fi Aware 레이어 2 메시징을 사용하는 등 대역 외로 통신하거나 mDNS와 같은 다른 프로토콜을 사용하여 대역 내에서 검색해야 했습니다. Android 10에서는 네트워크 설정의 일부로 이 정보를 전달할 수 있습니다.

서버는 다음 중 하나를 할 수 있습니다.

  • ServerSocket를 초기화하고 사용할 포트를 설정하거나 가져옵니다.
  • Wi-Fi Aware 네트워크 요청의 일부로 포트 정보를 지정합니다.

다음 코드 샘플은 네트워크 요청의 일부로 포트 정보를 지정하는 방법을 보여줍니다.

Kotlin

val ss = ServerSocket()
val ns = WifiAwareNetworkSpecifier.Builder(discoverySession, peerHandle)
  .setPskPassphrase("some-password")
  .setPort(ss.localPort)
  .build()

val myNetworkRequest = NetworkRequest.Builder()
  .addTransportType(NetworkCapabilities.TRANSPORT_WIFI_AWARE)
  .setNetworkSpecifier(ns)
  .build()

Java

ServerSocket ss = new ServerSocket();
WifiAwareNetworkSpecifier ns = new WifiAwareNetworkSpecifier
  .Builder(discoverySession, peerHandle)
  .setPskPassphrase(“some-password”)
  .setPort(ss.getLocalPort())
  .build();

NetworkRequest myNetworkRequest = new NetworkRequest.Builder()
  .addTransportType(NetworkCapabilities.TRANSPORT_WIFI_AWARE)
  .setNetworkSpecifier(ns)
  .build();

그런 다음 클라이언트는 Wi-Fi Aware 네트워크 요청을 실행하여 서버에서 제공하는 IPv6 및 포트를 가져옵니다.

Kotlin


val callback = object : ConnectivityManager.NetworkCallback() {
  override fun onAvailable(network: Network) {
    ...
  }
  
  override fun onLinkPropertiesChanged(network: Network,
      linkProperties: LinkProperties) {
    ...
  }

  override fun onCapabilitiesChanged(network: Network,
      networkCapabilities: NetworkCapabilities) {
    ...
    val ti = networkCapabilities.transportInfo
    if (ti is WifiAwareNetworkInfo) {
       val peerAddress = ti.peerIpv6Addr
       val peerPort = ti.port
    }
  }
  override fun onLost(network: Network) {
    ...
  }
};

connMgr.requestNetwork(networkRequest, callback)

Java

callback = new ConnectivityManager.NetworkCallback() {
  @Override
  public void onAvailable(Network network) {
    ...
  }
  @Override
  public void onLinkPropertiesChanged(Network network,
      LinkProperties linkProperties) {
    ...
  }
  @Override
  public void onCapabilitiesChanged(Network network,
      NetworkCapabilities networkCapabilities) {
    ...
    TransportInfo ti = networkCapabilities.getTransportInfo();
    if (ti instanceof WifiAwareNetworkInfo) {
       WifiAwareNetworkInfo info = (WifiAwareNetworkInfo) ti;
       Inet6Address peerAddress = info.getPeerIpv6Addr();
       int peerPort = info.getPort();
    }
  }
  @Override
  public void onLost(Network network) {
    ...
  }
};

connMgr.requestNetwork(networkRequest, callback);

Go 기기의 SYSTEM_ALERT_WINDOW

Android 10 (Go 버전) 기기에서 실행되는 앱은 SYSTEM_ALERT_WINDOW 권한을 받을 수 없습니다. 이는 그리기 오버레이 창에서 과도한 메모리를 사용하므로 메모리가 부족한 Android 기기의 성능에 특히 해로울 수 있습니다.

Android 9 이하를 실행하는 Go 버전 기기에서 실행되는 앱이 SYSTEM_ALERT_WINDOW 권한을 받는 경우 기기가 Android 10으로 업그레이드되더라도 앱은 권한을 유지합니다. 그러나 아직 이 권한이 없는 앱에는 기기가 업그레이드된 후 이 권한을 부여할 수 없습니다.

Go 기기의 앱이 ACTION_MANAGE_OVERLAY_PERMISSION 작업이 포함된 인텐트를 전송하면 시스템은 자동으로 요청을 거부하고 사용자를 설정 화면으로 이동합니다. 이 화면에는 기기의 속도가 느려져 권한이 허용되지 않는다는 메시지가 표시됩니다. Go 기기의 앱이 Settings.canDrawOverlays()를 호출하면 메서드는 항상 false를 반환합니다. 다시 말하지만, 이러한 제한사항은 기기가 Android 10으로 업그레이드되기 전에 SYSTEM_ALERT_WINDOW 권한을 받은 앱에는 적용되지 않습니다.

이전 Android 버전을 대상으로 하는 앱에 대한 경고

Android 10 이상을 실행하는 기기는 Android 5.1 (API 수준 22) 이하를 타겟팅하는 앱을 처음 실행할 때 사용자에게 경고를 표시합니다. 앱에서 사용자에게 권한 부여를 요구하는 경우 사용자는 앱을 처음 실행하도록 허용하기 전에 앱의 권한을 조정할 수도 있습니다.

Google Play의 대상 API 요구사항으로 인해 사용자가 최근에 업데이트되지 않은 앱을 실행할 때만 이러한 경고가 표시됩니다. 다른 스토어를 통해 배포되는 앱의 경우 2019년에 유사한 대상 API 요구사항이 적용됩니다. 이러한 요구사항에 관한 자세한 내용은 2019년의 대상 API 수준 요구사항 확장을 참고하세요.

SHA-2 CBC 암호화 제품군 제거

다음 SHA-2 CBC 암호화 제품군이 플랫폼에서 제거되었습니다.

  • TLS_RSA_WITH_AES_128_CBC_SHA256
  • TLS_RSA_WITH_AES_256_CBC_SHA256
  • TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
  • TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
  • TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
  • TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384

이러한 암호화 스위트는 GCM을 사용하는 유사한 암호화 스위트보다 안전하지 않으며, 대부분의 서버는 이러한 암호화 스위트의 GCM 및 CBC 변형을 모두 지원하거나 둘 다 지원하지 않습니다.

앱 사용

Android 10에서는 앱 사용과 관련하여 다음과 같은 동작이 변경되었습니다.

  • UsageStats 앱 사용량 개선 - 또한 Android 10은 인스턴트 앱 사용량을 올바르게 추적합니다.

  • 앱별 주의 분산 상태 -

  • 정지 및 재생 -

HTTPS 연결 변경

Android 10을 실행하는 앱이 nullsetSSLSocketFactory()에 전달하면 IllegalArgumentException이 발생합니다. 이전 버전에서는 nullsetSSLSocketFactory()에 전달하는 것이 현재 기본 팩토리를 전달하는 것과 효과가 같았습니다.

android.preference 라이브러리 지원 중단

android.preference 라이브러리는 Android 10부터 지원 중단됩니다. 개발자는 Android Jetpack의 일부인 AndroidX 환경설정 라이브러리를 대신 사용해야 합니다. 이전 및 개발에 도움이 되는 추가 리소스는 업데이트된 설정 가이드와 함께 공개 샘플 앱참조 문서를 확인하세요.

ZIP 파일 유틸리티 라이브러리 변경사항

Android 10에서는 ZIP 파일을 처리하는 java.util.zip 패키지의 클래스에 다음과 같은 변경사항이 도입되었습니다. 이러한 변경사항으로 인해 Android와 java.util.zip를 사용하는 다른 플랫폼 간에 라이브러리 동작의 일관성이 높아집니다.

Inflater

이전 버전에서는 Inflater 클래스의 일부 메서드가 end() 호출 후 호출되면 IllegalStateException이 발생했습니다. Android 10에서는 대신 이러한 메서드에서 NullPointerException이 발생합니다.

ZipFile

Android 10 이상에서는 제공된 ZIP 파일에 파일이 포함되어 있지 않으면 File, intCharset 유형의 인수를 받는 ZipFile의 생성자ZipException을 발생시키지 않습니다.

ZipOutputStream

Android 10 이상에서는 ZipOutputStreamfinish() 메서드가 파일이 포함되지 않은 ZIP 파일의 출력 스트림을 작성하려고 하면 ZipException이 발생하지 않습니다.

카메라 변경사항

카메라를 사용하는 많은 앱에서는 기기가 세로 모드로 구성된 경우 카메라 방향에 설명된 대로 실제 기기도 세로 모드 방향이라고 가정합니다. 이전에는 이것이 안전한 가정이었지만 폴더블과 같이 사용 가능한 폼 팩터가 확장됨에 따라 바뀌었습니다. 이러한 기기에서 이러한 가정으로 인해 카메라 뷰파인더의 디스플레이가 잘못 회전되거나 크기가 조정되거나 둘 다 잘못될 수 있습니다.

API 수준 24 이상을 타겟팅하는 애플리케이션은 android:resizeableActivity를 명시적으로 설정하고 멀티 윈도우 작업을 처리하는 데 필요한 기능을 제공해야 합니다.

배터리 사용량 추적

Android 10부터 SystemHealthManager주요 충전 이벤트 후 기기가 분리될 때마다 배터리 사용량 통계를 재설정합니다. 일반적으로 주요 충전 이벤트는 기기가 완전히 충전되었거나 기기가 거의 방전된 상태에서 대부분 충전된 상태입니다.

Android 10 이전에는 배터리 수준에 거의 변화가 없어도 기기가 전원에서 분리될 때마다 배터리 사용량 통계가 재설정되었습니다.

Android Beam 지원 중단

Android 10에서는 근거리 무선통신 (NFC)을 통해 기기 간 데이터 공유를 시작하기 위한 오래된 기능인 Android Beam을 공식적으로 지원 중단합니다. 또한 몇 가지 관련 NFC API에 대한 지원이 중단됩니다. Android Beam을 사용하려는 기기 제조업체 파트너는 선택사항으로 계속 사용할 수 있지만 더 이상 개발이 진행되지는 않습니다. 그러나 Android는 다른 NFC 기능과 API를 계속 지원하며 태그 및 결제에서 읽기와 같은 사용 사례는 계속 예상대로 작동합니다.

java.math.BigDecimal.stripTrailingZeros() 동작 변경

BigDecimal.stripTrailingZeros()는 입력 값이 0인 경우 후행 0을 더 이상 특수한 사례로 유지하지 않습니다.

java.util.regex.Matcher 및 패턴 동작 변경사항

입력 시작 부분에 너비가 0인 일치 항목이 있을 때 더 이상 빈 String("")로 시작하지 않도록 split()의 결과가 변경되었습니다. 이는 String.split()에도 영향을 줍니다. 예를 들어 이제 "x".split(""){"x"}를 반환하는 반면 이전 버전의 Android에서는 {"", "x"}를 반환했습니다. 이제 "aardvark".split("(?=a)"{"", "a", "ardv", "ark"} 대신 {"a", "ardv", "ark"}를 반환합니다.

잘못된 인수에 관한 예외 동작도 개선되었습니다.

  • 대체된 String가 잘못된 백슬래시로 끝나는 경우 이제 appendReplacement(StringBuffer, String)에서 IndexOutOfBoundsException 대신 IllegalArgumentException이 발생합니다. 이는 부적합합니다. 이제 대체 String$로 끝나는 경우 동일한 예외가 발생합니다. 이전에는 이 시나리오에서 예외가 발생하지 않았습니다.
  • replaceFirst(null)NullPointerException이 발생하면 더 이상 Matcher에서 reset()를 호출하지 않습니다. 이제 일치하는 항목이 없을 때도 NullPointerException이 발생합니다. 이전에는 일치하는 경우에만 발생했습니다.
  • 이제 그룹 색인이 범위를 벗어나면 start(int group), end(int group), group(int group)에서 더 일반적인 IndexOutOfBoundsException이 발생합니다. 이전에는 이러한 메서드에서 ArrayIndexOutOfBoundsException이 발생했습니다.

GradientDrawable의 기본 각도는 이제 TOP_BOTTOM입니다.

Android 10에서 XML로 GradientDrawable를 정의하고 각도 측정을 제공하지 않으면 그라데이션 방향이 기본적으로 TOP_BOTTOM로 설정됩니다. 이는 기본값이 LEFT_RIGHT인 이전 버전의 Android에서 변경된 것입니다.

이 문제를 해결하기 위해 최신 버전의 AAPT2로 업데이트하는 경우 각도 측정이 지정되지 않으면 도구에서 기존 앱의 각도 측정값을 0으로 설정합니다.

기본 SUID를 사용하여 직렬화된 객체 로깅

Android 7.0 (API 수준 24)부터 플랫폼에서는 직렬화 가능한 객체의 기본 serialVersionUID를 수정했습니다. 이 수정사항은 API 수준 23 이하를 타겟팅하는 앱에는 영향을 미치지 않았습니다.

Android 10부터 앱이 API 수준 23 이하를 타겟팅하고 기존의 잘못된 기본 serialVersionUID를 사용하면 시스템은 경고를 기록하고 코드 수정을 제안합니다.

특히 다음 조건을 모두 충족하는 경우 시스템에서 경고를 기록합니다.

  • 앱이 API 수준 23 이하를 타겟팅합니다.
  • 클래스는 직렬화됩니다.
  • 직렬화된 클래스는 serialVersionUID를 명시적으로 설정하는 대신 기본 serialVersionUID를 사용합니다.
  • 기본 serialVersionUID는 앱이 API 수준 24 이상을 타겟팅한 경우의 serialVersionUID와 다릅니다.

이 경고는 영향을 받는 클래스마다 한 번씩 기록됩니다. 경고 메시지에는 추천 수정사항이 포함됩니다. 즉, 앱에서 API 수준 24 이상을 타겟팅하는 경우 계산되는 기본값으로 serialVersionUID를 명시적으로 설정하는 것입니다. 이 수정사항을 사용하면 API 수준 23 이하를 타겟팅하는 앱에서 해당 클래스의 객체가 직렬화된 경우 24 이상을 타겟팅하는 앱에서 객체를 올바르게 읽도록 할 수 있으며 그 반대의 경우도 마찬가지입니다.

java.io.FileChannel.map() 변경사항

Android 10부터는 truncate()를 사용하여 크기를 변경할 수 없는 비표준 파일(예: /dev/zero)에는 FileChannel.map()가 지원되지 않습니다. 이전 버전의 Android는 truncate()에서 반환된 오류를 표시하지 않았지만 Android 10에서는 IOException이 발생합니다. 이전 동작이 필요하면 네이티브 코드를 사용해야 합니다.