38
38
public class ThreadDumpParser {
39
39
private static final Pattern BEGIN_MANAGED_THREAD_RE =
40
40
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
+
41
45
private static final Pattern NATIVE_RE =
42
46
Pattern .compile (
43
- " (?:native: )?#\\ d+ \\ S+ [0-9a-fA-F]+\\ s+(.*?)\\ s+\\ ((.*)\\ +(\\ d+)\\ )(?: \\ (.*\\ ))?" );
47
+ " * (?:native: )?#\\ d+ \\ S+ [0-9a-fA-F]+\\ s+(.*?)\\ s+\\ ((.*)\\ +(\\ d+)\\ )(?: \\ (.*\\ ))?" );
44
48
private static final Pattern NATIVE_NO_LOC_RE =
45
49
Pattern .compile (
46
- " (?:native: )?#\\ d+ \\ S+ [0-9a-fA-F]+\\ s+(.*)\\ s*\\ (?(.*)\\ )?(?: \\ (.*\\ ))?" );
50
+ " * (?:native: )?#\\ d+ \\ S+ [0-9a-fA-F]+\\ s+(.*)\\ s*\\ (?(.*)\\ )?(?: \\ (.*\\ ))?" );
47
51
private static final Pattern JAVA_RE =
48
- Pattern .compile (" at (?:(.+)\\ .)?([^.]+)\\ .([^.]+)\\ ((.*):([\\ d-]+)\\ )" );
52
+ Pattern .compile (" * at (?:(.+)\\ .)?([^.]+)\\ .([^.]+)\\ ((.*):([\\ d-]+)\\ )" );
49
53
private static final Pattern JNI_RE =
50
- Pattern .compile (" at (?:(.+)\\ .)?([^.]+)\\ .([^.]+)\\ (Native method\\ )" );
54
+ Pattern .compile (" * at (?:(.+)\\ .)?([^.]+)\\ .([^.]+)\\ (Native method\\ )" );
51
55
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 (?:(.+)\\ .)?([^.]+)\\ )" );
53
57
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 (?:(.+)\\ .)?([^.]+)\\ )" );
55
59
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 (?:(.+)\\ .)?([^.]+)\\ )" );
57
61
private static final Pattern WAITING_TO_LOCK_RE =
58
62
Pattern .compile (
59
- " - waiting to lock \\ <([0x0-9a-fA-F]{1,16})\\ > \\ (a (?:(.+)\\ .)?([^.]+)\\ )" );
63
+ " * - waiting to lock \\ <([0x0-9a-fA-F]{1,16})\\ > \\ (a (?:(.+)\\ .)?([^.]+)\\ )" );
60
64
private static final Pattern WAITING_TO_LOCK_HELD_RE =
61
65
Pattern .compile (
62
- " - waiting to lock \\ <([0x0-9a-fA-F]{1,16})\\ > \\ (a (?:(.+)\\ .)?([^.]+)\\ )"
66
+ " * - waiting to lock \\ <([0x0-9a-fA-F]{1,16})\\ > \\ (a (?:(.+)\\ .)?([^.]+)\\ )"
63
67
+ "(?: held by thread (\\ d+))" );
64
68
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" );
66
70
private static final Pattern BLANK_RE = Pattern .compile ("\\ s+" );
67
71
68
72
private final @ NotNull SentryOptions options ;
@@ -82,6 +86,7 @@ public List<SentryThread> parse(final @NotNull Lines lines) {
82
86
final List <SentryThread > sentryThreads = new ArrayList <>();
83
87
84
88
final Matcher beginManagedThreadRe = BEGIN_MANAGED_THREAD_RE .matcher ("" );
89
+ final Matcher beginUnmanagedNativeThreadRe = BEGIN_UNMANAGED_NATIVE_THREAD_RE .matcher ("" );
85
90
86
91
while (lines .hasNext ()) {
87
92
final Line line = lines .next ();
@@ -92,7 +97,7 @@ public List<SentryThread> parse(final @NotNull Lines lines) {
92
97
final String text = line .text ;
93
98
// we only handle managed threads, as unmanaged/not attached do not have the thread id and
94
99
// our protocol does not support this case
95
- if (matches (beginManagedThreadRe , text )) {
100
+ if (matches (beginManagedThreadRe , text ) || matches ( beginUnmanagedNativeThreadRe , text ) ) {
96
101
lines .rewind ();
97
102
98
103
final SentryThread thread = parseThread (lines );
@@ -108,6 +113,7 @@ private SentryThread parseThread(final @NotNull Lines lines) {
108
113
final SentryThread sentryThread = new SentryThread ();
109
114
110
115
final Matcher beginManagedThreadRe = BEGIN_MANAGED_THREAD_RE .matcher ("" );
116
+ final Matcher beginUnmanagedNativeThreadRe = BEGIN_UNMANAGED_NATIVE_THREAD_RE .matcher ("" );
111
117
112
118
// thread attributes
113
119
if (!lines .hasNext ()) {
@@ -137,14 +143,24 @@ private SentryThread parseThread(final @NotNull Lines lines) {
137
143
sentryThread .setState (state );
138
144
}
139
145
}
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 ;
147
152
}
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 );
148
164
}
149
165
150
166
// thread stacktrace
0 commit comments