crash: Report ARC app crashes

This CL enables ARC to report app crashes, which is useful to gather
statistics about app compatibility, e.g. whether apps crash on resize.
Note that only metadata is reported, i.e. stack traces are discarded
in the ARC container before transmitting the report to crash_reporter.

BUG=b:36088643
TEST=Trigger app crash and inspect report in ~chronos/crash.

Change-Id: Iebb38ca03e03b0533584b40dd05f9f4d6af28917
Reviewed-on: https://chromium-review.googlesource.com/480522
Commit-Ready: Dominik Laskowski <domlaskowski@google.com>
Tested-by: Dominik Laskowski <domlaskowski@google.com>
Reviewed-by: Luis Hector Chavez <lhchavez@chromium.org>
Reviewed-by: Victor Hsieh <victorhsieh@chromium.org>
(cherry picked from commit 4061b70952112b19478c83623fee90f722deba4f)
Reviewed-on: https://chromium-review.googlesource.com/492226
Commit-Queue: Victor Hsieh <victorhsieh@chromium.org>
Tested-by: Victor Hsieh <victorhsieh@chromium.org>
diff --git a/crash-reporter/arc_collector.cc b/crash-reporter/arc_collector.cc
index 6173d50..c8387df 100644
--- a/crash-reporter/arc_collector.cc
+++ b/crash-reporter/arc_collector.cc
@@ -57,9 +57,11 @@
 const char kBoardField[] = "board";
 const char kChromeOsVersionField[] = "chrome_os_version";
 const char kCpuAbiField[] = "cpu_abi";
+const char kCrashTagField[] = "crash_tag";
 const char kCrashTypeField[] = "crash_type";
 const char kDeviceField[] = "device";
 const char kExceptionInfoField[] = "exception_info";
+const char kPackageField[] = "package";
 const char kProcessField[] = "process";
 const char kProductField[] = "prod";
 const char kSignatureField[] = "sig";
@@ -71,6 +73,8 @@
 
 // Keys for crash log headers.
 const char kBuildKey[] = "Build";
+const char kCrashTagKey[] = "Crash-Tag";
+const char kPackageKey[] = "Package";
 const char kProcessKey[] = "Process";
 const char kSubjectKey[] = "Subject";
 
@@ -407,7 +411,9 @@
       const auto begin = line.find_first_not_of(' ', end + 1);
 
       if (begin != std::string::npos) {
-        map->emplace(line.substr(0, end), line.substr(begin));
+        // TODO(domlaskowski): Use multimap to allow multiple "Package" headers.
+        if (!map->emplace(line.substr(0, end), line.substr(begin)).second)
+          LOG(WARNING) << "Duplicate header: " << line;
         continue;
       }
     }
@@ -469,6 +475,13 @@
   AddCrashMetaUploadData(kBoardField, board);
   AddCrashMetaUploadData(kCpuAbiField, cpu_abi);
 
+  if (map.count(kPackageKey))
+    AddCrashMetaUploadData(kPackageField, GetCrashLogHeader(map, kPackageKey));
+
+  if (map.count(kCrashTagKey))
+    AddCrashMetaUploadData(kCrashTagField,
+                           GetCrashLogHeader(map, kCrashTagKey));
+
   if (exception_info.empty()) {
     if (const char * const tag = GetSubjectTag(crash_type)) {
       std::ostringstream out;
@@ -516,6 +529,7 @@
 
 bool HasExceptionInfo(const std::string &type) {
   static const std::unordered_set<std::string> kTypes = {
+    "data_app_crash",
     "system_app_crash",
     "system_app_wtf",
     "system_server_crash",