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