[문제의 발단]
2019년 8월부터 구글 플레이에 올라가는 앱은 64비트를 대응해야 한다고 한다.
지금 서비스 하고 있는 앱의 경우, 핵심 모듈은 C++로 되어 있는데 모두 몇 년 전에 만들었던 32비트 so 를 사용하고 있었다.
그래서 예전의 C++ 소스 코드를 꺼내서 다시 64비트 so로 만드는 과정이 필요했다.
예전에는 Eclipse에서 ndkBuild로 만들었다면, 지금은 최신 Android Studio에서 새로운 NDK 빌드 방식으로 만들어야 하는 점이 달랐는데,
새로 NDK Makefile을 만드는 것도 우여곡절이 많았지만 그건 어쨌든 과정의 일부였고, 최종적으로는 NDK 빌드를 성공하고 64비트 so를 적용하여 테스트를 거친 뒤 public release를 했다.
[문제의 발생]
그런데 릴리즈가 되자마자 며칠만에 에러 보고가 날아오기 시작했는데, 다음과 같은 메시지였다.
Fatal Exception: java.lang.UnsatisfiedLinkError
dlopen failed: cannot locate symbol "__register_atfork" referenced by "lib*****.so"...
java.lang.Runtime.loadLibrary (Runtime.java:372)
java.lang.System.loadLibrary (System.java:988)
JNI 연결을 위해 so를 읽는 과정에서 특정 내부 함수를 찾을 수 없다는 에러이다.
한국의 메이저 안드로이드 제조사 것은 문제가 없어서 자체 테스트에서는 발견이 안 되었던 것이고, 화웨이, OPPO, HTC, ZET 등의 기기에서도 OS 5 버전에서만 문제가 발생했다.
[문제의 원인]
위의 에러 상황으로 검색을 해보니, 이런 버그 레포트가 올라왔고
최종 review confirm된 코드의 diff를 보면 다음과 같은 내용의 추가로 문제를 해결을 하였다.
## `__register_atfork` (Available in API level >= 23)
To allow `atfork` and `pthread_atfork` handlers to be unregistered on
`dlclose`, the implementation changed in API level 23. Unfortunately this
requires a new libc function `__register_atfork`. Code using these functions
that is built with a target API level >= 23 therefore will not load on earlier
versions of Android, with an error referencing `__register_atfork`.
*Resolution*: build your code with an NDK target API level that matches your
app's minimum API level, or avoid using `atfork`/`pthread_atfork`.
위의 패치의 결과로, 공식 매뉴얼에서 다음과 같이 추가되었으며 (글 중간에 있음)
결론적으로는, 앱의 minSDK API level과 NDK의 minSDK API level이 다른 것이 문제로 보였다.
API level 23 이후로 내부 standard so에 저러한 것들이 많이 추가가 된 모양이다.
[문제의 해결]
앱은 원래부터 minSDK를 19로 지정하고 있었지만, NDK는 이번에 발드를 위해 새로 프로젝트를 만드는 바람에 minSDK 는 현재 가장 높은 버전인 28로 맞춰져 있었다,'
그래서 NDK 빌드를 위한 프로젝트에서 app/build.gradle 를 android:defaultConfig:minSdkVersion : 28 -> 19 로 수정하여 빌드를 하였고 문제가 해결된 것을 nm으로 확인할 수 있었다.
<minSdkVersion 28일 때>
00000000001285f8 A __end__
U __errno
U __register_atfork <- 여기
U __stack_chk_fail
00000000001285f8 A _bss_end__
<minSdkVersion 19일 때>
00000000001295f8 A __end__
U __errno
U __sF
U __stack_chk_fail
00000000001295f8 A _bss_end__
arm64와 x64 모두 동일하게 문제의 심볼인 '_register_atfork' 의 dynamic refrence가 사라진 것을 확인 하였다.
Posted by 안영기