55using Backtrace . Unity . Model . Breadcrumbs ;
66using Backtrace . Unity . Runtime . Native . Base ;
77using System ;
8+ using System . Collections ;
89using System . Collections . Generic ;
910using System . Globalization ;
1011using System . IO ;
@@ -24,6 +25,9 @@ internal sealed class NativeClient : NativeClientBase, INativeClient
2425 [ DllImport ( "backtrace-native" ) ]
2526 private static extern bool Initialize ( IntPtr submissionUrl , IntPtr databasePath , IntPtr handlerPath , IntPtr keys , IntPtr values , IntPtr attachments , bool enableClientSideUnwinding , int unwindingMode ) ;
2627
28+ [ DllImport ( "backtrace-native" ) ]
29+ private static extern bool InitializeJavaCrashHandler ( IntPtr submissionUrl , IntPtr databasePath , IntPtr classPath , IntPtr keys , IntPtr values , IntPtr attachments , IntPtr environmentVariables ) ;
30+
2731 [ DllImport ( "backtrace-native" ) ]
2832 private static extern bool AddAttribute ( IntPtr key , IntPtr value ) ;
2933
@@ -75,8 +79,12 @@ private void SetDefaultAttributeMaps()
7579 _attributeMapping . Add ( "VmallocUsed" , "system.memory.vmalloc.used" ) ;
7680 _attributeMapping . Add ( "VmallocChunk" , "system.memory.vmalloc.chunk" ) ;
7781 }
78- // Android native interface paths
79- private const string _namespace = "backtrace.io.backtrace_unity_android_plugin" ;
82+
83+ // Android base native interface path
84+ private const string _baseNamespace = "backtraceio" ;
85+
86+ // Unity-Android native interface path
87+ private const string _namespace = "backtraceio.unity" ;
8088
8189 /// <summary>
8290 /// unwinding mode
@@ -93,6 +101,16 @@ private void SetDefaultAttributeMaps()
93101 /// </summary>
94102 private readonly string _unhandledExceptionPath = string . Format ( "{0}.{1}" , _namespace , "BacktraceAndroidBackgroundUnhandledExceptionHandler" ) ;
95103
104+ /// <summary>
105+ /// Path to class responsible for generating and sending native dump on crash
106+ /// </summary>
107+ private readonly string _crashHandlerPath = string . Format ( "{0}.library.nativeCalls.BacktraceCrashHandler" , _baseNamespace ) ;
108+
109+ /// <summary>
110+ /// Backtrace-Android native library name
111+ /// </summary>
112+ private readonly string _nativeLibraryName = "libbacktrace-native.so" ;
113+
96114 /// <summary>
97115 /// Determine if android integration should be enabled
98116 /// </summary>
@@ -255,37 +273,20 @@ private void HandleNativeCrashes(IDictionary<string, string> backtraceAttributes
255273 return ;
256274 }
257275
276+ var minidumpUrl = new BacktraceCredentials ( _configuration . GetValidServerUrl ( ) ) . GetMinidumpSubmissionUrl ( ) . ToString ( ) ;
277+
258278 var libDirectory = GetNativeDirectoryPath ( ) ;
259279 if ( string . IsNullOrEmpty ( libDirectory ) || ! Directory . Exists ( libDirectory ) )
260280 {
261281 libDirectory = GuessNativeDirectoryPath ( ) ;
262282 }
263- if ( ! Directory . Exists ( libDirectory ) )
264- {
265- return ;
266- }
267283 const string crashpadHandlerName = "libcrashpad_handler.so" ;
268284 var crashpadHandlerPath = Path . Combine ( libDirectory , crashpadHandlerName ) ;
269285
270- if ( string . IsNullOrEmpty ( crashpadHandlerPath ) || ! File . Exists ( crashpadHandlerPath ) )
271- {
272- Debug . LogWarning ( "Backtrace native integration status: Cannot find crashpad library" ) ;
273- return ;
274- }
275-
276- var minidumpUrl = new BacktraceCredentials ( _configuration . GetValidServerUrl ( ) ) . GetMinidumpSubmissionUrl ( ) . ToString ( ) ;
286+ CaptureNativeCrashes = CanInitializeExecutableCrashHandler ( libDirectory , crashpadHandlerPath )
287+ ? InitializeExecutableCrashHandler ( minidumpUrl , databasePath , crashpadHandlerPath , attachments )
288+ : InitializeJavaCrashHandler ( minidumpUrl , databasePath , backtraceAttributes [ "device.abi" ] , libDirectory , attachments ) ;
277289
278- // reassign to captureNativeCrashes
279- // to avoid doing anything on crashpad binary, when crashpad isn't available
280- CaptureNativeCrashes = Initialize (
281- AndroidJNI . NewStringUTF ( minidumpUrl ) ,
282- AndroidJNI . NewStringUTF ( databasePath ) ,
283- AndroidJNI . NewStringUTF ( crashpadHandlerPath ) ,
284- AndroidJNIHelper . ConvertToJNIArray ( new string [ 0 ] ) ,
285- AndroidJNIHelper . ConvertToJNIArray ( new string [ 0 ] ) ,
286- AndroidJNIHelper . ConvertToJNIArray ( attachments . ToArray ( ) ) ,
287- _enableClientSideUnwinding ,
288- ( int ) UnwindingMode ) ;
289290 if ( ! CaptureNativeCrashes )
290291 {
291292 Debug . LogWarning ( "Backtrace native integration status: Cannot initialize Crashpad client" ) ;
@@ -309,6 +310,71 @@ private void HandleNativeCrashes(IDictionary<string, string> backtraceAttributes
309310 AndroidJNI . NewStringUTF ( CrashType ) ) ;
310311 }
311312
313+ private bool CanInitializeExecutableCrashHandler ( String nativeLibraryDirectory , String handlerPath ) {
314+ return Directory . Exists ( nativeLibraryDirectory ) && File . Exists ( handlerPath ) ;
315+ }
316+
317+ private bool InitializeExecutableCrashHandler ( String minidumpUrl , String databasePath , String crashpadHandlerPath , IEnumerable < String > attachments ) {
318+ return Initialize (
319+ AndroidJNI . NewStringUTF ( minidumpUrl ) ,
320+ AndroidJNI . NewStringUTF ( databasePath ) ,
321+ AndroidJNI . NewStringUTF ( crashpadHandlerPath ) ,
322+ AndroidJNIHelper . ConvertToJNIArray ( new string [ 0 ] ) ,
323+ AndroidJNIHelper . ConvertToJNIArray ( new string [ 0 ] ) ,
324+ AndroidJNIHelper . ConvertToJNIArray ( attachments . ToArray ( ) ) ,
325+ _enableClientSideUnwinding ,
326+ ( int ) UnwindingMode ) ;
327+ }
328+
329+ private bool InitializeJavaCrashHandler ( String minidumpUrl , String databasePath , String deviceAbi , String nativeDirectory , IEnumerable < String > attachments ) {
330+ if ( String . IsNullOrEmpty ( deviceAbi ) ) {
331+ Debug . LogWarning ( "Cannot determine device ABI" ) ;
332+ return false ;
333+ }
334+
335+ var envVariableDictionary = Environment . GetEnvironmentVariables ( ) ;
336+ if ( envVariableDictionary == null ) {
337+ Debug . LogWarning ( "Environment variables are not defined." ) ;
338+ return false ;
339+ }
340+
341+ // verify if the library is already extracted
342+ var backtraceNativeLibraryPath = Path . Combine ( nativeDirectory , _nativeLibraryName ) ;
343+ if ( ! File . Exists ( backtraceNativeLibraryPath ) ) {
344+ backtraceNativeLibraryPath = string . Format ( "{0}!/lib/{1}/{2}" , Application . dataPath , deviceAbi , _nativeLibraryName ) ;
345+ }
346+
347+ // prepare native crash handler environment variables
348+ List < String > environmentVariables = new List < string > ( ) {
349+ string . Format ( "CLASSPATH={0}" , Application . dataPath ) ,
350+ string . Format ( "BACKTRACE_UNITY_CRASH_HANDLER={0}" , backtraceNativeLibraryPath ) ,
351+ string . Format ( "LD_LIBRARY_PATH={0}" , string . Join ( ":" , nativeDirectory , Directory . GetParent ( nativeDirectory ) , GetLibrarySystemPath ( ) , "/data/local" ) ) ,
352+ "ANDROID_DATA=/data"
353+ } ;
354+
355+ foreach ( DictionaryEntry kvp in envVariableDictionary ) {
356+ environmentVariables . Add ( string . Format ( "{0}={1}" , kvp . Key , kvp . Value == null ? "NULL" : kvp . Value ) ) ;
357+ }
358+
359+
360+ return InitializeJavaCrashHandler (
361+ AndroidJNI . NewStringUTF ( minidumpUrl ) ,
362+ AndroidJNI . NewStringUTF ( databasePath ) ,
363+ AndroidJNI . NewStringUTF ( _crashHandlerPath ) ,
364+ AndroidJNIHelper . ConvertToJNIArray ( new string [ 0 ] ) ,
365+ AndroidJNIHelper . ConvertToJNIArray ( new string [ 0 ] ) ,
366+ AndroidJNIHelper . ConvertToJNIArray ( attachments . ToArray ( ) ) ,
367+ AndroidJNIHelper . ConvertToJNIArray ( environmentVariables . ToArray ( ) )
368+ ) ;
369+ }
370+
371+ private string GetLibrarySystemPath ( ) {
372+ using ( var systemClass = new AndroidJavaClass ( "java.lang.System" ) )
373+ {
374+ return systemClass . CallStatic < string > ( "getProperty" , "java.library.path" ) ;
375+ }
376+ }
377+
312378 /// <summary>
313379 /// Retrieve Backtrace Attributes from the Android native code.
314380 /// </summary>
0 commit comments