• 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 "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     const int classLen = className.length();
287     if (classLen > 0) {
288         if (classLen > 1 && className[classLen - 1] == '.') {
289             cmd.AddArg("-e");
290             cmd.AddArg("package");
291 
292             // "am" actually accepts without removing the last ".", but for cleanlines...
293             cmd.AddArg(className.substr(0, classLen - 1));
294         } else {
295             cmd.AddArg("-e");
296             cmd.AddArg("class");
297             cmd.AddArg(className);
298         }
299     }
300     cmd.AddArg(packageName + "/" + runner);
301 
302     print_command(cmd);
303 
304     int fds[2];
305     if (0 != pipe(fds)) {
306         return errno;
307     }
308 
309     pid_t pid = fork();
310 
311     if (pid == -1) {
312         // fork error
313         return errno;
314     } else if (pid == 0) {
315         // child
316         while ((dup2(fds[1], STDOUT_FILENO) == -1) && (errno == EINTR)) {}
317         close(fds[1]);
318         close(fds[0]);
319         const char* prog = cmd.GetProg();
320         char* const* argv = cmd.GetArgv();
321         char* const* env = cmd.GetEnv();
322         exec_with_path_search(prog, argv, env);
323         print_error("Unable to run command: %s", prog);
324         exit(1);
325     } else {
326         // parent
327         close(fds[1]);
328         string result;
329         const int size = 16*1024;
330         char* buf = (char*)malloc(size);
331         int err = read_instrumentation_results(fds[0], buf, size, callbacks);
332         free(buf);
333         int status;
334         waitpid(pid, &status, 0);
335         if (err != 0) {
336             return err;
337         }
338         if (WIFEXITED(status)) {
339             return WEXITSTATUS(status);
340         } else {
341             return -1;
342         }
343     }
344 }
345 
346 /**
347  * Get the second to last bundle in the args list. Stores the last name found
348  * in last. If the path is not found or if the args list is empty, returns NULL.
349  */
350 static const ResultsBundleEntry *
find_penultimate_entry(const ResultsBundle & bundle,va_list args)351 find_penultimate_entry(const ResultsBundle& bundle, va_list args)
352 {
353     const ResultsBundle* b = &bundle;
354     const char* arg = va_arg(args, char*);
355     while (arg) {
356         string last = arg;
357         arg = va_arg(args, char*);
358         bool found = false;
359         for (int i=0; i<b->entries_size(); i++) {
360             const ResultsBundleEntry& e = b->entries(i);
361             if (e.key() == last) {
362                 if (arg == NULL) {
363                     return &e;
364                 } else if (e.has_value_bundle()) {
365                     b = &e.value_bundle();
366                     found = true;
367                 }
368             }
369         }
370         if (!found) {
371             return NULL;
372         }
373         if (arg == NULL) {
374             return NULL;
375         }
376     }
377     return NULL;
378 }
379 
380 string
get_bundle_string(const ResultsBundle & bundle,bool * found,...)381 get_bundle_string(const ResultsBundle& bundle, bool* found, ...)
382 {
383     va_list args;
384     va_start(args, found);
385     const ResultsBundleEntry* entry = find_penultimate_entry(bundle, args);
386     va_end(args);
387     if (entry == NULL) {
388         *found = false;
389         return string();
390     }
391     if (entry->has_value_string()) {
392         *found = true;
393         return entry->value_string();
394     }
395     *found = false;
396     return string();
397 }
398 
399 int32_t
get_bundle_int(const ResultsBundle & bundle,bool * found,...)400 get_bundle_int(const ResultsBundle& bundle, bool* found, ...)
401 {
402     va_list args;
403     va_start(args, found);
404     const ResultsBundleEntry* entry = find_penultimate_entry(bundle, args);
405     va_end(args);
406     if (entry == NULL) {
407         *found = false;
408         return 0;
409     }
410     if (entry->has_value_int()) {
411         *found = true;
412         return entry->value_int();
413     }
414     *found = false;
415     return 0;
416 }
417 
418 float
get_bundle_float(const ResultsBundle & bundle,bool * found,...)419 get_bundle_float(const ResultsBundle& bundle, bool* found, ...)
420 {
421     va_list args;
422     va_start(args, found);
423     const ResultsBundleEntry* entry = find_penultimate_entry(bundle, args);
424     va_end(args);
425     if (entry == NULL) {
426         *found = false;
427         return 0;
428     }
429     if (entry->has_value_float()) {
430         *found = true;
431         return entry->value_float();
432     }
433     *found = false;
434     return 0;
435 }
436 
437 double
get_bundle_double(const ResultsBundle & bundle,bool * found,...)438 get_bundle_double(const ResultsBundle& bundle, bool* found, ...)
439 {
440     va_list args;
441     va_start(args, found);
442     const ResultsBundleEntry* entry = find_penultimate_entry(bundle, args);
443     va_end(args);
444     if (entry == NULL) {
445         *found = false;
446         return 0;
447     }
448     if (entry->has_value_double()) {
449         *found = true;
450         return entry->value_double();
451     }
452     *found = false;
453     return 0;
454 }
455 
456 int64_t
get_bundle_long(const ResultsBundle & bundle,bool * found,...)457 get_bundle_long(const ResultsBundle& bundle, bool* found, ...)
458 {
459     va_list args;
460     va_start(args, found);
461     const ResultsBundleEntry* entry = find_penultimate_entry(bundle, args);
462     va_end(args);
463     if (entry == NULL) {
464         *found = false;
465         return 0;
466     }
467     if (entry->has_value_long()) {
468         *found = true;
469         return entry->value_long();
470     }
471     *found = false;
472     return 0;
473 }
474 
475