blob: 250d1186c672cfbb642218fd67680bcc1d2dc69c [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#include "generic_message.h"
18#include "printer.h"
19
Joe Onorato766901262016-12-20 08:18:32 -080020#include <frameworks/base/core/proto/android/os/incident.pb.h>
Joe Onorato1754d742016-11-21 17:51:35 -080021#include <google/protobuf/wire_format.h>
22#include <google/protobuf/io/coded_stream.h>
23#include <google/protobuf/io/zero_copy_stream_impl.h>
24
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <sys/wait.h>
28#include <errno.h>
29#include <fcntl.h>
30#include <stdio.h>
31#include <string.h>
32#include <unistd.h>
33
34using namespace android::os;
35using namespace google::protobuf;
36using namespace google::protobuf::io;
37using namespace google::protobuf::internal;
38
39static bool read_message(CodedInputStream* in, Descriptor const* descriptor,
40 GenericMessage* message);
41static void print_message(Out* out, Descriptor const* descriptor, GenericMessage const* message);
42
43// ================================================================================
44static bool
45read_length_delimited(CodedInputStream* in, uint32 fieldId, Descriptor const* descriptor,
46 GenericMessage* message)
47{
48 uint32 size;
49 if (!in->ReadVarint32(&size)) {
50 return false;
51 }
52
53 FieldDescriptor const* field = descriptor->FindFieldByNumber(fieldId);
54 if (field != NULL) {
55 int type = field->type();
56 if (type == FieldDescriptor::TYPE_MESSAGE) {
57 GenericMessage* child = message->addMessage(fieldId);
58
59 CodedInputStream::Limit limit = in->PushLimit(size);
60 bool rv = read_message(in, field->message_type(), child);
61 in->PopLimit(limit);
62 return rv;
63 } else if (type == FieldDescriptor::TYPE_STRING) {
64 // TODO: do a version of readstring that just pumps the data
65 // rather than allocating a string which we don't care about.
66 string str;
67 if (in->ReadString(&str, size)) {
68 message->addString(fieldId, str);
69 return true;
70 } else {
71 return false;
72 }
73 } else if (type == FieldDescriptor::TYPE_BYTES) {
74 // TODO: Save bytes field.
75 return in->Skip(size);
76 }
77 }
78 return in->Skip(size);
79}
80
81// ================================================================================
82static bool
83read_message(CodedInputStream* in, Descriptor const* descriptor, GenericMessage* message)
84{
85 uint32 value32;
86 uint64 value64;
87
88 while (true) {
89 uint32 tag = in->ReadTag();
90 if (tag == 0) {
91 return true;
92 }
93 int fieldId = WireFormatLite::GetTagFieldNumber(tag);
94 switch (WireFormatLite::GetTagWireType(tag)) {
95 case WireFormatLite::WIRETYPE_VARINT:
96 if (in->ReadVarint64(&value64)) {
97 message->addInt64(fieldId, value64);
98 break;
99 } else {
Yi Jinf32af482017-08-11 15:00:49 -0700100 fprintf(stderr, "bad VARINT: 0x%x (%d) at index %d\n", tag, tag,
101 in->CurrentPosition());
Joe Onorato1754d742016-11-21 17:51:35 -0800102 return false;
103 }
104 case WireFormatLite::WIRETYPE_FIXED64:
105 if (in->ReadLittleEndian64(&value64)) {
106 message->addInt64(fieldId, value64);
107 break;
108 } else {
Yi Jinf32af482017-08-11 15:00:49 -0700109 fprintf(stderr, "bad VARINT: 0x%x (%d) at index %d\n", tag, tag,
110 in->CurrentPosition());
Joe Onorato1754d742016-11-21 17:51:35 -0800111 return false;
112 }
113 case WireFormatLite::WIRETYPE_LENGTH_DELIMITED:
114 if (!read_length_delimited(in, fieldId, descriptor, message)) {
Yi Jinf32af482017-08-11 15:00:49 -0700115 fprintf(stderr, "bad LENGTH_DELIMITED: 0x%x (%d) at index %d\n",
116 tag, tag, in->CurrentPosition());
Joe Onorato1754d742016-11-21 17:51:35 -0800117 return false;
118 }
119 break;
120 case WireFormatLite::WIRETYPE_FIXED32:
121 if (in->ReadLittleEndian32(&value32)) {
122 message->addInt32(fieldId, value32);
123 break;
124 } else {
Yi Jinf32af482017-08-11 15:00:49 -0700125 fprintf(stderr, "bad FIXED32: 0x%x (%d) at index %d\n", tag, tag,
126 in->CurrentPosition());
Joe Onorato1754d742016-11-21 17:51:35 -0800127 return false;
128 }
129 default:
130 fprintf(stderr, "bad tag: 0x%x (%d) at index %d\n", tag, tag,
131 in->CurrentPosition());
132 return false;
133 }
134 }
135}
136
137// ================================================================================
138static void
139print_value(Out* out, FieldDescriptor const* field, GenericMessage::Node const& node)
140{
141 uint32_t val32;
142 FieldDescriptor::Type type = field->type();
143
144 switch (node.type) {
145 case GenericMessage::TYPE_VALUE32:
146 switch (type) {
147 case FieldDescriptor::TYPE_FIXED32:
148 out->printf("%u", node.value32);
149 break;
150 case FieldDescriptor::TYPE_SFIXED32:
151 out->printf("%d", node.value32);
152 break;
153 case FieldDescriptor::TYPE_FLOAT:
154 out->printf("%f", *(float*)&node.value32);
155 break;
156 default:
Yi Jinf32af482017-08-11 15:00:49 -0700157 out->printf("(unexpected value32 %d (0x%x)", node.value32, node.value32);
Joe Onorato1754d742016-11-21 17:51:35 -0800158 break;
159 }
160 break;
161 case GenericMessage::TYPE_VALUE64:
162 switch (type) {
163 case FieldDescriptor::TYPE_FIXED64:
164 case FieldDescriptor::TYPE_SFIXED64:
165 case FieldDescriptor::TYPE_DOUBLE:
166 out->printf("%f", *(double*)&node.value64);
167 break;
168 case FieldDescriptor::TYPE_SINT32:
169 case FieldDescriptor::TYPE_INT32:
170 val32 = (uint32_t)node.value32;
171 out->printf("%d", val32);
172 break;
173 case FieldDescriptor::TYPE_INT64:
174 case FieldDescriptor::TYPE_UINT32:
175 val32 = (uint32_t)node.value32;
176 out->printf("%u", val32);
177 break;
178 case FieldDescriptor::TYPE_UINT64:
179 case FieldDescriptor::TYPE_SINT64:
180 case FieldDescriptor::TYPE_BOOL:
181 if (node.value64) {
182 out->printf("true");
183 } else {
184 out->printf("false");
185 }
186 break;
187 case FieldDescriptor::TYPE_ENUM:
Yi Jinf32af482017-08-11 15:00:49 -0700188 out->printf("%s", field->enum_type()->FindValueByNumber((int)node.value64)
189 ->name().c_str());
190 break;
Joe Onorato1754d742016-11-21 17:51:35 -0800191 default:
Yi Jinf32af482017-08-11 15:00:49 -0700192 out->printf("(unexpected value64 %ld (0x%x))", node.value64, node.value64);
Joe Onorato1754d742016-11-21 17:51:35 -0800193 break;
194 }
195 break;
196 case GenericMessage::TYPE_MESSAGE:
197 print_message(out, field->message_type(), node.message);
198 break;
199 case GenericMessage::TYPE_STRING:
200 // TODO: custom format for multi-line strings.
201 out->printf("%s", node.str->c_str());
202 break;
203 case GenericMessage::TYPE_DATA:
204 out->printf("<bytes>");
205 break;
206 }
207}
208
209static void
210print_message(Out* out, Descriptor const* descriptor, GenericMessage const* message)
211{
212 out->printf("%s {\n", descriptor->name().c_str());
213 out->indent();
214
215 int const N = descriptor->field_count();
216 for (int i=0; i<N; i++) {
217 FieldDescriptor const* field = descriptor->field(i);
218
219 int fieldId = field->number();
220 bool repeated = field->label() == FieldDescriptor::LABEL_REPEATED;
221 FieldDescriptor::Type type = field->type();
222 GenericMessage::const_iterator_pair it = message->find(fieldId);
223
224 out->printf("%s=", field->name().c_str());
225 if (repeated) {
226 if (it.first != it.second) {
227 out->printf("[");
228 if (type == FieldDescriptor::TYPE_MESSAGE
229 || type == FieldDescriptor::TYPE_STRING
230 || type == FieldDescriptor::TYPE_BYTES) {
231 out->printf("\n");
232 }
233 out->indent();
234
235 for (GenericMessage::const_iterator_pair it = message->find(fieldId);
236 it.first != it.second; it.first++) {
237 print_value(out, field, it.first->second);
238 if (type == FieldDescriptor::TYPE_MESSAGE
239 || type == FieldDescriptor::TYPE_STRING
240 || type == FieldDescriptor::TYPE_BYTES) {
241 out->printf("\n");
242 }
243 }
244
245 out->dedent();
246 out->printf("]");
247 } else {
248 out->printf("[]");
249 }
250 } else {
251 if (it.first != it.second) {
252 print_value(out, field, it.first->second);
253 } else {
254 switch (type) {
255 case FieldDescriptor::TYPE_BOOL:
256 out->printf("false");
257 break;
258 case FieldDescriptor::TYPE_STRING:
259 case FieldDescriptor::TYPE_MESSAGE:
260 out->printf("");
261 break;
262 case FieldDescriptor::TYPE_ENUM:
263 out->printf("%s", field->default_value_enum()->name().c_str());
264 break;
265 default:
266 out->printf("0");
267 break;
268 }
269 }
270 }
271 out->printf("\n");
272 }
273 out->dedent();
274 out->printf("}");
275}
276
277// ================================================================================
278static uint8_t*
279write_raw_varint(uint8_t* buf, uint32_t val)
280{
281 uint8_t* p = buf;
282 while (true) {
283 if ((val & ~0x7F) == 0) {
284 *p++ = (uint8_t)val;
285 return p;
286 } else {
287 *p++ = (uint8_t)((val & 0x7F) | 0x80);
288 val >>= 7;
289 }
290 }
291}
292
293static int
294write_all(int fd, uint8_t const* buf, size_t size)
295{
296 while (size > 0) {
297 ssize_t amt = ::write(fd, buf, size);
298 if (amt < 0) {
299 return errno;
300 }
301 size -= amt;
302 buf += amt;
303 }
304 return 0;
305}
306
307static int
308adb_incident_workaround(const char* adbSerial, const vector<string>& sections)
309{
310 const int maxAllowedSize = 20 * 1024 * 1024; // 20MB
Yunlian Jiang7a757a02017-07-25 16:03:05 -0700311 unique_ptr<uint8_t[]> buffer(new uint8_t[maxAllowedSize]);
Joe Onorato1754d742016-11-21 17:51:35 -0800312
313 for (vector<string>::const_iterator it=sections.begin(); it!=sections.end(); it++) {
314 Descriptor const* descriptor = IncidentProto::descriptor();
315 FieldDescriptor const* field;
316
317 // Get the name and field id.
318 string name = *it;
319 char* end;
320 int id = strtol(name.c_str(), &end, 0);
321 if (*end == '\0') {
322 // If it's an id, find out the string.
323 field = descriptor->FindFieldByNumber(id);
324 if (field == NULL) {
325 fprintf(stderr, "Unable to find field number: %d\n", id);
326 return 1;
327 }
328 name = field->name();
329 } else {
330 // If it's a string, find out the id.
331 field = descriptor->FindFieldByName(name);
332 if (field == NULL) {
333 fprintf(stderr, "Unable to find field: %s\n", name.c_str());
334 return 1;
335 }
336 id = field->number();
337 }
338
339 int pfd[2];
340 if (pipe(pfd) != 0) {
341 fprintf(stderr, "pipe failed: %s\n", strerror(errno));
342 return 1;
343 }
344
345 pid_t pid = fork();
346 if (pid == -1) {
347 fprintf(stderr, "fork failed: %s\n", strerror(errno));
348 return 1;
349 } else if (pid == 0) {
350 // child
351 dup2(pfd[1], STDOUT_FILENO);
352 close(pfd[0]);
353 close(pfd[1]);
354
355 char const** args = (char const**)malloc(sizeof(char*) * 8);
356 int argpos = 0;
357 args[argpos++] = "adb";
358 if (adbSerial != NULL) {
359 args[argpos++] = "-s";
360 args[argpos++] = adbSerial;
361 }
362 args[argpos++] = "shell";
363 args[argpos++] = "dumpsys";
364 args[argpos++] = name.c_str();
365 args[argpos++] = "--proto";
366 args[argpos++] = NULL;
367 execvp(args[0], (char*const*)args);
368 fprintf(stderr, "execvp failed: %s\n", strerror(errno));
Yunlian Jiang89547ce2017-01-31 16:17:50 -0800369 free(args);
Joe Onorato1754d742016-11-21 17:51:35 -0800370 return 1;
371 } else {
372 // parent
373 close(pfd[1]);
374
375 size_t size = 0;
376 while (size < maxAllowedSize) {
Yunlian Jiang7a757a02017-07-25 16:03:05 -0700377 ssize_t amt = read(pfd[0], buffer.get() + size, maxAllowedSize - size);
Joe Onorato1754d742016-11-21 17:51:35 -0800378 if (amt == 0) {
379 break;
380 } else if (amt == -1) {
381 fprintf(stderr, "read error: %s\n", strerror(errno));
382 return 1;
383 }
384 size += amt;
385 }
386
387 int status;
388 do {
389 waitpid(pid, &status, 0);
390 } while (!WIFEXITED(status));
391 if (WEXITSTATUS(status) != 0) {
392 return WEXITSTATUS(status);
393 }
394
395 if (size > 0) {
396 uint8_t header[20];
397 uint8_t* p = write_raw_varint(header, (id << 3) | 2);
398 p = write_raw_varint(p, size);
399 int err = write_all(STDOUT_FILENO, header, p-header);
400 if (err != 0) {
401 fprintf(stderr, "write error: %s\n", strerror(err));
402 return 1;
403 }
Yunlian Jiang7a757a02017-07-25 16:03:05 -0700404 err = write_all(STDOUT_FILENO, buffer.get(), size);
Joe Onorato1754d742016-11-21 17:51:35 -0800405 if (err != 0) {
406 fprintf(stderr, "write error: %s\n", strerror(err));
407 return 1;
408 }
409 }
410
411 close(pfd[0]);
412 }
413 }
414
Joe Onorato1754d742016-11-21 17:51:35 -0800415 return 0;
416}
417
418// ================================================================================
419static void
420usage(FILE* out)
421{
422 fprintf(out, "usage: incident_report -i INPUT [-o OUTPUT]\n");
423 fprintf(out, "\n");
424 fprintf(out, "Pretty-prints an incident report protobuf file.\n");
425 fprintf(out, " -i INPUT the input file. INPUT may be '-' to use stdin\n");
426 fprintf(out, " -o OUTPUT the output file. OUTPUT may be '-' or omitted to use stdout\n");
427 fprintf(out, "\n");
428 fprintf(out, "\n");
429 fprintf(out, "usage: incident_report [-o OUTPUT] [-t|b] [-s SERIAL] [SECTION...]\n");
430 fprintf(out, "\n");
431 fprintf(out, "Take an incident report over adb (which must be in the PATH).\n");
432 fprintf(out, " -b output the incident report raw protobuf format\n");
433 fprintf(out, " -o OUTPUT the output file. OUTPUT may be '-' or omitted to use stdout\n");
434 fprintf(out, " -s SERIAL sent to adb to choose which device, instead of $ANDROID_SERIAL\n");
435 fprintf(out, " -t output the incident report in pretty-printed text format\n");
436 fprintf(out, "\n");
437 fprintf(out, " SECTION which bugreport sections to print, either the int code of the\n");
438 fprintf(out, " section in the Incident proto or the field name. If ommited,\n");
439 fprintf(out, " the report will contain all fields\n");
440 fprintf(out, "\n");
441}
442
443int
444main(int argc, char** argv)
445{
446 enum { OUTPUT_TEXT, OUTPUT_PROTO } outputFormat = OUTPUT_TEXT;
447 const char* inFilename = NULL;
448 const char* outFilename = NULL;
449 const char* adbSerial = NULL;
450 bool adbIncidentWorkaround = true;
451 pid_t childPid = -1;
452 vector<string> sections;
453
454 int opt;
455 while ((opt = getopt(argc, argv, "bhi:o:s:tw")) != -1) {
456 switch (opt) {
457 case 'b':
458 outputFormat = OUTPUT_PROTO;
459 break;
460 case 'i':
461 inFilename = optarg;
462 break;
463 case 'o':
464 outFilename = optarg;
465 break;
466 case 's':
467 adbSerial = optarg;
468 break;
469 case 't':
470 outputFormat = OUTPUT_TEXT;
471 break;
472 case 'h':
473 usage(stdout);
474 return 0;
475 case 'w':
476 adbIncidentWorkaround = false;
477 break;
478 default:
479 usage(stderr);
480 return 1;
481 }
482 }
483
484 while (optind < argc) {
485 sections.push_back(argv[optind++]);
486 }
487
488 int inFd;
489 if (inFilename != NULL) {
490 // translate-only mode - oepn the file or use stdin.
491 if (strcmp("-", inFilename) == 0) {
492 inFd = STDIN_FILENO;
493 } else {
494 inFd = open(inFilename, O_RDONLY | O_CLOEXEC);
495 if (inFd < 0) {
496 fprintf(stderr, "unable to open file for read (%s): %s\n", strerror(errno),
497 inFilename);
498 return 1;
499 }
500 }
501 } else {
502 // pipe mode - run adb shell incident ...
503 int pfd[2];
504 if (pipe(pfd) != 0) {
505 fprintf(stderr, "pipe failed: %s\n", strerror(errno));
506 return 1;
507 }
508
509 childPid = fork();
510 if (childPid == -1) {
511 fprintf(stderr, "fork failed: %s\n", strerror(errno));
512 return 1;
513 } else if (childPid == 0) {
514 dup2(pfd[1], STDOUT_FILENO);
515 close(pfd[0]);
516 close(pfd[1]);
517 // child
518 if (adbIncidentWorkaround) {
519 // TODO: Until the device side incident command is checked in,
520 // the incident_report builds the outer Incident proto by hand
521 // from individual adb shell dumpsys <service> --proto calls,
522 // with a maximum allowed output size.
523 return adb_incident_workaround(adbSerial, sections);
524 }
525
526 // TODO: This is what the real implementation will be...
527 char const** args = (char const**)malloc(sizeof(char*) * (6 + sections.size()));
528 int argpos = 0;
529 args[argpos++] = "adb";
530 if (adbSerial != NULL) {
531 args[argpos++] = "-s";
532 args[argpos++] = adbSerial;
533 }
534 args[argpos++] = "shell";
535 args[argpos++] = "incident";
536 for (vector<string>::const_iterator it=sections.begin(); it!=sections.end(); it++) {
537 args[argpos++] = it->c_str();
538 }
539 args[argpos++] = NULL;
540 execvp(args[0], (char*const*)args);
541 fprintf(stderr, "execvp failed: %s\n", strerror(errno));
542 return 0;
543 } else {
544 // parent
545 inFd = pfd[0];
546 close(pfd[1]);
547 }
548 }
549
550 int outFd;
551 if (outFilename == NULL || strcmp("-", outFilename) == 0) {
552 outFd = STDOUT_FILENO;
553 } else {
554 outFd = open(outFilename, O_CREAT | O_RDWR, 0666);
555 if (outFd < 0) {
556 fprintf(stderr, "unable to open file for write: %s\n", outFilename);
557 return 1;
558 }
559 }
560
561 GenericMessage message;
562
563 Descriptor const* descriptor = IncidentProto::descriptor();
564 FileInputStream infile(inFd);
565 CodedInputStream in(&infile);
566
567 if (!read_message(&in, descriptor, &message)) {
568 fprintf(stderr, "unable to read incident\n");
569 return 1;
570 }
571
572 Out out(outFd);
573
574 print_message(&out, descriptor, &message);
575 out.printf("\n");
576
577 if (childPid != -1) {
578 int status;
579 do {
580 waitpid(childPid, &status, 0);
581 } while (!WIFEXITED(status));
582 if (WEXITSTATUS(status) != 0) {
583 return WEXITSTATUS(status);
584 }
585 }
586
587 return 0;
588}