adb.cpp revision 164e7967b1f47586338805e2ebfdee02a5de85db
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
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    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 */
348static const ResultsBundleEntry *
349find_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
378string
379get_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
397int32_t
398get_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
416float
417get_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
435double
436get_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
454int64_t
455get_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