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