@@ -33,6 +33,20 @@ public class TombstoneParser implements Closeable {
3333 @ Nullable private final String nativeLibraryDir ;
3434 private final Map <String , String > excTypeValueMap = new HashMap <>();
3535
36+ private static boolean isJavaFrame (@ NonNull final TombstoneProtos .BacktraceFrame frame ) {
37+ final String fileName = frame .getFileName ();
38+ return !fileName .endsWith (".so" )
39+ && !fileName .endsWith ("app_process64" )
40+ && (fileName .endsWith (".jar" )
41+ || fileName .endsWith (".odex" )
42+ || fileName .endsWith (".vdex" )
43+ || fileName .endsWith (".oat" )
44+ || fileName .startsWith ("[anon:dalvik-" )
45+ || fileName .startsWith ("<anonymous:" )
46+ || fileName .startsWith ("[anon_shmem:dalvik-" )
47+ || fileName .startsWith ("/memfd:jit-cache" ));
48+ }
49+
3650 private static String formatHex (long value ) {
3751 return String .format ("0x%x" , value );
3852 }
@@ -108,7 +122,8 @@ private SentryStackTrace createStackTrace(@NonNull final TombstoneProtos.Thread
108122 final List <SentryStackFrame > frames = new ArrayList <>();
109123
110124 for (TombstoneProtos .BacktraceFrame frame : thread .getCurrentBacktraceList ()) {
111- if (frame .getFileName ().endsWith ("libart.so" )) {
125+ if (frame .getFileName ().endsWith ("libart.so" )
126+ || Objects .equals (frame .getFunctionName (), "art_jni_trampoline" )) {
112127 // We ignore all ART frames for time being because they aren't actionable for app developers
113128 continue ;
114129 }
@@ -118,9 +133,15 @@ private SentryStackTrace createStackTrace(@NonNull final TombstoneProtos.Thread
118133 continue ;
119134 }
120135 final SentryStackFrame stackFrame = new SentryStackFrame ();
121- stackFrame .setPackage (frame .getFileName ());
122- stackFrame .setFunction (frame .getFunctionName ());
123- stackFrame .setInstructionAddr (formatHex (frame .getPc ()));
136+ if (isJavaFrame (frame )) {
137+ stackFrame .setPlatform ("java" );
138+ stackFrame .setFunction (extractJavaFunctionName (frame .getFunctionName ()));
139+ stackFrame .setModule (extractJavaModuleName (frame .getFunctionName ()));
140+ } else {
141+ stackFrame .setPackage (frame .getFileName ());
142+ stackFrame .setFunction (frame .getFunctionName ());
143+ stackFrame .setInstructionAddr (formatHex (frame .getPc ()));
144+ }
124145
125146 // inAppIncludes/inAppExcludes filter by Java/Kotlin package names, which don't overlap
126147 // with native C/C++ function names (e.g., "crash", "__libc_init"). For native frames,
@@ -159,6 +180,22 @@ private SentryStackTrace createStackTrace(@NonNull final TombstoneProtos.Thread
159180 return stacktrace ;
160181 }
161182
183+ private static @ Nullable String extractJavaModuleName (String fqFunctionName ) {
184+ if (fqFunctionName .contains ("." )) {
185+ return fqFunctionName .substring (0 , fqFunctionName .lastIndexOf ("." ));
186+ } else {
187+ return "" ;
188+ }
189+ }
190+
191+ private static @ Nullable String extractJavaFunctionName (String fqFunctionName ) {
192+ if (fqFunctionName .contains ("." )) {
193+ return fqFunctionName .substring (fqFunctionName .lastIndexOf ("." ) + 1 );
194+ } else {
195+ return fqFunctionName ;
196+ }
197+ }
198+
162199 @ NonNull
163200 private List <SentryException > createException (@ NonNull TombstoneProtos .Tombstone tombstone ) {
164201 final SentryException exception = new SentryException ();
@@ -296,7 +333,7 @@ private DebugMeta createDebugMeta(@NonNull final TombstoneProtos.Tombstone tombs
296333 // Check for duplicated mappings: On Android, the same ELF can have multiple
297334 // mappings at offset 0 with different permissions (r--p, r-xp, r--p).
298335 // If it's the same file as the current module, just extend it.
299- if (currentModule != null && mappingName .equals (currentModule .mappingName )) {
336+ if (currentModule != null && Objects .equals (mappingName , currentModule .mappingName )) {
300337 currentModule .extendTo (mapping .getEndAddress ());
301338 continue ;
302339 }
@@ -311,7 +348,7 @@ private DebugMeta createDebugMeta(@NonNull final TombstoneProtos.Tombstone tombs
311348
312349 // Start a new module
313350 currentModule = new ModuleAccumulator (mapping );
314- } else if (currentModule != null && mappingName .equals (currentModule .mappingName )) {
351+ } else if (currentModule != null && Objects .equals (mappingName , currentModule .mappingName )) {
315352 // Extend the current module with this mapping (same file, continuation)
316353 currentModule .extendTo (mapping .getEndAddress ());
317354 }
0 commit comments