• 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 void
usage(FILE * out)281 usage(FILE* out)
282 {
283     fprintf(out, "usage: incident_report -i INPUT [-o OUTPUT]\n");
284     fprintf(out, "\n");
285     fprintf(out, "Pretty-prints an incident report protobuf file.\n");
286     fprintf(out, "  -i INPUT    the input file. INPUT may be '-' to use stdin\n");
287     fprintf(out, "  -o OUTPUT   the output file. OUTPUT may be '-' or omitted to use stdout\n");
288     fprintf(out, "\n");
289     fprintf(out, "\n");
290     fprintf(out, "usage: incident_report [-o OUTPUT] [-t|b] [-s SERIAL] [SECTION...]\n");
291     fprintf(out, "\n");
292     fprintf(out, "Take an incident report over adb (which must be in the PATH).\n");
293     fprintf(out, "  -b          output the incident report raw protobuf format\n");
294     fprintf(out, "  -o OUTPUT   the output file. OUTPUT may be '-' or omitted to use stdout\n");
295     fprintf(out, "  -r REASON   human readable description of why the report is taken.\n");
296     fprintf(out, "  -s SERIAL   sent to adb to choose which device, instead of $ANDROID_SERIAL\n");
297     fprintf(out, "  -t          output the incident report in pretty-printed text format\n");
298     fprintf(out, "\n");
299     fprintf(out, "  SECTION     which bugreport sections to print, either the int code of the\n");
300     fprintf(out, "              section in the Incident proto or the field name.  If ommited,\n");
301     fprintf(out, "              the report will contain all fields\n");
302     fprintf(out, "\n");
303 }
304 
305 int
main(int argc,char ** argv)306 main(int argc, char** argv)
307 {
308     enum { OUTPUT_TEXT, OUTPUT_PROTO } outputFormat = OUTPUT_TEXT;
309     const char* inFilename = NULL;
310     const char* outFilename = NULL;
311     const char* reason = NULL;
312     const char* adbSerial = NULL;
313     pid_t childPid = -1;
314     vector<string> sections;
315     const char* privacy = NULL;
316 
317     int opt;
318     while ((opt = getopt(argc, argv, "bhi:o:r:s:twp:")) != -1) {
319         switch (opt) {
320             case 'b':
321                 outputFormat = OUTPUT_PROTO;
322                 break;
323             case 'i':
324                 inFilename = optarg;
325                 break;
326             case 'o':
327                 outFilename = optarg;
328                 break;
329             case 'r':
330                 reason = optarg;
331                 break;
332             case 's':
333                 adbSerial = optarg;
334                 break;
335             case 't':
336                 outputFormat = OUTPUT_TEXT;
337                 break;
338             case 'h':
339                 usage(stdout);
340                 return 0;
341             case 'p':
342                 privacy = optarg;
343                 break;
344             default:
345                 usage(stderr);
346                 return 1;
347         }
348     }
349 
350     while (optind < argc) {
351         sections.push_back(argv[optind++]);
352     }
353 
354     int inFd;
355     if (inFilename != NULL) {
356         // translate-only mode - oepn the file or use stdin.
357         if (strcmp("-", inFilename) == 0) {
358             inFd = STDIN_FILENO;
359         } else {
360             inFd = open(inFilename, O_RDONLY | O_CLOEXEC);
361             if (inFd < 0) {
362                 fprintf(stderr, "unable to open file for read (%s): %s\n", strerror(errno),
363                         inFilename);
364                 return 1;
365             }
366         }
367     } else {
368         // pipe mode - run adb shell incident ...
369         int pfd[2];
370         if (pipe(pfd) != 0) {
371             fprintf(stderr, "pipe failed: %s\n", strerror(errno));
372             return 1;
373         }
374 
375         childPid = fork();
376         if (childPid == -1) {
377             fprintf(stderr, "fork failed: %s\n", strerror(errno));
378             return 1;
379         } else if (childPid == 0) {
380             // child
381             dup2(pfd[1], STDOUT_FILENO);
382             close(pfd[0]);
383             close(pfd[1]);
384             char const** args = (char const**)malloc(sizeof(char*) * (10 + sections.size()));
385             int argpos = 0;
386             args[argpos++] = "adb";
387             if (adbSerial != NULL) {
388                 args[argpos++] = "-s";
389                 args[argpos++] = adbSerial;
390             }
391             args[argpos++] = "shell";
392             args[argpos++] = "incident";
393             if (privacy != NULL) {
394                 args[argpos++] = "-p";
395                 args[argpos++] = privacy;
396             }
397             if (reason != NULL) {
398                 args[argpos++] = "-r";
399                 args[argpos++] = reason;
400             }
401             for (vector<string>::const_iterator it=sections.begin(); it!=sections.end(); it++) {
402                 args[argpos++] = it->c_str();
403             }
404             args[argpos++] = NULL;
405             execvp(args[0], (char*const*)args);
406             fprintf(stderr, "execvp failed: %s\n", strerror(errno));
407             free(args);
408             return 0;
409         } else {
410             // parent
411             inFd = pfd[0];
412             close(pfd[1]);
413         }
414     }
415 
416     int outFd;
417     if (outFilename == NULL || strcmp("-", outFilename) == 0) {
418         outFd = STDOUT_FILENO;
419     } else {
420         outFd = open(outFilename, O_CREAT | O_RDWR, 0666);
421         if (outFd < 0) {
422             fprintf(stderr, "unable to open file for write: %s\n", outFilename);
423             return 1;
424         }
425     }
426 
427     GenericMessage message;
428 
429     Descriptor const* descriptor = IncidentProto::descriptor();
430     FileInputStream infile(inFd);
431     CodedInputStream in(&infile);
432 
433     if (!read_message(&in, descriptor, &message)) {
434         fprintf(stderr, "unable to read incident\n");
435         return 1;
436     }
437 
438     Out out(outFd);
439 
440     print_message(&out, descriptor, &message);
441     out.printf("\n");
442 
443     if (childPid != -1) {
444         int status;
445         do {
446             waitpid(childPid, &status, 0);
447         } while (!WIFEXITED(status));
448         if (WEXITSTATUS(status) != 0) {
449             return WEXITSTATUS(status);
450         }
451     }
452 
453     return 0;
454 }
455