The Android Developer Challenge is back! Submit your idea before December 2.

동작 변경사항: 모든 앱

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

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

참고: 이 문서에서는 동작 변경사항 외에도 Android 10 개인정보 보호 기능을 검토하고 지원해야 합니다.

비 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/에서 관련 삭제 표시 파일을 검사하여 이 동작이 비정상 종료의 원인인지를 식별할 수 있습니다. 실행 전용 관련 비정상 종료에는 다음과 같은 중단 메시지가 포함됩니다.

    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 Keystore의 서명 키)를 사용할 수 있습니다.

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()
    

자바

    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)
    

자바

    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에서는 앱이 화면 분할 또는 PIP 모드에서 사용될 때 UsageStats로 앱 사용량을 정확하게 추적합니다. 또한 Android 10은 인스턴트 앱 사용을 정확하게 추적합니다.

  • 앱별 그레이 스케일 - Android 10은 앱 단위로 그레이 스케일 표시 모드를 설정할 수 있습니다.

  • 앱별 주의 분산 상태 - 이제 Android 10은 앱에 알림이 표시되지 않고 앱이 추천 앱으로 표시되지 않는 '주의 분산 상태'로 앱을 선택적으로 설정할 수 있습니다.

  • Suspension and playback - Android 10에서는 일시정지된 앱이 오디오를 재생할 수 없습니다.

HTTPS 연결 변경

Android 10을 실행하는 앱이 setSSLSocketFactory()null을 전달하면 IllegalArgumentException이 발생합니다. 이전 버전에서는 setSSLSocketFactory()null을 전달하는 것이 현재의 공장 기본값을 전달하는 것과 동일했습니다.

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

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

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

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

Inflater

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

ZipFile

Android 10 이상에서 File, intCharset 유형의 인수를 사용하는 ZipFile용 생성자는 제공된 ZIP 파일에 아무것도 포함되지 않은 경우 ZipException을 표시합니다.

ZipOutputStream

Android 10 이상에서는 아무것도 포함되지 않은 ZIP 파일에 관한 출력 스트림을 쓰려고 시도할 경우 ZipOutputStreamfinish() 메서드가 ZipException을 표시합니다.

카메라 변경사항

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

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

배터리 사용량 추적

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

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

Android Beam 지원 중단

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