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