• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 <android/util/ProtoOutputStream.h>
25 #include <binder/IPCThreadState.h>
26 #include <binder/IServiceManager.h>
27 #include <utils/Looper.h>
28 
29 #include <cstring>
30 #include <fcntl.h>
31 #include <getopt.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 
36 using namespace android;
37 using namespace android::base;
38 using namespace android::binder;
39 using namespace android::os;
40 using android::util::FIELD_COUNT_SINGLE;
41 using android::util::FIELD_TYPE_STRING;
42 using android::util::ProtoOutputStream;
43 
44 // ================================================================================
45 class StatusListener : public BnIncidentReportStatusListener {
46 public:
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 
StatusListener()57 StatusListener::StatusListener()
58 {
59 }
60 
~StatusListener()61 StatusListener::~StatusListener()
62 {
63 }
64 
65 Status
onReportStarted()66 StatusListener::onReportStarted()
67 {
68     return Status::ok();
69 }
70 
71 Status
onReportSectionStatus(int32_t section,int32_t status)72 StatusListener::onReportSectionStatus(int32_t section, int32_t status)
73 {
74     fprintf(stderr, "section %d status %d\n", section, status);
75     ALOGD("section %d status %d\n", section, status);
76     return Status::ok();
77 }
78 
79 Status
onReportServiceStatus(const String16 & service,int32_t status)80 StatusListener::onReportServiceStatus(const String16& service, int32_t status)
81 {
82     fprintf(stderr, "service '%s' status %d\n", String8(service).string(), status);
83     ALOGD("service '%s' status %d\n", String8(service).string(), status);
84     return Status::ok();
85 }
86 
87 Status
onReportFinished()88 StatusListener::onReportFinished()
89 {
90     fprintf(stderr, "done\n");
91     ALOGD("done\n");
92     exit(0);
93     return Status::ok();
94 }
95 
96 Status
onReportFailed()97 StatusListener::onReportFailed()
98 {
99     fprintf(stderr, "failed\n");
100     ALOGD("failed\n");
101     exit(1);
102     return Status::ok();
103 }
104 
105 // ================================================================================
section_list(FILE * out)106 static 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 // ================================================================================
133 static IncidentSection const*
find_section(const char * name)134 find_section(const char* name)
135 {
136     ssize_t low = 0;
137     ssize_t high = INCIDENT_SECTION_COUNT - 1;
138 
139     while (low <= high) {
140         ssize_t mid = (low + high) / 2;
141         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 // ================================================================================
156 static int
get_privacy_policy(const char * arg)157 get_privacy_policy(const char* arg)
158 {
159     if (strcmp(arg, "L") == 0
160         || strcmp(arg, "LOCAL") == 0) {
161       return PRIVACY_POLICY_LOCAL;
162     }
163     if (strcmp(arg, "E") == 0
164         || strcmp(arg, "EXPLICIT") == 0) {
165       return PRIVACY_POLICY_EXPLICIT;
166     }
167     if (strcmp(arg, "A") == 0
168         || strcmp(arg, "AUTO") == 0
169         || strcmp(arg, "AUTOMATIC") == 0) {
170       return PRIVACY_POLICY_AUTOMATIC;
171     }
172     return -1; // return the default value
173 }
174 
175 // ================================================================================
176 static bool
parse_receiver_arg(const string & arg,string * pkg,string * cls)177 parse_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 // ================================================================================
201 static void
usage(FILE * out)202 usage(FILE* out)
203 {
204     fprintf(out, "usage: incident OPTIONS [SECTION...]\n");
205     fprintf(out, "\n");
206     fprintf(out, "Takes an incident report.\n");
207     fprintf(out, "\n");
208     fprintf(out, "OPTIONS\n");
209     fprintf(out, "  -l           list available sections\n");
210     fprintf(out, "  -p           privacy spec, LOCAL, EXPLICIT or AUTOMATIC. Default AUTOMATIC.\n");
211     fprintf(out, "\n");
212     fprintf(out, "and one of these destinations:\n");
213     fprintf(out, "  -b           (default) print the report to stdout (in proto format)\n");
214     fprintf(out, "  -d           send the report into dropbox\n");
215     fprintf(out, "  -r REASON    human readable description of why the report is taken.\n");
216     fprintf(out, "  -s PKG/CLS   send broadcast to the broadcast receiver.\n");
217     fprintf(out, "\n");
218     fprintf(out, "  SECTION     the field numbers of the incident report fields to include\n");
219     fprintf(out, "\n");
220 }
221 
222 int
main(int argc,char ** argv)223 main(int argc, char** argv)
224 {
225     Status status;
226     IncidentReportArgs args;
227     enum { DEST_UNSET, DEST_DROPBOX, DEST_STDOUT, DEST_BROADCAST } destination = DEST_UNSET;
228     int privacyPolicy = PRIVACY_POLICY_AUTOMATIC;
229     string reason;
230     string receiverArg;
231 
232     // Parse the args
233     int opt;
234     while ((opt = getopt(argc, argv, "bhdlp:r:s:")) != -1) {
235         switch (opt) {
236             case 'h':
237                 usage(stdout);
238                 return 0;
239             case 'l':
240                 section_list(stdout);
241                 return 0;
242             case 'b':
243                 if (!(destination == DEST_UNSET || destination == DEST_STDOUT)) {
244                     usage(stderr);
245                     return 1;
246                 }
247                 destination = DEST_STDOUT;
248                 break;
249             case 'd':
250                 if (!(destination == DEST_UNSET || destination == DEST_DROPBOX)) {
251                     usage(stderr);
252                     return 1;
253                 }
254                 destination = DEST_DROPBOX;
255                 break;
256             case 'p':
257                 privacyPolicy = get_privacy_policy(optarg);
258                 break;
259             case 'r':
260                 if (reason.size() > 0) {
261                     usage(stderr);
262                     return 1;
263                 }
264                 reason = optarg;
265                 break;
266             case 's':
267                 if (destination != DEST_UNSET) {
268                     usage(stderr);
269                     return 1;
270                 }
271                 destination = DEST_BROADCAST;
272                 receiverArg = optarg;
273                 break;
274             default:
275                 usage(stderr);
276                 return 1;
277         }
278     }
279     if (destination == DEST_UNSET) {
280         destination = DEST_STDOUT;
281     }
282 
283     string pkg;
284     string cls;
285     if (parse_receiver_arg(receiverArg, &pkg, &cls)) {
286         args.setReceiverPkg(pkg);
287         args.setReceiverCls(cls);
288     } else {
289         fprintf(stderr, "badly formatted -s package/class option: %s\n\n", receiverArg.c_str());
290         usage(stderr);
291         return 1;
292     }
293 
294     if (optind == argc) {
295         args.setAll(true);
296     } else {
297         for (int i=optind; i<argc; i++) {
298             const char* arg = argv[i];
299             char* end;
300             if (arg[0] != '\0') {
301                 int section = strtol(arg, &end, 0);
302                 if (*end == '\0') {
303                     args.addSection(section);
304                 } else {
305                     IncidentSection const* ic = find_section(arg);
306                     if (ic == NULL) {
307                         ALOGD("Invalid section: %s\n", arg);
308                         fprintf(stderr, "Invalid section: %s\n", arg);
309                         return 1;
310                     }
311                     args.addSection(ic->id);
312                 }
313             }
314         }
315     }
316     args.setPrivacyPolicy(privacyPolicy);
317 
318     if (reason.size() > 0) {
319         ProtoOutputStream proto;
320         proto.write(/* reason field id */ 2 | FIELD_TYPE_STRING | FIELD_COUNT_SINGLE, reason);
321         vector<uint8_t> header;
322         proto.serializeToVector(&header);
323         args.addHeader(header);
324     }
325 
326     // Start the thread pool.
327     sp<ProcessState> ps(ProcessState::self());
328     ps->startThreadPool();
329     ps->giveThreadPoolName();
330 
331     // Look up the service
332     sp<IIncidentManager> service = interface_cast<IIncidentManager>(
333             defaultServiceManager()->getService(android::String16("incident")));
334     if (service == NULL) {
335         fprintf(stderr, "Couldn't look up the incident service\n");
336         return 1;
337     }
338 
339     // Construct the stream
340     int fds[2];
341     pipe(fds);
342 
343     unique_fd readEnd(fds[0]);
344     unique_fd writeEnd(fds[1]);
345 
346     if (destination == DEST_STDOUT) {
347         // Call into the service
348         sp<StatusListener> listener(new StatusListener());
349         status = service->reportIncidentToStream(args, listener, writeEnd);
350 
351         if (!status.isOk()) {
352             fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().string());
353             return 1;
354         }
355 
356         // Wait for the result and print out the data they send.
357         //IPCThreadState::self()->joinThreadPool();
358 
359         while (true) {
360             uint8_t buf[4096];
361             ssize_t amt = TEMP_FAILURE_RETRY(read(fds[0], buf, sizeof(buf)));
362             if (amt < 0) {
363                 break;
364             } else if (amt == 0) {
365                 break;
366             }
367 
368             ssize_t wamt = TEMP_FAILURE_RETRY(write(STDOUT_FILENO, buf, amt));
369             if (wamt != amt) {
370                 return errno;
371             }
372         }
373     } else {
374         status = service->reportIncident(args);
375         if (!status.isOk()) {
376             fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().string());
377             return 1;
378         } else {
379             return 0;
380         }
381     }
382 
383 }
384