• Home
  • 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 <binder/IPCThreadState.h>
25 #include <binder/IServiceManager.h>
26 #include <utils/Looper.h>
27 
28 #include <cstring>
29 #include <fcntl.h>
30 #include <getopt.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 
35 using namespace android;
36 using namespace android::base;
37 using namespace android::binder;
38 using namespace android::os;
39 
40 // ================================================================================
41 class StatusListener : public BnIncidentReportStatusListener {
42 public:
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 
StatusListener()53 StatusListener::StatusListener()
54 {
55 }
56 
~StatusListener()57 StatusListener::~StatusListener()
58 {
59 }
60 
61 Status
onReportStarted()62 StatusListener::onReportStarted()
63 {
64     return Status::ok();
65 }
66 
67 Status
onReportSectionStatus(int32_t section,int32_t status)68 StatusListener::onReportSectionStatus(int32_t section, int32_t status)
69 {
70     fprintf(stderr, "section %d status %d\n", section, status);
71     return Status::ok();
72 }
73 
74 Status
onReportServiceStatus(const String16 & service,int32_t status)75 StatusListener::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 
81 Status
onReportFinished()82 StatusListener::onReportFinished()
83 {
84     fprintf(stderr, "done\n");
85     exit(0);
86     return Status::ok();
87 }
88 
89 Status
onReportFailed()90 StatusListener::onReportFailed()
91 {
92     fprintf(stderr, "failed\n");
93     exit(1);
94     return Status::ok();
95 }
96 
97 // ================================================================================
section_list(FILE * out)98 static 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 // ================================================================================
125 static IncidentSection const*
find_section(const char * name)126 find_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 // ================================================================================
148 static int
get_dest(const char * arg)149 get_dest(const char* arg)
150 {
151     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     }
164     return -1; // return the default value
165 }
166 
167 // ================================================================================
168 static void
usage(FILE * out)169 usage(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");
178     fprintf(out, "  -l           list available sections\n");
179     fprintf(out, "  -p           privacy spec, LOCAL, EXPLICIT or AUTOMATIC\n");
180     fprintf(out, "\n");
181     fprintf(out, "  SECTION     the field numbers of the incident report fields to include\n");
182     fprintf(out, "\n");
183 }
184 
185 int
main(int argc,char ** argv)186 main(int argc, char** argv)
187 {
188     Status status;
189     IncidentReportArgs args;
190     enum { DEST_DROPBOX, DEST_STDOUT } destination = DEST_STDOUT;
191     int dest = -1; // default
192 
193     // Parse the args
194     int opt;
195     while ((opt = getopt(argc, argv, "bhdlp:")) != -1) {
196         switch (opt) {
197             case 'h':
198                 usage(stdout);
199                 return 0;
200             case 'l':
201                 section_list(stdout);
202                 return 0;
203             case 'b':
204                 destination = DEST_STDOUT;
205                 break;
206             case 'd':
207                 destination = DEST_DROPBOX;
208                 break;
209             case 'p':
210                 dest = get_dest(optarg);
211                 break;
212             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     }
239     args.setDest(dest);
240 
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());
268             return 1;
269         }
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 }
294