• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
read_length_delimited(CodedInputStream * in,uint32 fieldId,Descriptor const * descriptor,GenericMessage * message)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
read_message(CodedInputStream * in,Descriptor const * descriptor,GenericMessage * message)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
print_value(Out * out,FieldDescriptor const * field,GenericMessage::Node const & node)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
print_message(Out * out,Descriptor const * descriptor,GenericMessage const * message)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*
write_raw_varint(uint8_t * buf,uint32_t val)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
write_all(int fd,uint8_t const * buf,size_t size)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
adb_incident_workaround(const char * adbSerial,const vector<string> & sections)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
usage(FILE * out)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
main(int argc,char ** argv)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