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