1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#define LOG_TAG "incident" 18 19#include "incident_sections.h" 20 21#include <android/os/BnIncidentReportStatusListener.h> 22#include <android/os/IIncidentManager.h> 23#include <android/os/IncidentReportArgs.h> 24#include <binder/IPCThreadState.h> 25#include <binder/IServiceManager.h> 26#include <utils/Looper.h> 27 28#include <fcntl.h> 29#include <getopt.h> 30#include <stdio.h> 31#include <stdlib.h> 32#include <unistd.h> 33 34using namespace android; 35using namespace android::base; 36using namespace android::binder; 37using namespace android::os; 38 39// ================================================================================ 40class StatusListener : public BnIncidentReportStatusListener { 41public: 42 StatusListener(); 43 virtual ~StatusListener(); 44 45 virtual Status onReportStarted(); 46 virtual Status onReportSectionStatus(int32_t section, int32_t status); 47 virtual Status onReportServiceStatus(const String16& service, int32_t status); 48 virtual Status onReportFinished(); 49 virtual Status onReportFailed(); 50}; 51 52StatusListener::StatusListener() 53{ 54} 55 56StatusListener::~StatusListener() 57{ 58} 59 60Status 61StatusListener::onReportStarted() 62{ 63 return Status::ok(); 64} 65 66Status 67StatusListener::onReportSectionStatus(int32_t section, int32_t status) 68{ 69 fprintf(stderr, "section %d status %d\n", section, status); 70 return Status::ok(); 71} 72 73Status 74StatusListener::onReportServiceStatus(const String16& service, int32_t status) 75{ 76 fprintf(stderr, "service '%s' status %d\n", String8(service).string(), status); 77 return Status::ok(); 78} 79 80Status 81StatusListener::onReportFinished() 82{ 83 fprintf(stderr, "done\n"); 84 exit(0); 85 return Status::ok(); 86} 87 88Status 89StatusListener::onReportFailed() 90{ 91 fprintf(stderr, "failed\n"); 92 exit(1); 93 return Status::ok(); 94} 95 96// ================================================================================ 97static IncidentSection const* 98find_section(const char* name) 99{ 100 size_t low = 0; 101 size_t high = INCIDENT_SECTION_COUNT - 1; 102 103 while (low <= high) { 104 size_t mid = (low + high) >> 1; 105 IncidentSection const* section = INCIDENT_SECTIONS + mid; 106 107 int cmp = strcmp(section->name, name); 108 if (cmp < 0) { 109 low = mid + 1; 110 } else if (cmp > 0) { 111 high = mid - 1; 112 } else { 113 return section; 114 } 115 } 116 return NULL; 117} 118 119// ================================================================================ 120static void 121usage(FILE* out) 122{ 123 fprintf(out, "usage: incident OPTIONS [SECTION...]\n"); 124 fprintf(out, "\n"); 125 fprintf(out, "Takes an incident report.\n"); 126 fprintf(out, "\n"); 127 fprintf(out, "OPTIONS\n"); 128 fprintf(out, " -b (default) print the report to stdout (in proto format)\n"); 129 fprintf(out, " -d send the report into dropbox\n"); 130 fprintf(out, "\n"); 131 fprintf(out, " SECTION the field numbers of the incident report fields to include\n"); 132 fprintf(out, "\n"); 133} 134 135int 136main(int argc, char** argv) 137{ 138 Status status; 139 IncidentReportArgs args; 140 enum { DEST_DROPBOX, DEST_STDOUT } destination = DEST_STDOUT; 141 142 // Parse the args 143 int opt; 144 while ((opt = getopt(argc, argv, "bhd")) != -1) { 145 switch (opt) { 146 case 'b': 147 destination = DEST_STDOUT; 148 break; 149 case 'h': 150 usage(stdout); 151 return 0; 152 case 'd': 153 destination = DEST_DROPBOX; 154 break; 155 default: 156 usage(stderr); 157 return 1; 158 } 159 } 160 161 if (optind == argc) { 162 args.setAll(true); 163 } else { 164 for (int i=optind; i<argc; i++) { 165 const char* arg = argv[i]; 166 char* end; 167 if (arg[0] != '\0') { 168 int section = strtol(arg, &end, 0); 169 if (*end == '\0') { 170 args.addSection(section); 171 } else { 172 IncidentSection const* ic = find_section(arg); 173 if (ic == NULL) { 174 fprintf(stderr, "Invalid section: %s\n", arg); 175 return 1; 176 } 177 args.addSection(ic->id); 178 } 179 } 180 } 181 } 182 183 184 185 // Start the thread pool. 186 sp<ProcessState> ps(ProcessState::self()); 187 ps->startThreadPool(); 188 ps->giveThreadPoolName(); 189 190 // Look up the service 191 sp<IIncidentManager> service = interface_cast<IIncidentManager>( 192 defaultServiceManager()->getService(android::String16("incident"))); 193 if (service == NULL) { 194 fprintf(stderr, "Couldn't look up the incident service\n"); 195 return 1; 196 } 197 198 // Construct the stream 199 int fds[2]; 200 pipe(fds); 201 202 unique_fd readEnd(fds[0]); 203 unique_fd writeEnd(fds[1]); 204 205 if (destination == DEST_STDOUT) { 206 // Call into the service 207 sp<StatusListener> listener(new StatusListener()); 208 status = service->reportIncidentToStream(args, listener, writeEnd); 209 210 if (!status.isOk()) { 211 fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().string()); 212 } 213 214 // Wait for the result and print out the data they send. 215 //IPCThreadState::self()->joinThreadPool(); 216 217 while (true) { 218 int amt = splice(fds[0], NULL, STDOUT_FILENO, NULL, 4096, 0); 219 fprintf(stderr, "spliced %d bytes\n", amt); 220 if (amt < 0) { 221 return errno; 222 } else if (amt == 0) { 223 return 0; 224 } 225 } 226 } else { 227 status = service->reportIncident(args); 228 if (!status.isOk()) { 229 fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().string()); 230 return 1; 231 } else { 232 return 0; 233 } 234 } 235 236} 237