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_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