diff options
author | Eric Rowe <erowe@google.com> | 2014-08-15 17:03:28 -0700 |
---|---|---|
committer | Eric Rowe <erowe@google.com> | 2014-08-15 17:03:28 -0700 |
commit | e337a91a147162fbad603c05c5ddffd12bff6f7d (patch) | |
tree | 0965eeeaed3f10986a20294ad50cd297737faca4 | |
parent | df2e25b0b50559b3d293a15a0714d41608eca305 (diff) | |
download | loganalysis-e337a91a147162fbad603c05c5ddffd12bff6f7d.tar.gz |
Update boot reason parsing for with 3.10 kernel
Also, bring kernel log parser in line with APR and only record first
kernel reset.
Bug: 14829888
Change-Id: Ice5db062b3fc8ece774afc8e284f1a276aa52d43
6 files changed, 178 insertions, 5 deletions
diff --git a/src/com/android/loganalysis/item/BugreportItem.java b/src/com/android/loganalysis/item/BugreportItem.java index 1df7d30..4b35816 100644 --- a/src/com/android/loganalysis/item/BugreportItem.java +++ b/src/com/android/loganalysis/item/BugreportItem.java @@ -28,6 +28,8 @@ public class BugreportItem extends GenericItem { /** Constant for JSON output */ public static final String TIME = "TIME"; /** Constant for JSON output */ + public static final String COMMAND_LINE = "COMMAND_LINE"; + /** Constant for JSON output */ public static final String MEM_INFO = "MEM_INFO"; /** Constant for JSON output */ public static final String PROCRANK = "PROCRANK"; @@ -45,8 +47,10 @@ public class BugreportItem extends GenericItem { public static final String DUMPSYS = "DUMPSYS"; private static final Set<String> ATTRIBUTES = new HashSet<String>(Arrays.asList( - TIME, MEM_INFO, PROCRANK, TOP, KERNEL_LOG, LAST_KMSG, SYSTEM_LOG, SYSTEM_PROPS, - DUMPSYS)); + TIME, COMMAND_LINE, MEM_INFO, PROCRANK, TOP, KERNEL_LOG, LAST_KMSG, SYSTEM_LOG, + SYSTEM_PROPS, DUMPSYS)); + + public static class CommandLineItem extends GenericMapItem<String> {} /** * The constructor for {@link BugreportItem}. @@ -70,6 +74,20 @@ public class BugreportItem extends GenericItem { } /** + * Get the {@link CommandLineItem} of the bugreport. + */ + public CommandLineItem getCommandLine() { + return (CommandLineItem) getAttribute(COMMAND_LINE); + } + + /** + * Set the {@link CommandLineItem} of the bugreport. + */ + public void setCommandLine(CommandLineItem commandLine) { + setAttribute(COMMAND_LINE, commandLine); + } + + /** * Get the {@link MemInfoItem} of the bugreport. */ public MemInfoItem getMemInfo() { diff --git a/src/com/android/loganalysis/item/KernelLogItem.java b/src/com/android/loganalysis/item/KernelLogItem.java index c9ebf16..60ed4de 100644 --- a/src/com/android/loganalysis/item/KernelLogItem.java +++ b/src/com/android/loganalysis/item/KernelLogItem.java @@ -15,6 +15,8 @@ */ package com.android.loganalysis.item; +import com.android.loganalysis.parser.KernelLogParser; + import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -91,6 +93,11 @@ public class KernelLogItem extends GenericItem { * Add an {@link MiscKernelLogItem} event to the end of the list of events. */ public void addEvent(MiscKernelLogItem event) { + // Only take the first kernel reset + if (KernelLogParser.KERNEL_RESET.equals(event.getCategory()) && + !getMiscEvents(KernelLogParser.KERNEL_RESET).isEmpty()) { + return; + } ((ItemList) getAttribute(EVENTS)).add(event); } diff --git a/src/com/android/loganalysis/parser/BugreportParser.java b/src/com/android/loganalysis/parser/BugreportParser.java index 3947a98..604ec1a 100644 --- a/src/com/android/loganalysis/parser/BugreportParser.java +++ b/src/com/android/loganalysis/parser/BugreportParser.java @@ -17,11 +17,13 @@ package com.android.loganalysis.parser; import com.android.loganalysis.item.AnrItem; import com.android.loganalysis.item.BugreportItem; +import com.android.loganalysis.item.BugreportItem.CommandLineItem; import com.android.loganalysis.item.DumpsysItem; import com.android.loganalysis.item.IItem; import com.android.loganalysis.item.KernelLogItem; import com.android.loganalysis.item.LogcatItem; import com.android.loganalysis.item.MemInfoItem; +import com.android.loganalysis.item.MiscKernelLogItem; import com.android.loganalysis.item.MiscLogcatItem; import com.android.loganalysis.item.ProcrankItem; import com.android.loganalysis.item.SystemPropsItem; @@ -55,12 +57,20 @@ public class BugreportParser extends AbstractSectionParser { private static final String DUMPSYS_SECTION_REGEX = "------ DUMPSYS .*"; private static final String NOOP_SECTION_REGEX = "------ .*"; + private static final String BOOTREASON = "androidboot.bootreason"; + /** * Matches: == dumpstate: 2012-04-26 12:13:14 */ private static final Pattern DATE = Pattern.compile( "^== dumpstate: (\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2})$"); + /** + * Matches: Command line: key=value key=value + */ + private static final Pattern COMMAND_LINE = Pattern.compile( + "Command line:((\\s+[^\\s=]+=[^\\s]*)*)\\s*"); + private IParser mBugreportParser = new IParser() { @Override public BugreportItem parse(List<String> lines) { @@ -73,6 +83,18 @@ public class BugreportParser extends AbstractSectionParser { if (m.matches()) { bugreport.setTime(parseTime(m.group(1))); } + m = COMMAND_LINE.matcher(line); + if (m.matches()) { + String argString = m.group(1).trim(); + if (!argString.isEmpty()) { + String[] pairs = argString.split("\\s+"); + for (String pair : pairs) { + System.out.println(pair); + String[] keyValue = pair.split("=", 2); + mCommandLine.put(keyValue[0], keyValue[1]); + } + } + } } return bugreport; } @@ -88,6 +110,7 @@ public class BugreportParser extends AbstractSectionParser { private DumpsysParser mDumpsysParser = new DumpsysParser(); private BugreportItem mBugreport = null; + private CommandLineItem mCommandLine = new CommandLineItem(); private boolean mParsedInput = false; @@ -164,6 +187,7 @@ public class BugreportParser extends AbstractSectionParser { } if (mBugreport != null) { + mBugreport.setCommandLine(mCommandLine); mBugreport.setMemInfo((MemInfoItem) getSection(mMemInfoParser)); mBugreport.setProcrank((ProcrankItem) getSection(mProcrankParser)); mBugreport.setTop((TopItem) getSection(mTopParser)); @@ -189,7 +213,20 @@ public class BugreportParser extends AbstractSectionParser { mBugreport.getSystemLog() != null) { addAnrTrace(mBugreport.getSystemLog().getAnrs(), traces.getApp(), traces.getStack()); + } + if (mCommandLine.containsKey(BOOTREASON)) { + String bootreason = mCommandLine.get(BOOTREASON); + Matcher m = KernelLogParser.BAD_BOOTREASONS.matcher(bootreason); + if (m.matches()) { + if (mBugreport.getLastKmsg() == null) { + mBugreport.setLastKmsg(new KernelLogItem()); + } + MiscKernelLogItem item = new MiscKernelLogItem(); + item.setStack("Last boot reason: " + bootreason.trim()); + item.setCategory(KernelLogParser.KERNEL_RESET); + mBugreport.getLastKmsg().addEvent(item); + } } } } diff --git a/src/com/android/loganalysis/parser/KernelLogParser.java b/src/com/android/loganalysis/parser/KernelLogParser.java index e240432..741c261 100644 --- a/src/com/android/loganalysis/parser/KernelLogParser.java +++ b/src/com/android/loganalysis/parser/KernelLogParser.java @@ -44,6 +44,13 @@ public class KernelLogParser implements IParser { private static final Pattern SELINUX_DENIAL_PATTERN = Pattern.compile( ".*avc:\\s.*scontext=\\w*:\\w*:([\\w\\s]*):\\w*\\s.*"); + /** + * Regular expression representing all known bootreasons which are bad. + */ + public static final Pattern BAD_BOOTREASONS = Pattern.compile( + "(?:kernel_panic|rpm_err|hw_reset(?:$|\\n)|wdog_.*|tz_err|adsp_err|modem_err|mba_err|" + + "watchdogr?|Watchdog|Panic|srto:.*)"); + private KernelLogItem mKernelLog = null; private Double mStartTime = null; private Double mStopTime = null; @@ -161,16 +168,17 @@ public class KernelLogParser implements IParser { "smem: DIAG.*", "smsm: AMSS FATAL ERROR.*", "kernel BUG at .*", + "BUG: failure at .*", "PVR_K:\\(Fatal\\): Debug assertion failed! \\[.*\\]", "Kernel panic.*", + "Unable to handle kernel paging request.*", "BP panicked", "WROTE DSP RAMDUMP", "tegra_wdt: last reset due to watchdog timeout.*", "tegra_wdt tegra_wdt.0: last reset is due to watchdog timeout.*", "Last reset was MPU Watchdog Timer reset.*", "\\[MODEM_IF\\].*CRASH.*", - "Last boot reason: (?:kernel_panic|rpm_err|hw_reset(?:$|\n)|wdog_.*|" + - "tz_err|adsp_err|modem_err|mba_err|watchdogr?|Watchdog|Panic)", + "Last boot reason: " + BAD_BOOTREASONS, "Last reset was system watchdog timer reset.*", }; for (String pattern : kernelResets) { diff --git a/tests/src/com/android/loganalysis/parser/BugreportParserTest.java b/tests/src/com/android/loganalysis/parser/BugreportParserTest.java index b080e0d..1eedf46 100644 --- a/tests/src/com/android/loganalysis/parser/BugreportParserTest.java +++ b/tests/src/com/android/loganalysis/parser/BugreportParserTest.java @@ -92,7 +92,7 @@ public class BugreportParserTest extends TestCase { "", "------ LAST KMSG (/proc/last_kmsg) ------", "[ 0.000000] Initializing cgroup subsys cpu", - "[ 16.203491] benight message", + "[ 16.203491] benign message", "", "------ SECTION ------", "", @@ -183,6 +183,83 @@ public class BugreportParserTest extends TestCase { } /** + * Test that the command line is parsed + */ + public void testParse_command_line() { + List<String> lines = Arrays.asList("Command line:"); + BugreportItem bugreport = new BugreportParser().parse(lines); + assertTrue(bugreport.getCommandLine().isEmpty()); + + lines = Arrays.asList("Command line: key=value"); + bugreport = new BugreportParser().parse(lines); + assertEquals(1, bugreport.getCommandLine().size()); + assertEquals("value", bugreport.getCommandLine().get("key")); + + lines = Arrays.asList("Command line: key1=value1 key2=value2"); + bugreport = new BugreportParser().parse(lines); + assertEquals(2, bugreport.getCommandLine().size()); + assertEquals("value1", bugreport.getCommandLine().get("key1")); + assertEquals("value2", bugreport.getCommandLine().get("key2")); + + // Test a bad strings + lines = Arrays.asList("Command line: key1=value=withequals key2= "); + bugreport = new BugreportParser().parse(lines); + assertEquals(2, bugreport.getCommandLine().size()); + assertEquals("value=withequals", bugreport.getCommandLine().get("key1")); + assertEquals("", bugreport.getCommandLine().get("key2")); + + lines = Arrays.asList("Command line: key1=value=withequals key2= key3"); + bugreport = new BugreportParser().parse(lines); + assertTrue(bugreport.getCommandLine().isEmpty()); + } + + /** + * Test + */ + public void testParse_bootreason_good() { + List<String> lines = Arrays.asList( + "========================================================", + "== dumpstate: 1999-01-01 02:03:04", + "========================================================", + "Command line: androidboot.bootreason=reboot", + ""); + BugreportItem bugreport = new BugreportParser().parse(lines); + assertNull(bugreport.getLastKmsg()); + } + + public void testParse_bootreason_bad() { + List<String> lines = Arrays.asList( + "========================================================", + "== dumpstate: 1999-01-01 02:03:04", + "========================================================", + "Command line: androidboot.bootreason=hw_reset", + ""); + BugreportItem bugreport = new BugreportParser().parse(lines); + assertNotNull(bugreport.getLastKmsg()); + assertEquals(1, bugreport.getLastKmsg().getEvents().size()); + assertEquals("Last boot reason: hw_reset", + bugreport.getLastKmsg().getEvents().get(0).getStack()); + assertEquals("KERNEL_RESET", bugreport.getLastKmsg().getEvents().get(0).getCategory()); + } + + public void testParse_bootreason_duplicate() { + List<String> lines = Arrays.asList( + "========================================================", + "== dumpstate: 1999-01-01 02:03:04", + "========================================================", + "Command line: androidboot.bootreason=hw_reset", + "------ LAST KMSG (/proc/last_kmsg) ------", + "[ 0.000000] Initializing cgroup subsys cpu", + "[ 16.203491] Kernel panic", + ""); + BugreportItem bugreport = new BugreportParser().parse(lines); + assertNotNull(bugreport.getLastKmsg()); + assertEquals(1, bugreport.getLastKmsg().getEvents().size()); + assertEquals("Kernel panic", bugreport.getLastKmsg().getEvents().get(0).getStack()); + assertEquals("KERNEL_RESET", bugreport.getLastKmsg().getEvents().get(0).getCategory()); + } + + /** * Test that the trace is set correctly if there is only one ANR. */ public void testSetAnrTrace_single() { diff --git a/tests/src/com/android/loganalysis/parser/KernelLogParserTest.java b/tests/src/com/android/loganalysis/parser/KernelLogParserTest.java index 118f3ff..890a196 100644 --- a/tests/src/com/android/loganalysis/parser/KernelLogParserTest.java +++ b/tests/src/com/android/loganalysis/parser/KernelLogParserTest.java @@ -212,4 +212,30 @@ public class KernelLogParserTest extends TestCase { assertEquals(1, kernelLog.getEvents().size()); assertEquals(1, kernelLog.getMiscEvents(KernelLogParser.KERNEL_RESET).size()); } + + /** + * Test that only the first kernel reset is taken but other signatures can have multiple + */ + public void testMultipleKernelResets() { + final String SELINUX_DENIAL_STACK = "type=1400 audit(1384544483.730:10): avc: denied " + + "{ getattr } for pid=797 comm=\"Binder_5\" path=\"/dev/pts/1\" + " + + "dev=devpts ino=4 scontext=u:r:system_server:s0 " + + "tcontext=u:object_r:devpts:s0 tclass=chr_file"; + final List<String> lines = Arrays.asList( + "[ 0.000000] Kernel panic", + "[ 0.000000] Internal error:", + "[ 0.000000] " + SELINUX_DENIAL_STACK, + "[ 1.000000] Kernel panic", + "[ 1.000000] Internal error:", + "[ 1.000000] " + SELINUX_DENIAL_STACK, + "[ 2.000000] Kernel panic", + "[ 2.000000] Internal error:", + "[ 2.000000] " + SELINUX_DENIAL_STACK); + + KernelLogItem kernelLog = new KernelLogParser().parse(lines); + assertEquals(7, kernelLog.getEvents().size()); + assertEquals(1, kernelLog.getMiscEvents(KernelLogParser.KERNEL_RESET).size()); + assertEquals(0.0, + kernelLog.getMiscEvents(KernelLogParser.KERNEL_RESET).get(0).getEventTime()); + } } |