Application binary interface
native code 를 포함한 앱의 경우 deploy target 에 따라 설치 시 아래와 같은 에러를 보는 경우가 있다.
Failure [INSTALL_FAILED_NO_MATCHING_ABIS: Failed to extract native libraries, res=-113]
이 에러의 의미는 무엇일까?
native code 가 포함된 경우 build script 에서 abiFilters 를 정의하여 abi 를 정의하거나 splits 를 이용하여 abi 마다 다른 apk 를 만들어 낼 수 있는데 abi 란 무엇일까?
android 는 java/kotlin 으로 대표할 수 있는 managed code 와 c/c++ 로 대표할 수 있는 android ndk 두 가지 방법으로 개발 할 수 있다.
managed code 는 아래와 같은 과정을 거쳐 dex 형태로 변환된다.
desugaring(semantic sugar 를 변환하는 과정)은 주제와 벗어나는 이야기이므로, 제외하고 본다면
- .java 를 .class 로 변경
- .class 를 .dex 로 변경
이후 target 설치 과정에서는 아래와 같은 과정을 거친다.
dex 코드는 기계어가 아니기 때문에 cpu는 직접 수행할 수 없다.
- android 2.1 까지는 JIT, AOT 가 없었으므로, runtime 에 이를 기계어로 변환하여 수행하였다.
- 성능 개선을 위해 android 2.2 부터 JIT 가 도입되었다. JIT는 빈번하게 수행될 것으로 예상되는 코드를 미리 기계어로 변환하여 보다 빠른 성능을 얻고 매번 runtime에 기계어로 변경하지 않도록 하여 배터리를 절약하였다.
- android 5.0 (kitkat 부터 개발자 옵션에 탑재되어 있었음) 부터는 AOT를 탑재하여 앱 설치시 전부 기계어로 dex 를 변환하여 JIT 보다 더 빠른 성능을 얻고 배터리를 절약하였다.
- android 7.0 부터는 JIT와 AOT를 병행하여 사용한다. (출처) AOT 는 앱 사용시 더 빠른 성능과 배터리 효율을 보장하지만 초기 설치시 모두 기계어 변환을 해야하기 때문에 배터리를 많이 사용하고, 설치 시간이 길어지고, 설치 용량이 커지게 된다.
즉, 현재 dex 로 변환된 코드는 JIT, AOT 를 거쳐 해당 기기에 맞는 기계어로 변환된다는 사실을 알 수 있다.
Native code 는 이미 기계어로 compile 된 상태기 때문에 dex 와는 다르다. 즉, 직접 기계어로 compile 하여 apk 에 패키징해야 한다.
수많은 cpu 와 architecture 가 있으며 이를 모두 지원하기는 현실적으로 불가능하기 때문에 binary level 의 호환성을 보장할 수 있는 규약이 필요하며 그 규약이 abi(application binary interface) 이다.
api 가 application layer에서의 호환성을 보장한다면, abi 는 binary level 에서의 호환성을 보장한다.
또, 이를 위해 ndk toolchain 은 대상 안드로이드 기기에 맞게 compile 할 수 있는 방법을 제공한다.
안드로이드의 abi 는 Android Compatibility Definition Document(예, android 10 cdd)에 이미 정의되어 있으며, 이 정의를 따르지 않으면 Compatibility Test Suite를 통과할 수 없으며, GMS를 탑재할 수도 없다.
처음으로 돌아가서
Failure [INSTALL_FAILED_NO_MATCHING_ABIS: Failed to extract native libraries, res=-113]
위 에러는 native code 가 deploy target 이 지원하는 abi 에 해당하는 binary를 포함하지 않고 있는 경우에 발생함을 알 수 있다.
abiFilters는 apk 에 포함할 abi 를 제한하는데 사용한다.
splits는 abi 별로 여러개의 apk 를 생성하는데 사용한다.
안드로이드 기기의 abi 는 아래와 build.prop 값에서 확인할 수 있으며 (cdd에 정의되어 있음)
ro.product.cpu.abi
ro.product.cpu.abilist
ro.product.cpu.abilist32
ro.product.cpu.abilist64
cpu 의 세부 정보는 /proc/cpuinfo 파일을 통해 확인할 수 있다.
2019년 9월 26일에 android pie, x86 기반의 안드로이드 emulator image 에 arm to x86 translation 가 포함되었다고 한다. (출처)
arm to x86 translation 이 포함된 이미지에는 x86 기반 emulator 에서도 arm target 으로 build 한 native binary를 수행할 수 있으므로, arm 기반 native code 만 포함하고 있는 application 도 (빠른) x86 emulator 에 설치하여 개발할 수 있을 것으로 보인다.