기기 식별자

Android 10에서는 모든 기기 식별자가 READ_PRIVILEGED_PHONE_STATE 권한으로 보호되도록 기기 식별자 권한이 변경됩니다. Android 10 이전에는 영구 기기 식별자(IMEI/MEID, IMSI, SIM 및 빌드 일련번호)가 READ_PHONE_STATE 런타임 권한 뒤에서 보호되었습니다. READ_PRIVILEGED_PHONE_STATE 권한은 플랫폼 키로 서명된 앱과 권한이 있는 시스템 앱에만 부여됩니다.

새 권한 요구사항을 자세히 알아보려면 Javadoc 페이지의 TelephonyManager.javaBuild.java 관련 정보를 참조하세요.

이 변경사항은 다음과 같은 API에 영향을 미칩니다.

  • TelephonyManager#getDeviceId
  • TelephonyManager#getImei
  • TelephonyManager#getMeid
  • TelephonyManager#getSimSerialNumber
  • TelephonyManager#getSubscriberId
  • Build#getSerial

READ_PRIVILEGED_PHONE_STATE 권한이 없는 이동통신사 앱의 액세스

READ_PRIVILEGED_PHONE_STATE 권한을 이용할 자격이 없는 미리 로드된 이동통신사 앱은 아래 표에 있는 옵션 중 하나를 구현하면 됩니다.

옵션 설명 제한사항
UICC 이동통신사 권한 Android 플랫폼은 UICC에 저장된 인증서를 로드하고 이러한 인증서로 서명된 앱에 권한을 부여하여 특수 메서드를 호출합니다. 기존 이동통신사의 경우 SIM 이용 고객이 많아서 업데이트하기 쉽지 않습니다. 또한, 새로운 SIM에 작성할 권한이 없는 이동통신사(예: MNO에서 발행한 SIM이 있는 MVNO)는 SIM에 인증서를 추가하거나 업데이트할 수 없습니다.
OEM 허용 목록 OEM은 OP_READ_DEVICE_IDENTIFIER를 사용하여 허용 목록에 있는 이동통신사 앱에 기기 식별자를 제공할 수 있습니다. 이 해결 방법은 일부 이동통신사에만 적용됩니다.
유형 할당 코드(TAC) Android 10에 도입된 getTypeAllocationCode 메서드를 사용하여 제조업체 및 모델 정보를 반환하는 TAC를 노출합니다. TAC에 포함된 정보는 특정 기기를 식별하기에 부적절합니다.
MSISDN 이동통신사는 TelephonyManager에서 PHONE 권한 그룹을 통해 가져올 수 있는 전화번호(MSISDN)를 사용하여 백엔드 시스템의 IMEI를 조회할 수 있습니다. 이 작업은 이동통신사에 큰 부담이 됩니다. IMSI를 사용하여 네트워크 키를 매핑하는 이동통신사가 MSISDN으로 전환하려면 상당한 기술 리소스가 필요합니다.

모든 이동통신사 앱은 CarrierConfig.xml 파일을 이동통신사 앱의 서명 인증서 해시로 업데이트하여 기기 식별자에 액세스할 수 있습니다. 이동통신사 앱에서 권한 정보를 읽는 메서드를 호출하면 플랫폼에서 CarrierConfig.xml 파일에 포함된 앱의 서명 인증서 해시(인증서의 SHA-1 또는 SHA-256 서명)와 일치하는 항목이 있는지 찾습니다. 일치하는 항목을 찾으면 요청한 정보가 반환됩니다. 일치하는 정보가 없다면 보안 예외가 반환됩니다.

이 해결 방법을 구현하려면 이동통신사는 반드시 다음 단계를 따라야 합니다.

  1. CarrierConfig.xml을 이동통신사 앱의 서명 인증서 해시로 업데이트하고 패치를 제출합니다.
  2. QPR1+(권장) 또는 다음 필수 플랫폼 패치와 위의 1단계에서 업데이트된 CarrierConfig.xml 파일이 포함된 패치를 사용하여 빌드를 업데이트하도록 OEM에 요청합니다.

구현

독점 권한 허용 목록을 업데이트하여 기기 식별자에 액세스해야 하는 권한 있는 앱에 READ_PRIVILEGED_PHONE_STATE 권한을 부여하세요.

허용 목록에 관해 자세히 알아보려면 독점 권한 허용 목록을 참고하세요.

영향을 받은 API를 호출하려면 앱이 다음과 같은 요구사항 중 하나를 충족해야 합니다.

  • 앱이 미리 로드된 권한 있는 애플리케이션인 경우 AndroidManifest.xml에 READ_PRIVILEGED_PHONE_STATE 권한을 선언해야 합니다. 또한 앱은 이 독점 권한을 허용 목록에 추가해야 합니다.
  • Google Play를 통해 제공되는 앱은 이동통신사 권한이 필요합니다. 이동통신사 권한 부여에 관한 자세한 내용은 UICC 이동통신사 권한 페이지를 참조하세요.
  • READ_PHONE_STATE 권한을 부여받은 기기 또는 프로필 소유자 앱이 필요합니다.

이러한 요구사항을 하나도 충족하지 않는 앱은 다음과 같이 작동합니다.

  • 앱이 Q 이전 버전을 타겟팅하고 READ_PHONE_STATE 권한을 부여받지 않았다면 SecurityException이 트리거됩니다. 이는 현재의 Q 이전 버전의 동작이며, 이러한 API를 호출하려면 이 권한이 필요하기 때문입니다.
  • Q보다 낮은 버전을 타겟팅하고 READ_PHONE_STATE 권한을 부여받은 앱은 모든 TelephonyManager API에 관해 null 값을, Build#getSerial 메서드에 관해 Build.UNKNOWN을 수신합니다.
  • Android 10 이상을 타겟팅하고 새로운 요구사항을 하나도 충족하지 않는 앱은 SecurityException을 수신합니다.

유효성 검사 및 테스트

호환성 테스트 모음(CTS)에는 이동통신사 권한을 보유한 앱, 기기 및 프로필 소유자, 기기 식별자에 액세스할 수 없을 것으로 예상되는 앱의 예상 기기 식별자 액세스 동작을 검증하기 위한 테스트가 포함되어 있습니다.

다음 CTS 테스트는 이러한 기능과 관련이 있습니다.

cts-tradefed run cts -m CtsCarrierApiTestCases -t
    android.carrierapi.cts.CarrierApiTest

cts-tradefed run cts -m CtsTelephonyTestCases -t
    android.telephony.cts.TelephonyManagerTest

cts-tradefed run cts -m CtsTelephony3TestCases

cts-tradefed run cts -m CtsPermissionTestCases -t
    android.permission.cts.TelephonyManagerPermissionTest

cts-tradefed run cts -m CtsDevicePolicyManagerTestCases -t
    com.android.cts.devicepolicy.DeviceOwnerTest#testDeviceOwnerCanGetDeviceIdentifiers

cts-tradefed run cts -m CtsDevicePolicyManagerTestCases -t
    com.android.cts.devicepolicy.ManagedProfileTest#testProfileOwnerCanGetDeviceIdentifiers

cts-tradefed run cts -m CtsDevicePolicyManagerTestCases -t
    com.android.cts.devicepolicy.ManagedProfileTest#testProfileOwnerCannotGetDeviceIdentifiersWithoutPermission

cts-tradefed run cts -m CtsDevicePolicyManagerTestCases -t
    com.android.cts.devicepolicy.DeviceOwnerTest#testDeviceOwnerCannotGetDeviceIdentifiersWithoutPermission

FAQ

특정 (MCC, MNC)에 해당하도록 CarrierConfig.xml의 허용 목록에 추가할 수 있는 앱은 몇 개인가요?

배열에 포함된 인증서 해시 수에는 제한이 없습니다.

앱을 허용 목록에 추가하려면 CarrierConfig.xml에서 어떤 CarrierConfig 매개변수를 사용해야 하나요?

구성 중인 AOSP 옵션의 특정 CarrierConfig.xml 내에 다음 최상위 구성 항목을 사용합니다.

<string-array name="carrier_certificate_string_array" num="2">
    <item value="BF02262E5EF59FDD53E57059082F1A7914F284B"/>
    <item value="9F3868A3E1DD19A5311D511A60CF94D975A344B"/>
</string-array>

사용할 수 있는 기본 CarrierConfig 템플릿이 있나요?

다음 템플릿을 사용하세요. 이 템플릿을 관련 애셋에 추가해야 합니다.

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<carrier_config>
    <string-array name="carrier_certificate_string_array"
num="1">
        <item value="CERTIFICATE_HASH_HERE"/>
    </string-array>
</carrier_config>

기기 식별자에 액세스하려면 이동통신사 SIM이 기기에 있어야 하나요?

사용되는 CarrierConfig.xml은 현재 삽입된 SIM을 기반으로 결정됩니다. 즉, 이동통신사 Y의 SIM이 삽입된 상태에서 이동통신사 X의 앱이 액세스 권한을 가져오려고 하면 기기에서 해시와 일치하는 항목을 찾지 못하고 보안 예외를 반환합니다.

멀티 SIM 기기에서 이동통신사 #1은 SIM #1의 액세스 권한만 보유하며 그 반대의 경우도 마찬가지입니다.

이동통신사에서 어떻게 앱의 서명 인증서를 해시로 변환하나요?

CarrierConfig.xml에 추가하기 전에 서명 인증서를 해시로 변환하려면 다음과 같이 하세요.

  1. toByteArray를 사용하여 서명 인증서의 서명을 바이트 배열로 변환합니다.
  2. MessageDigest를 사용하여 바이트 배열을 byte[] 유형의 해시로 변환합니다.
  3. byte[]의 해시를 16진수 문자열 형식으로 변환합니다. IccUtils.java 예를 참고하세요.

    List<String> certHashes = new ArrayList<>();
    PackageInfo pInfo; // Carrier app PackageInfo
    MessageDigest md =
    MessageDigest.getInstance("SHA-256");
    for (Signature signature : pInfo.signatures) {
        certHashes.add(bytesToHexString(md.digest(signature.toByteArray()));
    }
    
  4. certHashes1234554321이라는 값이 있는 크기 2의 배열이라면 다음을 이동통신사 구성 파일에 추가합니다.

    <string-array name="carrier_certificate_string_array" num="2">
        <item value="12345"/>
        <item value="54321"/>
    </string-array>