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