Symptoms:
- You get an Android crash log from your users.
- You can’t understand the call stack as it only reports memory addresses.
Cause:
When you build in release mode, the symbols are not packed with the APK. If your app crashes, the call stack will only show the memory address.
Resolution:
You can find the Android symbols here:
Mono scripting backend:
- For MacOS:
- /Applications/Unity/PlaybackEngines/AndroidPlayer/Variations/mono/Release/Symbols
- For Windows:
- C:\Program Files\Unity\Editor\Data\PlaybackEngines\AndroidPlayer\Variations\mono\Release\Symbols\armeabi-v7a\libunity.sym.so
IL2CPP scripting backend:
There are two possible library files to use here:
- Il2cpp.so: this file is generated when you build your project and is located in the symbols.zip file that is created next to the APK, abb, or Gradle project.
- libunity.so: this file is located in the Unity installation folder:
- <installation Folder>/PlaybackEngines/AndroidPlayer/Variations/il2cpp/Development/Symbols
You have to use the symbols for the same architecture as the device where the call stack is taken: ARM64-v8a, ARMEABI-v7a, or x86 (which is already deprecated).
When you build using IL2CPP, if the Strip Engine Code option is enabled, Unity creates a new libunity.so that it is different from the installation folder, so you need to use this for the symbolization.
From unity 2019.2 onwards, you can use the Android log cat package to help you in the symbolization process. A guide can be found here: Android Logcat: Stacktrace Utility.
You can follow the instructions in the next section to manually resolve the stack trace.
You can use the addr2line tool and the symbols file to convert the memory addresses into function names and create a call stack.
For example, let's say you have the following crash log:
05-26 18:06:51.311: A/libc(26986): Fatal signal 11 (SIGSEGV) at 0x000004e4 (code=1), thread 27024 (Worker Thread) 05-26 18:06:51.411: I/DEBUG(242): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 05-26 18:06:51.411: I/DEBUG(242): Build fingerprint: 'Xiaomi/cancro_wc_lte/cancro:4.4.4/KTU84P/V6.7.1.0.KXDCNCH:user/release-keys' 05-26 18:06:51.411: I/DEBUG(242): Revision: '0' 05-26 18:06:51.411: I/DEBUG(242): pid: 26986, tid: 27024, name: Worker Thread >>> com.u.demo <<< 05-26 18:06:51.411: I/DEBUG(242): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 000004e4 I/DEBUG(242): backtrace: I/DEBUG(242): #00 pc 006d4960 /data/app-lib/com.u.demo-1/libunity.so I/DEBUG(242): #01 pc 006d4c0c /data/app-lib/com.u.demo-1/libunity.so I/DEBUG(242): #02 pc 006d4c0c /data/app-lib/com.u.demo-1/libunity.so I/DEBUG(242): #03 pc 006d4c0c /data/app-lib/com.u.demo-1/libunity.so I/DEBUG(242): #04 pc 006d4c0c /data/app-lib/com.u.demo-1/libunity.so I/DEBUG(242): #05 pc 001c5510 /data/app-lib/com.u.demo-1/libunity.so I/DEBUG(242): #06 pc 001c595c /data/app-lib/com.u.demo-1/libunity.so I/DEBUG(242): #07 pc 001c4ec0 /data/app-lib/com.u.demo-1/libunity.so I/DEBUG(242): #08 pc 0043a05c /data/app-lib/com.u.demo-1/libunity.so I/DEBUG(242): #09 pc 0000d248 /system/lib/libc.so (__thread_entry+72) I/DEBUG(242): #10 pc 0000d3e0 /system/lib/libc.so (pthread_create+240)
In the above call stack, the bold numbers (such as 006d4960) are the memory addresses of the functions that were executing when the crash happened, and at the end of the line is the library used (libunity.so in this instance).
You can get the symbol from each memory addresses by executing the addr2line tool on each memory address:
> ./arm-linux-androideabi-addr2line -f -C -e /Applications/Unity.app/Content/PlaybackEngines/AndroidPlayer/Variations/mono/Release/Symbols/armeabi-v7a/libunity.sym.so 0043a05c
- -f - Show function names
- -C - Demangle function names
- -e - Set the input file name
After you execute the command with each memory address, you get the proper call stack when the app crashed:
I/DEBUG(242): backtrace: I/DEBUG(242): #00 AnimationPlayable::PrepareAnimationEvents(float, dynamic_array<AnimationClipEventInfo, 4u>&) I/DEBUG(242): #01 AnimationPlayable::PrepareAnimationEvents(float, dynamic_array<AnimationClipEventInfo, 4u>&) I/DEBUG(242): #02 AnimationPlayable::PrepareAnimationEvents(float, dynamic_array<AnimationClipEventInfo, 4u>&) I/DEBUG(242): #03 AnimationPlayable::PrepareAnimationEvents(float, dynamic_array<AnimationClipEventInfo, 4u>&) I/DEBUG(242): #04 AnimationPlayable::PrepareAnimationEvents(float, dynamic_array<AnimationClipEventInfo, 4u>&) I/DEBUG(242): #05 JobQueue::ExecuteJobFunc(JobInfo*) I/DEBUG(242): #06 JobQueue::ExecuteJobFromHighPriorityStack() I/DEBUG(242): #07 JobQueue::WorkLoop(void*) I/DEBUG(242): #08 Thread::RunThreadWrapper(void*) 18:06:51.501: I/DEBUG(242): #09 pc 0000d248 /system/lib/libc.so (__thread_entry+72) I/DEBUG(242): #10 pc 0000d3e0 /system/lib/libc.so (pthread_create+240)
In this case, we can read the call stack properly and detect that the crash happened due to animation events. This information is useful for a number of purposes, including:
- Creating a bug report.
- Reviewing patch releases for a possible fix.
- Reviewing the code for a possible issue.
You can find the addr2line tool in your Android NDK at the following address:
/android-ndk_auto-r10e/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-addr2line
Important: Always use the symbols from the same version of the Editor from which you built the APK, otherwise you will get the wrong values.
ARM 64
If the symbols line looks like this one /lib/arm64/libunity.so, it means the build was created for Android 64 bits. In this case you should use the android-addr2line for 64 bits, aarch64-linux-android-addr2line and the symbols for 64bits, for example :
./aarch64-linux-android-addr2line -f -C -e /Downloads/build/releasableartifacts/android/Variations/il2cpp/Release/Symbols/arm64-v8a/libunity.dbg.so 0000000000310e04
libil2cpp symbols
If the build was made with IL2CPP and the symbols line looks like this: lib/arm64/libil2cpp.so, you should use the libil2cpp.sym.so file inside the symbols.zip. In case of ARM 64, it’s under symbols/arm64-v8a/libil2cpp.sym.so. The symbols.zip file is generated in the same directory as your build.
./aarch64-linux-android-addr2line -f -C -e <Path_Symbols.zip>/symbols/arm64-v8a/libil2cpp.sym.so 0000000000310e04
More Information:
For more information, consult the following documentation: