blob: d6c6c39dd1d8e8c85bbe41008fa9f55cd1348059 [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 Suc43df502020-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 Suc43df502020-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 Suc43df502020-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 Suc43df502020-02-27 03:22:53 +0900105 mExitCode = 1;
Joe Onorato1754d742016-11-21 17:51:35 -0800106 return Status::ok();
107}
108
Boleyn Suc43df502020-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 Ma15f83a32019-08-21 14:52:46 -0700210static int
211stream_output(const int read_fd, const int write_fd) {
212 while (true) {
Boleyn Suc43df502020-02-27 03:22:53 +0900213 int amt = splice(read_fd, NULL, write_fd, NULL, 4096, 0);
Mike Ma15f83a32019-08-21 14:52:46 -0700214 if (amt < 0) {
Mike Ma15f83a32019-08-21 14:52:46 -0700215 return errno;
Boleyn Suc43df502020-02-27 03:22:53 +0900216 } else if (amt == 0) {
217 return 0;
Mike Ma15f83a32019-08-21 14:52:46 -0700218 }
219 }
Mike Ma15f83a32019-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 Ma15f83a32019-08-21 14:52:46 -0700233 fprintf(out, " -r REASON human readable description of why the report is taken.\n");
Joe Onorato99598ee2019-02-11 15:55:13 +0000234 fprintf(out, "\n");
235 fprintf(out, "and one of these destinations:\n");
Joe Onorato1754d742016-11-21 17:51:35 -0800236 fprintf(out, " -b (default) print the report to stdout (in proto format)\n");
237 fprintf(out, " -d send the report into dropbox\n");
Mike Ma15f83a32019-08-21 14:52:46 -0700238 fprintf(out, " -u print a full report to stdout for dumpstate to zip as a bug\n");
239 fprintf(out, " report. SECTION is ignored. Should only be called by dumpstate.\n");
Joe Onorato99598ee2019-02-11 15:55:13 +0000240 fprintf(out, " -s PKG/CLS send broadcast to the broadcast receiver.\n");
Joe Onorato1754d742016-11-21 17:51:35 -0800241 fprintf(out, "\n");
242 fprintf(out, " SECTION the field numbers of the incident report fields to include\n");
243 fprintf(out, "\n");
244}
245
246int
247main(int argc, char** argv)
248{
249 Status status;
250 IncidentReportArgs args;
Mike Ma15f83a32019-08-21 14:52:46 -0700251 enum { DEST_UNSET, DEST_DROPBOX, DEST_STDOUT, DEST_BROADCAST, DEST_DUMPSTATE } destination = DEST_UNSET;
Joe Onorato99598ee2019-02-11 15:55:13 +0000252 int privacyPolicy = PRIVACY_POLICY_AUTOMATIC;
Joe Onorato5dfe3df2019-05-19 17:36:08 -0700253 string reason;
Joe Onorato99598ee2019-02-11 15:55:13 +0000254 string receiverArg;
Joe Onorato1754d742016-11-21 17:51:35 -0800255
256 // Parse the args
257 int opt;
Mike Ma15f83a32019-08-21 14:52:46 -0700258 while ((opt = getopt(argc, argv, "bhdlp:r:s:u")) != -1) {
Joe Onorato1754d742016-11-21 17:51:35 -0800259 switch (opt) {
Joe Onorato1754d742016-11-21 17:51:35 -0800260 case 'h':
261 usage(stdout);
262 return 0;
Yi Jin0a3406f2017-06-22 19:23:11 -0700263 case 'l':
264 section_list(stdout);
265 return 0;
266 case 'b':
Joe Onorato99598ee2019-02-11 15:55:13 +0000267 if (!(destination == DEST_UNSET || destination == DEST_STDOUT)) {
268 usage(stderr);
269 return 1;
270 }
Yi Jin0a3406f2017-06-22 19:23:11 -0700271 destination = DEST_STDOUT;
272 break;
Joe Onorato1754d742016-11-21 17:51:35 -0800273 case 'd':
Joe Onorato99598ee2019-02-11 15:55:13 +0000274 if (!(destination == DEST_UNSET || destination == DEST_DROPBOX)) {
275 usage(stderr);
276 return 1;
277 }
Joe Onorato1754d742016-11-21 17:51:35 -0800278 destination = DEST_DROPBOX;
279 break;
Mike Ma15f83a32019-08-21 14:52:46 -0700280 case 'u':
281 if (!(destination == DEST_UNSET || destination == DEST_DUMPSTATE)) {
282 usage(stderr);
283 return 1;
284 }
285 destination = DEST_DUMPSTATE;
286 break;
Yi Jin0f047162017-09-05 13:44:22 -0700287 case 'p':
Joe Onorato99598ee2019-02-11 15:55:13 +0000288 privacyPolicy = get_privacy_policy(optarg);
289 break;
Joe Onorato5dfe3df2019-05-19 17:36:08 -0700290 case 'r':
291 if (reason.size() > 0) {
292 usage(stderr);
293 return 1;
294 }
295 reason = optarg;
296 break;
Joe Onorato99598ee2019-02-11 15:55:13 +0000297 case 's':
298 if (destination != DEST_UNSET) {
299 usage(stderr);
300 return 1;
301 }
302 destination = DEST_BROADCAST;
303 receiverArg = optarg;
Yi Jin0f047162017-09-05 13:44:22 -0700304 break;
Joe Onorato1754d742016-11-21 17:51:35 -0800305 default:
306 usage(stderr);
307 return 1;
308 }
309 }
Joe Onoratoe5472052019-04-24 16:27:33 -0700310 if (destination == DEST_UNSET) {
311 destination = DEST_STDOUT;
312 }
Joe Onorato1754d742016-11-21 17:51:35 -0800313
Joe Onorato99598ee2019-02-11 15:55:13 +0000314 string pkg;
315 string cls;
316 if (parse_receiver_arg(receiverArg, &pkg, &cls)) {
317 args.setReceiverPkg(pkg);
318 args.setReceiverCls(cls);
319 } else {
320 fprintf(stderr, "badly formatted -s package/class option: %s\n\n", receiverArg.c_str());
321 usage(stderr);
322 return 1;
323 }
324
Joe Onorato1754d742016-11-21 17:51:35 -0800325 if (optind == argc) {
326 args.setAll(true);
327 } else {
328 for (int i=optind; i<argc; i++) {
329 const char* arg = argv[i];
330 char* end;
331 if (arg[0] != '\0') {
332 int section = strtol(arg, &end, 0);
333 if (*end == '\0') {
334 args.addSection(section);
335 } else {
336 IncidentSection const* ic = find_section(arg);
337 if (ic == NULL) {
Joe Onorato3864a342019-05-19 20:51:47 -0700338 ALOGD("Invalid section: %s\n", arg);
Joe Onorato1754d742016-11-21 17:51:35 -0800339 fprintf(stderr, "Invalid section: %s\n", arg);
340 return 1;
341 }
342 args.addSection(ic->id);
343 }
344 }
345 }
346 }
Joe Onorato99598ee2019-02-11 15:55:13 +0000347 args.setPrivacyPolicy(privacyPolicy);
Joe Onorato1754d742016-11-21 17:51:35 -0800348
Joe Onorato5dfe3df2019-05-19 17:36:08 -0700349 if (reason.size() > 0) {
350 ProtoOutputStream proto;
351 proto.write(/* reason field id */ 2 | FIELD_TYPE_STRING | FIELD_COUNT_SINGLE, reason);
352 vector<uint8_t> header;
353 proto.serializeToVector(&header);
354 args.addHeader(header);
355 }
356
Joe Onorato1754d742016-11-21 17:51:35 -0800357 // Start the thread pool.
358 sp<ProcessState> ps(ProcessState::self());
359 ps->startThreadPool();
360 ps->giveThreadPoolName();
361
362 // Look up the service
363 sp<IIncidentManager> service = interface_cast<IIncidentManager>(
364 defaultServiceManager()->getService(android::String16("incident")));
365 if (service == NULL) {
366 fprintf(stderr, "Couldn't look up the incident service\n");
367 return 1;
368 }
369
370 // Construct the stream
371 int fds[2];
372 pipe(fds);
373
374 unique_fd readEnd(fds[0]);
375 unique_fd writeEnd(fds[1]);
376
377 if (destination == DEST_STDOUT) {
378 // Call into the service
379 sp<StatusListener> listener(new StatusListener());
Jiyong Park573fd3d2019-11-25 11:03:38 +0900380 status = service->reportIncidentToStream(args, listener, std::move(writeEnd));
Joe Onorato1754d742016-11-21 17:51:35 -0800381
382 if (!status.isOk()) {
383 fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().string());
Yi Jin603f3b32017-08-03 18:50:48 -0700384 return 1;
Joe Onorato1754d742016-11-21 17:51:35 -0800385 }
386
387 // Wait for the result and print out the data they send.
388 //IPCThreadState::self()->joinThreadPool();
Boleyn Suc43df502020-02-27 03:22:53 +0900389 return listener->getExitCodeOrElse(stream_output(fds[0], STDOUT_FILENO));
Mike Ma15f83a32019-08-21 14:52:46 -0700390 } else if (destination == DEST_DUMPSTATE) {
391 // Call into the service
392 sp<StatusListener> listener(new StatusListener());
Jiyong Park573fd3d2019-11-25 11:03:38 +0900393 status = service->reportIncidentToDumpstate(std::move(writeEnd), listener);
Mike Ma15f83a32019-08-21 14:52:46 -0700394 if (!status.isOk()) {
395 fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().string());
396 return 1;
Joe Onorato1754d742016-11-21 17:51:35 -0800397 }
Boleyn Suc43df502020-02-27 03:22:53 +0900398 return listener->getExitCodeOrElse(stream_output(fds[0], STDOUT_FILENO));
Joe Onorato1754d742016-11-21 17:51:35 -0800399 } else {
400 status = service->reportIncident(args);
401 if (!status.isOk()) {
402 fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().string());
403 return 1;
404 } else {
405 return 0;
406 }
407 }
408
409}