blob: 47f1db89e1cbe88300497cec69817f83ec2c6ae8 [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
28#include <fcntl.h>
29#include <getopt.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <unistd.h>
33
34using namespace android;
35using namespace android::base;
36using namespace android::binder;
37using namespace android::os;
38
39// ================================================================================
40class StatusListener : public BnIncidentReportStatusListener {
41public:
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
52StatusListener::StatusListener()
53{
54}
55
56StatusListener::~StatusListener()
57{
58}
59
60Status
61StatusListener::onReportStarted()
62{
63 return Status::ok();
64}
65
66Status
67StatusListener::onReportSectionStatus(int32_t section, int32_t status)
68{
69 fprintf(stderr, "section %d status %d\n", section, status);
70 return Status::ok();
71}
72
73Status
74StatusListener::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
80Status
81StatusListener::onReportFinished()
82{
83 fprintf(stderr, "done\n");
84 exit(0);
85 return Status::ok();
86}
87
88Status
89StatusListener::onReportFailed()
90{
91 fprintf(stderr, "failed\n");
92 exit(1);
93 return Status::ok();
94}
95
96// ================================================================================
Yi Jin0a3406f2017-06-22 19:23:11 -070097static void section_list(FILE* out) {
98 IncidentSection sections[INCIDENT_SECTION_COUNT];
99 int i = 0;
100 int j = 0;
101 // sort the sections based on id
102 while (i < INCIDENT_SECTION_COUNT) {
103 IncidentSection curr = INCIDENT_SECTIONS[i];
104 for (int k = 0; k < j; k++) {
105 if (curr.id > sections[k].id) {
106 continue;
107 }
108 IncidentSection tmp = curr;
109 curr = sections[k];
110 sections[k] = tmp;
111 }
112 sections[j] = curr;
113 i++;
114 j++;
115 }
116
117 fprintf(out, "available sections:\n");
118 for (int i = 0; i < INCIDENT_SECTION_COUNT; ++i) {
119 fprintf(out, "id: %4d, name: %s\n", sections[i].id, sections[i].name);
120 }
121}
122
123// ================================================================================
Joe Onorato1754d742016-11-21 17:51:35 -0800124static IncidentSection const*
125find_section(const char* name)
126{
127 size_t low = 0;
128 size_t high = INCIDENT_SECTION_COUNT - 1;
129
130 while (low <= high) {
131 size_t mid = (low + high) >> 1;
132 IncidentSection const* section = INCIDENT_SECTIONS + mid;
133
134 int cmp = strcmp(section->name, name);
135 if (cmp < 0) {
136 low = mid + 1;
137 } else if (cmp > 0) {
138 high = mid - 1;
139 } else {
140 return section;
141 }
142 }
143 return NULL;
144}
145
146// ================================================================================
147static void
148usage(FILE* out)
149{
150 fprintf(out, "usage: incident OPTIONS [SECTION...]\n");
151 fprintf(out, "\n");
152 fprintf(out, "Takes an incident report.\n");
153 fprintf(out, "\n");
154 fprintf(out, "OPTIONS\n");
155 fprintf(out, " -b (default) print the report to stdout (in proto format)\n");
156 fprintf(out, " -d send the report into dropbox\n");
Yi Jin0a3406f2017-06-22 19:23:11 -0700157 fprintf(out, " -l list available sections\n");
Joe Onorato1754d742016-11-21 17:51:35 -0800158 fprintf(out, "\n");
159 fprintf(out, " SECTION the field numbers of the incident report fields to include\n");
160 fprintf(out, "\n");
161}
162
163int
164main(int argc, char** argv)
165{
166 Status status;
167 IncidentReportArgs args;
168 enum { DEST_DROPBOX, DEST_STDOUT } destination = DEST_STDOUT;
169
170 // Parse the args
171 int opt;
Yi Jin0a3406f2017-06-22 19:23:11 -0700172 while ((opt = getopt(argc, argv, "bhdl")) != -1) {
Joe Onorato1754d742016-11-21 17:51:35 -0800173 switch (opt) {
Joe Onorato1754d742016-11-21 17:51:35 -0800174 case 'h':
175 usage(stdout);
176 return 0;
Yi Jin0a3406f2017-06-22 19:23:11 -0700177 case 'l':
178 section_list(stdout);
179 return 0;
180 case 'b':
181 destination = DEST_STDOUT;
182 break;
Joe Onorato1754d742016-11-21 17:51:35 -0800183 case 'd':
184 destination = DEST_DROPBOX;
185 break;
186 default:
187 usage(stderr);
188 return 1;
189 }
190 }
191
192 if (optind == argc) {
193 args.setAll(true);
194 } else {
195 for (int i=optind; i<argc; i++) {
196 const char* arg = argv[i];
197 char* end;
198 if (arg[0] != '\0') {
199 int section = strtol(arg, &end, 0);
200 if (*end == '\0') {
201 args.addSection(section);
202 } else {
203 IncidentSection const* ic = find_section(arg);
204 if (ic == NULL) {
205 fprintf(stderr, "Invalid section: %s\n", arg);
206 return 1;
207 }
208 args.addSection(ic->id);
209 }
210 }
211 }
212 }
213
214
215
216 // Start the thread pool.
217 sp<ProcessState> ps(ProcessState::self());
218 ps->startThreadPool();
219 ps->giveThreadPoolName();
220
221 // Look up the service
222 sp<IIncidentManager> service = interface_cast<IIncidentManager>(
223 defaultServiceManager()->getService(android::String16("incident")));
224 if (service == NULL) {
225 fprintf(stderr, "Couldn't look up the incident service\n");
226 return 1;
227 }
228
229 // Construct the stream
230 int fds[2];
231 pipe(fds);
232
233 unique_fd readEnd(fds[0]);
234 unique_fd writeEnd(fds[1]);
235
236 if (destination == DEST_STDOUT) {
237 // Call into the service
238 sp<StatusListener> listener(new StatusListener());
239 status = service->reportIncidentToStream(args, listener, writeEnd);
240
241 if (!status.isOk()) {
242 fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().string());
Yi Jin603f3b32017-08-03 18:50:48 -0700243 return 1;
Joe Onorato1754d742016-11-21 17:51:35 -0800244 }
245
246 // Wait for the result and print out the data they send.
247 //IPCThreadState::self()->joinThreadPool();
248
249 while (true) {
250 int amt = splice(fds[0], NULL, STDOUT_FILENO, NULL, 4096, 0);
251 fprintf(stderr, "spliced %d bytes\n", amt);
252 if (amt < 0) {
253 return errno;
254 } else if (amt == 0) {
255 return 0;
256 }
257 }
258 } else {
259 status = service->reportIncident(args);
260 if (!status.isOk()) {
261 fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().string());
262 return 1;
263 } else {
264 return 0;
265 }
266 }
267
268}