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 process. 31 * 32 * The parser can be reused, but is not thread safe. 33 */ 34 public class ProcessSnapshotParser { 35 public static final Pattern BEGIN_PROCESS_RE = Pattern.compile( 36 "----- pid (\\d+) at (\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}) -----"); 37 private static final Pattern END_PROCESS_RE 38 = Pattern.compile("----- end \\d+ -----"); 39 40 public static final Pattern CMD_LINE_RE = Pattern.compile( 41 "Cmd line: (.*)"); 42 43 /** 44 * Construct a new parser. 45 */ ProcessSnapshotParser()46 public ProcessSnapshotParser() { 47 } 48 49 /** 50 * Parse the given Lines until the beginning of the next process section, or until 51 * the end of input is reached. 52 */ parse(Lines<? extends Line> lines)53 public ProcessSnapshot parse(Lines<? extends Line> lines) { 54 final ProcessSnapshot result = new ProcessSnapshot(); 55 56 final Matcher beginProcessRe = BEGIN_PROCESS_RE.matcher(""); 57 final Matcher beginUnmanagedThreadRe = ThreadSnapshotParser.BEGIN_UNMANAGED_THREAD_RE 58 .matcher(""); 59 final Matcher beginManagedThreadRe = ThreadSnapshotParser.BEGIN_MANAGED_THREAD_RE 60 .matcher(""); 61 final Matcher beginNotAttachedThreadRe = ThreadSnapshotParser.BEGIN_NOT_ATTACHED_THREAD_RE 62 .matcher(""); 63 final Matcher endProcessRe = END_PROCESS_RE.matcher(""); 64 final Matcher cmdLineRe = CMD_LINE_RE.matcher(""); 65 66 final int STATE_INITIAL = 0; 67 final int STATE_THREADS = 1; 68 int state = STATE_INITIAL; 69 70 // Preamble 71 while (lines.hasNext()) { 72 final Line line = lines.next(); 73 final String text = line.text; 74 if (Utils.matches(beginProcessRe, text)) { 75 result.pid = Integer.parseInt(beginProcessRe.group(1)); 76 result.date = beginProcessRe.group(2); 77 } else if (Utils.matches(beginUnmanagedThreadRe, text)) { 78 state = STATE_THREADS; 79 lines.rewind(); 80 break; 81 } else if (Utils.matches(beginManagedThreadRe, text)) { 82 state = STATE_THREADS; 83 lines.rewind(); 84 break; 85 } else if (Utils.matches(beginNotAttachedThreadRe, text)) { 86 state = STATE_THREADS; 87 lines.rewind(); 88 break; 89 } else if (Utils.matches(endProcessRe, text)) { 90 break; 91 } else if (Utils.matches(cmdLineRe, text)) { 92 result.cmdLine = cmdLineRe.group(1); 93 } else { 94 if (false) { 95 System.out.println("ProcessSnapshotParser Dropping: " + text); 96 } 97 } 98 } 99 100 // Thread list 101 if (state == STATE_THREADS) { 102 while (lines.hasNext()) { 103 final Line line = lines.next(); 104 final String text = line.text; 105 if (Utils.matches(beginUnmanagedThreadRe, text) 106 || Utils.matches(beginManagedThreadRe, text) 107 || Utils.matches(beginNotAttachedThreadRe, text)) { 108 lines.rewind(); 109 ThreadSnapshotParser parser = new ThreadSnapshotParser(); 110 final ThreadSnapshot snapshot = parser.parse(lines); 111 if (snapshot != null) { 112 result.threads.add(snapshot); 113 } else { 114 // TODO: Try to backtrack and correct the parsing. 115 } 116 } else if (Utils.matches(endProcessRe, text)) { 117 break; 118 } else { 119 if (false) { 120 System.out.println("ProcessSnapshotParser STATE_THREADS Dropping: " + text); 121 } 122 } 123 } 124 } 125 126 if (false) { 127 System.out.println(); 128 System.out.println("PROCESS"); 129 System.out.println("pid=" + result.pid); 130 System.out.println("date=" + result.date); 131 System.out.println("threads=" + result.threads.size()); 132 System.out.println("cmdLine=" + result.cmdLine); 133 } 134 135 return result; 136 } 137 138 } 139 140