Add command line utilites to set the reason field in incident report header

Bug: 132890298
Test: incident_report -t -r "\"Hello Joe\"" 3000
Change-Id: Ic7a2523d7e87ba88019c5ac9b23ff35387fbc498
diff --git a/cmds/incident/Android.bp b/cmds/incident/Android.bp
index f56f101..9e9dac1 100644
--- a/cmds/incident/Android.bp
+++ b/cmds/incident/Android.bp
@@ -30,7 +30,7 @@
     ],
 
     static_libs: [
-        "libplatformprotos",
+        "libprotoutil",
     ],
 
     cflags: [
diff --git a/cmds/incident/main.cpp b/cmds/incident/main.cpp
index eca781f..13e707b 100644
--- a/cmds/incident/main.cpp
+++ b/cmds/incident/main.cpp
@@ -21,6 +21,7 @@
 #include <android/os/BnIncidentReportStatusListener.h>
 #include <android/os/IIncidentManager.h>
 #include <android/os/IncidentReportArgs.h>
+#include <android/util/ProtoOutputStream.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
 #include <utils/Looper.h>
@@ -36,6 +37,9 @@
 using namespace android::base;
 using namespace android::binder;
 using namespace android::os;
+using android::util::FIELD_COUNT_SINGLE;
+using android::util::FIELD_TYPE_STRING;
+using android::util::ProtoOutputStream;
 
 // ================================================================================
 class StatusListener : public BnIncidentReportStatusListener {
@@ -208,6 +212,7 @@
     fprintf(out, "and one of these destinations:\n");
     fprintf(out, "  -b           (default) print the report to stdout (in proto format)\n");
     fprintf(out, "  -d           send the report into dropbox\n");
+    fprintf(out, "  -r REASON    human readable description of why the report is taken.\n");
     fprintf(out, "  -s PKG/CLS   send broadcast to the broadcast receiver.\n");
     fprintf(out, "\n");
     fprintf(out, "  SECTION     the field numbers of the incident report fields to include\n");
@@ -221,11 +226,12 @@
     IncidentReportArgs args;
     enum { DEST_UNSET, DEST_DROPBOX, DEST_STDOUT, DEST_BROADCAST } destination = DEST_UNSET;
     int privacyPolicy = PRIVACY_POLICY_AUTOMATIC;
+    string reason;
     string receiverArg;
 
     // Parse the args
     int opt;
-    while ((opt = getopt(argc, argv, "bhdlp:s:")) != -1) {
+    while ((opt = getopt(argc, argv, "bhdlp:r:s:")) != -1) {
         switch (opt) {
             case 'h':
                 usage(stdout);
@@ -250,6 +256,13 @@
             case 'p':
                 privacyPolicy = get_privacy_policy(optarg);
                 break;
+            case 'r':
+                if (reason.size() > 0) {
+                    usage(stderr);
+                    return 1;
+                }
+                reason = optarg;
+                break;
             case 's':
                 if (destination != DEST_UNSET) {
                     usage(stderr);
@@ -301,6 +314,14 @@
     }
     args.setPrivacyPolicy(privacyPolicy);
 
+    if (reason.size() > 0) {
+        ProtoOutputStream proto;
+        proto.write(/* reason field id */ 2 | FIELD_TYPE_STRING | FIELD_COUNT_SINGLE, reason);
+        vector<uint8_t> header;
+        proto.serializeToVector(&header);
+        args.addHeader(header);
+    }
+
     // Start the thread pool.
     sp<ProcessState> ps(ProcessState::self());
     ps->startThreadPool();
diff --git a/tools/incident_report/main.cpp b/tools/incident_report/main.cpp
index 17a3c7a..974166a 100644
--- a/tools/incident_report/main.cpp
+++ b/tools/incident_report/main.cpp
@@ -292,6 +292,7 @@
     fprintf(out, "Take an incident report over adb (which must be in the PATH).\n");
     fprintf(out, "  -b          output the incident report raw protobuf format\n");
     fprintf(out, "  -o OUTPUT   the output file. OUTPUT may be '-' or omitted to use stdout\n");
+    fprintf(out, "  -r REASON   human readable description of why the report is taken.\n");
     fprintf(out, "  -s SERIAL   sent to adb to choose which device, instead of $ANDROID_SERIAL\n");
     fprintf(out, "  -t          output the incident report in pretty-printed text format\n");
     fprintf(out, "\n");
@@ -307,13 +308,14 @@
     enum { OUTPUT_TEXT, OUTPUT_PROTO } outputFormat = OUTPUT_TEXT;
     const char* inFilename = NULL;
     const char* outFilename = NULL;
+    const char* reason = NULL;
     const char* adbSerial = NULL;
     pid_t childPid = -1;
     vector<string> sections;
     const char* privacy = NULL;
 
     int opt;
-    while ((opt = getopt(argc, argv, "bhi:o:s:twp:")) != -1) {
+    while ((opt = getopt(argc, argv, "bhi:o:r:s:twp:")) != -1) {
         switch (opt) {
             case 'b':
                 outputFormat = OUTPUT_PROTO;
@@ -324,6 +326,9 @@
             case 'o':
                 outFilename = optarg;
                 break;
+            case 'r':
+                reason = optarg;
+                break;
             case 's':
                 adbSerial = optarg;
                 break;
@@ -376,7 +381,7 @@
             dup2(pfd[1], STDOUT_FILENO);
             close(pfd[0]);
             close(pfd[1]);
-            char const** args = (char const**)malloc(sizeof(char*) * (8 + sections.size()));
+            char const** args = (char const**)malloc(sizeof(char*) * (10 + sections.size()));
             int argpos = 0;
             args[argpos++] = "adb";
             if (adbSerial != NULL) {
@@ -389,6 +394,10 @@
                 args[argpos++] = "-p";
                 args[argpos++] = privacy;
             }
+            if (reason != NULL) {
+                args[argpos++] = "-r";
+                args[argpos++] = reason;
+            }
             for (vector<string>::const_iterator it=sections.begin(); it!=sections.end(); it++) {
                 args[argpos++] = it->c_str();
             }