blob: 6e0bd06292746ef303387e5043b35fd5ac916916 [file] [log] [blame]
Joe Onorato1754d742016-11-21 17:51:35 -08001/*
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>
Joe Onorato5dfe3df2019-05-19 17:36:08 -070024#include <android/util/ProtoOutputStream.h>
Joe Onorato1754d742016-11-21 17:51:35 -080025#include <binder/IPCThreadState.h>
26#include <binder/IServiceManager.h>
27#include <utils/Looper.h>
28
Yi Jin0f047162017-09-05 13:44:22 -070029#include <cstring>
Joe Onorato1754d742016-11-21 17:51:35 -080030#include <fcntl.h>
31#include <getopt.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <unistd.h>
35
36using namespace android;
37using namespace android::base;
38using namespace android::binder;
39using namespace android::os;
Joe Onorato5dfe3df2019-05-19 17:36:08 -070040using android::util::FIELD_COUNT_SINGLE;
41using android::util::FIELD_TYPE_STRING;
42using android::util::ProtoOutputStream;
Joe Onorato1754d742016-11-21 17:51:35 -080043
44// ================================================================================
45class StatusListener : public BnIncidentReportStatusListener {
46public:
47 StatusListener();
48 virtual ~StatusListener();
49
50 virtual Status onReportStarted();
51 virtual Status onReportSectionStatus(int32_t section, int32_t status);
52 virtual Status onReportServiceStatus(const String16& service, int32_t status);
53 virtual Status onReportFinished();
54 virtual Status onReportFailed();
Boleyn Su1c8ed242020-02-27 03:22:53 +090055
56 int getExitCodeOrElse(int defaultCode);
57 private:
58 int mExitCode;
Joe Onorato1754d742016-11-21 17:51:35 -080059};
60
Boleyn Su1c8ed242020-02-27 03:22:53 +090061StatusListener::StatusListener(): mExitCode(-1)
Joe Onorato1754d742016-11-21 17:51:35 -080062{
63}
64
65StatusListener::~StatusListener()
66{
67}
68
69Status
70StatusListener::onReportStarted()
71{
72 return Status::ok();
73}
74
75Status
76StatusListener::onReportSectionStatus(int32_t section, int32_t status)
77{
78 fprintf(stderr, "section %d status %d\n", section, status);
Joe Onorato99598ee2019-02-11 15:55:13 +000079 ALOGD("section %d status %d\n", section, status);
Joe Onorato1754d742016-11-21 17:51:35 -080080 return Status::ok();
81}
82
83Status
84StatusListener::onReportServiceStatus(const String16& service, int32_t status)
85{
86 fprintf(stderr, "service '%s' status %d\n", String8(service).string(), status);
Joe Onorato99598ee2019-02-11 15:55:13 +000087 ALOGD("service '%s' status %d\n", String8(service).string(), status);
Joe Onorato1754d742016-11-21 17:51:35 -080088 return Status::ok();
89}
90
91Status
92StatusListener::onReportFinished()
93{
94 fprintf(stderr, "done\n");
Joe Onorato99598ee2019-02-11 15:55:13 +000095 ALOGD("done\n");
Boleyn Su1c8ed242020-02-27 03:22:53 +090096 mExitCode = 0;
Joe Onorato1754d742016-11-21 17:51:35 -080097 return Status::ok();
98}
99
100Status
101StatusListener::onReportFailed()
102{
103 fprintf(stderr, "failed\n");
Joe Onorato99598ee2019-02-11 15:55:13 +0000104 ALOGD("failed\n");
Boleyn Su1c8ed242020-02-27 03:22:53 +0900105 mExitCode = 1;
Joe Onorato1754d742016-11-21 17:51:35 -0800106 return Status::ok();
107}
108
Boleyn Su1c8ed242020-02-27 03:22:53 +0900109int
110StatusListener::getExitCodeOrElse(int defaultCode) {
111 return mExitCode == -1 ? defaultCode : mExitCode;
112}
113
Joe Onorato1754d742016-11-21 17:51:35 -0800114// ================================================================================
Yi Jin0a3406f2017-06-22 19:23:11 -0700115static void section_list(FILE* out) {
116 IncidentSection sections[INCIDENT_SECTION_COUNT];
117 int i = 0;
118 int j = 0;
119 // sort the sections based on id
120 while (i < INCIDENT_SECTION_COUNT) {
121 IncidentSection curr = INCIDENT_SECTIONS[i];
122 for (int k = 0; k < j; k++) {
123 if (curr.id > sections[k].id) {
124 continue;
125 }
126 IncidentSection tmp = curr;
127 curr = sections[k];
128 sections[k] = tmp;
129 }
130 sections[j] = curr;
131 i++;
132 j++;
133 }
134
135 fprintf(out, "available sections:\n");
136 for (int i = 0; i < INCIDENT_SECTION_COUNT; ++i) {
137 fprintf(out, "id: %4d, name: %s\n", sections[i].id, sections[i].name);
138 }
139}
140
141// ================================================================================
Joe Onorato1754d742016-11-21 17:51:35 -0800142static IncidentSection const*
143find_section(const char* name)
144{
Joe Onorato3864a342019-05-19 20:51:47 -0700145 ssize_t low = 0;
146 ssize_t high = INCIDENT_SECTION_COUNT - 1;
Joe Onorato1754d742016-11-21 17:51:35 -0800147
148 while (low <= high) {
Joe Onorato3864a342019-05-19 20:51:47 -0700149 ssize_t mid = (low + high) / 2;
Joe Onorato1754d742016-11-21 17:51:35 -0800150 IncidentSection const* section = INCIDENT_SECTIONS + mid;
151
152 int cmp = strcmp(section->name, name);
153 if (cmp < 0) {
154 low = mid + 1;
155 } else if (cmp > 0) {
156 high = mid - 1;
157 } else {
158 return section;
159 }
160 }
161 return NULL;
162}
163
164// ================================================================================
Yi Jin0f047162017-09-05 13:44:22 -0700165static int
Joe Onorato99598ee2019-02-11 15:55:13 +0000166get_privacy_policy(const char* arg)
Yi Jin0f047162017-09-05 13:44:22 -0700167{
Yi Jinb8344dc2018-01-24 17:33:35 -0800168 if (strcmp(arg, "L") == 0
169 || strcmp(arg, "LOCAL") == 0) {
Joe Onorato99598ee2019-02-11 15:55:13 +0000170 return PRIVACY_POLICY_LOCAL;
Yi Jinb8344dc2018-01-24 17:33:35 -0800171 }
172 if (strcmp(arg, "E") == 0
173 || strcmp(arg, "EXPLICIT") == 0) {
Joe Onorato99598ee2019-02-11 15:55:13 +0000174 return PRIVACY_POLICY_EXPLICIT;
Yi Jinb8344dc2018-01-24 17:33:35 -0800175 }
176 if (strcmp(arg, "A") == 0
177 || strcmp(arg, "AUTO") == 0
178 || strcmp(arg, "AUTOMATIC") == 0) {
Joe Onorato99598ee2019-02-11 15:55:13 +0000179 return PRIVACY_POLICY_AUTOMATIC;
Yi Jinb8344dc2018-01-24 17:33:35 -0800180 }
Yi Jin0f047162017-09-05 13:44:22 -0700181 return -1; // return the default value
182}
183
184// ================================================================================
Joe Onorato99598ee2019-02-11 15:55:13 +0000185static bool
186parse_receiver_arg(const string& arg, string* pkg, string* cls)
187{
188 if (arg.length() == 0) {
189 return true;
190 }
191 size_t slash = arg.find('/');
192 if (slash == string::npos) {
193 return false;
194 }
195 if (slash == 0 || slash == arg.length() - 1) {
196 return false;
197 }
198 if (arg.find('/', slash+1) != string::npos) {
199 return false;
200 }
201 pkg->assign(arg, 0, slash);
202 cls->assign(arg, slash+1);
203 if ((*cls)[0] == '.') {
204 *cls = (*pkg) + (*cls);
205 }
206 return true;
207}
208
209// ================================================================================
Mike Ma5a57d792019-08-21 14:52:46 -0700210static int
211stream_output(const int read_fd, const int write_fd) {
212 while (true) {
Boleyn Su1c8ed242020-02-27 03:22:53 +0900213 int amt = splice(read_fd, NULL, write_fd, NULL, 4096, 0);
Mike Ma5a57d792019-08-21 14:52:46 -0700214 if (amt < 0) {
Mike Ma5a57d792019-08-21 14:52:46 -0700215 return errno;
Boleyn Su1c8ed242020-02-27 03:22:53 +0900216 } else if (amt == 0) {
217 return 0;
Mike Ma5a57d792019-08-21 14:52:46 -0700218 }
219 }
Mike Ma5a57d792019-08-21 14:52:46 -0700220}
221
222// ================================================================================
Joe Onorato1754d742016-11-21 17:51:35 -0800223static void
224usage(FILE* out)
225{
226 fprintf(out, "usage: incident OPTIONS [SECTION...]\n");
227 fprintf(out, "\n");
228 fprintf(out, "Takes an incident report.\n");
229 fprintf(out, "\n");
230 fprintf(out, "OPTIONS\n");
Joe Onorato99598ee2019-02-11 15:55:13 +0000231 fprintf(out, " -l list available sections\n");
232 fprintf(out, " -p privacy spec, LOCAL, EXPLICIT or AUTOMATIC. Default AUTOMATIC.\n");
Mike Ma5a57d792019-08-21 14:52:46 -0700233 fprintf(out, " -r REASON human readable description of why the report is taken.\n");
Mike Mab6f7c472020-03-03 17:58:35 -0800234 fprintf(out, " -z gzip the incident report, i.e. pipe the output through gzip.\n");
Joe Onorato99598ee2019-02-11 15:55:13 +0000235 fprintf(out, "\n");
236 fprintf(out, "and one of these destinations:\n");
Joe Onorato1754d742016-11-21 17:51:35 -0800237 fprintf(out, " -b (default) print the report to stdout (in proto format)\n");
238 fprintf(out, " -d send the report into dropbox\n");
Mike Ma5a57d792019-08-21 14:52:46 -0700239 fprintf(out, " -u print a full report to stdout for dumpstate to zip as a bug\n");
240 fprintf(out, " report. SECTION is ignored. Should only be called by dumpstate.\n");
Joe Onorato99598ee2019-02-11 15:55:13 +0000241 fprintf(out, " -s PKG/CLS send broadcast to the broadcast receiver.\n");
Joe Onorato1754d742016-11-21 17:51:35 -0800242 fprintf(out, "\n");
243 fprintf(out, " SECTION the field numbers of the incident report fields to include\n");
244 fprintf(out, "\n");
245}
246
247int
248main(int argc, char** argv)
249{
250 Status status;
251 IncidentReportArgs args;
Mike Ma5a57d792019-08-21 14:52:46 -0700252 enum { DEST_UNSET, DEST_DROPBOX, DEST_STDOUT, DEST_BROADCAST, DEST_DUMPSTATE } destination = DEST_UNSET;
Joe Onorato99598ee2019-02-11 15:55:13 +0000253 int privacyPolicy = PRIVACY_POLICY_AUTOMATIC;
Joe Onorato5dfe3df2019-05-19 17:36:08 -0700254 string reason;
Joe Onorato99598ee2019-02-11 15:55:13 +0000255 string receiverArg;
Joe Onorato1754d742016-11-21 17:51:35 -0800256
257 // Parse the args
258 int opt;
Mike Mab6f7c472020-03-03 17:58:35 -0800259 while ((opt = getopt(argc, argv, "bhdlp:r:s:uz")) != -1) {
Joe Onorato1754d742016-11-21 17:51:35 -0800260 switch (opt) {
Joe Onorato1754d742016-11-21 17:51:35 -0800261 case 'h':
262 usage(stdout);
263 return 0;
Yi Jin0a3406f2017-06-22 19:23:11 -0700264 case 'l':
265 section_list(stdout);
266 return 0;
267 case 'b':
Joe Onorato99598ee2019-02-11 15:55:13 +0000268 if (!(destination == DEST_UNSET || destination == DEST_STDOUT)) {
269 usage(stderr);
270 return 1;
271 }
Yi Jin0a3406f2017-06-22 19:23:11 -0700272 destination = DEST_STDOUT;
273 break;
Joe Onorato1754d742016-11-21 17:51:35 -0800274 case 'd':
Joe Onorato99598ee2019-02-11 15:55:13 +0000275 if (!(destination == DEST_UNSET || destination == DEST_DROPBOX)) {
276 usage(stderr);
277 return 1;
278 }
Joe Onorato1754d742016-11-21 17:51:35 -0800279 destination = DEST_DROPBOX;
280 break;
Mike Ma5a57d792019-08-21 14:52:46 -0700281 case 'u':
282 if (!(destination == DEST_UNSET || destination == DEST_DUMPSTATE)) {
283 usage(stderr);
284 return 1;
285 }
286 destination = DEST_DUMPSTATE;
287 break;
Yi Jin0f047162017-09-05 13:44:22 -0700288 case 'p':
Joe Onorato99598ee2019-02-11 15:55:13 +0000289 privacyPolicy = get_privacy_policy(optarg);
290 break;
Joe Onorato5dfe3df2019-05-19 17:36:08 -0700291 case 'r':
292 if (reason.size() > 0) {
293 usage(stderr);
294 return 1;
295 }
296 reason = optarg;
297 break;
Joe Onorato99598ee2019-02-11 15:55:13 +0000298 case 's':
299 if (destination != DEST_UNSET) {
300 usage(stderr);
301 return 1;
302 }
303 destination = DEST_BROADCAST;
304 receiverArg = optarg;
Yi Jin0f047162017-09-05 13:44:22 -0700305 break;
Mike Mab6f7c472020-03-03 17:58:35 -0800306 case 'z':
307 args.setGzip(true);
308 break;
Joe Onorato1754d742016-11-21 17:51:35 -0800309 default:
310 usage(stderr);
311 return 1;
312 }
313 }
Joe Onoratoe5472052019-04-24 16:27:33 -0700314 if (destination == DEST_UNSET) {
315 destination = DEST_STDOUT;
316 }
Joe Onorato1754d742016-11-21 17:51:35 -0800317
Joe Onorato99598ee2019-02-11 15:55:13 +0000318 string pkg;
319 string cls;
320 if (parse_receiver_arg(receiverArg, &pkg, &cls)) {
321 args.setReceiverPkg(pkg);
322 args.setReceiverCls(cls);
323 } else {
324 fprintf(stderr, "badly formatted -s package/class option: %s\n\n", receiverArg.c_str());
325 usage(stderr);
326 return 1;
327 }
328
Joe Onorato1754d742016-11-21 17:51:35 -0800329 if (optind == argc) {
330 args.setAll(true);
331 } else {
332 for (int i=optind; i<argc; i++) {
333 const char* arg = argv[i];
334 char* end;
335 if (arg[0] != '\0') {
336 int section = strtol(arg, &end, 0);
337 if (*end == '\0') {
338 args.addSection(section);
339 } else {
340 IncidentSection const* ic = find_section(arg);
341 if (ic == NULL) {
Joe Onorato3864a342019-05-19 20:51:47 -0700342 ALOGD("Invalid section: %s\n", arg);
Joe Onorato1754d742016-11-21 17:51:35 -0800343 fprintf(stderr, "Invalid section: %s\n", arg);
344 return 1;
345 }
346 args.addSection(ic->id);
347 }
348 }
349 }
350 }
Joe Onorato99598ee2019-02-11 15:55:13 +0000351 args.setPrivacyPolicy(privacyPolicy);
Joe Onorato1754d742016-11-21 17:51:35 -0800352
Joe Onorato5dfe3df2019-05-19 17:36:08 -0700353 if (reason.size() > 0) {
354 ProtoOutputStream proto;
355 proto.write(/* reason field id */ 2 | FIELD_TYPE_STRING | FIELD_COUNT_SINGLE, reason);
356 vector<uint8_t> header;
357 proto.serializeToVector(&header);
358 args.addHeader(header);
359 }
360
Joe Onorato1754d742016-11-21 17:51:35 -0800361 // Start the thread pool.
362 sp<ProcessState> ps(ProcessState::self());
363 ps->startThreadPool();
364 ps->giveThreadPoolName();
365
366 // Look up the service
367 sp<IIncidentManager> service = interface_cast<IIncidentManager>(
368 defaultServiceManager()->getService(android::String16("incident")));
369 if (service == NULL) {
370 fprintf(stderr, "Couldn't look up the incident service\n");
371 return 1;
372 }
373
374 // Construct the stream
375 int fds[2];
376 pipe(fds);
377
378 unique_fd readEnd(fds[0]);
379 unique_fd writeEnd(fds[1]);
380
381 if (destination == DEST_STDOUT) {
382 // Call into the service
383 sp<StatusListener> listener(new StatusListener());
Jiyong Parkb8ba2342019-11-25 11:03:38 +0900384 status = service->reportIncidentToStream(args, listener, std::move(writeEnd));
Joe Onorato1754d742016-11-21 17:51:35 -0800385
386 if (!status.isOk()) {
387 fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().string());
Yi Jin603f3b32017-08-03 18:50:48 -0700388 return 1;
Joe Onorato1754d742016-11-21 17:51:35 -0800389 }
390
391 // Wait for the result and print out the data they send.
392 //IPCThreadState::self()->joinThreadPool();
Boleyn Su1c8ed242020-02-27 03:22:53 +0900393 return listener->getExitCodeOrElse(stream_output(fds[0], STDOUT_FILENO));
Mike Ma5a57d792019-08-21 14:52:46 -0700394 } else if (destination == DEST_DUMPSTATE) {
395 // Call into the service
396 sp<StatusListener> listener(new StatusListener());
Jiyong Parkb8ba2342019-11-25 11:03:38 +0900397 status = service->reportIncidentToDumpstate(std::move(writeEnd), listener);
Mike Ma5a57d792019-08-21 14:52:46 -0700398 if (!status.isOk()) {
399 fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().string());
400 return 1;
Joe Onorato1754d742016-11-21 17:51:35 -0800401 }
Boleyn Su1c8ed242020-02-27 03:22:53 +0900402 return listener->getExitCodeOrElse(stream_output(fds[0], STDOUT_FILENO));
Joe Onorato1754d742016-11-21 17:51:35 -0800403 } else {
404 status = service->reportIncident(args);
405 if (!status.isOk()) {
406 fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().string());
407 return 1;
408 } else {
409 return 0;
410 }
411 }
412
413}