diff options
Diffstat (limited to 'cmds/incident/main.cpp')
-rw-r--r-- | cmds/incident/main.cpp | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/cmds/incident/main.cpp b/cmds/incident/main.cpp new file mode 100644 index 000000000000..91b7c22b2038 --- /dev/null +++ b/cmds/incident/main.cpp @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "incident" + +#include "incident_sections.h" + +#include <android/os/BnIncidentReportStatusListener.h> +#include <android/os/IIncidentManager.h> +#include <android/os/IncidentReportArgs.h> +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> +#include <utils/Looper.h> + +#include <fcntl.h> +#include <getopt.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +using namespace android; +using namespace android::base; +using namespace android::binder; +using namespace android::os; + +// ================================================================================ +class StatusListener : public BnIncidentReportStatusListener { +public: + StatusListener(); + virtual ~StatusListener(); + + virtual Status onReportStarted(); + virtual Status onReportSectionStatus(int32_t section, int32_t status); + virtual Status onReportServiceStatus(const String16& service, int32_t status); + virtual Status onReportFinished(); + virtual Status onReportFailed(); +}; + +StatusListener::StatusListener() +{ +} + +StatusListener::~StatusListener() +{ +} + +Status +StatusListener::onReportStarted() +{ + return Status::ok(); +} + +Status +StatusListener::onReportSectionStatus(int32_t section, int32_t status) +{ + fprintf(stderr, "section %d status %d\n", section, status); + return Status::ok(); +} + +Status +StatusListener::onReportServiceStatus(const String16& service, int32_t status) +{ + fprintf(stderr, "service '%s' status %d\n", String8(service).string(), status); + return Status::ok(); +} + +Status +StatusListener::onReportFinished() +{ + fprintf(stderr, "done\n"); + exit(0); + return Status::ok(); +} + +Status +StatusListener::onReportFailed() +{ + fprintf(stderr, "failed\n"); + exit(1); + return Status::ok(); +} + +// ================================================================================ +static IncidentSection const* +find_section(const char* name) +{ + size_t low = 0; + size_t high = INCIDENT_SECTION_COUNT - 1; + + while (low <= high) { + size_t mid = (low + high) >> 1; + IncidentSection const* section = INCIDENT_SECTIONS + mid; + + int cmp = strcmp(section->name, name); + if (cmp < 0) { + low = mid + 1; + } else if (cmp > 0) { + high = mid - 1; + } else { + return section; + } + } + return NULL; +} + +// ================================================================================ +static void +usage(FILE* out) +{ + fprintf(out, "usage: incident OPTIONS [SECTION...]\n"); + fprintf(out, "\n"); + fprintf(out, "Takes an incident report.\n"); + fprintf(out, "\n"); + fprintf(out, "OPTIONS\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, "\n"); + fprintf(out, " SECTION the field numbers of the incident report fields to include\n"); + fprintf(out, "\n"); +} + +int +main(int argc, char** argv) +{ + Status status; + IncidentReportArgs args; + enum { DEST_DROPBOX, DEST_STDOUT } destination = DEST_STDOUT; + + // Parse the args + int opt; + while ((opt = getopt(argc, argv, "bhd")) != -1) { + switch (opt) { + case 'b': + destination = DEST_STDOUT; + break; + case 'h': + usage(stdout); + return 0; + case 'd': + destination = DEST_DROPBOX; + break; + default: + usage(stderr); + return 1; + } + } + + if (optind == argc) { + args.setAll(true); + } else { + for (int i=optind; i<argc; i++) { + const char* arg = argv[i]; + char* end; + if (arg[0] != '\0') { + int section = strtol(arg, &end, 0); + if (*end == '\0') { + args.addSection(section); + } else { + IncidentSection const* ic = find_section(arg); + if (ic == NULL) { + fprintf(stderr, "Invalid section: %s\n", arg); + return 1; + } + args.addSection(ic->id); + } + } + } + } + + + + // Start the thread pool. + sp<ProcessState> ps(ProcessState::self()); + ps->startThreadPool(); + ps->giveThreadPoolName(); + + // Look up the service + sp<IIncidentManager> service = interface_cast<IIncidentManager>( + defaultServiceManager()->getService(android::String16("incident"))); + if (service == NULL) { + fprintf(stderr, "Couldn't look up the incident service\n"); + return 1; + } + + // Construct the stream + int fds[2]; + pipe(fds); + + unique_fd readEnd(fds[0]); + unique_fd writeEnd(fds[1]); + + if (destination == DEST_STDOUT) { + // Call into the service + sp<StatusListener> listener(new StatusListener()); + status = service->reportIncidentToStream(args, listener, writeEnd); + + if (!status.isOk()) { + fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().string()); + } + + // Wait for the result and print out the data they send. + //IPCThreadState::self()->joinThreadPool(); + + while (true) { + int amt = splice(fds[0], NULL, STDOUT_FILENO, NULL, 4096, 0); + fprintf(stderr, "spliced %d bytes\n", amt); + if (amt < 0) { + return errno; + } else if (amt == 0) { + return 0; + } + } + } else { + status = service->reportIncident(args); + if (!status.isOk()) { + fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().string()); + return 1; + } else { + return 0; + } + } + +} |