blob: cdec6a01d086d80f489c0ebeacdab173dfd9f060 [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);
71 return Status::ok();
72}
73
74Status
75StatusListener::onReportServiceStatus(const String16& service, int32_t status)
76{
77 fprintf(stderr, "service '%s' status %d\n", String8(service).string(), status);
78 return Status::ok();
79}
80
81Status
82StatusListener::onReportFinished()
83{
84 fprintf(stderr, "done\n");
85 exit(0);
86 return Status::ok();
87}
88
89Status
90StatusListener::onReportFailed()
91{
92 fprintf(stderr, "failed\n");
93 exit(1);
94 return Status::ok();
95}
96
97// ================================================================================
Yi Jin0a3406f2017-06-22 19:23:11 -070098static void section_list(FILE* out) {
99 IncidentSection sections[INCIDENT_SECTION_COUNT];
100 int i = 0;
101 int j = 0;
102 // sort the sections based on id
103 while (i < INCIDENT_SECTION_COUNT) {
104 IncidentSection curr = INCIDENT_SECTIONS[i];
105 for (int k = 0; k < j; k++) {
106 if (curr.id > sections[k].id) {
107 continue;
108 }
109 IncidentSection tmp = curr;
110 curr = sections[k];
111 sections[k] = tmp;
112 }
113 sections[j] = curr;
114 i++;
115 j++;
116 }
117
118 fprintf(out, "available sections:\n");
119 for (int i = 0; i < INCIDENT_SECTION_COUNT; ++i) {
120 fprintf(out, "id: %4d, name: %s\n", sections[i].id, sections[i].name);
121 }
122}
123
124// ================================================================================
Joe Onorato1754d742016-11-21 17:51:35 -0800125static IncidentSection const*
126find_section(const char* name)
127{
128 size_t low = 0;
129 size_t high = INCIDENT_SECTION_COUNT - 1;
130
131 while (low <= high) {
132 size_t mid = (low + high) >> 1;
133 IncidentSection const* section = INCIDENT_SECTIONS + mid;
134
135 int cmp = strcmp(section->name, name);
136 if (cmp < 0) {
137 low = mid + 1;
138 } else if (cmp > 0) {
139 high = mid - 1;
140 } else {
141 return section;
142 }
143 }
144 return NULL;
145}
146
147// ================================================================================
Yi Jin0f047162017-09-05 13:44:22 -0700148static int
149get_dest(const char* arg)
150{
Yi Jinb8344dc2018-01-24 17:33:35 -0800151 if (strcmp(arg, "L") == 0
152 || strcmp(arg, "LOCAL") == 0) {
153 return DEST_LOCAL;
154 }
155 if (strcmp(arg, "E") == 0
156 || strcmp(arg, "EXPLICIT") == 0) {
157 return DEST_EXPLICIT;
158 }
159 if (strcmp(arg, "A") == 0
160 || strcmp(arg, "AUTO") == 0
161 || strcmp(arg, "AUTOMATIC") == 0) {
162 return DEST_AUTOMATIC;
163 }
Yi Jin0f047162017-09-05 13:44:22 -0700164 return -1; // return the default value
165}
166
167// ================================================================================
Joe Onorato1754d742016-11-21 17:51:35 -0800168static void
169usage(FILE* out)
170{
171 fprintf(out, "usage: incident OPTIONS [SECTION...]\n");
172 fprintf(out, "\n");
173 fprintf(out, "Takes an incident report.\n");
174 fprintf(out, "\n");
175 fprintf(out, "OPTIONS\n");
176 fprintf(out, " -b (default) print the report to stdout (in proto format)\n");
177 fprintf(out, " -d send the report into dropbox\n");
Yi Jin0a3406f2017-06-22 19:23:11 -0700178 fprintf(out, " -l list available sections\n");
Yi Jin0f047162017-09-05 13:44:22 -0700179 fprintf(out, " -p privacy spec, LOCAL, EXPLICIT or AUTOMATIC\n");
Joe Onorato1754d742016-11-21 17:51:35 -0800180 fprintf(out, "\n");
181 fprintf(out, " SECTION the field numbers of the incident report fields to include\n");
182 fprintf(out, "\n");
183}
184
185int
186main(int argc, char** argv)
187{
188 Status status;
189 IncidentReportArgs args;
190 enum { DEST_DROPBOX, DEST_STDOUT } destination = DEST_STDOUT;
Yi Jin0f047162017-09-05 13:44:22 -0700191 int dest = -1; // default
Joe Onorato1754d742016-11-21 17:51:35 -0800192
193 // Parse the args
194 int opt;
Yi Jin0f047162017-09-05 13:44:22 -0700195 while ((opt = getopt(argc, argv, "bhdlp:")) != -1) {
Joe Onorato1754d742016-11-21 17:51:35 -0800196 switch (opt) {
Joe Onorato1754d742016-11-21 17:51:35 -0800197 case 'h':
198 usage(stdout);
199 return 0;
Yi Jin0a3406f2017-06-22 19:23:11 -0700200 case 'l':
201 section_list(stdout);
202 return 0;
203 case 'b':
204 destination = DEST_STDOUT;
205 break;
Joe Onorato1754d742016-11-21 17:51:35 -0800206 case 'd':
207 destination = DEST_DROPBOX;
208 break;
Yi Jin0f047162017-09-05 13:44:22 -0700209 case 'p':
210 dest = get_dest(optarg);
211 break;
Joe Onorato1754d742016-11-21 17:51:35 -0800212 default:
213 usage(stderr);
214 return 1;
215 }
216 }
217
218 if (optind == argc) {
219 args.setAll(true);
220 } else {
221 for (int i=optind; i<argc; i++) {
222 const char* arg = argv[i];
223 char* end;
224 if (arg[0] != '\0') {
225 int section = strtol(arg, &end, 0);
226 if (*end == '\0') {
227 args.addSection(section);
228 } else {
229 IncidentSection const* ic = find_section(arg);
230 if (ic == NULL) {
231 fprintf(stderr, "Invalid section: %s\n", arg);
232 return 1;
233 }
234 args.addSection(ic->id);
235 }
236 }
237 }
238 }
Yi Jin0f047162017-09-05 13:44:22 -0700239 args.setDest(dest);
Joe Onorato1754d742016-11-21 17:51:35 -0800240
241 // Start the thread pool.
242 sp<ProcessState> ps(ProcessState::self());
243 ps->startThreadPool();
244 ps->giveThreadPoolName();
245
246 // Look up the service
247 sp<IIncidentManager> service = interface_cast<IIncidentManager>(
248 defaultServiceManager()->getService(android::String16("incident")));
249 if (service == NULL) {
250 fprintf(stderr, "Couldn't look up the incident service\n");
251 return 1;
252 }
253
254 // Construct the stream
255 int fds[2];
256 pipe(fds);
257
258 unique_fd readEnd(fds[0]);
259 unique_fd writeEnd(fds[1]);
260
261 if (destination == DEST_STDOUT) {
262 // Call into the service
263 sp<StatusListener> listener(new StatusListener());
264 status = service->reportIncidentToStream(args, listener, writeEnd);
265
266 if (!status.isOk()) {
267 fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().string());
Yi Jin603f3b32017-08-03 18:50:48 -0700268 return 1;
Joe Onorato1754d742016-11-21 17:51:35 -0800269 }
270
271 // Wait for the result and print out the data they send.
272 //IPCThreadState::self()->joinThreadPool();
273
274 while (true) {
275 int amt = splice(fds[0], NULL, STDOUT_FILENO, NULL, 4096, 0);
276 fprintf(stderr, "spliced %d bytes\n", amt);
277 if (amt < 0) {
278 return errno;
279 } else if (amt == 0) {
280 return 0;
281 }
282 }
283 } else {
284 status = service->reportIncident(args);
285 if (!status.isOk()) {
286 fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().string());
287 return 1;
288 } else {
289 return 0;
290 }
291 }
292
293}