1 /*
2  * Copyright (C) 2012 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 package com.android.loganalysis.parser;
17 
18 import com.android.loganalysis.item.AnrItem;
19 
20 import java.util.List;
21 import java.util.regex.Matcher;
22 import java.util.regex.Pattern;
23 
24 /**
25  * An {@link IParser} to handle ANRs.
26  */
27 public class AnrParser implements IParser {
28     /**
29      * Matches: ANR (application not responding) in process: app
30      * Matches: ANR in app
31      * Matches: ANR in app (class/package)
32      */
33     public static final Pattern START = Pattern.compile(
34             "^ANR (?:\\(application not responding\\) )?in (?:process: )?(\\S+).*$");
35     /**
36      * Matches: PID: 1234
37      */
38     private static final Pattern PID = Pattern.compile("^PID: (\\d+)$");
39     /**
40      * Matches: Reason: reason
41      */
42     private static final Pattern REASON = Pattern.compile("^Reason: (.*)$");
43     /**
44      * Matches: Load: 0.71 / 0.83 / 0.51
45      */
46     private static final Pattern LOAD = Pattern.compile(
47             "^Load: (\\d+\\.\\d+) / (\\d+\\.\\d+) / (\\d+\\.\\d+)$");
48 
49     /**
50      * Matches: 33% TOTAL: 21% user + 11% kernel + 0.3% iowait
51      */
52     private static final Pattern TOTAL = Pattern.compile("^(\\d+(\\.\\d+)?)% TOTAL: .*$");
53     private static final Pattern USER = Pattern.compile("^.* (\\d+(\\.\\d+)?)% user.*$");
54     private static final Pattern KERNEL = Pattern.compile("^.* (\\d+(\\.\\d+)?)% kernel.*$");
55     private static final Pattern IOWAIT = Pattern.compile("^.* (\\d+(\\.\\d+)?)% iowait.*$");
56 
57     /**
58      * {@inheritDoc}
59      *
60      * @return The {@link AnrItem}.
61      */
62     @Override
parse(List<String> lines)63     public AnrItem parse(List<String> lines) {
64         AnrItem anr = null;
65         StringBuilder stack = new StringBuilder();
66         boolean matchedTotal = false;
67 
68         for (String line : lines) {
69             Matcher m = START.matcher(line);
70             // Ignore all input until the start pattern is matched.
71             if (m.matches()) {
72                 anr = new AnrItem();
73                 anr.setApp(m.group(1));
74             }
75 
76             if (anr != null) {
77                 m = PID.matcher(line);
78                 if (m.matches()) {
79                     anr.setPid(Integer.valueOf(m.group(1)));
80                 }
81                 m = REASON.matcher(line);
82                 if (m.matches()) {
83                     anr.setReason(m.group(1));
84                 }
85 
86                 m = LOAD.matcher(line);
87                 if (m.matches()) {
88                     anr.setLoad(AnrItem.LoadCategory.LOAD_1, Double.parseDouble(m.group(1)));
89                     anr.setLoad(AnrItem.LoadCategory.LOAD_5, Double.parseDouble(m.group(2)));
90                     anr.setLoad(AnrItem.LoadCategory.LOAD_15, Double.parseDouble(m.group(3)));
91                 }
92 
93                 m = TOTAL.matcher(line);
94                 if (!matchedTotal && m.matches()) {
95                     matchedTotal = true;
96                     anr.setCpuUsage(AnrItem.CpuUsageCategory.TOTAL, Double.parseDouble(m.group(1)));
97 
98                     m = USER.matcher(line);
99                     Double usage = m.matches() ? Double.parseDouble(m.group(1)) : 0.0;
100                     anr.setCpuUsage(AnrItem.CpuUsageCategory.USER, usage);
101 
102                     m = KERNEL.matcher(line);
103                     usage = m.matches() ? Double.parseDouble(m.group(1)) : 0.0;
104                     anr.setCpuUsage(AnrItem.CpuUsageCategory.KERNEL, usage);
105 
106                     m = IOWAIT.matcher(line);
107                     usage = m.matches() ? Double.parseDouble(m.group(1)) : 0.0;
108                     anr.setCpuUsage(AnrItem.CpuUsageCategory.IOWAIT, usage);
109                 }
110 
111                 stack.append(line);
112                 stack.append("\n");
113             }
114         }
115 
116         if (anr != null) {
117             anr.setStack(stack.toString().trim());
118         }
119         return anr;
120     }
121 }
122 
123