Application binary interface

Jungwook Park
kjcoop
Published in
5 min readNov 11, 2019

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 형태로 변환된다.

android java to dex (출처)

desugaring(semantic sugar 를 변환하는 과정)은 주제와 벗어나는 이야기이므로, 제외하고 본다면

  1. .java 를 .class 로 변경
  2. .class 를 .dex 로 변경

이후 target 설치 과정에서는 아래와 같은 과정을 거친다.

JIT architecture (출처)

dex 코드는 기계어가 아니기 때문에 cpu는 직접 수행할 수 없다.

  1. android 2.1 까지는 JIT, AOT 가 없었으므로, runtime 에 이를 기계어로 변환하여 수행하였다.
  2. 성능 개선을 위해 android 2.2 부터 JIT 가 도입되었다. JIT는 빈번하게 수행될 것으로 예상되는 코드를 미리 기계어로 변환하여 보다 빠른 성능을 얻고 매번 runtime에 기계어로 변경하지 않도록 하여 배터리를 절약하였다.
  3. android 5.0 (kitkat 부터 개발자 옵션에 탑재되어 있었음) 부터는 AOT를 탑재하여 앱 설치시 전부 기계어로 dex 를 변환하여 JIT 보다 더 빠른 성능을 얻고 배터리를 절약하였다.
  4. 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 에 설치하여 개발할 수 있을 것으로 보인다.

--

--