blob: cc252649da96685336152402e0e013999af2dedc [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 Jin129fc6c2017-09-28 15:48:38 -0700100 fprintf(stderr, "bad VARINT: 0x%x (%d) at index %d of field %s\n",
101 tag, tag, in->CurrentPosition(), descriptor->name().c_str());
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 Jin129fc6c2017-09-28 15:48:38 -0700109 fprintf(stderr, "bad VARINT: 0x%x (%d) at index %d of field %s\n",
110 tag, tag, in->CurrentPosition(), descriptor->name().c_str());
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 Jin129fc6c2017-09-28 15:48:38 -0700115 fprintf(stderr, "bad LENGTH_DELIMITED: 0x%x (%d) at index %d of field %s\n",
116 tag, tag, in->CurrentPosition(), descriptor->name().c_str());
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 Jin129fc6c2017-09-28 15:48:38 -0700125 fprintf(stderr, "bad FIXED32: 0x%x (%d) at index %d of field %s\n",
126 tag, tag, in->CurrentPosition(), descriptor->name().c_str());
Joe Onorato1754d742016-11-21 17:51:35 -0800127 return false;
128 }
129 default:
Yi Jin129fc6c2017-09-28 15:48:38 -0700130 fprintf(stderr, "bad tag: 0x%x (%d) at index %d of field %s\n", tag, tag,
131 in->CurrentPosition(), descriptor->name().c_str());
Joe Onorato1754d742016-11-21 17:51:35 -0800132 return false;
133 }
134 }
135}
136
137// ================================================================================
138static void
139print_value(Out* out, FieldDescriptor const* field, GenericMessage::Node const& node)
140{
Joe Onorato1754d742016-11-21 17:51:35 -0800141 FieldDescriptor::Type type = field->type();
142
143 switch (node.type) {
144 case GenericMessage::TYPE_VALUE32:
145 switch (type) {
146 case FieldDescriptor::TYPE_FIXED32:
147 out->printf("%u", node.value32);
148 break;
149 case FieldDescriptor::TYPE_SFIXED32:
150 out->printf("%d", node.value32);
151 break;
152 case FieldDescriptor::TYPE_FLOAT:
153 out->printf("%f", *(float*)&node.value32);
154 break;
155 default:
Yi Jin129fc6c2017-09-28 15:48:38 -0700156 out->printf("(unexpected type %d: value32 %d (0x%x)",
157 type, node.value32, node.value32);
Joe Onorato1754d742016-11-21 17:51:35 -0800158 break;
159 }
160 break;
161 case GenericMessage::TYPE_VALUE64:
162 switch (type) {
Joe Onorato1754d742016-11-21 17:51:35 -0800163 case FieldDescriptor::TYPE_DOUBLE:
164 out->printf("%f", *(double*)&node.value64);
165 break;
Kweku Adamsee649592017-10-04 16:03:57 -0700166 // Int32s here were added with addInt64 from a WIRETYPE_VARINT,
167 // even if the definition is for a 32 bit int.
Joe Onorato1754d742016-11-21 17:51:35 -0800168 case FieldDescriptor::TYPE_SINT32:
169 case FieldDescriptor::TYPE_INT32:
Kweku Adamsee649592017-10-04 16:03:57 -0700170 out->printf("%d", node.value64);
Joe Onorato1754d742016-11-21 17:51:35 -0800171 break;
172 case FieldDescriptor::TYPE_INT64:
Joe Onorato1754d742016-11-21 17:51:35 -0800173 case FieldDescriptor::TYPE_SINT64:
Kweku Adamsee649592017-10-04 16:03:57 -0700174 case FieldDescriptor::TYPE_SFIXED64:
175 out->printf("%lld", node.value64);
176 break;
177 case FieldDescriptor::TYPE_UINT32:
178 case FieldDescriptor::TYPE_UINT64:
179 case FieldDescriptor::TYPE_FIXED64:
180 out->printf("%u", node.value64);
181 break;
Joe Onorato1754d742016-11-21 17:51:35 -0800182 case FieldDescriptor::TYPE_BOOL:
183 if (node.value64) {
184 out->printf("true");
185 } else {
186 out->printf("false");
187 }
188 break;
189 case FieldDescriptor::TYPE_ENUM:
Kweku Adamsee649592017-10-04 16:03:57 -0700190 if (field->enum_type()->FindValueByNumber((int)node.value64) == NULL) {
191 out->printf("%lld", (int) node.value64);
192 } else {
193 out->printf("%s", field->enum_type()->FindValueByNumber((int)node.value64)
Yi Jinf32af482017-08-11 15:00:49 -0700194 ->name().c_str());
Kweku Adamsee649592017-10-04 16:03:57 -0700195 }
Yi Jinf32af482017-08-11 15:00:49 -0700196 break;
Joe Onorato1754d742016-11-21 17:51:35 -0800197 default:
Yi Jin129fc6c2017-09-28 15:48:38 -0700198 out->printf("(unexpected type %d: value64 %lld (0x%x))",
199 type, node.value64, node.value64);
Joe Onorato1754d742016-11-21 17:51:35 -0800200 break;
201 }
202 break;
203 case GenericMessage::TYPE_MESSAGE:
204 print_message(out, field->message_type(), node.message);
205 break;
206 case GenericMessage::TYPE_STRING:
207 // TODO: custom format for multi-line strings.
208 out->printf("%s", node.str->c_str());
209 break;
210 case GenericMessage::TYPE_DATA:
211 out->printf("<bytes>");
212 break;
213 }
214}
215
216static void
217print_message(Out* out, Descriptor const* descriptor, GenericMessage const* message)
218{
219 out->printf("%s {\n", descriptor->name().c_str());
220 out->indent();
221
222 int const N = descriptor->field_count();
223 for (int i=0; i<N; i++) {
224 FieldDescriptor const* field = descriptor->field(i);
225
226 int fieldId = field->number();
227 bool repeated = field->label() == FieldDescriptor::LABEL_REPEATED;
228 FieldDescriptor::Type type = field->type();
229 GenericMessage::const_iterator_pair it = message->find(fieldId);
230
231 out->printf("%s=", field->name().c_str());
232 if (repeated) {
233 if (it.first != it.second) {
Kweku Adamsee649592017-10-04 16:03:57 -0700234 out->printf("[\n");
Joe Onorato1754d742016-11-21 17:51:35 -0800235 out->indent();
236
237 for (GenericMessage::const_iterator_pair it = message->find(fieldId);
238 it.first != it.second; it.first++) {
239 print_value(out, field, it.first->second);
Kweku Adamsee649592017-10-04 16:03:57 -0700240 out->printf("\n");
Joe Onorato1754d742016-11-21 17:51:35 -0800241 }
242
243 out->dedent();
244 out->printf("]");
245 } else {
246 out->printf("[]");
247 }
248 } else {
249 if (it.first != it.second) {
250 print_value(out, field, it.first->second);
251 } else {
252 switch (type) {
253 case FieldDescriptor::TYPE_BOOL:
254 out->printf("false");
255 break;
256 case FieldDescriptor::TYPE_STRING:
257 case FieldDescriptor::TYPE_MESSAGE:
258 out->printf("");
259 break;
260 case FieldDescriptor::TYPE_ENUM:
261 out->printf("%s", field->default_value_enum()->name().c_str());
262 break;
263 default:
264 out->printf("0");
265 break;
266 }
267 }
268 }
269 out->printf("\n");
270 }
271 out->dedent();
272 out->printf("}");
273}
274
275// ================================================================================
276static uint8_t*
277write_raw_varint(uint8_t* buf, uint32_t val)
278{
279 uint8_t* p = buf;
280 while (true) {
281 if ((val & ~0x7F) == 0) {
282 *p++ = (uint8_t)val;
283 return p;
284 } else {
285 *p++ = (uint8_t)((val & 0x7F) | 0x80);
286 val >>= 7;
287 }
288 }
289}
290
291static int
292write_all(int fd, uint8_t const* buf, size_t size)
293{
294 while (size > 0) {
295 ssize_t amt = ::write(fd, buf, size);
296 if (amt < 0) {
297 return errno;
298 }
299 size -= amt;
300 buf += amt;
301 }
302 return 0;
303}
304
305static int
306adb_incident_workaround(const char* adbSerial, const vector<string>& sections)
307{
308 const int maxAllowedSize = 20 * 1024 * 1024; // 20MB
Yunlian Jiang7a757a02017-07-25 16:03:05 -0700309 unique_ptr<uint8_t[]> buffer(new uint8_t[maxAllowedSize]);
Joe Onorato1754d742016-11-21 17:51:35 -0800310
311 for (vector<string>::const_iterator it=sections.begin(); it!=sections.end(); it++) {
312 Descriptor const* descriptor = IncidentProto::descriptor();
313 FieldDescriptor const* field;
314
315 // Get the name and field id.
316 string name = *it;
317 char* end;
318 int id = strtol(name.c_str(), &end, 0);
319 if (*end == '\0') {
320 // If it's an id, find out the string.
321 field = descriptor->FindFieldByNumber(id);
322 if (field == NULL) {
323 fprintf(stderr, "Unable to find field number: %d\n", id);
324 return 1;
325 }
326 name = field->name();
327 } else {
328 // If it's a string, find out the id.
329 field = descriptor->FindFieldByName(name);
330 if (field == NULL) {
331 fprintf(stderr, "Unable to find field: %s\n", name.c_str());
332 return 1;
333 }
334 id = field->number();
335 }
Kweku Adamsee649592017-10-04 16:03:57 -0700336
Joe Onorato1754d742016-11-21 17:51:35 -0800337 int pfd[2];
338 if (pipe(pfd) != 0) {
339 fprintf(stderr, "pipe failed: %s\n", strerror(errno));
340 return 1;
341 }
342
343 pid_t pid = fork();
344 if (pid == -1) {
345 fprintf(stderr, "fork failed: %s\n", strerror(errno));
346 return 1;
347 } else if (pid == 0) {
348 // child
349 dup2(pfd[1], STDOUT_FILENO);
350 close(pfd[0]);
351 close(pfd[1]);
352
353 char const** args = (char const**)malloc(sizeof(char*) * 8);
354 int argpos = 0;
355 args[argpos++] = "adb";
356 if (adbSerial != NULL) {
357 args[argpos++] = "-s";
358 args[argpos++] = adbSerial;
359 }
360 args[argpos++] = "shell";
361 args[argpos++] = "dumpsys";
362 args[argpos++] = name.c_str();
363 args[argpos++] = "--proto";
364 args[argpos++] = NULL;
365 execvp(args[0], (char*const*)args);
366 fprintf(stderr, "execvp failed: %s\n", strerror(errno));
Yunlian Jiang89547ce2017-01-31 16:17:50 -0800367 free(args);
Joe Onorato1754d742016-11-21 17:51:35 -0800368 return 1;
369 } else {
370 // parent
371 close(pfd[1]);
372
373 size_t size = 0;
374 while (size < maxAllowedSize) {
Yunlian Jiang7a757a02017-07-25 16:03:05 -0700375 ssize_t amt = read(pfd[0], buffer.get() + size, maxAllowedSize - size);
Joe Onorato1754d742016-11-21 17:51:35 -0800376 if (amt == 0) {
377 break;
378 } else if (amt == -1) {
379 fprintf(stderr, "read error: %s\n", strerror(errno));
380 return 1;
381 }
382 size += amt;
383 }
384
385 int status;
386 do {
387 waitpid(pid, &status, 0);
388 } while (!WIFEXITED(status));
389 if (WEXITSTATUS(status) != 0) {
390 return WEXITSTATUS(status);
391 }
392
393 if (size > 0) {
394 uint8_t header[20];
395 uint8_t* p = write_raw_varint(header, (id << 3) | 2);
396 p = write_raw_varint(p, size);
397 int err = write_all(STDOUT_FILENO, header, p-header);
398 if (err != 0) {
399 fprintf(stderr, "write error: %s\n", strerror(err));
400 return 1;
401 }
Yunlian Jiang7a757a02017-07-25 16:03:05 -0700402 err = write_all(STDOUT_FILENO, buffer.get(), size);
Joe Onorato1754d742016-11-21 17:51:35 -0800403 if (err != 0) {
404 fprintf(stderr, "write error: %s\n", strerror(err));
405 return 1;
406 }
407 }
408
409 close(pfd[0]);
410 }
411 }
412
Joe Onorato1754d742016-11-21 17:51:35 -0800413 return 0;
414}
415
416// ================================================================================
417static void
418usage(FILE* out)
419{
420 fprintf(out, "usage: incident_report -i INPUT [-o OUTPUT]\n");
421 fprintf(out, "\n");
422 fprintf(out, "Pretty-prints an incident report protobuf file.\n");
423 fprintf(out, " -i INPUT the input file. INPUT may be '-' to use stdin\n");
424 fprintf(out, " -o OUTPUT the output file. OUTPUT may be '-' or omitted to use stdout\n");
425 fprintf(out, "\n");
426 fprintf(out, "\n");
427 fprintf(out, "usage: incident_report [-o OUTPUT] [-t|b] [-s SERIAL] [SECTION...]\n");
428 fprintf(out, "\n");
429 fprintf(out, "Take an incident report over adb (which must be in the PATH).\n");
430 fprintf(out, " -b output the incident report raw protobuf format\n");
431 fprintf(out, " -o OUTPUT the output file. OUTPUT may be '-' or omitted to use stdout\n");
432 fprintf(out, " -s SERIAL sent to adb to choose which device, instead of $ANDROID_SERIAL\n");
433 fprintf(out, " -t output the incident report in pretty-printed text format\n");
434 fprintf(out, "\n");
435 fprintf(out, " SECTION which bugreport sections to print, either the int code of the\n");
436 fprintf(out, " section in the Incident proto or the field name. If ommited,\n");
437 fprintf(out, " the report will contain all fields\n");
438 fprintf(out, "\n");
439}
440
441int
442main(int argc, char** argv)
443{
444 enum { OUTPUT_TEXT, OUTPUT_PROTO } outputFormat = OUTPUT_TEXT;
445 const char* inFilename = NULL;
446 const char* outFilename = NULL;
447 const char* adbSerial = NULL;
448 bool adbIncidentWorkaround = true;
449 pid_t childPid = -1;
450 vector<string> sections;
451
452 int opt;
453 while ((opt = getopt(argc, argv, "bhi:o:s:tw")) != -1) {
454 switch (opt) {
455 case 'b':
456 outputFormat = OUTPUT_PROTO;
457 break;
458 case 'i':
459 inFilename = optarg;
460 break;
461 case 'o':
462 outFilename = optarg;
463 break;
464 case 's':
465 adbSerial = optarg;
466 break;
467 case 't':
468 outputFormat = OUTPUT_TEXT;
469 break;
470 case 'h':
471 usage(stdout);
472 return 0;
473 case 'w':
474 adbIncidentWorkaround = false;
475 break;
476 default:
477 usage(stderr);
478 return 1;
479 }
480 }
481
482 while (optind < argc) {
483 sections.push_back(argv[optind++]);
484 }
485
486 int inFd;
487 if (inFilename != NULL) {
488 // translate-only mode - oepn the file or use stdin.
489 if (strcmp("-", inFilename) == 0) {
490 inFd = STDIN_FILENO;
491 } else {
492 inFd = open(inFilename, O_RDONLY | O_CLOEXEC);
493 if (inFd < 0) {
494 fprintf(stderr, "unable to open file for read (%s): %s\n", strerror(errno),
495 inFilename);
496 return 1;
497 }
498 }
499 } else {
500 // pipe mode - run adb shell incident ...
501 int pfd[2];
502 if (pipe(pfd) != 0) {
503 fprintf(stderr, "pipe failed: %s\n", strerror(errno));
504 return 1;
505 }
506
507 childPid = fork();
508 if (childPid == -1) {
509 fprintf(stderr, "fork failed: %s\n", strerror(errno));
510 return 1;
511 } else if (childPid == 0) {
512 dup2(pfd[1], STDOUT_FILENO);
513 close(pfd[0]);
514 close(pfd[1]);
515 // child
516 if (adbIncidentWorkaround) {
517 // TODO: Until the device side incident command is checked in,
518 // the incident_report builds the outer Incident proto by hand
519 // from individual adb shell dumpsys <service> --proto calls,
520 // with a maximum allowed output size.
521 return adb_incident_workaround(adbSerial, sections);
522 }
523
524 // TODO: This is what the real implementation will be...
525 char const** args = (char const**)malloc(sizeof(char*) * (6 + sections.size()));
526 int argpos = 0;
527 args[argpos++] = "adb";
528 if (adbSerial != NULL) {
529 args[argpos++] = "-s";
530 args[argpos++] = adbSerial;
531 }
532 args[argpos++] = "shell";
533 args[argpos++] = "incident";
534 for (vector<string>::const_iterator it=sections.begin(); it!=sections.end(); it++) {
535 args[argpos++] = it->c_str();
536 }
537 args[argpos++] = NULL;
538 execvp(args[0], (char*const*)args);
539 fprintf(stderr, "execvp failed: %s\n", strerror(errno));
540 return 0;
541 } else {
542 // parent
543 inFd = pfd[0];
544 close(pfd[1]);
545 }
546 }
547
548 int outFd;
549 if (outFilename == NULL || strcmp("-", outFilename) == 0) {
550 outFd = STDOUT_FILENO;
551 } else {
552 outFd = open(outFilename, O_CREAT | O_RDWR, 0666);
553 if (outFd < 0) {
554 fprintf(stderr, "unable to open file for write: %s\n", outFilename);
555 return 1;
556 }
557 }
558
559 GenericMessage message;
560
561 Descriptor const* descriptor = IncidentProto::descriptor();
562 FileInputStream infile(inFd);
563 CodedInputStream in(&infile);
564
565 if (!read_message(&in, descriptor, &message)) {
566 fprintf(stderr, "unable to read incident\n");
567 return 1;
568 }
569
570 Out out(outFd);
571
572 print_message(&out, descriptor, &message);
573 out.printf("\n");
574
575 if (childPid != -1) {
576 int status;
577 do {
578 waitpid(childPid, &status, 0);
579 } while (!WIFEXITED(status));
580 if (WEXITSTATUS(status) != 0) {
581 return WEXITSTATUS(status);
582 }
583 }
584
585 return 0;
586}