Android CTS/GTS UnofficialApisUsageTest 비 인터페이스 제한 대응

이슈 내용

Android를 이용한 Hidden API 및 Refection을 활용한 Access가 제한되어있는 API를 통한 개발이 Android 9에서 부터 적용되었다.

https://developer.android.com/guide/app-compatibility/restrictions-non-sdk-interfaces

Android APP을 개발하고 App Store 검증을 받을 때, restriction에 걸리면 릴리즈가 제한된다.

 

Hidden API 확인 방법

그리고 제한되는 API는 점점 많아지고 있다.

위의 URL을 들어가면 확인 가능하다. 

hiddenapi-flags.csv

예를 들자면

Landroid/view/autofill/AutofillManager;->mServiceClientCleaner:Lsun/misc/Cleaner; lo-prio max-target-o

위의 경우에는 sun.misc.cleaner를 사용하면 안된다.

 

Hidden API 사용 확인 방법

이런것을 쉽게 check하기 위해서 Google에서는 Tool을 제공해 주는데,

veridex 도구 를 통해서 테스트 하면 된다.

이건 Google Manual에 이미 있는 것이기 때문에 그것을 적고자 Posting 하는 것은 아니고,

  • GTS 중에 UnofficialApisUsageTest  오류가 나는 경우에 대해서 쓰고자 한다.

이전에는 CTS에서 Test가 되던 것인데, 언젠가 부터는 GTS로 테스트 되는 시점이 바뀌었다.

그리고 CTS와 다르게 GTS는 별도의 Test Tool이 일반인에게 Open 되지 않는다. 그렇기 때문에

UnofficialApisUsageTest Disallowed type ref 오류가 나면 난감하다. 왜냐하면 내가 만든 소스에 없는 코드 조차도 오류대상이 되기 때문이다. 어떤 Library에서 해당 오류가 나는지도 알 수가 없다.

 

UnofficialApisUsageTest 프로그램 사용법

그래서 

https://android.googlesource.com/platform/cts/+/810c260130d1d8c7714d2949e8c2fdb3df444a76/hostsidetests/api/src/com/android/cts/api/UnofficialApisUsageTest.java 

를 참고해서 간단한 check 프로그램을 만들었다.

public class RunClass {
    private static final Map<String, DefinedClass> definedClassesInDex = new HashMap<>();

    public static void main(String[] args) throws Exception{
        File file = new File("dex/apk_name.apk");

        DexBackedDexFile dexFile = DexFileFactory.loadDexEntry(file, "classes.dex", true, Opcodes.getDefault()).getDexFile();

        dexFile.getClasses().stream().forEach(dexBackedClassDef -> {
            DefinedClass dx = DexAnalyzer.definedClassFrom(dexBackedClassDef);
            definedClassesInDex.put(dx.getName(), dx);
        });
        System.out.println(String.valueOf(dexFile.getClasses().size()));

        List list0 = dexFile.getReferences(0); //String Ref
        List list1 = dexFile.getReferences(1); // Type Ref
        List list2 = dexFile.getReferences(2); // Field Ref
        List list3 = dexFile.getReferences(3); // Method Ref

        System.out.println("String Ref" + list0.size());
        System.out.println("Type Ref" + list1.size());
        System.out.println("Field Ref" + list2.size());
        System.out.println("Method Ref" + list3.size());

        List<DexBackedTypeReference> filtered = (List<DexBackedTypeReference>) list1.stream().filter((Predicate<DexBackedTypeReference>) typeRef-> {
            return 0 < typeRef.getType().indexOf("sun");
        }).collect(Collectors.toList());

        System.out.println("Error Count = " + String.valueOf(filtered.size()));
        filtered.forEach((item)->{
            System.out.println(item.getType());
        });

    }
}

프로젝트 Dex 폴더 밑에

File file = new File("dex/apk_name.apk");

분석할 apk를 넣고, 위의 apk name을 변경해준다.

        List<DexBackedTypeReference> filtered = (List<DexBackedTypeReference>) list1.stream().filter((Predicate<DexBackedTypeReference>) typeRef-> {
            return 0 < typeRef.getType().indexOf("sun");
        }).collect(Collectors.toList());

오류가 났다고 하는 이름을 (위는 sun) 지정해 주고 몇개의 Error count가 나오면 되는지 보면된다.

뭐 별거 아니긴 한데,

무슨 라이브러리에서 해당 오류 대상 Object를 참조하는지 알 방법이 없고,

그렇다고 앱개발사에서 Manufacture에게 GTS 실시간으로 돌려달라고 할 수도 없는 경우, 사용하는 라이브러리를 지워가면서 Test 하는 방법말고는 다른 방법이 없어 보였다.

code는 여기 있고 주의 해야할 것은 프로젝트 구성시 lib 밑에있는 baksmali 를 import 시켜줘야 한다.

https://github.com/theyoung/DexUnofficialChecker

728x90
반응형