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 <fcntl.h>
29 #include <getopt.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 
34 using namespace android;
35 using namespace android::base;
36 using namespace android::binder;
37 using namespace android::os;
38 
39 // ================================================================================
40 class StatusListener : public BnIncidentReportStatusListener {
41 public:
42     StatusListener();
43     virtual ~StatusListener();
44 
45     virtual Status onReportStarted();
46     virtual Status onReportSectionStatus(int32_t section, int32_t status);
47     virtual Status onReportServiceStatus(const String16& service, int32_t status);
48     virtual Status onReportFinished();
49     virtual Status onReportFailed();
50 };
51 
StatusListener()52 StatusListener::StatusListener()
53 {
54 }
55 
~StatusListener()56 StatusListener::~StatusListener()
57 {
58 }
59 
60 Status
onReportStarted()61 StatusListener::onReportStarted()
62 {
63     return Status::ok();
64 }
65 
66 Status
onReportSectionStatus(int32_t section,int32_t status)67 StatusListener::onReportSectionStatus(int32_t section, int32_t status)
68 {
69     fprintf(stderr, "section %d status %d\n", section, status);
70     return Status::ok();
71 }
72 
73 Status
onReportServiceStatus(const String16 & service,int32_t status)74 StatusListener::onReportServiceStatus(const String16& service, int32_t status)
75 {
76     fprintf(stderr, "service '%s' status %d\n", String8(service).string(), status);
77     return Status::ok();
78 }
79 
80 Status
onReportFinished()81 StatusListener::onReportFinished()
82 {
83     fprintf(stderr, "done\n");
84     exit(0);
85     return Status::ok();
86 }
87 
88 Status
onReportFailed()89 StatusListener::onReportFailed()
90 {
91     fprintf(stderr, "failed\n");
92     exit(1);
93     return Status::ok();
94 }
95 
96 // ================================================================================
97 static IncidentSection const*
find_section(const char * name)98 find_section(const char* name)
99 {
100     size_t low = 0;
101     size_t high = INCIDENT_SECTION_COUNT - 1;
102 
103     while (low <= high) {
104         size_t mid = (low + high) >> 1;
105         IncidentSection const* section = INCIDENT_SECTIONS + mid;
106 
107         int cmp = strcmp(section->name, name);
108         if (cmp < 0) {
109             low = mid + 1;
110         } else if (cmp > 0) {
111             high = mid - 1;
112         } else {
113             return section;
114         }
115     }
116     return NULL;
117 }
118 
119 // ================================================================================
120 static void
usage(FILE * out)121 usage(FILE* out)
122 {
123     fprintf(out, "usage: incident OPTIONS [SECTION...]\n");
124     fprintf(out, "\n");
125     fprintf(out, "Takes an incident report.\n");
126     fprintf(out, "\n");
127     fprintf(out, "OPTIONS\n");
128     fprintf(out, "  -b           (default) print the report to stdout (in proto format)\n");
129     fprintf(out, "  -d           send the report into dropbox\n");
130     fprintf(out, "\n");
131     fprintf(out, "  SECTION     the field numbers of the incident report fields to include\n");
132     fprintf(out, "\n");
133 }
134 
135 int
main(int argc,char ** argv)136 main(int argc, char** argv)
137 {
138     Status status;
139     IncidentReportArgs args;
140     enum { DEST_DROPBOX, DEST_STDOUT } destination = DEST_STDOUT;
141 
142     // Parse the args
143     int opt;
144     while ((opt = getopt(argc, argv, "bhd")) != -1) {
145         switch (opt) {
146             case 'b':
147                 destination = DEST_STDOUT;
148                 break;
149             case 'h':
150                 usage(stdout);
151                 return 0;
152             case 'd':
153                 destination = DEST_DROPBOX;
154                 break;
155             default:
156                 usage(stderr);
157                 return 1;
158         }
159     }
160 
161     if (optind == argc) {
162         args.setAll(true);
163     } else {
164         for (int i=optind; i<argc; i++) {
165             const char* arg = argv[i];
166             char* end;
167             if (arg[0] != '\0') {
168                 int section = strtol(arg, &end, 0);
169                 if (*end == '\0') {
170                     args.addSection(section);
171                 } else {
172                     IncidentSection const* ic = find_section(arg);
173                     if (ic == NULL) {
174                         fprintf(stderr, "Invalid section: %s\n", arg);
175                         return 1;
176                     }
177                     args.addSection(ic->id);
178                 }
179             }
180         }
181     }
182 
183 
184 
185     // Start the thread pool.
186     sp<ProcessState> ps(ProcessState::self());
187     ps->startThreadPool();
188     ps->giveThreadPoolName();
189 
190     // Look up the service
191     sp<IIncidentManager> service = interface_cast<IIncidentManager>(
192             defaultServiceManager()->getService(android::String16("incident")));
193     if (service == NULL) {
194         fprintf(stderr, "Couldn't look up the incident service\n");
195         return 1;
196     }
197 
198     // Construct the stream
199     int fds[2];
200     pipe(fds);
201 
202     unique_fd readEnd(fds[0]);
203     unique_fd writeEnd(fds[1]);
204 
205     if (destination == DEST_STDOUT) {
206         // Call into the service
207         sp<StatusListener> listener(new StatusListener());
208         status = service->reportIncidentToStream(args, listener, writeEnd);
209 
210         if (!status.isOk()) {
211             fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().string());
212         }
213 
214         // Wait for the result and print out the data they send.
215         //IPCThreadState::self()->joinThreadPool();
216 
217         while (true) {
218             int amt = splice(fds[0], NULL, STDOUT_FILENO, NULL, 4096, 0);
219             fprintf(stderr, "spliced %d bytes\n", amt);
220             if (amt < 0) {
221                 return errno;
222             } else if (amt == 0) {
223                 return 0;
224             }
225         }
226     } else {
227         status = service->reportIncident(args);
228         if (!status.isOk()) {
229             fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().string());
230             return 1;
231         } else {
232             return 0;
233         }
234     }
235 
236 }
237