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 {