incidentd can now handle multiple callers asking it for incident reports

Test: bit incident_test:* GtsIncidentManagerTestCases:*
Bug: 123543706
Change-Id: I9f671dd5d8b2ad139f952a23e575c2be16120459
diff --git a/cmds/incident/main.cpp b/cmds/incident/main.cpp
index cdec6a0..93e592c 100644
--- a/cmds/incident/main.cpp
+++ b/cmds/incident/main.cpp
@@ -68,6 +68,7 @@
 StatusListener::onReportSectionStatus(int32_t section, int32_t status)
 {
     fprintf(stderr, "section %d status %d\n", section, status);
+    ALOGD("section %d status %d\n", section, status);
     return Status::ok();
 }
 
@@ -75,6 +76,7 @@
 StatusListener::onReportServiceStatus(const String16& service, int32_t status)
 {
     fprintf(stderr, "service '%s' status %d\n", String8(service).string(), status);
+    ALOGD("service '%s' status %d\n", String8(service).string(), status);
     return Status::ok();
 }
 
@@ -82,6 +84,7 @@
 StatusListener::onReportFinished()
 {
     fprintf(stderr, "done\n");
+    ALOGD("done\n");
     exit(0);
     return Status::ok();
 }
@@ -90,6 +93,7 @@
 StatusListener::onReportFailed()
 {
     fprintf(stderr, "failed\n");
+    ALOGD("failed\n");
     exit(1);
     return Status::ok();
 }
@@ -146,25 +150,50 @@
 
 // ================================================================================
 static int
-get_dest(const char* arg)
+get_privacy_policy(const char* arg)
 {
     if (strcmp(arg, "L") == 0
         || strcmp(arg, "LOCAL") == 0) {
-      return DEST_LOCAL;
+      return PRIVACY_POLICY_LOCAL;
     }
     if (strcmp(arg, "E") == 0
         || strcmp(arg, "EXPLICIT") == 0) {
-      return DEST_EXPLICIT;
+      return PRIVACY_POLICY_EXPLICIT;
     }
     if (strcmp(arg, "A") == 0
         || strcmp(arg, "AUTO") == 0
         || strcmp(arg, "AUTOMATIC") == 0) {
-      return DEST_AUTOMATIC;
+      return PRIVACY_POLICY_AUTOMATIC;
     }
     return -1; // return the default value
 }
 
 // ================================================================================
+static bool
+parse_receiver_arg(const string& arg, string* pkg, string* cls)
+{
+    if (arg.length() == 0) {
+        return true;
+    }
+    size_t slash = arg.find('/');
+    if (slash == string::npos) {
+        return false;
+    }
+    if (slash == 0 || slash == arg.length() - 1) {
+        return false;
+    }
+    if (arg.find('/', slash+1) != string::npos) {
+        return false;
+    }
+    pkg->assign(arg, 0, slash);
+    cls->assign(arg, slash+1);
+    if ((*cls)[0] == '.') {
+        *cls = (*pkg) + (*cls);
+    }
+    return true;
+}
+
+// ================================================================================
 static void
 usage(FILE* out)
 {
@@ -173,10 +202,13 @@
     fprintf(out, "Takes an incident report.\n");
     fprintf(out, "\n");
     fprintf(out, "OPTIONS\n");
+    fprintf(out, "  -l           list available sections\n");
+    fprintf(out, "  -p           privacy spec, LOCAL, EXPLICIT or AUTOMATIC. Default AUTOMATIC.\n");
+    fprintf(out, "\n");
+    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, "  -l           list available sections\n");
-    fprintf(out, "  -p           privacy spec, LOCAL, EXPLICIT or AUTOMATIC\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");
     fprintf(out, "\n");
@@ -187,12 +219,13 @@
 {
     Status status;
     IncidentReportArgs args;
-    enum { DEST_DROPBOX, DEST_STDOUT } destination = DEST_STDOUT;
-    int dest = -1; // default
+    enum { DEST_UNSET, DEST_DROPBOX, DEST_STDOUT, DEST_BROADCAST } destination = DEST_UNSET;
+    int privacyPolicy = PRIVACY_POLICY_AUTOMATIC;
+    string receiverArg;
 
     // Parse the args
     int opt;
-    while ((opt = getopt(argc, argv, "bhdlp:")) != -1) {
+    while ((opt = getopt(argc, argv, "bhdlp:s:")) != -1) {
         switch (opt) {
             case 'h':
                 usage(stdout);
@@ -201,13 +234,29 @@
                 section_list(stdout);
                 return 0;
             case 'b':
+                if (!(destination == DEST_UNSET || destination == DEST_STDOUT)) {
+                    usage(stderr);
+                    return 1;
+                }
                 destination = DEST_STDOUT;
                 break;
             case 'd':
+                if (!(destination == DEST_UNSET || destination == DEST_DROPBOX)) {
+                    usage(stderr);
+                    return 1;
+                }
                 destination = DEST_DROPBOX;
                 break;
             case 'p':
-                dest = get_dest(optarg);
+                privacyPolicy = get_privacy_policy(optarg);
+                break;
+            case 's':
+                if (destination != DEST_UNSET) {
+                    usage(stderr);
+                    return 1;
+                }
+                destination = DEST_BROADCAST;
+                receiverArg = optarg;
                 break;
             default:
                 usage(stderr);
@@ -215,6 +264,17 @@
         }
     }
 
+    string pkg;
+    string cls;
+    if (parse_receiver_arg(receiverArg, &pkg, &cls)) {
+        args.setReceiverPkg(pkg);
+        args.setReceiverCls(cls);
+    } else {
+        fprintf(stderr, "badly formatted -s package/class option: %s\n\n", receiverArg.c_str());
+        usage(stderr);
+        return 1;
+    }
+
     if (optind == argc) {
         args.setAll(true);
     } else {
@@ -236,7 +296,7 @@
             }
         }
     }
-    args.setDest(dest);
+    args.setPrivacyPolicy(privacyPolicy);
 
     // Start the thread pool.
     sp<ProcessState> ps(ProcessState::self());
@@ -272,12 +332,17 @@
         //IPCThreadState::self()->joinThreadPool();
 
         while (true) {
-            int amt = splice(fds[0], NULL, STDOUT_FILENO, NULL, 4096, 0);
-            fprintf(stderr, "spliced %d bytes\n", amt);
+            uint8_t buf[4096];
+            ssize_t amt = TEMP_FAILURE_RETRY(read(fds[0], buf, sizeof(buf)));
             if (amt < 0) {
-                return errno;
+                break;
             } else if (amt == 0) {
-                return 0;
+                break;
+            }
+
+            ssize_t wamt = TEMP_FAILURE_RETRY(write(STDOUT_FILENO, buf, amt));
+            if (wamt != amt) {
+                return errno;
             }
         }
     } else {