Home | History | Annotate | Download | only in incident_report
      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