blob: 302d7395f3e46cab2a591fc79cc16aa122c407e9 [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 Onorato76690122016-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{
Yi Jin22769e02017-10-16 14:42:50 -070048 uint32_t size;
Joe Onorato1754d742016-11-21 17:51:35 -080049 if (!in->ReadVarint32(&size)) {
Yi Jin22769e02017-10-16 14:42:50 -070050 fprintf(stderr, "Fail to read size of %s\n", descriptor->name().c_str());
Joe Onorato1754d742016-11-21 17:51:35 -080051 return false;
52 }
53
54 FieldDescriptor const* field = descriptor->FindFieldByNumber(fieldId);
55 if (field != NULL) {
56 int type = field->type();
57 if (type == FieldDescriptor::TYPE_MESSAGE) {
58 GenericMessage* child = message->addMessage(fieldId);
59
60 CodedInputStream::Limit limit = in->PushLimit(size);
61 bool rv = read_message(in, field->message_type(), child);
62 in->PopLimit(limit);
63 return rv;
64 } else if (type == FieldDescriptor::TYPE_STRING) {
65 // TODO: do a version of readstring that just pumps the data
66 // rather than allocating a string which we don't care about.
67 string str;
68 if (in->ReadString(&str, size)) {
69 message->addString(fieldId, str);
70 return true;
71 } else {
Yi Jin22769e02017-10-16 14:42:50 -070072 fprintf(stderr, "Fail to read string of field %s, expect size %d, read %lu\n",
73 field->full_name().c_str(), size, str.size());
74 fprintf(stderr, "String read \"%s\"\n", str.c_str());
Joe Onorato1754d742016-11-21 17:51:35 -080075 return false;
76 }
77 } else if (type == FieldDescriptor::TYPE_BYTES) {
78 // TODO: Save bytes field.
79 return in->Skip(size);
80 }
81 }
82 return in->Skip(size);
83}
84
85// ================================================================================
86static bool
87read_message(CodedInputStream* in, Descriptor const* descriptor, GenericMessage* message)
88{
89 uint32 value32;
90 uint64 value64;
91
92 while (true) {
93 uint32 tag = in->ReadTag();
94 if (tag == 0) {
95 return true;
96 }
97 int fieldId = WireFormatLite::GetTagFieldNumber(tag);
98 switch (WireFormatLite::GetTagWireType(tag)) {
99 case WireFormatLite::WIRETYPE_VARINT:
100 if (in->ReadVarint64(&value64)) {
101 message->addInt64(fieldId, value64);
102 break;
103 } else {
Yi Jin129fc6c2017-09-28 15:48:38 -0700104 fprintf(stderr, "bad VARINT: 0x%x (%d) at index %d of field %s\n",
105 tag, tag, in->CurrentPosition(), descriptor->name().c_str());
Joe Onorato1754d742016-11-21 17:51:35 -0800106 return false;
107 }
108 case WireFormatLite::WIRETYPE_FIXED64:
109 if (in->ReadLittleEndian64(&value64)) {
110 message->addInt64(fieldId, value64);
111 break;
112 } else {
Yi Jin129fc6c2017-09-28 15:48:38 -0700113 fprintf(stderr, "bad VARINT: 0x%x (%d) at index %d of field %s\n",
114 tag, tag, in->CurrentPosition(), descriptor->name().c_str());
Joe Onorato1754d742016-11-21 17:51:35 -0800115 return false;
116 }
117 case WireFormatLite::WIRETYPE_LENGTH_DELIMITED:
118 if (!read_length_delimited(in, fieldId, descriptor, message)) {
Yi Jin129fc6c2017-09-28 15:48:38 -0700119 fprintf(stderr, "bad LENGTH_DELIMITED: 0x%x (%d) at index %d of field %s\n",
120 tag, tag, in->CurrentPosition(), descriptor->name().c_str());
Joe Onorato1754d742016-11-21 17:51:35 -0800121 return false;
122 }
123 break;
124 case WireFormatLite::WIRETYPE_FIXED32:
125 if (in->ReadLittleEndian32(&value32)) {
126 message->addInt32(fieldId, value32);
127 break;
128 } else {
Yi Jin129fc6c2017-09-28 15:48:38 -0700129 fprintf(stderr, "bad FIXED32: 0x%x (%d) at index %d of field %s\n",
130 tag, tag, in->CurrentPosition(), descriptor->name().c_str());
Joe Onorato1754d742016-11-21 17:51:35 -0800131 return false;
132 }
133 default:
Yi Jin129fc6c2017-09-28 15:48:38 -0700134 fprintf(stderr, "bad tag: 0x%x (%d) at index %d of field %s\n", tag, tag,
135 in->CurrentPosition(), descriptor->name().c_str());
Joe Onorato1754d742016-11-21 17:51:35 -0800136 return false;
137 }
138 }
139}
140
141// ================================================================================
142static void
143print_value(Out* out, FieldDescriptor const* field, GenericMessage::Node const& node)
144{
Joe Onorato1754d742016-11-21 17:51:35 -0800145 FieldDescriptor::Type type = field->type();
146
147 switch (node.type) {
148 case GenericMessage::TYPE_VALUE32:
149 switch (type) {
150 case FieldDescriptor::TYPE_FIXED32:
151 out->printf("%u", node.value32);
152 break;
153 case FieldDescriptor::TYPE_SFIXED32:
154 out->printf("%d", node.value32);
155 break;
156 case FieldDescriptor::TYPE_FLOAT:
157 out->printf("%f", *(float*)&node.value32);
158 break;
159 default:
Yi Jin129fc6c2017-09-28 15:48:38 -0700160 out->printf("(unexpected type %d: value32 %d (0x%x)",
161 type, node.value32, node.value32);
Joe Onorato1754d742016-11-21 17:51:35 -0800162 break;
163 }
164 break;
165 case GenericMessage::TYPE_VALUE64:
166 switch (type) {
Joe Onorato1754d742016-11-21 17:51:35 -0800167 case FieldDescriptor::TYPE_DOUBLE:
168 out->printf("%f", *(double*)&node.value64);
169 break;
Kweku Adamsee649592017-10-04 16:03:57 -0700170 // Int32s here were added with addInt64 from a WIRETYPE_VARINT,
171 // even if the definition is for a 32 bit int.
Joe Onorato1754d742016-11-21 17:51:35 -0800172 case FieldDescriptor::TYPE_SINT32:
173 case FieldDescriptor::TYPE_INT32:
Kweku Adamsee649592017-10-04 16:03:57 -0700174 out->printf("%d", node.value64);
Joe Onorato1754d742016-11-21 17:51:35 -0800175 break;
176 case FieldDescriptor::TYPE_INT64:
Joe Onorato1754d742016-11-21 17:51:35 -0800177 case FieldDescriptor::TYPE_SINT64:
Kweku Adamsee649592017-10-04 16:03:57 -0700178 case FieldDescriptor::TYPE_SFIXED64:
179 out->printf("%lld", node.value64);
180 break;
181 case FieldDescriptor::TYPE_UINT32:
182 case FieldDescriptor::TYPE_UINT64:
183 case FieldDescriptor::TYPE_FIXED64:
184 out->printf("%u", node.value64);
185 break;
Joe Onorato1754d742016-11-21 17:51:35 -0800186 case FieldDescriptor::TYPE_BOOL:
187 if (node.value64) {
188 out->printf("true");
189 } else {
190 out->printf("false");
191 }
192 break;
193 case FieldDescriptor::TYPE_ENUM:
Kweku Adamsee649592017-10-04 16:03:57 -0700194 if (field->enum_type()->FindValueByNumber((int)node.value64) == NULL) {
195 out->printf("%lld", (int) node.value64);
196 } else {
197 out->printf("%s", field->enum_type()->FindValueByNumber((int)node.value64)
Yi Jinf32af482017-08-11 15:00:49 -0700198 ->name().c_str());
Kweku Adamsee649592017-10-04 16:03:57 -0700199 }
Yi Jinf32af482017-08-11 15:00:49 -0700200 break;
Joe Onorato1754d742016-11-21 17:51:35 -0800201 default:
Yi Jin129fc6c2017-09-28 15:48:38 -0700202 out->printf("(unexpected type %d: value64 %lld (0x%x))",
203 type, node.value64, node.value64);
Joe Onorato1754d742016-11-21 17:51:35 -0800204 break;
205 }
206 break;
207 case GenericMessage::TYPE_MESSAGE:
208 print_message(out, field->message_type(), node.message);
209 break;
210 case GenericMessage::TYPE_STRING:
211 // TODO: custom format for multi-line strings.
212 out->printf("%s", node.str->c_str());
213 break;
214 case GenericMessage::TYPE_DATA:
215 out->printf("<bytes>");
216 break;
217 }
218}
219
220static void
221print_message(Out* out, Descriptor const* descriptor, GenericMessage const* message)
222{
223 out->printf("%s {\n", descriptor->name().c_str());
224 out->indent();
225
226 int const N = descriptor->field_count();
227 for (int i=0; i<N; i++) {
228 FieldDescriptor const* field = descriptor->field(i);
229
230 int fieldId = field->number();
231 bool repeated = field->label() == FieldDescriptor::LABEL_REPEATED;
232 FieldDescriptor::Type type = field->type();
233 GenericMessage::const_iterator_pair it = message->find(fieldId);
234
235 out->printf("%s=", field->name().c_str());
236 if (repeated) {
237 if (it.first != it.second) {
Kweku Adamsee649592017-10-04 16:03:57 -0700238 out->printf("[\n");
Joe Onorato1754d742016-11-21 17:51:35 -0800239 out->indent();
240
241 for (GenericMessage::const_iterator_pair it = message->find(fieldId);
242 it.first != it.second; it.first++) {
243 print_value(out, field, it.first->second);
Kweku Adamsee649592017-10-04 16:03:57 -0700244 out->printf("\n");
Joe Onorato1754d742016-11-21 17:51:35 -0800245 }
246
247 out->dedent();
248 out->printf("]");
249 } else {
250 out->printf("[]");
251 }
252 } else {
253 if (it.first != it.second) {
254 print_value(out, field, it.first->second);
255 } else {
256 switch (type) {
257 case FieldDescriptor::TYPE_BOOL:
258 out->printf("false");
259 break;
260 case FieldDescriptor::TYPE_STRING:
261 case FieldDescriptor::TYPE_MESSAGE:
262 out->printf("");
263 break;
264 case FieldDescriptor::TYPE_ENUM:
265 out->printf("%s", field->default_value_enum()->name().c_str());
266 break;
267 default:
268 out->printf("0");
269 break;
270 }
271 }
272 }
273 out->printf("\n");
274 }
275 out->dedent();
276 out->printf("}");
277}
278
279// ================================================================================
280static uint8_t*
281write_raw_varint(uint8_t* buf, uint32_t val)
282{
283 uint8_t* p = buf;
284 while (true) {
285 if ((val & ~0x7F) == 0) {
286 *p++ = (uint8_t)val;
287 return p;
288 } else {
289 *p++ = (uint8_t)((val & 0x7F) | 0x80);
290 val >>= 7;
291 }
292 }
293}
294
295static int
296write_all(int fd, uint8_t const* buf, size_t size)
297{
298 while (size > 0) {
299 ssize_t amt = ::write(fd, buf, size);
300 if (amt < 0) {
301 return errno;
302 }
303 size -= amt;
304 buf += amt;
305 }
306 return 0;
307}
308
309static int
310adb_incident_workaround(const char* adbSerial, const vector<string>& sections)
311{
312 const int maxAllowedSize = 20 * 1024 * 1024; // 20MB
Yunlian Jiang7a757a02017-07-25 16:03:05 -0700313 unique_ptr<uint8_t[]> buffer(new uint8_t[maxAllowedSize]);
Joe Onorato1754d742016-11-21 17:51:35 -0800314
315 for (vector<string>::const_iterator it=sections.begin(); it!=sections.end(); it++) {
316 Descriptor const* descriptor = IncidentProto::descriptor();
317 FieldDescriptor const* field;
318
319 // Get the name and field id.
320 string name = *it;
321 char* end;
322 int id = strtol(name.c_str(), &end, 0);
323 if (*end == '\0') {
324 // If it's an id, find out the string.
325 field = descriptor->FindFieldByNumber(id);
326 if (field == NULL) {
327 fprintf(stderr, "Unable to find field number: %d\n", id);
328 return 1;
329 }
330 name = field->name();
331 } else {
332 // If it's a string, find out the id.
333 field = descriptor->FindFieldByName(name);
334 if (field == NULL) {
335 fprintf(stderr, "Unable to find field: %s\n", name.c_str());
336 return 1;
337 }
338 id = field->number();
339 }
Kweku Adamsee649592017-10-04 16:03:57 -0700340
Joe Onorato1754d742016-11-21 17:51:35 -0800341 int pfd[2];
342 if (pipe(pfd) != 0) {
343 fprintf(stderr, "pipe failed: %s\n", strerror(errno));
344 return 1;
345 }
346
347 pid_t pid = fork();
348 if (pid == -1) {
349 fprintf(stderr, "fork failed: %s\n", strerror(errno));
350 return 1;
351 } else if (pid == 0) {
352 // child
353 dup2(pfd[1], STDOUT_FILENO);
354 close(pfd[0]);
355 close(pfd[1]);
356
357 char const** args = (char const**)malloc(sizeof(char*) * 8);
358 int argpos = 0;
359 args[argpos++] = "adb";
360 if (adbSerial != NULL) {
361 args[argpos++] = "-s";
362 args[argpos++] = adbSerial;
363 }
364 args[argpos++] = "shell";
365 args[argpos++] = "dumpsys";
366 args[argpos++] = name.c_str();
367 args[argpos++] = "--proto";
368 args[argpos++] = NULL;
369 execvp(args[0], (char*const*)args);
370 fprintf(stderr, "execvp failed: %s\n", strerror(errno));
Yunlian Jiang89547ce2017-01-31 16:17:50 -0800371 free(args);
Joe Onorato1754d742016-11-21 17:51:35 -0800372 return 1;
373 } else {
374 // parent
375 close(pfd[1]);
376
377 size_t size = 0;
378 while (size < maxAllowedSize) {
Yunlian Jiang7a757a02017-07-25 16:03:05 -0700379 ssize_t amt = read(pfd[0], buffer.get() + size, maxAllowedSize - size);
Joe Onorato1754d742016-11-21 17:51:35 -0800380 if (amt == 0) {
381 break;
382 } else if (amt == -1) {
383 fprintf(stderr, "read error: %s\n", strerror(errno));
384 return 1;
385 }
386 size += amt;
387 }
388
389 int status;
390 do {
391 waitpid(pid, &status, 0);
392 } while (!WIFEXITED(status));
393 if (WEXITSTATUS(status) != 0) {
394 return WEXITSTATUS(status);
395 }
396
397 if (size > 0) {
398 uint8_t header[20];
399 uint8_t* p = write_raw_varint(header, (id << 3) | 2);
400 p = write_raw_varint(p, size);
401 int err = write_all(STDOUT_FILENO, header, p-header);
402 if (err != 0) {
403 fprintf(stderr, "write error: %s\n", strerror(err));
404 return 1;
405 }
Yunlian Jiang7a757a02017-07-25 16:03:05 -0700406 err = write_all(STDOUT_FILENO, buffer.get(), size);
Joe Onorato1754d742016-11-21 17:51:35 -0800407 if (err != 0) {
408 fprintf(stderr, "write error: %s\n", strerror(err));
409 return 1;
410 }
411 }
412
413 close(pfd[0]);
414 }
415 }
416
Joe Onorato1754d742016-11-21 17:51:35 -0800417 return 0;
418}
419
420// ================================================================================
421static void
422usage(FILE* out)
423{
424 fprintf(out, "usage: incident_report -i INPUT [-o OUTPUT]\n");
425 fprintf(out, "\n");
426 fprintf(out, "Pretty-prints an incident report protobuf file.\n");
427 fprintf(out, " -i INPUT the input file. INPUT may be '-' to use stdin\n");
428 fprintf(out, " -o OUTPUT the output file. OUTPUT may be '-' or omitted to use stdout\n");
429 fprintf(out, "\n");
430 fprintf(out, "\n");
431 fprintf(out, "usage: incident_report [-o OUTPUT] [-t|b] [-s SERIAL] [SECTION...]\n");
432 fprintf(out, "\n");
433 fprintf(out, "Take an incident report over adb (which must be in the PATH).\n");
434 fprintf(out, " -b output the incident report raw protobuf format\n");
435 fprintf(out, " -o OUTPUT the output file. OUTPUT may be '-' or omitted to use stdout\n");
436 fprintf(out, " -s SERIAL sent to adb to choose which device, instead of $ANDROID_SERIAL\n");
437 fprintf(out, " -t output the incident report in pretty-printed text format\n");
438 fprintf(out, "\n");
439 fprintf(out, " SECTION which bugreport sections to print, either the int code of the\n");
440 fprintf(out, " section in the Incident proto or the field name. If ommited,\n");
441 fprintf(out, " the report will contain all fields\n");
442 fprintf(out, "\n");
443}
444
445int
446main(int argc, char** argv)
447{
448 enum { OUTPUT_TEXT, OUTPUT_PROTO } outputFormat = OUTPUT_TEXT;
449 const char* inFilename = NULL;
450 const char* outFilename = NULL;
451 const char* adbSerial = NULL;
452 bool adbIncidentWorkaround = true;
453 pid_t childPid = -1;
454 vector<string> sections;
Yi Jinb8344dc2018-01-24 17:33:35 -0800455 const char* privacy = NULL;
Joe Onorato1754d742016-11-21 17:51:35 -0800456
457 int opt;
Yi Jinb8344dc2018-01-24 17:33:35 -0800458 while ((opt = getopt(argc, argv, "bhi:o:s:twp:")) != -1) {
Joe Onorato1754d742016-11-21 17:51:35 -0800459 switch (opt) {
460 case 'b':
461 outputFormat = OUTPUT_PROTO;
462 break;
463 case 'i':
464 inFilename = optarg;
465 break;
466 case 'o':
467 outFilename = optarg;
468 break;
469 case 's':
470 adbSerial = optarg;
471 break;
472 case 't':
473 outputFormat = OUTPUT_TEXT;
474 break;
475 case 'h':
476 usage(stdout);
477 return 0;
478 case 'w':
479 adbIncidentWorkaround = false;
480 break;
Yi Jinb8344dc2018-01-24 17:33:35 -0800481 case 'p':
482 privacy = optarg;
483 break;
Joe Onorato1754d742016-11-21 17:51:35 -0800484 default:
485 usage(stderr);
486 return 1;
487 }
488 }
489
490 while (optind < argc) {
491 sections.push_back(argv[optind++]);
492 }
493
494 int inFd;
495 if (inFilename != NULL) {
496 // translate-only mode - oepn the file or use stdin.
497 if (strcmp("-", inFilename) == 0) {
498 inFd = STDIN_FILENO;
499 } else {
500 inFd = open(inFilename, O_RDONLY | O_CLOEXEC);
501 if (inFd < 0) {
502 fprintf(stderr, "unable to open file for read (%s): %s\n", strerror(errno),
503 inFilename);
504 return 1;
505 }
506 }
507 } else {
508 // pipe mode - run adb shell incident ...
509 int pfd[2];
510 if (pipe(pfd) != 0) {
511 fprintf(stderr, "pipe failed: %s\n", strerror(errno));
512 return 1;
513 }
514
515 childPid = fork();
516 if (childPid == -1) {
517 fprintf(stderr, "fork failed: %s\n", strerror(errno));
518 return 1;
519 } else if (childPid == 0) {
520 dup2(pfd[1], STDOUT_FILENO);
521 close(pfd[0]);
522 close(pfd[1]);
523 // child
524 if (adbIncidentWorkaround) {
525 // TODO: Until the device side incident command is checked in,
526 // the incident_report builds the outer Incident proto by hand
527 // from individual adb shell dumpsys <service> --proto calls,
528 // with a maximum allowed output size.
529 return adb_incident_workaround(adbSerial, sections);
530 }
531
532 // TODO: This is what the real implementation will be...
Yi Jinb8344dc2018-01-24 17:33:35 -0800533 char const** args = (char const**)malloc(sizeof(char*) * (8 + sections.size()));
Joe Onorato1754d742016-11-21 17:51:35 -0800534 int argpos = 0;
535 args[argpos++] = "adb";
536 if (adbSerial != NULL) {
537 args[argpos++] = "-s";
538 args[argpos++] = adbSerial;
539 }
540 args[argpos++] = "shell";
541 args[argpos++] = "incident";
Yi Jinb8344dc2018-01-24 17:33:35 -0800542 if (privacy != NULL) {
543 args[argpos++] = "-p";
544 args[argpos++] = privacy;
545 }
Joe Onorato1754d742016-11-21 17:51:35 -0800546 for (vector<string>::const_iterator it=sections.begin(); it!=sections.end(); it++) {
547 args[argpos++] = it->c_str();
548 }
549 args[argpos++] = NULL;
550 execvp(args[0], (char*const*)args);
551 fprintf(stderr, "execvp failed: %s\n", strerror(errno));
552 return 0;
553 } else {
554 // parent
555 inFd = pfd[0];
556 close(pfd[1]);
557 }
558 }
559
560 int outFd;
561 if (outFilename == NULL || strcmp("-", outFilename) == 0) {
562 outFd = STDOUT_FILENO;
563 } else {
564 outFd = open(outFilename, O_CREAT | O_RDWR, 0666);
565 if (outFd < 0) {
566 fprintf(stderr, "unable to open file for write: %s\n", outFilename);
567 return 1;
568 }
569 }
570
571 GenericMessage message;
572
573 Descriptor const* descriptor = IncidentProto::descriptor();
574 FileInputStream infile(inFd);
575 CodedInputStream in(&infile);
576
577 if (!read_message(&in, descriptor, &message)) {
578 fprintf(stderr, "unable to read incident\n");
579 return 1;
580 }
581
582 Out out(outFd);
583
584 print_message(&out, descriptor, &message);
585 out.printf("\n");
586
587 if (childPid != -1) {
588 int status;
589 do {
590 waitpid(childPid, &status, 0);
591 } while (!WIFEXITED(status));
592 if (WEXITSTATUS(status) != 0) {
593 return WEXITSTATUS(status);
594 }
595 }
596
597 return 0;
598}