blob: fa7d3d4031d41a702703ff292f895480b693f47c [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");
Makoto Onuki164e7962017-07-06 16:20:11 -0700286 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 }
Joe Onorato0578cbc2016-10-19 17:03:06 -0700299 }
300 cmd.AddArg(packageName + "/" + runner);
301
302 print_command(cmd);
303
304 int fds[2];
Chih-Hung Hsiehc7edf072017-10-03 09:57:55 -0700305 if (0 != pipe(fds)) {
306 return errno;
307 }
Joe Onorato0578cbc2016-10-19 17:03:06 -0700308
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();
Joe Onorato31617e3b2016-10-21 15:18:18 -0700322 exec_with_path_search(prog, argv, env);
Joe Onorato0578cbc2016-10-19 17:03:06 -0700323 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 */
350static const ResultsBundleEntry *
351find_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
380string
381get_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
399int32_t
400get_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
418float
419get_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
437double
438get_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
456int64_t
457get_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