main.cpp revision b8344dc72fde9386cdecbb1aa8a47f1e8e430111
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_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// ================================================================================
86static bool
87read_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// ================================================================================
142static void
143print_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
220static void
221print_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// ================================================================================
280static uint8_t*
281write_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
295static int
296write_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
309static int
310adb_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// ================================================================================
421static void
422usage(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
445int
446main(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