blob: eb2b98a666b9caebf5c551f03216d30176ed1922 [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();
55};
56
57StatusListener::StatusListener()
58{
59}
60
61StatusListener::~StatusListener()
62{
63}
64
65Status
66StatusListener::onReportStarted()
67{
68 return Status::ok();
69}
70
71Status
72StatusListener::onReportSectionStatus(int32_t section, int32_t status)
73{
74 fprintf(stderr, "section %d status %d\n", section, status);
Joe Onorato99598ee2019-02-11 15:55:13 +000075 ALOGD("section %d status %d\n", section, status);
Joe Onorato1754d742016-11-21 17:51:35 -080076 return Status::ok();
77}
78
79Status
80StatusListener::onReportServiceStatus(const String16& service, int32_t status)
81{
82 fprintf(stderr, "service '%s' status %d\n", String8(service).string(), status);
Joe Onorato99598ee2019-02-11 15:55:13 +000083 ALOGD("service '%s' status %d\n", String8(service).string(), status);
Joe Onorato1754d742016-11-21 17:51:35 -080084 return Status::ok();
85}
86
87Status
88StatusListener::onReportFinished()
89{
90 fprintf(stderr, "done\n");
Joe Onorato99598ee2019-02-11 15:55:13 +000091 ALOGD("done\n");
Joe Onorato1754d742016-11-21 17:51:35 -080092 exit(0);
93 return Status::ok();
94}
95
96Status
97StatusListener::onReportFailed()
98{
99 fprintf(stderr, "failed\n");
Joe Onorato99598ee2019-02-11 15:55:13 +0000100 ALOGD("failed\n");
Joe Onorato1754d742016-11-21 17:51:35 -0800101 exit(1);
102 return Status::ok();
103}
104
105// ================================================================================
Yi Jin0a3406f2017-06-22 19:23:11 -0700106static void section_list(FILE* out) {
107 IncidentSection sections[INCIDENT_SECTION_COUNT];
108 int i = 0;
109 int j = 0;
110 // sort the sections based on id
111 while (i < INCIDENT_SECTION_COUNT) {
112 IncidentSection curr = INCIDENT_SECTIONS[i];
113 for (int k = 0; k < j; k++) {
114 if (curr.id > sections[k].id) {
115 continue;
116 }
117 IncidentSection tmp = curr;
118 curr = sections[k];
119 sections[k] = tmp;
120 }
121 sections[j] = curr;
122 i++;
123 j++;
124 }
125
126 fprintf(out, "available sections:\n");
127 for (int i = 0; i < INCIDENT_SECTION_COUNT; ++i) {
128 fprintf(out, "id: %4d, name: %s\n", sections[i].id, sections[i].name);
129 }
130}
131
132// ================================================================================
Joe Onorato1754d742016-11-21 17:51:35 -0800133static IncidentSection const*
134find_section(const char* name)
135{
Joe Onorato3864a342019-05-19 20:51:47 -0700136 ssize_t low = 0;
137 ssize_t high = INCIDENT_SECTION_COUNT - 1;
Joe Onorato1754d742016-11-21 17:51:35 -0800138
139 while (low <= high) {
Joe Onorato3864a342019-05-19 20:51:47 -0700140 ssize_t mid = (low + high) / 2;
Joe Onorato1754d742016-11-21 17:51:35 -0800141 IncidentSection const* section = INCIDENT_SECTIONS + mid;
142
143 int cmp = strcmp(section->name, name);
144 if (cmp < 0) {
145 low = mid + 1;
146 } else if (cmp > 0) {
147 high = mid - 1;
148 } else {
149 return section;
150 }
151 }
152 return NULL;
153}
154
155// ================================================================================
Yi Jin0f047162017-09-05 13:44:22 -0700156static int
Joe Onorato99598ee2019-02-11 15:55:13 +0000157get_privacy_policy(const char* arg)
Yi Jin0f047162017-09-05 13:44:22 -0700158{
Yi Jinb8344dc2018-01-24 17:33:35 -0800159 if (strcmp(arg, "L") == 0
160 || strcmp(arg, "LOCAL") == 0) {
Joe Onorato99598ee2019-02-11 15:55:13 +0000161 return PRIVACY_POLICY_LOCAL;
Yi Jinb8344dc2018-01-24 17:33:35 -0800162 }
163 if (strcmp(arg, "E") == 0
164 || strcmp(arg, "EXPLICIT") == 0) {
Joe Onorato99598ee2019-02-11 15:55:13 +0000165 return PRIVACY_POLICY_EXPLICIT;
Yi Jinb8344dc2018-01-24 17:33:35 -0800166 }
167 if (strcmp(arg, "A") == 0
168 || strcmp(arg, "AUTO") == 0
169 || strcmp(arg, "AUTOMATIC") == 0) {
Joe Onorato99598ee2019-02-11 15:55:13 +0000170 return PRIVACY_POLICY_AUTOMATIC;
Yi Jinb8344dc2018-01-24 17:33:35 -0800171 }
Yi Jin0f047162017-09-05 13:44:22 -0700172 return -1; // return the default value
173}
174
175// ================================================================================
Joe Onorato99598ee2019-02-11 15:55:13 +0000176static bool
177parse_receiver_arg(const string& arg, string* pkg, string* cls)
178{
179 if (arg.length() == 0) {
180 return true;
181 }
182 size_t slash = arg.find('/');
183 if (slash == string::npos) {
184 return false;
185 }
186 if (slash == 0 || slash == arg.length() - 1) {
187 return false;
188 }
189 if (arg.find('/', slash+1) != string::npos) {
190 return false;
191 }
192 pkg->assign(arg, 0, slash);
193 cls->assign(arg, slash+1);
194 if ((*cls)[0] == '.') {
195 *cls = (*pkg) + (*cls);
196 }
197 return true;
198}
199
200// ================================================================================
Mike Ma15f83a32019-08-21 14:52:46 -0700201static int
202stream_output(const int read_fd, const int write_fd) {
203 while (true) {
204 uint8_t buf[4096];
205 ssize_t amt = TEMP_FAILURE_RETRY(read(read_fd, buf, sizeof(buf)));
206 if (amt < 0) {
207 break;
208 } else if (amt == 0) {
209 break;
210 }
211
212 ssize_t wamt = TEMP_FAILURE_RETRY(write(write_fd, buf, amt));
213 if (wamt != amt) {
214 return errno;
215 }
216 }
217 return 0;
218}
219
220// ================================================================================
Joe Onorato1754d742016-11-21 17:51:35 -0800221static void
222usage(FILE* out)
223{
224 fprintf(out, "usage: incident OPTIONS [SECTION...]\n");
225 fprintf(out, "\n");
226 fprintf(out, "Takes an incident report.\n");
227 fprintf(out, "\n");
228 fprintf(out, "OPTIONS\n");
Joe Onorato99598ee2019-02-11 15:55:13 +0000229 fprintf(out, " -l list available sections\n");
230 fprintf(out, " -p privacy spec, LOCAL, EXPLICIT or AUTOMATIC. Default AUTOMATIC.\n");
Mike Ma15f83a32019-08-21 14:52:46 -0700231 fprintf(out, " -r REASON human readable description of why the report is taken.\n");
Joe Onorato99598ee2019-02-11 15:55:13 +0000232 fprintf(out, "\n");
233 fprintf(out, "and one of these destinations:\n");
Joe Onorato1754d742016-11-21 17:51:35 -0800234 fprintf(out, " -b (default) print the report to stdout (in proto format)\n");
235 fprintf(out, " -d send the report into dropbox\n");
Mike Ma15f83a32019-08-21 14:52:46 -0700236 fprintf(out, " -u print a full report to stdout for dumpstate to zip as a bug\n");
237 fprintf(out, " report. SECTION is ignored. Should only be called by dumpstate.\n");
Joe Onorato99598ee2019-02-11 15:55:13 +0000238 fprintf(out, " -s PKG/CLS send broadcast to the broadcast receiver.\n");
Joe Onorato1754d742016-11-21 17:51:35 -0800239 fprintf(out, "\n");
240 fprintf(out, " SECTION the field numbers of the incident report fields to include\n");
241 fprintf(out, "\n");
242}
243
244int
245main(int argc, char** argv)
246{
247 Status status;
248 IncidentReportArgs args;
Mike Ma15f83a32019-08-21 14:52:46 -0700249 enum { DEST_UNSET, DEST_DROPBOX, DEST_STDOUT, DEST_BROADCAST, DEST_DUMPSTATE } destination = DEST_UNSET;
Joe Onorato99598ee2019-02-11 15:55:13 +0000250 int privacyPolicy = PRIVACY_POLICY_AUTOMATIC;
Joe Onorato5dfe3df2019-05-19 17:36:08 -0700251 string reason;
Joe Onorato99598ee2019-02-11 15:55:13 +0000252 string receiverArg;
Joe Onorato1754d742016-11-21 17:51:35 -0800253
254 // Parse the args
255 int opt;
Mike Ma15f83a32019-08-21 14:52:46 -0700256 while ((opt = getopt(argc, argv, "bhdlp:r:s:u")) != -1) {
Joe Onorato1754d742016-11-21 17:51:35 -0800257 switch (opt) {
Joe Onorato1754d742016-11-21 17:51:35 -0800258 case 'h':
259 usage(stdout);
260 return 0;
Yi Jin0a3406f2017-06-22 19:23:11 -0700261 case 'l':
262 section_list(stdout);
263 return 0;
264 case 'b':
Joe Onorato99598ee2019-02-11 15:55:13 +0000265 if (!(destination == DEST_UNSET || destination == DEST_STDOUT)) {
266 usage(stderr);
267 return 1;
268 }
Yi Jin0a3406f2017-06-22 19:23:11 -0700269 destination = DEST_STDOUT;
270 break;
Joe Onorato1754d742016-11-21 17:51:35 -0800271 case 'd':
Joe Onorato99598ee2019-02-11 15:55:13 +0000272 if (!(destination == DEST_UNSET || destination == DEST_DROPBOX)) {
273 usage(stderr);
274 return 1;
275 }
Joe Onorato1754d742016-11-21 17:51:35 -0800276 destination = DEST_DROPBOX;
277 break;
Mike Ma15f83a32019-08-21 14:52:46 -0700278 case 'u':
279 if (!(destination == DEST_UNSET || destination == DEST_DUMPSTATE)) {
280 usage(stderr);
281 return 1;
282 }
283 destination = DEST_DUMPSTATE;
284 break;
Yi Jin0f047162017-09-05 13:44:22 -0700285 case 'p':
Joe Onorato99598ee2019-02-11 15:55:13 +0000286 privacyPolicy = get_privacy_policy(optarg);
287 break;
Joe Onorato5dfe3df2019-05-19 17:36:08 -0700288 case 'r':
289 if (reason.size() > 0) {
290 usage(stderr);
291 return 1;
292 }
293 reason = optarg;
294 break;
Joe Onorato99598ee2019-02-11 15:55:13 +0000295 case 's':
296 if (destination != DEST_UNSET) {
297 usage(stderr);
298 return 1;
299 }
300 destination = DEST_BROADCAST;
301 receiverArg = optarg;
Yi Jin0f047162017-09-05 13:44:22 -0700302 break;
Joe Onorato1754d742016-11-21 17:51:35 -0800303 default:
304 usage(stderr);
305 return 1;
306 }
307 }
Joe Onoratoe5472052019-04-24 16:27:33 -0700308 if (destination == DEST_UNSET) {
309 destination = DEST_STDOUT;
310 }
Joe Onorato1754d742016-11-21 17:51:35 -0800311
Joe Onorato99598ee2019-02-11 15:55:13 +0000312 string pkg;
313 string cls;
314 if (parse_receiver_arg(receiverArg, &pkg, &cls)) {
315 args.setReceiverPkg(pkg);
316 args.setReceiverCls(cls);
317 } else {
318 fprintf(stderr, "badly formatted -s package/class option: %s\n\n", receiverArg.c_str());
319 usage(stderr);
320 return 1;
321 }
322
Joe Onorato1754d742016-11-21 17:51:35 -0800323 if (optind == argc) {
324 args.setAll(true);
325 } else {
326 for (int i=optind; i<argc; i++) {
327 const char* arg = argv[i];
328 char* end;
329 if (arg[0] != '\0') {
330 int section = strtol(arg, &end, 0);
331 if (*end == '\0') {
332 args.addSection(section);
333 } else {
334 IncidentSection const* ic = find_section(arg);
335 if (ic == NULL) {
Joe Onorato3864a342019-05-19 20:51:47 -0700336 ALOGD("Invalid section: %s\n", arg);
Joe Onorato1754d742016-11-21 17:51:35 -0800337 fprintf(stderr, "Invalid section: %s\n", arg);
338 return 1;
339 }
340 args.addSection(ic->id);
341 }
342 }
343 }
344 }
Joe Onorato99598ee2019-02-11 15:55:13 +0000345 args.setPrivacyPolicy(privacyPolicy);
Joe Onorato1754d742016-11-21 17:51:35 -0800346
Joe Onorato5dfe3df2019-05-19 17:36:08 -0700347 if (reason.size() > 0) {
348 ProtoOutputStream proto;
349 proto.write(/* reason field id */ 2 | FIELD_TYPE_STRING | FIELD_COUNT_SINGLE, reason);
350 vector<uint8_t> header;
351 proto.serializeToVector(&header);
352 args.addHeader(header);
353 }
354
Joe Onorato1754d742016-11-21 17:51:35 -0800355 // Start the thread pool.
356 sp<ProcessState> ps(ProcessState::self());
357 ps->startThreadPool();
358 ps->giveThreadPoolName();
359
360 // Look up the service
361 sp<IIncidentManager> service = interface_cast<IIncidentManager>(
362 defaultServiceManager()->getService(android::String16("incident")));
363 if (service == NULL) {
364 fprintf(stderr, "Couldn't look up the incident service\n");
365 return 1;
366 }
367
368 // Construct the stream
369 int fds[2];
370 pipe(fds);
371
372 unique_fd readEnd(fds[0]);
373 unique_fd writeEnd(fds[1]);
374
375 if (destination == DEST_STDOUT) {
376 // Call into the service
377 sp<StatusListener> listener(new StatusListener());
Jiyong Park573fd3d2019-11-25 11:03:38 +0900378 status = service->reportIncidentToStream(args, listener, std::move(writeEnd));
Joe Onorato1754d742016-11-21 17:51:35 -0800379
380 if (!status.isOk()) {
381 fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().string());
Yi Jin603f3b32017-08-03 18:50:48 -0700382 return 1;
Joe Onorato1754d742016-11-21 17:51:35 -0800383 }
384
385 // Wait for the result and print out the data they send.
386 //IPCThreadState::self()->joinThreadPool();
Mike Ma15f83a32019-08-21 14:52:46 -0700387 return stream_output(fds[0], STDOUT_FILENO);
388 } else if (destination == DEST_DUMPSTATE) {
389 // Call into the service
390 sp<StatusListener> listener(new StatusListener());
Jiyong Park573fd3d2019-11-25 11:03:38 +0900391 status = service->reportIncidentToDumpstate(std::move(writeEnd), listener);
Mike Ma15f83a32019-08-21 14:52:46 -0700392 if (!status.isOk()) {
393 fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().string());
394 return 1;
Joe Onorato1754d742016-11-21 17:51:35 -0800395 }
Mike Ma15f83a32019-08-21 14:52:46 -0700396 return stream_output(fds[0], STDOUT_FILENO);
Joe Onorato1754d742016-11-21 17:51:35 -0800397 } else {
398 status = service->reportIncident(args);
399 if (!status.isOk()) {
400 fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().string());
401 return 1;
402 } else {
403 return 0;
404 }
405 }
406
407}