1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.bugreport.stacks; 18 19 import com.android.bugreport.util.Line; 20 import com.android.bugreport.util.Lines; 21 import com.android.bugreport.util.Utils; 22 23 import java.io.BufferedReader; 24 import java.io.IOException; 25 import java.util.ArrayList; 26 import java.util.regex.Pattern; 27 import java.util.regex.Matcher; 28 29 /** 30 * Parse a vm traces thread. 31 * 32 * The parser can be reused, but is not thread safe. 33 */ 34 public class ThreadSnapshotParser { 35 public static final Pattern BEGIN_UNMANAGED_THREAD_RE = Pattern.compile( 36 "\"(.*)\" sysTid=(\\d+)(.*)"); 37 public static final Pattern BEGIN_MANAGED_THREAD_RE = Pattern.compile( 38 "\"(.*)\" (.*) ?prio=(\\d+)\\s+tid=(\\d+)\\s*(.*)"); 39 public static final Pattern BEGIN_NOT_ATTACHED_THREAD_RE = Pattern.compile( 40 "\"(.*)\" (.*) ?prio=(\\d+)\\s+(\\(not attached\\))"); 41 42 public static final Pattern ATTR_RE = Pattern.compile( 43 " \\| (.*)"); 44 public static final Pattern HELD_MUTEXES_RE = Pattern.compile( 45 " \\| (held mutexes=\\s*(.*))"); 46 public static final Pattern NATIVE_RE = Pattern.compile( 47 " (?:native: )?#\\d+ \\S+ [0-9a-fA-F]+\\s+(.*)\\s+\\((.*)\\+(\\d+)\\)"); 48 public static final Pattern NATIVE_NO_LOC_RE = Pattern.compile( 49 " (?:native: )?#\\d+ \\S+ [0-9a-fA-F]+\\s+(.*)\\s*\\(?(.*)\\)?"); 50 public static final Pattern KERNEL_RE = Pattern.compile( 51 " kernel: (.*)\\+0x([0-9a-fA-F]+)/0x([0-9a-fA-F]+)"); 52 public static final Pattern KERNEL_UNKNOWN_RE = Pattern.compile( 53 " kernel: \\(couldn't read /proc/self/task/\\d+/stack\\)"); 54 public static final Pattern JAVA_RE = Pattern.compile( 55 " at (?:(.+)\\.)?([^.]+)\\.([^.]+)\\((.*):([\\d-]+)\\)"); 56 public static final Pattern JNI_RE = Pattern.compile( 57 " at (?:(.+)\\.)?([^.]+)\\.([^.]+)\\(Native method\\)"); 58 public static final Pattern LOCKED_RE = Pattern.compile( 59 " - locked \\<0x([0-9a-fA-F]{1,16})\\> \\(a (?:(.+)\\.)?([^.]+)\\)"); 60 public static final Pattern SLEEPING_ON_RE = Pattern.compile( 61 " - sleeping on \\<0x([0-9a-fA-F]{1,16})\\> \\(a (?:(.+)\\.)?([^.]+)\\)"); 62 public static final Pattern WAITING_ON_RE = Pattern.compile( 63 " - waiting on \\<0x([0-9a-fA-F]{1,16})\\> \\(a (?:(.+)\\.)?([^.]+)\\)"); 64 public static final Pattern WAITING_TO_LOCK_RE = Pattern.compile( 65 " - waiting to lock \\<0x([0-9a-fA-F]{1,16})\\> \\(a (?:(.+)\\.)?([^.]+)\\)"); 66 public static final Pattern WAITING_TO_LOCK_HELD_RE = Pattern.compile( 67 " - waiting to lock \\<0x([0-9a-fA-F]{1,16})\\> \\(a (?:(.+)\\.)?([^.]+)\\)" 68 + "(?: held by thread (\\d+))"); 69 public static final Pattern WAITING_TO_LOCK_UNKNOWN_RE = Pattern.compile( 70 " - waiting to lock an unknown object"); 71 public static final Pattern NO_MANAGED_STACK_FRAME_RE = Pattern.compile( 72 " (\\(no managed stack frames\\))"); 73 private static final Pattern BLANK_RE 74 = Pattern.compile("\\s+"); 75 76 public static final Pattern SYS_TID_ATTR_RE = Pattern.compile( 77 " \\| sysTid=(\\d+) .*"); 78 public static final Pattern STATE_ATTR_RE = Pattern.compile( 79 " \\| state=R .*"); 80 81 /** 82 * Construct a new parser. 83 */ ThreadSnapshotParser()84 public ThreadSnapshotParser() { 85 } 86 87 /** 88 * Parse the given Lines until the first blank line, which signals the 89 * end of the thread. Return a ThreadSnapshot object or null if there wasn't 90 * enough text to parse. 91 */ parse(Lines<? extends Line> lines)92 public ThreadSnapshot parse(Lines<? extends Line> lines) { 93 final ThreadSnapshot result = new ThreadSnapshot(); 94 JavaStackFrameSnapshot lastJava = null; 95 96 final Matcher beginUnmanagedThreadRe = BEGIN_UNMANAGED_THREAD_RE.matcher(""); 97 final Matcher beginManagedThreadRe = BEGIN_MANAGED_THREAD_RE.matcher(""); 98 final Matcher beginNotAttachedThreadRe = BEGIN_NOT_ATTACHED_THREAD_RE.matcher(""); 99 final Matcher attrRe = ATTR_RE.matcher(""); 100 final Matcher heldMutexesRe = HELD_MUTEXES_RE.matcher(""); 101 final Matcher nativeRe = NATIVE_RE.matcher(""); 102 final Matcher nativeNoLocRe = NATIVE_NO_LOC_RE.matcher(""); 103 final Matcher kernelRe = KERNEL_RE.matcher(""); 104 final Matcher kernelUnknownRe = KERNEL_UNKNOWN_RE.matcher(""); 105 final Matcher javaRe = JAVA_RE.matcher(""); 106 final Matcher jniRe = JNI_RE.matcher(""); 107 final Matcher lockedRe = LOCKED_RE.matcher(""); 108 final Matcher waitingOnRe = WAITING_ON_RE.matcher(""); 109 final Matcher sleepingOnRe = SLEEPING_ON_RE.matcher(""); 110 final Matcher waitingToLockHeldRe = WAITING_TO_LOCK_HELD_RE.matcher(""); 111 final Matcher waitingToLockRe = WAITING_TO_LOCK_RE.matcher(""); 112 final Matcher waitingToLockUnknownRe = WAITING_TO_LOCK_UNKNOWN_RE.matcher(""); 113 final Matcher noManagedStackFrameRe = NO_MANAGED_STACK_FRAME_RE.matcher(""); 114 final Matcher blankRe = BLANK_RE.matcher(""); 115 116 final Matcher sysTidAttrRe = SYS_TID_ATTR_RE.matcher(""); 117 final Matcher stateAttrRe = STATE_ATTR_RE.matcher(""); 118 119 120 Line line; 121 String text; 122 123 // First Line 124 if (!lines.hasNext()) { 125 // TODO: Handle errors. 126 return null; 127 } 128 line = lines.next(); 129 if (Utils.matches(beginUnmanagedThreadRe, line.text)) { 130 result.type = ThreadSnapshot.TYPE_UNMANAGED; 131 result.name = beginUnmanagedThreadRe.group(1); 132 result.priority = -1; 133 result.tid = -1; 134 result.sysTid = Integer.parseInt(beginUnmanagedThreadRe.group(2)); 135 } else if (Utils.matches(beginManagedThreadRe, line.text)) { 136 result.type = ThreadSnapshot.TYPE_MANAGED; 137 result.name = beginManagedThreadRe.group(1); 138 result.daemon = beginManagedThreadRe.group(2); 139 result.priority = Utils.getInt(beginManagedThreadRe, 3, -1); 140 result.tid = Utils.getInt(beginManagedThreadRe, 4, -1); 141 result.vmState = beginManagedThreadRe.group(5); 142 } else if (Utils.matches(beginNotAttachedThreadRe, line.text)) { 143 result.type = ThreadSnapshot.TYPE_MANAGED; 144 result.name = beginNotAttachedThreadRe.group(1); 145 result.daemon = beginNotAttachedThreadRe.group(2); 146 result.priority = Utils.getInt(beginNotAttachedThreadRe, 3, -1); 147 result.tid = -1; 148 result.vmState = beginNotAttachedThreadRe.group(4); 149 } 150 151 // Attributes 152 while (lines.hasNext()) { 153 line = lines.next(); 154 text = line.text; 155 if (Utils.matches(heldMutexesRe, text)) { 156 result.attributeText.add(heldMutexesRe.group(1)); 157 result.heldMutexes = heldMutexesRe.group(2); 158 } else if (Utils.matches(attrRe, text)) { 159 result.attributeText.add(attrRe.group(1)); 160 if (Utils.matches(sysTidAttrRe, text)) { 161 result.sysTid = Integer.parseInt(sysTidAttrRe.group(1)); 162 } 163 if (Utils.matches(stateAttrRe, text)) { 164 result.runnable = true; 165 } 166 } else { 167 lines.rewind(); 168 break; 169 } 170 } 171 172 // Stack 173 while (lines.hasNext()) { 174 line = lines.next(); 175 text = line.text; 176 if (Utils.matches(nativeRe, text)) { 177 final NativeStackFrameSnapshot frame = new NativeStackFrameSnapshot(); 178 frame.text = text; 179 frame.library = nativeRe.group(1); 180 frame.symbol = nativeRe.group(2); 181 frame.offset = Integer.parseInt(nativeRe.group(3)); 182 result.frames.add(frame); 183 lastJava = null; 184 } else if (Utils.matches(nativeNoLocRe, text)) { 185 final NativeStackFrameSnapshot frame = new NativeStackFrameSnapshot(); 186 frame.text = text; 187 frame.library = nativeNoLocRe.group(1); 188 frame.symbol = nativeNoLocRe.group(2); 189 frame.offset = -1; 190 result.frames.add(frame); 191 lastJava = null; 192 } else if (Utils.matches(kernelRe, text)) { 193 final KernelStackFrameSnapshot frame = new KernelStackFrameSnapshot(); 194 frame.text = text; 195 frame.syscall = kernelRe.group(1); 196 frame.offset0 = Integer.parseInt(kernelRe.group(3), 16); 197 frame.offset1 = Integer.parseInt(kernelRe.group(3), 16); 198 result.frames.add(frame); 199 lastJava = null; 200 } else if (Utils.matches(kernelUnknownRe, text)) { 201 final StackFrameSnapshot frame = new StackFrameSnapshot(); 202 frame.text = text; 203 result.frames.add(frame); 204 lastJava = null; 205 } else if (Utils.matches(javaRe, text)) { 206 final JavaStackFrameSnapshot frame = new JavaStackFrameSnapshot(); 207 frame.text = text; 208 frame.packageName = javaRe.group(1); 209 frame.className = javaRe.group(2); 210 frame.methodName = javaRe.group(3); 211 frame.sourceFile = javaRe.group(4); 212 frame.sourceLine = Integer.parseInt(javaRe.group(5)); 213 frame.language = JavaStackFrameSnapshot.LANGUAGE_JAVA; 214 result.frames.add(frame); 215 lastJava = frame; 216 } else if (Utils.matches(jniRe, text)) { 217 final JavaStackFrameSnapshot frame = new JavaStackFrameSnapshot(); 218 frame.text = text; 219 frame.packageName = jniRe.group(1); 220 frame.className = jniRe.group(2); 221 frame.methodName = jniRe.group(3); 222 frame.language = JavaStackFrameSnapshot.LANGUAGE_JNI; 223 result.frames.add(frame); 224 lastJava = frame; 225 } else if (Utils.matches(lockedRe, text)) { 226 if (lastJava != null) { 227 final LockSnapshot lock = new LockSnapshot(); 228 lock.type = LockSnapshot.LOCKED; 229 lock.address = lockedRe.group(1); 230 lock.packageName = lockedRe.group(2); 231 lock.className = lockedRe.group(3); 232 lastJava.locks.add(lock); 233 } 234 } else if (Utils.matches(waitingOnRe, text)) { 235 if (lastJava != null) { 236 final LockSnapshot lock = new LockSnapshot(); 237 lock.type = LockSnapshot.WAITING; 238 lock.address = waitingOnRe.group(1); 239 lock.packageName = waitingOnRe.group(2); 240 lock.className = waitingOnRe.group(3); 241 lastJava.locks.add(lock); 242 } 243 } else if (Utils.matches(sleepingOnRe, text)) { 244 if (lastJava != null) { 245 final LockSnapshot lock = new LockSnapshot(); 246 lock.type = LockSnapshot.SLEEPING; 247 lock.address = sleepingOnRe.group(1); 248 lock.packageName = sleepingOnRe.group(2); 249 lock.className = sleepingOnRe.group(3); 250 lastJava.locks.add(lock); 251 } 252 } else if (Utils.matches(waitingToLockHeldRe, text)) { 253 if (lastJava != null) { 254 final LockSnapshot lock = new LockSnapshot(); 255 lock.type = LockSnapshot.BLOCKED; 256 lock.address = waitingToLockHeldRe.group(1); 257 lock.packageName = waitingToLockHeldRe.group(2); 258 lock.className = waitingToLockHeldRe.group(3); 259 lock.threadId = Integer.parseInt(waitingToLockHeldRe.group(4)); 260 lastJava.locks.add(lock); 261 } 262 } else if (Utils.matches(waitingToLockRe, text)) { 263 if (lastJava != null) { 264 final LockSnapshot lock = new LockSnapshot(); 265 lock.type = LockSnapshot.BLOCKED; 266 lock.address = waitingToLockRe.group(1); 267 lock.packageName = waitingToLockRe.group(2); 268 lock.className = waitingToLockRe.group(3); 269 lock.threadId = -1; 270 lastJava.locks.add(lock); 271 } 272 } else if (Utils.matches(waitingToLockUnknownRe, text)) { 273 if (lastJava != null) { 274 final LockSnapshot lock = new LockSnapshot(); 275 lock.type = LockSnapshot.BLOCKED; 276 lastJava.locks.add(lock); 277 } 278 } else if (Utils.matches(noManagedStackFrameRe, text)) { 279 final StackFrameSnapshot frame = new StackFrameSnapshot(); 280 frame.text = noManagedStackFrameRe.group(1); 281 result.frames.add(frame); 282 lastJava = null; 283 } else if (text.length() == 0 || Utils.matches(blankRe, text)) { 284 break; 285 } else { 286 final StackFrameSnapshot frame = new StackFrameSnapshot(); 287 frame.text = text; 288 result.frames.add(frame); 289 lastJava = null; 290 System.out.println(" other ==> [" + frame.text + "]"); 291 } 292 } 293 294 295 if (false) { 296 System.out.println(); 297 System.out.println("THREAD"); 298 System.out.println("name=" + result.name); 299 System.out.println("daemon=" + result.daemon); 300 System.out.println("priority=" + result.priority); 301 System.out.println("tid=" + result.tid); 302 System.out.println("vmState=" + result.vmState); 303 for (String s: result.attributeText) { 304 System.out.println(" attr --> " + s); 305 } 306 System.out.println("heldMutexes=" + result.heldMutexes); 307 for (StackFrameSnapshot frame: result.frames) { 308 if (frame.frameType == StackFrameSnapshot.FRAME_TYPE_NATIVE) { 309 final NativeStackFrameSnapshot nf = (NativeStackFrameSnapshot)frame; 310 System.out.println(" frame(native) ==> " + nf.library 311 + " / " + nf.symbol + " / " + nf.offset); 312 } else if (frame.frameType == StackFrameSnapshot.FRAME_TYPE_KERNEL) { 313 final KernelStackFrameSnapshot kf = (KernelStackFrameSnapshot)frame; 314 System.out.println(" frame(kernel) ==> " + kf.syscall 315 + " / 0x" + kf.offset0 + " / 0x" + kf.offset1); 316 } else if (frame.frameType == StackFrameSnapshot.FRAME_TYPE_JAVA) { 317 final JavaStackFrameSnapshot jf = (JavaStackFrameSnapshot)frame; 318 System.out.println(" frame(java) ==> " + jf.packageName 319 + " / " + jf.className + " / " + jf.methodName 320 + " / " + jf.sourceFile + " / " + jf.sourceLine 321 + " / " 322 + (jf.language == JavaStackFrameSnapshot.LANGUAGE_JAVA ? "java" : "jni") 323 + " ===> " + jf.text); 324 for (LockSnapshot ls: jf.locks) { 325 System.out.println(" --> " 326 + (ls.type == LockSnapshot.LOCKED ? "locked" : "waiting") 327 + " / " + ls.address + " / " + ls.packageName 328 + " / " + ls.className); 329 } 330 } else { 331 System.out.println(" frame(other) ==> " + frame.text); 332 } 333 } 334 } 335 336 return result; 337 } 338 } 339 340