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