3838public class ThreadDumpParser {
3939 private static final Pattern BEGIN_MANAGED_THREAD_RE =
4040 Pattern .compile ("\" (.*)\" (.*) ?prio=(\\ d+)\\ s+tid=(\\ d+)\\ s*(.*)" );
41+
42+ private static final Pattern BEGIN_UNMANAGED_NATIVE_THREAD_RE =
43+ Pattern .compile ("\" (.*)\" (.*) ?sysTid=(\\ d+)" );
44+
4145 private static final Pattern NATIVE_RE =
4246 Pattern .compile (
43- " (?:native: )?#\\ d+ \\ S+ [0-9a-fA-F]+\\ s+(.*?)\\ s+\\ ((.*)\\ +(\\ d+)\\ )(?: \\ (.*\\ ))?" );
47+ " * (?:native: )?#\\ d+ \\ S+ [0-9a-fA-F]+\\ s+(.*?)\\ s+\\ ((.*)\\ +(\\ d+)\\ )(?: \\ (.*\\ ))?" );
4448 private static final Pattern NATIVE_NO_LOC_RE =
4549 Pattern .compile (
46- " (?:native: )?#\\ d+ \\ S+ [0-9a-fA-F]+\\ s+(.*)\\ s*\\ (?(.*)\\ )?(?: \\ (.*\\ ))?" );
50+ " * (?:native: )?#\\ d+ \\ S+ [0-9a-fA-F]+\\ s+(.*)\\ s*\\ (?(.*)\\ )?(?: \\ (.*\\ ))?" );
4751 private static final Pattern JAVA_RE =
48- Pattern .compile (" at (?:(.+)\\ .)?([^.]+)\\ .([^.]+)\\ ((.*):([\\ d-]+)\\ )" );
52+ Pattern .compile (" * at (?:(.+)\\ .)?([^.]+)\\ .([^.]+)\\ ((.*):([\\ d-]+)\\ )" );
4953 private static final Pattern JNI_RE =
50- Pattern .compile (" at (?:(.+)\\ .)?([^.]+)\\ .([^.]+)\\ (Native method\\ )" );
54+ Pattern .compile (" * at (?:(.+)\\ .)?([^.]+)\\ .([^.]+)\\ (Native method\\ )" );
5155 private static final Pattern LOCKED_RE =
52- Pattern .compile (" - locked \\ <([0x0-9a-fA-F]{1,16})\\ > \\ (a (?:(.+)\\ .)?([^.]+)\\ )" );
56+ Pattern .compile (" * - locked \\ <([0x0-9a-fA-F]{1,16})\\ > \\ (a (?:(.+)\\ .)?([^.]+)\\ )" );
5357 private static final Pattern SLEEPING_ON_RE =
54- Pattern .compile (" - sleeping on \\ <([0x0-9a-fA-F]{1,16})\\ > \\ (a (?:(.+)\\ .)?([^.]+)\\ )" );
58+ Pattern .compile (" * - sleeping on \\ <([0x0-9a-fA-F]{1,16})\\ > \\ (a (?:(.+)\\ .)?([^.]+)\\ )" );
5559 private static final Pattern WAITING_ON_RE =
56- Pattern .compile (" - waiting on \\ <([0x0-9a-fA-F]{1,16})\\ > \\ (a (?:(.+)\\ .)?([^.]+)\\ )" );
60+ Pattern .compile (" * - waiting on \\ <([0x0-9a-fA-F]{1,16})\\ > \\ (a (?:(.+)\\ .)?([^.]+)\\ )" );
5761 private static final Pattern WAITING_TO_LOCK_RE =
5862 Pattern .compile (
59- " - waiting to lock \\ <([0x0-9a-fA-F]{1,16})\\ > \\ (a (?:(.+)\\ .)?([^.]+)\\ )" );
63+ " * - waiting to lock \\ <([0x0-9a-fA-F]{1,16})\\ > \\ (a (?:(.+)\\ .)?([^.]+)\\ )" );
6064 private static final Pattern WAITING_TO_LOCK_HELD_RE =
6165 Pattern .compile (
62- " - waiting to lock \\ <([0x0-9a-fA-F]{1,16})\\ > \\ (a (?:(.+)\\ .)?([^.]+)\\ )"
66+ " * - waiting to lock \\ <([0x0-9a-fA-F]{1,16})\\ > \\ (a (?:(.+)\\ .)?([^.]+)\\ )"
6367 + "(?: held by thread (\\ d+))" );
6468 private static final Pattern WAITING_TO_LOCK_UNKNOWN_RE =
65- Pattern .compile (" - waiting to lock an unknown object" );
69+ Pattern .compile (" * - waiting to lock an unknown object" );
6670 private static final Pattern BLANK_RE = Pattern .compile ("\\ s+" );
6771
6872 private final @ NotNull SentryOptions options ;
@@ -82,6 +86,7 @@ public List<SentryThread> parse(final @NotNull Lines lines) {
8286 final List <SentryThread > sentryThreads = new ArrayList <>();
8387
8488 final Matcher beginManagedThreadRe = BEGIN_MANAGED_THREAD_RE .matcher ("" );
89+ final Matcher beginUnmanagedNativeThreadRe = BEGIN_UNMANAGED_NATIVE_THREAD_RE .matcher ("" );
8590
8691 while (lines .hasNext ()) {
8792 final Line line = lines .next ();
@@ -92,7 +97,7 @@ public List<SentryThread> parse(final @NotNull Lines lines) {
9297 final String text = line .text ;
9398 // we only handle managed threads, as unmanaged/not attached do not have the thread id and
9499 // our protocol does not support this case
95- if (matches (beginManagedThreadRe , text )) {
100+ if (matches (beginManagedThreadRe , text ) || matches ( beginUnmanagedNativeThreadRe , text ) ) {
96101 lines .rewind ();
97102
98103 final SentryThread thread = parseThread (lines );
@@ -108,6 +113,7 @@ private SentryThread parseThread(final @NotNull Lines lines) {
108113 final SentryThread sentryThread = new SentryThread ();
109114
110115 final Matcher beginManagedThreadRe = BEGIN_MANAGED_THREAD_RE .matcher ("" );
116+ final Matcher beginUnmanagedNativeThreadRe = BEGIN_UNMANAGED_NATIVE_THREAD_RE .matcher ("" );
111117
112118 // thread attributes
113119 if (!lines .hasNext ()) {
@@ -137,14 +143,24 @@ private SentryThread parseThread(final @NotNull Lines lines) {
137143 sentryThread .setState (state );
138144 }
139145 }
140- final String threadName = sentryThread .getName ();
141- if (threadName != null ) {
142- final boolean isMain = threadName .equals ("main" );
143- sentryThread .setMain (isMain );
144- // since it's an ANR, the crashed thread will always be main
145- sentryThread .setCrashed (isMain );
146- sentryThread .setCurrent (isMain && !isBackground );
146+ } else if (matches (beginUnmanagedNativeThreadRe , line .text )) {
147+ final Long sysTid = getLong (beginUnmanagedNativeThreadRe , 3 , null );
148+ if (sysTid == null ) {
149+ options .getLogger ().log (SentryLevel .DEBUG , "No thread id in the dump, skipping thread." );
150+ // tid is required by our protocol
151+ return null ;
147152 }
153+ sentryThread .setId (sysTid );
154+ sentryThread .setName (beginUnmanagedNativeThreadRe .group (1 ));
155+ }
156+
157+ final String threadName = sentryThread .getName ();
158+ if (threadName != null ) {
159+ final boolean isMain = threadName .equals ("main" );
160+ sentryThread .setMain (isMain );
161+ // since it's an ANR, the crashed thread will always be main
162+ sentryThread .setCrashed (isMain );
163+ sentryThread .setCurrent (isMain && !isBackground );
148164 }
149165
150166 // thread stacktrace
0 commit comments