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 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 { 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// ================================================================================ 130static void 131print_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 198static void 199print_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// ================================================================================ 267static uint8_t* 268write_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 282static int 283write_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 296static int 297adb_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 return 1; 359 } else { 360 // parent 361 close(pfd[1]); 362 363 size_t size = 0; 364 while (size < maxAllowedSize) { 365 ssize_t amt = read(pfd[0], buffer + size, maxAllowedSize - size); 366 if (amt == 0) { 367 break; 368 } else if (amt == -1) { 369 fprintf(stderr, "read error: %s\n", strerror(errno)); 370 return 1; 371 } 372 size += amt; 373 } 374 375 int status; 376 do { 377 waitpid(pid, &status, 0); 378 } while (!WIFEXITED(status)); 379 if (WEXITSTATUS(status) != 0) { 380 return WEXITSTATUS(status); 381 } 382 383 if (size > 0) { 384 uint8_t header[20]; 385 uint8_t* p = write_raw_varint(header, (id << 3) | 2); 386 p = write_raw_varint(p, size); 387 int err = write_all(STDOUT_FILENO, header, p-header); 388 if (err != 0) { 389 fprintf(stderr, "write error: %s\n", strerror(err)); 390 return 1; 391 } 392 err = write_all(STDOUT_FILENO, buffer, size); 393 if (err != 0) { 394 fprintf(stderr, "write error: %s\n", strerror(err)); 395 return 1; 396 } 397 } 398 399 close(pfd[0]); 400 } 401 } 402 403 return 0; 404} 405 406// ================================================================================ 407static void 408usage(FILE* out) 409{ 410 fprintf(out, "usage: incident_report -i INPUT [-o OUTPUT]\n"); 411 fprintf(out, "\n"); 412 fprintf(out, "Pretty-prints an incident report protobuf file.\n"); 413 fprintf(out, " -i INPUT the input file. INPUT may be '-' to use stdin\n"); 414 fprintf(out, " -o OUTPUT the output file. OUTPUT may be '-' or omitted to use stdout\n"); 415 fprintf(out, "\n"); 416 fprintf(out, "\n"); 417 fprintf(out, "usage: incident_report [-o OUTPUT] [-t|b] [-s SERIAL] [SECTION...]\n"); 418 fprintf(out, "\n"); 419 fprintf(out, "Take an incident report over adb (which must be in the PATH).\n"); 420 fprintf(out, " -b output the incident report raw protobuf format\n"); 421 fprintf(out, " -o OUTPUT the output file. OUTPUT may be '-' or omitted to use stdout\n"); 422 fprintf(out, " -s SERIAL sent to adb to choose which device, instead of $ANDROID_SERIAL\n"); 423 fprintf(out, " -t output the incident report in pretty-printed text format\n"); 424 fprintf(out, "\n"); 425 fprintf(out, " SECTION which bugreport sections to print, either the int code of the\n"); 426 fprintf(out, " section in the Incident proto or the field name. If ommited,\n"); 427 fprintf(out, " the report will contain all fields\n"); 428 fprintf(out, "\n"); 429} 430 431int 432main(int argc, char** argv) 433{ 434 enum { OUTPUT_TEXT, OUTPUT_PROTO } outputFormat = OUTPUT_TEXT; 435 const char* inFilename = NULL; 436 const char* outFilename = NULL; 437 const char* adbSerial = NULL; 438 bool adbIncidentWorkaround = true; 439 pid_t childPid = -1; 440 vector<string> sections; 441 442 int opt; 443 while ((opt = getopt(argc, argv, "bhi:o:s:tw")) != -1) { 444 switch (opt) { 445 case 'b': 446 outputFormat = OUTPUT_PROTO; 447 break; 448 case 'i': 449 inFilename = optarg; 450 break; 451 case 'o': 452 outFilename = optarg; 453 break; 454 case 's': 455 adbSerial = optarg; 456 break; 457 case 't': 458 outputFormat = OUTPUT_TEXT; 459 break; 460 case 'h': 461 usage(stdout); 462 return 0; 463 case 'w': 464 adbIncidentWorkaround = false; 465 break; 466 default: 467 usage(stderr); 468 return 1; 469 } 470 } 471 472 while (optind < argc) { 473 sections.push_back(argv[optind++]); 474 } 475 476 int inFd; 477 if (inFilename != NULL) { 478 // translate-only mode - oepn the file or use stdin. 479 if (strcmp("-", inFilename) == 0) { 480 inFd = STDIN_FILENO; 481 } else { 482 inFd = open(inFilename, O_RDONLY | O_CLOEXEC); 483 if (inFd < 0) { 484 fprintf(stderr, "unable to open file for read (%s): %s\n", strerror(errno), 485 inFilename); 486 return 1; 487 } 488 } 489 } else { 490 // pipe mode - run adb shell incident ... 491 int pfd[2]; 492 if (pipe(pfd) != 0) { 493 fprintf(stderr, "pipe failed: %s\n", strerror(errno)); 494 return 1; 495 } 496 497 childPid = fork(); 498 if (childPid == -1) { 499 fprintf(stderr, "fork failed: %s\n", strerror(errno)); 500 return 1; 501 } else if (childPid == 0) { 502 dup2(pfd[1], STDOUT_FILENO); 503 close(pfd[0]); 504 close(pfd[1]); 505 // child 506 if (adbIncidentWorkaround) { 507 // TODO: Until the device side incident command is checked in, 508 // the incident_report builds the outer Incident proto by hand 509 // from individual adb shell dumpsys <service> --proto calls, 510 // with a maximum allowed output size. 511 return adb_incident_workaround(adbSerial, sections); 512 } 513 514 // TODO: This is what the real implementation will be... 515 char const** args = (char const**)malloc(sizeof(char*) * (6 + sections.size())); 516 int argpos = 0; 517 args[argpos++] = "adb"; 518 if (adbSerial != NULL) { 519 args[argpos++] = "-s"; 520 args[argpos++] = adbSerial; 521 } 522 args[argpos++] = "shell"; 523 args[argpos++] = "incident"; 524 for (vector<string>::const_iterator it=sections.begin(); it!=sections.end(); it++) { 525 args[argpos++] = it->c_str(); 526 } 527 args[argpos++] = NULL; 528 execvp(args[0], (char*const*)args); 529 fprintf(stderr, "execvp failed: %s\n", strerror(errno)); 530 return 0; 531 } else { 532 // parent 533 inFd = pfd[0]; 534 close(pfd[1]); 535 } 536 } 537 538 int outFd; 539 if (outFilename == NULL || strcmp("-", outFilename) == 0) { 540 outFd = STDOUT_FILENO; 541 } else { 542 outFd = open(outFilename, O_CREAT | O_RDWR, 0666); 543 if (outFd < 0) { 544 fprintf(stderr, "unable to open file for write: %s\n", outFilename); 545 return 1; 546 } 547 } 548 549 GenericMessage message; 550 551 Descriptor const* descriptor = IncidentProto::descriptor(); 552 FileInputStream infile(inFd); 553 CodedInputStream in(&infile); 554 555 if (!read_message(&in, descriptor, &message)) { 556 fprintf(stderr, "unable to read incident\n"); 557 return 1; 558 } 559 560 Out out(outFd); 561 562 print_message(&out, descriptor, &message); 563 out.printf("\n"); 564 565 if (childPid != -1) { 566 int status; 567 do { 568 waitpid(childPid, &status, 0); 569 } while (!WIFEXITED(status)); 570 if (WEXITSTATUS(status) != 0) { 571 return WEXITSTATUS(status); 572 } 573 } 574 575 return 0; 576} 577