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