[android] loadLibrary 와 CPU 특성
android 2013. 10. 31. 14:20Android에서 native 라이브러리를 만들 때 보통은 armeabi / armeabi-v7a 용으로 컴파일 해서 프로젝트의 libs 폴더 밑에 넣어준다. 이는 대부분의 안드로이드 장치가 ARM 기반의 CPU로 만들어 졌기 때문이다. 사실 Android 에서 지원하는 cpu는 ARM 뿐만 아니라 Interl의 x86 도 지원하고 MIPS 또한 공식적으로 지원한다. 다만 시장에 아직 제품이 많지 않을 뿐이다.
참고 : CPU Architecuture 별 지원 Platforms
Native Code CPU Architecture Used |
Compatible Android Platform(s) |
ARM, ARM-NEON |
Android 1.5 (API Level 3) and higher |
x86 |
Android 2.3 (API Level 9) and higher |
MIPS |
Android 2.3 (API Level 9) and higher |
이번에 Intel에서 Xolo-X900 이라는 Intel의 x86 기반의 안드로이드 폰을 출시했다. 이번이라고 한건 내가 지금 알았기 때문이고, 찾아보니 실체 출시된 날짜는 2012년 4월 쯤이었다. 와~ 완전 모르고 있었네 ㅎㅎ
So 파일을 로딩하기 위해서 보통은 System.loadLibrary() 함수를 호출한다. 그러면 해당 함수가 알아서 CPU를 확인해서 알맞은 so 모듈을 로딩해주는 것으로 알고 있었다. 우연히 xolo 디바이스를 구할 수 있어서 armeabi/armeabi-v7a 용 so 모듈만 있는 프로그램을 실행시켰는데, armeabi-v7a용 so 가 로딩 되는 것이다. 우와~ 그러나 실행하다가 죽는다. ㅠㅠ
그래서 loadLibrary를 연구해 보기 시작했다. 가장 먼저 developer의 문서를 찾아보면 아래와 같다.
Loads and links the library with the specified name. The mapping of the specified library name to the full path for loading the library is implementation-dependent.
즉 loadLibrary(“foo”) 이렇게 호출하면 이름(foo)과 일치하면서, device의 CPU타입에 따라서 적절한 모듈을 로딩해 준다. 즉 해당 device가 armeabi-v7a 를 지원하면 lib/armeabi-v7a 경로에 있는 foo.so를 로딩한고 device가 x86을 지원하면 lib/x86 경로이 있는 foo.so를 로딩하는 것이다. 그리고 full path를 사용하면 해당 so를 직접 로딩한다는 말이다.
그럼, loadlibrary(foo)를 호출 했을 때 Intel의 Xolo 단말기는 왜 lib/armeabi-v7a 경로에 있는 모듈을 로딩한걸까? ( lib/x86 폴더는 존재하지 않는 상태임 )
궁금증을 해결하기 위해서 일단 Java 레벨에서(NDK가 아닌) CPU 정보를 얻는 방법부터 찾아 보았다. 간단하게 Build 클래스에 정보가 있었다.
Build.CPU_ABI 를 이용하면 되는데, 보다보니 Build.CPU_ABI2가 존재 한다. 아~~ 느낌이 온다~
(참고로 ABI는 Application Binary Interface의 약자다. )
System.loadLibrary는 디바이스의 Build.CPU_ABI / Build.CPU_ABI2 의 순서로 so 모듈을 찾는 것이다. Android 의 loadLibrary 내부에서 mapLibraryName을 호출하는 부분이 아마도 이 동작을 하는 것으로 추측된다.
해결 하려면 so 파일을 x86용으로 개발해서 빌드한후 추가하면 된다. 또는 모든 기능이 x86을 지원하는 것이 아니라면 아래처럼 Java 코드로 간단하게 막을수 있다.
public static void loadLibrary() {
if (isLoaded) {
return;
}
if (isLoaded == false) {
if (Build.CPU_ABI.equals(“x86”)) {
isLoaded = false;
return;
}
try {
System.loadLibrary("foo");
isLoaded = true;
} catch (Throwable e) {
isLoaded = false;
}
}
추가로 발견한 내용으로는 프로젝트의 lib/x86 폴더에 해당 모듈이 하나라도 있으면 google play 마켓에서 x86용 디바이스에 노출이 된다는 점이다.
따라서 프로젝트가 x86을 부분적으로 지원 할 수는 없고 모든 so 모듈들을 x86으로 지원하는 것이 좋다.