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 #include "generic_message.h" 18 #include "printer.h" 19 20 #include <frameworks/base/core/proto/android/os/incident.pb.h> 21 #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 34 using namespace android::os; 35 using namespace google::protobuf; 36 using namespace google::protobuf::io; 37 using namespace google::protobuf::internal; 38 39 static bool read_message(CodedInputStream* in, Descriptor const* descriptor, 40 GenericMessage* message); 41 static void print_message(Out* out, Descriptor const* descriptor, GenericMessage const* message); 42 43 // ================================================================================ 44 static bool 45 read_length_delimited(CodedInputStream* in, uint32 fieldId, Descriptor const* descriptor, 46 GenericMessage* message) 47 { 48 uint32_t size; 49 if (!in->ReadVarint32(&size)) { 50 fprintf(stderr, "Fail to read size of %s\n", descriptor->name().c_str()); 51 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 { 72 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()); 75 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 // ================================================================================ 86 static bool 87 read_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 { 104 fprintf(stderr, "bad VARINT: 0x%x (%d) at index %d of field %s\n", 105 tag, tag, in->CurrentPosition(), descriptor->name().c_str()); 106 return false; 107 } 108 case WireFormatLite::WIRETYPE_FIXED64: 109 if (in->ReadLittleEndian64(&value64)) { 110 message->addInt64(fieldId, value64); 111 break; 112 } else { 113 fprintf(stderr, "bad VARINT: 0x%x (%d) at index %d of field %s\n", 114 tag, tag, in->CurrentPosition(), descriptor->name().c_str()); 115 return false; 116 } 117 case WireFormatLite::WIRETYPE_LENGTH_DELIMITED: 118 if (!read_length_delimited(in, fieldId, descriptor, message)) { 119 fprintf(stderr, "bad LENGTH_DELIMITED: 0x%x (%d) at index %d of field %s\n", 120 tag, tag, in->CurrentPosition(), descriptor->name().c_str()); 121 return false; 122 } 123 break; 124 case WireFormatLite::WIRETYPE_FIXED32: 125 if (in->ReadLittleEndian32(&value32)) { 126 message->addInt32(fieldId, value32); 127 break; 128 } else { 129 fprintf(stderr, "bad FIXED32: 0x%x (%d) at index %d of field %s\n", 130 tag, tag, in->CurrentPosition(), descriptor->name().c_str()); 131 return false; 132 } 133 default: 134 fprintf(stderr, "bad tag: 0x%x (%d) at index %d of field %s\n", tag, tag, 135 in->CurrentPosition(), descriptor->name().c_str()); 136 return false; 137 } 138 } 139 } 140 141 // ================================================================================ 142 static void 143 print_value(Out* out, FieldDescriptor const* field, GenericMessage::Node const& node) 144 { 145 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: 160 out->printf("(unexpected type %d: value32 %d (0x%x)", 161 type, node.value32, node.value32); 162 break; 163 } 164 break; 165 case GenericMessage::TYPE_VALUE64: 166 switch (type) { 167 case FieldDescriptor::TYPE_DOUBLE: 168 out->printf("%f", *(double*)&node.value64); 169 break; 170 // Int32s here were added with addInt64 from a WIRETYPE_VARINT, 171 // even if the definition is for a 32 bit int. 172 case FieldDescriptor::TYPE_SINT32: 173 case FieldDescriptor::TYPE_INT32: 174 out->printf("%d", node.value64); 175 break; 176 case FieldDescriptor::TYPE_INT64: 177 case FieldDescriptor::TYPE_SINT64: 178 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; 186 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: 194 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) 198 ->name().c_str()); 199 } 200 break; 201 default: 202 out->printf("(unexpected type %d: value64 %lld (0x%x))", 203 type, node.value64, node.value64); 204 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 220 static void 221 print_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) { 238 out->printf("[\n"); 239 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); 244 out->printf("\n"); 245 } 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 // ================================================================================ 280 static uint8_t* 281 write_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 295 static int 296 write_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 309 static int 310 adb_incident_workaround(const char* adbSerial, const vector<string>& sections) 311 { 312 const int maxAllowedSize = 20 * 1024 * 1024; // 20MB 313 unique_ptr<uint8_t[]> buffer(new uint8_t[maxAllowedSize]); 314 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 } 340 341 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)); 371 free(args); 372 return 1; 373 } else { 374 // parent 375 close(pfd[1]); 376 377 size_t size = 0; 378 while (size < maxAllowedSize) { 379 ssize_t amt = read(pfd[0], buffer.get() + size, maxAllowedSize - size); 380 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 } 406 err = write_all(STDOUT_FILENO, buffer.get(), size); 407 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 417 return 0; 418 } 419 420 // ================================================================================ 421 static void 422 usage(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 445 int 446 main(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; 455 const char* privacy = NULL; 456 457 int opt; 458 while ((opt = getopt(argc, argv, "bhi:o:s:twp:")) != -1) { 459 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; 481 case 'p': 482 privacy = optarg; 483 break; 484 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... 533 char const** args = (char const**)malloc(sizeof(char*) * (8 + sections.size())); 534 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"; 542 if (privacy != NULL) { 543 args[argpos++] = "-p"; 544 args[argpos++] = privacy; 545 } 546 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 } 599