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 "adb.h"
18 
19 #include "command.h"
20 #include "print.h"
21 #include "util.h"
22 
23 #include <errno.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <sys/types.h>
28 #include <sys/wait.h>
29 #include <limits.h>
30 
31 #include <iostream>
32 #include <istream>
33 #include <streambuf>
34 
35 using namespace std;
36 
37 struct Buffer: public streambuf
38 {
39     Buffer(char* begin, size_t size);
40 };
41 
Buffer(char * begin,size_t size)42 Buffer::Buffer(char* begin, size_t size)
43 {
44     this->setg(begin, begin, begin + size);
45 }
46 
47 int
run_adb(const char * first,...)48 run_adb(const char* first, ...)
49 {
50     Command cmd("adb");
51 
52     if (first == NULL) {
53         return 0;
54     }
55 
56     cmd.AddArg(first);
57 
58     va_list args;
59     va_start(args, first);
60     while (true) {
61         const char* arg = va_arg(args, char*);
62         if (arg == NULL) {
63             break;
64         }
65         cmd.AddArg(arg);
66     }
67     va_end(args);
68 
69     return run_command(cmd);
70 }
71 
72 string
get_system_property(const string & name,int * err)73 get_system_property(const string& name, int* err)
74 {
75     Command cmd("adb");
76     cmd.AddArg("shell");
77     cmd.AddArg("getprop");
78     cmd.AddArg(name);
79 
80     return trim(get_command_output(cmd, err, false));
81 }
82 
83 
84 static uint64_t
read_varint(int fd,int * err,bool * done)85 read_varint(int fd, int* err, bool* done)
86 {
87     uint32_t bits = 0;
88     uint64_t result = 0;
89     while (true) {
90         uint8_t byte;
91         ssize_t amt = read(fd, &byte, 1);
92         if (amt == 0) {
93             *done = true;
94             return result;
95         } else if (amt < 0) {
96             return *err = errno;
97         }
98         result |= uint64_t(byte & 0x7F) << bits;
99         if ((byte & 0x80) == 0) {
100             return result;
101         }
102         bits += 7;
103         if (bits > 64) {
104             *err = -1;
105             return 0;
106         }
107     }
108 }
109 
110 static char*
read_sized_buffer(int fd,int * err,size_t * resultSize)111 read_sized_buffer(int fd, int* err, size_t* resultSize)
112 {
113     bool done = false;
114     uint64_t size = read_varint(fd, err, &done);
115     if (*err != 0 || done) {
116         return NULL;
117     }
118     if (size == 0) {
119         *resultSize = 0;
120         return NULL;
121     }
122     // 10 MB seems like a reasonable limit.
123     if (size > 10*1024*1024) {
124         print_error("result buffer too large: %llu", size);
125         return NULL;
126     }
127     char* buf = (char*)malloc(size);
128     if (buf == NULL) {
129         print_error("Can't allocate a buffer of size for test results: %llu", size);
130         return NULL;
131     }
132     int pos = 0;
133     while (size - pos > 0) {
134         ssize_t amt = read(fd, buf+pos, size-pos);
135         if (amt == 0) {
136             // early end of pipe
137             print_error("Early end of pipe.");
138             *err = -1;
139             free(buf);
140             return NULL;
141         } else if (amt < 0) {
142             // error
143             *err = errno;
144             free(buf);
145             return NULL;
146         }
147         pos += amt;
148     }
149     *resultSize = (size_t)size;
150     return buf;
151 }
152 
153 static int
read_sized_proto(int fd,Message * message)154 read_sized_proto(int fd, Message* message)
155 {
156     int err = 0;
157     size_t size;
158     char* buf = read_sized_buffer(fd, &err, &size);
159     if (err != 0) {
160         if (buf != NULL) {
161             free(buf);
162         }
163         return err;
164     } else if (size == 0) {
165         if (buf != NULL) {
166             free(buf);
167         }
168         return 0;
169     } else if (buf == NULL) {
170         return -1;
171     }
172     Buffer buffer(buf, size);
173     istream in(&buffer);
174 
175     err = message->ParseFromIstream(&in) ? 0 : -1;
176 
177     free(buf);
178     return err;
179 }
180 
181 static int
skip_bytes(int fd,ssize_t size,char * scratch,int scratchSize)182 skip_bytes(int fd, ssize_t size, char* scratch, int scratchSize)
183 {
184     while (size > 0) {
185         ssize_t amt = size < scratchSize ? size : scratchSize;
186         fprintf(stderr, "skipping %lu/%ld bytes\n", size, amt);
187         amt = read(fd, scratch, amt);
188         if (amt == 0) {
189             // early end of pipe
190             print_error("Early end of pipe.");
191             return -1;
192         } else if (amt < 0) {
193             // error
194             return errno;
195         }
196         size -= amt;
197     }
198     return 0;
199 }
200 
201 static int
skip_unknown_field(int fd,uint64_t tag,char * scratch,int scratchSize)202 skip_unknown_field(int fd, uint64_t tag, char* scratch, int scratchSize) {
203     bool done;
204     int err;
205     uint64_t size;
206     switch (tag & 0x7) {
207         case 0: // varint
208             read_varint(fd, &err, &done);
209             if (err != 0) {
210                 return err;
211             } else if (done) {
212                 return -1;
213             } else {
214                 return 0;
215             }
216         case 1:
217             return skip_bytes(fd, 8, scratch, scratchSize);
218         case 2:
219             size = read_varint(fd, &err, &done);
220             if (err != 0) {
221                 return err;
222             } else if (done) {
223                 return -1;
224             }
225             if (size > INT_MAX) {
226                 // we'll be here a long time but this keeps it from overflowing
227                 return -1;
228             }
229             return skip_bytes(fd, (ssize_t)size, scratch, scratchSize);
230         case 5:
231             return skip_bytes(fd, 4, scratch, scratchSize);
232         default:
233             print_error("bad wire type for tag 0x%lx\n", tag);
234             return -1;
235     }
236 }
237 
238 static int
read_instrumentation_results(int fd,char * scratch,int scratchSize,InstrumentationCallbacks * callbacks)239 read_instrumentation_results(int fd, char* scratch, int scratchSize,
240         InstrumentationCallbacks* callbacks)
241 {
242     bool done = false;
243     int err = 0;
244     string result;
245     while (true) {
246         uint64_t tag = read_varint(fd, &err, &done);
247         if (done) {
248             // Done reading input (this is the only place that a stream end isn't an error).
249             return 0;
250         } else if (err != 0) {
251             return err;
252         } else if (tag == 0xa) { // test_status
253             TestStatus status;
254             err = read_sized_proto(fd, &status);
255             if (err != 0) {
256                 return err;
257             }
258             callbacks->OnTestStatus(status);
259         } else if (tag == 0x12) { // session_status
260             SessionStatus status;
261             err = read_sized_proto(fd, &status);
262             if (err != 0) {
263                 return err;
264             }
265             callbacks->OnSessionStatus(status);
266         } else {
267             err = skip_unknown_field(fd, tag, scratch, scratchSize);
268             if (err != 0) {
269                 return err;
270             }
271         }
272     }
273     return 0;
274 }
275 
276 int
run_instrumentation_test(const string & packageName,const string & runner,const string & className,InstrumentationCallbacks * callbacks)277 run_instrumentation_test(const string& packageName, const string& runner, const string& className,
278         InstrumentationCallbacks* callbacks)
279 {
280     Command cmd("adb");
281     cmd.AddArg("shell");
282     cmd.AddArg("am");
283     cmd.AddArg("instrument");
284     cmd.AddArg("-w");
285     cmd.AddArg("-m");
286     if (className.length() > 0) {
287         cmd.AddArg("-e");
288         cmd.AddArg("class");
289         cmd.AddArg(className);
290     }
291     cmd.AddArg(packageName + "/" + runner);
292 
293     print_command(cmd);
294 
295     int fds[2];
296     pipe(fds);
297 
298     pid_t pid = fork();
299 
300     if (pid == -1) {
301         // fork error
302         return errno;
303     } else if (pid == 0) {
304         // child
305         while ((dup2(fds[1], STDOUT_FILENO) == -1) && (errno == EINTR)) {}
306         close(fds[1]);
307         close(fds[0]);
308         const char* prog = cmd.GetProg();
309         char* const* argv = cmd.GetArgv();
310         char* const* env = cmd.GetEnv();
311         exec_with_path_search(prog, argv, env);
312         print_error("Unable to run command: %s", prog);
313         exit(1);
314     } else {
315         // parent
316         close(fds[1]);
317         string result;
318         const int size = 16*1024;
319         char* buf = (char*)malloc(size);
320         int err = read_instrumentation_results(fds[0], buf, size, callbacks);
321         free(buf);
322         int status;
323         waitpid(pid, &status, 0);
324         if (err != 0) {
325             return err;
326         }
327         if (WIFEXITED(status)) {
328             return WEXITSTATUS(status);
329         } else {
330             return -1;
331         }
332     }
333 }
334 
335 /**
336  * Get the second to last bundle in the args list. Stores the last name found
337  * in last. If the path is not found or if the args list is empty, returns NULL.
338  */
339 static const ResultsBundleEntry *
find_penultimate_entry(const ResultsBundle & bundle,va_list args)340 find_penultimate_entry(const ResultsBundle& bundle, va_list args)
341 {
342     const ResultsBundle* b = &bundle;
343     const char* arg = va_arg(args, char*);
344     while (arg) {
345         string last = arg;
346         arg = va_arg(args, char*);
347         bool found = false;
348         for (int i=0; i<b->entries_size(); i++) {
349             const ResultsBundleEntry& e = b->entries(i);
350             if (e.key() == last) {
351                 if (arg == NULL) {
352                     return &e;
353                 } else if (e.has_value_bundle()) {
354                     b = &e.value_bundle();
355                     found = true;
356                 }
357             }
358         }
359         if (!found) {
360             return NULL;
361         }
362         if (arg == NULL) {
363             return NULL;
364         }
365     }
366     return NULL;
367 }
368 
369 string
get_bundle_string(const ResultsBundle & bundle,bool * found,...)370 get_bundle_string(const ResultsBundle& bundle, bool* found, ...)
371 {
372     va_list args;
373     va_start(args, found);
374     const ResultsBundleEntry* entry = find_penultimate_entry(bundle, args);
375     va_end(args);
376     if (entry == NULL) {
377         *found = false;
378         return string();
379     }
380     if (entry->has_value_string()) {
381         *found = true;
382         return entry->value_string();
383     }
384     *found = false;
385     return string();
386 }
387 
388 int32_t
get_bundle_int(const ResultsBundle & bundle,bool * found,...)389 get_bundle_int(const ResultsBundle& bundle, bool* found, ...)
390 {
391     va_list args;
392     va_start(args, found);
393     const ResultsBundleEntry* entry = find_penultimate_entry(bundle, args);
394     va_end(args);
395     if (entry == NULL) {
396         *found = false;
397         return 0;
398     }
399     if (entry->has_value_int()) {
400         *found = true;
401         return entry->value_int();
402     }
403     *found = false;
404     return 0;
405 }
406 
407 float
get_bundle_float(const ResultsBundle & bundle,bool * found,...)408 get_bundle_float(const ResultsBundle& bundle, bool* found, ...)
409 {
410     va_list args;
411     va_start(args, found);
412     const ResultsBundleEntry* entry = find_penultimate_entry(bundle, args);
413     va_end(args);
414     if (entry == NULL) {
415         *found = false;
416         return 0;
417     }
418     if (entry->has_value_float()) {
419         *found = true;
420         return entry->value_float();
421     }
422     *found = false;
423     return 0;
424 }
425 
426 double
get_bundle_double(const ResultsBundle & bundle,bool * found,...)427 get_bundle_double(const ResultsBundle& bundle, bool* found, ...)
428 {
429     va_list args;
430     va_start(args, found);
431     const ResultsBundleEntry* entry = find_penultimate_entry(bundle, args);
432     va_end(args);
433     if (entry == NULL) {
434         *found = false;
435         return 0;
436     }
437     if (entry->has_value_double()) {
438         *found = true;
439         return entry->value_double();
440     }
441     *found = false;
442     return 0;
443 }
444 
445 int64_t
get_bundle_long(const ResultsBundle & bundle,bool * found,...)446 get_bundle_long(const ResultsBundle& bundle, bool* found, ...)
447 {
448     va_list args;
449     va_start(args, found);
450     const ResultsBundleEntry* entry = find_penultimate_entry(bundle, args);
451     va_end(args);
452     if (entry == NULL) {
453         *found = false;
454         return 0;
455     }
456     if (entry->has_value_long()) {
457         *found = true;
458         return entry->value_long();
459     }
460     *found = false;
461     return 0;
462 }
463 
464