blob: eca781fd4e4f126aa5ac56ae8d1ae64515f15a29 [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>
24#include <binder/IPCThreadState.h>
25#include <binder/IServiceManager.h>
26#include <utils/Looper.h>
27
Yi Jin0f047162017-09-05 13:44:22 -070028#include <cstring>
Joe Onorato1754d742016-11-21 17:51:35 -080029#include <fcntl.h>
30#include <getopt.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <unistd.h>
34
35using namespace android;
36using namespace android::base;
37using namespace android::binder;
38using namespace android::os;
39
40// ================================================================================
41class StatusListener : public BnIncidentReportStatusListener {
42public:
43 StatusListener();
44 virtual ~StatusListener();
45
46 virtual Status onReportStarted();
47 virtual Status onReportSectionStatus(int32_t section, int32_t status);
48 virtual Status onReportServiceStatus(const String16& service, int32_t status);
49 virtual Status onReportFinished();
50 virtual Status onReportFailed();
51};
52
53StatusListener::StatusListener()
54{
55}
56
57StatusListener::~StatusListener()
58{
59}
60
61Status
62StatusListener::onReportStarted()
63{
64 return Status::ok();
65}
66
67Status
68StatusListener::onReportSectionStatus(int32_t section, int32_t status)
69{
70 fprintf(stderr, "section %d status %d\n", section, status);
Joe Onorato99598ee2019-02-11 15:55:13 +000071 ALOGD("section %d status %d\n", section, status);
Joe Onorato1754d742016-11-21 17:51:35 -080072 return Status::ok();
73}
74
75Status
76StatusListener::onReportServiceStatus(const String16& service, int32_t status)
77{
78 fprintf(stderr, "service '%s' status %d\n", String8(service).string(), status);
Joe Onorato99598ee2019-02-11 15:55:13 +000079 ALOGD("service '%s' status %d\n", String8(service).string(), status);
Joe Onorato1754d742016-11-21 17:51:35 -080080 return Status::ok();
81}
82
83Status
84StatusListener::onReportFinished()
85{
86 fprintf(stderr, "done\n");
Joe Onorato99598ee2019-02-11 15:55:13 +000087 ALOGD("done\n");
Joe Onorato1754d742016-11-21 17:51:35 -080088 exit(0);
89 return Status::ok();
90}
91
92Status
93StatusListener::onReportFailed()
94{
95 fprintf(stderr, "failed\n");
Joe Onorato99598ee2019-02-11 15:55:13 +000096 ALOGD("failed\n");
Joe Onorato1754d742016-11-21 17:51:35 -080097 exit(1);
98 return Status::ok();
99}
100
101// ================================================================================
Yi Jin0a3406f2017-06-22 19:23:11 -0700102static void section_list(FILE* out) {
103 IncidentSection sections[INCIDENT_SECTION_COUNT];
104 int i = 0;
105 int j = 0;
106 // sort the sections based on id
107 while (i < INCIDENT_SECTION_COUNT) {
108 IncidentSection curr = INCIDENT_SECTIONS[i];
109 for (int k = 0; k < j; k++) {
110 if (curr.id > sections[k].id) {
111 continue;
112 }
113 IncidentSection tmp = curr;
114 curr = sections[k];
115 sections[k] = tmp;
116 }
117 sections[j] = curr;
118 i++;
119 j++;
120 }
121
122 fprintf(out, "available sections:\n");
123 for (int i = 0; i < INCIDENT_SECTION_COUNT; ++i) {
124 fprintf(out, "id: %4d, name: %s\n", sections[i].id, sections[i].name);
125 }
126}
127
128// ================================================================================
Joe Onorato1754d742016-11-21 17:51:35 -0800129static IncidentSection const*
130find_section(const char* name)
131{
132 size_t low = 0;
133 size_t high = INCIDENT_SECTION_COUNT - 1;
134
135 while (low <= high) {
136 size_t mid = (low + high) >> 1;
137 IncidentSection const* section = INCIDENT_SECTIONS + mid;
138
139 int cmp = strcmp(section->name, name);
140 if (cmp < 0) {
141 low = mid + 1;
142 } else if (cmp > 0) {
143 high = mid - 1;
144 } else {
145 return section;
146 }
147 }
148 return NULL;
149}
150
151// ================================================================================
Yi Jin0f047162017-09-05 13:44:22 -0700152static int
Joe Onorato99598ee2019-02-11 15:55:13 +0000153get_privacy_policy(const char* arg)
Yi Jin0f047162017-09-05 13:44:22 -0700154{
Yi Jinb8344dc2018-01-24 17:33:35 -0800155 if (strcmp(arg, "L") == 0
156 || strcmp(arg, "LOCAL") == 0) {
Joe Onorato99598ee2019-02-11 15:55:13 +0000157 return PRIVACY_POLICY_LOCAL;
Yi Jinb8344dc2018-01-24 17:33:35 -0800158 }
159 if (strcmp(arg, "E") == 0
160 || strcmp(arg, "EXPLICIT") == 0) {
Joe Onorato99598ee2019-02-11 15:55:13 +0000161 return PRIVACY_POLICY_EXPLICIT;
Yi Jinb8344dc2018-01-24 17:33:35 -0800162 }
163 if (strcmp(arg, "A") == 0
164 || strcmp(arg, "AUTO") == 0
165 || strcmp(arg, "AUTOMATIC") == 0) {
Joe Onorato99598ee2019-02-11 15:55:13 +0000166 return PRIVACY_POLICY_AUTOMATIC;
Yi Jinb8344dc2018-01-24 17:33:35 -0800167 }
Yi Jin0f047162017-09-05 13:44:22 -0700168 return -1; // return the default value
169}
170
171// ================================================================================
Joe Onorato99598ee2019-02-11 15:55:13 +0000172static bool
173parse_receiver_arg(const string& arg, string* pkg, string* cls)
174{
175 if (arg.length() == 0) {
176 return true;
177 }
178 size_t slash = arg.find('/');
179 if (slash == string::npos) {
180 return false;
181 }
182 if (slash == 0 || slash == arg.length() - 1) {
183 return false;
184 }
185 if (arg.find('/', slash+1) != string::npos) {
186 return false;
187 }
188 pkg->assign(arg, 0, slash);
189 cls->assign(arg, slash+1);
190 if ((*cls)[0] == '.') {
191 *cls = (*pkg) + (*cls);
192 }
193 return true;
194}
195
196// ================================================================================
Joe Onorato1754d742016-11-21 17:51:35 -0800197static void
198usage(FILE* out)
199{
200 fprintf(out, "usage: incident OPTIONS [SECTION...]\n");
201 fprintf(out, "\n");
202 fprintf(out, "Takes an incident report.\n");
203 fprintf(out, "\n");
204 fprintf(out, "OPTIONS\n");
Joe Onorato99598ee2019-02-11 15:55:13 +0000205 fprintf(out, " -l list available sections\n");
206 fprintf(out, " -p privacy spec, LOCAL, EXPLICIT or AUTOMATIC. Default AUTOMATIC.\n");
207 fprintf(out, "\n");
208 fprintf(out, "and one of these destinations:\n");
Joe Onorato1754d742016-11-21 17:51:35 -0800209 fprintf(out, " -b (default) print the report to stdout (in proto format)\n");
210 fprintf(out, " -d send the report into dropbox\n");
Joe Onorato99598ee2019-02-11 15:55:13 +0000211 fprintf(out, " -s PKG/CLS send broadcast to the broadcast receiver.\n");
Joe Onorato1754d742016-11-21 17:51:35 -0800212 fprintf(out, "\n");
213 fprintf(out, " SECTION the field numbers of the incident report fields to include\n");
214 fprintf(out, "\n");
215}
216
217int
218main(int argc, char** argv)
219{
220 Status status;
221 IncidentReportArgs args;
Joe Onorato99598ee2019-02-11 15:55:13 +0000222 enum { DEST_UNSET, DEST_DROPBOX, DEST_STDOUT, DEST_BROADCAST } destination = DEST_UNSET;
223 int privacyPolicy = PRIVACY_POLICY_AUTOMATIC;
224 string receiverArg;
Joe Onorato1754d742016-11-21 17:51:35 -0800225
226 // Parse the args
227 int opt;
Joe Onorato99598ee2019-02-11 15:55:13 +0000228 while ((opt = getopt(argc, argv, "bhdlp:s:")) != -1) {
Joe Onorato1754d742016-11-21 17:51:35 -0800229 switch (opt) {
Joe Onorato1754d742016-11-21 17:51:35 -0800230 case 'h':
231 usage(stdout);
232 return 0;
Yi Jin0a3406f2017-06-22 19:23:11 -0700233 case 'l':
234 section_list(stdout);
235 return 0;
236 case 'b':
Joe Onorato99598ee2019-02-11 15:55:13 +0000237 if (!(destination == DEST_UNSET || destination == DEST_STDOUT)) {
238 usage(stderr);
239 return 1;
240 }
Yi Jin0a3406f2017-06-22 19:23:11 -0700241 destination = DEST_STDOUT;
242 break;
Joe Onorato1754d742016-11-21 17:51:35 -0800243 case 'd':
Joe Onorato99598ee2019-02-11 15:55:13 +0000244 if (!(destination == DEST_UNSET || destination == DEST_DROPBOX)) {
245 usage(stderr);
246 return 1;
247 }
Joe Onorato1754d742016-11-21 17:51:35 -0800248 destination = DEST_DROPBOX;
249 break;
Yi Jin0f047162017-09-05 13:44:22 -0700250 case 'p':
Joe Onorato99598ee2019-02-11 15:55:13 +0000251 privacyPolicy = get_privacy_policy(optarg);
252 break;
253 case 's':
254 if (destination != DEST_UNSET) {
255 usage(stderr);
256 return 1;
257 }
258 destination = DEST_BROADCAST;
259 receiverArg = optarg;
Yi Jin0f047162017-09-05 13:44:22 -0700260 break;
Joe Onorato1754d742016-11-21 17:51:35 -0800261 default:
262 usage(stderr);
263 return 1;
264 }
265 }
Joe Onoratoe5472052019-04-24 16:27:33 -0700266 if (destination == DEST_UNSET) {
267 destination = DEST_STDOUT;
268 }
Joe Onorato1754d742016-11-21 17:51:35 -0800269
Joe Onorato99598ee2019-02-11 15:55:13 +0000270 string pkg;
271 string cls;
272 if (parse_receiver_arg(receiverArg, &pkg, &cls)) {
273 args.setReceiverPkg(pkg);
274 args.setReceiverCls(cls);
275 } else {
276 fprintf(stderr, "badly formatted -s package/class option: %s\n\n", receiverArg.c_str());
277 usage(stderr);
278 return 1;
279 }
280
Joe Onorato1754d742016-11-21 17:51:35 -0800281 if (optind == argc) {
282 args.setAll(true);
283 } else {
284 for (int i=optind; i<argc; i++) {
285 const char* arg = argv[i];
286 char* end;
287 if (arg[0] != '\0') {
288 int section = strtol(arg, &end, 0);
289 if (*end == '\0') {
290 args.addSection(section);
291 } else {
292 IncidentSection const* ic = find_section(arg);
293 if (ic == NULL) {
294 fprintf(stderr, "Invalid section: %s\n", arg);
295 return 1;
296 }
297 args.addSection(ic->id);
298 }
299 }
300 }
301 }
Joe Onorato99598ee2019-02-11 15:55:13 +0000302 args.setPrivacyPolicy(privacyPolicy);
Joe Onorato1754d742016-11-21 17:51:35 -0800303
304 // Start the thread pool.
305 sp<ProcessState> ps(ProcessState::self());
306 ps->startThreadPool();
307 ps->giveThreadPoolName();
308
309 // Look up the service
310 sp<IIncidentManager> service = interface_cast<IIncidentManager>(
311 defaultServiceManager()->getService(android::String16("incident")));
312 if (service == NULL) {
313 fprintf(stderr, "Couldn't look up the incident service\n");
314 return 1;
315 }
316
317 // Construct the stream
318 int fds[2];
319 pipe(fds);
320
321 unique_fd readEnd(fds[0]);
322 unique_fd writeEnd(fds[1]);
323
324 if (destination == DEST_STDOUT) {
325 // Call into the service
326 sp<StatusListener> listener(new StatusListener());
327 status = service->reportIncidentToStream(args, listener, writeEnd);
328
329 if (!status.isOk()) {
330 fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().string());
Yi Jin603f3b32017-08-03 18:50:48 -0700331 return 1;
Joe Onorato1754d742016-11-21 17:51:35 -0800332 }
333
334 // Wait for the result and print out the data they send.
335 //IPCThreadState::self()->joinThreadPool();
336
337 while (true) {
Joe Onorato99598ee2019-02-11 15:55:13 +0000338 uint8_t buf[4096];
339 ssize_t amt = TEMP_FAILURE_RETRY(read(fds[0], buf, sizeof(buf)));
Joe Onorato1754d742016-11-21 17:51:35 -0800340 if (amt < 0) {
Joe Onorato99598ee2019-02-11 15:55:13 +0000341 break;
Joe Onorato1754d742016-11-21 17:51:35 -0800342 } else if (amt == 0) {
Joe Onorato99598ee2019-02-11 15:55:13 +0000343 break;
344 }
345
346 ssize_t wamt = TEMP_FAILURE_RETRY(write(STDOUT_FILENO, buf, amt));
347 if (wamt != amt) {
348 return errno;
Joe Onorato1754d742016-11-21 17:51:35 -0800349 }
350 }
351 } else {
352 status = service->reportIncident(args);
353 if (!status.isOk()) {
354 fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().string());
355 return 1;
356 } else {
357 return 0;
358 }
359 }
360
361}