Home | History | Annotate | Download | only in bit
      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     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 *
    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
    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
    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
    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
    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
    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