Better identify java crashes when they don't come from regular apps.

Change-Id: I4e14fb4dc3414b6a78d1b5456403699980abb8a8
diff --git a/src/com/android/loganalysis/parser/LogcatParser.java b/src/com/android/loganalysis/parser/LogcatParser.java
index 8d9ca7f..7011646 100644
--- a/src/com/android/loganalysis/parser/LogcatParser.java
+++ b/src/com/android/loganalysis/parser/LogcatParser.java
@@ -79,6 +79,12 @@
     private static final Pattern JAVA_CRASH_PROCESS_PID = Pattern.compile(
             "^(Process: (\\S+), )?PID: (\\d+)$");
 
+
+    /**
+     * Match a line thats printed when a non app java process starts.
+     */
+    private static final Pattern JAVA_PROC_START = Pattern.compile("Calling main entry (.+)");
+
     /**
      * Class for storing logcat meta data for a particular grouped list of lines.
      */
@@ -119,6 +125,8 @@
 
     private boolean mIsParsing = true;
 
+    private Map<Integer, String> mPids = new HashMap<Integer, String>();
+
     /**
      * Constructor for {@link LogcatParser}.
      */
@@ -233,6 +241,14 @@
             return;
         }
 
+
+        // When a non app java process starts add its pid to the map
+        Matcher pidMatcher = JAVA_PROC_START.matcher(msg);
+        if (pidMatcher.matches()) {
+            String name = pidMatcher.group(1);
+            mPids.put(pid, name);
+        }
+
         // ANRs are separated either by different PID/TIDs or when AnrParser.START matches a line.
         // The newest entry is kept in the dataMap for quick lookup while all entries are added to
         // the list.
@@ -321,7 +337,10 @@
                     }
                     m = SYSTEM_SERVER_CRASH.matcher(line);
                     if (m.matches()) {
-                        app = "system_server";
+                        app = mPids.get(data.mPid);
+                        if (app == null) {
+                            app = "system_server";
+                        }
                         data.mLines = data.mLines.subList(i + 1, data.mLines.size());
                         break;
                     }
diff --git a/tests/src/com/android/loganalysis/parser/LogcatParserTest.java b/tests/src/com/android/loganalysis/parser/LogcatParserTest.java
index a794a14..44f3151 100644
--- a/tests/src/com/android/loganalysis/parser/LogcatParserTest.java
+++ b/tests/src/com/android/loganalysis/parser/LogcatParserTest.java
@@ -15,6 +15,7 @@
  */
 package com.android.loganalysis.parser;
 
+import com.android.loganalysis.item.JavaCrashItem;
 import com.android.loganalysis.item.LogcatItem;
 import com.android.loganalysis.item.MiscLogcatItem;
 import com.android.loganalysis.util.ArrayUtil;
@@ -596,6 +597,26 @@
         assertEquals("I'm the one you need to find!", matchedEvents.get(0).getStack());
     }
 
+    public void testFatalException() {
+        List<String> lines = Arrays.asList(
+                "06-05 06:14:51.529  1712  1712 D AndroidRuntime: Calling main entry com.android.commands.input.Input",
+                "06-05 06:14:51.709  1712  1712 E AndroidRuntime: *** FATAL EXCEPTION IN SYSTEM PROCESS: main",
+                "06-05 06:14:51.709  1712  1712 E AndroidRuntime: java.lang.NullPointerException",
+                "06-05 06:14:51.709  1712  1712 E AndroidRuntime: \tat android.hardware.input.InputManager.injectInputEvent(InputManager.java:641)",
+                "06-05 06:14:51.709  1712  1712 E AndroidRuntime: \tat com.android.commands.input.Input.injectKeyEvent(Input.java:233)",
+                "06-05 06:14:51.709  1712  1712 E AndroidRuntime: \tat com.android.commands.input.Input.sendKeyEvent(Input.java:184)",
+                "06-05 06:14:51.709  1712  1712 E AndroidRuntime: \tat com.android.commands.input.Input.run(Input.java:96)",
+                "06-05 06:14:51.709  1712  1712 E AndroidRuntime: \tat com.android.commands.input.Input.main(Input.java:59)",
+                "06-05 06:14:51.709  1712  1712 E AndroidRuntime: \tat com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method)",
+                "06-05 06:14:51.709  1712  1712 E AndroidRuntime: \tat com.android.internal.os.RuntimeInit.main(RuntimeInit.java:243)",
+                "06-05 06:14:51.709  1712  1712 E AndroidRuntime: \tat dalvik.system.NativeStart.main(Native Method)");
+        LogcatParser parser = new LogcatParser("2014");
+        LogcatItem logcat = parser.parse(lines);
+        assertEquals(1, logcat.getJavaCrashes().size());
+        JavaCrashItem crash = logcat.getJavaCrashes().get(0);
+        assertEquals("com.android.commands.input.Input", crash.getApp());
+    }
+
     /**
      * Test that an empty input returns {@code null}.
      */