• 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 size;
49     if (!in->ReadVarint32(&size)) {
50         return false;
51     }
52 
53     FieldDescriptor const* field = descriptor->FindFieldByNumber(fieldId);
54     if (field != NULL) {
55         int type = field->type();
56         if (type == FieldDescriptor::TYPE_MESSAGE) {
57             GenericMessage* child = message->addMessage(fieldId);
58 
59             CodedInputStream::Limit limit = in->PushLimit(size);
60             bool rv = read_message(in, field->message_type(), child);
61             in->PopLimit(limit);
62             return rv;
63         } else if (type == FieldDescriptor::TYPE_STRING) {
64             // TODO: do a version of readstring that just pumps the data
65             // rather than allocating a string which we don't care about.
66             string str;
67             if (in->ReadString(&str, size)) {
68                 message->addString(fieldId, str);
69                 return true;
70             } else {
71                 return false;
72             }
73         } else if (type == FieldDescriptor::TYPE_BYTES) {
74             // TODO: Save bytes field.
75             return in->Skip(size);
76         }
77     }
78     return in->Skip(size);
79 }
80 
81 // ================================================================================
82 static bool
read_message(CodedInputStream * in,Descriptor const * descriptor,GenericMessage * message)83 read_message(CodedInputStream* in, Descriptor const* descriptor, GenericMessage* message)
84 {
85     uint32 value32;
86     uint64 value64;
87 
88     while (true) {
89         uint32 tag = in->ReadTag();
90         if (tag == 0) {
91             return true;
92         }
93         int fieldId = WireFormatLite::GetTagFieldNumber(tag);
94         switch (WireFormatLite::GetTagWireType(tag)) {
95             case WireFormatLite::WIRETYPE_VARINT:
96                 if (in->ReadVarint64(&value64)) {
97                     message->addInt64(fieldId, value64);
98                     break;
99                 } else {
100                     return false;
101                 }
102             case WireFormatLite::WIRETYPE_FIXED64:
103                 if (in->ReadLittleEndian64(&value64)) {
104                     message->addInt64(fieldId, value64);
105                     break;
106                 } else {
107                     return false;
108                 }
109             case WireFormatLite::WIRETYPE_LENGTH_DELIMITED:
110                 if (!read_length_delimited(in, fieldId, descriptor, message)) {
111                     return false;
112                 }
113                 break;
114             case WireFormatLite::WIRETYPE_FIXED32:
115                 if (in->ReadLittleEndian32(&value32)) {
116                     message->addInt32(fieldId, value32);
117                     break;
118                 } else {
119                     return false;
120                 }
121             default:
122                 fprintf(stderr, "bad tag: 0x%x (%d) at index %d\n", tag, tag,
123                         in->CurrentPosition());
124                 return false;
125         }
126     }
127 }
128 
129 // ================================================================================
130 static void
print_value(Out * out,FieldDescriptor const * field,GenericMessage::Node const & node)131 print_value(Out* out, FieldDescriptor const* field, GenericMessage::Node const& node)
132 {
133     uint32_t val32;
134     FieldDescriptor::Type type = field->type();
135 
136     switch (node.type) {
137         case GenericMessage::TYPE_VALUE32:
138             switch (type) {
139                 case FieldDescriptor::TYPE_FIXED32:
140                     out->printf("%u", node.value32);
141                     break;
142                 case FieldDescriptor::TYPE_SFIXED32:
143                     out->printf("%d", node.value32);
144                     break;
145                 case FieldDescriptor::TYPE_FLOAT:
146                     out->printf("%f", *(float*)&node.value32);
147                     break;
148                 default:
149                     out->printf("(unexpected value %d (0x%x)", node.value32, node.value32);
150                     break;
151             }
152             break;
153         case GenericMessage::TYPE_VALUE64:
154             switch (type) {
155                 case FieldDescriptor::TYPE_FIXED64:
156                 case FieldDescriptor::TYPE_SFIXED64:
157                 case FieldDescriptor::TYPE_DOUBLE:
158                     out->printf("%f", *(double*)&node.value64);
159                     break;
160                 case FieldDescriptor::TYPE_SINT32:
161                 case FieldDescriptor::TYPE_INT32:
162                     val32 = (uint32_t)node.value32;
163                     out->printf("%d", val32);
164                     break;
165                 case FieldDescriptor::TYPE_INT64:
166                 case FieldDescriptor::TYPE_UINT32:
167                     val32 = (uint32_t)node.value32;
168                     out->printf("%u", val32);
169                     break;
170                 case FieldDescriptor::TYPE_UINT64:
171                 case FieldDescriptor::TYPE_SINT64:
172                 case FieldDescriptor::TYPE_BOOL:
173                     if (node.value64) {
174                         out->printf("true");
175                     } else {
176                         out->printf("false");
177                     }
178                     break;
179                 case FieldDescriptor::TYPE_ENUM:
180                 default:
181                     out->printf("(unexpected value %ld (0x%x))", node.value64, node.value64);
182                     break;
183             }
184             break;
185         case GenericMessage::TYPE_MESSAGE:
186             print_message(out, field->message_type(), node.message);
187             break;
188         case GenericMessage::TYPE_STRING:
189             // TODO: custom format for multi-line strings.
190             out->printf("%s", node.str->c_str());
191             break;
192         case GenericMessage::TYPE_DATA:
193             out->printf("<bytes>");
194             break;
195     }
196 }
197 
198 static void
print_message(Out * out,Descriptor const * descriptor,GenericMessage const * message)199 print_message(Out* out, Descriptor const* descriptor, GenericMessage const* message)
200 {
201     out->printf("%s {\n", descriptor->name().c_str());
202     out->indent();
203 
204     int const N = descriptor->field_count();
205     for (int i=0; i<N; i++) {
206         FieldDescriptor const* field = descriptor->field(i);
207 
208         int fieldId = field->number();
209         bool repeated = field->label() == FieldDescriptor::LABEL_REPEATED;
210         FieldDescriptor::Type type = field->type();
211         GenericMessage::const_iterator_pair it = message->find(fieldId);
212 
213         out->printf("%s=", field->name().c_str());
214         if (repeated) {
215             if (it.first != it.second) {
216                 out->printf("[");
217                 if (type == FieldDescriptor::TYPE_MESSAGE
218                         || type == FieldDescriptor::TYPE_STRING
219                         || type == FieldDescriptor::TYPE_BYTES) {
220                     out->printf("\n");
221                 }
222                 out->indent();
223 
224                 for (GenericMessage::const_iterator_pair it = message->find(fieldId);
225                         it.first != it.second; it.first++) {
226                     print_value(out, field, it.first->second);
227                     if (type == FieldDescriptor::TYPE_MESSAGE
228                             || type == FieldDescriptor::TYPE_STRING
229                             || type == FieldDescriptor::TYPE_BYTES) {
230                         out->printf("\n");
231                     }
232                 }
233 
234                 out->dedent();
235                 out->printf("]");
236             } else {
237                 out->printf("[]");
238             }
239         } else {
240             if (it.first != it.second) {
241                 print_value(out, field, it.first->second);
242             } else {
243                 switch (type) {
244                     case FieldDescriptor::TYPE_BOOL:
245                         out->printf("false");
246                         break;
247                     case FieldDescriptor::TYPE_STRING:
248                     case FieldDescriptor::TYPE_MESSAGE:
249                         out->printf("");
250                         break;
251                     case FieldDescriptor::TYPE_ENUM:
252                         out->printf("%s", field->default_value_enum()->name().c_str());
253                         break;
254                     default:
255                         out->printf("0");
256                         break;
257                 }
258             }
259         }
260         out->printf("\n");
261     }
262     out->dedent();
263     out->printf("}");
264 }
265 
266 // ================================================================================
267 static uint8_t*
write_raw_varint(uint8_t * buf,uint32_t val)268 write_raw_varint(uint8_t* buf, uint32_t val)
269 {
270     uint8_t* p = buf;
271     while (true) {
272         if ((val & ~0x7F) == 0) {
273             *p++ = (uint8_t)val;
274             return p;
275         } else {
276             *p++ = (uint8_t)((val & 0x7F) | 0x80);
277             val >>= 7;
278         }
279     }
280 }
281 
282 static int
write_all(int fd,uint8_t const * buf,size_t size)283 write_all(int fd, uint8_t const* buf, size_t size)
284 {
285     while (size > 0) {
286         ssize_t amt = ::write(fd, buf, size);
287         if (amt < 0) {
288             return errno;
289         }
290         size -= amt;
291         buf += amt;
292     }
293     return 0;
294 }
295 
296 static int
adb_incident_workaround(const char * adbSerial,const vector<string> & sections)297 adb_incident_workaround(const char* adbSerial, const vector<string>& sections)
298 {
299     const int maxAllowedSize = 20 * 1024 * 1024; // 20MB
300     uint8_t* buffer = (uint8_t*)malloc(maxAllowedSize);
301 
302     for (vector<string>::const_iterator it=sections.begin(); it!=sections.end(); it++) {
303         Descriptor const* descriptor = IncidentProto::descriptor();
304         FieldDescriptor const* field;
305 
306         // Get the name and field id.
307         string name = *it;
308         char* end;
309         int id = strtol(name.c_str(), &end, 0);
310         if (*end == '\0') {
311             // If it's an id, find out the string.
312             field = descriptor->FindFieldByNumber(id);
313             if (field == NULL) {
314                 fprintf(stderr, "Unable to find field number: %d\n", id);
315                 return 1;
316             }
317             name = field->name();
318         } else {
319             // If it's a string, find out the id.
320             field = descriptor->FindFieldByName(name);
321             if (field == NULL) {
322                 fprintf(stderr, "Unable to find field: %s\n", name.c_str());
323                 return 1;
324             }
325             id = field->number();
326         }
327 
328         int pfd[2];
329         if (pipe(pfd) != 0) {
330             fprintf(stderr, "pipe failed: %s\n", strerror(errno));
331             return 1;
332         }
333 
334         pid_t pid = fork();
335         if (pid == -1) {
336             fprintf(stderr, "fork failed: %s\n", strerror(errno));
337             return 1;
338         } else if (pid == 0) {
339             // child
340             dup2(pfd[1], STDOUT_FILENO);
341             close(pfd[0]);
342             close(pfd[1]);
343 
344             char const** args = (char const**)malloc(sizeof(char*) * 8);
345             int argpos = 0;
346             args[argpos++] = "adb";
347             if (adbSerial != NULL) {
348                 args[argpos++] = "-s";
349                 args[argpos++] = adbSerial;
350             }
351             args[argpos++] = "shell";
352             args[argpos++] = "dumpsys";
353             args[argpos++] = name.c_str();
354             args[argpos++] = "--proto";
355             args[argpos++] = NULL;
356             execvp(args[0], (char*const*)args);
357             fprintf(stderr, "execvp failed: %s\n", strerror(errno));
358             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 // ================================================================================
407 static void
usage(FILE * out)408 usage(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 
431 int
main(int argc,char ** argv)432 main(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