blob: 93fda5434307cecd840dc06cf085f469bdb32ef7 [file] [log] [blame]
Joe Onorato0578cbc2016-10-19 17:03:06 -07001/*
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
35using namespace std;
36
37struct Buffer: public streambuf
38{
39 Buffer(char* begin, size_t size);
40};
41
42Buffer::Buffer(char* begin, size_t size)
43{
44 this->setg(begin, begin, begin + size);
45}
46
47int
48run_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
72string
73get_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
84static uint64_t
85read_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
110static char*
111read_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
153static int
154read_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
181static int
182skip_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
201static int
202skip_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
238static int
239read_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
276int
277run_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];
Chih-Hung Hsiehc7edf072017-10-03 09:57:55 -0700296 if (0 != pipe(fds)) {
297 return errno;
298 }
Joe Onorato0578cbc2016-10-19 17:03:06 -0700299
300 pid_t pid = fork();
301
302 if (pid == -1) {
303 // fork error
304 return errno;
305 } else if (pid == 0) {
306 // child
307 while ((dup2(fds[1], STDOUT_FILENO) == -1) && (errno == EINTR)) {}
308 close(fds[1]);
309 close(fds[0]);
310 const char* prog = cmd.GetProg();
311 char* const* argv = cmd.GetArgv();
312 char* const* env = cmd.GetEnv();
Joe Onorato31617e3b2016-10-21 15:18:18 -0700313 exec_with_path_search(prog, argv, env);
Joe Onorato0578cbc2016-10-19 17:03:06 -0700314 print_error("Unable to run command: %s", prog);
315 exit(1);
316 } else {
317 // parent
318 close(fds[1]);
319 string result;
320 const int size = 16*1024;
321 char* buf = (char*)malloc(size);
322 int err = read_instrumentation_results(fds[0], buf, size, callbacks);
323 free(buf);
324 int status;
325 waitpid(pid, &status, 0);
326 if (err != 0) {
327 return err;
328 }
329 if (WIFEXITED(status)) {
330 return WEXITSTATUS(status);
331 } else {
332 return -1;
333 }
334 }
335}
336
337/**
338 * Get the second to last bundle in the args list. Stores the last name found
339 * in last. If the path is not found or if the args list is empty, returns NULL.
340 */
341static const ResultsBundleEntry *
342find_penultimate_entry(const ResultsBundle& bundle, va_list args)
343{
344 const ResultsBundle* b = &bundle;
345 const char* arg = va_arg(args, char*);
346 while (arg) {
347 string last = arg;
348 arg = va_arg(args, char*);
349 bool found = false;
350 for (int i=0; i<b->entries_size(); i++) {
351 const ResultsBundleEntry& e = b->entries(i);
352 if (e.key() == last) {
353 if (arg == NULL) {
354 return &e;
355 } else if (e.has_value_bundle()) {
356 b = &e.value_bundle();
357 found = true;
358 }
359 }
360 }
361 if (!found) {
362 return NULL;
363 }
364 if (arg == NULL) {
365 return NULL;
366 }
367 }
368 return NULL;
369}
370
371string
372get_bundle_string(const ResultsBundle& bundle, bool* found, ...)
373{
374 va_list args;
375 va_start(args, found);
376 const ResultsBundleEntry* entry = find_penultimate_entry(bundle, args);
377 va_end(args);
378 if (entry == NULL) {
379 *found = false;
380 return string();
381 }
382 if (entry->has_value_string()) {
383 *found = true;
384 return entry->value_string();
385 }
386 *found = false;
387 return string();
388}
389
390int32_t
391get_bundle_int(const ResultsBundle& bundle, bool* found, ...)
392{
393 va_list args;
394 va_start(args, found);
395 const ResultsBundleEntry* entry = find_penultimate_entry(bundle, args);
396 va_end(args);
397 if (entry == NULL) {
398 *found = false;
399 return 0;
400 }
401 if (entry->has_value_int()) {
402 *found = true;
403 return entry->value_int();
404 }
405 *found = false;
406 return 0;
407}
408
409float
410get_bundle_float(const ResultsBundle& bundle, bool* found, ...)
411{
412 va_list args;
413 va_start(args, found);
414 const ResultsBundleEntry* entry = find_penultimate_entry(bundle, args);
415 va_end(args);
416 if (entry == NULL) {
417 *found = false;
418 return 0;
419 }
420 if (entry->has_value_float()) {
421 *found = true;
422 return entry->value_float();
423 }
424 *found = false;
425 return 0;
426}
427
428double
429get_bundle_double(const ResultsBundle& bundle, bool* found, ...)
430{
431 va_list args;
432 va_start(args, found);
433 const ResultsBundleEntry* entry = find_penultimate_entry(bundle, args);
434 va_end(args);
435 if (entry == NULL) {
436 *found = false;
437 return 0;
438 }
439 if (entry->has_value_double()) {
440 *found = true;
441 return entry->value_double();
442 }
443 *found = false;
444 return 0;
445}
446
447int64_t
448get_bundle_long(const ResultsBundle& bundle, bool* found, ...)
449{
450 va_list args;
451 va_start(args, found);
452 const ResultsBundleEntry* entry = find_penultimate_entry(bundle, args);
453 va_end(args);
454 if (entry == NULL) {
455 *found = false;
456 return 0;
457 }
458 if (entry->has_value_long()) {
459 *found = true;
460 return entry->value_long();
461 }
462 *found = false;
463 return 0;
464}
465