android-tools: add recipe
authorGrazvydas Ignotas <notasas@gmail.com>
Sat, 8 Nov 2014 22:13:03 +0000 (00:13 +0200)
committerGrazvydas Ignotas <notasas@gmail.com>
Sat, 8 Nov 2014 22:13:03 +0000 (00:13 +0200)
recipes/android-tools/android-tools/adbd-disable-client-authentication.patch [new file with mode: 0644]
recipes/android-tools/android-tools/add_adbd.patch [new file with mode: 0644]
recipes/android-tools/android-tools/android-tools-adbd.service [new file with mode: 0644]
recipes/android-tools/android-tools/disable-selinux-support.patch [new file with mode: 0644]
recipes/android-tools/android-tools/mkbootimg.mk [new file with mode: 0644]
recipes/android-tools/android-tools/reboot-syscall.patch [new file with mode: 0644]
recipes/android-tools/android-tools/remove-libselinux.patch [new file with mode: 0644]
recipes/android-tools/android-tools/sha.c [new file with mode: 0644]
recipes/android-tools/android-tools_4.2.2.bb [new file with mode: 0644]

diff --git a/recipes/android-tools/android-tools/adbd-disable-client-authentication.patch b/recipes/android-tools/android-tools/adbd-disable-client-authentication.patch
new file mode 100644 (file)
index 0000000..9539160
--- /dev/null
@@ -0,0 +1,16 @@
+--- android-tools-orig/core/adbd/adb_auth_client.c     2013-07-29 16:24:49.827822956 +0000
++++ android-tools/core/adbd/adb_auth_client.c  2013-07-29 16:25:29.931623038 +0000
+@@ -200,8 +200,11 @@
+         return;
+     }
+-    fdevent_install(&t->auth_fde, framework_fd, adb_auth_event, t);
+-    fdevent_add(&t->auth_fde, FDE_READ);
++    // fdevent_install(&t->auth_fde, framework_fd, adb_auth_event, t);
++    // fdevent_add(&t->auth_fde, FDE_READ);
++
++    adb_auth_reload_keys();
++    adb_auth_verified(t);
+ }
+ static void adb_auth_listener(int fd, unsigned events, void *data)
diff --git a/recipes/android-tools/android-tools/add_adbd.patch b/recipes/android-tools/android-tools/add_adbd.patch
new file mode 100644 (file)
index 0000000..561978f
--- /dev/null
@@ -0,0 +1,20218 @@
+## Description: add some description
+## Origin/Author: add some origin or author
+## Bug: bug URL
+Index: android-tools-4.2.2+git20130218/core/adbd/adb.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/adb.c    2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,1719 @@
++/*
++ * Copyright (C) 2007 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#define  TRACE_TAG   TRACE_ADB
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <ctype.h>
++#include <stdarg.h>
++#include <errno.h>
++#include <stddef.h>
++#include <string.h>
++#include <time.h>
++#include <sys/time.h>
++#include <stdint.h>
++
++#include "sysdeps.h"
++#include "adb.h"
++#include "adb_auth.h"
++
++#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
++
++#if !ADB_HOST
++#include "android_filesystem_config.h"
++#include <linux/capability.h>
++#include <linux/prctl.h>
++#include <sys/mount.h>
++#else
++#include "usb_vendors.h"
++#endif
++
++#if ADB_TRACE
++ADB_MUTEX_DEFINE( D_lock );
++#endif
++
++int HOST = 0;
++int gListenAll = 0;
++
++static int auth_enabled = 0;
++
++#if !ADB_HOST
++static const char *adb_device_banner = "device";
++#endif
++
++void fatal(const char *fmt, ...)
++{
++    va_list ap;
++    va_start(ap, fmt);
++    fprintf(stderr, "error: ");
++    vfprintf(stderr, fmt, ap);
++    fprintf(stderr, "\n");
++    va_end(ap);
++    exit(-1);
++}
++
++void fatal_errno(const char *fmt, ...)
++{
++    va_list ap;
++    va_start(ap, fmt);
++    fprintf(stderr, "error: %s: ", strerror(errno));
++    vfprintf(stderr, fmt, ap);
++    fprintf(stderr, "\n");
++    va_end(ap);
++    exit(-1);
++}
++
++int   adb_trace_mask;
++
++/* read a comma/space/colum/semi-column separated list of tags
++ * from the ADB_TRACE environment variable and build the trace
++ * mask from it. note that '1' and 'all' are special cases to
++ * enable all tracing
++ */
++void  adb_trace_init(void)
++{
++    const char*  p = getenv("ADB_TRACE");
++    const char*  q;
++
++    static const struct {
++        const char*  tag;
++        int           flag;
++    } tags[] = {
++        { "1", 0 },
++        { "all", 0 },
++        { "adb", TRACE_ADB },
++        { "sockets", TRACE_SOCKETS },
++        { "packets", TRACE_PACKETS },
++        { "rwx", TRACE_RWX },
++        { "usb", TRACE_USB },
++        { "sync", TRACE_SYNC },
++        { "sysdeps", TRACE_SYSDEPS },
++        { "transport", TRACE_TRANSPORT },
++        { "jdwp", TRACE_JDWP },
++        { "services", TRACE_SERVICES },
++        { "auth", TRACE_AUTH },
++        { NULL, 0 }
++    };
++
++    if (p == NULL)
++            return;
++
++    /* use a comma/column/semi-colum/space separated list */
++    while (*p) {
++        int  len, tagn;
++
++        q = strpbrk(p, " ,:;");
++        if (q == NULL) {
++            q = p + strlen(p);
++        }
++        len = q - p;
++
++        for (tagn = 0; tags[tagn].tag != NULL; tagn++)
++        {
++            int  taglen = strlen(tags[tagn].tag);
++
++            if (len == taglen && !memcmp(tags[tagn].tag, p, len) )
++            {
++                int  flag = tags[tagn].flag;
++                if (flag == 0) {
++                    adb_trace_mask = ~0;
++                    return;
++                }
++                adb_trace_mask |= (1 << flag);
++                break;
++            }
++        }
++        p = q;
++        if (*p)
++            p++;
++    }
++}
++
++#if !ADB_HOST
++/*
++ * Implements ADB tracing inside the emulator.
++ */
++
++#include <stdarg.h>
++
++/*
++ * Redefine open and write for qemu_pipe.h that contains inlined references
++ * to those routines. We will redifine them back after qemu_pipe.h inclusion.
++ */
++
++#undef open
++#undef write
++#define open    adb_open
++#define write   adb_write
++#include "qemu_pipe.h"
++#undef open
++#undef write
++#define open    ___xxx_open
++#define write   ___xxx_write
++
++/* A handle to adb-debug qemud service in the emulator. */
++int   adb_debug_qemu = -1;
++
++/* Initializes connection with the adb-debug qemud service in the emulator. */
++static int adb_qemu_trace_init(void)
++{
++    char con_name[32];
++
++    if (adb_debug_qemu >= 0) {
++        return 0;
++    }
++
++    /* adb debugging QEMUD service connection request. */
++    snprintf(con_name, sizeof(con_name), "qemud:adb-debug");
++    adb_debug_qemu = qemu_pipe_open(con_name);
++    return (adb_debug_qemu >= 0) ? 0 : -1;
++}
++
++void adb_qemu_trace(const char* fmt, ...)
++{
++    va_list args;
++    va_start(args, fmt);
++    char msg[1024];
++
++    if (adb_debug_qemu >= 0) {
++        vsnprintf(msg, sizeof(msg), fmt, args);
++        adb_write(adb_debug_qemu, msg, strlen(msg));
++    }
++}
++#endif  /* !ADB_HOST */
++
++apacket *get_apacket(void)
++{
++    apacket *p = malloc(sizeof(apacket));
++    if(p == 0) fatal("failed to allocate an apacket");
++    memset(p, 0, sizeof(apacket) - MAX_PAYLOAD);
++    return p;
++}
++
++void put_apacket(apacket *p)
++{
++    free(p);
++}
++
++void handle_online(atransport *t)
++{
++    D("adb: online\n");
++    t->online = 1;
++}
++
++void handle_offline(atransport *t)
++{
++    D("adb: offline\n");
++    //Close the associated usb
++    t->online = 0;
++    run_transport_disconnects(t);
++}
++
++#if DEBUG_PACKETS
++#define DUMPMAX 32
++void print_packet(const char *label, apacket *p)
++{
++    char *tag;
++    char *x;
++    unsigned count;
++
++    switch(p->msg.command){
++    case A_SYNC: tag = "SYNC"; break;
++    case A_CNXN: tag = "CNXN" ; break;
++    case A_OPEN: tag = "OPEN"; break;
++    case A_OKAY: tag = "OKAY"; break;
++    case A_CLSE: tag = "CLSE"; break;
++    case A_WRTE: tag = "WRTE"; break;
++    case A_AUTH: tag = "AUTH"; break;
++    default: tag = "????"; break;
++    }
++
++    fprintf(stderr, "%s: %s %08x %08x %04x \"",
++            label, tag, p->msg.arg0, p->msg.arg1, p->msg.data_length);
++    count = p->msg.data_length;
++    x = (char*) p->data;
++    if(count > DUMPMAX) {
++        count = DUMPMAX;
++        tag = "\n";
++    } else {
++        tag = "\"\n";
++    }
++    while(count-- > 0){
++        if((*x >= ' ') && (*x < 127)) {
++            fputc(*x, stderr);
++        } else {
++            fputc('.', stderr);
++        }
++        x++;
++    }
++    fputs(tag, stderr);
++}
++#endif
++
++static void send_ready(unsigned local, unsigned remote, atransport *t)
++{
++    D("Calling send_ready \n");
++    apacket *p = get_apacket();
++    p->msg.command = A_OKAY;
++    p->msg.arg0 = local;
++    p->msg.arg1 = remote;
++    send_packet(p, t);
++}
++
++static void send_close(unsigned local, unsigned remote, atransport *t)
++{
++    D("Calling send_close \n");
++    apacket *p = get_apacket();
++    p->msg.command = A_CLSE;
++    p->msg.arg0 = local;
++    p->msg.arg1 = remote;
++    send_packet(p, t);
++}
++
++static size_t fill_connect_data(char *buf, size_t bufsize)
++{
++#if ADB_HOST
++    return snprintf(buf, bufsize, "host::") + 1;
++#else
++    static const char *cnxn_props[] = {
++        "ro.product.name",
++        "ro.product.model",
++        "ro.product.device",
++    };
++    static const int num_cnxn_props = ARRAY_SIZE(cnxn_props);
++    static const char *values[] = {
++        "occam",
++        "Nexus 4",
++        "mako",
++    };
++    int i;
++    size_t remaining = bufsize;
++    size_t len;
++
++    len = snprintf(buf, remaining, "%s::", adb_device_banner);
++    remaining -= len;
++    buf += len;
++    for (i = 0; i < num_cnxn_props; i++) {
++        char value[PROPERTY_VALUE_MAX];
++        //property_get(cnxn_props[i], value, "");
++        len = snprintf(buf, remaining, "%s=%s;", cnxn_props[i], values[i]);
++        remaining -= len;
++        buf += len;
++    }
++
++    return bufsize - remaining + 1;
++#endif
++}
++
++static void send_connect(atransport *t)
++{
++    D("Calling send_connect \n");
++    apacket *cp = get_apacket();
++    cp->msg.command = A_CNXN;
++    cp->msg.arg0 = A_VERSION;
++    cp->msg.arg1 = MAX_PAYLOAD;
++    cp->msg.data_length = fill_connect_data((char *)cp->data,
++                                            sizeof(cp->data));
++    send_packet(cp, t);
++}
++
++static void send_auth_request(atransport *t)
++{
++    D("Calling send_auth_request\n");
++    apacket *p;
++    int ret;
++
++    ret = adb_auth_generate_token(t->token, sizeof(t->token));
++    if (ret != sizeof(t->token)) {
++        D("Error generating token ret=%d\n", ret);
++        return;
++    }
++
++    p = get_apacket();
++    memcpy(p->data, t->token, ret);
++    p->msg.command = A_AUTH;
++    p->msg.arg0 = ADB_AUTH_TOKEN;
++    p->msg.data_length = ret;
++    send_packet(p, t);
++}
++
++static void send_auth_response(uint8_t *token, size_t token_size, atransport *t)
++{
++    D("Calling send_auth_response\n");
++    apacket *p = get_apacket();
++    int ret;
++
++    ret = adb_auth_sign(t->key, token, token_size, p->data);
++    if (!ret) {
++        D("Error signing the token\n");
++        put_apacket(p);
++        return;
++    }
++
++    p->msg.command = A_AUTH;
++    p->msg.arg0 = ADB_AUTH_SIGNATURE;
++    p->msg.data_length = ret;
++    send_packet(p, t);
++}
++
++static void send_auth_publickey(atransport *t)
++{
++    D("Calling send_auth_publickey\n");
++    apacket *p = get_apacket();
++    int ret;
++
++    ret = adb_auth_get_userkey(p->data, sizeof(p->data));
++    if (!ret) {
++        D("Failed to get user public key\n");
++        put_apacket(p);
++        return;
++    }
++
++    p->msg.command = A_AUTH;
++    p->msg.arg0 = ADB_AUTH_RSAPUBLICKEY;
++    p->msg.data_length = ret;
++    send_packet(p, t);
++}
++
++void adb_auth_verified(atransport *t)
++{
++    handle_online(t);
++    send_connect(t);
++}
++
++static char *connection_state_name(atransport *t)
++{
++    if (t == NULL) {
++        return "unknown";
++    }
++
++    switch(t->connection_state) {
++    case CS_BOOTLOADER:
++        return "bootloader";
++    case CS_DEVICE:
++        return "device";
++    case CS_OFFLINE:
++        return "offline";
++    default:
++        return "unknown";
++    }
++}
++
++/* qual_overwrite is used to overwrite a qualifier string.  dst is a
++ * pointer to a char pointer.  It is assumed that if *dst is non-NULL, it
++ * was malloc'ed and needs to freed.  *dst will be set to a dup of src.
++ */
++static void qual_overwrite(char **dst, const char *src)
++{
++    if (!dst)
++        return;
++
++    free(*dst);
++    *dst = NULL;
++
++    if (!src || !*src)
++        return;
++
++    *dst = strdup(src);
++}
++
++void parse_banner(char *banner, atransport *t)
++{
++    static const char *prop_seps = ";";
++    static const char key_val_sep = '=';
++    char *cp;
++    char *type;
++
++    D("parse_banner: %s\n", banner);
++    type = banner;
++    cp = strchr(type, ':');
++    if (cp) {
++        *cp++ = 0;
++        /* Nothing is done with second field. */
++        cp = strchr(cp, ':');
++        if (cp) {
++            char *save;
++            char *key;
++            key = adb_strtok_r(cp + 1, prop_seps, &save);
++            while (key) {
++                cp = strchr(key, key_val_sep);
++                if (cp) {
++                    *cp++ = '\0';
++                    if (!strcmp(key, "ro.product.name"))
++                        qual_overwrite(&t->product, cp);
++                    else if (!strcmp(key, "ro.product.model"))
++                        qual_overwrite(&t->model, cp);
++                    else if (!strcmp(key, "ro.product.device"))
++                        qual_overwrite(&t->device, cp);
++                }
++                key = adb_strtok_r(NULL, prop_seps, &save);
++            }
++        }
++    }
++
++    if(!strcmp(type, "bootloader")){
++        D("setting connection_state to CS_BOOTLOADER\n");
++        t->connection_state = CS_BOOTLOADER;
++        update_transports();
++        return;
++    }
++
++    if(!strcmp(type, "device")) {
++        D("setting connection_state to CS_DEVICE\n");
++        t->connection_state = CS_DEVICE;
++        update_transports();
++        return;
++    }
++
++    if(!strcmp(type, "recovery")) {
++        D("setting connection_state to CS_RECOVERY\n");
++        t->connection_state = CS_RECOVERY;
++        update_transports();
++        return;
++    }
++
++    if(!strcmp(type, "sideload")) {
++        D("setting connection_state to CS_SIDELOAD\n");
++        t->connection_state = CS_SIDELOAD;
++        update_transports();
++        return;
++    }
++
++    t->connection_state = CS_HOST;
++}
++
++void handle_packet(apacket *p, atransport *t)
++{
++    asocket *s;
++
++    D("handle_packet() %c%c%c%c\n", ((char*) (&(p->msg.command)))[0],
++            ((char*) (&(p->msg.command)))[1],
++            ((char*) (&(p->msg.command)))[2],
++            ((char*) (&(p->msg.command)))[3]);
++    print_packet("recv", p);
++
++    switch(p->msg.command){
++    case A_SYNC:
++        if(p->msg.arg0){
++            send_packet(p, t);
++            if(HOST) send_connect(t);
++        } else {
++            t->connection_state = CS_OFFLINE;
++            handle_offline(t);
++            send_packet(p, t);
++        }
++        return;
++
++    case A_CNXN: /* CONNECT(version, maxdata, "system-id-string") */
++            /* XXX verify version, etc */
++        if(t->connection_state != CS_OFFLINE) {
++            t->connection_state = CS_OFFLINE;
++            handle_offline(t);
++        }
++
++        parse_banner((char*) p->data, t);
++
++        if (HOST || !auth_enabled) {
++            handle_online(t);
++            if(!HOST) send_connect(t);
++        } else {
++            send_auth_request(t);
++        }
++        break;
++
++    case A_AUTH:
++        if (p->msg.arg0 == ADB_AUTH_TOKEN) {
++            t->key = adb_auth_nextkey(t->key);
++            if (t->key) {
++                send_auth_response(p->data, p->msg.data_length, t);
++            } else {
++                /* No more private keys to try, send the public key */
++                send_auth_publickey(t);
++            }
++        } else if (p->msg.arg0 == ADB_AUTH_SIGNATURE) {
++            if (adb_auth_verify(t->token, p->data, p->msg.data_length)) {
++                adb_auth_verified(t);
++                t->failed_auth_attempts = 0;
++            } else {
++                if (t->failed_auth_attempts++ > 10)
++                    adb_sleep_ms(1000);
++                send_auth_request(t);
++            }
++        } else if (p->msg.arg0 == ADB_AUTH_RSAPUBLICKEY) {
++            adb_auth_confirm_key(p->data, p->msg.data_length, t);
++        }
++        break;
++
++    case A_OPEN: /* OPEN(local-id, 0, "destination") */
++        if (t->online) {
++            char *name = (char*) p->data;
++            name[p->msg.data_length > 0 ? p->msg.data_length - 1 : 0] = 0;
++            s = create_local_service_socket(name);
++            if(s == 0) {
++                send_close(0, p->msg.arg0, t);
++            } else {
++                s->peer = create_remote_socket(p->msg.arg0, t);
++                s->peer->peer = s;
++                send_ready(s->id, s->peer->id, t);
++                s->ready(s);
++            }
++        }
++        break;
++
++    case A_OKAY: /* READY(local-id, remote-id, "") */
++        if (t->online) {
++            if((s = find_local_socket(p->msg.arg1))) {
++                if(s->peer == 0) {
++                    s->peer = create_remote_socket(p->msg.arg0, t);
++                    s->peer->peer = s;
++                }
++                s->ready(s);
++            }
++        }
++        break;
++
++    case A_CLSE: /* CLOSE(local-id, remote-id, "") */
++        if (t->online) {
++            if((s = find_local_socket(p->msg.arg1))) {
++                s->close(s);
++            }
++        }
++        break;
++
++    case A_WRTE:
++        if (t->online) {
++            if((s = find_local_socket(p->msg.arg1))) {
++                unsigned rid = p->msg.arg0;
++                p->len = p->msg.data_length;
++
++                if(s->enqueue(s, p) == 0) {
++                    D("Enqueue the socket\n");
++                    send_ready(s->id, rid, t);
++                }
++                return;
++            }
++        }
++        break;
++
++    default:
++        printf("handle_packet: what is %08x?!\n", p->msg.command);
++    }
++
++    put_apacket(p);
++}
++
++alistener listener_list = {
++    .next = &listener_list,
++    .prev = &listener_list,
++};
++
++static void ss_listener_event_func(int _fd, unsigned ev, void *_l)
++{
++    asocket *s;
++
++    if(ev & FDE_READ) {
++        struct sockaddr addr;
++        socklen_t alen;
++        int fd;
++
++        alen = sizeof(addr);
++        fd = adb_socket_accept(_fd, &addr, &alen);
++        if(fd < 0) return;
++
++        adb_socket_setbufsize(fd, CHUNK_SIZE);
++
++        s = create_local_socket(fd);
++        if(s) {
++            connect_to_smartsocket(s);
++            return;
++        }
++
++        adb_close(fd);
++    }
++}
++
++static void listener_event_func(int _fd, unsigned ev, void *_l)
++{
++    alistener *l = _l;
++    asocket *s;
++
++    if(ev & FDE_READ) {
++        struct sockaddr addr;
++        socklen_t alen;
++        int fd;
++
++        alen = sizeof(addr);
++        fd = adb_socket_accept(_fd, &addr, &alen);
++        if(fd < 0) return;
++
++        s = create_local_socket(fd);
++        if(s) {
++            s->transport = l->transport;
++            connect_to_remote(s, l->connect_to);
++            return;
++        }
++
++        adb_close(fd);
++    }
++}
++
++static void  free_listener(alistener*  l)
++{
++    if (l->next) {
++        l->next->prev = l->prev;
++        l->prev->next = l->next;
++        l->next = l->prev = l;
++    }
++
++    // closes the corresponding fd
++    fdevent_remove(&l->fde);
++
++    if (l->local_name)
++        free((char*)l->local_name);
++
++    if (l->connect_to)
++        free((char*)l->connect_to);
++
++    if (l->transport) {
++        remove_transport_disconnect(l->transport, &l->disconnect);
++    }
++    free(l);
++}
++
++static void listener_disconnect(void*  _l, atransport*  t)
++{
++    alistener*  l = _l;
++
++    free_listener(l);
++}
++
++int local_name_to_fd(const char *name)
++{
++    int port;
++
++    if(!strncmp("tcp:", name, 4)){
++        int  ret;
++        port = atoi(name + 4);
++
++        if (gListenAll > 0) {
++            ret = socket_inaddr_any_server(port, SOCK_STREAM);
++        } else {
++            ret = socket_loopback_server(port, SOCK_STREAM);
++        }
++
++        return ret;
++    }
++#ifndef HAVE_WIN32_IPC  /* no Unix-domain sockets on Win32 */
++    // It's non-sensical to support the "reserved" space on the adb host side
++    if(!strncmp(name, "local:", 6)) {
++        return socket_local_server(name + 6,
++                ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
++    } else if(!strncmp(name, "localabstract:", 14)) {
++        return socket_local_server(name + 14,
++                ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
++    } else if(!strncmp(name, "localfilesystem:", 16)) {
++        return socket_local_server(name + 16,
++                ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
++    }
++
++#endif
++    printf("unknown local portname '%s'\n", name);
++    return -1;
++}
++
++// Write a single line describing a listener to a user-provided buffer.
++// Appends a trailing zero, even in case of truncation, but the function
++// returns the full line length.
++// If |buffer| is NULL, does not write but returns required size.
++static int format_listener(alistener* l, char* buffer, size_t buffer_len) {
++    // Format is simply:
++    //
++    //  <device-serial> " " <local-name> " " <remote-name> "\n"
++    //
++    int local_len = strlen(l->local_name);
++    int connect_len = strlen(l->connect_to);
++    int serial_len = strlen(l->transport->serial);
++
++    if (buffer != NULL) {
++        snprintf(buffer, buffer_len, "%s %s %s\n",
++                l->transport->serial, l->local_name, l->connect_to);
++    }
++    // NOTE: snprintf() on Windows returns -1 in case of truncation, so
++    // return the computed line length instead.
++    return local_len + connect_len + serial_len + 3;
++}
++
++// Write the list of current listeners (network redirections) into a
++// user-provided buffer. Appends a trailing zero, even in case of
++// trunctaion, but return the full size in bytes.
++// If |buffer| is NULL, does not write but returns required size.
++static int format_listeners(char* buf, size_t buflen)
++{
++    alistener* l;
++    int result = 0;
++    for (l = listener_list.next; l != &listener_list; l = l->next) {
++        // Ignore special listeners like those for *smartsocket*
++        if (l->connect_to[0] == '*')
++          continue;
++        int len = format_listener(l, buf, buflen);
++        // Ensure there is space for the trailing zero.
++        result += len;
++        if (buf != NULL) {
++          buf += len;
++          buflen -= len;
++          if (buflen <= 0)
++              break;
++        }
++    }
++    return result;
++}
++
++static int remove_listener(const char *local_name, atransport* transport)
++{
++    alistener *l;
++
++    for (l = listener_list.next; l != &listener_list; l = l->next) {
++        if (!strcmp(local_name, l->local_name)) {
++            listener_disconnect(l, l->transport);
++            return 0;
++        }
++    }
++    return -1;
++}
++
++static void remove_all_listeners(void)
++{
++    alistener *l, *l_next;
++    for (l = listener_list.next; l != &listener_list; l = l_next) {
++        l_next = l->next;
++        // Never remove smart sockets.
++        if (l->connect_to[0] == '*')
++            continue;
++        listener_disconnect(l, l->transport);
++    }
++}
++
++// error/status codes for install_listener.
++typedef enum {
++  INSTALL_STATUS_OK = 0,
++  INSTALL_STATUS_INTERNAL_ERROR = -1,
++  INSTALL_STATUS_CANNOT_BIND = -2,
++  INSTALL_STATUS_CANNOT_REBIND = -3,
++} install_status_t;
++
++static install_status_t install_listener(const char *local_name,
++                                         const char *connect_to,
++                                         atransport* transport,
++                                         int no_rebind)
++{
++    alistener *l;
++
++    printf("install_listener('%s','%s')\n", local_name, connect_to);
++
++    for(l = listener_list.next; l != &listener_list; l = l->next){
++        if(strcmp(local_name, l->local_name) == 0) {
++            char *cto;
++
++                /* can't repurpose a smartsocket */
++            if(l->connect_to[0] == '*') {
++                return INSTALL_STATUS_INTERNAL_ERROR;
++            }
++
++                /* can't repurpose a listener if 'no_rebind' is true */
++            if (no_rebind) {
++                return INSTALL_STATUS_CANNOT_REBIND;
++            }
++
++            cto = strdup(connect_to);
++            if(cto == 0) {
++                return INSTALL_STATUS_INTERNAL_ERROR;
++            }
++
++            //printf("rebinding '%s' to '%s'\n", local_name, connect_to);
++            free((void*) l->connect_to);
++            l->connect_to = cto;
++            if (l->transport != transport) {
++                remove_transport_disconnect(l->transport, &l->disconnect);
++                l->transport = transport;
++                add_transport_disconnect(l->transport, &l->disconnect);
++            }
++            return INSTALL_STATUS_OK;
++        }
++    }
++
++    if((l = calloc(1, sizeof(alistener))) == 0) goto nomem;
++    if((l->local_name = strdup(local_name)) == 0) goto nomem;
++    if((l->connect_to = strdup(connect_to)) == 0) goto nomem;
++
++
++    l->fd = local_name_to_fd(local_name);
++    if(l->fd < 0) {
++        free((void*) l->local_name);
++        free((void*) l->connect_to);
++        free(l);
++        printf("cannot bind '%s'\n", local_name);
++        return -2;
++    }
++
++    close_on_exec(l->fd);
++    if(!strcmp(l->connect_to, "*smartsocket*")) {
++        fdevent_install(&l->fde, l->fd, ss_listener_event_func, l);
++    } else {
++        fdevent_install(&l->fde, l->fd, listener_event_func, l);
++    }
++    fdevent_set(&l->fde, FDE_READ);
++
++    l->next = &listener_list;
++    l->prev = listener_list.prev;
++    l->next->prev = l;
++    l->prev->next = l;
++    l->transport = transport;
++
++    if (transport) {
++        l->disconnect.opaque = l;
++        l->disconnect.func   = listener_disconnect;
++        add_transport_disconnect(transport, &l->disconnect);
++    }
++    return INSTALL_STATUS_OK;
++
++nomem:
++    fatal("cannot allocate listener");
++    return INSTALL_STATUS_INTERNAL_ERROR;
++}
++
++#ifdef HAVE_WIN32_PROC
++static BOOL WINAPI ctrlc_handler(DWORD type)
++{
++    exit(STATUS_CONTROL_C_EXIT);
++    return TRUE;
++}
++#endif
++
++static void adb_cleanup(void)
++{
++    usb_cleanup();
++}
++
++void start_logging(void)
++{
++#ifdef HAVE_WIN32_PROC
++    char    temp[ MAX_PATH ];
++    FILE*   fnul;
++    FILE*   flog;
++
++    GetTempPath( sizeof(temp) - 8, temp );
++    strcat( temp, "adb.log" );
++
++    /* Win32 specific redirections */
++    fnul = fopen( "NUL", "rt" );
++    if (fnul != NULL)
++        stdin[0] = fnul[0];
++
++    flog = fopen( temp, "at" );
++    if (flog == NULL)
++        flog = fnul;
++
++    setvbuf( flog, NULL, _IONBF, 0 );
++
++    stdout[0] = flog[0];
++    stderr[0] = flog[0];
++    fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid());
++#else
++    int fd;
++
++    fd = unix_open("/dev/null", O_RDONLY);
++    dup2(fd, 0);
++    adb_close(fd);
++
++    fd = unix_open("/tmp/adb.log", O_WRONLY | O_CREAT | O_APPEND, 0640);
++    if(fd < 0) {
++        fd = unix_open("/dev/null", O_WRONLY);
++    }
++    dup2(fd, 1);
++    dup2(fd, 2);
++    adb_close(fd);
++    fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid());
++#endif
++}
++
++#if !ADB_HOST
++void start_device_log(void)
++{
++    int fd;
++    char    path[PATH_MAX];
++    struct tm now;
++    time_t t;
++    char value[PROPERTY_VALUE_MAX];
++
++    // read the trace mask from persistent property persist.adb.trace_mask
++    // give up if the property is not set or cannot be parsed
++    //property_get("persist.adb.trace_mask", value, "");
++    //if (sscanf(value, "%x", &adb_trace_mask) != 1)
++    return;
++
++    adb_mkdir("/data/adb", 0775);
++    tzset();
++    time(&t);
++    localtime_r(&t, &now);
++    strftime(path, sizeof(path),
++                "/data/adb/adb-%Y-%m-%d-%H-%M-%S.txt",
++                &now);
++    fd = unix_open(path, O_WRONLY | O_CREAT | O_TRUNC, 0640);
++    if (fd < 0)
++        return;
++
++    // redirect stdout and stderr to the log file
++    dup2(fd, 1);
++    dup2(fd, 2);
++    fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid());
++    adb_close(fd);
++
++    fd = unix_open("/dev/null", O_RDONLY);
++    dup2(fd, 0);
++    adb_close(fd);
++}
++#endif
++
++#if ADB_HOST
++int launch_server(int server_port)
++{
++#ifdef HAVE_WIN32_PROC
++    /* we need to start the server in the background                    */
++    /* we create a PIPE that will be used to wait for the server's "OK" */
++    /* message since the pipe handles must be inheritable, we use a     */
++    /* security attribute                                               */
++    HANDLE                pipe_read, pipe_write;
++    HANDLE                stdout_handle, stderr_handle;
++    SECURITY_ATTRIBUTES   sa;
++    STARTUPINFO           startup;
++    PROCESS_INFORMATION   pinfo;
++    char                  program_path[ MAX_PATH ];
++    int                   ret;
++
++    sa.nLength = sizeof(sa);
++    sa.lpSecurityDescriptor = NULL;
++    sa.bInheritHandle = TRUE;
++
++    /* create pipe, and ensure its read handle isn't inheritable */
++    ret = CreatePipe( &pipe_read, &pipe_write, &sa, 0 );
++    if (!ret) {
++        fprintf(stderr, "CreatePipe() failure, error %ld\n", GetLastError() );
++        return -1;
++    }
++
++    SetHandleInformation( pipe_read, HANDLE_FLAG_INHERIT, 0 );
++
++    /* Some programs want to launch an adb command and collect its output by
++     * calling CreateProcess with inheritable stdout/stderr handles, then
++     * using read() to get its output. When this happens, the stdout/stderr
++     * handles passed to the adb client process will also be inheritable.
++     * When starting the adb server here, care must be taken to reset them
++     * to non-inheritable.
++     * Otherwise, something bad happens: even if the adb command completes,
++     * the calling process is stuck while read()-ing from the stdout/stderr
++     * descriptors, because they're connected to corresponding handles in the
++     * adb server process (even if the latter never uses/writes to them).
++     */
++    stdout_handle = GetStdHandle( STD_OUTPUT_HANDLE );
++    stderr_handle = GetStdHandle( STD_ERROR_HANDLE );
++    if (stdout_handle != INVALID_HANDLE_VALUE) {
++        SetHandleInformation( stdout_handle, HANDLE_FLAG_INHERIT, 0 );
++    }
++    if (stderr_handle != INVALID_HANDLE_VALUE) {
++        SetHandleInformation( stderr_handle, HANDLE_FLAG_INHERIT, 0 );
++    }
++
++    ZeroMemory( &startup, sizeof(startup) );
++    startup.cb = sizeof(startup);
++    startup.hStdInput  = GetStdHandle( STD_INPUT_HANDLE );
++    startup.hStdOutput = pipe_write;
++    startup.hStdError  = GetStdHandle( STD_ERROR_HANDLE );
++    startup.dwFlags    = STARTF_USESTDHANDLES;
++
++    ZeroMemory( &pinfo, sizeof(pinfo) );
++
++    /* get path of current program */
++    GetModuleFileName( NULL, program_path, sizeof(program_path) );
++
++    ret = CreateProcess(
++            program_path,                              /* program path  */
++            "adb fork-server server",
++                                    /* the fork-server argument will set the
++                                       debug = 2 in the child           */
++            NULL,                   /* process handle is not inheritable */
++            NULL,                    /* thread handle is not inheritable */
++            TRUE,                          /* yes, inherit some handles */
++            DETACHED_PROCESS, /* the new process doesn't have a console */
++            NULL,                     /* use parent's environment block */
++            NULL,                    /* use parent's starting directory */
++            &startup,                 /* startup info, i.e. std handles */
++            &pinfo );
++
++    CloseHandle( pipe_write );
++
++    if (!ret) {
++        fprintf(stderr, "CreateProcess failure, error %ld\n", GetLastError() );
++        CloseHandle( pipe_read );
++        return -1;
++    }
++
++    CloseHandle( pinfo.hProcess );
++    CloseHandle( pinfo.hThread );
++
++    /* wait for the "OK\n" message */
++    {
++        char  temp[3];
++        DWORD  count;
++
++        ret = ReadFile( pipe_read, temp, 3, &count, NULL );
++        CloseHandle( pipe_read );
++        if ( !ret ) {
++            fprintf(stderr, "could not read ok from ADB Server, error = %ld\n", GetLastError() );
++            return -1;
++        }
++        if (count != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
++            fprintf(stderr, "ADB server didn't ACK\n" );
++            return -1;
++        }
++    }
++#elif defined(HAVE_FORKEXEC)
++    char    path[PATH_MAX];
++    int     fd[2];
++
++    // set up a pipe so the child can tell us when it is ready.
++    // fd[0] will be parent's end, and fd[1] will get mapped to stderr in the child.
++    if (pipe(fd)) {
++        fprintf(stderr, "pipe failed in launch_server, errno: %d\n", errno);
++        return -1;
++    }
++    get_my_path(path, PATH_MAX);
++    pid_t pid = fork();
++    if(pid < 0) return -1;
++
++    if (pid == 0) {
++        // child side of the fork
++
++        // redirect stderr to the pipe
++        // we use stderr instead of stdout due to stdout's buffering behavior.
++        adb_close(fd[0]);
++        dup2(fd[1], STDERR_FILENO);
++        adb_close(fd[1]);
++
++        char str_port[30];
++        snprintf(str_port, sizeof(str_port), "%d",  server_port);
++        // child process
++        int result = execl(path, "adb", "-P", str_port, "fork-server", "server", NULL);
++        // this should not return
++        fprintf(stderr, "OOPS! execl returned %d, errno: %d\n", result, errno);
++    } else  {
++        // parent side of the fork
++
++        char  temp[3];
++
++        temp[0] = 'A'; temp[1] = 'B'; temp[2] = 'C';
++        // wait for the "OK\n" message
++        adb_close(fd[1]);
++        int ret = adb_read(fd[0], temp, 3);
++        int saved_errno = errno;
++        adb_close(fd[0]);
++        if (ret < 0) {
++            fprintf(stderr, "could not read ok from ADB Server, errno = %d\n", saved_errno);
++            return -1;
++        }
++        if (ret != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
++            fprintf(stderr, "ADB server didn't ACK\n" );
++            return -1;
++        }
++
++        setsid();
++    }
++#else
++#error "cannot implement background server start on this platform"
++#endif
++    return 0;
++}
++#endif
++
++/* Constructs a local name of form tcp:port.
++ * target_str points to the target string, it's content will be overwritten.
++ * target_size is the capacity of the target string.
++ * server_port is the port number to use for the local name.
++ */
++void build_local_name(char* target_str, size_t target_size, int server_port)
++{
++  snprintf(target_str, target_size, "tcp:%d", server_port);
++}
++
++#if !ADB_HOST
++static int should_drop_privileges() {
++#ifndef ALLOW_ADBD_ROOT
++    return 1;
++#else /* ALLOW_ADBD_ROOT */
++    int secure = 0;
++    char value[PROPERTY_VALUE_MAX];
++
++    return 0;
++   /* run adbd in secure mode if ro.secure is set and
++    ** we are not in the emulator
++    */
++//    property_get("ro.kernel.qemu", value, "");
++    if (strcmp(value, "1") != 0) {
++//        property_get("ro.secure", value, "1");
++        if (strcmp(value, "1") == 0) {
++            // don't run as root if ro.secure is set...
++            secure = 1;
++
++            // ... except we allow running as root in userdebug builds if the
++            // service.adb.root property has been set by the "adb root" command
++//            property_get("ro.debuggable", value, "");
++            if (strcmp(value, "1") == 0) {
++//                property_get("service.adb.root", value, "");
++                if (strcmp(value, "1") == 0) {
++                    secure = 0;
++                }
++            }
++        }
++    }
++    return secure;
++#endif /* ALLOW_ADBD_ROOT */
++}
++#endif /* !ADB_HOST */
++
++int adb_main(int is_daemon, int server_port)
++{
++#if !ADB_HOST
++    int port;
++    char value[PROPERTY_VALUE_MAX];
++
++    umask(000);
++#endif
++
++    atexit(adb_cleanup);
++#ifdef HAVE_WIN32_PROC
++    SetConsoleCtrlHandler( ctrlc_handler, TRUE );
++#elif defined(HAVE_FORKEXEC)
++    // No SIGCHLD. Let the service subproc handle its children.
++    signal(SIGPIPE, SIG_IGN);
++#endif
++
++    init_transport_registration();
++
++#if ADB_HOST
++    HOST = 1;
++    usb_vendors_init();
++    usb_init();
++    local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
++    adb_auth_init();
++
++    char local_name[30];
++    build_local_name(local_name, sizeof(local_name), server_port);
++    if(install_listener(local_name, "*smartsocket*", NULL, 0)) {
++        exit(1);
++    }
++#else
++    //property_get("ro.adb.secure", value, "0");
++    auth_enabled = 0;//!strcmp(value, "1");
++    if (auth_enabled)
++        adb_auth_init();
++
++    // Our external storage path may be different than apps, since
++    // we aren't able to bind mount after dropping root.
++    const char* adb_external_storage = getenv("ADB_EXTERNAL_STORAGE");
++    if (NULL != adb_external_storage) {
++        setenv("EXTERNAL_STORAGE", adb_external_storage, 1);
++    } else {
++        D("Warning: ADB_EXTERNAL_STORAGE is not set.  Leaving EXTERNAL_STORAGE"
++          " unchanged.\n");
++    }
++
++    /* don't listen on a port (default 5037) if running in secure mode */
++    /* don't run as root if we are running in secure mode */
++    if (should_drop_privileges()) {
++        struct __user_cap_header_struct header;
++        struct __user_cap_data_struct cap[2];
++
++        if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
++            exit(1);
++        }
++
++        /* add extra groups:
++        ** AID_ADB to access the USB driver
++        ** AID_LOG to read system logs (adb logcat)
++        ** AID_INPUT to diagnose input issues (getevent)
++        ** AID_INET to diagnose network issues (netcfg, ping)
++        ** AID_GRAPHICS to access the frame buffer
++        ** AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump)
++        ** AID_SDCARD_R to allow reading from the SD card
++        ** AID_SDCARD_RW to allow writing to the SD card
++        ** AID_MOUNT to allow unmounting the SD card before rebooting
++        ** AID_NET_BW_STATS to read out qtaguid statistics
++        */
++        gid_t groups[] = { AID_ADB, AID_LOG, AID_INPUT, AID_INET, AID_GRAPHICS,
++                           AID_NET_BT, AID_NET_BT_ADMIN, AID_SDCARD_R, AID_SDCARD_RW,
++                           AID_MOUNT, AID_NET_BW_STATS };
++        if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
++            exit(1);
++        }
++
++        /* then switch user and group to "shell" */
++        if (setgid(AID_SHELL) != 0) {
++            exit(1);
++        }
++        if (setuid(AID_SHELL) != 0) {
++            exit(1);
++        }
++
++        memset(&header, 0, sizeof(header));
++        memset(cap, 0, sizeof(cap));
++
++        /* set CAP_SYS_BOOT capability, so "adb reboot" will succeed */
++        header.version = _LINUX_CAPABILITY_VERSION_3;
++        header.pid = 0;
++        cap[CAP_TO_INDEX(CAP_SYS_BOOT)].effective |= CAP_TO_MASK(CAP_SYS_BOOT);
++        cap[CAP_TO_INDEX(CAP_SYS_BOOT)].permitted |= CAP_TO_MASK(CAP_SYS_BOOT);
++        capset(&header, cap);
++
++        D("Local port disabled\n");
++    } else {
++        char local_name[30];
++        build_local_name(local_name, sizeof(local_name), server_port);
++        if(install_listener(local_name, "*smartsocket*", NULL, 0)) {
++            exit(1);
++        }
++    }
++
++    int usb = 0;
++    if (access(USB_ADB_PATH, F_OK) == 0 || access(USB_FFS_ADB_EP0, F_OK) == 0) {
++        // listen on USB
++        usb_init();
++        usb = 1;
++    }
++
++    // If one of these properties is set, also listen on that port
++    // If one of the properties isn't set and we couldn't listen on usb,
++    // listen on the default port.
++    //property_get("service.adb.tcp.port", value, "");
++    //if (!value[0]) {
++        //property_get("persist.adb.tcp.port", value, "");
++    //}
++    //if (sscanf(value, "%d", &port) == 1 && port > 0) {
++    //    printf("using port=%d\n", port);
++        // listen on TCP port specified by service.adb.tcp.port property
++    //    local_init(port);
++    //} else 
++    if (!usb) {
++        printf("Using USB\n");
++        // listen on default port
++        local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
++    }
++
++    D("adb_main(): pre init_jdwp()\n");
++    init_jdwp();
++    D("adb_main(): post init_jdwp()\n");
++#endif
++
++    if (is_daemon)
++    {
++        // inform our parent that we are up and running.
++#ifdef HAVE_WIN32_PROC
++        DWORD  count;
++        WriteFile( GetStdHandle( STD_OUTPUT_HANDLE ), "OK\n", 3, &count, NULL );
++#elif defined(HAVE_FORKEXEC)
++        fprintf(stderr, "OK\n");
++#endif
++        start_logging();
++    }
++    D("Event loop starting\n");
++
++    fdevent_loop();
++
++    usb_cleanup();
++
++    return 0;
++}
++
++#if ADB_HOST
++void connect_device(char* host, char* buffer, int buffer_size)
++{
++    int port, fd;
++    char* portstr = strchr(host, ':');
++    char hostbuf[100];
++    char serial[100];
++
++    strncpy(hostbuf, host, sizeof(hostbuf) - 1);
++    if (portstr) {
++        if (portstr - host >= (ptrdiff_t)sizeof(hostbuf)) {
++            snprintf(buffer, buffer_size, "bad host name %s", host);
++            return;
++        }
++        // zero terminate the host at the point we found the colon
++        hostbuf[portstr - host] = 0;
++        if (sscanf(portstr + 1, "%d", &port) == 0) {
++            snprintf(buffer, buffer_size, "bad port number %s", portstr);
++            return;
++        }
++    } else {
++        port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
++    }
++
++    snprintf(serial, sizeof(serial), "%s:%d", hostbuf, port);
++    if (find_transport(serial)) {
++        snprintf(buffer, buffer_size, "already connected to %s", serial);
++        return;
++    }
++
++    fd = socket_network_client(hostbuf, port, SOCK_STREAM);
++    if (fd < 0) {
++        snprintf(buffer, buffer_size, "unable to connect to %s:%d", host, port);
++        return;
++    }
++
++    D("client: connected on remote on fd %d\n", fd);
++    close_on_exec(fd);
++    disable_tcp_nagle(fd);
++    register_socket_transport(fd, serial, port, 0);
++    snprintf(buffer, buffer_size, "connected to %s", serial);
++}
++
++void connect_emulator(char* port_spec, char* buffer, int buffer_size)
++{
++    char* port_separator = strchr(port_spec, ',');
++    if (!port_separator) {
++        snprintf(buffer, buffer_size,
++                "unable to parse '%s' as <console port>,<adb port>",
++                port_spec);
++        return;
++    }
++
++    // Zero-terminate console port and make port_separator point to 2nd port.
++    *port_separator++ = 0;
++    int console_port = strtol(port_spec, NULL, 0);
++    int adb_port = strtol(port_separator, NULL, 0);
++    if (!(console_port > 0 && adb_port > 0)) {
++        *(port_separator - 1) = ',';
++        snprintf(buffer, buffer_size,
++                "Invalid port numbers: Expected positive numbers, got '%s'",
++                port_spec);
++        return;
++    }
++
++    /* Check if the emulator is already known.
++     * Note: There's a small but harmless race condition here: An emulator not
++     * present just yet could be registered by another invocation right
++     * after doing this check here. However, local_connect protects
++     * against double-registration too. From here, a better error message
++     * can be produced. In the case of the race condition, the very specific
++     * error message won't be shown, but the data doesn't get corrupted. */
++    atransport* known_emulator = find_emulator_transport_by_adb_port(adb_port);
++    if (known_emulator != NULL) {
++        snprintf(buffer, buffer_size,
++                "Emulator on port %d already registered.", adb_port);
++        return;
++    }
++
++    /* Check if more emulators can be registered. Similar unproblematic
++     * race condition as above. */
++    int candidate_slot = get_available_local_transport_index();
++    if (candidate_slot < 0) {
++        snprintf(buffer, buffer_size, "Cannot accept more emulators.");
++        return;
++    }
++
++    /* Preconditions met, try to connect to the emulator. */
++    if (!local_connect_arbitrary_ports(console_port, adb_port)) {
++        snprintf(buffer, buffer_size,
++                "Connected to emulator on ports %d,%d", console_port, adb_port);
++    } else {
++        snprintf(buffer, buffer_size,
++                "Could not connect to emulator on ports %d,%d",
++                console_port, adb_port);
++    }
++}
++#endif
++
++int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s)
++{
++    atransport *transport = NULL;
++    char buf[4096];
++
++    if(!strcmp(service, "kill")) {
++        fprintf(stderr,"adb server killed by remote request\n");
++        fflush(stdout);
++        adb_write(reply_fd, "OKAY", 4);
++        usb_cleanup();
++        exit(0);
++    }
++
++#if ADB_HOST
++    // "transport:" is used for switching transport with a specified serial number
++    // "transport-usb:" is used for switching transport to the only USB transport
++    // "transport-local:" is used for switching transport to the only local transport
++    // "transport-any:" is used for switching transport to the only transport
++    if (!strncmp(service, "transport", strlen("transport"))) {
++        char* error_string = "unknown failure";
++        transport_type type = kTransportAny;
++
++        if (!strncmp(service, "transport-usb", strlen("transport-usb"))) {
++            type = kTransportUsb;
++        } else if (!strncmp(service, "transport-local", strlen("transport-local"))) {
++            type = kTransportLocal;
++        } else if (!strncmp(service, "transport-any", strlen("transport-any"))) {
++            type = kTransportAny;
++        } else if (!strncmp(service, "transport:", strlen("transport:"))) {
++            service += strlen("transport:");
++            serial = service;
++        }
++
++        transport = acquire_one_transport(CS_ANY, type, serial, &error_string);
++
++        if (transport) {
++            s->transport = transport;
++            adb_write(reply_fd, "OKAY", 4);
++        } else {
++            sendfailmsg(reply_fd, error_string);
++        }
++        return 1;
++    }
++
++    // return a list of all connected devices
++    if (!strncmp(service, "devices", 7)) {
++        char buffer[4096];
++        int use_long = !strcmp(service+7, "-l");
++        if (use_long || service[7] == 0) {
++            memset(buf, 0, sizeof(buf));
++            memset(buffer, 0, sizeof(buffer));
++            D("Getting device list \n");
++            list_transports(buffer, sizeof(buffer), use_long);
++            snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer),buffer);
++            D("Wrote device list \n");
++            writex(reply_fd, buf, strlen(buf));
++            return 0;
++        }
++    }
++
++    // add a new TCP transport, device or emulator
++    if (!strncmp(service, "connect:", 8)) {
++        char buffer[4096];
++        char* host = service + 8;
++        if (!strncmp(host, "emu:", 4)) {
++            connect_emulator(host + 4, buffer, sizeof(buffer));
++        } else {
++            connect_device(host, buffer, sizeof(buffer));
++        }
++        // Send response for emulator and device
++        snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer), buffer);
++        writex(reply_fd, buf, strlen(buf));
++        return 0;
++    }
++
++    // remove TCP transport
++    if (!strncmp(service, "disconnect:", 11)) {
++        char buffer[4096];
++        memset(buffer, 0, sizeof(buffer));
++        char* serial = service + 11;
++        if (serial[0] == 0) {
++            // disconnect from all TCP devices
++            unregister_all_tcp_transports();
++        } else {
++            char hostbuf[100];
++            // assume port 5555 if no port is specified
++            if (!strchr(serial, ':')) {
++                snprintf(hostbuf, sizeof(hostbuf) - 1, "%s:5555", serial);
++                serial = hostbuf;
++            }
++            atransport *t = find_transport(serial);
++
++            if (t) {
++                unregister_transport(t);
++            } else {
++                snprintf(buffer, sizeof(buffer), "No such device %s", serial);
++            }
++        }
++
++        snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer), buffer);
++        writex(reply_fd, buf, strlen(buf));
++        return 0;
++    }
++
++    // returns our value for ADB_SERVER_VERSION
++    if (!strcmp(service, "version")) {
++        char version[12];
++        snprintf(version, sizeof version, "%04x", ADB_SERVER_VERSION);
++        snprintf(buf, sizeof buf, "OKAY%04x%s", (unsigned)strlen(version), version);
++        writex(reply_fd, buf, strlen(buf));
++        return 0;
++    }
++
++    if(!strncmp(service,"get-serialno",strlen("get-serialno"))) {
++        char *out = "unknown";
++         transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
++       if (transport && transport->serial) {
++            out = transport->serial;
++        }
++        snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(out),out);
++        writex(reply_fd, buf, strlen(buf));
++        return 0;
++    }
++    if(!strncmp(service,"get-devpath",strlen("get-devpath"))) {
++        char *out = "unknown";
++         transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
++       if (transport && transport->devpath) {
++            out = transport->devpath;
++        }
++        snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(out),out);
++        writex(reply_fd, buf, strlen(buf));
++        return 0;
++    }
++    // indicates a new emulator instance has started
++    if (!strncmp(service,"emulator:",9)) {
++        int  port = atoi(service+9);
++        local_connect(port);
++        /* we don't even need to send a reply */
++        return 0;
++    }
++#endif // ADB_HOST
++
++    if(!strcmp(service,"list-forward")) {
++        // Create the list of forward redirections.
++        char header[9];
++        int buffer_size = format_listeners(NULL, 0);
++        // Add one byte for the trailing zero.
++        char* buffer = malloc(buffer_size+1);
++        (void) format_listeners(buffer, buffer_size+1);
++        snprintf(header, sizeof header, "OKAY%04x", buffer_size);
++        writex(reply_fd, header, 8);
++        writex(reply_fd, buffer, buffer_size);
++        free(buffer);
++        return 0;
++    }
++
++    if (!strcmp(service,"killforward-all")) {
++        remove_all_listeners();
++        adb_write(reply_fd, "OKAYOKAY", 8);
++        return 0;
++    }
++
++    if(!strncmp(service,"forward:",8) ||
++       !strncmp(service,"killforward:",12)) {
++        char *local, *remote, *err;
++        int r;
++        atransport *transport;
++
++        int createForward = strncmp(service,"kill",4);
++        int no_rebind = 0;
++
++        local = strchr(service, ':') + 1;
++
++        // Handle forward:norebind:<local>... here
++        if (createForward && !strncmp(local, "norebind:", 9)) {
++            no_rebind = 1;
++            local = strchr(local, ':') + 1;
++        }
++
++        remote = strchr(local,';');
++
++        if (createForward) {
++            // Check forward: parameter format: '<local>;<remote>'
++            if(remote == 0) {
++                sendfailmsg(reply_fd, "malformed forward spec");
++                return 0;
++            }
++
++            *remote++ = 0;
++            if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')){
++                sendfailmsg(reply_fd, "malformed forward spec");
++                return 0;
++            }
++        } else {
++            // Check killforward: parameter format: '<local>'
++            if (local[0] == 0) {
++                sendfailmsg(reply_fd, "malformed forward spec");
++                return 0;
++            }
++        }
++
++        transport = acquire_one_transport(CS_ANY, ttype, serial, &err);
++        if (!transport) {
++            sendfailmsg(reply_fd, err);
++            return 0;
++        }
++
++        if (createForward) {
++            r = install_listener(local, remote, transport, no_rebind);
++        } else {
++            r = remove_listener(local, transport);
++        }
++        if(r == 0) {
++                /* 1st OKAY is connect, 2nd OKAY is status */
++            writex(reply_fd, "OKAYOKAY", 8);
++            return 0;
++        }
++
++        if (createForward) {
++            const char* message;
++            switch (r) {
++              case INSTALL_STATUS_CANNOT_BIND:
++                message = "cannot bind to socket";
++                break;
++              case INSTALL_STATUS_CANNOT_REBIND:
++                message = "cannot rebind existing socket";
++                break;
++              default:
++                message = "internal error";
++            }
++            sendfailmsg(reply_fd, message);
++        } else {
++            sendfailmsg(reply_fd, "cannot remove listener");
++        }
++        return 0;
++    }
++
++    if(!strncmp(service,"get-state",strlen("get-state"))) {
++        transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
++        char *state = connection_state_name(transport);
++        snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(state),state);
++        writex(reply_fd, buf, strlen(buf));
++        return 0;
++    }
++    return -1;
++}
++
++#if !ADB_HOST
++int recovery_mode = 0;
++#endif
++
++int main(int argc, char **argv)
++{
++#if ADB_HOST
++    adb_sysdeps_init();
++    adb_trace_init();
++    D("Handling commandline()\n");
++    return adb_commandline(argc - 1, argv + 1);
++#else
++    /* If adbd runs inside the emulator this will enable adb tracing via
++     * adb-debug qemud service in the emulator. */
++    adb_qemu_trace_init();
++    if((argc > 1) && (!strcmp(argv[1],"recovery"))) {
++        adb_device_banner = "recovery";
++        recovery_mode = 1;
++    }
++
++    start_device_log();
++    D("Handling main()\n");
++    return adb_main(0, DEFAULT_ADB_PORT);
++#endif
++}
+Index: android-tools-4.2.2+git20130218/core/adbd/adb.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/adb.h    2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,491 @@
++/*
++ * Copyright (C) 2007 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#ifndef __ADB_H
++#define __ADB_H
++
++#include <limits.h>
++
++#include "transport.h"  /* readx(), writex() */
++
++#define MAX_PAYLOAD 4096
++
++#define A_SYNC 0x434e5953
++#define A_CNXN 0x4e584e43
++#define A_OPEN 0x4e45504f
++#define A_OKAY 0x59414b4f
++#define A_CLSE 0x45534c43
++#define A_WRTE 0x45545257
++#define A_AUTH 0x48545541
++
++#define A_VERSION 0x01000000        // ADB protocol version
++
++#define ADB_VERSION_MAJOR 1         // Used for help/version information
++#define ADB_VERSION_MINOR 0         // Used for help/version information
++
++#define ADB_SERVER_VERSION    31    // Increment this when we want to force users to start a new adb server
++
++typedef struct amessage amessage;
++typedef struct apacket apacket;
++typedef struct asocket asocket;
++typedef struct alistener alistener;
++typedef struct aservice aservice;
++typedef struct atransport atransport;
++typedef struct adisconnect  adisconnect;
++typedef struct usb_handle usb_handle;
++
++struct amessage {
++    unsigned command;       /* command identifier constant      */
++    unsigned arg0;          /* first argument                   */
++    unsigned arg1;          /* second argument                  */
++    unsigned data_length;   /* length of payload (0 is allowed) */
++    unsigned data_check;    /* checksum of data payload         */
++    unsigned magic;         /* command ^ 0xffffffff             */
++};
++
++struct apacket
++{
++    apacket *next;
++
++    unsigned len;
++    unsigned char *ptr;
++
++    amessage msg;
++    unsigned char data[MAX_PAYLOAD];
++};
++
++/* An asocket represents one half of a connection between a local and
++** remote entity.  A local asocket is bound to a file descriptor.  A
++** remote asocket is bound to the protocol engine.
++*/
++struct asocket {
++        /* chain pointers for the local/remote list of
++        ** asockets that this asocket lives in
++        */
++    asocket *next;
++    asocket *prev;
++
++        /* the unique identifier for this asocket
++        */
++    unsigned id;
++
++        /* flag: set when the socket's peer has closed
++        ** but packets are still queued for delivery
++        */
++    int    closing;
++
++        /* flag: quit adbd when both ends close the
++        ** local service socket
++        */
++    int    exit_on_close;
++
++        /* the asocket we are connected to
++        */
++
++    asocket *peer;
++
++        /* For local asockets, the fde is used to bind
++        ** us to our fd event system.  For remote asockets
++        ** these fields are not used.
++        */
++    fdevent fde;
++    int fd;
++
++        /* queue of apackets waiting to be written
++        */
++    apacket *pkt_first;
++    apacket *pkt_last;
++
++        /* enqueue is called by our peer when it has data
++        ** for us.  It should return 0 if we can accept more
++        ** data or 1 if not.  If we return 1, we must call
++        ** peer->ready() when we once again are ready to
++        ** receive data.
++        */
++    int (*enqueue)(asocket *s, apacket *pkt);
++
++        /* ready is called by the peer when it is ready for
++        ** us to send data via enqueue again
++        */
++    void (*ready)(asocket *s);
++
++        /* close is called by the peer when it has gone away.
++        ** we are not allowed to make any further calls on the
++        ** peer once our close method is called.
++        */
++    void (*close)(asocket *s);
++
++        /* socket-type-specific extradata */
++    void *extra;
++
++      /* A socket is bound to atransport */
++    atransport *transport;
++};
++
++
++/* the adisconnect structure is used to record a callback that
++** will be called whenever a transport is disconnected (e.g. by the user)
++** this should be used to cleanup objects that depend on the
++** transport (e.g. remote sockets, listeners, etc...)
++*/
++struct  adisconnect
++{
++    void        (*func)(void*  opaque, atransport*  t);
++    void*         opaque;
++    adisconnect*  next;
++    adisconnect*  prev;
++};
++
++
++/* a transport object models the connection to a remote device or emulator
++** there is one transport per connected device/emulator. a "local transport"
++** connects through TCP (for the emulator), while a "usb transport" through
++** USB (for real devices)
++**
++** note that kTransportHost doesn't really correspond to a real transport
++** object, it's a special value used to indicate that a client wants to
++** connect to a service implemented within the ADB server itself.
++*/
++typedef enum transport_type {
++        kTransportUsb,
++        kTransportLocal,
++        kTransportAny,
++        kTransportHost,
++} transport_type;
++
++#define TOKEN_SIZE 20
++
++struct atransport
++{
++    atransport *next;
++    atransport *prev;
++
++    int (*read_from_remote)(apacket *p, atransport *t);
++    int (*write_to_remote)(apacket *p, atransport *t);
++    void (*close)(atransport *t);
++    void (*kick)(atransport *t);
++
++    int fd;
++    int transport_socket;
++    fdevent transport_fde;
++    int ref_count;
++    unsigned sync_token;
++    int connection_state;
++    int online;
++    transport_type type;
++
++        /* usb handle or socket fd as needed */
++    usb_handle *usb;
++    int sfd;
++
++        /* used to identify transports for clients */
++    char *serial;
++    char *product;
++    char *model;
++    char *device;
++    char *devpath;
++    int adb_port; // Use for emulators (local transport)
++
++        /* a list of adisconnect callbacks called when the transport is kicked */
++    int          kicked;
++    adisconnect  disconnects;
++
++    void *key;
++    unsigned char token[TOKEN_SIZE];
++    fdevent auth_fde;
++    unsigned failed_auth_attempts;
++};
++
++
++/* A listener is an entity which binds to a local port
++** and, upon receiving a connection on that port, creates
++** an asocket to connect the new local connection to a
++** specific remote service.
++**
++** TODO: some listeners read from the new connection to
++** determine what exact service to connect to on the far
++** side.
++*/
++struct alistener
++{
++    alistener *next;
++    alistener *prev;
++
++    fdevent fde;
++    int fd;
++
++    const char *local_name;
++    const char *connect_to;
++    atransport *transport;
++    adisconnect  disconnect;
++};
++
++
++void print_packet(const char *label, apacket *p);
++
++asocket *find_local_socket(unsigned id);
++void install_local_socket(asocket *s);
++void remove_socket(asocket *s);
++void close_all_sockets(atransport *t);
++
++#define  LOCAL_CLIENT_PREFIX  "emulator-"
++
++asocket *create_local_socket(int fd);
++asocket *create_local_service_socket(const char *destination);
++
++asocket *create_remote_socket(unsigned id, atransport *t);
++void connect_to_remote(asocket *s, const char *destination);
++void connect_to_smartsocket(asocket *s);
++
++void fatal(const char *fmt, ...);
++void fatal_errno(const char *fmt, ...);
++
++void handle_packet(apacket *p, atransport *t);
++void send_packet(apacket *p, atransport *t);
++
++void get_my_path(char *s, size_t maxLen);
++int launch_server(int server_port);
++int adb_main(int is_daemon, int server_port);
++
++
++/* transports are ref-counted
++** get_device_transport does an acquire on your behalf before returning
++*/
++void init_transport_registration(void);
++int  list_transports(char *buf, size_t  bufsize, int long_listing);
++void update_transports(void);
++
++asocket*  create_device_tracker(void);
++
++/* Obtain a transport from the available transports.
++** If state is != CS_ANY, only transports in that state are considered.
++** If serial is non-NULL then only the device with that serial will be chosen.
++** If no suitable transport is found, error is set.
++*/
++atransport *acquire_one_transport(int state, transport_type ttype, const char* serial, char **error_out);
++void   add_transport_disconnect( atransport*  t, adisconnect*  dis );
++void   remove_transport_disconnect( atransport*  t, adisconnect*  dis );
++void   run_transport_disconnects( atransport*  t );
++void   kick_transport( atransport*  t );
++
++/* initialize a transport object's func pointers and state */
++#if ADB_HOST
++int get_available_local_transport_index();
++#endif
++int  init_socket_transport(atransport *t, int s, int port, int local);
++void init_usb_transport(atransport *t, usb_handle *usb, int state);
++
++/* for MacOS X cleanup */
++void close_usb_devices();
++
++/* cause new transports to be init'd and added to the list */
++void register_socket_transport(int s, const char *serial, int port, int local);
++
++/* these should only be used for the "adb disconnect" command */
++void unregister_transport(atransport *t);
++void unregister_all_tcp_transports();
++
++void register_usb_transport(usb_handle *h, const char *serial, const char *devpath, unsigned writeable);
++
++/* this should only be used for transports with connection_state == CS_NOPERM */
++void unregister_usb_transport(usb_handle *usb);
++
++atransport *find_transport(const char *serial);
++#if ADB_HOST
++atransport* find_emulator_transport_by_adb_port(int adb_port);
++#endif
++
++int service_to_fd(const char *name);
++#if ADB_HOST
++asocket *host_service_to_socket(const char*  name, const char *serial);
++#endif
++
++#if !ADB_HOST
++int       init_jdwp(void);
++asocket*  create_jdwp_service_socket();
++asocket*  create_jdwp_tracker_service_socket();
++int       create_jdwp_connection_fd(int  jdwp_pid);
++#endif
++
++#if !ADB_HOST
++typedef enum {
++    BACKUP,
++    RESTORE
++} BackupOperation;
++int backup_service(BackupOperation operation, char* args);
++void framebuffer_service(int fd, void *cookie);
++void log_service(int fd, void *cookie);
++void remount_service(int fd, void *cookie);
++char * get_log_file_path(const char * log_name);
++#endif
++
++/* packet allocator */
++apacket *get_apacket(void);
++void put_apacket(apacket *p);
++
++int check_header(apacket *p);
++int check_data(apacket *p);
++
++/* define ADB_TRACE to 1 to enable tracing support, or 0 to disable it */
++
++#define  ADB_TRACE    1
++
++/* IMPORTANT: if you change the following list, don't
++ * forget to update the corresponding 'tags' table in
++ * the adb_trace_init() function implemented in adb.c
++ */
++typedef enum {
++    TRACE_ADB = 0,   /* 0x001 */
++    TRACE_SOCKETS,
++    TRACE_PACKETS,
++    TRACE_TRANSPORT,
++    TRACE_RWX,       /* 0x010 */
++    TRACE_USB,
++    TRACE_SYNC,
++    TRACE_SYSDEPS,
++    TRACE_JDWP,      /* 0x100 */
++    TRACE_SERVICES,
++    TRACE_AUTH,
++} AdbTrace;
++
++#if ADB_TRACE
++
++#if !ADB_HOST
++/*
++ * When running inside the emulator, guest's adbd can connect to 'adb-debug'
++ * qemud service that can display adb trace messages (on condition that emulator
++ * has been started with '-debug adb' option).
++ */
++
++/* Delivers a trace message to the emulator via QEMU pipe. */
++void adb_qemu_trace(const char* fmt, ...);
++/* Macro to use to send ADB trace messages to the emulator. */
++#define DQ(...)    adb_qemu_trace(__VA_ARGS__)
++#else
++#define DQ(...) ((void)0)
++#endif  /* !ADB_HOST */
++
++  extern int     adb_trace_mask;
++  extern unsigned char    adb_trace_output_count;
++  void    adb_trace_init(void);
++
++#  define ADB_TRACING  ((adb_trace_mask & (1 << TRACE_TAG)) != 0)
++
++  /* you must define TRACE_TAG before using this macro */
++#  define  D(...)                                      \
++        do {                                           \
++            if (ADB_TRACING) {                         \
++                int save_errno = errno;                \
++                adb_mutex_lock(&D_lock);               \
++                fprintf(stderr, "%s::%s():",           \
++                        __FILE__, __FUNCTION__);       \
++                errno = save_errno;                    \
++                fprintf(stderr, __VA_ARGS__ );         \
++                fflush(stderr);                        \
++                adb_mutex_unlock(&D_lock);             \
++                errno = save_errno;                    \
++           }                                           \
++        } while (0)
++#  define  DR(...)                                     \
++        do {                                           \
++            if (ADB_TRACING) {                         \
++                int save_errno = errno;                \
++                adb_mutex_lock(&D_lock);               \
++                errno = save_errno;                    \
++                fprintf(stderr, __VA_ARGS__ );         \
++                fflush(stderr);                        \
++                adb_mutex_unlock(&D_lock);             \
++                errno = save_errno;                    \
++           }                                           \
++        } while (0)
++#else
++#  define  D(...)          ((void)0)
++#  define  DR(...)         ((void)0)
++#  define  ADB_TRACING     0
++#endif
++
++
++#if !DEBUG_PACKETS
++#define print_packet(tag,p) do {} while (0)
++#endif
++
++#if ADB_HOST_ON_TARGET
++/* adb and adbd are coexisting on the target, so use 5038 for adb
++ * to avoid conflicting with adbd's usage of 5037
++ */
++#  define DEFAULT_ADB_PORT 5038
++#else
++#  define DEFAULT_ADB_PORT 5037
++#endif
++
++#define DEFAULT_ADB_LOCAL_TRANSPORT_PORT 5555
++
++#define ADB_CLASS              0xff
++#define ADB_SUBCLASS           0x42
++#define ADB_PROTOCOL           0x1
++
++
++void local_init(int port);
++int  local_connect(int  port);
++int  local_connect_arbitrary_ports(int console_port, int adb_port);
++
++/* usb host/client interface */
++void usb_init();
++void usb_cleanup();
++int usb_write(usb_handle *h, const void *data, int len);
++int usb_read(usb_handle *h, void *data, int len);
++int usb_close(usb_handle *h);
++void usb_kick(usb_handle *h);
++
++/* used for USB device detection */
++#if ADB_HOST
++int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol);
++#endif
++
++unsigned host_to_le32(unsigned n);
++int adb_commandline(int argc, char **argv);
++
++int connection_state(atransport *t);
++
++#define CS_ANY       -1
++#define CS_OFFLINE    0
++#define CS_BOOTLOADER 1
++#define CS_DEVICE     2
++#define CS_HOST       3
++#define CS_RECOVERY   4
++#define CS_NOPERM     5 /* Insufficient permissions to communicate with the device */
++#define CS_SIDELOAD   6
++
++extern int HOST;
++extern int SHELL_EXIT_NOTIFY_FD;
++
++#define CHUNK_SIZE (64*1024)
++
++#if !ADB_HOST
++#define USB_ADB_PATH     "/dev/android_adb"
++
++#define USB_FFS_ADB_PATH  "/dev/usb-ffs/adb/"
++#define USB_FFS_ADB_EP(x) USB_FFS_ADB_PATH#x
++
++#define USB_FFS_ADB_EP0   USB_FFS_ADB_EP(ep0)
++#define USB_FFS_ADB_OUT   USB_FFS_ADB_EP(ep1)
++#define USB_FFS_ADB_IN    USB_FFS_ADB_EP(ep2)
++#endif
++
++int sendfailmsg(int fd, const char *reason);
++int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s);
++
++#endif
+Index: android-tools-4.2.2+git20130218/core/adbd/adb_auth.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/adb_auth.h       2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,54 @@
++/*
++ * Copyright (C) 2012 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#ifndef __ADB_AUTH_H
++#define __ADB_AUTH_H
++
++void adb_auth_init(void);
++void adb_auth_verified(atransport *t);
++
++/* AUTH packets first argument */
++/* Request */
++#define ADB_AUTH_TOKEN         1
++/* Response */
++#define ADB_AUTH_SIGNATURE     2
++#define ADB_AUTH_RSAPUBLICKEY  3
++
++#if ADB_HOST
++
++int adb_auth_sign(void *key, void *token, size_t token_size, void *sig);
++void *adb_auth_nextkey(void *current);
++int adb_auth_get_userkey(unsigned char *data, size_t len);
++
++static inline int adb_auth_generate_token(void *token, size_t token_size) { return 0; }
++static inline int adb_auth_verify(void *token, void *sig, int siglen) { return 0; }
++static inline void adb_auth_confirm_key(unsigned char *data, size_t len, atransport *t) { }
++static inline void adb_auth_reload_keys(void) { }
++
++#else // !ADB_HOST
++
++static inline int adb_auth_sign(void* key, void *token, size_t token_size, void *sig) { return 0; }
++static inline void *adb_auth_nextkey(void *current) { return NULL; }
++static inline int adb_auth_get_userkey(unsigned char *data, size_t len) { return 0; }
++
++int adb_auth_generate_token(void *token, size_t token_size);
++int adb_auth_verify(void *token, void *sig, int siglen);
++void adb_auth_confirm_key(unsigned char *data, size_t len, atransport *t);
++void adb_auth_reload_keys(void);
++
++#endif // ADB_HOST
++
++#endif // __ADB_AUTH_H
+Index: android-tools-4.2.2+git20130218/core/adbd/adb_auth_client.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/adb_auth_client.c        2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,245 @@
++/*
++ * Copyright (C) 2012 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include <stdio.h>
++#include <string.h>
++#include <resolv.h>
++#include <cutils/list.h>
++#include <cutils/sockets.h>
++
++#include "sysdeps.h"
++#include "adb.h"
++#include "adb_auth.h"
++#include "fdevent.h"
++#include "mincrypt/rsa.h"
++
++#define TRACE_TAG TRACE_AUTH
++
++
++struct adb_public_key {
++    struct listnode node;
++    RSAPublicKey key;
++};
++
++static struct listnode key_list;
++
++static char *key_paths[] = {
++    "/adb_keys",
++    "/data/misc/adb/adb_keys",
++    NULL
++};
++
++static fdevent listener_fde;
++static int framework_fd = -1;
++
++
++static void read_keys(const char *file, struct listnode *list)
++{
++    struct adb_public_key *key;
++    FILE *f;
++    char buf[MAX_PAYLOAD];
++    char *sep;
++    int ret;
++
++    f = fopen(file, "r");
++    if (!f) {
++        D("Can't open '%s'\n", file);
++        return;
++    }
++
++    while (fgets(buf, sizeof(buf), f)) {
++        /* Allocate 4 extra bytes to decode the base64 data in-place */
++        key = calloc(1, sizeof(*key) + 4);
++        if (!key) {
++            D("Can't malloc key\n");
++            break;
++        }
++
++        sep = strpbrk(buf, " \t");
++        if (sep)
++            *sep = '\0';
++
++        ret = __b64_pton(buf, (u_char *)&key->key, sizeof(key->key) + 4);
++        if (ret != sizeof(key->key)) {
++            D("%s: Invalid base64 data ret=%d\n", file, ret);
++            free(key);
++            continue;
++        }
++
++        if (key->key.len != RSANUMWORDS) {
++            D("%s: Invalid key len %d\n", file, key->key.len);
++            free(key);
++            continue;
++        }
++
++        list_add_tail(list, &key->node);
++    }
++
++    fclose(f);
++}
++
++static void free_keys(struct listnode *list)
++{
++    struct listnode *item;
++
++    while (!list_empty(list)) {
++        item = list_head(list);
++        list_remove(item);
++        free(node_to_item(item, struct adb_public_key, node));
++    }
++}
++
++void adb_auth_reload_keys(void)
++{
++    char *path;
++    char **paths = key_paths;
++    struct stat buf;
++
++    free_keys(&key_list);
++
++    while ((path = *paths++)) {
++        if (!stat(path, &buf)) {
++            D("Loading keys from '%s'\n", path);
++            read_keys(path, &key_list);
++        }
++    }
++}
++
++int adb_auth_generate_token(void *token, size_t token_size)
++{
++    FILE *f;
++    int ret;
++
++    f = fopen("/dev/urandom", "r");
++    if (!f)
++        return 0;
++
++    ret = fread(token, token_size, 1, f);
++
++    fclose(f);
++    return ret * token_size;
++}
++
++int adb_auth_verify(void *token, void *sig, int siglen)
++{
++    struct listnode *item;
++    struct adb_public_key *key;
++    int ret;
++
++    if (siglen != RSANUMBYTES)
++        return 0;
++
++    list_for_each(item, &key_list) {
++        key = node_to_item(item, struct adb_public_key, node);
++        ret = RSA_verify(&key->key, sig, siglen, token);
++        if (ret)
++            return 1;
++    }
++
++    return 0;
++}
++
++static void adb_auth_event(int fd, unsigned events, void *data)
++{
++    atransport *t = data;
++    char response[2];
++    int ret;
++
++    if (events & FDE_READ) {
++        ret = unix_read(fd, response, sizeof(response));
++        if (ret < 0) {
++            D("Disconnect");
++            fdevent_remove(&t->auth_fde);
++            framework_fd = -1;
++        }
++        else if (ret == 2 && response[0] == 'O' && response[1] == 'K') {
++            adb_auth_reload_keys();
++            adb_auth_verified(t);
++        }
++    }
++}
++
++void adb_auth_confirm_key(unsigned char *key, size_t len, atransport *t)
++{
++    char msg[MAX_PAYLOAD];
++    int ret;
++
++    if (framework_fd < 0) {
++        D("Client not connected\n");
++        return;
++    }
++
++    if (key[len - 1] != '\0') {
++        D("Key must be a null-terminated string\n");
++        return;
++    }
++
++    ret = snprintf(msg, sizeof(msg), "PK%s", key);
++    if (ret >= (signed)sizeof(msg)) {
++        D("Key too long. ret=%d", ret);
++        return;
++    }
++    D("Sending '%s'\n", msg);
++
++    ret = unix_write(framework_fd, msg, ret);
++    if (ret < 0) {
++        D("Failed to write PK, errno=%d\n", errno);
++        return;
++    }
++
++    fdevent_install(&t->auth_fde, framework_fd, adb_auth_event, t);
++    fdevent_add(&t->auth_fde, FDE_READ);
++}
++
++static void adb_auth_listener(int fd, unsigned events, void *data)
++{
++    struct sockaddr addr;
++    socklen_t alen;
++    int s;
++
++    alen = sizeof(addr);
++
++    s = adb_socket_accept(fd, &addr, &alen);
++    if (s < 0) {
++        D("Failed to accept: errno=%d\n", errno);
++        return;
++    }
++
++    framework_fd = s;
++}
++
++void adb_auth_init(void)
++{
++    int fd, ret;
++
++    list_init(&key_list);
++    adb_auth_reload_keys();
++
++    fd = android_get_control_socket("adbd");
++    if (fd < 0) {
++        D("Failed to get adbd socket\n");
++        return;
++    }
++
++    ret = listen(fd, 4);
++    if (ret < 0) {
++        D("Failed to listen on '%d'\n", fd);
++        return;
++    }
++
++    fdevent_install(&listener_fde, fd, adb_auth_listener, NULL);
++    fdevent_add(&listener_fde, FDE_READ);
++}
+Index: android-tools-4.2.2+git20130218/core/adbd/adb_auth_host.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/adb_auth_host.c  2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,426 @@
++/*
++ * Copyright (C) 2012 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include <stdio.h>
++
++#ifdef _WIN32
++#  define WIN32_LEAN_AND_MEAN
++#  include "windows.h"
++#  include "shlobj.h"
++#else
++#  include <sys/types.h>
++#  include <sys/stat.h>
++#  include <unistd.h>
++#endif
++#include <string.h>
++
++#include "sysdeps.h"
++#include "adb.h"
++#include "adb_auth.h"
++
++/* HACK: we need the RSAPublicKey struct
++ * but RSA_verify conflits with openssl */
++#define RSA_verify RSA_verify_mincrypt
++#include "mincrypt/rsa.h"
++#undef RSA_verify
++
++#include <cutils/list.h>
++
++#include <openssl/evp.h>
++#include <openssl/objects.h>
++#include <openssl/pem.h>
++#include <openssl/rsa.h>
++#include <openssl/sha.h>
++
++#define TRACE_TAG TRACE_AUTH
++
++#define ANDROID_PATH   ".android"
++#define ADB_KEY_FILE   "adbkey"
++
++
++struct adb_private_key {
++    struct listnode node;
++    RSA *rsa;
++};
++
++static struct listnode key_list;
++
++
++/* Convert OpenSSL RSA private key to android pre-computed RSAPublicKey format */
++static int RSA_to_RSAPublicKey(RSA *rsa, RSAPublicKey *pkey)
++{
++    int ret = 1;
++    unsigned int i;
++
++    BN_CTX* ctx = BN_CTX_new();
++    BIGNUM* r32 = BN_new();
++    BIGNUM* rr = BN_new();
++    BIGNUM* r = BN_new();
++    BIGNUM* rem = BN_new();
++    BIGNUM* n = BN_new();
++    BIGNUM* n0inv = BN_new();
++
++    if (RSA_size(rsa) != RSANUMBYTES) {
++        ret = 0;
++        goto out;
++    }
++
++    BN_set_bit(r32, 32);
++    BN_copy(n, rsa->n);
++    BN_set_bit(r, RSANUMWORDS * 32);
++    BN_mod_sqr(rr, r, n, ctx);
++    BN_div(NULL, rem, n, r32, ctx);
++    BN_mod_inverse(n0inv, rem, r32, ctx);
++
++    pkey->len = RSANUMWORDS;
++    pkey->n0inv = 0 - BN_get_word(n0inv);
++    for (i = 0; i < RSANUMWORDS; i++) {
++        BN_div(rr, rem, rr, r32, ctx);
++        pkey->rr[i] = BN_get_word(rem);
++        BN_div(n, rem, n, r32, ctx);
++        pkey->n[i] = BN_get_word(rem);
++    }
++    pkey->exponent = BN_get_word(rsa->e);
++
++out:
++    BN_free(n0inv);
++    BN_free(n);
++    BN_free(rem);
++    BN_free(r);
++    BN_free(rr);
++    BN_free(r32);
++    BN_CTX_free(ctx);
++
++    return ret;
++}
++
++static void get_user_info(char *buf, size_t len)
++{
++    char hostname[1024], username[1024];
++    int ret;
++
++#ifndef _WIN32
++    ret = gethostname(hostname, sizeof(hostname));
++    if (ret < 0)
++#endif
++        strcpy(hostname, "unknown");
++
++#if !defined _WIN32 && !defined ADB_HOST_ON_TARGET
++    ret = getlogin_r(username, sizeof(username));
++    if (ret < 0)
++#endif
++        strcpy(username, "unknown");
++
++    ret = snprintf(buf, len, " %s@%s", username, hostname);
++    if (ret >= (signed)len)
++        buf[len - 1] = '\0';
++}
++
++static int write_public_keyfile(RSA *private_key, const char *private_key_path)
++{
++    RSAPublicKey pkey;
++    BIO *bio, *b64, *bfile;
++    char path[PATH_MAX], info[MAX_PAYLOAD];
++    int ret;
++
++    ret = snprintf(path, sizeof(path), "%s.pub", private_key_path);
++    if (ret >= (signed)sizeof(path))
++        return 0;
++
++    ret = RSA_to_RSAPublicKey(private_key, &pkey);
++    if (!ret) {
++        D("Failed to convert to publickey\n");
++        return 0;
++    }
++
++    bfile = BIO_new_file(path, "w");
++    if (!bfile) {
++        D("Failed to open '%s'\n", path);
++        return 0;
++    }
++
++    D("Writing public key to '%s'\n", path);
++
++    b64 = BIO_new(BIO_f_base64());
++    BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
++
++    bio = BIO_push(b64, bfile);
++    BIO_write(bio, &pkey, sizeof(pkey));
++    BIO_flush(bio);
++    BIO_pop(b64);
++    BIO_free(b64);
++
++    get_user_info(info, sizeof(info));
++    BIO_write(bfile, info, strlen(info));
++    BIO_flush(bfile);
++    BIO_free_all(bfile);
++
++    return 1;
++}
++
++static int generate_key(const char *file)
++{
++    EVP_PKEY* pkey = EVP_PKEY_new();
++    BIGNUM* exponent = BN_new();
++    RSA* rsa = RSA_new();
++    mode_t old_mask;
++    FILE *f = NULL;
++    int ret = 0;
++
++    D("generate_key '%s'\n", file);
++
++    if (!pkey || !exponent || !rsa) {
++        D("Failed to allocate key\n");
++        goto out;
++    }
++
++    BN_set_word(exponent, RSA_F4);
++    RSA_generate_key_ex(rsa, 2048, exponent, NULL);
++    EVP_PKEY_set1_RSA(pkey, rsa);
++
++    old_mask = umask(077);
++
++    f = fopen(file, "w");
++    if (!f) {
++        D("Failed to open '%s'\n", file);
++        umask(old_mask);
++        goto out;
++    }
++
++    umask(old_mask);
++
++    if (!PEM_write_PrivateKey(f, pkey, NULL, NULL, 0, NULL, NULL)) {
++        D("Failed to write key\n");
++        goto out;
++    }
++
++    if (!write_public_keyfile(rsa, file)) {
++        D("Failed to write public key\n");
++        goto out;
++    }
++
++    ret = 1;
++
++out:
++    if (f)
++        fclose(f);
++    EVP_PKEY_free(pkey);
++    RSA_free(rsa);
++    BN_free(exponent);
++    return ret;
++}
++
++static int read_key(const char *file, struct listnode *list)
++{
++    struct adb_private_key *key;
++    FILE *f;
++
++    D("read_key '%s'\n", file);
++
++    f = fopen(file, "r");
++    if (!f) {
++        D("Failed to open '%s'\n", file);
++        return 0;
++    }
++
++    key = malloc(sizeof(*key));
++    if (!key) {
++        D("Failed to alloc key\n");
++        fclose(f);
++        return 0;
++    }
++    key->rsa = RSA_new();
++
++    if (!PEM_read_RSAPrivateKey(f, &key->rsa, NULL, NULL)) {
++        D("Failed to read key\n");
++        fclose(f);
++        RSA_free(key->rsa);
++        free(key);
++        return 0;
++    }
++
++    fclose(f);
++    list_add_tail(list, &key->node);
++    return 1;
++}
++
++static int get_user_keyfilepath(char *filename, size_t len)
++{
++    const char *format, *home;
++    char android_dir[PATH_MAX];
++    struct stat buf;
++#ifdef _WIN32
++    char path[PATH_MAX];
++    home = getenv("ANDROID_SDK_HOME");
++    if (!home) {
++        SHGetFolderPath(NULL, CSIDL_PROFILE, NULL, 0, path);
++        home = path;
++    }
++    format = "%s\\%s";
++#else
++    home = getenv("HOME");
++    if (!home)
++        return -1;
++    format = "%s/%s";
++#endif
++
++    D("home '%s'\n", home);
++
++    if (snprintf(android_dir, sizeof(android_dir), format, home,
++                        ANDROID_PATH) >= (int)sizeof(android_dir))
++        return -1;
++
++    if (stat(android_dir, &buf)) {
++        if (adb_mkdir(android_dir, 0750) < 0) {
++            D("Cannot mkdir '%s'", android_dir);
++            return -1;
++        }
++    }
++
++    return snprintf(filename, len, format, android_dir, ADB_KEY_FILE);
++}
++
++static int get_user_key(struct listnode *list)
++{
++    struct stat buf;
++    char path[PATH_MAX];
++    int ret;
++
++    ret = get_user_keyfilepath(path, sizeof(path));
++    if (ret < 0 || ret >= (signed)sizeof(path)) {
++        D("Error getting user key filename");
++        return 0;
++    }
++
++    D("user key '%s'\n", path);
++
++    if (stat(path, &buf) == -1) {
++        if (!generate_key(path)) {
++            D("Failed to generate new key\n");
++            return 0;
++        }
++    }
++
++    return read_key(path, list);
++}
++
++static void get_vendor_keys(struct listnode *list)
++{
++    const char *adb_keys_path;
++    char keys_path[MAX_PAYLOAD];
++    char *path;
++    char *save;
++    struct stat buf;
++
++    adb_keys_path = getenv("ADB_VENDOR_KEYS");
++    if (!adb_keys_path)
++        return;
++    strncpy(keys_path, adb_keys_path, sizeof(keys_path));
++
++    path = adb_strtok_r(keys_path, ENV_PATH_SEPARATOR_STR, &save);
++    while (path) {
++        D("Reading: '%s'\n", path);
++
++        if (stat(path, &buf))
++            D("Can't read '%s'\n", path);
++        else if (!read_key(path, list))
++            D("Failed to read '%s'\n", path);
++
++        path = adb_strtok_r(NULL, ENV_PATH_SEPARATOR_STR, &save);
++    }
++}
++
++int adb_auth_sign(void *node, void *token, size_t token_size, void *sig)
++{
++    unsigned int len;
++    struct adb_private_key *key = node_to_item(node, struct adb_private_key, node);
++
++    if (!RSA_sign(NID_sha1, token, token_size, sig, &len, key->rsa)) {
++        return 0;
++    }
++
++    D("adb_auth_sign len=%d\n", len);
++    return (int)len;
++}
++
++void *adb_auth_nextkey(void *current)
++{
++    struct listnode *item;
++
++    if (list_empty(&key_list))
++        return NULL;
++
++    if (!current)
++        return list_head(&key_list);
++
++    list_for_each(item, &key_list) {
++        if (item == current) {
++            /* current is the last item, we tried all the keys */
++            if (item->next == &key_list)
++                return NULL;
++            return item->next;
++        }
++    }
++
++    return NULL;
++}
++
++int adb_auth_get_userkey(unsigned char *data, size_t len)
++{
++    char path[PATH_MAX];
++    char *file;
++    int ret;
++
++    ret = get_user_keyfilepath(path, sizeof(path) - 4);
++    if (ret < 0 || ret >= (signed)(sizeof(path) - 4)) {
++        D("Error getting user key filename");
++        return 0;
++    }
++    strcat(path, ".pub");
++
++    file = load_file(path, (unsigned*)&ret);
++    if (!file) {
++        D("Can't load '%s'\n", path);
++        return 0;
++    }
++
++    if (len < (size_t)(ret + 1)) {
++        D("%s: Content too large ret=%d\n", path, ret);
++        return 0;
++    }
++
++    memcpy(data, file, ret);
++    data[ret] = '\0';
++
++    return ret + 1;
++}
++
++void adb_auth_init(void)
++{
++    int ret;
++
++    D("adb_auth_init\n");
++
++    list_init(&key_list);
++
++    ret = get_user_key(&key_list);
++    if (!ret) {
++        D("Failed to get user key\n");
++        return;
++    }
++
++    get_vendor_keys(&key_list);
++}
+Index: android-tools-4.2.2+git20130218/core/adbd/adb_client.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/adb_client.c     2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,340 @@
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <errno.h>
++#include <limits.h>
++#include <stdarg.h>
++#include <zipfile/zipfile.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++
++#include "sysdeps.h"
++
++#define  TRACE_TAG  TRACE_ADB
++#include "adb_client.h"
++
++static transport_type __adb_transport = kTransportAny;
++static const char* __adb_serial = NULL;
++
++static int __adb_server_port = DEFAULT_ADB_PORT;
++static const char* __adb_server_name = NULL;
++
++void adb_set_transport(transport_type type, const char* serial)
++{
++    __adb_transport = type;
++    __adb_serial = serial;
++}
++
++void adb_set_tcp_specifics(int server_port)
++{
++    __adb_server_port = server_port;
++}
++
++void adb_set_tcp_name(const char* hostname)
++{
++    __adb_server_name = hostname;
++}
++
++int  adb_get_emulator_console_port(void)
++{
++    const char*   serial = __adb_serial;
++    int           port;
++
++    if (serial == NULL) {
++        /* if no specific device was specified, we need to look at */
++        /* the list of connected devices, and extract an emulator  */
++        /* name from it. two emulators is an error                 */
++        char*  tmp = adb_query("host:devices");
++        char*  p   = tmp;
++        if(!tmp) {
++            printf("no emulator connected\n");
++            return -1;
++        }
++        while (*p) {
++            char*  q = strchr(p, '\n');
++            if (q != NULL)
++                *q++ = 0;
++            else
++                q = p + strlen(p);
++
++            if (!memcmp(p, LOCAL_CLIENT_PREFIX, sizeof(LOCAL_CLIENT_PREFIX)-1)) {
++                if (serial != NULL) {  /* more than one emulator listed */
++                    free(tmp);
++                    return -2;
++                }
++                serial = p;
++            }
++
++            p = q;
++        }
++        free(tmp);
++
++        if (serial == NULL)
++            return -1;  /* no emulator found */
++    }
++    else {
++        if (memcmp(serial, LOCAL_CLIENT_PREFIX, sizeof(LOCAL_CLIENT_PREFIX)-1) != 0)
++            return -1;  /* not an emulator */
++    }
++
++    serial += sizeof(LOCAL_CLIENT_PREFIX)-1;
++    port    = strtol(serial, NULL, 10);
++    return port;
++}
++
++static char __adb_error[256] = { 0 };
++
++const char *adb_error(void)
++{
++    return __adb_error;
++}
++
++static int switch_socket_transport(int fd)
++{
++    char service[64];
++    char tmp[5];
++    int len;
++
++    if (__adb_serial)
++        snprintf(service, sizeof service, "host:transport:%s", __adb_serial);
++    else {
++        char* transport_type = "???";
++
++         switch (__adb_transport) {
++            case kTransportUsb:
++                transport_type = "transport-usb";
++                break;
++            case kTransportLocal:
++                transport_type = "transport-local";
++                break;
++            case kTransportAny:
++                transport_type = "transport-any";
++                break;
++            case kTransportHost:
++                // no switch necessary
++                return 0;
++                break;
++        }
++
++        snprintf(service, sizeof service, "host:%s", transport_type);
++    }
++    len = strlen(service);
++    snprintf(tmp, sizeof tmp, "%04x", len);
++
++    if(writex(fd, tmp, 4) || writex(fd, service, len)) {
++        strcpy(__adb_error, "write failure during connection");
++        adb_close(fd);
++        return -1;
++    }
++    D("Switch transport in progress\n");
++
++    if(adb_status(fd)) {
++        adb_close(fd);
++        D("Switch transport failed\n");
++        return -1;
++    }
++    D("Switch transport success\n");
++    return 0;
++}
++
++int adb_status(int fd)
++{
++    unsigned char buf[5];
++    unsigned len;
++
++    if(readx(fd, buf, 4)) {
++        strcpy(__adb_error, "protocol fault (no status)");
++        return -1;
++    }
++
++    if(!memcmp(buf, "OKAY", 4)) {
++        return 0;
++    }
++
++    if(memcmp(buf, "FAIL", 4)) {
++        sprintf(__adb_error,
++                "protocol fault (status %02x %02x %02x %02x?!)",
++                buf[0], buf[1], buf[2], buf[3]);
++        return -1;
++    }
++
++    if(readx(fd, buf, 4)) {
++        strcpy(__adb_error, "protocol fault (status len)");
++        return -1;
++    }
++    buf[4] = 0;
++    len = strtoul((char*)buf, 0, 16);
++    if(len > 255) len = 255;
++    if(readx(fd, __adb_error, len)) {
++        strcpy(__adb_error, "protocol fault (status read)");
++        return -1;
++    }
++    __adb_error[len] = 0;
++    return -1;
++}
++
++int _adb_connect(const char *service)
++{
++    char tmp[5];
++    int len;
++    int fd;
++
++    D("_adb_connect: %s\n", service);
++    len = strlen(service);
++    if((len < 1) || (len > 1024)) {
++        strcpy(__adb_error, "service name too long");
++        return -1;
++    }
++    snprintf(tmp, sizeof tmp, "%04x", len);
++
++    if (__adb_server_name)
++        fd = socket_network_client(__adb_server_name, __adb_server_port, SOCK_STREAM);
++    else
++        fd = socket_loopback_client(__adb_server_port, SOCK_STREAM);
++
++    if(fd < 0) {
++        strcpy(__adb_error, "cannot connect to daemon");
++        return -2;
++    }
++
++    if (memcmp(service,"host",4) != 0 && switch_socket_transport(fd)) {
++        return -1;
++    }
++
++    if(writex(fd, tmp, 4) || writex(fd, service, len)) {
++        strcpy(__adb_error, "write failure during connection");
++        adb_close(fd);
++        return -1;
++    }
++
++    if(adb_status(fd)) {
++        adb_close(fd);
++        return -1;
++    }
++
++    D("_adb_connect: return fd %d\n", fd);
++    return fd;
++}
++
++int adb_connect(const char *service)
++{
++    // first query the adb server's version
++    int fd = _adb_connect("host:version");
++
++    D("adb_connect: service %s\n", service);
++    if(fd == -2 && __adb_server_name) {
++        fprintf(stderr,"** Cannot start server on remote host\n");
++        return fd;
++    } else if(fd == -2) {
++        fprintf(stdout,"* daemon not running. starting it now on port %d *\n",
++                __adb_server_port);
++    start_server:
++        if(launch_server(__adb_server_port)) {
++            fprintf(stderr,"* failed to start daemon *\n");
++            return -1;
++        } else {
++            fprintf(stdout,"* daemon started successfully *\n");
++        }
++        /* give the server some time to start properly and detect devices */
++        adb_sleep_ms(3000);
++        // fall through to _adb_connect
++    } else {
++        // if server was running, check its version to make sure it is not out of date
++        char buf[100];
++        int n;
++        int version = ADB_SERVER_VERSION - 1;
++
++        // if we have a file descriptor, then parse version result
++        if(fd >= 0) {
++            if(readx(fd, buf, 4)) goto error;
++
++            buf[4] = 0;
++            n = strtoul(buf, 0, 16);
++            if(n > (int)sizeof(buf)) goto error;
++            if(readx(fd, buf, n)) goto error;
++            adb_close(fd);
++
++            if (sscanf(buf, "%04x", &version) != 1) goto error;
++        } else {
++            // if fd is -1, then check for "unknown host service",
++            // which would indicate a version of adb that does not support the version command
++            if (strcmp(__adb_error, "unknown host service") != 0)
++                return fd;
++        }
++
++        if(version != ADB_SERVER_VERSION) {
++            printf("adb server is out of date.  killing...\n");
++            fd = _adb_connect("host:kill");
++            adb_close(fd);
++
++            /* XXX can we better detect its death? */
++            adb_sleep_ms(2000);
++            goto start_server;
++        }
++    }
++
++    // if the command is start-server, we are done.
++    if (!strcmp(service, "host:start-server"))
++        return 0;
++
++    fd = _adb_connect(service);
++    if(fd == -2) {
++        fprintf(stderr,"** daemon still not running\n");
++    }
++    D("adb_connect: return fd %d\n", fd);
++
++    return fd;
++error:
++    adb_close(fd);
++    return -1;
++}
++
++
++int adb_command(const char *service)
++{
++    int fd = adb_connect(service);
++    if(fd < 0) {
++        return -1;
++    }
++
++    if(adb_status(fd)) {
++        adb_close(fd);
++        return -1;
++    }
++
++    return 0;
++}
++
++char *adb_query(const char *service)
++{
++    char buf[5];
++    unsigned n;
++    char *tmp;
++
++    D("adb_query: %s\n", service);
++    int fd = adb_connect(service);
++    if(fd < 0) {
++        fprintf(stderr,"error: %s\n", __adb_error);
++        return 0;
++    }
++
++    if(readx(fd, buf, 4)) goto oops;
++
++    buf[4] = 0;
++    n = strtoul(buf, 0, 16);
++    if(n > 1024) goto oops;
++
++    tmp = malloc(n + 1);
++    if(tmp == 0) goto oops;
++
++    if(readx(fd, tmp, n) == 0) {
++        tmp[n] = 0;
++        adb_close(fd);
++        return tmp;
++    }
++    free(tmp);
++
++oops:
++    adb_close(fd);
++    return 0;
++}
+Index: android-tools-4.2.2+git20130218/core/adbd/adb_client.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/adb_client.h     2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,57 @@
++#ifndef _ADB_CLIENT_H_
++#define _ADB_CLIENT_H_
++
++#include "adb.h"
++
++/* connect to adb, connect to the named service, and return
++** a valid fd for interacting with that service upon success
++** or a negative number on failure
++*/
++int adb_connect(const char *service);
++int _adb_connect(const char *service);
++
++/* connect to adb, connect to the named service, return 0 if
++** the connection succeeded AND the service returned OKAY
++*/
++int adb_command(const char *service);
++
++/* connect to adb, connect to the named service, return
++** a malloc'd string of its response upon success or NULL
++** on failure.
++*/
++char *adb_query(const char *service);
++
++/* Set the preferred transport to connect to.
++*/
++void adb_set_transport(transport_type type, const char* serial);
++
++/* Set TCP specifics of the transport to use
++*/
++void adb_set_tcp_specifics(int server_port);
++
++/* Set TCP Hostname of the transport to use
++*/
++void adb_set_tcp_name(const char* hostname);
++
++/* Return the console port of the currently connected emulator (if any)
++ * of -1 if there is no emulator, and -2 if there is more than one.
++ * assumes adb_set_transport() was alled previously...
++ */
++int  adb_get_emulator_console_port(void);
++
++/* send commands to the current emulator instance. will fail if there
++ * is zero, or more than one emulator connected (or if you use -s <serial>
++ * with a <serial> that does not designate an emulator)
++ */
++int  adb_send_emulator_command(int  argc, char**  argv);
++
++/* return verbose error string from last operation */
++const char *adb_error(void);
++
++/* read a standard adb status response (OKAY|FAIL) and
++** return 0 in the event of OKAY, -1 in the event of FAIL
++** or protocol error
++*/
++int adb_status(int fd);
++
++#endif
+Index: android-tools-4.2.2+git20130218/core/adbd/android_filesystem_config.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/android_filesystem_config.h      2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,302 @@
++/*
++ * Copyright (C) 2007 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++/* This file is used to define the properties of the filesystem
++** images generated by build tools (mkbootfs and mkyaffs2image) and
++** by the device side of adb.
++*/
++
++#ifndef _ANDROID_FILESYSTEM_CONFIG_H_
++#define _ANDROID_FILESYSTEM_CONFIG_H_
++
++#include <string.h>
++#include <sys/stat.h>
++#include <sys/types.h>
++
++/* This is the master Users and Groups config for the platform.
++** DO NOT EVER RENUMBER.
++*/
++
++#define AID_ROOT             0  /* traditional unix root user */
++
++#define AID_SYSTEM        1000  /* system server */
++
++#define AID_RADIO         1001  /* telephony subsystem, RIL */
++#define AID_BLUETOOTH     1002  /* bluetooth subsystem */
++#define AID_GRAPHICS      1003  /* graphics devices */
++#define AID_INPUT         1004  /* input devices */
++#define AID_AUDIO         1005  /* audio devices */
++#define AID_CAMERA        1006  /* camera devices */
++#define AID_LOG           1007  /* log devices */
++#define AID_COMPASS       1008  /* compass device */
++#define AID_MOUNT         1009  /* mountd socket */
++#define AID_WIFI          1010  /* wifi subsystem */
++#define AID_ADB           1011  /* android debug bridge (adbd) */
++#define AID_INSTALL       1012  /* group for installing packages */
++#define AID_MEDIA         1013  /* mediaserver process */
++#define AID_DHCP          1014  /* dhcp client */
++#define AID_SDCARD_RW     1015  /* external storage write access */
++#define AID_VPN           1016  /* vpn system */
++#define AID_KEYSTORE      1017  /* keystore subsystem */
++#define AID_USB           1018  /* USB devices */
++#define AID_DRM           1019  /* DRM server */
++#define AID_MDNSR         1020  /* MulticastDNSResponder (service discovery) */
++#define AID_GPS           1021  /* GPS daemon */
++#define AID_UNUSED1       1022  /* deprecated, DO NOT USE */
++#define AID_MEDIA_RW      1023  /* internal media storage write access */
++#define AID_MTP           1024  /* MTP USB driver access */
++#define AID_UNUSED2       1025  /* deprecated, DO NOT USE */
++#define AID_DRMRPC        1026  /* group for drm rpc */
++#define AID_NFC           1027  /* nfc subsystem */
++#define AID_SDCARD_R      1028  /* external storage read access */
++
++#define AID_SHELL         2000  /* adb and debug shell user */
++#define AID_CACHE         2001  /* cache access */
++#define AID_DIAG          2002  /* access to diagnostic resources */
++
++/* The 3000 series are intended for use as supplemental group id's only.
++ * They indicate special Android capabilities that the kernel is aware of. */
++#define AID_NET_BT_ADMIN  3001  /* bluetooth: create any socket */
++#define AID_NET_BT        3002  /* bluetooth: create sco, rfcomm or l2cap sockets */
++#define AID_INET          3003  /* can create AF_INET and AF_INET6 sockets */
++#define AID_NET_RAW       3004  /* can create raw INET sockets */
++#define AID_NET_ADMIN     3005  /* can configure interfaces and routing tables. */
++#define AID_NET_BW_STATS  3006  /* read bandwidth statistics */
++#define AID_NET_BW_ACCT   3007  /* change bandwidth statistics accounting */
++#define AID_NET_BT_STACK  3008  /* bluetooth: access config files */
++#define AID_QCOM_ONCRPC   3009  /* can read/write /dev/oncrpc files */
++#define AID_QCOM_DIAG     3010  /* can read/write /dev/diag */
++
++#if defined(MOTOROLA_UIDS)
++#define AID_MOT_OSH       5000  /* OSH */
++#define AID_MOT_ACCY      9000  /* access to accessory */
++#define AID_MOT_PWRIC     9001  /* power IC */
++#define AID_MOT_USB       9002  /* mot usb */
++#define AID_MOT_DRM       9003  /* can access DRM resource. */
++#define AID_MOT_TCMD      9004  /* mot_tcmd */
++#define AID_MOT_SEC_RTC   9005  /* mot cpcap rtc */
++#define AID_MOT_TOMBSTONE 9006
++#define AID_MOT_TPAPI     9007  /* mot_tpapi */
++#define AID_MOT_SECCLKD   9008  /* mot_secclkd */
++#define AID_MOT_WHISPER   9009  /* Whisper Protocol access */
++#define AID_MOT_CAIF      9010  /* can create CAIF sockets */
++#define AID_MOT_DLNA      9011  /* DLNA native */
++#endif // MOTOROLA_UIDS
++
++#define AID_MISC          9998  /* access to misc storage */
++#define AID_NOBODY        9999
++
++#define AID_APP          10000  /* first app user */
++
++#define AID_ISOLATED_START 99000 /* start of uids for fully isolated sandboxed processes */
++#define AID_ISOLATED_END   99999 /* end of uids for fully isolated sandboxed processes */
++
++#define AID_USER        100000  /* offset for uid ranges for each user */
++
++#define AID_SHARED_GID_START 50000 /* start of gids for apps in each user to share */
++#define AID_SHARED_GID_END   59999 /* start of gids for apps in each user to share */
++
++#if !defined(EXCLUDE_FS_CONFIG_STRUCTURES)
++struct android_id_info {
++    const char *name;
++    unsigned aid;
++};
++
++static const struct android_id_info android_ids[] = {
++    { "root",      AID_ROOT, },
++    { "system",    AID_SYSTEM, },
++    { "radio",     AID_RADIO, },
++    { "bluetooth", AID_BLUETOOTH, },
++    { "graphics",  AID_GRAPHICS, },
++    { "input",     AID_INPUT, },
++    { "audio",     AID_AUDIO, },
++    { "camera",    AID_CAMERA, },
++    { "log",       AID_LOG, },
++    { "compass",   AID_COMPASS, },
++    { "mount",     AID_MOUNT, },
++    { "wifi",      AID_WIFI, },
++    { "dhcp",      AID_DHCP, },
++    { "adb",       AID_ADB, },
++    { "install",   AID_INSTALL, },
++    { "media",     AID_MEDIA, },
++    { "drm",       AID_DRM, },
++    { "mdnsr",     AID_MDNSR, },
++    { "nfc",       AID_NFC, },
++    { "drmrpc",    AID_DRMRPC, },
++    { "shell",     AID_SHELL, },
++    { "cache",     AID_CACHE, },
++    { "diag",      AID_DIAG, },
++    { "net_bt_admin", AID_NET_BT_ADMIN, },
++    { "net_bt",    AID_NET_BT, },
++    { "net_bt_stack",    AID_NET_BT_STACK, },
++    { "sdcard_r",  AID_SDCARD_R, },
++    { "sdcard_rw", AID_SDCARD_RW, },
++    { "media_rw",  AID_MEDIA_RW, },
++    { "vpn",       AID_VPN, },
++    { "keystore",  AID_KEYSTORE, },
++    { "usb",       AID_USB, },
++    { "mtp",       AID_MTP, },
++    { "gps",       AID_GPS, },
++    { "inet",      AID_INET, },
++    { "net_raw",   AID_NET_RAW, },
++    { "net_admin", AID_NET_ADMIN, },
++    { "net_bw_stats", AID_NET_BW_STATS, },
++    { "net_bw_acct", AID_NET_BW_ACCT, },
++    { "qcom_oncrpc", AID_QCOM_ONCRPC, },
++    { "qcom_diag", AID_QCOM_DIAG, },
++#if defined(MOTOROLA_UIDS)
++    { "mot_osh",   AID_MOT_OSH, },
++    { "mot_accy",  AID_MOT_ACCY, },
++    { "mot_pwric", AID_MOT_PWRIC, },
++    { "mot_usb",   AID_MOT_USB, },
++    { "mot_drm",   AID_MOT_DRM, },
++    { "mot_tcmd",  AID_MOT_TCMD, },
++    { "mot_sec_rtc",   AID_MOT_SEC_RTC, },
++    { "mot_tombstone", AID_MOT_TOMBSTONE, },
++    { "mot_tpapi",     AID_MOT_TPAPI, },
++    { "mot_secclkd",   AID_MOT_SECCLKD, },
++    { "mot_whisper",   AID_MOT_WHISPER, },
++    { "mot_caif",  AID_MOT_CAIF, },
++    { "mot_dlna",  AID_MOT_DLNA, },
++#endif
++    { "misc",      AID_MISC, },
++    { "nobody",    AID_NOBODY, },
++};
++
++#define android_id_count \
++    (sizeof(android_ids) / sizeof(android_ids[0]))
++
++struct fs_path_config {
++    unsigned mode;
++    unsigned uid;
++    unsigned gid;
++    const char *prefix;
++};
++
++/* Rules for directories.
++** These rules are applied based on "first match", so they
++** should start with the most specific path and work their
++** way up to the root.
++*/
++
++static struct fs_path_config android_dirs[] = {
++    { 00770, AID_SYSTEM, AID_CACHE,  "cache" },
++    { 00771, AID_SYSTEM, AID_SYSTEM, "data/app" },
++    { 00771, AID_SYSTEM, AID_SYSTEM, "data/app-private" },
++    { 00771, AID_SYSTEM, AID_SYSTEM, "data/dalvik-cache" },
++    { 00771, AID_SYSTEM, AID_SYSTEM, "data/data" },
++    { 00771, AID_SHELL,  AID_SHELL,  "data/local/tmp" },
++    { 00771, AID_SHELL,  AID_SHELL,  "data/local" },
++    { 01771, AID_SYSTEM, AID_MISC,   "data/misc" },
++    { 00770, AID_DHCP,   AID_DHCP,   "data/misc/dhcp" },
++    { 00775, AID_MEDIA_RW, AID_MEDIA_RW, "data/media" },
++    { 00775, AID_MEDIA_RW, AID_MEDIA_RW, "data/media/Music" },
++    { 00771, AID_SYSTEM, AID_SYSTEM, "data" },
++    { 00750, AID_ROOT,   AID_SHELL,  "sbin" },
++    { 00755, AID_ROOT,   AID_ROOT,   "system/addon.d" },
++    { 00755, AID_ROOT,   AID_SHELL,  "system/bin" },
++    { 00755, AID_ROOT,   AID_SHELL,  "system/vendor" },
++    { 00755, AID_ROOT,   AID_SHELL,  "system/xbin" },
++    { 00755, AID_ROOT,   AID_ROOT,   "system/etc/ppp" },
++    { 00777, AID_ROOT,   AID_ROOT,   "sdcard" },
++    { 00755, AID_ROOT,   AID_ROOT,   0 },
++};
++
++/* Rules for files.
++** These rules are applied based on "first match", so they
++** should start with the most specific path and work their
++** way up to the root. Prefixes ending in * denotes wildcard
++** and will allow partial matches.
++*/
++static struct fs_path_config android_files[] = {
++    { 00440, AID_ROOT,      AID_SHELL,     "system/etc/init.goldfish.rc" },
++    { 00550, AID_ROOT,      AID_SHELL,     "system/etc/init.goldfish.sh" },
++    { 00440, AID_ROOT,      AID_SHELL,     "system/etc/init.trout.rc" },
++    { 00550, AID_ROOT,      AID_SHELL,     "system/etc/init.ril" },
++    { 00550, AID_ROOT,      AID_SHELL,     "system/etc/init.testmenu" },
++    { 00550, AID_DHCP,      AID_SHELL,     "system/etc/dhcpcd/dhcpcd-run-hooks" },
++    { 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/dbus.conf" },
++    { 00444, AID_RADIO,     AID_AUDIO,     "system/etc/AudioPara4.csv" },
++    { 00555, AID_ROOT,      AID_ROOT,      "system/etc/ppp/*" },
++    { 00555, AID_ROOT,      AID_ROOT,      "system/etc/rc.*" },
++    { 00755, AID_ROOT,      AID_ROOT,      "system/addon.d/*" },
++    { 00644, AID_SYSTEM,    AID_SYSTEM,    "data/app/*" },
++    { 00644, AID_MEDIA_RW,  AID_MEDIA_RW,  "data/media/*" },
++    { 00644, AID_SYSTEM,    AID_SYSTEM,    "data/app-private/*" },
++    { 00644, AID_APP,       AID_APP,       "data/data/*" },
++        /* the following two files are INTENTIONALLY set-gid and not set-uid.
++         * Do not change. */
++    { 02755, AID_ROOT,      AID_NET_RAW,   "system/bin/ping" },
++    { 02750, AID_ROOT,      AID_INET,      "system/bin/netcfg" },
++      /* the following five files are INTENTIONALLY set-uid, but they
++       * are NOT included on user builds. */
++    { 06755, AID_ROOT,      AID_ROOT,      "system/xbin/su" },
++    { 06755, AID_ROOT,      AID_ROOT,      "system/xbin/librank" },
++    { 06755, AID_ROOT,      AID_ROOT,      "system/xbin/procrank" },
++    { 06755, AID_ROOT,      AID_ROOT,      "system/xbin/procmem" },
++    { 06755, AID_ROOT,      AID_ROOT,      "system/xbin/tcpdump" },
++    { 04770, AID_ROOT,      AID_RADIO,     "system/bin/pppd-ril" },
++              /* the following file is INTENTIONALLY set-uid, and IS included
++               * in user builds. */
++    { 06750, AID_ROOT,      AID_SHELL,     "system/bin/run-as" },
++    { 06750, AID_ROOT,      AID_SYSTEM,    "system/bin/rebootcmd" },
++    { 00755, AID_ROOT,      AID_SHELL,     "system/bin/*" },
++    { 00755, AID_ROOT,      AID_ROOT,      "system/lib/valgrind/*" },
++    { 00755, AID_ROOT,      AID_SHELL,     "system/xbin/*" },
++    { 00755, AID_ROOT,      AID_SHELL,     "system/vendor/bin/*" },
++    { 00750, AID_ROOT,      AID_SHELL,     "sbin/*" },
++    { 00755, AID_ROOT,      AID_ROOT,      "bin/*" },
++    { 00750, AID_ROOT,      AID_SHELL,     "init*" },
++    { 00750, AID_ROOT,      AID_SHELL,     "charger*" },
++    { 00750, AID_ROOT,      AID_SHELL,     "sbin/fs_mgr" },
++    { 00640, AID_ROOT,      AID_SHELL,     "fstab.*" },
++    { 00755, AID_ROOT,      AID_SHELL,     "system/etc/init.d/*" },
++    { 00644, AID_ROOT,      AID_ROOT,       0 },
++};
++
++static inline void fs_config(const char *path, int dir,
++                             unsigned *uid, unsigned *gid, unsigned *mode)
++{
++    struct fs_path_config *pc;
++    int plen;
++
++    pc = dir ? android_dirs : android_files;
++    plen = strlen(path);
++    for(; pc->prefix; pc++){
++        int len = strlen(pc->prefix);
++        if (dir) {
++            if(plen < len) continue;
++            if(!strncmp(pc->prefix, path, len)) break;
++            continue;
++        }
++        /* If name ends in * then allow partial matches. */
++        if (pc->prefix[len -1] == '*') {
++            if(!strncmp(pc->prefix, path, len - 1)) break;
++        } else if (plen == len){
++            if(!strncmp(pc->prefix, path, len)) break;
++        }
++    }
++    *uid = pc->uid;
++    *gid = pc->gid;
++    *mode = (*mode & (~07777)) | pc->mode;
++
++#if 0
++    fprintf(stderr,"< '%s' '%s' %d %d %o >\n",
++            path, pc->prefix ? pc->prefix : "", *uid, *gid, *mode);
++#endif
++}
++#endif
++#endif
+Index: android-tools-4.2.2+git20130218/core/adbd/arpa_nameser.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/arpa_nameser.h   2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,577 @@
++/*    $NetBSD: nameser.h,v 1.19 2005/12/26 19:01:47 perry Exp $       */
++
++/*
++ * Copyright (c) 1983, 1989, 1993
++ *    The Regents of the University of California.  All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. Neither the name of the University nor the names of its contributors
++ *    may be used to endorse or promote products derived from this software
++ *    without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ */
++
++/*
++ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
++ * Copyright (c) 1996-1999 by Internet Software Consortium.
++ *
++ * Permission to use, copy, modify, and distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
++ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/*
++ *    Id: nameser.h,v 1.2.2.4.4.1 2004/03/09 08:33:30 marka Exp
++ */
++
++#ifndef _ARPA_NAMESER_H_
++#define _ARPA_NAMESER_H_
++
++#define BIND_4_COMPAT
++
++#include <sys/types.h>
++#include <sys/cdefs.h>
++
++/*
++ * Revision information.  This is the release date in YYYYMMDD format.
++ * It can change every day so the right thing to do with it is use it
++ * in preprocessor commands such as "#if (__NAMESER > 19931104)".  Do not
++ * compare for equality; rather, use it to determine whether your libbind.a
++ * contains a new enough lib/nameser/ to support the feature you need.
++ */
++
++#define __NAMESER     19991006        /* New interface version stamp. */
++
++/*
++ * Define constants based on RFC 883, RFC 1034, RFC 1035
++ */
++#define NS_PACKETSZ   512     /* default UDP packet size */
++#define NS_MAXDNAME   1025    /* maximum domain name */
++#define NS_MAXMSG     65535   /* maximum message size */
++#define NS_MAXCDNAME  255     /* maximum compressed domain name */
++#define NS_MAXLABEL   63      /* maximum length of domain label */
++#define NS_HFIXEDSZ   12      /* #/bytes of fixed data in header */
++#define NS_QFIXEDSZ   4       /* #/bytes of fixed data in query */
++#define NS_RRFIXEDSZ  10      /* #/bytes of fixed data in r record */
++#define NS_INT32SZ    4       /* #/bytes of data in a uint32_t */
++#define NS_INT16SZ    2       /* #/bytes of data in a uint16_t */
++#define NS_INT8SZ     1       /* #/bytes of data in a uint8_t */
++#define NS_INADDRSZ   4       /* IPv4 T_A */
++#define NS_IN6ADDRSZ  16      /* IPv6 T_AAAA */
++#define NS_CMPRSFLGS  0xc0    /* Flag bits indicating name compression. */
++#define NS_DEFAULTPORT        53      /* For both TCP and UDP. */
++
++/*
++ * These can be expanded with synonyms, just keep ns_parse.c:ns_parserecord()
++ * in synch with it.
++ */
++typedef enum __ns_sect {
++      ns_s_qd = 0,            /* Query: Question. */
++      ns_s_zn = 0,            /* Update: Zone. */
++      ns_s_an = 1,            /* Query: Answer. */
++      ns_s_pr = 1,            /* Update: Prerequisites. */
++      ns_s_ns = 2,            /* Query: Name servers. */
++      ns_s_ud = 2,            /* Update: Update. */
++      ns_s_ar = 3,            /* Query|Update: Additional records. */
++      ns_s_max = 4
++} ns_sect;
++
++/*
++ * This is a message handle.  It is caller allocated and has no dynamic data.
++ * This structure is intended to be opaque to all but ns_parse.c, thus the
++ * leading _'s on the member names.  Use the accessor functions, not the _'s.
++ */
++typedef struct __ns_msg {
++      const u_char    *_msg, *_eom;
++      uint16_t        _id, _flags, _counts[ns_s_max];
++      const u_char    *_sections[ns_s_max];
++      ns_sect         _sect;
++      int             _rrnum;
++      const u_char    *_msg_ptr;
++} ns_msg;
++
++/* Private data structure - do not use from outside library. */
++struct _ns_flagdata {  int mask, shift;  };
++extern const struct _ns_flagdata _ns_flagdata[];
++
++/* Accessor macros - this is part of the public interface. */
++
++#define ns_msg_id(handle) ((handle)._id + 0)
++#define ns_msg_base(handle) ((handle)._msg + 0)
++#define ns_msg_end(handle) ((handle)._eom + 0)
++#define ns_msg_size(handle) ((size_t)((handle)._eom - (handle)._msg))
++#define ns_msg_count(handle, section) ((handle)._counts[section] + 0)
++
++/*
++ * This is a parsed record.  It is caller allocated and has no dynamic data.
++ */
++typedef       struct __ns_rr {
++      char            name[NS_MAXDNAME];
++      uint16_t        type;
++      uint16_t        rr_class;
++      uint32_t        ttl;
++      uint16_t        rdlength;
++      const u_char *  rdata;
++} ns_rr;
++
++/* Accessor macros - this is part of the public interface. */
++#define ns_rr_name(rr)        (((rr).name[0] != '\0') ? (rr).name : ".")
++#define ns_rr_type(rr)        ((ns_type)((rr).type + 0))
++#define ns_rr_class(rr)       ((ns_class)((rr).rr_class + 0))
++#define ns_rr_ttl(rr) ((u_long)(rr).ttl + 0)
++#define ns_rr_rdlen(rr)       ((size_t)(rr).rdlength + 0)
++#define ns_rr_rdata(rr)       ((rr).rdata + 0)
++
++/*
++ * These don't have to be in the same order as in the packet flags word,
++ * and they can even overlap in some cases, but they will need to be kept
++ * in synch with ns_parse.c:ns_flagdata[].
++ */
++typedef enum __ns_flag {
++      ns_f_qr,                /* Question/Response. */
++      ns_f_opcode,            /* Operation code. */
++      ns_f_aa,                /* Authoritative Answer. */
++      ns_f_tc,                /* Truncation occurred. */
++      ns_f_rd,                /* Recursion Desired. */
++      ns_f_ra,                /* Recursion Available. */
++      ns_f_z,                 /* MBZ. */
++      ns_f_ad,                /* Authentic Data (DNSSEC). */
++      ns_f_cd,                /* Checking Disabled (DNSSEC). */
++      ns_f_rcode,             /* Response code. */
++      ns_f_max
++} ns_flag;
++
++/*
++ * Currently defined opcodes.
++ */
++typedef enum __ns_opcode {
++      ns_o_query = 0,         /* Standard query. */
++      ns_o_iquery = 1,        /* Inverse query (deprecated/unsupported). */
++      ns_o_status = 2,        /* Name server status query (unsupported). */
++                              /* Opcode 3 is undefined/reserved. */
++      ns_o_notify = 4,        /* Zone change notification. */
++      ns_o_update = 5,        /* Zone update message. */
++      ns_o_max = 6
++} ns_opcode;
++
++/*
++ * Currently defined response codes.
++ */
++typedef       enum __ns_rcode {
++      ns_r_noerror = 0,       /* No error occurred. */
++      ns_r_formerr = 1,       /* Format error. */
++      ns_r_servfail = 2,      /* Server failure. */
++      ns_r_nxdomain = 3,      /* Name error. */
++      ns_r_notimpl = 4,       /* Unimplemented. */
++      ns_r_refused = 5,       /* Operation refused. */
++      /* these are for BIND_UPDATE */
++      ns_r_yxdomain = 6,      /* Name exists */
++      ns_r_yxrrset = 7,       /* RRset exists */
++      ns_r_nxrrset = 8,       /* RRset does not exist */
++      ns_r_notauth = 9,       /* Not authoritative for zone */
++      ns_r_notzone = 10,      /* Zone of record different from zone section */
++      ns_r_max = 11,
++      /* The following are EDNS extended rcodes */
++      ns_r_badvers = 16,
++      /* The following are TSIG errors */
++      ns_r_badsig = 16,
++      ns_r_badkey = 17,
++      ns_r_badtime = 18
++} ns_rcode;
++
++/* BIND_UPDATE */
++typedef enum __ns_update_operation {
++      ns_uop_delete = 0,
++      ns_uop_add = 1,
++      ns_uop_max = 2
++} ns_update_operation;
++
++/*
++ * This structure is used for TSIG authenticated messages
++ */
++struct ns_tsig_key {
++        char name[NS_MAXDNAME], alg[NS_MAXDNAME];
++        unsigned char *data;
++        int len;
++};
++typedef struct ns_tsig_key ns_tsig_key;
++
++/*
++ * This structure is used for TSIG authenticated TCP messages
++ */
++struct ns_tcp_tsig_state {
++      int counter;
++      struct dst_key *key;
++      void *ctx;
++      unsigned char sig[NS_PACKETSZ];
++      int siglen;
++};
++typedef struct ns_tcp_tsig_state ns_tcp_tsig_state;
++
++#define NS_TSIG_FUDGE 300
++#define NS_TSIG_TCP_COUNT 100
++#define NS_TSIG_ALG_HMAC_MD5 "HMAC-MD5.SIG-ALG.REG.INT"
++
++#define NS_TSIG_ERROR_NO_TSIG -10
++#define NS_TSIG_ERROR_NO_SPACE -11
++#define NS_TSIG_ERROR_FORMERR -12
++
++/*
++ * Currently defined type values for resources and queries.
++ */
++typedef enum __ns_type {
++      ns_t_invalid = 0,       /* Cookie. */
++      ns_t_a = 1,             /* Host address. */
++      ns_t_ns = 2,            /* Authoritative server. */
++      ns_t_md = 3,            /* Mail destination. */
++      ns_t_mf = 4,            /* Mail forwarder. */
++      ns_t_cname = 5,         /* Canonical name. */
++      ns_t_soa = 6,           /* Start of authority zone. */
++      ns_t_mb = 7,            /* Mailbox domain name. */
++      ns_t_mg = 8,            /* Mail group member. */
++      ns_t_mr = 9,            /* Mail rename name. */
++      ns_t_null = 10,         /* Null resource record. */
++      ns_t_wks = 11,          /* Well known service. */
++      ns_t_ptr = 12,          /* Domain name pointer. */
++      ns_t_hinfo = 13,        /* Host information. */
++      ns_t_minfo = 14,        /* Mailbox information. */
++      ns_t_mx = 15,           /* Mail routing information. */
++      ns_t_txt = 16,          /* Text strings. */
++      ns_t_rp = 17,           /* Responsible person. */
++      ns_t_afsdb = 18,        /* AFS cell database. */
++      ns_t_x25 = 19,          /* X_25 calling address. */
++      ns_t_isdn = 20,         /* ISDN calling address. */
++      ns_t_rt = 21,           /* Router. */
++      ns_t_nsap = 22,         /* NSAP address. */
++      ns_t_nsap_ptr = 23,     /* Reverse NSAP lookup (deprecated). */
++      ns_t_sig = 24,          /* Security signature. */
++      ns_t_key = 25,          /* Security key. */
++      ns_t_px = 26,           /* X.400 mail mapping. */
++      ns_t_gpos = 27,         /* Geographical position (withdrawn). */
++      ns_t_aaaa = 28,         /* Ip6 Address. */
++      ns_t_loc = 29,          /* Location Information. */
++      ns_t_nxt = 30,          /* Next domain (security). */
++      ns_t_eid = 31,          /* Endpoint identifier. */
++      ns_t_nimloc = 32,       /* Nimrod Locator. */
++      ns_t_srv = 33,          /* Server Selection. */
++      ns_t_atma = 34,         /* ATM Address */
++      ns_t_naptr = 35,        /* Naming Authority PoinTeR */
++      ns_t_kx = 36,           /* Key Exchange */
++      ns_t_cert = 37,         /* Certification record */
++      ns_t_a6 = 38,           /* IPv6 address (deprecates AAAA) */
++      ns_t_dname = 39,        /* Non-terminal DNAME (for IPv6) */
++      ns_t_sink = 40,         /* Kitchen sink (experimentatl) */
++      ns_t_opt = 41,          /* EDNS0 option (meta-RR) */
++      ns_t_apl = 42,          /* Address prefix list (RFC 3123) */
++      ns_t_tkey = 249,        /* Transaction key */
++      ns_t_tsig = 250,        /* Transaction signature. */
++      ns_t_ixfr = 251,        /* Incremental zone transfer. */
++      ns_t_axfr = 252,        /* Transfer zone of authority. */
++      ns_t_mailb = 253,       /* Transfer mailbox records. */
++      ns_t_maila = 254,       /* Transfer mail agent records. */
++      ns_t_any = 255,         /* Wildcard match. */
++      ns_t_zxfr = 256,        /* BIND-specific, nonstandard. */
++      ns_t_max = 65536
++} ns_type;
++
++/* Exclusively a QTYPE? (not also an RTYPE) */
++#define       ns_t_qt_p(t) (ns_t_xfr_p(t) || (t) == ns_t_any || \
++                    (t) == ns_t_mailb || (t) == ns_t_maila)
++/* Some kind of meta-RR? (not a QTYPE, but also not an RTYPE) */
++#define       ns_t_mrr_p(t) ((t) == ns_t_tsig || (t) == ns_t_opt)
++/* Exclusively an RTYPE? (not also a QTYPE or a meta-RR) */
++#define ns_t_rr_p(t) (!ns_t_qt_p(t) && !ns_t_mrr_p(t))
++#define ns_t_udp_p(t) ((t) != ns_t_axfr && (t) != ns_t_zxfr)
++#define ns_t_xfr_p(t) ((t) == ns_t_axfr || (t) == ns_t_ixfr || \
++                     (t) == ns_t_zxfr)
++
++/*
++ * Values for class field
++ */
++typedef enum __ns_class {
++      ns_c_invalid = 0,       /* Cookie. */
++      ns_c_in = 1,            /* Internet. */
++      ns_c_2 = 2,             /* unallocated/unsupported. */
++      ns_c_chaos = 3,         /* MIT Chaos-net. */
++      ns_c_hs = 4,            /* MIT Hesiod. */
++      /* Query class values which do not appear in resource records */
++      ns_c_none = 254,        /* for prereq. sections in update requests */
++      ns_c_any = 255,         /* Wildcard match. */
++      ns_c_max = 65536
++} ns_class;
++
++/* DNSSEC constants. */
++
++typedef enum __ns_key_types {
++      ns_kt_rsa = 1,          /* key type RSA/MD5 */
++      ns_kt_dh  = 2,          /* Diffie Hellman */
++      ns_kt_dsa = 3,          /* Digital Signature Standard (MANDATORY) */
++      ns_kt_private = 254     /* Private key type starts with OID */
++} ns_key_types;
++
++typedef enum __ns_cert_types {
++      cert_t_pkix = 1,        /* PKIX (X.509v3) */
++      cert_t_spki = 2,        /* SPKI */
++      cert_t_pgp  = 3,        /* PGP */
++      cert_t_url  = 253,      /* URL private type */
++      cert_t_oid  = 254       /* OID private type */
++} ns_cert_types;
++
++/* Flags field of the KEY RR rdata. */
++#define       NS_KEY_TYPEMASK         0xC000  /* Mask for "type" bits */
++#define       NS_KEY_TYPE_AUTH_CONF   0x0000  /* Key usable for both */
++#define       NS_KEY_TYPE_CONF_ONLY   0x8000  /* Key usable for confidentiality */
++#define       NS_KEY_TYPE_AUTH_ONLY   0x4000  /* Key usable for authentication */
++#define       NS_KEY_TYPE_NO_KEY      0xC000  /* No key usable for either; no key */
++/* The type bits can also be interpreted independently, as single bits: */
++#define       NS_KEY_NO_AUTH          0x8000  /* Key unusable for authentication */
++#define       NS_KEY_NO_CONF          0x4000  /* Key unusable for confidentiality */
++#define       NS_KEY_RESERVED2        0x2000  /* Security is *mandatory* if bit=0 */
++#define       NS_KEY_EXTENDED_FLAGS   0x1000  /* reserved - must be zero */
++#define       NS_KEY_RESERVED4        0x0800  /* reserved - must be zero */
++#define       NS_KEY_RESERVED5        0x0400  /* reserved - must be zero */
++#define       NS_KEY_NAME_TYPE        0x0300  /* these bits determine the type */
++#define       NS_KEY_NAME_USER        0x0000  /* key is assoc. with user */
++#define       NS_KEY_NAME_ENTITY      0x0200  /* key is assoc. with entity eg host */
++#define       NS_KEY_NAME_ZONE        0x0100  /* key is zone key */
++#define       NS_KEY_NAME_RESERVED    0x0300  /* reserved meaning */
++#define       NS_KEY_RESERVED8        0x0080  /* reserved - must be zero */
++#define       NS_KEY_RESERVED9        0x0040  /* reserved - must be zero */
++#define       NS_KEY_RESERVED10       0x0020  /* reserved - must be zero */
++#define       NS_KEY_RESERVED11       0x0010  /* reserved - must be zero */
++#define       NS_KEY_SIGNATORYMASK    0x000F  /* key can sign RR's of same name */
++#define       NS_KEY_RESERVED_BITMASK ( NS_KEY_RESERVED2 | \
++                                NS_KEY_RESERVED4 | \
++                                NS_KEY_RESERVED5 | \
++                                NS_KEY_RESERVED8 | \
++                                NS_KEY_RESERVED9 | \
++                                NS_KEY_RESERVED10 | \
++                                NS_KEY_RESERVED11 )
++#define NS_KEY_RESERVED_BITMASK2 0xFFFF /* no bits defined here */
++
++/* The Algorithm field of the KEY and SIG RR's is an integer, {1..254} */
++#define       NS_ALG_MD5RSA           1       /* MD5 with RSA */
++#define       NS_ALG_DH               2       /* Diffie Hellman KEY */
++#define       NS_ALG_DSA              3       /* DSA KEY */
++#define       NS_ALG_DSS              NS_ALG_DSA
++#define       NS_ALG_EXPIRE_ONLY      253     /* No alg, no security */
++#define       NS_ALG_PRIVATE_OID      254     /* Key begins with OID giving alg */
++
++/* Protocol values  */
++/* value 0 is reserved */
++#define NS_KEY_PROT_TLS         1
++#define NS_KEY_PROT_EMAIL       2
++#define NS_KEY_PROT_DNSSEC      3
++#define NS_KEY_PROT_IPSEC       4
++#define NS_KEY_PROT_ANY               255
++
++/* Signatures */
++#define       NS_MD5RSA_MIN_BITS       512    /* Size of a mod or exp in bits */
++#define       NS_MD5RSA_MAX_BITS      4096
++      /* Total of binary mod and exp */
++#define       NS_MD5RSA_MAX_BYTES     ((NS_MD5RSA_MAX_BITS+7/8)*2+3)
++      /* Max length of text sig block */
++#define       NS_MD5RSA_MAX_BASE64    (((NS_MD5RSA_MAX_BYTES+2)/3)*4)
++#define NS_MD5RSA_MIN_SIZE    ((NS_MD5RSA_MIN_BITS+7)/8)
++#define NS_MD5RSA_MAX_SIZE    ((NS_MD5RSA_MAX_BITS+7)/8)
++
++#define NS_DSA_SIG_SIZE         41
++#define NS_DSA_MIN_SIZE         213
++#define NS_DSA_MAX_BYTES        405
++
++/* Offsets into SIG record rdata to find various values */
++#define       NS_SIG_TYPE     0       /* Type flags */
++#define       NS_SIG_ALG      2       /* Algorithm */
++#define       NS_SIG_LABELS   3       /* How many labels in name */
++#define       NS_SIG_OTTL     4       /* Original TTL */
++#define       NS_SIG_EXPIR    8       /* Expiration time */
++#define       NS_SIG_SIGNED   12      /* Signature time */
++#define       NS_SIG_FOOT     16      /* Key footprint */
++#define       NS_SIG_SIGNER   18      /* Domain name of who signed it */
++
++/* How RR types are represented as bit-flags in NXT records */
++#define       NS_NXT_BITS 8
++#define       NS_NXT_BIT_SET(  n,p) (p[(n)/NS_NXT_BITS] |=  (0x80>>((n)%NS_NXT_BITS)))
++#define       NS_NXT_BIT_CLEAR(n,p) (p[(n)/NS_NXT_BITS] &= ~(0x80>>((n)%NS_NXT_BITS)))
++#define       NS_NXT_BIT_ISSET(n,p) (p[(n)/NS_NXT_BITS] &   (0x80>>((n)%NS_NXT_BITS)))
++#define NS_NXT_MAX 127
++
++/*
++ * EDNS0 extended flags, host order.
++ */
++#define NS_OPT_DNSSEC_OK      0x8000U
++
++/*
++ * Inline versions of get/put short/long.  Pointer is advanced.
++ */
++#define NS_GET16(s, cp) do { \
++      const u_char *t_cp = (const u_char *)(cp); \
++      (s) = ((uint16_t)t_cp[0] << 8) \
++          | ((uint16_t)t_cp[1]) \
++          ; \
++      (cp) += NS_INT16SZ; \
++} while (/*CONSTCOND*/0)
++
++#define NS_GET32(l, cp) do { \
++      const u_char *t_cp = (const u_char *)(cp); \
++      (l) = ((uint32_t)t_cp[0] << 24) \
++          | ((uint32_t)t_cp[1] << 16) \
++          | ((uint32_t)t_cp[2] << 8) \
++          | ((uint32_t)t_cp[3]) \
++          ; \
++      (cp) += NS_INT32SZ; \
++} while (/*CONSTCOND*/0)
++
++#define NS_PUT16(s, cp) do { \
++      uint32_t t_s = (uint32_t)(s); \
++      u_char *t_cp = (u_char *)(cp); \
++      *t_cp++ = t_s >> 8; \
++      *t_cp   = t_s; \
++      (cp) += NS_INT16SZ; \
++} while (/*CONSTCOND*/0)
++
++#define NS_PUT32(l, cp) do { \
++      uint32_t t_l = (uint32_t)(l); \
++      u_char *t_cp = (u_char *)(cp); \
++      *t_cp++ = t_l >> 24; \
++      *t_cp++ = t_l >> 16; \
++      *t_cp++ = t_l >> 8; \
++      *t_cp   = t_l; \
++      (cp) += NS_INT32SZ; \
++} while (/*CONSTCOND*/0)
++
++/*
++ * ANSI C identifier hiding for bind's lib/nameser.
++ */
++#define       ns_msg_getflag          __ns_msg_getflag
++#define ns_get16              __ns_get16
++#define ns_get32              __ns_get32
++#define ns_put16              __ns_put16
++#define ns_put32              __ns_put32
++#define ns_initparse          __ns_initparse
++#define ns_skiprr             __ns_skiprr
++#define ns_parserr            __ns_parserr
++#define       ns_sprintrr             __ns_sprintrr
++#define       ns_sprintrrf            __ns_sprintrrf
++#define       ns_format_ttl           __ns_format_ttl
++#define       ns_parse_ttl            __ns_parse_ttl
++#define ns_datetosecs         __ns_datetosecs
++#define       ns_name_ntol            __ns_name_ntol
++#define       ns_name_ntop            __ns_name_ntop
++#define       ns_name_pton            __ns_name_pton
++#define       ns_name_unpack          __ns_name_unpack
++#define       ns_name_pack            __ns_name_pack
++#define       ns_name_compress        __ns_name_compress
++#define       ns_name_uncompress      __ns_name_uncompress
++#define       ns_name_skip            __ns_name_skip
++#define       ns_name_rollback        __ns_name_rollback
++#define       ns_sign                 __ns_sign
++#define       ns_sign2                __ns_sign2
++#define       ns_sign_tcp             __ns_sign_tcp
++#define       ns_sign_tcp2            __ns_sign_tcp2
++#define       ns_sign_tcp_init        __ns_sign_tcp_init
++#define ns_find_tsig          __ns_find_tsig
++#define       ns_verify               __ns_verify
++#define       ns_verify_tcp           __ns_verify_tcp
++#define       ns_verify_tcp_init      __ns_verify_tcp_init
++#define       ns_samedomain           __ns_samedomain
++#define       ns_subdomain            __ns_subdomain
++#define       ns_makecanon            __ns_makecanon
++#define       ns_samename             __ns_samename
++
++__BEGIN_DECLS
++int           ns_msg_getflag(ns_msg, int);
++uint16_t      ns_get16(const u_char *);
++uint32_t      ns_get32(const u_char *);
++void          ns_put16(uint16_t, u_char *);
++void          ns_put32(uint32_t, u_char *);
++int           ns_initparse(const u_char *, int, ns_msg *);
++int           ns_skiprr(const u_char *, const u_char *, ns_sect, int);
++int           ns_parserr(ns_msg *, ns_sect, int, ns_rr *);
++int           ns_sprintrr(const ns_msg *, const ns_rr *,
++                               const char *, const char *, char *, size_t);
++int           ns_sprintrrf(const u_char *, size_t, const char *,
++                                ns_class, ns_type, u_long, const u_char *,
++                                size_t, const char *, const char *,
++                                char *, size_t);
++int           ns_format_ttl(u_long, char *, size_t);
++int           ns_parse_ttl(const char *, u_long *);
++uint32_t      ns_datetosecs(const char *cp, int *errp);
++int           ns_name_ntol(const u_char *, u_char *, size_t);
++int           ns_name_ntop(const u_char *, char *, size_t);
++int           ns_name_pton(const char *, u_char *, size_t);
++int           ns_name_unpack(const u_char *, const u_char *,
++                                  const u_char *, u_char *, size_t);
++int           ns_name_pack(const u_char *, u_char *, int,
++                                const u_char **, const u_char **);
++int           ns_name_uncompress(const u_char *, const u_char *,
++                                      const u_char *, char *, size_t);
++int           ns_name_compress(const char *, u_char *, size_t,
++                                    const u_char **, const u_char **);
++int           ns_name_skip(const u_char **, const u_char *);
++void          ns_name_rollback(const u_char *, const u_char **,
++                                    const u_char **);
++int           ns_sign(u_char *, int *, int, int, void *,
++                           const u_char *, int, u_char *, int *, time_t);
++int           ns_sign2(u_char *, int *, int, int, void *,
++                            const u_char *, int, u_char *, int *, time_t,
++                            u_char **, u_char **);
++int           ns_sign_tcp(u_char *, int *, int, int,
++                               ns_tcp_tsig_state *, int);
++int           ns_sign_tcp2(u_char *, int *, int, int,
++                                ns_tcp_tsig_state *, int,
++                                u_char **, u_char **);
++int           ns_sign_tcp_init(void *, const u_char *, int,
++                                      ns_tcp_tsig_state *);
++u_char                *ns_find_tsig(u_char *, u_char *);
++int           ns_verify(u_char *, int *, void *,
++                             const u_char *, int, u_char *, int *,
++                             time_t *, int);
++int           ns_verify_tcp(u_char *, int *, ns_tcp_tsig_state *, int);
++int           ns_verify_tcp_init(void *, const u_char *, int,
++                                      ns_tcp_tsig_state *);
++int           ns_samedomain(const char *, const char *);
++int           ns_subdomain(const char *, const char *);
++int           ns_makecanon(const char *, char *, size_t);
++int           ns_samename(const char *, const char *);
++__END_DECLS
++
++#ifdef BIND_4_COMPAT
++#include "arpa_nameser_compat.h"
++#endif
++
++#if 0
++#  include <logd.h>
++#  define  XLOG(...)   \
++    __libc_android_log_print(ANDROID_LOG_DEBUG,"libc",__VA_ARGS__)
++#else
++#define  XLOG(...)   do {} while (0)
++#endif
++
++#endif /* !_ARPA_NAMESER_H_ */
+Index: android-tools-4.2.2+git20130218/core/adbd/arpa_nameser_compat.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/arpa_nameser_compat.h    2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,236 @@
++/*    $NetBSD: nameser_compat.h,v 1.1.1.2 2004/11/07 01:28:27 christos Exp $  */
++
++/* Copyright (c) 1983, 1989
++ *    The Regents of the University of California.  All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. All advertising materials mentioning features or use of this software
++ *    must display the following acknowledgement:
++ *    This product includes software developed by the University of
++ *    California, Berkeley and its contributors.
++ * 4. Neither the name of the University nor the names of its contributors
++ *    may be used to endorse or promote products derived from this software
++ *    without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ */
++
++/*
++ *      from nameser.h        8.1 (Berkeley) 6/2/93
++ *    Id: nameser_compat.h,v 1.1.2.3.4.2 2004/07/01 04:43:41 marka Exp
++ */
++
++#ifndef _ARPA_NAMESER_COMPAT_
++#define       _ARPA_NAMESER_COMPAT_
++
++#define       __BIND          19950621        /* (DEAD) interface version stamp. */
++
++#include <endian.h>
++
++#ifndef BYTE_ORDER
++#if (BSD >= 199103)
++# include <machine/endian.h>
++#else
++#ifdef __linux
++# include <endian.h>
++#else
++#define       LITTLE_ENDIAN   1234    /* least-significant byte first (vax, pc) */
++#define       BIG_ENDIAN      4321    /* most-significant byte first (IBM, net) */
++#define       PDP_ENDIAN      3412    /* LSB first in word, MSW first in long (pdp)*/
++
++#if defined(vax) || defined(ns32000) || defined(sun386) || defined(i386) || \
++    defined(MIPSEL) || defined(_MIPSEL) || defined(BIT_ZERO_ON_RIGHT) || \
++    defined(__alpha__) || defined(__alpha) || \
++    (defined(__Lynx__) && defined(__x86__))
++#define BYTE_ORDER    LITTLE_ENDIAN
++#endif
++
++#if defined(sel) || defined(pyr) || defined(mc68000) || defined(sparc) || \
++    defined(is68k) || defined(tahoe) || defined(ibm032) || defined(ibm370) || \
++    defined(MIPSEB) || defined(_MIPSEB) || defined(_IBMR2) || defined(DGUX) ||\
++    defined(apollo) || defined(__convex__) || defined(_CRAY) || \
++    defined(__hppa) || defined(__hp9000) || \
++    defined(__hp9000s300) || defined(__hp9000s700) || \
++    defined(__hp3000s900) || defined(__hpux) || defined(MPE) || \
++    defined (BIT_ZERO_ON_LEFT) || defined(m68k) || defined(__sparc) ||  \
++    (defined(__Lynx__) && \
++     (defined(__68k__) || defined(__sparc__) || defined(__powerpc__)))
++#define BYTE_ORDER    BIG_ENDIAN
++#endif
++#endif /* __linux */
++#endif /* BSD */
++#endif /* BYTE_ORDER */
++
++#if !defined(BYTE_ORDER) || \
++    (BYTE_ORDER != BIG_ENDIAN && BYTE_ORDER != LITTLE_ENDIAN && \
++    BYTE_ORDER != PDP_ENDIAN)
++      /* you must determine what the correct bit order is for
++       * your compiler - the next line is an intentional error
++       * which will force your compiles to bomb until you fix
++       * the above macros.
++       */
++  #error "Undefined or invalid BYTE_ORDER";
++#endif
++
++/*
++ * Structure for query header.  The order of the fields is machine- and
++ * compiler-dependent, depending on the byte/bit order and the layout
++ * of bit fields.  We use bit fields only in int variables, as this
++ * is all ANSI requires.  This requires a somewhat confusing rearrangement.
++ */
++
++typedef struct {
++      unsigned        id :16;         /* query identification number */
++#if BYTE_ORDER == BIG_ENDIAN
++                      /* fields in third byte */
++      unsigned        qr: 1;          /* response flag */
++      unsigned        opcode: 4;      /* purpose of message */
++      unsigned        aa: 1;          /* authoritive answer */
++      unsigned        tc: 1;          /* truncated message */
++      unsigned        rd: 1;          /* recursion desired */
++                      /* fields in fourth byte */
++      unsigned        ra: 1;          /* recursion available */
++      unsigned        unused :1;      /* unused bits (MBZ as of 4.9.3a3) */
++      unsigned        ad: 1;          /* authentic data from named */
++      unsigned        cd: 1;          /* checking disabled by resolver */
++      unsigned        rcode :4;       /* response code */
++#endif
++#if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN
++                      /* fields in third byte */
++      unsigned        rd :1;          /* recursion desired */
++      unsigned        tc :1;          /* truncated message */
++      unsigned        aa :1;          /* authoritive answer */
++      unsigned        opcode :4;      /* purpose of message */
++      unsigned        qr :1;          /* response flag */
++                      /* fields in fourth byte */
++      unsigned        rcode :4;       /* response code */
++      unsigned        cd: 1;          /* checking disabled by resolver */
++      unsigned        ad: 1;          /* authentic data from named */
++      unsigned        unused :1;      /* unused bits (MBZ as of 4.9.3a3) */
++      unsigned        ra :1;          /* recursion available */
++#endif
++                      /* remaining bytes */
++      unsigned        qdcount :16;    /* number of question entries */
++      unsigned        ancount :16;    /* number of answer entries */
++      unsigned        nscount :16;    /* number of authority entries */
++      unsigned        arcount :16;    /* number of resource entries */
++} HEADER;
++
++#define PACKETSZ      NS_PACKETSZ
++#define MAXDNAME      NS_MAXDNAME
++#define MAXCDNAME     NS_MAXCDNAME
++#define MAXLABEL      NS_MAXLABEL
++#define       HFIXEDSZ        NS_HFIXEDSZ
++#define QFIXEDSZ      NS_QFIXEDSZ
++#define RRFIXEDSZ     NS_RRFIXEDSZ
++#define       INT32SZ         NS_INT32SZ
++#define       INT16SZ         NS_INT16SZ
++#define       INT8SZ          NS_INT8SZ
++#define       INADDRSZ        NS_INADDRSZ
++#define       IN6ADDRSZ       NS_IN6ADDRSZ
++#define       INDIR_MASK      NS_CMPRSFLGS
++#define NAMESERVER_PORT       NS_DEFAULTPORT
++
++#define S_ZONE                ns_s_zn
++#define S_PREREQ      ns_s_pr
++#define S_UPDATE      ns_s_ud
++#define S_ADDT                ns_s_ar
++
++#define QUERY         ns_o_query
++#define IQUERY                ns_o_iquery
++#define STATUS                ns_o_status
++#define       NS_NOTIFY_OP    ns_o_notify
++#define       NS_UPDATE_OP    ns_o_update
++
++#define NOERROR               ns_r_noerror
++#define FORMERR               ns_r_formerr
++#define SERVFAIL      ns_r_servfail
++#define NXDOMAIN      ns_r_nxdomain
++#define NOTIMP                ns_r_notimpl
++#define REFUSED               ns_r_refused
++#define YXDOMAIN      ns_r_yxdomain
++#define YXRRSET               ns_r_yxrrset
++#define NXRRSET               ns_r_nxrrset
++#define NOTAUTH               ns_r_notauth
++#define NOTZONE               ns_r_notzone
++/*#define BADSIG              ns_r_badsig*/
++/*#define BADKEY              ns_r_badkey*/
++/*#define BADTIME             ns_r_badtime*/
++
++
++#define DELETE                ns_uop_delete
++#define ADD           ns_uop_add
++
++#define T_A           ns_t_a
++#define T_NS          ns_t_ns
++#define T_MD          ns_t_md
++#define T_MF          ns_t_mf
++#define T_CNAME               ns_t_cname
++#define T_SOA         ns_t_soa
++#define T_MB          ns_t_mb
++#define T_MG          ns_t_mg
++#define T_MR          ns_t_mr
++#define T_NULL                ns_t_null
++#define T_WKS         ns_t_wks
++#define T_PTR         ns_t_ptr
++#define T_HINFO               ns_t_hinfo
++#define T_MINFO               ns_t_minfo
++#define T_MX          ns_t_mx
++#define T_TXT         ns_t_txt
++#define       T_RP            ns_t_rp
++#define T_AFSDB               ns_t_afsdb
++#define T_X25         ns_t_x25
++#define T_ISDN                ns_t_isdn
++#define T_RT          ns_t_rt
++#define T_NSAP                ns_t_nsap
++#define T_NSAP_PTR    ns_t_nsap_ptr
++#define       T_SIG           ns_t_sig
++#define       T_KEY           ns_t_key
++#define       T_PX            ns_t_px
++#define       T_GPOS          ns_t_gpos
++#define       T_AAAA          ns_t_aaaa
++#define       T_LOC           ns_t_loc
++#define       T_NXT           ns_t_nxt
++#define       T_EID           ns_t_eid
++#define       T_NIMLOC        ns_t_nimloc
++#define       T_SRV           ns_t_srv
++#define T_ATMA                ns_t_atma
++#define T_NAPTR               ns_t_naptr
++#define T_A6          ns_t_a6
++#define       T_TSIG          ns_t_tsig
++#define       T_IXFR          ns_t_ixfr
++#define T_AXFR                ns_t_axfr
++#define T_MAILB               ns_t_mailb
++#define T_MAILA               ns_t_maila
++#define T_ANY         ns_t_any
++
++#define C_IN          ns_c_in
++#define C_CHAOS               ns_c_chaos
++#define C_HS          ns_c_hs
++/* BIND_UPDATE */
++#define C_NONE                ns_c_none
++#define C_ANY         ns_c_any
++
++#define       GETSHORT                NS_GET16
++#define       GETLONG                 NS_GET32
++#define       PUTSHORT                NS_PUT16
++#define       PUTLONG                 NS_PUT32
++
++#endif /* _ARPA_NAMESER_COMPAT_ */
+Index: android-tools-4.2.2+git20130218/core/adbd/backup_service.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/backup_service.c 2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,155 @@
++/*
++ * Copyright (C) 2011 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include <unistd.h>
++#include <stdio.h>
++
++#include "sysdeps.h"
++
++#define TRACE_TAG  TRACE_ADB
++#include "adb.h"
++
++typedef struct {
++    pid_t pid;
++    int fd;
++} backup_harvest_params;
++
++// socketpair but do *not* mark as close_on_exec
++static int backup_socketpair(int sv[2]) {
++    int rc = unix_socketpair( AF_UNIX, SOCK_STREAM, 0, sv );
++    if (rc < 0)
++        return -1;
++
++    return 0;
++}
++
++// harvest the child process then close the read end of the socketpair
++static void* backup_child_waiter(void* args) {
++    int status;
++    backup_harvest_params* params = (backup_harvest_params*) args;
++
++    waitpid(params->pid, &status, 0);
++    adb_close(params->fd);
++    free(params);
++    return NULL;
++}
++
++/* returns the data socket passing the backup data here for forwarding */
++int backup_service(BackupOperation op, char* args) {
++    pid_t pid;
++    int s[2];
++    char* operation;
++    int socketnum;
++
++    // Command string and choice of stdin/stdout for the pipe depend on our invocation
++    if (op == BACKUP) {
++        operation = "backup";
++        socketnum = STDOUT_FILENO;
++    } else {
++        operation = "restore";
++        socketnum = STDIN_FILENO;
++    }
++
++    D("backup_service(%s, %s)\n", operation, args);
++
++    // set up the pipe from the subprocess to here
++    // parent will read s[0]; child will write s[1]
++    if (backup_socketpair(s)) {
++        D("can't create backup/restore socketpair\n");
++        fprintf(stderr, "unable to create backup/restore socketpair\n");
++        return -1;
++    }
++
++    D("Backup/restore socket pair: (send=%d, receive=%d)\n", s[1], s[0]);
++    close_on_exec(s[0]);    // only the side we hold on to
++
++    // spin off the child process to run the backup command
++    pid = fork();
++    if (pid < 0) {
++        // failure
++        D("can't fork for %s\n", operation);
++        fprintf(stderr, "unable to fork for %s\n", operation);
++        adb_close(s[0]);
++        adb_close(s[1]);
++        return -1;
++    }
++
++    // Great, we're off and running.
++    if (pid == 0) {
++        // child -- actually run the backup here
++        char* p;
++        int argc;
++        char portnum[16];
++        char** bu_args;
++
++        // fixed args:  [0] is 'bu', [1] is the port number, [2] is the 'operation' string
++        argc = 3;
++        for (p = (char*)args; p && *p; ) {
++            argc++;
++            while (*p && *p != ':') p++;
++            if (*p == ':') p++;
++        }
++
++        bu_args = (char**) alloca(argc*sizeof(char*) + 1);
++
++        // run through again to build the argv array
++        argc = 0;
++        bu_args[argc++] = "bu";
++        snprintf(portnum, sizeof(portnum), "%d", s[1]);
++        bu_args[argc++] = portnum;
++        bu_args[argc++] = operation;
++        for (p = (char*)args; p && *p; ) {
++            bu_args[argc++] = p;
++            while (*p && *p != ':') p++;
++            if (*p == ':') {
++                *p = 0;
++                p++;
++            }
++        }
++        bu_args[argc] = NULL;
++
++        // Close the half of the socket that we don't care about, route 'bu's console
++        // to the output socket, and off we go
++        adb_close(s[0]);
++
++        // off we go
++        execvp("/system/bin/bu", (char * const *)bu_args);
++        // oops error - close up shop and go home
++        fprintf(stderr, "Unable to exec 'bu', bailing\n");
++        exit(-1);
++    } else {
++        adb_thread_t t;
++        backup_harvest_params* params;
++
++        // parent, i.e. adbd -- close the sending half of the socket
++        D("fork() returned pid %d\n", pid);
++        adb_close(s[1]);
++
++        // spin a thread to harvest the child process
++        params = (backup_harvest_params*) malloc(sizeof(backup_harvest_params));
++        params->pid = pid;
++        params->fd = s[0];
++        if (adb_thread_create(&t, backup_child_waiter, params)) {
++            adb_close(s[0]);
++            free(params);
++            D("Unable to create child harvester\n");
++            return -1;
++        }
++    }
++
++    // we'll be reading from s[0] as the data is sent by the child process
++    return s[0];
++}
+Index: android-tools-4.2.2+git20130218/core/adbd/base64.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/base64.c 2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,340 @@
++/*    $NetBSD: base64.c,v 1.8 2002/11/11 01:15:17 thorpej Exp $       */
++
++/*
++ * Copyright (c) 1996 by Internet Software Consortium.
++ *
++ * Permission to use, copy, modify, and distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
++ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
++ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
++ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
++ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
++ * SOFTWARE.
++ */
++
++/*
++ * Portions Copyright (c) 1995 by International Business Machines, Inc.
++ *
++ * International Business Machines, Inc. (hereinafter called IBM) grants
++ * permission under its copyrights to use, copy, modify, and distribute this
++ * Software with or without fee, provided that the above copyright notice and
++ * all paragraphs of this notice appear in all copies, and that the name of IBM
++ * not be used in connection with the marketing of any product incorporating
++ * the Software or modifications thereof, without specific, written prior
++ * permission.
++ *
++ * To the extent it has a right to do so, IBM grants an immunity from suit
++ * under its patents, if any, for the use, sale or manufacture of products to
++ * the extent that such products are used for performing Domain Name System
++ * dynamic updates in TCP/IP networks by means of the Software.  No immunity is
++ * granted for any product per se or for any other function of any product.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
++ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
++ * PARTICULAR PURPOSE.  IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
++ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
++ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
++ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
++ */
++
++#include <sys/cdefs.h>
++#if defined(LIBC_SCCS) && !defined(lint)
++__RCSID("$NetBSD: base64.c,v 1.8 2002/11/11 01:15:17 thorpej Exp $");
++#endif /* LIBC_SCCS and not lint */
++
++#include <sys/types.h>
++#include <sys/param.h>
++#include <sys/socket.h>
++#include <netinet/in.h>
++#include <arpa/inet.h>
++#include "arpa_nameser.h"
++
++#include <assert.h>
++#include <ctype.h>
++#ifdef ANDROID_CHANGES
++#include "resolv_private.h"
++#else
++#include <resolv.h>
++#endif
++#include <stdio.h>
++
++#include <stdlib.h>
++#include <string.h>
++
++static const char Base64[] =
++      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
++static const char Pad64 = '=';
++
++/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
++   The following encoding technique is taken from RFC 1521 by Borenstein
++   and Freed.  It is reproduced here in a slightly edited form for
++   convenience.
++
++   A 65-character subset of US-ASCII is used, enabling 6 bits to be
++   represented per printable character. (The extra 65th character, "=",
++   is used to signify a special processing function.)
++
++   The encoding process represents 24-bit groups of input bits as output
++   strings of 4 encoded characters. Proceeding from left to right, a
++   24-bit input group is formed by concatenating 3 8-bit input groups.
++   These 24 bits are then treated as 4 concatenated 6-bit groups, each
++   of which is translated into a single digit in the base64 alphabet.
++
++   Each 6-bit group is used as an index into an array of 64 printable
++   characters. The character referenced by the index is placed in the
++   output string.
++
++                         Table 1: The Base64 Alphabet
++
++      Value Encoding  Value Encoding  Value Encoding  Value Encoding
++          0 A            17 R            34 i            51 z
++          1 B            18 S            35 j            52 0
++          2 C            19 T            36 k            53 1
++          3 D            20 U            37 l            54 2
++          4 E            21 V            38 m            55 3
++          5 F            22 W            39 n            56 4
++          6 G            23 X            40 o            57 5
++          7 H            24 Y            41 p            58 6
++          8 I            25 Z            42 q            59 7
++          9 J            26 a            43 r            60 8
++         10 K            27 b            44 s            61 9
++         11 L            28 c            45 t            62 +
++         12 M            29 d            46 u            63 /
++         13 N            30 e            47 v
++         14 O            31 f            48 w         (pad) =
++         15 P            32 g            49 x
++         16 Q            33 h            50 y
++
++   Special processing is performed if fewer than 24 bits are available
++   at the end of the data being encoded.  A full encoding quantum is
++   always completed at the end of a quantity.  When fewer than 24 input
++   bits are available in an input group, zero bits are added (on the
++   right) to form an integral number of 6-bit groups.  Padding at the
++   end of the data is performed using the '=' character.
++
++   Since all base64 input is an integral number of octets, only the
++         -------------------------------------------------
++   following cases can arise:
++
++       (1) the final quantum of encoding input is an integral
++           multiple of 24 bits; here, the final unit of encoded
++         output will be an integral multiple of 4 characters
++         with no "=" padding,
++       (2) the final quantum of encoding input is exactly 8 bits;
++           here, the final unit of encoded output will be two
++         characters followed by two "=" padding characters, or
++       (3) the final quantum of encoding input is exactly 16 bits;
++           here, the final unit of encoded output will be three
++         characters followed by one "=" padding character.
++   */
++
++int
++b64_ntop(src, srclength, target, targsize)
++      u_char const *src;
++      size_t srclength;
++      char *target;
++      size_t targsize;
++{
++      size_t datalength = 0;
++      u_char input[3] = { 0, 0, 0 };  /* make compiler happy */
++      u_char output[4];
++      size_t i;
++
++      assert(src != NULL);
++      assert(target != NULL);
++
++      while (2 < srclength) {
++              input[0] = *src++;
++              input[1] = *src++;
++              input[2] = *src++;
++              srclength -= 3;
++
++              output[0] = (u_int32_t)input[0] >> 2;
++              output[1] = ((u_int32_t)(input[0] & 0x03) << 4) +
++                  ((u_int32_t)input[1] >> 4);
++              output[2] = ((u_int32_t)(input[1] & 0x0f) << 2) +
++                  ((u_int32_t)input[2] >> 6);
++              output[3] = input[2] & 0x3f;
++              assert(output[0] < 64);
++              assert(output[1] < 64);
++              assert(output[2] < 64);
++              assert(output[3] < 64);
++
++              if (datalength + 4 > targsize)
++                      return (-1);
++              target[datalength++] = Base64[output[0]];
++              target[datalength++] = Base64[output[1]];
++              target[datalength++] = Base64[output[2]];
++              target[datalength++] = Base64[output[3]];
++      }
++
++      /* Now we worry about padding. */
++      if (0 != srclength) {
++              /* Get what's left. */
++              input[0] = input[1] = input[2] = '\0';
++              for (i = 0; i < srclength; i++)
++                      input[i] = *src++;
++
++              output[0] = (u_int32_t)input[0] >> 2;
++              output[1] = ((u_int32_t)(input[0] & 0x03) << 4) +
++                  ((u_int32_t)input[1] >> 4);
++              output[2] = ((u_int32_t)(input[1] & 0x0f) << 2) +
++                  ((u_int32_t)input[2] >> 6);
++              assert(output[0] < 64);
++              assert(output[1] < 64);
++              assert(output[2] < 64);
++
++              if (datalength + 4 > targsize)
++                      return (-1);
++              target[datalength++] = Base64[output[0]];
++              target[datalength++] = Base64[output[1]];
++              if (srclength == 1)
++                      target[datalength++] = Pad64;
++              else
++                      target[datalength++] = Base64[output[2]];
++              target[datalength++] = Pad64;
++      }
++      if (datalength >= targsize)
++              return (-1);
++      target[datalength] = '\0';      /* Returned value doesn't count \0. */
++      return (datalength);
++}
++
++/* skips all whitespace anywhere.
++   converts characters, four at a time, starting at (or after)
++   src from base - 64 numbers into three 8 bit bytes in the target area.
++   it returns the number of data bytes stored at the target, or -1 on error.
++ */
++
++int
++b64_pton(src, target, targsize)
++      char const *src;
++      u_char *target;
++      size_t targsize;
++{
++      size_t tarindex;
++      int state, ch;
++      char *pos;
++
++      assert(src != NULL);
++      assert(target != NULL);
++
++      state = 0;
++      tarindex = 0;
++
++      while ((ch = (u_char) *src++) != '\0') {
++              if (isspace(ch))        /* Skip whitespace anywhere. */
++                      continue;
++
++              if (ch == Pad64)
++                      break;
++
++              pos = strchr(Base64, ch);
++              if (pos == 0)           /* A non-base64 character. */
++                      return (-1);
++
++              switch (state) {
++              case 0:
++                      if (target) {
++                              if (tarindex >= targsize)
++                                      return (-1);
++                              target[tarindex] = (pos - Base64) << 2;
++                      }
++                      state = 1;
++                      break;
++              case 1:
++                      if (target) {
++                              if (tarindex + 1 >= targsize)
++                                      return (-1);
++                              target[tarindex] |=
++                                  (u_int32_t)(pos - Base64) >> 4;
++                              target[tarindex+1]  = ((pos - Base64) & 0x0f)
++                                                      << 4 ;
++                      }
++                      tarindex++;
++                      state = 2;
++                      break;
++              case 2:
++                      if (target) {
++                              if (tarindex + 1 >= targsize)
++                                      return (-1);
++                              target[tarindex] |=
++                                      (u_int32_t)(pos - Base64) >> 2;
++                              target[tarindex+1] = ((pos - Base64) & 0x03)
++                                                      << 6;
++                      }
++                      tarindex++;
++                      state = 3;
++                      break;
++              case 3:
++                      if (target) {
++                              if (tarindex >= targsize)
++                                      return (-1);
++                              target[tarindex] |= (pos - Base64);
++                      }
++                      tarindex++;
++                      state = 0;
++                      break;
++              default:
++                      abort();
++              }
++      }
++
++      /*
++       * We are done decoding Base-64 chars.  Let's see if we ended
++       * on a byte boundary, and/or with erroneous trailing characters.
++       */
++
++      if (ch == Pad64) {              /* We got a pad char. */
++              ch = *src++;            /* Skip it, get next. */
++              switch (state) {
++              case 0:         /* Invalid = in first position */
++              case 1:         /* Invalid = in second position */
++                      return (-1);
++
++              case 2:         /* Valid, means one byte of info */
++                      /* Skip any number of spaces. */
++                      for (; ch != '\0'; ch = (u_char) *src++)
++                              if (!isspace(ch))
++                                      break;
++                      /* Make sure there is another trailing = sign. */
++                      if (ch != Pad64)
++                              return (-1);
++                      ch = *src++;            /* Skip the = */
++                      /* Fall through to "single trailing =" case. */
++                      /* FALLTHROUGH */
++
++              case 3:         /* Valid, means two bytes of info */
++                      /*
++                       * We know this char is an =.  Is there anything but
++                       * whitespace after it?
++                       */
++                      for (; ch != '\0'; ch = (u_char) *src++)
++                              if (!isspace(ch))
++                                      return (-1);
++
++                      /*
++                       * Now make sure for cases 2 and 3 that the "extra"
++                       * bits that slopped past the last full byte were
++                       * zeros.  If we don't check them, they become a
++                       * subliminal channel.
++                       */
++                      if (target && target[tarindex] != 0)
++                              return (-1);
++              }
++      } else {
++              /*
++               * We ended by seeing the end of the string.  Make sure we
++               * have no partial bytes lying around.
++               */
++              if (state != 0)
++                      return (-1);
++      }
++
++      return (tarindex);
++}
+Index: android-tools-4.2.2+git20130218/core/adbd/commandline.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/commandline.c    2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,1743 @@
++/*
++ * Copyright (C) 2007 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <errno.h>
++#include <unistd.h>
++#include <limits.h>
++#include <stdarg.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <ctype.h>
++#include <assert.h>
++
++#include "sysdeps.h"
++
++#ifdef HAVE_TERMIO_H
++#include <termios.h>
++#endif
++
++#define  TRACE_TAG  TRACE_ADB
++#include "adb.h"
++#include "adb_client.h"
++#include "file_sync_service.h"
++
++static int do_cmd(transport_type ttype, char* serial, char *cmd, ...);
++
++void get_my_path(char *s, size_t maxLen);
++int find_sync_dirs(const char *srcarg,
++        char **android_srcdir_out, char **data_srcdir_out);
++int install_app(transport_type transport, char* serial, int argc, char** argv);
++int uninstall_app(transport_type transport, char* serial, int argc, char** argv);
++
++static const char *gProductOutPath = NULL;
++extern int gListenAll;
++
++static char *product_file(const char *extra)
++{
++    int n;
++    char *x;
++
++    if (gProductOutPath == NULL) {
++        fprintf(stderr, "adb: Product directory not specified; "
++                "use -p or define ANDROID_PRODUCT_OUT\n");
++        exit(1);
++    }
++
++    n = strlen(gProductOutPath) + strlen(extra) + 2;
++    x = malloc(n);
++    if (x == 0) {
++        fprintf(stderr, "adb: Out of memory (product_file())\n");
++        exit(1);
++    }
++
++    snprintf(x, (size_t)n, "%s" OS_PATH_SEPARATOR_STR "%s", gProductOutPath, extra);
++    return x;
++}
++
++void version(FILE * out) {
++    fprintf(out, "Android Debug Bridge version %d.%d.%d\n",
++         ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION);
++}
++
++void help()
++{
++    version(stderr);
++
++    fprintf(stderr,
++        "\n"
++        " -a                            - directs adb to listen on all interfaces for a connection\n"
++        " -d                            - directs command to the only connected USB device\n"
++        "                                 returns an error if more than one USB device is present.\n"
++        " -e                            - directs command to the only running emulator.\n"
++        "                                 returns an error if more than one emulator is running.\n"
++        " -s <specific device>          - directs command to the device or emulator with the given\n"
++        "                                 serial number or qualifier. Overrides ANDROID_SERIAL\n"
++        "                                 environment variable.\n"
++        " -p <product name or path>     - simple product name like 'sooner', or\n"
++        "                                 a relative/absolute path to a product\n"
++        "                                 out directory like 'out/target/product/sooner'.\n"
++        "                                 If -p is not specified, the ANDROID_PRODUCT_OUT\n"
++        "                                 environment variable is used, which must\n"
++        "                                 be an absolute path.\n"
++        " -H                            - Name of adb server host (default: localhost)\n"
++        " -P                            - Port of adb server (default: 5037)\n"
++        " devices [-l]                  - list all connected devices\n"
++        "                                 ('-l' will also list device qualifiers)\n"
++        " connect <host>[:<port>]       - connect to a device via TCP/IP\n"
++        "                                 Port 5555 is used by default if no port number is specified.\n"
++        " disconnect [<host>[:<port>]]  - disconnect from a TCP/IP device.\n"
++        "                                 Port 5555 is used by default if no port number is specified.\n"
++        "                                 Using this command with no additional arguments\n"
++        "                                 will disconnect from all connected TCP/IP devices.\n"
++        "\n"
++        "device commands:\n"
++        "  adb push <local> <remote>    - copy file/dir to device\n"
++        "  adb pull <remote> [<local>]  - copy file/dir from device\n"
++        "  adb sync [ <directory> ]     - copy host->device only if changed\n"
++        "                                 (-l means list but don't copy)\n"
++        "                                 (see 'adb help all')\n"
++        "  adb shell                    - run remote shell interactively\n"
++        "  adb shell <command>          - run remote shell command\n"
++        "  adb emu <command>            - run emulator console command\n"
++        "  adb logcat [ <filter-spec> ] - View device log\n"
++        "  adb forward --list           - list all forward socket connections.\n"
++        "                                 the format is a list of lines with the following format:\n"
++        "                                    <serial> \" \" <local> \" \" <remote> \"\\n\"\n"
++        "  adb forward <local> <remote> - forward socket connections\n"
++        "                                 forward specs are one of: \n"
++        "                                   tcp:<port>\n"
++        "                                   localabstract:<unix domain socket name>\n"
++        "                                   localreserved:<unix domain socket name>\n"
++        "                                   localfilesystem:<unix domain socket name>\n"
++        "                                   dev:<character device name>\n"
++        "                                   jdwp:<process pid> (remote only)\n"
++        "  adb forward --no-rebind <local> <remote>\n"
++        "                               - same as 'adb forward <local> <remote>' but fails\n"
++        "                                 if <local> is already forwarded\n"
++        "  adb forward --remove <local> - remove a specific forward socket connection\n"
++        "  adb forward --remove-all     - remove all forward socket connections\n"
++        "  adb jdwp                     - list PIDs of processes hosting a JDWP transport\n"
++        "  adb install [-l] [-r] [-s] [--algo <algorithm name> --key <hex-encoded key> --iv <hex-encoded iv>] <file>\n"
++        "                               - push this package file to the device and install it\n"
++        "                                 ('-l' means forward-lock the app)\n"
++        "                                 ('-r' means reinstall the app, keeping its data)\n"
++        "                                 ('-s' means install on SD card instead of internal storage)\n"
++        "                                 ('--algo', '--key', and '--iv' mean the file is encrypted already)\n"
++        "  adb uninstall [-k] <package> - remove this app package from the device\n"
++        "                                 ('-k' means keep the data and cache directories)\n"
++        "  adb bugreport                - return all information from the device\n"
++        "                                 that should be included in a bug report.\n"
++        "\n"
++        "  adb backup [-f <file>] [-apk|-noapk] [-shared|-noshared] [-all] [-system|-nosystem] [<packages...>]\n"
++        "                               - write an archive of the device's data to <file>.\n"
++        "                                 If no -f option is supplied then the data is written\n"
++        "                                 to \"backup.ab\" in the current directory.\n"
++        "                                 (-apk|-noapk enable/disable backup of the .apks themselves\n"
++        "                                    in the archive; the default is noapk.)\n"
++        "                                 (-shared|-noshared enable/disable backup of the device's\n"
++        "                                    shared storage / SD card contents; the default is noshared.)\n"
++        "                                 (-all means to back up all installed applications)\n"
++        "                                 (-system|-nosystem toggles whether -all automatically includes\n"
++        "                                    system applications; the default is to include system apps)\n"
++        "                                 (<packages...> is the list of applications to be backed up.  If\n"
++        "                                    the -all or -shared flags are passed, then the package\n"
++        "                                    list is optional.  Applications explicitly given on the\n"
++        "                                    command line will be included even if -nosystem would\n"
++        "                                    ordinarily cause them to be omitted.)\n"
++        "\n"
++        "  adb restore <file>           - restore device contents from the <file> backup archive\n"
++        "\n"
++        "  adb help                     - show this help message\n"
++        "  adb version                  - show version num\n"
++        "\n"
++        "scripting:\n"
++        "  adb wait-for-device          - block until device is online\n"
++        "  adb start-server             - ensure that there is a server running\n"
++        "  adb kill-server              - kill the server if it is running\n"
++        "  adb get-state                - prints: offline | bootloader | device\n"
++        "  adb get-serialno             - prints: <serial-number>\n"
++        "  adb get-devpath              - prints: <device-path>\n"
++        "  adb status-window            - continuously print device status for a specified device\n"
++        "  adb remount                  - remounts the /system partition on the device read-write\n"
++        "  adb reboot [bootloader|recovery] - reboots the device, optionally into the bootloader or recovery program\n"
++        "  adb reboot-bootloader        - reboots the device into the bootloader\n"
++        "  adb root                     - restarts the adbd daemon with root permissions\n"
++        "  adb usb                      - restarts the adbd daemon listening on USB\n"
++        "  adb tcpip <port>             - restarts the adbd daemon listening on TCP on the specified port"
++        "\n"
++        "networking:\n"
++        "  adb ppp <tty> [parameters]   - Run PPP over USB.\n"
++        " Note: you should not automatically start a PPP connection.\n"
++        " <tty> refers to the tty for PPP stream. Eg. dev:/dev/omap_csmi_tty1\n"
++        " [parameters] - Eg. defaultroute debug dump local notty usepeerdns\n"
++        "\n"
++        "adb sync notes: adb sync [ <directory> ]\n"
++        "  <localdir> can be interpreted in several ways:\n"
++        "\n"
++        "  - If <directory> is not specified, both /system and /data partitions will be updated.\n"
++        "\n"
++        "  - If it is \"system\" or \"data\", only the corresponding partition\n"
++        "    is updated.\n"
++        "\n"
++        "environmental variables:\n"
++        "  ADB_TRACE                    - Print debug information. A comma separated list of the following values\n"
++        "                                 1 or all, adb, sockets, packets, rwx, usb, sync, sysdeps, transport, jdwp\n"
++        "  ANDROID_SERIAL               - The serial number to connect to. -s takes priority over this if given.\n"
++        "  ANDROID_LOG_TAGS             - When used with the logcat option, only these debug tags are printed.\n"
++        );
++}
++
++int usage()
++{
++    help();
++    return 1;
++}
++
++#ifdef HAVE_TERMIO_H
++static struct termios tio_save;
++
++static void stdin_raw_init(int fd)
++{
++    struct termios tio;
++
++    if(tcgetattr(fd, &tio)) return;
++    if(tcgetattr(fd, &tio_save)) return;
++
++    tio.c_lflag = 0; /* disable CANON, ECHO*, etc */
++
++        /* no timeout but request at least one character per read */
++    tio.c_cc[VTIME] = 0;
++    tio.c_cc[VMIN] = 1;
++
++    tcsetattr(fd, TCSANOW, &tio);
++    tcflush(fd, TCIFLUSH);
++}
++
++static void stdin_raw_restore(int fd)
++{
++    tcsetattr(fd, TCSANOW, &tio_save);
++    tcflush(fd, TCIFLUSH);
++}
++#endif
++
++static void read_and_dump(int fd)
++{
++    char buf[4096];
++    int len;
++
++    while(fd >= 0) {
++        D("read_and_dump(): pre adb_read(fd=%d)\n", fd);
++        len = adb_read(fd, buf, 4096);
++        D("read_and_dump(): post adb_read(fd=%d): len=%d\n", fd, len);
++        if(len == 0) {
++            break;
++        }
++
++        if(len < 0) {
++            if(errno == EINTR) continue;
++            break;
++        }
++        fwrite(buf, 1, len, stdout);
++        fflush(stdout);
++    }
++}
++
++static void copy_to_file(int inFd, int outFd) {
++    const size_t BUFSIZE = 32 * 1024;
++    char* buf = (char*) malloc(BUFSIZE);
++    int len;
++    long total = 0;
++
++    D("copy_to_file(%d -> %d)\n", inFd, outFd);
++    for (;;) {
++        len = adb_read(inFd, buf, BUFSIZE);
++        if (len == 0) {
++            D("copy_to_file() : read 0 bytes; exiting\n");
++            break;
++        }
++        if (len < 0) {
++            if (errno == EINTR) {
++                D("copy_to_file() : EINTR, retrying\n");
++                continue;
++            }
++            D("copy_to_file() : error %d\n", errno);
++            break;
++        }
++        adb_write(outFd, buf, len);
++        total += len;
++    }
++    D("copy_to_file() finished after %lu bytes\n", total);
++    free(buf);
++}
++
++static void *stdin_read_thread(void *x)
++{
++    int fd, fdi;
++    unsigned char buf[1024];
++    int r, n;
++    int state = 0;
++
++    int *fds = (int*) x;
++    fd = fds[0];
++    fdi = fds[1];
++    free(fds);
++
++    for(;;) {
++        /* fdi is really the client's stdin, so use read, not adb_read here */
++        D("stdin_read_thread(): pre unix_read(fdi=%d,...)\n", fdi);
++        r = unix_read(fdi, buf, 1024);
++        D("stdin_read_thread(): post unix_read(fdi=%d,...)\n", fdi);
++        if(r == 0) break;
++        if(r < 0) {
++            if(errno == EINTR) continue;
++            break;
++        }
++        for(n = 0; n < r; n++){
++            switch(buf[n]) {
++            case '\n':
++                state = 1;
++                break;
++            case '\r':
++                state = 1;
++                break;
++            case '~':
++                if(state == 1) state++;
++                break;
++            case '.':
++                if(state == 2) {
++                    fprintf(stderr,"\n* disconnect *\n");
++#ifdef HAVE_TERMIO_H
++                    stdin_raw_restore(fdi);
++#endif
++                    exit(0);
++                }
++            default:
++                state = 0;
++            }
++        }
++        r = adb_write(fd, buf, r);
++        if(r <= 0) {
++            break;
++        }
++    }
++    return 0;
++}
++
++int interactive_shell(void)
++{
++    adb_thread_t thr;
++    int fdi, fd;
++    int *fds;
++
++    fd = adb_connect("shell:");
++    if(fd < 0) {
++        fprintf(stderr,"error: %s\n", adb_error());
++        return 1;
++    }
++    fdi = 0; //dup(0);
++
++    fds = malloc(sizeof(int) * 2);
++    fds[0] = fd;
++    fds[1] = fdi;
++
++#ifdef HAVE_TERMIO_H
++    stdin_raw_init(fdi);
++#endif
++    adb_thread_create(&thr, stdin_read_thread, fds);
++    read_and_dump(fd);
++#ifdef HAVE_TERMIO_H
++    stdin_raw_restore(fdi);
++#endif
++    return 0;
++}
++
++
++static void format_host_command(char* buffer, size_t  buflen, const char* command, transport_type ttype, const char* serial)
++{
++    if (serial) {
++        snprintf(buffer, buflen, "host-serial:%s:%s", serial, command);
++    } else {
++        const char* prefix = "host";
++        if (ttype == kTransportUsb)
++            prefix = "host-usb";
++        else if (ttype == kTransportLocal)
++            prefix = "host-local";
++
++        snprintf(buffer, buflen, "%s:%s", prefix, command);
++    }
++}
++
++int adb_download_buffer(const char *service, const void* data, int sz,
++                        unsigned progress)
++{
++    char buf[4096];
++    unsigned total;
++    int fd;
++    const unsigned char *ptr;
++
++    sprintf(buf,"%s:%d", service, sz);
++    fd = adb_connect(buf);
++    if(fd < 0) {
++        fprintf(stderr,"error: %s\n", adb_error());
++        return -1;
++    }
++
++    int opt = CHUNK_SIZE;
++    opt = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt));
++
++    total = sz;
++    ptr = data;
++
++    if(progress) {
++        char *x = strrchr(service, ':');
++        if(x) service = x + 1;
++    }
++
++    while(sz > 0) {
++        unsigned xfer = (sz > CHUNK_SIZE) ? CHUNK_SIZE : sz;
++        if(writex(fd, ptr, xfer)) {
++            adb_status(fd);
++            fprintf(stderr,"* failed to write data '%s' *\n", adb_error());
++            return -1;
++        }
++        sz -= xfer;
++        ptr += xfer;
++        if(progress) {
++            printf("sending: '%s' %4d%%    \r", service, (int)(100LL - ((100LL * sz) / (total))));
++            fflush(stdout);
++        }
++    }
++    if(progress) {
++        printf("\n");
++    }
++
++    if(readx(fd, buf, 4)){
++        fprintf(stderr,"* error reading response *\n");
++        adb_close(fd);
++        return -1;
++    }
++    if(memcmp(buf, "OKAY", 4)) {
++        buf[4] = 0;
++        fprintf(stderr,"* error response '%s' *\n", buf);
++        adb_close(fd);
++        return -1;
++    }
++
++    adb_close(fd);
++    return 0;
++}
++
++
++int adb_download(const char *service, const char *fn, unsigned progress)
++{
++    void *data;
++    unsigned sz;
++
++    data = load_file(fn, &sz);
++    if(data == 0) {
++        fprintf(stderr,"* cannot read '%s' *\n", service);
++        return -1;
++    }
++
++    int status = adb_download_buffer(service, data, sz, progress);
++    free(data);
++    return status;
++}
++
++static void status_window(transport_type ttype, const char* serial)
++{
++    char command[4096];
++    char *state = 0;
++    char *laststate = 0;
++
++        /* silence stderr */
++#ifdef _WIN32
++    /* XXX: TODO */
++#else
++    int  fd;
++    fd = unix_open("/dev/null", O_WRONLY);
++    dup2(fd, 2);
++    adb_close(fd);
++#endif
++
++    format_host_command(command, sizeof command, "get-state", ttype, serial);
++
++    for(;;) {
++        adb_sleep_ms(250);
++
++        if(state) {
++            free(state);
++            state = 0;
++        }
++
++        state = adb_query(command);
++
++        if(state) {
++            if(laststate && !strcmp(state,laststate)){
++                continue;
++            } else {
++                if(laststate) free(laststate);
++                laststate = strdup(state);
++            }
++        }
++
++        printf("%c[2J%c[2H", 27, 27);
++        printf("Android Debug Bridge\n");
++        printf("State: %s\n", state ? state : "offline");
++        fflush(stdout);
++    }
++}
++
++/** duplicate string and quote all \ " ( ) chars + space character. */
++static char *
++dupAndQuote(const char *s)
++{
++    const char *ts;
++    size_t alloc_len;
++    char *ret;
++    char *dest;
++
++    ts = s;
++
++    alloc_len = 0;
++
++    for( ;*ts != '\0'; ts++) {
++        alloc_len++;
++        if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
++            alloc_len++;
++        }
++    }
++
++    ret = (char *)malloc(alloc_len + 1);
++
++    ts = s;
++    dest = ret;
++
++    for ( ;*ts != '\0'; ts++) {
++        if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
++            *dest++ = '\\';
++        }
++
++        *dest++ = *ts;
++    }
++
++    *dest++ = '\0';
++
++    return ret;
++}
++
++/**
++ * Run ppp in "notty" mode against a resource listed as the first parameter
++ * eg:
++ *
++ * ppp dev:/dev/omap_csmi_tty0 <ppp options>
++ *
++ */
++int ppp(int argc, char **argv)
++{
++#ifdef HAVE_WIN32_PROC
++    fprintf(stderr, "error: adb %s not implemented on Win32\n", argv[0]);
++    return -1;
++#else
++    char *adb_service_name;
++    pid_t pid;
++    int fd;
++
++    if (argc < 2) {
++        fprintf(stderr, "usage: adb %s <adb service name> [ppp opts]\n",
++                argv[0]);
++
++        return 1;
++    }
++
++    adb_service_name = argv[1];
++
++    fd = adb_connect(adb_service_name);
++
++    if(fd < 0) {
++        fprintf(stderr,"Error: Could not open adb service: %s. Error: %s\n",
++                adb_service_name, adb_error());
++        return 1;
++    }
++
++    pid = fork();
++
++    if (pid < 0) {
++        perror("from fork()");
++        return 1;
++    } else if (pid == 0) {
++        int err;
++        int i;
++        const char **ppp_args;
++
++        // copy args
++        ppp_args = (const char **) alloca(sizeof(char *) * argc + 1);
++        ppp_args[0] = "pppd";
++        for (i = 2 ; i < argc ; i++) {
++            //argv[2] and beyond become ppp_args[1] and beyond
++            ppp_args[i - 1] = argv[i];
++        }
++        ppp_args[i-1] = NULL;
++
++        // child side
++
++        dup2(fd, STDIN_FILENO);
++        dup2(fd, STDOUT_FILENO);
++        adb_close(STDERR_FILENO);
++        adb_close(fd);
++
++        err = execvp("pppd", (char * const *)ppp_args);
++
++        if (err < 0) {
++            perror("execing pppd");
++        }
++        exit(-1);
++    } else {
++        // parent side
++
++        adb_close(fd);
++        return 0;
++    }
++#endif /* !HAVE_WIN32_PROC */
++}
++
++static int send_shellcommand(transport_type transport, char* serial, char* buf)
++{
++    int fd, ret;
++
++    for(;;) {
++        fd = adb_connect(buf);
++        if(fd >= 0)
++            break;
++        fprintf(stderr,"- waiting for device -\n");
++        adb_sleep_ms(1000);
++        do_cmd(transport, serial, "wait-for-device", 0);
++    }
++
++    read_and_dump(fd);
++    ret = adb_close(fd);
++    if (ret)
++        perror("close");
++
++    return ret;
++}
++
++static int logcat(transport_type transport, char* serial, int argc, char **argv)
++{
++    char buf[4096];
++
++    char *log_tags;
++    char *quoted_log_tags;
++
++    log_tags = getenv("ANDROID_LOG_TAGS");
++    quoted_log_tags = dupAndQuote(log_tags == NULL ? "" : log_tags);
++
++    snprintf(buf, sizeof(buf),
++        "shell:export ANDROID_LOG_TAGS=\"\%s\" ; exec logcat",
++        quoted_log_tags);
++
++    free(quoted_log_tags);
++
++    if (!strcmp(argv[0],"longcat")) {
++        strncat(buf, " -v long", sizeof(buf)-1);
++    }
++
++    argc -= 1;
++    argv += 1;
++    while(argc-- > 0) {
++        char *quoted;
++
++        quoted = dupAndQuote (*argv++);
++
++        strncat(buf, " ", sizeof(buf)-1);
++        strncat(buf, quoted, sizeof(buf)-1);
++        free(quoted);
++    }
++
++    send_shellcommand(transport, serial, buf);
++    return 0;
++}
++
++static int mkdirs(char *path)
++{
++    int ret;
++    char *x = path + 1;
++
++    for(;;) {
++        x = adb_dirstart(x);
++        if(x == 0) return 0;
++        *x = 0;
++        ret = adb_mkdir(path, 0775);
++        *x = OS_PATH_SEPARATOR;
++        if((ret < 0) && (errno != EEXIST)) {
++            return ret;
++        }
++        x++;
++    }
++    return 0;
++}
++
++static int backup(int argc, char** argv) {
++    char buf[4096];
++    char default_name[32];
++    const char* filename = strcpy(default_name, "./backup.ab");
++    int fd, outFd;
++    int i, j;
++
++    /* find, extract, and use any -f argument */
++    for (i = 1; i < argc; i++) {
++        if (!strcmp("-f", argv[i])) {
++            if (i == argc-1) {
++                fprintf(stderr, "adb: -f passed with no filename\n");
++                return usage();
++            }
++            filename = argv[i+1];
++            for (j = i+2; j <= argc; ) {
++                argv[i++] = argv[j++];
++            }
++            argc -= 2;
++            argv[argc] = NULL;
++        }
++    }
++
++    /* bare "adb backup" or "adb backup -f filename" are not valid invocations */
++    if (argc < 2) return usage();
++
++    adb_unlink(filename);
++    mkdirs((char *)filename);
++    outFd = adb_creat(filename, 0640);
++    if (outFd < 0) {
++        fprintf(stderr, "adb: unable to open file %s\n", filename);
++        return -1;
++    }
++
++    snprintf(buf, sizeof(buf), "backup");
++    for (argc--, argv++; argc; argc--, argv++) {
++        strncat(buf, ":", sizeof(buf) - strlen(buf) - 1);
++        strncat(buf, argv[0], sizeof(buf) - strlen(buf) - 1);
++    }
++
++    D("backup. filename=%s buf=%s\n", filename, buf);
++    fd = adb_connect(buf);
++    if (fd < 0) {
++        fprintf(stderr, "adb: unable to connect for backup\n");
++        adb_close(outFd);
++        return -1;
++    }
++
++    printf("Now unlock your device and confirm the backup operation.\n");
++    copy_to_file(fd, outFd);
++
++    adb_close(fd);
++    adb_close(outFd);
++    return 0;
++}
++
++static int restore(int argc, char** argv) {
++    const char* filename;
++    int fd, tarFd;
++
++    if (argc != 2) return usage();
++
++    filename = argv[1];
++    tarFd = adb_open(filename, O_RDONLY);
++    if (tarFd < 0) {
++        fprintf(stderr, "adb: unable to open file %s\n", filename);
++        return -1;
++    }
++
++    fd = adb_connect("restore:");
++    if (fd < 0) {
++        fprintf(stderr, "adb: unable to connect for backup\n");
++        adb_close(tarFd);
++        return -1;
++    }
++
++    printf("Now unlock your device and confirm the restore operation.\n");
++    copy_to_file(tarFd, fd);
++
++    adb_close(fd);
++    adb_close(tarFd);
++    return 0;
++}
++
++#define SENTINEL_FILE "config" OS_PATH_SEPARATOR_STR "envsetup.make"
++static int top_works(const char *top)
++{
++    if (top != NULL && adb_is_absolute_host_path(top)) {
++        char path_buf[PATH_MAX];
++        snprintf(path_buf, sizeof(path_buf),
++                "%s" OS_PATH_SEPARATOR_STR SENTINEL_FILE, top);
++        return access(path_buf, F_OK) == 0;
++    }
++    return 0;
++}
++
++static char *find_top_from(const char *indir, char path_buf[PATH_MAX])
++{
++    strcpy(path_buf, indir);
++    while (1) {
++        if (top_works(path_buf)) {
++            return path_buf;
++        }
++        char *s = adb_dirstop(path_buf);
++        if (s != NULL) {
++            *s = '\0';
++        } else {
++            path_buf[0] = '\0';
++            return NULL;
++        }
++    }
++}
++
++static char *find_top(char path_buf[PATH_MAX])
++{
++    char *top = getenv("ANDROID_BUILD_TOP");
++    if (top != NULL && top[0] != '\0') {
++        if (!top_works(top)) {
++            fprintf(stderr, "adb: bad ANDROID_BUILD_TOP value \"%s\"\n", top);
++            return NULL;
++        }
++    } else {
++        top = getenv("TOP");
++        if (top != NULL && top[0] != '\0') {
++            if (!top_works(top)) {
++                fprintf(stderr, "adb: bad TOP value \"%s\"\n", top);
++                return NULL;
++            }
++        } else {
++            top = NULL;
++        }
++    }
++
++    if (top != NULL) {
++        /* The environment pointed to a top directory that works.
++         */
++        strcpy(path_buf, top);
++        return path_buf;
++    }
++
++    /* The environment didn't help.  Walk up the tree from the CWD
++     * to see if we can find the top.
++     */
++    char dir[PATH_MAX];
++    top = find_top_from(getcwd(dir, sizeof(dir)), path_buf);
++    if (top == NULL) {
++        /* If the CWD isn't under a good-looking top, see if the
++         * executable is.
++         */
++        get_my_path(dir, PATH_MAX);
++        top = find_top_from(dir, path_buf);
++    }
++    return top;
++}
++
++/* <hint> may be:
++ * - A simple product name
++ *   e.g., "sooner"
++TODO: debug?  sooner-debug, sooner:debug?
++ * - A relative path from the CWD to the ANDROID_PRODUCT_OUT dir
++ *   e.g., "out/target/product/sooner"
++ * - An absolute path to the PRODUCT_OUT dir
++ *   e.g., "/src/device/out/target/product/sooner"
++ *
++ * Given <hint>, try to construct an absolute path to the
++ * ANDROID_PRODUCT_OUT dir.
++ */
++static const char *find_product_out_path(const char *hint)
++{
++    static char path_buf[PATH_MAX];
++
++    if (hint == NULL || hint[0] == '\0') {
++        return NULL;
++    }
++
++    /* If it's already absolute, don't bother doing any work.
++     */
++    if (adb_is_absolute_host_path(hint)) {
++        strcpy(path_buf, hint);
++        return path_buf;
++    }
++
++    /* If there are any slashes in it, assume it's a relative path;
++     * make it absolute.
++     */
++    if (adb_dirstart(hint) != NULL) {
++        if (getcwd(path_buf, sizeof(path_buf)) == NULL) {
++            fprintf(stderr, "adb: Couldn't get CWD: %s\n", strerror(errno));
++            return NULL;
++        }
++        if (strlen(path_buf) + 1 + strlen(hint) >= sizeof(path_buf)) {
++            fprintf(stderr, "adb: Couldn't assemble path\n");
++            return NULL;
++        }
++        strcat(path_buf, OS_PATH_SEPARATOR_STR);
++        strcat(path_buf, hint);
++        return path_buf;
++    }
++
++    /* It's a string without any slashes.  Try to do something with it.
++     *
++     * Try to find the root of the build tree, and build a PRODUCT_OUT
++     * path from there.
++     */
++    char top_buf[PATH_MAX];
++    const char *top = find_top(top_buf);
++    if (top == NULL) {
++        fprintf(stderr, "adb: Couldn't find top of build tree\n");
++        return NULL;
++    }
++//TODO: if we have a way to indicate debug, look in out/debug/target/...
++    snprintf(path_buf, sizeof(path_buf),
++            "%s" OS_PATH_SEPARATOR_STR
++            "out" OS_PATH_SEPARATOR_STR
++            "target" OS_PATH_SEPARATOR_STR
++            "product" OS_PATH_SEPARATOR_STR
++            "%s", top_buf, hint);
++    if (access(path_buf, F_OK) < 0) {
++        fprintf(stderr, "adb: Couldn't find a product dir "
++                "based on \"-p %s\"; \"%s\" doesn't exist\n", hint, path_buf);
++        return NULL;
++    }
++    return path_buf;
++}
++
++int adb_commandline(int argc, char **argv)
++{
++    char buf[4096];
++    int no_daemon = 0;
++    int is_daemon = 0;
++    int is_server = 0;
++    int persist = 0;
++    int r;
++    int quote;
++    transport_type ttype = kTransportAny;
++    char* serial = NULL;
++    char* server_port_str = NULL;
++
++        /* If defined, this should be an absolute path to
++         * the directory containing all of the various system images
++         * for a particular product.  If not defined, and the adb
++         * command requires this information, then the user must
++         * specify the path using "-p".
++         */
++    gProductOutPath = getenv("ANDROID_PRODUCT_OUT");
++    if (gProductOutPath == NULL || gProductOutPath[0] == '\0') {
++        gProductOutPath = NULL;
++    }
++    // TODO: also try TARGET_PRODUCT/TARGET_DEVICE as a hint
++
++    serial = getenv("ANDROID_SERIAL");
++
++    /* Validate and assign the server port */
++    server_port_str = getenv("ANDROID_ADB_SERVER_PORT");
++    int server_port = DEFAULT_ADB_PORT;
++    if (server_port_str && strlen(server_port_str) > 0) {
++        server_port = (int) strtol(server_port_str, NULL, 0);
++        if (server_port <= 0 || server_port > 65535) {
++            fprintf(stderr,
++                    "adb: Env var ANDROID_ADB_SERVER_PORT must be a positive number less than 65535. Got \"%s\"\n",
++                    server_port_str);
++            return usage();
++        }
++    }
++
++    /* modifiers and flags */
++    while(argc > 0) {
++        if(!strcmp(argv[0],"server")) {
++            is_server = 1;
++        } else if(!strcmp(argv[0],"nodaemon")) {
++            no_daemon = 1;
++        } else if (!strcmp(argv[0], "fork-server")) {
++            /* this is a special flag used only when the ADB client launches the ADB Server */
++            is_daemon = 1;
++        } else if(!strcmp(argv[0],"persist")) {
++            persist = 1;
++        } else if(!strncmp(argv[0], "-p", 2)) {
++            const char *product = NULL;
++            if (argv[0][2] == '\0') {
++                if (argc < 2) return usage();
++                product = argv[1];
++                argc--;
++                argv++;
++            } else {
++                product = argv[0] + 2;
++            }
++            gProductOutPath = find_product_out_path(product);
++            if (gProductOutPath == NULL) {
++                fprintf(stderr, "adb: could not resolve \"-p %s\"\n",
++                        product);
++                return usage();
++            }
++        } else if (argv[0][0]=='-' && argv[0][1]=='s') {
++            if (isdigit(argv[0][2])) {
++                serial = argv[0] + 2;
++            } else {
++                if(argc < 2 || argv[0][2] != '\0') return usage();
++                serial = argv[1];
++                argc--;
++                argv++;
++            }
++        } else if (!strcmp(argv[0],"-d")) {
++            ttype = kTransportUsb;
++        } else if (!strcmp(argv[0],"-e")) {
++            ttype = kTransportLocal;
++        } else if (!strcmp(argv[0],"-a")) {
++            gListenAll = 1;
++        } else if(!strncmp(argv[0], "-H", 2)) {
++            const char *hostname = NULL;
++            if (argv[0][2] == '\0') {
++                if (argc < 2) return usage();
++                hostname = argv[1];
++                argc--;
++                argv++;
++            } else {
++                hostname = argv[0] + 2;
++            }
++            adb_set_tcp_name(hostname);
++
++        } else if(!strncmp(argv[0], "-P", 2)) {
++            if (argv[0][2] == '\0') {
++                if (argc < 2) return usage();
++                server_port_str = argv[1];
++                argc--;
++                argv++;
++            } else {
++                server_port_str = argv[0] + 2;
++            }
++            if (strlen(server_port_str) > 0) {
++                server_port = (int) strtol(server_port_str, NULL, 0);
++                if (server_port <= 0 || server_port > 65535) {
++                    fprintf(stderr,
++                            "adb: port number must be a positive number less than 65536. Got \"%s\"\n",
++                            server_port_str);
++                    return usage();
++                }
++            } else {
++                fprintf(stderr,
++                "adb: port number must be a positive number less than 65536. Got empty string.\n");
++                return usage();
++            }
++        } else {
++                /* out of recognized modifiers and flags */
++            break;
++        }
++        argc--;
++        argv++;
++    }
++
++    adb_set_transport(ttype, serial);
++    adb_set_tcp_specifics(server_port);
++
++    if (is_server) {
++        if (no_daemon || is_daemon) {
++            r = adb_main(is_daemon, server_port);
++        } else {
++            r = launch_server(server_port);
++        }
++        if(r) {
++            fprintf(stderr,"* could not start server *\n");
++        }
++        return r;
++    }
++
++top:
++    if(argc == 0) {
++        return usage();
++    }
++
++    /* adb_connect() commands */
++
++    if(!strcmp(argv[0], "devices")) {
++        char *tmp;
++        char *listopt;
++        if (argc < 2)
++            listopt = "";
++        else if (argc == 2 && !strcmp(argv[1], "-l"))
++            listopt = argv[1];
++        else {
++            fprintf(stderr, "Usage: adb devices [-l]\n");
++            return 1;
++        }
++        snprintf(buf, sizeof buf, "host:%s%s", argv[0], listopt);
++        tmp = adb_query(buf);
++        if(tmp) {
++            printf("List of devices attached \n");
++            printf("%s\n", tmp);
++            return 0;
++        } else {
++            return 1;
++        }
++    }
++
++    if(!strcmp(argv[0], "connect")) {
++        char *tmp;
++        if (argc != 2) {
++            fprintf(stderr, "Usage: adb connect <host>[:<port>]\n");
++            return 1;
++        }
++        snprintf(buf, sizeof buf, "host:connect:%s", argv[1]);
++        tmp = adb_query(buf);
++        if(tmp) {
++            printf("%s\n", tmp);
++            return 0;
++        } else {
++            return 1;
++        }
++    }
++
++    if(!strcmp(argv[0], "disconnect")) {
++        char *tmp;
++        if (argc > 2) {
++            fprintf(stderr, "Usage: adb disconnect [<host>[:<port>]]\n");
++            return 1;
++        }
++        if (argc == 2) {
++            snprintf(buf, sizeof buf, "host:disconnect:%s", argv[1]);
++        } else {
++            snprintf(buf, sizeof buf, "host:disconnect:");
++        }
++        tmp = adb_query(buf);
++        if(tmp) {
++            printf("%s\n", tmp);
++            return 0;
++        } else {
++            return 1;
++        }
++    }
++
++    if (!strcmp(argv[0], "emu")) {
++        return adb_send_emulator_command(argc, argv);
++    }
++
++    if(!strcmp(argv[0], "shell") || !strcmp(argv[0], "hell")) {
++        int r;
++        int fd;
++
++        char h = (argv[0][0] == 'h');
++
++        if (h) {
++            printf("\x1b[41;33m");
++            fflush(stdout);
++        }
++
++        if(argc < 2) {
++            D("starting interactive shell\n");
++            r = interactive_shell();
++            if (h) {
++                printf("\x1b[0m");
++                fflush(stdout);
++            }
++            return r;
++        }
++
++        snprintf(buf, sizeof buf, "shell:%s", argv[1]);
++        argc -= 2;
++        argv += 2;
++        while(argc-- > 0) {
++            strcat(buf, " ");
++
++            /* quote empty strings and strings with spaces */
++            quote = (**argv == 0 || strchr(*argv, ' '));
++            if (quote)
++                strcat(buf, "\"");
++            strcat(buf, *argv++);
++            if (quote)
++                strcat(buf, "\"");
++        }
++
++        for(;;) {
++            D("interactive shell loop. buff=%s\n", buf);
++            fd = adb_connect(buf);
++            if(fd >= 0) {
++                D("about to read_and_dump(fd=%d)\n", fd);
++                read_and_dump(fd);
++                D("read_and_dump() done.\n");
++                adb_close(fd);
++                r = 0;
++            } else {
++                fprintf(stderr,"error: %s\n", adb_error());
++                r = -1;
++            }
++
++            if(persist) {
++                fprintf(stderr,"\n- waiting for device -\n");
++                adb_sleep_ms(1000);
++                do_cmd(ttype, serial, "wait-for-device", 0);
++            } else {
++                if (h) {
++                    printf("\x1b[0m");
++                    fflush(stdout);
++                }
++                D("interactive shell loop. return r=%d\n", r);
++                return r;
++            }
++        }
++    }
++
++    if(!strcmp(argv[0], "kill-server")) {
++        int fd;
++        fd = _adb_connect("host:kill");
++        if(fd == -1) {
++            fprintf(stderr,"* server not running *\n");
++            return 1;
++        }
++        return 0;
++    }
++
++    if(!strcmp(argv[0], "sideload")) {
++        if(argc != 2) return usage();
++        if(adb_download("sideload", argv[1], 1)) {
++            return 1;
++        } else {
++            return 0;
++        }
++    }
++
++    if(!strcmp(argv[0], "remount") || !strcmp(argv[0], "reboot")
++            || !strcmp(argv[0], "reboot-bootloader")
++            || !strcmp(argv[0], "tcpip") || !strcmp(argv[0], "usb")
++            || !strcmp(argv[0], "root")) {
++        char command[100];
++        if (!strcmp(argv[0], "reboot-bootloader"))
++            snprintf(command, sizeof(command), "reboot:bootloader");
++        else if (argc > 1)
++            snprintf(command, sizeof(command), "%s:%s", argv[0], argv[1]);
++        else
++            snprintf(command, sizeof(command), "%s:", argv[0]);
++        int fd = adb_connect(command);
++        if(fd >= 0) {
++            read_and_dump(fd);
++            adb_close(fd);
++            return 0;
++        }
++        fprintf(stderr,"error: %s\n", adb_error());
++        return 1;
++    }
++
++    if(!strcmp(argv[0], "bugreport")) {
++        if (argc != 1) return usage();
++        do_cmd(ttype, serial, "shell", "bugreport", 0);
++        return 0;
++    }
++
++    /* adb_command() wrapper commands */
++
++    if(!strncmp(argv[0], "wait-for-", strlen("wait-for-"))) {
++        char* service = argv[0];
++        if (!strncmp(service, "wait-for-device", strlen("wait-for-device"))) {
++            if (ttype == kTransportUsb) {
++                service = "wait-for-usb";
++            } else if (ttype == kTransportLocal) {
++                service = "wait-for-local";
++            } else {
++                service = "wait-for-any";
++            }
++        }
++
++        format_host_command(buf, sizeof buf, service, ttype, serial);
++
++        if (adb_command(buf)) {
++            D("failure: %s *\n",adb_error());
++            fprintf(stderr,"error: %s\n", adb_error());
++            return 1;
++        }
++
++        /* Allow a command to be run after wait-for-device,
++            * e.g. 'adb wait-for-device shell'.
++            */
++        if(argc > 1) {
++            argc--;
++            argv++;
++            goto top;
++        }
++        return 0;
++    }
++
++    if(!strcmp(argv[0], "forward")) {
++        char host_prefix[64];
++        char remove = 0;
++        char remove_all = 0;
++        char list = 0;
++        char no_rebind = 0;
++
++        // Parse options here.
++        while (argc > 1 && argv[1][0] == '-') {
++            if (!strcmp(argv[1], "--list"))
++                list = 1;
++            else if (!strcmp(argv[1], "--remove"))
++                remove = 1;
++            else if (!strcmp(argv[1], "--remove-all"))
++                remove_all = 1;
++            else if (!strcmp(argv[1], "--no-rebind"))
++                no_rebind = 1;
++            else {
++                return usage();
++            }
++            argc--;
++            argv++;
++        }
++
++        // Ensure we can only use one option at a time.
++        if (list + remove + remove_all + no_rebind > 1) {
++            return usage();
++        }
++
++        // Determine the <host-prefix> for this command.
++        if (serial) {
++            snprintf(host_prefix, sizeof host_prefix, "host-serial:%s",
++                    serial);
++        } else if (ttype == kTransportUsb) {
++            snprintf(host_prefix, sizeof host_prefix, "host-usb");
++        } else if (ttype == kTransportLocal) {
++            snprintf(host_prefix, sizeof host_prefix, "host-local");
++        } else {
++            snprintf(host_prefix, sizeof host_prefix, "host");
++        }
++
++        // Implement forward --list
++        if (list) {
++            if (argc != 1)
++                return usage();
++            snprintf(buf, sizeof buf, "%s:list-forward", host_prefix);
++            char* forwards = adb_query(buf);
++            if (forwards == NULL) {
++                fprintf(stderr, "error: %s\n", adb_error());
++                return 1;
++            }
++            printf("%s", forwards);
++            free(forwards);
++            return 0;
++        }
++
++        // Implement forward --remove-all
++        else if (remove_all) {
++            if (argc != 1)
++                return usage();
++            snprintf(buf, sizeof buf, "%s:killforward-all", host_prefix);
++        }
++
++        // Implement forward --remove <local>
++        else if (remove) {
++            if (argc != 2)
++                return usage();
++            snprintf(buf, sizeof buf, "%s:killforward:%s", host_prefix, argv[1]);
++        }
++        // Or implement one of:
++        //    forward <local> <remote>
++        //    forward --no-rebind <local> <remote>
++        else
++        {
++          if (argc != 3)
++            return usage();
++          const char* command = no_rebind ? "forward:norebind:" : "forward";
++          snprintf(buf, sizeof buf, "%s:%s:%s;%s", host_prefix, command, argv[1], argv[2]);
++        }
++
++        if(adb_command(buf)) {
++            fprintf(stderr,"error: %s\n", adb_error());
++            return 1;
++        }
++        return 0;
++    }
++
++    /* do_sync_*() commands */
++
++    if(!strcmp(argv[0], "ls")) {
++        if(argc != 2) return usage();
++        return do_sync_ls(argv[1]);
++    }
++
++    if(!strcmp(argv[0], "push")) {
++        if(argc != 3) return usage();
++        return do_sync_push(argv[1], argv[2], 0 /* no verify APK */);
++    }
++
++    if(!strcmp(argv[0], "pull")) {
++        if (argc == 2) {
++            return do_sync_pull(argv[1], ".");
++        } else if (argc == 3) {
++            return do_sync_pull(argv[1], argv[2]);
++        } else {
++            return usage();
++        }
++    }
++
++    if(!strcmp(argv[0], "install")) {
++        if (argc < 2) return usage();
++        return install_app(ttype, serial, argc, argv);
++    }
++
++    if(!strcmp(argv[0], "uninstall")) {
++        if (argc < 2) return usage();
++        return uninstall_app(ttype, serial, argc, argv);
++    }
++
++    if(!strcmp(argv[0], "sync")) {
++        char *srcarg, *android_srcpath, *data_srcpath;
++        int listonly = 0;
++
++        int ret;
++        if(argc < 2) {
++            /* No local path was specified. */
++            srcarg = NULL;
++        } else if (argc >= 2 && strcmp(argv[1], "-l") == 0) {
++            listonly = 1;
++            if (argc == 3) {
++                srcarg = argv[2];
++            } else {
++                srcarg = NULL;
++            }
++        } else if(argc == 2) {
++            /* A local path or "android"/"data" arg was specified. */
++            srcarg = argv[1];
++        } else {
++            return usage();
++        }
++        ret = find_sync_dirs(srcarg, &android_srcpath, &data_srcpath);
++        if(ret != 0) return usage();
++
++        if(android_srcpath != NULL)
++            ret = do_sync_sync(android_srcpath, "/system", listonly);
++        if(ret == 0 && data_srcpath != NULL)
++            ret = do_sync_sync(data_srcpath, "/data", listonly);
++
++        free(android_srcpath);
++        free(data_srcpath);
++        return ret;
++    }
++
++    /* passthrough commands */
++
++    if(!strcmp(argv[0],"get-state") ||
++        !strcmp(argv[0],"get-serialno") ||
++        !strcmp(argv[0],"get-devpath"))
++    {
++        char *tmp;
++
++        format_host_command(buf, sizeof buf, argv[0], ttype, serial);
++        tmp = adb_query(buf);
++        if(tmp) {
++            printf("%s\n", tmp);
++            return 0;
++        } else {
++            return 1;
++        }
++    }
++
++    /* other commands */
++
++    if(!strcmp(argv[0],"status-window")) {
++        status_window(ttype, serial);
++        return 0;
++    }
++
++    if(!strcmp(argv[0],"logcat") || !strcmp(argv[0],"lolcat") || !strcmp(argv[0],"longcat")) {
++        return logcat(ttype, serial, argc, argv);
++    }
++
++    if(!strcmp(argv[0],"ppp")) {
++        return ppp(argc, argv);
++    }
++
++    if (!strcmp(argv[0], "start-server")) {
++        return adb_connect("host:start-server");
++    }
++
++    if (!strcmp(argv[0], "backup")) {
++        return backup(argc, argv);
++    }
++
++    if (!strcmp(argv[0], "restore")) {
++        return restore(argc, argv);
++    }
++
++    if (!strcmp(argv[0], "jdwp")) {
++        int  fd = adb_connect("jdwp");
++        if (fd >= 0) {
++            read_and_dump(fd);
++            adb_close(fd);
++            return 0;
++        } else {
++            fprintf(stderr, "error: %s\n", adb_error());
++            return -1;
++        }
++    }
++
++    /* "adb /?" is a common idiom under Windows */
++    if(!strcmp(argv[0], "help") || !strcmp(argv[0], "/?")) {
++        help();
++        return 0;
++    }
++
++    if(!strcmp(argv[0], "version")) {
++        version(stdout);
++        return 0;
++    }
++
++    usage();
++    return 1;
++}
++
++static int do_cmd(transport_type ttype, char* serial, char *cmd, ...)
++{
++    char *argv[16];
++    int argc;
++    va_list ap;
++
++    va_start(ap, cmd);
++    argc = 0;
++
++    if (serial) {
++        argv[argc++] = "-s";
++        argv[argc++] = serial;
++    } else if (ttype == kTransportUsb) {
++        argv[argc++] = "-d";
++    } else if (ttype == kTransportLocal) {
++        argv[argc++] = "-e";
++    }
++
++    argv[argc++] = cmd;
++    while((argv[argc] = va_arg(ap, char*)) != 0) argc++;
++    va_end(ap);
++
++#if 0
++    int n;
++    fprintf(stderr,"argc = %d\n",argc);
++    for(n = 0; n < argc; n++) {
++        fprintf(stderr,"argv[%d] = \"%s\"\n", n, argv[n]);
++    }
++#endif
++
++    return adb_commandline(argc, argv);
++}
++
++int find_sync_dirs(const char *srcarg,
++        char **android_srcdir_out, char **data_srcdir_out)
++{
++    char *android_srcdir, *data_srcdir;
++
++    if(srcarg == NULL) {
++        android_srcdir = product_file("system");
++        data_srcdir = product_file("data");
++    } else {
++        /* srcarg may be "data", "system" or NULL.
++         * if srcarg is NULL, then both data and system are synced
++         */
++        if(strcmp(srcarg, "system") == 0) {
++            android_srcdir = product_file("system");
++            data_srcdir = NULL;
++        } else if(strcmp(srcarg, "data") == 0) {
++            android_srcdir = NULL;
++            data_srcdir = product_file("data");
++        } else {
++            /* It's not "system" or "data".
++             */
++            return 1;
++        }
++    }
++
++    if(android_srcdir_out != NULL)
++        *android_srcdir_out = android_srcdir;
++    else
++        free(android_srcdir);
++
++    if(data_srcdir_out != NULL)
++        *data_srcdir_out = data_srcdir;
++    else
++        free(data_srcdir);
++
++    return 0;
++}
++
++static int pm_command(transport_type transport, char* serial,
++                      int argc, char** argv)
++{
++    char buf[4096];
++
++    snprintf(buf, sizeof(buf), "shell:pm");
++
++    while(argc-- > 0) {
++        char *quoted;
++
++        quoted = dupAndQuote(*argv++);
++
++        strncat(buf, " ", sizeof(buf)-1);
++        strncat(buf, quoted, sizeof(buf)-1);
++        free(quoted);
++    }
++
++    send_shellcommand(transport, serial, buf);
++    return 0;
++}
++
++int uninstall_app(transport_type transport, char* serial, int argc, char** argv)
++{
++    /* if the user choose the -k option, we refuse to do it until devices are
++       out with the option to uninstall the remaining data somehow (adb/ui) */
++    if (argc == 3 && strcmp(argv[1], "-k") == 0)
++    {
++        printf(
++            "The -k option uninstalls the application while retaining the data/cache.\n"
++            "At the moment, there is no way to remove the remaining data.\n"
++            "You will have to reinstall the application with the same signature, and fully uninstall it.\n"
++            "If you truly wish to continue, execute 'adb shell pm uninstall -k %s'\n", argv[2]);
++        return -1;
++    }
++
++    /* 'adb uninstall' takes the same arguments as 'pm uninstall' on device */
++    return pm_command(transport, serial, argc, argv);
++}
++
++static int delete_file(transport_type transport, char* serial, char* filename)
++{
++    char buf[4096];
++    char* quoted;
++
++    snprintf(buf, sizeof(buf), "shell:rm ");
++    quoted = dupAndQuote(filename);
++    strncat(buf, quoted, sizeof(buf)-1);
++    free(quoted);
++
++    send_shellcommand(transport, serial, buf);
++    return 0;
++}
++
++static const char* get_basename(const char* filename)
++{
++    const char* basename = adb_dirstop(filename);
++    if (basename) {
++        basename++;
++        return basename;
++    } else {
++        return filename;
++    }
++}
++
++static int check_file(const char* filename)
++{
++    struct stat st;
++
++    if (filename == NULL) {
++        return 0;
++    }
++
++    if (stat(filename, &st) != 0) {
++        fprintf(stderr, "can't find '%s' to install\n", filename);
++        return 1;
++    }
++
++    if (!S_ISREG(st.st_mode)) {
++        fprintf(stderr, "can't install '%s' because it's not a file\n", filename);
++        return 1;
++    }
++
++    return 0;
++}
++
++int install_app(transport_type transport, char* serial, int argc, char** argv)
++{
++    static const char *const DATA_DEST = "/data/local/tmp/%s";
++    static const char *const SD_DEST = "/sdcard/tmp/%s";
++    const char* where = DATA_DEST;
++    char apk_dest[PATH_MAX];
++    char verification_dest[PATH_MAX];
++    char* apk_file;
++    char* verification_file = NULL;
++    int file_arg = -1;
++    int err;
++    int i;
++    int verify_apk = 1;
++
++    for (i = 1; i < argc; i++) {
++        if (*argv[i] != '-') {
++            file_arg = i;
++            break;
++        } else if (!strcmp(argv[i], "-i")) {
++            // Skip the installer package name.
++            i++;
++        } else if (!strcmp(argv[i], "-s")) {
++            where = SD_DEST;
++        } else if (!strcmp(argv[i], "--algo")) {
++            verify_apk = 0;
++            i++;
++        } else if (!strcmp(argv[i], "--iv")) {
++            verify_apk = 0;
++            i++;
++        } else if (!strcmp(argv[i], "--key")) {
++            verify_apk = 0;
++            i++;
++        }
++    }
++
++    if (file_arg < 0) {
++        fprintf(stderr, "can't find filename in arguments\n");
++        return 1;
++    } else if (file_arg + 2 < argc) {
++        fprintf(stderr, "too many files specified; only takes APK file and verifier file\n");
++        return 1;
++    }
++
++    apk_file = argv[file_arg];
++
++    if (file_arg != argc - 1) {
++        verification_file = argv[file_arg + 1];
++    }
++
++    if (check_file(apk_file) || check_file(verification_file)) {
++        return 1;
++    }
++
++    snprintf(apk_dest, sizeof apk_dest, where, get_basename(apk_file));
++    if (verification_file != NULL) {
++        snprintf(verification_dest, sizeof(verification_dest), where, get_basename(verification_file));
++
++        if (!strcmp(apk_dest, verification_dest)) {
++            fprintf(stderr, "APK and verification file can't have the same name\n");
++            return 1;
++        }
++    }
++
++    err = do_sync_push(apk_file, apk_dest, verify_apk);
++    if (err) {
++        goto cleanup_apk;
++    } else {
++        argv[file_arg] = apk_dest; /* destination name, not source location */
++    }
++
++    if (verification_file != NULL) {
++        err = do_sync_push(verification_file, verification_dest, 0 /* no verify APK */);
++        if (err) {
++            goto cleanup_apk;
++        } else {
++            argv[file_arg + 1] = verification_dest; /* destination name, not source location */
++        }
++    }
++
++    pm_command(transport, serial, argc, argv);
++
++cleanup_apk:
++    if (verification_file != NULL) {
++        delete_file(transport, serial, verification_dest);
++    }
++
++    delete_file(transport, serial, apk_dest);
++
++    return err;
++}
+Index: android-tools-4.2.2+git20130218/core/adbd/console.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/console.c        2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,45 @@
++#include "sysdeps.h"
++#include "adb.h"
++#include "adb_client.h"
++#include <stdio.h>
++
++static int  connect_to_console(void)
++{
++    int  fd, port;
++
++    port = adb_get_emulator_console_port();
++    if (port < 0) {
++        if (port == -2)
++            fprintf(stderr, "error: more than one emulator detected. use -s option\n");
++        else
++            fprintf(stderr, "error: no emulator detected\n");
++        return -1;
++    }
++    fd = socket_loopback_client( port, SOCK_STREAM );
++    if (fd < 0) {
++        fprintf(stderr, "error: could not connect to TCP port %d\n", port);
++        return -1;
++    }
++    return  fd;
++}
++
++
++int  adb_send_emulator_command(int  argc, char**  argv)
++{
++    int   fd, nn;
++
++    fd = connect_to_console();
++    if (fd < 0)
++        return 1;
++
++#define  QUIT  "quit\n"
++
++    for (nn = 1; nn < argc; nn++) {
++        adb_write( fd, argv[nn], strlen(argv[nn]) );
++        adb_write( fd, (nn == argc-1) ? "\n" : " ", 1 );
++    }
++    adb_write( fd, QUIT, sizeof(QUIT)-1 );
++    adb_close(fd);
++
++    return 0;
++}
+Index: android-tools-4.2.2+git20130218/core/adbd/fdevent.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/fdevent.c        2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,695 @@
++/* http://frotznet.googlecode.com/svn/trunk/utils/fdevent.c
++**
++** Copyright 2006, Brian Swetland <swetland@frotz.net>
++**
++** Licensed under the Apache License, Version 2.0 (the "License"); 
++** you may not use this file except in compliance with the License. 
++** You may obtain a copy of the License at 
++**
++**     http://www.apache.org/licenses/LICENSE-2.0 
++**
++** Unless required by applicable law or agreed to in writing, software 
++** distributed under the License is distributed on an "AS IS" BASIS, 
++** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
++** See the License for the specific language governing permissions and 
++** limitations under the License.
++*/
++
++#include <sys/ioctl.h>
++
++#include <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++#include <unistd.h>
++#include <errno.h>
++
++#include <fcntl.h>
++
++#include <stdarg.h>
++#include <stddef.h>
++
++#include "fdevent.h"
++#include "transport.h"
++#include "sysdeps.h"
++
++
++/* !!! Do not enable DEBUG for the adb that will run as the server:
++** both stdout and stderr are used to communicate between the client
++** and server. Any extra output will cause failures.
++*/
++#define DEBUG 0   /* non-0 will break adb server */
++
++// This socket is used when a subproc shell service exists.
++// It wakes up the fdevent_loop() and cause the correct handling
++// of the shell's pseudo-tty master. I.e. force close it.
++int SHELL_EXIT_NOTIFY_FD = -1;
++
++static void fatal(const char *fn, const char *fmt, ...)
++{
++    va_list ap;
++    va_start(ap, fmt);
++    fprintf(stderr, "%s:", fn);
++    vfprintf(stderr, fmt, ap);
++    va_end(ap);
++    abort();
++}
++
++#define FATAL(x...) fatal(__FUNCTION__, x)
++
++#if DEBUG
++#define D(...) \
++    do { \
++        adb_mutex_lock(&D_lock);               \
++        int save_errno = errno;                \
++        fprintf(stderr, "%s::%s():", __FILE__, __FUNCTION__);  \
++        errno = save_errno;                    \
++        fprintf(stderr, __VA_ARGS__);          \
++        adb_mutex_unlock(&D_lock);             \
++        errno = save_errno;                    \
++    } while(0)
++static void dump_fde(fdevent *fde, const char *info)
++{
++    adb_mutex_lock(&D_lock);
++    fprintf(stderr,"FDE #%03d %c%c%c %s\n", fde->fd,
++            fde->state & FDE_READ ? 'R' : ' ',
++            fde->state & FDE_WRITE ? 'W' : ' ',
++            fde->state & FDE_ERROR ? 'E' : ' ',
++            info);
++    adb_mutex_unlock(&D_lock);
++}
++#else
++#define D(...) ((void)0)
++#define dump_fde(fde, info) do { } while(0)
++#endif
++
++#define FDE_EVENTMASK  0x00ff
++#define FDE_STATEMASK  0xff00
++
++#define FDE_ACTIVE     0x0100
++#define FDE_PENDING    0x0200
++#define FDE_CREATED    0x0400
++
++static void fdevent_plist_enqueue(fdevent *node);
++static void fdevent_plist_remove(fdevent *node);
++static fdevent *fdevent_plist_dequeue(void);
++static void fdevent_subproc_event_func(int fd, unsigned events, void *userdata);
++
++static fdevent list_pending = {
++    .next = &list_pending,
++    .prev = &list_pending,
++};
++
++static fdevent **fd_table = 0;
++static int fd_table_max = 0;
++
++#ifdef CRAPTASTIC
++//HAVE_EPOLL
++
++#include <sys/epoll.h>
++
++static int epoll_fd = -1;
++
++static void fdevent_init()
++{
++        /* XXX: what's a good size for the passed in hint? */
++    epoll_fd = epoll_create(256);
++
++    if(epoll_fd < 0) {
++        perror("epoll_create() failed");
++        exit(1);
++    }
++
++        /* mark for close-on-exec */
++    fcntl(epoll_fd, F_SETFD, FD_CLOEXEC);
++}
++
++static void fdevent_connect(fdevent *fde)
++{
++    struct epoll_event ev;
++
++    memset(&ev, 0, sizeof(ev));
++    ev.events = 0;
++    ev.data.ptr = fde;
++
++#if 0
++    if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fde->fd, &ev)) {
++        perror("epoll_ctl() failed\n");
++        exit(1);
++    }
++#endif
++}
++
++static void fdevent_disconnect(fdevent *fde)
++{
++    struct epoll_event ev;
++
++    memset(&ev, 0, sizeof(ev));
++    ev.events = 0;
++    ev.data.ptr = fde;
++
++        /* technically we only need to delete if we
++        ** were actively monitoring events, but let's
++        ** be aggressive and do it anyway, just in case
++        ** something's out of sync
++        */
++    epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fde->fd, &ev);
++}
++
++static void fdevent_update(fdevent *fde, unsigned events)
++{
++    struct epoll_event ev;
++    int active;
++
++    active = (fde->state & FDE_EVENTMASK) != 0;
++
++    memset(&ev, 0, sizeof(ev));
++    ev.events = 0;
++    ev.data.ptr = fde;
++
++    if(events & FDE_READ) ev.events |= EPOLLIN;
++    if(events & FDE_WRITE) ev.events |= EPOLLOUT;
++    if(events & FDE_ERROR) ev.events |= (EPOLLERR | EPOLLHUP);
++
++    fde->state = (fde->state & FDE_STATEMASK) | events;
++
++    if(active) {
++            /* we're already active. if we're changing to *no*
++            ** events being monitored, we need to delete, otherwise
++            ** we need to just modify
++            */
++        if(ev.events) {
++            if(epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fde->fd, &ev)) {
++                perror("epoll_ctl() failed\n");
++                exit(1);
++            }
++        } else {
++            if(epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fde->fd, &ev)) {
++                perror("epoll_ctl() failed\n");
++                exit(1);
++            }
++        }
++    } else {
++            /* we're not active.  if we're watching events, we need
++            ** to add, otherwise we can just do nothing
++            */
++        if(ev.events) {
++            if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fde->fd, &ev)) {
++                perror("epoll_ctl() failed\n");
++                exit(1);
++            }
++        }
++    }
++}
++
++static void fdevent_process()
++{
++    struct epoll_event events[256];
++    fdevent *fde;
++    int i, n;
++
++    n = epoll_wait(epoll_fd, events, 256, -1);
++
++    if(n < 0) {
++        if(errno == EINTR) return;
++        perror("epoll_wait");
++        exit(1);
++    }
++
++    for(i = 0; i < n; i++) {
++        struct epoll_event *ev = events + i;
++        fde = ev->data.ptr;
++
++        if(ev->events & EPOLLIN) {
++            fde->events |= FDE_READ;
++        }
++        if(ev->events & EPOLLOUT) {
++            fde->events |= FDE_WRITE;
++        }
++        if(ev->events & (EPOLLERR | EPOLLHUP)) {
++            fde->events |= FDE_ERROR;
++        }
++        if(fde->events) {
++            if(fde->state & FDE_PENDING) continue;
++            fde->state |= FDE_PENDING;
++            fdevent_plist_enqueue(fde);
++        }
++    }
++}
++
++#else /* USE_SELECT */
++
++#ifdef HAVE_WINSOCK
++#include <winsock2.h>
++#else
++#include <sys/select.h>
++#endif
++
++static fd_set read_fds;
++static fd_set write_fds;
++static fd_set error_fds;
++
++static int select_n = 0;
++
++static void fdevent_init(void)
++{
++    FD_ZERO(&read_fds);
++    FD_ZERO(&write_fds);
++    FD_ZERO(&error_fds);
++}
++
++static void fdevent_connect(fdevent *fde)
++{
++    if(fde->fd >= select_n) {
++        select_n = fde->fd + 1;
++    }
++}
++
++static void fdevent_disconnect(fdevent *fde)
++{
++    int i, n;
++
++    FD_CLR(fde->fd, &read_fds);
++    FD_CLR(fde->fd, &write_fds);
++    FD_CLR(fde->fd, &error_fds);
++
++    for(n = 0, i = 0; i < select_n; i++) {
++        if(fd_table[i] != 0) n = i;
++    }
++    select_n = n + 1;
++}
++
++static void fdevent_update(fdevent *fde, unsigned events)
++{
++    if(events & FDE_READ) {
++        FD_SET(fde->fd, &read_fds);
++    } else {
++        FD_CLR(fde->fd, &read_fds);
++    }
++    if(events & FDE_WRITE) {
++        FD_SET(fde->fd, &write_fds);
++    } else {
++        FD_CLR(fde->fd, &write_fds);
++    }
++    if(events & FDE_ERROR) {
++        FD_SET(fde->fd, &error_fds);
++    } else {
++        FD_CLR(fde->fd, &error_fds);
++    }
++
++    fde->state = (fde->state & FDE_STATEMASK) | events;
++}
++
++/* Looks at fd_table[] for bad FDs and sets bit in fds.
++** Returns the number of bad FDs.
++*/
++static int fdevent_fd_check(fd_set *fds)
++{
++    int i, n = 0;
++    fdevent *fde;
++
++    for(i = 0; i < select_n; i++) {
++        fde = fd_table[i];
++        if(fde == 0) continue;
++        if(fcntl(i, F_GETFL, NULL) < 0) {
++            FD_SET(i, fds);
++            n++;
++            // fde->state |= FDE_DONT_CLOSE;
++
++        }
++    }
++    return n;
++}
++
++#if !DEBUG
++static inline void dump_all_fds(const char *extra_msg) {}
++#else
++static void dump_all_fds(const char *extra_msg)
++{
++int i;
++    fdevent *fde;
++    // per fd: 4 digits (but really: log10(FD_SETSIZE)), 1 staus, 1 blank
++    char msg_buff[FD_SETSIZE*6 + 1], *pb=msg_buff;
++    size_t max_chars = FD_SETSIZE * 6 + 1;
++    int printed_out;
++#define SAFE_SPRINTF(...)                                                    \
++    do {                                                                     \
++        printed_out = snprintf(pb, max_chars, __VA_ARGS__);                  \
++        if (printed_out <= 0) {                                              \
++            D("... snprintf failed.\n");                                     \
++            return;                                                          \
++        }                                                                    \
++        if (max_chars < (unsigned int)printed_out) {                         \
++            D("... snprintf out of space.\n");                               \
++            return;                                                          \
++        }                                                                    \
++        pb += printed_out;                                                   \
++        max_chars -= printed_out;                                            \
++    } while(0)
++
++    for(i = 0; i < select_n; i++) {
++        fde = fd_table[i];
++        SAFE_SPRINTF("%d", i);
++        if(fde == 0) {
++            SAFE_SPRINTF("? ");
++            continue;
++        }
++        if(fcntl(i, F_GETFL, NULL) < 0) {
++            SAFE_SPRINTF("b");
++        }
++        SAFE_SPRINTF(" ");
++    }
++    D("%s fd_table[]->fd = {%s}\n", extra_msg, msg_buff);
++}
++#endif
++
++static void fdevent_process()
++{
++    int i, n;
++    fdevent *fde;
++    unsigned events;
++    fd_set rfd, wfd, efd;
++
++    memcpy(&rfd, &read_fds, sizeof(fd_set));
++    memcpy(&wfd, &write_fds, sizeof(fd_set));
++    memcpy(&efd, &error_fds, sizeof(fd_set));
++
++    dump_all_fds("pre select()");
++
++    n = select(select_n, &rfd, &wfd, &efd, NULL);
++    int saved_errno = errno;
++    D("select() returned n=%d, errno=%d\n", n, n<0?saved_errno:0);
++
++    dump_all_fds("post select()");
++
++    if(n < 0) {
++        switch(saved_errno) {
++        case EINTR: return;
++        case EBADF:
++            // Can't trust the FD sets after an error.
++            FD_ZERO(&wfd);
++            FD_ZERO(&efd);
++            FD_ZERO(&rfd);
++            break;
++        default:
++            D("Unexpected select() error=%d\n", saved_errno);
++            return;
++        }
++    }
++    if(n <= 0) {
++        // We fake a read, as the rest of the code assumes
++        // that errors will be detected at that point.
++        n = fdevent_fd_check(&rfd);
++    }
++
++    for(i = 0; (i < select_n) && (n > 0); i++) {
++        events = 0;
++        if(FD_ISSET(i, &rfd)) { events |= FDE_READ; n--; }
++        if(FD_ISSET(i, &wfd)) { events |= FDE_WRITE; n--; }
++        if(FD_ISSET(i, &efd)) { events |= FDE_ERROR; n--; }
++
++        if(events) {
++            fde = fd_table[i];
++            if(fde == 0)
++              FATAL("missing fde for fd %d\n", i);
++
++            fde->events |= events;
++
++            D("got events fde->fd=%d events=%04x, state=%04x\n",
++                fde->fd, fde->events, fde->state);
++            if(fde->state & FDE_PENDING) continue;
++            fde->state |= FDE_PENDING;
++            fdevent_plist_enqueue(fde);
++        }
++    }
++}
++
++#endif
++
++static void fdevent_register(fdevent *fde)
++{
++    if(fde->fd < 0) {
++        FATAL("bogus negative fd (%d)\n", fde->fd);
++    }
++
++    if(fde->fd >= fd_table_max) {
++        int oldmax = fd_table_max;
++        if(fde->fd > 32000) {
++            FATAL("bogus huuuuge fd (%d)\n", fde->fd);
++        }
++        if(fd_table_max == 0) {
++            fdevent_init();
++            fd_table_max = 256;
++        }
++        while(fd_table_max <= fde->fd) {
++            fd_table_max *= 2;
++        }
++        fd_table = realloc(fd_table, sizeof(fdevent*) * fd_table_max);
++        if(fd_table == 0) {
++            FATAL("could not expand fd_table to %d entries\n", fd_table_max);
++        }
++        memset(fd_table + oldmax, 0, sizeof(int) * (fd_table_max - oldmax));
++    }
++
++    fd_table[fde->fd] = fde;
++}
++
++static void fdevent_unregister(fdevent *fde)
++{
++    if((fde->fd < 0) || (fde->fd >= fd_table_max)) {
++        FATAL("fd out of range (%d)\n", fde->fd);
++    }
++
++    if(fd_table[fde->fd] != fde) {
++        FATAL("fd_table out of sync [%d]\n", fde->fd);
++    }
++
++    fd_table[fde->fd] = 0;
++
++    if(!(fde->state & FDE_DONT_CLOSE)) {
++        dump_fde(fde, "close");
++        adb_close(fde->fd);
++    }
++}
++
++static void fdevent_plist_enqueue(fdevent *node)
++{
++    fdevent *list = &list_pending;
++
++    node->next = list;
++    node->prev = list->prev;
++    node->prev->next = node;
++    list->prev = node;
++}
++
++static void fdevent_plist_remove(fdevent *node)
++{
++    node->prev->next = node->next;
++    node->next->prev = node->prev;
++    node->next = 0;
++    node->prev = 0;
++}
++
++static fdevent *fdevent_plist_dequeue(void)
++{
++    fdevent *list = &list_pending;
++    fdevent *node = list->next;
++
++    if(node == list) return 0;
++
++    list->next = node->next;
++    list->next->prev = list;
++    node->next = 0;
++    node->prev = 0;
++
++    return node;
++}
++
++static void fdevent_call_fdfunc(fdevent* fde)
++{
++    unsigned events = fde->events;
++    fde->events = 0;
++    if(!(fde->state & FDE_PENDING)) return;
++    fde->state &= (~FDE_PENDING);
++    dump_fde(fde, "callback");
++    fde->func(fde->fd, events, fde->arg);
++}
++
++static void fdevent_subproc_event_func(int fd, unsigned ev, void *userdata)
++{
++
++    D("subproc handling on fd=%d ev=%04x\n", fd, ev);
++
++    // Hook oneself back into the fde's suitable for select() on read.
++    if((fd < 0) || (fd >= fd_table_max)) {
++        FATAL("fd %d out of range for fd_table \n", fd);
++    }
++    fdevent *fde = fd_table[fd];
++    fdevent_add(fde, FDE_READ);
++
++    if(ev & FDE_READ){
++      int subproc_fd;
++
++      if(readx(fd, &subproc_fd, sizeof(subproc_fd))) {
++          FATAL("Failed to read the subproc's fd from fd=%d\n", fd);
++      }
++      if((subproc_fd < 0) || (subproc_fd >= fd_table_max)) {
++          D("subproc_fd %d out of range 0, fd_table_max=%d\n",
++            subproc_fd, fd_table_max);
++          return;
++      }
++      fdevent *subproc_fde = fd_table[subproc_fd];
++      if(!subproc_fde) {
++          D("subproc_fd %d cleared from fd_table\n", subproc_fd);
++          return;
++      }
++      if(subproc_fde->fd != subproc_fd) {
++          // Already reallocated?
++          D("subproc_fd %d != fd_table[].fd %d\n", subproc_fd, subproc_fde->fd);
++          return;
++      }
++
++      subproc_fde->force_eof = 1;
++
++      int rcount = 0;
++      ioctl(subproc_fd, FIONREAD, &rcount);
++      D("subproc with fd=%d  has rcount=%d err=%d\n",
++        subproc_fd, rcount, errno);
++
++      if(rcount) {
++        // If there is data left, it will show up in the select().
++        // This works because there is no other thread reading that
++        // data when in this fd_func().
++        return;
++      }
++
++      D("subproc_fde.state=%04x\n", subproc_fde->state);
++      subproc_fde->events |= FDE_READ;
++      if(subproc_fde->state & FDE_PENDING) {
++        return;
++      }
++      subproc_fde->state |= FDE_PENDING;
++      fdevent_call_fdfunc(subproc_fde);
++    }
++}
++
++fdevent *fdevent_create(int fd, fd_func func, void *arg)
++{
++    fdevent *fde = (fdevent*) malloc(sizeof(fdevent));
++    if(fde == 0) return 0;
++    fdevent_install(fde, fd, func, arg);
++    fde->state |= FDE_CREATED;
++    return fde;
++}
++
++void fdevent_destroy(fdevent *fde)
++{
++    if(fde == 0) return;
++    if(!(fde->state & FDE_CREATED)) {
++        FATAL("fde %p not created by fdevent_create()\n", fde);
++    }
++    fdevent_remove(fde);
++}
++
++void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg)
++{
++    memset(fde, 0, sizeof(fdevent));
++    fde->state = FDE_ACTIVE;
++    fde->fd = fd;
++    fde->force_eof = 0;
++    fde->func = func;
++    fde->arg = arg;
++
++#ifndef HAVE_WINSOCK
++    fcntl(fd, F_SETFL, O_NONBLOCK);
++#endif
++    fdevent_register(fde);
++    dump_fde(fde, "connect");
++    fdevent_connect(fde);
++    fde->state |= FDE_ACTIVE;
++}
++
++void fdevent_remove(fdevent *fde)
++{
++    if(fde->state & FDE_PENDING) {
++        fdevent_plist_remove(fde);
++    }
++
++    if(fde->state & FDE_ACTIVE) {
++        fdevent_disconnect(fde);
++        dump_fde(fde, "disconnect");
++        fdevent_unregister(fde);
++    }
++
++    fde->state = 0;
++    fde->events = 0;
++}
++
++
++void fdevent_set(fdevent *fde, unsigned events)
++{
++    events &= FDE_EVENTMASK;
++
++    if((fde->state & FDE_EVENTMASK) == events) return;
++
++    if(fde->state & FDE_ACTIVE) {
++        fdevent_update(fde, events);
++        dump_fde(fde, "update");
++    }
++
++    fde->state = (fde->state & FDE_STATEMASK) | events;
++
++    if(fde->state & FDE_PENDING) {
++            /* if we're pending, make sure
++            ** we don't signal an event that
++            ** is no longer wanted.
++            */
++        fde->events &= (~events);
++        if(fde->events == 0) {
++            fdevent_plist_remove(fde);
++            fde->state &= (~FDE_PENDING);
++        }
++    }
++}
++
++void fdevent_add(fdevent *fde, unsigned events)
++{
++    fdevent_set(
++        fde, (fde->state & FDE_EVENTMASK) | (events & FDE_EVENTMASK));
++}
++
++void fdevent_del(fdevent *fde, unsigned events)
++{
++    fdevent_set(
++        fde, (fde->state & FDE_EVENTMASK) & (~(events & FDE_EVENTMASK)));
++}
++
++void fdevent_subproc_setup()
++{
++    int s[2];
++
++    if(adb_socketpair(s)) {
++        FATAL("cannot create shell-exit socket-pair\n");
++    }
++    SHELL_EXIT_NOTIFY_FD = s[0];
++    fdevent *fde;
++    fde = fdevent_create(s[1], fdevent_subproc_event_func, NULL);
++    if(!fde)
++      FATAL("cannot create fdevent for shell-exit handler\n");
++    fdevent_add(fde, FDE_READ);
++}
++
++void fdevent_loop()
++{
++    fdevent *fde;
++    fdevent_subproc_setup();
++
++    for(;;) {
++        D("--- ---- waiting for events\n");
++
++        fdevent_process();
++
++        while((fde = fdevent_plist_dequeue())) {
++            fdevent_call_fdfunc(fde);
++        }
++    }
++}
+Index: android-tools-4.2.2+git20130218/core/adbd/fdevent.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/fdevent.h        2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,83 @@
++/*
++ * Copyright (C) 2006 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#ifndef __FDEVENT_H
++#define __FDEVENT_H
++
++#include <stdint.h>  /* for int64_t */
++
++/* events that may be observed */
++#define FDE_READ              0x0001
++#define FDE_WRITE             0x0002
++#define FDE_ERROR             0x0004
++#define FDE_TIMEOUT           0x0008
++
++/* features that may be set (via the events set/add/del interface) */
++#define FDE_DONT_CLOSE        0x0080
++
++typedef struct fdevent fdevent;
++
++typedef void (*fd_func)(int fd, unsigned events, void *userdata);
++
++/* Allocate and initialize a new fdevent object
++ * Note: use FD_TIMER as 'fd' to create a fd-less object
++ * (used to implement timers).
++*/
++fdevent *fdevent_create(int fd, fd_func func, void *arg);
++
++/* Uninitialize and deallocate an fdevent object that was
++** created by fdevent_create()
++*/
++void fdevent_destroy(fdevent *fde);
++
++/* Initialize an fdevent object that was externally allocated
++*/
++void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg);
++
++/* Uninitialize an fdevent object that was initialized by
++** fdevent_install()
++*/
++void fdevent_remove(fdevent *item);
++
++/* Change which events should cause notifications
++*/
++void fdevent_set(fdevent *fde, unsigned events);
++void fdevent_add(fdevent *fde, unsigned events);
++void fdevent_del(fdevent *fde, unsigned events);
++
++void fdevent_set_timeout(fdevent *fde, int64_t  timeout_ms);
++
++/* loop forever, handling events.
++*/
++void fdevent_loop();
++
++struct fdevent 
++{
++    fdevent *next;
++    fdevent *prev;
++
++    int fd;
++    int force_eof;
++
++    unsigned short state;
++    unsigned short events;
++
++    fd_func func;
++    void *arg;
++};
++
++
++#endif
+Index: android-tools-4.2.2+git20130218/core/adbd/file_sync_client.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/file_sync_client.c       2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,1024 @@
++/*
++ * Copyright (C) 2007 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <errno.h>
++#include <sys/stat.h>
++#include <sys/time.h>
++#include <time.h>
++#include <dirent.h>
++#include <limits.h>
++#include <sys/types.h>
++#include <zipfile/zipfile.h>
++
++#include "sysdeps.h"
++#include "adb.h"
++#include "adb_client.h"
++#include "file_sync_service.h"
++
++
++static unsigned total_bytes;
++static long long start_time;
++
++static long long NOW()
++{
++    struct timeval tv;
++    gettimeofday(&tv, 0);
++    return ((long long) tv.tv_usec) +
++        1000000LL * ((long long) tv.tv_sec);
++}
++
++static void BEGIN()
++{
++    total_bytes = 0;
++    start_time = NOW();
++}
++
++static void END()
++{
++    long long t = NOW() - start_time;
++    if(total_bytes == 0) return;
++
++    if (t == 0)  /* prevent division by 0 :-) */
++        t = 1000000;
++
++    fprintf(stderr,"%lld KB/s (%lld bytes in %lld.%03llds)\n",
++            ((((long long) total_bytes) * 1000000LL) / t) / 1024LL,
++            (long long) total_bytes, (t / 1000000LL), (t % 1000000LL) / 1000LL);
++}
++
++void sync_quit(int fd)
++{
++    syncmsg msg;
++
++    msg.req.id = ID_QUIT;
++    msg.req.namelen = 0;
++
++    writex(fd, &msg.req, sizeof(msg.req));
++}
++
++typedef void (*sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char *name, void *cookie);
++
++int sync_ls(int fd, const char *path, sync_ls_cb func, void *cookie)
++{
++    syncmsg msg;
++    char buf[257];
++    int len;
++
++    len = strlen(path);
++    if(len > 1024) goto fail;
++
++    msg.req.id = ID_LIST;
++    msg.req.namelen = htoll(len);
++
++    if(writex(fd, &msg.req, sizeof(msg.req)) ||
++       writex(fd, path, len)) {
++        goto fail;
++    }
++
++    for(;;) {
++        if(readx(fd, &msg.dent, sizeof(msg.dent))) break;
++        if(msg.dent.id == ID_DONE) return 0;
++        if(msg.dent.id != ID_DENT) break;
++
++        len = ltohl(msg.dent.namelen);
++        if(len > 256) break;
++
++        if(readx(fd, buf, len)) break;
++        buf[len] = 0;
++
++        func(ltohl(msg.dent.mode),
++             ltohl(msg.dent.size),
++             ltohl(msg.dent.time),
++             buf, cookie);
++    }
++
++fail:
++    adb_close(fd);
++    return -1;
++}
++
++typedef struct syncsendbuf syncsendbuf;
++
++struct syncsendbuf {
++    unsigned id;
++    unsigned size;
++    char data[SYNC_DATA_MAX];
++};
++
++static syncsendbuf send_buffer;
++
++int sync_readtime(int fd, const char *path, unsigned *timestamp)
++{
++    syncmsg msg;
++    int len = strlen(path);
++
++    msg.req.id = ID_STAT;
++    msg.req.namelen = htoll(len);
++
++    if(writex(fd, &msg.req, sizeof(msg.req)) ||
++       writex(fd, path, len)) {
++        return -1;
++    }
++
++    if(readx(fd, &msg.stat, sizeof(msg.stat))) {
++        return -1;
++    }
++
++    if(msg.stat.id != ID_STAT) {
++        return -1;
++    }
++
++    *timestamp = ltohl(msg.stat.time);
++    return 0;
++}
++
++static int sync_start_readtime(int fd, const char *path)
++{
++    syncmsg msg;
++    int len = strlen(path);
++
++    msg.req.id = ID_STAT;
++    msg.req.namelen = htoll(len);
++
++    if(writex(fd, &msg.req, sizeof(msg.req)) ||
++       writex(fd, path, len)) {
++        return -1;
++    }
++
++    return 0;
++}
++
++static int sync_finish_readtime(int fd, unsigned int *timestamp,
++                                unsigned int *mode, unsigned int *size)
++{
++    syncmsg msg;
++
++    if(readx(fd, &msg.stat, sizeof(msg.stat)))
++        return -1;
++
++    if(msg.stat.id != ID_STAT)
++        return -1;
++
++    *timestamp = ltohl(msg.stat.time);
++    *mode = ltohl(msg.stat.mode);
++    *size = ltohl(msg.stat.size);
++
++    return 0;
++}
++
++int sync_readmode(int fd, const char *path, unsigned *mode)
++{
++    syncmsg msg;
++    int len = strlen(path);
++
++    msg.req.id = ID_STAT;
++    msg.req.namelen = htoll(len);
++
++    if(writex(fd, &msg.req, sizeof(msg.req)) ||
++       writex(fd, path, len)) {
++        return -1;
++    }
++
++    if(readx(fd, &msg.stat, sizeof(msg.stat))) {
++        return -1;
++    }
++
++    if(msg.stat.id != ID_STAT) {
++        return -1;
++    }
++
++    *mode = ltohl(msg.stat.mode);
++    return 0;
++}
++
++static int write_data_file(int fd, const char *path, syncsendbuf *sbuf)
++{
++    int lfd, err = 0;
++
++    lfd = adb_open(path, O_RDONLY);
++    if(lfd < 0) {
++        fprintf(stderr,"cannot open '%s': %s\n", path, strerror(errno));
++        return -1;
++    }
++
++    sbuf->id = ID_DATA;
++    for(;;) {
++        int ret;
++
++        ret = adb_read(lfd, sbuf->data, SYNC_DATA_MAX);
++        if(!ret)
++            break;
++
++        if(ret < 0) {
++            if(errno == EINTR)
++                continue;
++            fprintf(stderr,"cannot read '%s': %s\n", path, strerror(errno));
++            break;
++        }
++
++        sbuf->size = htoll(ret);
++        if(writex(fd, sbuf, sizeof(unsigned) * 2 + ret)){
++            err = -1;
++            break;
++        }
++        total_bytes += ret;
++    }
++
++    adb_close(lfd);
++    return err;
++}
++
++static int write_data_buffer(int fd, char* file_buffer, int size, syncsendbuf *sbuf)
++{
++    int err = 0;
++    int total = 0;
++
++    sbuf->id = ID_DATA;
++    while (total < size) {
++        int count = size - total;
++        if (count > SYNC_DATA_MAX) {
++            count = SYNC_DATA_MAX;
++        }
++
++        memcpy(sbuf->data, &file_buffer[total], count);
++        sbuf->size = htoll(count);
++        if(writex(fd, sbuf, sizeof(unsigned) * 2 + count)){
++            err = -1;
++            break;
++        }
++        total += count;
++        total_bytes += count;
++    }
++
++    return err;
++}
++
++#ifdef HAVE_SYMLINKS
++static int write_data_link(int fd, const char *path, syncsendbuf *sbuf)
++{
++    int len, ret;
++
++    len = readlink(path, sbuf->data, SYNC_DATA_MAX-1);
++    if(len < 0) {
++        fprintf(stderr, "error reading link '%s': %s\n", path, strerror(errno));
++        return -1;
++    }
++    sbuf->data[len] = '\0';
++
++    sbuf->size = htoll(len + 1);
++    sbuf->id = ID_DATA;
++
++    ret = writex(fd, sbuf, sizeof(unsigned) * 2 + len + 1);
++    if(ret)
++        return -1;
++
++    total_bytes += len + 1;
++
++    return 0;
++}
++#endif
++
++static int sync_send(int fd, const char *lpath, const char *rpath,
++                     unsigned mtime, mode_t mode, int verifyApk)
++{
++    syncmsg msg;
++    int len, r;
++    syncsendbuf *sbuf = &send_buffer;
++    char* file_buffer = NULL;
++    int size = 0;
++    char tmp[64];
++
++    len = strlen(rpath);
++    if(len > 1024) goto fail;
++
++    snprintf(tmp, sizeof(tmp), ",%d", mode);
++    r = strlen(tmp);
++
++    if (verifyApk) {
++        int lfd;
++        zipfile_t zip;
++        zipentry_t entry;
++        int amt;
++
++        // if we are transferring an APK file, then sanity check to make sure
++        // we have a real zip file that contains an AndroidManifest.xml
++        // this requires that we read the entire file into memory.
++        lfd = adb_open(lpath, O_RDONLY);
++        if(lfd < 0) {
++            fprintf(stderr,"cannot open '%s': %s\n", lpath, strerror(errno));
++            return -1;
++        }
++
++        size = adb_lseek(lfd, 0, SEEK_END);
++        if (size == -1 || -1 == adb_lseek(lfd, 0, SEEK_SET)) {
++            fprintf(stderr, "error seeking in file '%s'\n", lpath);
++            adb_close(lfd);
++            return 1;
++        }
++
++        file_buffer = (char *)malloc(size);
++        if (file_buffer == NULL) {
++            fprintf(stderr, "could not allocate buffer for '%s'\n",
++                    lpath);
++            adb_close(lfd);
++            return 1;
++        }
++        amt = adb_read(lfd, file_buffer, size);
++        if (amt != size) {
++            fprintf(stderr, "error reading from file: '%s'\n", lpath);
++            adb_close(lfd);
++            free(file_buffer);
++            return 1;
++        }
++
++        adb_close(lfd);
++
++        zip = init_zipfile(file_buffer, size);
++        if (zip == NULL) {
++            fprintf(stderr, "file '%s' is not a valid zip file\n",
++                    lpath);
++            free(file_buffer);
++            return 1;
++        }
++
++        entry = lookup_zipentry(zip, "AndroidManifest.xml");
++        release_zipfile(zip);
++        if (entry == NULL) {
++            fprintf(stderr, "file '%s' does not contain AndroidManifest.xml\n",
++                    lpath);
++            free(file_buffer);
++            return 1;
++        }
++    }
++
++    msg.req.id = ID_SEND;
++    msg.req.namelen = htoll(len + r);
++
++    if(writex(fd, &msg.req, sizeof(msg.req)) ||
++       writex(fd, rpath, len) || writex(fd, tmp, r)) {
++        free(file_buffer);
++        goto fail;
++    }
++
++    if (file_buffer) {
++        write_data_buffer(fd, file_buffer, size, sbuf);
++        free(file_buffer);
++    } else if (S_ISREG(mode))
++        write_data_file(fd, lpath, sbuf);
++#ifdef HAVE_SYMLINKS
++    else if (S_ISLNK(mode))
++        write_data_link(fd, lpath, sbuf);
++#endif
++    else
++        goto fail;
++
++    msg.data.id = ID_DONE;
++    msg.data.size = htoll(mtime);
++    if(writex(fd, &msg.data, sizeof(msg.data)))
++        goto fail;
++
++    if(readx(fd, &msg.status, sizeof(msg.status)))
++        return -1;
++
++    if(msg.status.id != ID_OKAY) {
++        if(msg.status.id == ID_FAIL) {
++            len = ltohl(msg.status.msglen);
++            if(len > 256) len = 256;
++            if(readx(fd, sbuf->data, len)) {
++                return -1;
++            }
++            sbuf->data[len] = 0;
++        } else
++            strcpy(sbuf->data, "unknown reason");
++
++        fprintf(stderr,"failed to copy '%s' to '%s': %s\n", lpath, rpath, sbuf->data);
++        return -1;
++    }
++
++    return 0;
++
++fail:
++    fprintf(stderr,"protocol failure\n");
++    adb_close(fd);
++    return -1;
++}
++
++static int mkdirs(char *name)
++{
++    int ret;
++    char *x = name + 1;
++
++    for(;;) {
++        x = adb_dirstart(x);
++        if(x == 0) return 0;
++        *x = 0;
++        ret = adb_mkdir(name, 0775);
++        *x = OS_PATH_SEPARATOR;
++        if((ret < 0) && (errno != EEXIST)) {
++            return ret;
++        }
++        x++;
++    }
++    return 0;
++}
++
++int sync_recv(int fd, const char *rpath, const char *lpath)
++{
++    syncmsg msg;
++    int len;
++    int lfd = -1;
++    char *buffer = send_buffer.data;
++    unsigned id;
++
++    len = strlen(rpath);
++    if(len > 1024) return -1;
++
++    msg.req.id = ID_RECV;
++    msg.req.namelen = htoll(len);
++    if(writex(fd, &msg.req, sizeof(msg.req)) ||
++       writex(fd, rpath, len)) {
++        return -1;
++    }
++
++    if(readx(fd, &msg.data, sizeof(msg.data))) {
++        return -1;
++    }
++    id = msg.data.id;
++
++    if((id == ID_DATA) || (id == ID_DONE)) {
++        adb_unlink(lpath);
++        mkdirs((char *)lpath);
++        lfd = adb_creat(lpath, 0644);
++        if(lfd < 0) {
++            fprintf(stderr,"cannot create '%s': %s\n", lpath, strerror(errno));
++            return -1;
++        }
++        goto handle_data;
++    } else {
++        goto remote_error;
++    }
++
++    for(;;) {
++        if(readx(fd, &msg.data, sizeof(msg.data))) {
++            return -1;
++        }
++        id = msg.data.id;
++
++    handle_data:
++        len = ltohl(msg.data.size);
++        if(id == ID_DONE) break;
++        if(id != ID_DATA) goto remote_error;
++        if(len > SYNC_DATA_MAX) {
++            fprintf(stderr,"data overrun\n");
++            adb_close(lfd);
++            return -1;
++        }
++
++        if(readx(fd, buffer, len)) {
++            adb_close(lfd);
++            return -1;
++        }
++
++        if(writex(lfd, buffer, len)) {
++            fprintf(stderr,"cannot write '%s': %s\n", rpath, strerror(errno));
++            adb_close(lfd);
++            return -1;
++        }
++
++        total_bytes += len;
++    }
++
++    adb_close(lfd);
++    return 0;
++
++remote_error:
++    adb_close(lfd);
++    adb_unlink(lpath);
++
++    if(id == ID_FAIL) {
++        len = ltohl(msg.data.size);
++        if(len > 256) len = 256;
++        if(readx(fd, buffer, len)) {
++            return -1;
++        }
++        buffer[len] = 0;
++    } else {
++        memcpy(buffer, &id, 4);
++        buffer[4] = 0;
++//        strcpy(buffer,"unknown reason");
++    }
++    fprintf(stderr,"failed to copy '%s' to '%s': %s\n", rpath, lpath, buffer);
++    return 0;
++}
++
++
++
++/* --- */
++
++
++static void do_sync_ls_cb(unsigned mode, unsigned size, unsigned time,
++                          const char *name, void *cookie)
++{
++    printf("%08x %08x %08x %s\n", mode, size, time, name);
++}
++
++int do_sync_ls(const char *path)
++{
++    int fd = adb_connect("sync:");
++    if(fd < 0) {
++        fprintf(stderr,"error: %s\n", adb_error());
++        return 1;
++    }
++
++    if(sync_ls(fd, path, do_sync_ls_cb, 0)) {
++        return 1;
++    } else {
++        sync_quit(fd);
++        return 0;
++    }
++}
++
++typedef struct copyinfo copyinfo;
++
++struct copyinfo
++{
++    copyinfo *next;
++    const char *src;
++    const char *dst;
++    unsigned int time;
++    unsigned int mode;
++    unsigned int size;
++    int flag;
++    //char data[0];
++};
++
++copyinfo *mkcopyinfo(const char *spath, const char *dpath,
++                     const char *name, int isdir)
++{
++    int slen = strlen(spath);
++    int dlen = strlen(dpath);
++    int nlen = strlen(name);
++    int ssize = slen + nlen + 2;
++    int dsize = dlen + nlen + 2;
++
++    copyinfo *ci = malloc(sizeof(copyinfo) + ssize + dsize);
++    if(ci == 0) {
++        fprintf(stderr,"out of memory\n");
++        abort();
++    }
++
++    ci->next = 0;
++    ci->time = 0;
++    ci->mode = 0;
++    ci->size = 0;
++    ci->flag = 0;
++    ci->src = (const char*)(ci + 1);
++    ci->dst = ci->src + ssize;
++    snprintf((char*) ci->src, ssize, isdir ? "%s%s/" : "%s%s", spath, name);
++    snprintf((char*) ci->dst, dsize, isdir ? "%s%s/" : "%s%s", dpath, name);
++
++//    fprintf(stderr,"mkcopyinfo('%s','%s')\n", ci->src, ci->dst);
++    return ci;
++}
++
++
++static int local_build_list(copyinfo **filelist,
++                            const char *lpath, const char *rpath)
++{
++    DIR *d;
++    struct dirent *de;
++    struct stat st;
++    copyinfo *dirlist = 0;
++    copyinfo *ci, *next;
++
++//    fprintf(stderr,"local_build_list('%s','%s')\n", lpath, rpath);
++
++    d = opendir(lpath);
++    if(d == 0) {
++        fprintf(stderr,"cannot open '%s': %s\n", lpath, strerror(errno));
++        return -1;
++    }
++
++    while((de = readdir(d))) {
++        char stat_path[PATH_MAX];
++        char *name = de->d_name;
++
++        if(name[0] == '.') {
++            if(name[1] == 0) continue;
++            if((name[1] == '.') && (name[2] == 0)) continue;
++        }
++
++        /*
++         * We could use d_type if HAVE_DIRENT_D_TYPE is defined, but reiserfs
++         * always returns DT_UNKNOWN, so we just use stat() for all cases.
++         */
++        if (strlen(lpath) + strlen(de->d_name) + 1 > sizeof(stat_path))
++            continue;
++        strcpy(stat_path, lpath);
++        strcat(stat_path, de->d_name);
++        stat(stat_path, &st);
++
++        if (S_ISDIR(st.st_mode)) {
++            ci = mkcopyinfo(lpath, rpath, name, 1);
++            ci->next = dirlist;
++            dirlist = ci;
++        } else {
++            ci = mkcopyinfo(lpath, rpath, name, 0);
++            if(lstat(ci->src, &st)) {
++                fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno));
++                closedir(d);
++
++                return -1;
++            }
++            if(!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
++                fprintf(stderr, "skipping special file '%s'\n", ci->src);
++                free(ci);
++            } else {
++                ci->time = st.st_mtime;
++                ci->mode = st.st_mode;
++                ci->size = st.st_size;
++                ci->next = *filelist;
++                *filelist = ci;
++            }
++        }
++    }
++
++    closedir(d);
++
++    for(ci = dirlist; ci != 0; ci = next) {
++        next = ci->next;
++        local_build_list(filelist, ci->src, ci->dst);
++        free(ci);
++    }
++
++    return 0;
++}
++
++
++static int copy_local_dir_remote(int fd, const char *lpath, const char *rpath, int checktimestamps, int listonly)
++{
++    copyinfo *filelist = 0;
++    copyinfo *ci, *next;
++    int pushed = 0;
++    int skipped = 0;
++
++    if((lpath[0] == 0) || (rpath[0] == 0)) return -1;
++    if(lpath[strlen(lpath) - 1] != '/') {
++        int  tmplen = strlen(lpath)+2;
++        char *tmp = malloc(tmplen);
++        if(tmp == 0) return -1;
++        snprintf(tmp, tmplen, "%s/",lpath);
++        lpath = tmp;
++    }
++    if(rpath[strlen(rpath) - 1] != '/') {
++        int tmplen = strlen(rpath)+2;
++        char *tmp = malloc(tmplen);
++        if(tmp == 0) return -1;
++        snprintf(tmp, tmplen, "%s/",rpath);
++        rpath = tmp;
++    }
++
++    if(local_build_list(&filelist, lpath, rpath)) {
++        return -1;
++    }
++
++    if(checktimestamps){
++        for(ci = filelist; ci != 0; ci = ci->next) {
++            if(sync_start_readtime(fd, ci->dst)) {
++                return 1;
++            }
++        }
++        for(ci = filelist; ci != 0; ci = ci->next) {
++            unsigned int timestamp, mode, size;
++            if(sync_finish_readtime(fd, &timestamp, &mode, &size))
++                return 1;
++            if(size == ci->size) {
++                /* for links, we cannot update the atime/mtime */
++                if((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
++                    (S_ISLNK(ci->mode & mode) && timestamp >= ci->time))
++                    ci->flag = 1;
++            }
++        }
++    }
++    for(ci = filelist; ci != 0; ci = next) {
++        next = ci->next;
++        if(ci->flag == 0) {
++            fprintf(stderr,"%spush: %s -> %s\n", listonly ? "would " : "", ci->src, ci->dst);
++            if(!listonly &&
++               sync_send(fd, ci->src, ci->dst, ci->time, ci->mode, 0 /* no verify APK */)){
++                return 1;
++            }
++            pushed++;
++        } else {
++            skipped++;
++        }
++        free(ci);
++    }
++
++    fprintf(stderr,"%d file%s pushed. %d file%s skipped.\n",
++            pushed, (pushed == 1) ? "" : "s",
++            skipped, (skipped == 1) ? "" : "s");
++
++    return 0;
++}
++
++
++int do_sync_push(const char *lpath, const char *rpath, int verifyApk)
++{
++    struct stat st;
++    unsigned mode;
++    int fd;
++
++    fd = adb_connect("sync:");
++    if(fd < 0) {
++        fprintf(stderr,"error: %s\n", adb_error());
++        return 1;
++    }
++
++    if(stat(lpath, &st)) {
++        fprintf(stderr,"cannot stat '%s': %s\n", lpath, strerror(errno));
++        sync_quit(fd);
++        return 1;
++    }
++
++    if(S_ISDIR(st.st_mode)) {
++        BEGIN();
++        if(copy_local_dir_remote(fd, lpath, rpath, 0, 0)) {
++            return 1;
++        } else {
++            END();
++            sync_quit(fd);
++        }
++    } else {
++        if(sync_readmode(fd, rpath, &mode)) {
++            return 1;
++        }
++        if((mode != 0) && S_ISDIR(mode)) {
++                /* if we're copying a local file to a remote directory,
++                ** we *really* want to copy to remotedir + "/" + localfilename
++                */
++            const char *name = adb_dirstop(lpath);
++            if(name == 0) {
++                name = lpath;
++            } else {
++                name++;
++            }
++            int  tmplen = strlen(name) + strlen(rpath) + 2;
++            char *tmp = malloc(strlen(name) + strlen(rpath) + 2);
++            if(tmp == 0) return 1;
++            snprintf(tmp, tmplen, "%s/%s", rpath, name);
++            rpath = tmp;
++        }
++        BEGIN();
++        if(sync_send(fd, lpath, rpath, st.st_mtime, st.st_mode, verifyApk)) {
++            return 1;
++        } else {
++            END();
++            sync_quit(fd);
++            return 0;
++        }
++    }
++
++    return 0;
++}
++
++
++typedef struct {
++    copyinfo **filelist;
++    copyinfo **dirlist;
++    const char *rpath;
++    const char *lpath;
++} sync_ls_build_list_cb_args;
++
++void
++sync_ls_build_list_cb(unsigned mode, unsigned size, unsigned time,
++                      const char *name, void *cookie)
++{
++    sync_ls_build_list_cb_args *args = (sync_ls_build_list_cb_args *)cookie;
++    copyinfo *ci;
++
++    if (S_ISDIR(mode)) {
++        copyinfo **dirlist = args->dirlist;
++
++        /* Don't try recursing down "." or ".." */
++        if (name[0] == '.') {
++            if (name[1] == '\0') return;
++            if ((name[1] == '.') && (name[2] == '\0')) return;
++        }
++
++        ci = mkcopyinfo(args->rpath, args->lpath, name, 1);
++        ci->next = *dirlist;
++        *dirlist = ci;
++    } else if (S_ISREG(mode) || S_ISLNK(mode)) {
++        copyinfo **filelist = args->filelist;
++
++        ci = mkcopyinfo(args->rpath, args->lpath, name, 0);
++        ci->time = time;
++        ci->mode = mode;
++        ci->size = size;
++        ci->next = *filelist;
++        *filelist = ci;
++    } else {
++        fprintf(stderr, "skipping special file '%s'\n", name);
++    }
++}
++
++static int remote_build_list(int syncfd, copyinfo **filelist,
++                             const char *rpath, const char *lpath)
++{
++    copyinfo *dirlist = NULL;
++    sync_ls_build_list_cb_args args;
++
++    args.filelist = filelist;
++    args.dirlist = &dirlist;
++    args.rpath = rpath;
++    args.lpath = lpath;
++
++    /* Put the files/dirs in rpath on the lists. */
++    if (sync_ls(syncfd, rpath, sync_ls_build_list_cb, (void *)&args)) {
++        return 1;
++    }
++
++    /* Recurse into each directory we found. */
++    while (dirlist != NULL) {
++        copyinfo *next = dirlist->next;
++        if (remote_build_list(syncfd, filelist, dirlist->src, dirlist->dst)) {
++            return 1;
++        }
++        free(dirlist);
++        dirlist = next;
++    }
++
++    return 0;
++}
++
++static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath,
++                                 int checktimestamps)
++{
++    copyinfo *filelist = 0;
++    copyinfo *ci, *next;
++    int pulled = 0;
++    int skipped = 0;
++
++    /* Make sure that both directory paths end in a slash. */
++    if (rpath[0] == 0 || lpath[0] == 0) return -1;
++    if (rpath[strlen(rpath) - 1] != '/') {
++        int  tmplen = strlen(rpath) + 2;
++        char *tmp = malloc(tmplen);
++        if (tmp == 0) return -1;
++        snprintf(tmp, tmplen, "%s/", rpath);
++        rpath = tmp;
++    }
++    if (lpath[strlen(lpath) - 1] != '/') {
++        int  tmplen = strlen(lpath) + 2;
++        char *tmp = malloc(tmplen);
++        if (tmp == 0) return -1;
++        snprintf(tmp, tmplen, "%s/", lpath);
++        lpath = tmp;
++    }
++
++    fprintf(stderr, "pull: building file list...\n");
++    /* Recursively build the list of files to copy. */
++    if (remote_build_list(fd, &filelist, rpath, lpath)) {
++        return -1;
++    }
++
++#if 0
++    if (checktimestamps) {
++        for (ci = filelist; ci != 0; ci = ci->next) {
++            if (sync_start_readtime(fd, ci->dst)) {
++                return 1;
++            }
++        }
++        for (ci = filelist; ci != 0; ci = ci->next) {
++            unsigned int timestamp, mode, size;
++            if (sync_finish_readtime(fd, &timestamp, &mode, &size))
++                return 1;
++            if (size == ci->size) {
++                /* for links, we cannot update the atime/mtime */
++                if ((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
++                    (S_ISLNK(ci->mode & mode) && timestamp >= ci->time))
++                    ci->flag = 1;
++            }
++        }
++    }
++#endif
++    for (ci = filelist; ci != 0; ci = next) {
++        next = ci->next;
++        if (ci->flag == 0) {
++            fprintf(stderr, "pull: %s -> %s\n", ci->src, ci->dst);
++            if (sync_recv(fd, ci->src, ci->dst)) {
++                return 1;
++            }
++            pulled++;
++        } else {
++            skipped++;
++        }
++        free(ci);
++    }
++
++    fprintf(stderr, "%d file%s pulled. %d file%s skipped.\n",
++            pulled, (pulled == 1) ? "" : "s",
++            skipped, (skipped == 1) ? "" : "s");
++
++    return 0;
++}
++
++int do_sync_pull(const char *rpath, const char *lpath)
++{
++    unsigned mode;
++    struct stat st;
++
++    int fd;
++
++    fd = adb_connect("sync:");
++    if(fd < 0) {
++        fprintf(stderr,"error: %s\n", adb_error());
++        return 1;
++    }
++
++    if(sync_readmode(fd, rpath, &mode)) {
++        return 1;
++    }
++    if(mode == 0) {
++        fprintf(stderr,"remote object '%s' does not exist\n", rpath);
++        return 1;
++    }
++
++    if(S_ISREG(mode) || S_ISLNK(mode) || S_ISCHR(mode) || S_ISBLK(mode)) {
++        if(stat(lpath, &st) == 0) {
++            if(S_ISDIR(st.st_mode)) {
++                    /* if we're copying a remote file to a local directory,
++                    ** we *really* want to copy to localdir + "/" + remotefilename
++                    */
++                const char *name = adb_dirstop(rpath);
++                if(name == 0) {
++                    name = rpath;
++                } else {
++                    name++;
++                }
++                int  tmplen = strlen(name) + strlen(lpath) + 2;
++                char *tmp = malloc(tmplen);
++                if(tmp == 0) return 1;
++                snprintf(tmp, tmplen, "%s/%s", lpath, name);
++                lpath = tmp;
++            }
++        }
++        BEGIN();
++        if(sync_recv(fd, rpath, lpath)) {
++            return 1;
++        } else {
++            END();
++            sync_quit(fd);
++            return 0;
++        }
++    } else if(S_ISDIR(mode)) {
++        BEGIN();
++        if (copy_remote_dir_local(fd, rpath, lpath, 0)) {
++            return 1;
++        } else {
++            END();
++            sync_quit(fd);
++            return 0;
++        }
++    } else {
++        fprintf(stderr,"remote object '%s' not a file or directory\n", rpath);
++        return 1;
++    }
++}
++
++int do_sync_sync(const char *lpath, const char *rpath, int listonly)
++{
++    fprintf(stderr,"syncing %s...\n",rpath);
++
++    int fd = adb_connect("sync:");
++    if(fd < 0) {
++        fprintf(stderr,"error: %s\n", adb_error());
++        return 1;
++    }
++
++    BEGIN();
++    if(copy_local_dir_remote(fd, lpath, rpath, 1, listonly)){
++        return 1;
++    } else {
++        END();
++        sync_quit(fd);
++        return 0;
++    }
++}
+Index: android-tools-4.2.2+git20130218/core/adbd/file_sync_service.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/file_sync_service.c      2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,414 @@
++/*
++ * Copyright (C) 2007 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++
++#include <sys/stat.h>
++#include <sys/types.h>
++#include <dirent.h>
++#include <utime.h>
++
++#include <errno.h>
++
++#include "sysdeps.h"
++
++#define TRACE_TAG  TRACE_SYNC
++#include "adb.h"
++#include "file_sync_service.h"
++
++static int mkdirs(char *name)
++{
++    int ret;
++    char *x = name + 1;
++
++    if(name[0] != '/') return -1;
++
++    for(;;) {
++        x = adb_dirstart(x);
++        if(x == 0) return 0;
++        *x = 0;
++        ret = adb_mkdir(name, 0775);
++        if((ret < 0) && (errno != EEXIST)) {
++            D("mkdir(\"%s\") -> %s\n", name, strerror(errno));
++            *x = '/';
++            return ret;
++        }
++        *x++ = '/';
++    }
++    return 0;
++}
++
++static int do_stat(int s, const char *path)
++{
++    syncmsg msg;
++    struct stat st;
++
++    msg.stat.id = ID_STAT;
++
++    if(lstat(path, &st)) {
++        msg.stat.mode = 0;
++        msg.stat.size = 0;
++        msg.stat.time = 0;
++    } else {
++        msg.stat.mode = htoll(st.st_mode);
++        msg.stat.size = htoll(st.st_size);
++        msg.stat.time = htoll(st.st_mtime);
++    }
++
++    return writex(s, &msg.stat, sizeof(msg.stat));
++}
++
++static int do_list(int s, const char *path)
++{
++    DIR *d;
++    struct dirent *de;
++    struct stat st;
++    syncmsg msg;
++    int len;
++
++    char tmp[1024 + 256 + 1];
++    char *fname;
++
++    len = strlen(path);
++    memcpy(tmp, path, len);
++    tmp[len] = '/';
++    fname = tmp + len + 1;
++
++    msg.dent.id = ID_DENT;
++
++    d = opendir(path);
++    if(d == 0) goto done;
++
++    while((de = readdir(d))) {
++        int len = strlen(de->d_name);
++
++            /* not supposed to be possible, but
++               if it does happen, let's not buffer overrun */
++        if(len > 256) continue;
++
++        strcpy(fname, de->d_name);
++        if(lstat(tmp, &st) == 0) {
++            msg.dent.mode = htoll(st.st_mode);
++            msg.dent.size = htoll(st.st_size);
++            msg.dent.time = htoll(st.st_mtime);
++            msg.dent.namelen = htoll(len);
++
++            if(writex(s, &msg.dent, sizeof(msg.dent)) ||
++               writex(s, de->d_name, len)) {
++                return -1;
++            }
++        }
++    }
++
++    closedir(d);
++
++done:
++    msg.dent.id = ID_DONE;
++    msg.dent.mode = 0;
++    msg.dent.size = 0;
++    msg.dent.time = 0;
++    msg.dent.namelen = 0;
++    return writex(s, &msg.dent, sizeof(msg.dent));
++}
++
++static int fail_message(int s, const char *reason)
++{
++    syncmsg msg;
++    int len = strlen(reason);
++
++    D("sync: failure: %s\n", reason);
++
++    msg.data.id = ID_FAIL;
++    msg.data.size = htoll(len);
++    if(writex(s, &msg.data, sizeof(msg.data)) ||
++       writex(s, reason, len)) {
++        return -1;
++    } else {
++        return 0;
++    }
++}
++
++static int fail_errno(int s)
++{
++    return fail_message(s, strerror(errno));
++}
++
++static int handle_send_file(int s, char *path, mode_t mode, char *buffer)
++{
++    syncmsg msg;
++    unsigned int timestamp = 0;
++    int fd;
++
++    fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode);
++    if(fd < 0 && errno == ENOENT) {
++        mkdirs(path);
++        fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode);
++    }
++    if(fd < 0 && errno == EEXIST) {
++        fd = adb_open_mode(path, O_WRONLY, mode);
++    }
++    if(fd < 0) {
++        if(fail_errno(s))
++            return -1;
++        fd = -1;
++    }
++
++    for(;;) {
++        unsigned int len;
++
++        if(readx(s, &msg.data, sizeof(msg.data)))
++            goto fail;
++
++        if(msg.data.id != ID_DATA) {
++            if(msg.data.id == ID_DONE) {
++                timestamp = ltohl(msg.data.size);
++                break;
++            }
++            fail_message(s, "invalid data message");
++            goto fail;
++        }
++        len = ltohl(msg.data.size);
++        if(len > SYNC_DATA_MAX) {
++            fail_message(s, "oversize data message");
++            goto fail;
++        }
++        if(readx(s, buffer, len))
++            goto fail;
++
++        if(fd < 0)
++            continue;
++        if(writex(fd, buffer, len)) {
++            int saved_errno = errno;
++            adb_close(fd);
++            adb_unlink(path);
++            fd = -1;
++            errno = saved_errno;
++            if(fail_errno(s)) return -1;
++        }
++    }
++
++    if(fd >= 0) {
++        struct utimbuf u;
++        adb_close(fd);
++        u.actime = timestamp;
++        u.modtime = timestamp;
++        utime(path, &u);
++
++        msg.status.id = ID_OKAY;
++        msg.status.msglen = 0;
++        if(writex(s, &msg.status, sizeof(msg.status)))
++            return -1;
++    }
++    return 0;
++
++fail:
++    if(fd >= 0)
++        adb_close(fd);
++    adb_unlink(path);
++    return -1;
++}
++
++#ifdef HAVE_SYMLINKS
++static int handle_send_link(int s, char *path, char *buffer)
++{
++    syncmsg msg;
++    unsigned int len;
++    int ret;
++
++    if(readx(s, &msg.data, sizeof(msg.data)))
++        return -1;
++
++    if(msg.data.id != ID_DATA) {
++        fail_message(s, "invalid data message: expected ID_DATA");
++        return -1;
++    }
++
++    len = ltohl(msg.data.size);
++    if(len > SYNC_DATA_MAX) {
++        fail_message(s, "oversize data message");
++        return -1;
++    }
++    if(readx(s, buffer, len))
++        return -1;
++
++    ret = symlink(buffer, path);
++    if(ret && errno == ENOENT) {
++        mkdirs(path);
++        ret = symlink(buffer, path);
++    }
++    if(ret) {
++        fail_errno(s);
++        return -1;
++    }
++
++    if(readx(s, &msg.data, sizeof(msg.data)))
++        return -1;
++
++    if(msg.data.id == ID_DONE) {
++        msg.status.id = ID_OKAY;
++        msg.status.msglen = 0;
++        if(writex(s, &msg.status, sizeof(msg.status)))
++            return -1;
++    } else {
++        fail_message(s, "invalid data message: expected ID_DONE");
++        return -1;
++    }
++
++    return 0;
++}
++#endif /* HAVE_SYMLINKS */
++
++static int do_send(int s, char *path, char *buffer)
++{
++    char *tmp;
++    mode_t mode;
++    int is_link, ret;
++
++    tmp = strrchr(path,',');
++    if(tmp) {
++        *tmp = 0;
++        errno = 0;
++        mode = strtoul(tmp + 1, NULL, 0);
++#ifndef HAVE_SYMLINKS
++        is_link = 0;
++#else
++        is_link = S_ISLNK(mode);
++#endif
++        mode &= 0777;
++    }
++    if(!tmp || errno) {
++        mode = 0644;
++        is_link = 0;
++    }
++
++    adb_unlink(path);
++
++
++#ifdef HAVE_SYMLINKS
++    if(is_link)
++        ret = handle_send_link(s, path, buffer);
++    else {
++#else
++    {
++#endif
++        /* copy user permission bits to "group" and "other" permissions */
++        mode |= ((mode >> 3) & 0070);
++        mode |= ((mode >> 3) & 0007);
++
++        ret = handle_send_file(s, path, mode, buffer);
++    }
++
++    return ret;
++}
++
++static int do_recv(int s, const char *path, char *buffer)
++{
++    syncmsg msg;
++    int fd, r;
++
++    fd = adb_open(path, O_RDONLY);
++    if(fd < 0) {
++        if(fail_errno(s)) return -1;
++        return 0;
++    }
++
++    msg.data.id = ID_DATA;
++    for(;;) {
++        r = adb_read(fd, buffer, SYNC_DATA_MAX);
++        if(r <= 0) {
++            if(r == 0) break;
++            if(errno == EINTR) continue;
++            r = fail_errno(s);
++            adb_close(fd);
++            return r;
++        }
++        msg.data.size = htoll(r);
++        if(writex(s, &msg.data, sizeof(msg.data)) ||
++           writex(s, buffer, r)) {
++            adb_close(fd);
++            return -1;
++        }
++    }
++
++    adb_close(fd);
++
++    msg.data.id = ID_DONE;
++    msg.data.size = 0;
++    if(writex(s, &msg.data, sizeof(msg.data))) {
++        return -1;
++    }
++
++    return 0;
++}
++
++void file_sync_service(int fd, void *cookie)
++{
++    syncmsg msg;
++    char name[1025];
++    unsigned namelen;
++
++    char *buffer = malloc(SYNC_DATA_MAX);
++    if(buffer == 0) goto fail;
++
++    for(;;) {
++        D("sync: waiting for command\n");
++
++        if(readx(fd, &msg.req, sizeof(msg.req))) {
++            fail_message(fd, "command read failure");
++            break;
++        }
++        namelen = ltohl(msg.req.namelen);
++        if(namelen > 1024) {
++            fail_message(fd, "invalid namelen");
++            break;
++        }
++        if(readx(fd, name, namelen)) {
++            fail_message(fd, "filename read failure");
++            break;
++        }
++        name[namelen] = 0;
++
++        msg.req.namelen = 0;
++        D("sync: '%s' '%s'\n", (char*) &msg.req, name);
++
++        switch(msg.req.id) {
++        case ID_STAT:
++            if(do_stat(fd, name)) goto fail;
++            break;
++        case ID_LIST:
++            if(do_list(fd, name)) goto fail;
++            break;
++        case ID_SEND:
++            if(do_send(fd, name, buffer)) goto fail;
++            break;
++        case ID_RECV:
++            if(do_recv(fd, name, buffer)) goto fail;
++            break;
++        case ID_QUIT:
++            goto fail;
++        default:
++            fail_message(fd, "unknown command");
++            goto fail;
++        }
++    }
++
++fail:
++    if(buffer != 0) free(buffer);
++    D("sync: done\n");
++    adb_close(fd);
++}
+Index: android-tools-4.2.2+git20130218/core/adbd/file_sync_service.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/file_sync_service.h      2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,87 @@
++/*
++ * Copyright (C) 2007 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#ifndef _FILE_SYNC_SERVICE_H_
++#define _FILE_SYNC_SERVICE_H_
++
++#ifdef HAVE_BIG_ENDIAN
++static inline unsigned __swap_uint32(unsigned x) 
++{
++    return (((x) & 0xFF000000) >> 24)
++        | (((x) & 0x00FF0000) >> 8)
++        | (((x) & 0x0000FF00) << 8)
++        | (((x) & 0x000000FF) << 24);
++}
++#define htoll(x) __swap_uint32(x)
++#define ltohl(x) __swap_uint32(x)
++#define MKID(a,b,c,d) ((d) | ((c) << 8) | ((b) << 16) | ((a) << 24))
++#else
++#define htoll(x) (x)
++#define ltohl(x) (x)
++#define MKID(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24))
++#endif
++
++#define ID_STAT MKID('S','T','A','T')
++#define ID_LIST MKID('L','I','S','T')
++#define ID_ULNK MKID('U','L','N','K')
++#define ID_SEND MKID('S','E','N','D')
++#define ID_RECV MKID('R','E','C','V')
++#define ID_DENT MKID('D','E','N','T')
++#define ID_DONE MKID('D','O','N','E')
++#define ID_DATA MKID('D','A','T','A')
++#define ID_OKAY MKID('O','K','A','Y')
++#define ID_FAIL MKID('F','A','I','L')
++#define ID_QUIT MKID('Q','U','I','T')
++
++typedef union {
++    unsigned id;
++    struct {
++        unsigned id;
++        unsigned namelen;
++    } req;
++    struct {
++        unsigned id;
++        unsigned mode;
++        unsigned size;
++        unsigned time;
++    } stat;
++    struct {
++        unsigned id;
++        unsigned mode;
++        unsigned size;
++        unsigned time;
++        unsigned namelen;
++    } dent;
++    struct {
++        unsigned id;
++        unsigned size;
++    } data;
++    struct {
++        unsigned id;
++        unsigned msglen;
++    } status;    
++} syncmsg;
++
++
++void file_sync_service(int fd, void *cookie);
++int do_sync_ls(const char *path);
++int do_sync_push(const char *lpath, const char *rpath, int verifyApk);
++int do_sync_sync(const char *lpath, const char *rpath, int listonly);
++int do_sync_pull(const char *rpath, const char *lpath);
++
++#define SYNC_DATA_MAX (64*1024)
++
++#endif
+Index: android-tools-4.2.2+git20130218/core/adbd/framebuffer_service.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/framebuffer_service.c    2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,180 @@
++/*
++ * Copyright (C) 2007 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include <stdlib.h>
++#include <stdio.h>
++#include <unistd.h>
++#include <string.h>
++#include <fcntl.h>
++#include <errno.h>
++#include <sys/types.h>
++#include <sys/wait.h>
++
++#include "fdevent.h"
++#include "adb.h"
++
++#include <linux/fb.h>
++#include <sys/ioctl.h>
++#include <sys/mman.h>
++
++/* TODO:
++** - sync with vsync to avoid tearing
++*/
++/* This version number defines the format of the fbinfo struct.
++   It must match versioning in ddms where this data is consumed. */
++#define DDMS_RAWIMAGE_VERSION 1
++struct fbinfo {
++    unsigned int version;
++    unsigned int bpp;
++    unsigned int size;
++    unsigned int width;
++    unsigned int height;
++    unsigned int red_offset;
++    unsigned int red_length;
++    unsigned int blue_offset;
++    unsigned int blue_length;
++    unsigned int green_offset;
++    unsigned int green_length;
++    unsigned int alpha_offset;
++    unsigned int alpha_length;
++} __attribute__((packed));
++
++void framebuffer_service(int fd, void *cookie)
++{
++    struct fbinfo fbinfo;
++    unsigned int i;
++    char buf[640];
++    int fd_screencap;
++    int w, h, f;
++    int fds[2];
++
++    if (pipe(fds) < 0) goto done;
++
++    pid_t pid = fork();
++    if (pid < 0) goto done;
++
++    if (pid == 0) {
++        dup2(fds[1], STDOUT_FILENO);
++        close(fds[0]);
++        close(fds[1]);
++        const char* command = "screencap";
++        const char *args[2] = {command, NULL};
++        execvp(command, (char**)args);
++        exit(1);
++    }
++
++    fd_screencap = fds[0];
++
++    /* read w, h & format */
++    if(readx(fd_screencap, &w, 4)) goto done;
++    if(readx(fd_screencap, &h, 4)) goto done;
++    if(readx(fd_screencap, &f, 4)) goto done;
++
++    fbinfo.version = DDMS_RAWIMAGE_VERSION;
++    /* see hardware/hardware.h */
++    switch (f) {
++        case 1: /* RGBA_8888 */
++            fbinfo.bpp = 32;
++            fbinfo.size = w * h * 4;
++            fbinfo.width = w;
++            fbinfo.height = h;
++            fbinfo.red_offset = 0;
++            fbinfo.red_length = 8;
++            fbinfo.green_offset = 8;
++            fbinfo.green_length = 8;
++            fbinfo.blue_offset = 16;
++            fbinfo.blue_length = 8;
++            fbinfo.alpha_offset = 24;
++            fbinfo.alpha_length = 8;
++            break;
++        case 2: /* RGBX_8888 */
++            fbinfo.bpp = 32;
++            fbinfo.size = w * h * 4;
++            fbinfo.width = w;
++            fbinfo.height = h;
++            fbinfo.red_offset = 0;
++            fbinfo.red_length = 8;
++            fbinfo.green_offset = 8;
++            fbinfo.green_length = 8;
++            fbinfo.blue_offset = 16;
++            fbinfo.blue_length = 8;
++            fbinfo.alpha_offset = 24;
++            fbinfo.alpha_length = 0;
++            break;
++        case 3: /* RGB_888 */
++            fbinfo.bpp = 24;
++            fbinfo.size = w * h * 3;
++            fbinfo.width = w;
++            fbinfo.height = h;
++            fbinfo.red_offset = 0;
++            fbinfo.red_length = 8;
++            fbinfo.green_offset = 8;
++            fbinfo.green_length = 8;
++            fbinfo.blue_offset = 16;
++            fbinfo.blue_length = 8;
++            fbinfo.alpha_offset = 24;
++            fbinfo.alpha_length = 0;
++            break;
++        case 4: /* RGB_565 */
++            fbinfo.bpp = 16;
++            fbinfo.size = w * h * 2;
++            fbinfo.width = w;
++            fbinfo.height = h;
++            fbinfo.red_offset = 11;
++            fbinfo.red_length = 5;
++            fbinfo.green_offset = 5;
++            fbinfo.green_length = 6;
++            fbinfo.blue_offset = 0;
++            fbinfo.blue_length = 5;
++            fbinfo.alpha_offset = 0;
++            fbinfo.alpha_length = 0;
++            break;
++        case 5: /* BGRA_8888 */
++            fbinfo.bpp = 32;
++            fbinfo.size = w * h * 4;
++            fbinfo.width = w;
++            fbinfo.height = h;
++            fbinfo.red_offset = 16;
++            fbinfo.red_length = 8;
++            fbinfo.green_offset = 8;
++            fbinfo.green_length = 8;
++            fbinfo.blue_offset = 0;
++            fbinfo.blue_length = 8;
++            fbinfo.alpha_offset = 24;
++            fbinfo.alpha_length = 8;
++           break;
++        default:
++            goto done;
++    }
++
++    /* write header */
++    if(writex(fd, &fbinfo, sizeof(fbinfo))) goto done;
++
++    /* write data */
++    for(i = 0; i < fbinfo.size; i += sizeof(buf)) {
++      if(readx(fd_screencap, buf, sizeof(buf))) goto done;
++      if(writex(fd, buf, sizeof(buf))) goto done;
++    }
++    if(readx(fd_screencap, buf, fbinfo.size % sizeof(buf))) goto done;
++    if(writex(fd, buf, fbinfo.size % sizeof(buf))) goto done;
++
++done:
++    TEMP_FAILURE_RETRY(waitpid(pid, NULL, 0));
++
++    close(fds[0]);
++    close(fds[1]);
++    close(fd);
++}
+Index: android-tools-4.2.2+git20130218/core/adbd/get_my_path_darwin.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/get_my_path_darwin.c     2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,30 @@
++/*
++ * Copyright (C) 2007 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#import <Carbon/Carbon.h>
++#include <unistd.h>
++
++void get_my_path(char *s, size_t maxLen)
++{
++    ProcessSerialNumber psn;
++    GetCurrentProcess(&psn);
++    CFDictionaryRef dict;
++    dict = ProcessInformationCopyDictionary(&psn, 0xffffffff);
++    CFStringRef value = (CFStringRef)CFDictionaryGetValue(dict,
++                CFSTR("CFBundleExecutable"));
++    CFStringGetCString(value, s, maxLen, kCFStringEncodingUTF8);
++}
++
+Index: android-tools-4.2.2+git20130218/core/adbd/get_my_path_freebsd.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/get_my_path_freebsd.c    2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,36 @@
++/*
++ * Copyright (C) 2009 bsdroid project
++ *               Alexey Tarasov <tarasov@dodologics.com>
++ *
++ * Copyright (C) 2007 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include <sys/types.h>
++#include <unistd.h>
++#include <limits.h>
++#include <stdio.h>
++
++void
++get_my_path(char *exe, size_t maxLen)
++{
++    char proc[64];
++
++    snprintf(proc, sizeof(proc), "/proc/%d/file", getpid());
++
++    int err = readlink(proc, exe, maxLen - 1);
++
++    exe[err > 0 ? err : 0] = '\0';
++}
++
+Index: android-tools-4.2.2+git20130218/core/adbd/get_my_path_linux.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/get_my_path_linux.c      2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,33 @@
++/*
++ * Copyright (C) 2007 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include <sys/types.h>
++#include <unistd.h>
++#include <limits.h>
++#include <stdio.h>
++
++void get_my_path(char *exe, size_t maxLen)
++{
++    char proc[64];
++    snprintf(proc, sizeof proc, "/proc/%d/exe", getpid());
++    int err = readlink(proc, exe, maxLen - 1);
++    if(err > 0) {
++        exe[err] = '\0';
++    } else {
++        exe[0] = '\0';
++    }
++}
++
+Index: android-tools-4.2.2+git20130218/core/adbd/get_my_path_windows.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/get_my_path_windows.c    2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,34 @@
++/*
++ * Copyright (C) 2007 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include <limits.h>
++#include <assert.h>
++#include <windows.h>
++
++void get_my_path(char *exe, size_t maxLen)
++{
++    char  *r;
++
++    /* XXX: should be GetModuleFileNameA */
++    if (GetModuleFileName(NULL, exe, maxLen) > 0) {
++        r = strrchr(exe, '\\');
++        if (r != NULL)
++            *r = '\0';
++    } else {
++        exe[0] = '\0';
++    }
++}
++
+Index: android-tools-4.2.2+git20130218/core/adbd/jdwp_service.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/jdwp_service.c   2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,735 @@
++/* implement the "debug-ports" and "track-debug-ports" device services */
++#include "sysdeps.h"
++#define  TRACE_TAG   TRACE_JDWP
++#include "adb.h"
++#include <errno.h>
++#include <stdio.h>
++#include <string.h>
++#include <unistd.h>
++
++/* here's how these things work.
++
++   when adbd starts, it creates a unix server socket
++   named @vm-debug-control (@ is a shortcut for "first byte is zero"
++   to use the private namespace instead of the file system)
++
++   when a new JDWP daemon thread starts in a new VM process, it creates
++   a connection to @vm-debug-control to announce its availability.
++
++
++     JDWP thread                             @vm-debug-control
++         |                                         |
++         |------------------------------->         |
++         | hello I'm in process <pid>              |
++         |                                         |
++         |                                         |
++
++    the connection is kept alive. it will be closed automatically if
++    the JDWP process terminates (this allows adbd to detect dead
++    processes).
++
++    adbd thus maintains a list of "active" JDWP processes. it can send
++    its content to clients through the "device:debug-ports" service,
++    or even updates through the "device:track-debug-ports" service.
++
++    when a debugger wants to connect, it simply runs the command
++    equivalent to  "adb forward tcp:<hostport> jdwp:<pid>"
++
++    "jdwp:<pid>" is a new forward destination format used to target
++    a given JDWP process on the device. when sutch a request arrives,
++    adbd does the following:
++
++      - first, it calls socketpair() to create a pair of equivalent
++        sockets.
++
++      - it attaches the first socket in the pair to a local socket
++        which is itself attached to the transport's remote socket:
++
++
++      - it sends the file descriptor of the second socket directly
++        to the JDWP process with the help of sendmsg()
++
++
++     JDWP thread                             @vm-debug-control
++         |                                         |
++         |                  <----------------------|
++         |           OK, try this file descriptor  |
++         |                                         |
++         |                                         |
++
++   then, the JDWP thread uses this new socket descriptor as its
++   pass-through connection to the debugger (and receives the
++   JDWP-Handshake message, answers to it, etc...)
++
++   this gives the following graphics:
++                    ____________________________________
++                   |                                    |
++                   |          ADB Server (host)         |
++                   |                                    |
++        Debugger <---> LocalSocket <----> RemoteSocket  |
++                   |                           ^^       |
++                   |___________________________||_______|
++                                               ||
++                                     Transport ||
++           (TCP for emulator - USB for device) ||
++                                               ||
++                    ___________________________||_______
++                   |                           ||       |
++                   |          ADBD  (device)   ||       |
++                   |                           VV       |
++         JDWP <======> LocalSocket <----> RemoteSocket  |
++                   |                                    |
++                   |____________________________________|
++
++    due to the way adb works, this doesn't need a special socket
++    type or fancy handling of socket termination if either the debugger
++    or the JDWP process closes the connection.
++
++    THIS IS THE SIMPLEST IMPLEMENTATION I COULD FIND, IF YOU HAPPEN
++    TO HAVE A BETTER IDEA, LET ME KNOW - Digit
++
++**********************************************************************/
++
++/** JDWP PID List Support Code
++ ** for each JDWP process, we record its pid and its connected socket
++ **/
++
++#define  MAX_OUT_FDS   4
++
++#if !ADB_HOST
++
++#include <sys/socket.h>
++#include <sys/un.h>
++
++typedef struct JdwpProcess  JdwpProcess;
++struct JdwpProcess {
++    JdwpProcess*  next;
++    JdwpProcess*  prev;
++    int           pid;
++    int           socket;
++    fdevent*      fde;
++
++    char          in_buff[4];  /* input character to read PID */
++    int           in_len;      /* number from JDWP process    */
++
++    int           out_fds[MAX_OUT_FDS]; /* output array of file descriptors */
++    int           out_count;            /* to send to the JDWP process      */
++};
++
++static JdwpProcess  _jdwp_list;
++
++static int
++jdwp_process_list( char*  buffer, int  bufferlen )
++{
++    char*         end  = buffer + bufferlen;
++    char*         p    = buffer;
++    JdwpProcess*  proc = _jdwp_list.next;
++
++    for ( ; proc != &_jdwp_list; proc = proc->next ) {
++        int  len;
++
++        /* skip transient connections */
++        if (proc->pid < 0)
++            continue;
++
++        len = snprintf(p, end-p, "%d\n", proc->pid);
++        if (p + len >= end)
++            break;
++        p += len;
++    }
++    p[0] = 0;
++    return (p - buffer);
++}
++
++
++static int
++jdwp_process_list_msg( char*  buffer, int  bufferlen )
++{
++    char  head[5];
++    int   len = jdwp_process_list( buffer+4, bufferlen-4 );
++    snprintf(head, sizeof head, "%04x", len);
++    memcpy(buffer, head, 4);
++    return len + 4;
++}
++
++
++static void  jdwp_process_list_updated(void);
++
++static void
++jdwp_process_free( JdwpProcess*  proc )
++{
++    if (proc) {
++        int  n;
++
++        proc->prev->next = proc->next;
++        proc->next->prev = proc->prev;
++
++        if (proc->socket >= 0) {
++            adb_shutdown(proc->socket);
++            adb_close(proc->socket);
++            proc->socket = -1;
++        }
++
++        if (proc->fde != NULL) {
++            fdevent_destroy(proc->fde);
++            proc->fde = NULL;
++        }
++        proc->pid = -1;
++
++        for (n = 0; n < proc->out_count; n++) {
++            adb_close(proc->out_fds[n]);
++        }
++        proc->out_count = 0;
++
++        free(proc);
++
++        jdwp_process_list_updated();
++    }
++}
++
++
++static void  jdwp_process_event(int, unsigned, void*);  /* forward */
++
++
++static JdwpProcess*
++jdwp_process_alloc( int  socket )
++{
++    JdwpProcess*  proc = calloc(1,sizeof(*proc));
++
++    if (proc == NULL) {
++        D("not enough memory to create new JDWP process\n");
++        return NULL;
++    }
++
++    proc->socket = socket;
++    proc->pid    = -1;
++    proc->next   = proc;
++    proc->prev   = proc;
++
++    proc->fde = fdevent_create( socket, jdwp_process_event, proc );
++    if (proc->fde == NULL) {
++        D("could not create fdevent for new JDWP process\n" );
++        free(proc);
++        return NULL;
++    }
++
++    proc->fde->state |= FDE_DONT_CLOSE;
++    proc->in_len      = 0;
++    proc->out_count   = 0;
++
++    /* append to list */
++    proc->next = &_jdwp_list;
++    proc->prev = proc->next->prev;
++
++    proc->prev->next = proc;
++    proc->next->prev = proc;
++
++    /* start by waiting for the PID */
++    fdevent_add(proc->fde, FDE_READ);
++
++    return proc;
++}
++
++
++static void
++jdwp_process_event( int  socket, unsigned  events, void*  _proc )
++{
++    JdwpProcess*  proc = _proc;
++
++    if (events & FDE_READ) {
++        if (proc->pid < 0) {
++            /* read the PID as a 4-hexchar string */
++            char*  p    = proc->in_buff + proc->in_len;
++            int    size = 4 - proc->in_len;
++            char   temp[5];
++            while (size > 0) {
++                int  len = recv( socket, p, size, 0 );
++                if (len < 0) {
++                    if (errno == EINTR)
++                        continue;
++                    if (errno == EAGAIN)
++                        return;
++                    /* this can fail here if the JDWP process crashes very fast */
++                    D("weird unknown JDWP process failure: %s\n",
++                      strerror(errno));
++
++                    goto CloseProcess;
++                }
++                if (len == 0) {  /* end of stream ? */
++                    D("weird end-of-stream from unknown JDWP process\n");
++                    goto CloseProcess;
++                }
++                p            += len;
++                proc->in_len += len;
++                size         -= len;
++            }
++            /* we have read 4 characters, now decode the pid */
++            memcpy(temp, proc->in_buff, 4);
++            temp[4] = 0;
++
++            if (sscanf( temp, "%04x", &proc->pid ) != 1) {
++                D("could not decode JDWP %p PID number: '%s'\n", proc, temp);
++                goto CloseProcess;
++            }
++
++            /* all is well, keep reading to detect connection closure */
++            D("Adding pid %d to jdwp process list\n", proc->pid);
++            jdwp_process_list_updated();
++        }
++        else
++        {
++            /* the pid was read, if we get there it's probably because the connection
++             * was closed (e.g. the JDWP process exited or crashed) */
++            char  buf[32];
++
++            for (;;) {
++                int  len = recv(socket, buf, sizeof(buf), 0);
++
++                if (len <= 0) {
++                    if (len < 0 && errno == EINTR)
++                        continue;
++                    if (len < 0 && errno == EAGAIN)
++                        return;
++                    else {
++                        D("terminating JDWP %d connection: %s\n", proc->pid,
++                          strerror(errno));
++                        break;
++                    }
++                }
++                else {
++                    D( "ignoring unexpected JDWP %d control socket activity (%d bytes)\n",
++                       proc->pid, len );
++                }
++            }
++
++        CloseProcess:
++            if (proc->pid >= 0)
++                D( "remove pid %d to jdwp process list\n", proc->pid );
++            jdwp_process_free(proc);
++            return;
++        }
++    }
++
++    if (events & FDE_WRITE) {
++        D("trying to write to JDWP pid controli (count=%d first=%d) %d\n",
++          proc->pid, proc->out_count, proc->out_fds[0]);
++        if (proc->out_count > 0) {
++            int  fd = proc->out_fds[0];
++            int  n, ret;
++            struct cmsghdr*  cmsg;
++            struct msghdr    msg;
++            struct iovec     iov;
++            char             dummy = '!';
++            char             buffer[sizeof(struct cmsghdr) + sizeof(int)];
++            int flags;
++
++            iov.iov_base       = &dummy;
++            iov.iov_len        = 1;
++            msg.msg_name       = NULL;
++            msg.msg_namelen    = 0;
++            msg.msg_iov        = &iov;
++            msg.msg_iovlen     = 1;
++            msg.msg_flags      = 0;
++            msg.msg_control    = buffer;
++            msg.msg_controllen = sizeof(buffer);
++
++            cmsg = CMSG_FIRSTHDR(&msg);
++            cmsg->cmsg_len   = msg.msg_controllen;
++            cmsg->cmsg_level = SOL_SOCKET;
++            cmsg->cmsg_type  = SCM_RIGHTS;
++            ((int*)CMSG_DATA(cmsg))[0] = fd;
++
++            flags = fcntl(proc->socket,F_GETFL,0);
++
++            if (flags == -1) {
++                D("failed to get cntl flags for socket %d: %s\n",
++                  proc->pid, strerror(errno));
++                goto CloseProcess;
++
++            }
++
++            if (fcntl(proc->socket, F_SETFL, flags & ~O_NONBLOCK) == -1) {
++                D("failed to remove O_NONBLOCK flag for socket %d: %s\n",
++                  proc->pid, strerror(errno));
++                goto CloseProcess;
++            }
++
++            for (;;) {
++                ret = sendmsg(proc->socket, &msg, 0);
++                if (ret >= 0) {
++                    adb_close(fd);
++                    break;
++                }
++                if (errno == EINTR)
++                    continue;
++                D("sending new file descriptor to JDWP %d failed: %s\n",
++                  proc->pid, strerror(errno));
++                goto CloseProcess;
++            }
++
++            D("sent file descriptor %d to JDWP process %d\n",
++              fd, proc->pid);
++
++            for (n = 1; n < proc->out_count; n++)
++                proc->out_fds[n-1] = proc->out_fds[n];
++
++            if (fcntl(proc->socket, F_SETFL, flags) == -1) {
++                D("failed to set O_NONBLOCK flag for socket %d: %s\n",
++                  proc->pid, strerror(errno));
++                goto CloseProcess;
++            }
++
++            if (--proc->out_count == 0)
++                fdevent_del( proc->fde, FDE_WRITE );
++        }
++    }
++}
++
++
++int
++create_jdwp_connection_fd(int  pid)
++{
++    JdwpProcess*  proc = _jdwp_list.next;
++
++    D("looking for pid %d in JDWP process list\n", pid);
++    for ( ; proc != &_jdwp_list; proc = proc->next ) {
++        if (proc->pid == pid) {
++            goto FoundIt;
++        }
++    }
++    D("search failed !!\n");
++    return -1;
++
++FoundIt:
++    {
++        int  fds[2];
++
++        if (proc->out_count >= MAX_OUT_FDS) {
++            D("%s: too many pending JDWP connection for pid %d\n",
++              __FUNCTION__, pid);
++            return -1;
++        }
++
++        if (adb_socketpair(fds) < 0) {
++            D("%s: socket pair creation failed: %s\n",
++              __FUNCTION__, strerror(errno));
++            return -1;
++        }
++
++        proc->out_fds[ proc->out_count ] = fds[1];
++        if (++proc->out_count == 1)
++            fdevent_add( proc->fde, FDE_WRITE );
++
++        return fds[0];
++    }
++}
++
++/**  VM DEBUG CONTROL SOCKET
++ **
++ **  we do implement a custom asocket to receive the data
++ **/
++
++/* name of the debug control Unix socket */
++#define  JDWP_CONTROL_NAME      "\0jdwp-control"
++#define  JDWP_CONTROL_NAME_LEN  (sizeof(JDWP_CONTROL_NAME)-1)
++
++typedef struct {
++    int       listen_socket;
++    fdevent*  fde;
++
++} JdwpControl;
++
++
++static void
++jdwp_control_event(int  s, unsigned events, void*  user);
++
++
++static int
++jdwp_control_init( JdwpControl*  control,
++                   const char*   sockname,
++                   int           socknamelen )
++{
++    struct sockaddr_un   addr;
++    socklen_t            addrlen;
++    int                  s;
++    int                  maxpath = sizeof(addr.sun_path);
++    int                  pathlen = socknamelen;
++
++    if (pathlen >= maxpath) {
++        D( "vm debug control socket name too long (%d extra chars)\n",
++           pathlen+1-maxpath );
++        return -1;
++    }
++
++    memset(&addr, 0, sizeof(addr));
++    addr.sun_family = AF_UNIX;
++    memcpy(addr.sun_path, sockname, socknamelen);
++
++    s = socket( AF_UNIX, SOCK_STREAM, 0 );
++    if (s < 0) {
++        D( "could not create vm debug control socket. %d: %s\n",
++           errno, strerror(errno));
++        return -1;
++    }
++
++    addrlen = (pathlen + sizeof(addr.sun_family));
++
++    if (bind(s, (struct sockaddr*)&addr, addrlen) < 0) {
++        D( "could not bind vm debug control socket: %d: %s\n",
++           errno, strerror(errno) );
++        adb_close(s);
++        return -1;
++    }
++
++    if ( listen(s, 4) < 0 ) {
++        D("listen failed in jdwp control socket: %d: %s\n",
++          errno, strerror(errno));
++        adb_close(s);
++        return -1;
++    }
++
++    control->listen_socket = s;
++
++    control->fde = fdevent_create(s, jdwp_control_event, control);
++    if (control->fde == NULL) {
++        D( "could not create fdevent for jdwp control socket\n" );
++        adb_close(s);
++        return -1;
++    }
++
++    /* only wait for incoming connections */
++    fdevent_add(control->fde, FDE_READ);
++    close_on_exec(s);
++
++    D("jdwp control socket started (%d)\n", control->listen_socket);
++    return 0;
++}
++
++
++static void
++jdwp_control_event( int  s, unsigned  events, void*  _control )
++{
++    JdwpControl*  control = (JdwpControl*) _control;
++
++    if (events & FDE_READ) {
++        struct sockaddr   addr;
++        socklen_t         addrlen = sizeof(addr);
++        int               s = -1;
++        JdwpProcess*      proc;
++
++        do {
++            s = adb_socket_accept( control->listen_socket, &addr, &addrlen );
++            if (s < 0) {
++                if (errno == EINTR)
++                    continue;
++                if (errno == ECONNABORTED) {
++                    /* oops, the JDWP process died really quick */
++                    D("oops, the JDWP process died really quick\n");
++                    return;
++                }
++                /* the socket is probably closed ? */
++                D( "weird accept() failed on jdwp control socket: %s\n",
++                   strerror(errno) );
++                return;
++            }
++        }
++        while (s < 0);
++
++        proc = jdwp_process_alloc( s );
++        if (proc == NULL)
++            return;
++    }
++}
++
++
++static JdwpControl   _jdwp_control;
++
++/** "jdwp" local service implementation
++ ** this simply returns the list of known JDWP process pids
++ **/
++
++typedef struct {
++    asocket  socket;
++    int      pass;
++} JdwpSocket;
++
++static void
++jdwp_socket_close( asocket*  s )
++{
++    asocket*  peer = s->peer;
++
++    remove_socket(s);
++
++    if (peer) {
++        peer->peer = NULL;
++        peer->close(peer);
++    }
++    free(s);
++}
++
++static int
++jdwp_socket_enqueue( asocket*  s, apacket*  p )
++{
++    /* you can't write to this asocket */
++    put_apacket(p);
++    s->peer->close(s->peer);
++    return -1;
++}
++
++
++static void
++jdwp_socket_ready( asocket*  s )
++{
++    JdwpSocket*  jdwp = (JdwpSocket*)s;
++    asocket*     peer = jdwp->socket.peer;
++
++   /* on the first call, send the list of pids,
++    * on the second one, close the connection
++    */
++    if (jdwp->pass == 0) {
++        apacket*  p = get_apacket();
++        p->len = jdwp_process_list((char*)p->data, MAX_PAYLOAD);
++        peer->enqueue(peer, p);
++        jdwp->pass = 1;
++    }
++    else {
++        peer->close(peer);
++    }
++}
++
++asocket*
++create_jdwp_service_socket( void )
++{
++    JdwpSocket*  s = calloc(sizeof(*s),1);
++
++    if (s == NULL)
++        return NULL;
++
++    install_local_socket(&s->socket);
++
++    s->socket.ready   = jdwp_socket_ready;
++    s->socket.enqueue = jdwp_socket_enqueue;
++    s->socket.close   = jdwp_socket_close;
++    s->pass           = 0;
++
++    return &s->socket;
++}
++
++/** "track-jdwp" local service implementation
++ ** this periodically sends the list of known JDWP process pids
++ ** to the client...
++ **/
++
++typedef struct JdwpTracker  JdwpTracker;
++
++struct JdwpTracker {
++    asocket       socket;
++    JdwpTracker*  next;
++    JdwpTracker*  prev;
++    int           need_update;
++};
++
++static JdwpTracker   _jdwp_trackers_list;
++
++
++static void
++jdwp_process_list_updated(void)
++{
++    char             buffer[1024];
++    int              len;
++    JdwpTracker*  t = _jdwp_trackers_list.next;
++
++    len = jdwp_process_list_msg(buffer, sizeof(buffer));
++
++    for ( ; t != &_jdwp_trackers_list; t = t->next ) {
++        apacket*  p    = get_apacket();
++        asocket*  peer = t->socket.peer;
++        memcpy(p->data, buffer, len);
++        p->len = len;
++        peer->enqueue( peer, p );
++    }
++}
++
++static void
++jdwp_tracker_close( asocket*  s )
++{
++    JdwpTracker*  tracker = (JdwpTracker*) s;
++    asocket*      peer    = s->peer;
++
++    if (peer) {
++        peer->peer = NULL;
++        peer->close(peer);
++    }
++
++    remove_socket(s);
++
++    tracker->prev->next = tracker->next;
++    tracker->next->prev = tracker->prev;
++
++    free(s);
++}
++
++static void
++jdwp_tracker_ready( asocket*  s )
++{
++    JdwpTracker*  t = (JdwpTracker*) s;
++
++    if (t->need_update) {
++        apacket*  p = get_apacket();
++        t->need_update = 0;
++        p->len = jdwp_process_list_msg((char*)p->data, sizeof(p->data));
++        s->peer->enqueue(s->peer, p);
++    }
++}
++
++static int
++jdwp_tracker_enqueue( asocket*  s, apacket*  p )
++{
++    /* you can't write to this socket */
++    put_apacket(p);
++    s->peer->close(s->peer);
++    return -1;
++}
++
++
++asocket*
++create_jdwp_tracker_service_socket( void )
++{
++    JdwpTracker*  t = calloc(sizeof(*t),1);
++
++    if (t == NULL)
++        return NULL;
++
++    t->next = &_jdwp_trackers_list;
++    t->prev = t->next->prev;
++
++    t->next->prev = t;
++    t->prev->next = t;
++
++    install_local_socket(&t->socket);
++
++    t->socket.ready   = jdwp_tracker_ready;
++    t->socket.enqueue = jdwp_tracker_enqueue;
++    t->socket.close   = jdwp_tracker_close;
++    t->need_update    = 1;
++
++    return &t->socket;
++}
++
++
++int
++init_jdwp(void)
++{
++    _jdwp_list.next = &_jdwp_list;
++    _jdwp_list.prev = &_jdwp_list;
++
++    _jdwp_trackers_list.next = &_jdwp_trackers_list;
++    _jdwp_trackers_list.prev = &_jdwp_trackers_list;
++
++    return jdwp_control_init( &_jdwp_control,
++                              JDWP_CONTROL_NAME,
++                              JDWP_CONTROL_NAME_LEN );
++}
++
++#endif /* !ADB_HOST */
++
+Index: android-tools-4.2.2+git20130218/core/adbd/log_service.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/log_service.c    2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,92 @@
++/*
++ * Copyright (C) 2007 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++
++#include <stdlib.h>
++#include <stdio.h>
++#include <unistd.h>
++#include <string.h>
++#include <fcntl.h>
++#include <errno.h>
++#include <sys/socket.h>
++#include <cutils/logger.h>
++#include "sysdeps.h"
++#include "adb.h"
++
++#define LOG_FILE_DIR    "/dev/log/"
++
++void write_log_entry(int fd, struct logger_entry *buf);
++
++void log_service(int fd, void *cookie)
++{
++    /* get the name of the log filepath to read */
++    char * log_filepath = cookie;
++
++    /* open the log file. */
++    int logfd = unix_open(log_filepath, O_RDONLY);
++    if (logfd < 0) {
++        goto done;
++    }
++
++    // temp buffer to read the entries
++    unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1] __attribute__((aligned(4)));
++    struct logger_entry *entry = (struct logger_entry *) buf;
++
++    while (1) {
++        int ret;
++
++        ret = unix_read(logfd, entry, LOGGER_ENTRY_MAX_LEN);
++        if (ret < 0) {
++            if (errno == EINTR || errno == EAGAIN)
++                continue;
++            // perror("logcat read");
++            goto done;
++        }
++        else if (!ret) {
++            // fprintf(stderr, "read: Unexpected EOF!\n");
++            goto done;
++        }
++
++        /* NOTE: driver guarantees we read exactly one full entry */
++
++        entry->msg[entry->len] = '\0';
++
++        write_log_entry(fd, entry);
++    }
++
++done:
++    unix_close(fd);
++    free(log_filepath);
++}
++
++/* returns the full path to the log file in a newly allocated string */
++char * get_log_file_path(const char * log_name) {
++    char *log_device = malloc(strlen(LOG_FILE_DIR) + strlen(log_name) + 1);
++
++    strcpy(log_device, LOG_FILE_DIR);
++    strcat(log_device, log_name);
++
++    return log_device;
++}
++
++
++/* prints one log entry into the file descriptor fd */
++void write_log_entry(int fd, struct logger_entry *buf)
++{
++    size_t size = sizeof(struct logger_entry) + buf->len;
++
++    writex(fd, buf, size);
++}
+Index: android-tools-4.2.2+git20130218/core/adbd/mutex_list.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/mutex_list.h     2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,26 @@
++/* the list of mutexes used by adb */
++/* #ifndef __MUTEX_LIST_H
++ * Do not use an include-guard. This file is included once to declare the locks
++ * and once in win32 to actually do the runtime initialization.
++ */
++#ifndef ADB_MUTEX
++#error ADB_MUTEX not defined when including this file
++#endif
++ADB_MUTEX(dns_lock)
++ADB_MUTEX(socket_list_lock)
++ADB_MUTEX(transport_lock)
++#if ADB_HOST
++ADB_MUTEX(local_transports_lock)
++#endif
++ADB_MUTEX(usb_lock)
++
++// Sadly logging to /data/adb/adb-... is not thread safe.
++//  After modifying adb.h::D() to count invocations:
++//   DEBUG(jpa):0:Handling main()
++//   DEBUG(jpa):1:[ usb_init - starting thread ]
++// (Oopsies, no :2:, and matching message is also gone.)
++//   DEBUG(jpa):3:[ usb_thread - opening device ]
++//   DEBUG(jpa):4:jdwp control socket started (10)
++ADB_MUTEX(D_lock)
++
++#undef ADB_MUTEX
+Index: android-tools-4.2.2+git20130218/core/adbd/qemu_pipe.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/qemu_pipe.h      2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,91 @@
++/*
++ * Copyright (C) 2011 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++#ifndef ANDROID_INCLUDE_HARDWARE_QEMU_PIPE_H
++#define ANDROID_INCLUDE_HARDWARE_QEMU_PIPE_H
++
++#include <sys/cdefs.h>
++#include <unistd.h>
++#include <fcntl.h>
++#include <sys/mman.h>
++#include <pthread.h>  /* for pthread_once() */
++#include <stdlib.h>
++#include <stdio.h>
++#include <errno.h>
++
++#ifndef D
++#  define  D(...)   do{}while(0)
++#endif
++
++/* Try to open a new Qemu fast-pipe. This function returns a file descriptor
++ * that can be used to communicate with a named service managed by the
++ * emulator.
++ *
++ * This file descriptor can be used as a standard pipe/socket descriptor.
++ *
++ * 'pipeName' is the name of the emulator service you want to connect to.
++ * E.g. 'opengles' or 'camera'.
++ *
++ * On success, return a valid file descriptor
++ * Returns -1 on error, and errno gives the error code, e.g.:
++ *
++ *    EINVAL  -> unknown/unsupported pipeName
++ *    ENOSYS  -> fast pipes not available in this system.
++ *
++ * ENOSYS should never happen, except if you're trying to run within a
++ * misconfigured emulator.
++ *
++ * You should be able to open several pipes to the same pipe service,
++ * except for a few special cases (e.g. GSM modem), where EBUSY will be
++ * returned if more than one client tries to connect to it.
++ */
++static __inline__ int
++qemu_pipe_open(const char*  pipeName)
++{
++    char  buff[256];
++    int   buffLen;
++    int   fd, ret;
++
++    if (pipeName == NULL || pipeName[0] == '\0') {
++        errno = EINVAL;
++        return -1;
++    }
++
++    snprintf(buff, sizeof buff, "pipe:%s", pipeName);
++
++    fd = open("/dev/qemu_pipe", O_RDWR);
++    if (fd < 0) {
++        D("%s: Could not open /dev/qemu_pipe: %s", __FUNCTION__, strerror(errno));
++        //errno = ENOSYS;
++        return -1;
++    }
++
++    buffLen = strlen(buff);
++
++    ret = TEMP_FAILURE_RETRY(write(fd, buff, buffLen+1));
++    if (ret != buffLen+1) {
++        D("%s: Could not connect to %s pipe service: %s", __FUNCTION__, pipeName, strerror(errno));
++        if (ret == 0) {
++            errno = ECONNRESET;
++        } else if (ret > 0) {
++            errno = EINVAL;
++        }
++        return -1;
++    }
++
++    return fd;
++}
++
++#endif /* ANDROID_INCLUDE_HARDWARE_QEMUD_PIPE_H */
+Index: android-tools-4.2.2+git20130218/core/adbd/remount_service.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/remount_service.c        2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,111 @@
++/*
++ * Copyright (C) 2008 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include <stdlib.h>
++#include <stdio.h>
++#include <unistd.h>
++#include <string.h>
++#include <fcntl.h>
++#include <sys/mount.h>
++#include <errno.h>
++
++#include "sysdeps.h"
++
++#define  TRACE_TAG  TRACE_ADB
++#include "adb.h"
++
++
++static int system_ro = 1;
++
++/* Returns the device used to mount a directory in /proc/mounts */
++static char *find_mount(const char *dir)
++{
++    int fd;
++    int res;
++    int size;
++    char *token = NULL;
++    const char delims[] = "\n";
++    char buf[4096];
++
++    fd = unix_open("/proc/mounts", O_RDONLY);
++    if (fd < 0)
++        return NULL;
++
++    buf[sizeof(buf) - 1] = '\0';
++    size = adb_read(fd, buf, sizeof(buf) - 1);
++    adb_close(fd);
++
++    token = strtok(buf, delims);
++
++    while (token) {
++        char mount_dev[256];
++        char mount_dir[256];
++        int mount_freq;
++        int mount_passno;
++
++        res = sscanf(token, "%255s %255s %*s %*s %d %d\n",
++                     mount_dev, mount_dir, &mount_freq, &mount_passno);
++        mount_dev[255] = 0;
++        mount_dir[255] = 0;
++        if (res == 4 && (strcmp(dir, mount_dir) == 0))
++            return strdup(mount_dev);
++
++        token = strtok(NULL, delims);
++    }
++    return NULL;
++}
++
++/* Init mounts /system as read only, remount to enable writes. */
++static int remount_system()
++{
++    char *dev;
++
++    if (system_ro == 0) {
++        return 0;
++    }
++
++    dev = find_mount("/system");
++
++    if (!dev)
++        return -1;
++
++    system_ro = mount(dev, "/system", "none", MS_REMOUNT, NULL);
++
++    free(dev);
++
++    return system_ro;
++}
++
++static void write_string(int fd, const char* str)
++{
++    writex(fd, str, strlen(str));
++}
++
++void remount_service(int fd, void *cookie)
++{
++    int ret = remount_system();
++
++    if (!ret)
++       write_string(fd, "remount succeeded\n");
++    else {
++        char    buffer[200];
++        snprintf(buffer, sizeof(buffer), "remount failed: %s\n", strerror(errno));
++        write_string(fd, buffer);
++    }
++
++    adb_close(fd);
++}
++
+Index: android-tools-4.2.2+git20130218/core/adbd/services.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/services.c       2013-06-19 02:41:32.583408302 -0300
+@@ -0,0 +1,568 @@
++/*
++ * Copyright (C) 2007 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include <stdlib.h>
++#include <stdio.h>
++#include <unistd.h>
++#include <string.h>
++#include <errno.h>
++#include <pwd.h>
++
++#include "sysdeps.h"
++
++#define  TRACE_TAG  TRACE_SERVICES
++#include "adb.h"
++#include "file_sync_service.h"
++
++#if ADB_HOST
++#  ifndef HAVE_WINSOCK
++#    include <netinet/in.h>
++#    include <netdb.h>
++#    include <sys/ioctl.h>
++#  endif
++#else
++#  include <cutils/android_reboot.h>
++#endif
++
++typedef struct stinfo stinfo;
++
++struct stinfo {
++    void (*func)(int fd, void *cookie);
++    int fd;
++    void *cookie;
++};
++
++
++void *service_bootstrap_func(void *x)
++{
++    stinfo *sti = x;
++    sti->func(sti->fd, sti->cookie);
++    free(sti);
++    return 0;
++}
++
++#if ADB_HOST
++ADB_MUTEX_DEFINE( dns_lock );
++
++static void dns_service(int fd, void *cookie)
++{
++    char *hostname = cookie;
++    struct hostent *hp;
++    unsigned zero = 0;
++
++    adb_mutex_lock(&dns_lock);
++    hp = gethostbyname(hostname);
++    free(cookie);
++    if(hp == 0) {
++        writex(fd, &zero, 4);
++    } else {
++        writex(fd, hp->h_addr, 4);
++    }
++    adb_mutex_unlock(&dns_lock);
++    adb_close(fd);
++}
++#else
++extern int recovery_mode;
++
++static void recover_service(int s, void *cookie)
++{
++    unsigned char buf[4096];
++    unsigned count = (unsigned) cookie;
++    int fd;
++
++    fd = adb_creat("/tmp/update", 0644);
++    if(fd < 0) {
++        adb_close(s);
++        return;
++    }
++
++    while(count > 0) {
++        unsigned xfer = (count > 4096) ? 4096 : count;
++        if(readx(s, buf, xfer)) break;
++        if(writex(fd, buf, xfer)) break;
++        count -= xfer;
++    }
++
++    if(count == 0) {
++        writex(s, "OKAY", 4);
++    } else {
++        writex(s, "FAIL", 4);
++    }
++    adb_close(fd);
++    adb_close(s);
++
++    fd = adb_creat("/tmp/update.begin", 0644);
++    adb_close(fd);
++}
++
++void restart_root_service(int fd, void *cookie)
++{
++    char buf[100];
++    char value[PROPERTY_VALUE_MAX];
++
++    if (getuid() == 0) {
++        snprintf(buf, sizeof(buf), "adbd is already running as root\n");
++        writex(fd, buf, strlen(buf));
++        adb_close(fd);
++    } else {
++        //property_get("ro.debuggable", value, "");
++        if (strcmp(value, "1") != 0) {
++            snprintf(buf, sizeof(buf), "adbd cannot run as root in production builds\n");
++            writex(fd, buf, strlen(buf));
++            adb_close(fd);
++            return;
++        }
++
++        //property_set("service.adb.root", "1");
++        snprintf(buf, sizeof(buf), "restarting adbd as root\n");
++        writex(fd, buf, strlen(buf));
++        adb_close(fd);
++    }
++}
++
++void restart_tcp_service(int fd, void *cookie)
++{
++    char buf[100];
++    char value[PROPERTY_VALUE_MAX];
++    int port = (int)cookie;
++
++    if (port <= 0) {
++        snprintf(buf, sizeof(buf), "invalid port\n");
++        writex(fd, buf, strlen(buf));
++        adb_close(fd);
++        return;
++    }
++
++    snprintf(value, sizeof(value), "%d", port);
++    //property_set("service.adb.tcp.port", value);
++    snprintf(buf, sizeof(buf), "restarting in TCP mode port: %d\n", port);
++    writex(fd, buf, strlen(buf));
++    adb_close(fd);
++}
++
++void restart_usb_service(int fd, void *cookie)
++{
++    char buf[100];
++
++    //property_set("service.adb.tcp.port", "0");
++    snprintf(buf, sizeof(buf), "restarting in USB mode\n");
++    writex(fd, buf, strlen(buf));
++    adb_close(fd);
++}
++
++void reboot_service(int fd, void *arg)
++{
++    char buf[100];
++    int pid, ret;
++
++    sync();
++
++    /* Attempt to unmount the SD card first.
++     * No need to bother checking for errors.
++     */
++    pid = fork();
++    if (pid == 0) {
++        /* ask vdc to unmount it */
++        execl("/system/bin/vdc", "/system/bin/vdc", "volume", "unmount",
++                getenv("EXTERNAL_STORAGE"), "force", NULL);
++    } else if (pid > 0) {
++        /* wait until vdc succeeds or fails */
++        waitpid(pid, &ret, 0);
++    }
++
++    ret = android_reboot(ANDROID_RB_RESTART2, 0, (char *) arg);
++    if (ret < 0) {
++        snprintf(buf, sizeof(buf), "reboot failed: %s\n", strerror(errno));
++        writex(fd, buf, strlen(buf));
++    }
++    free(arg);
++    adb_close(fd);
++}
++
++#endif
++
++#if 0
++static void echo_service(int fd, void *cookie)
++{
++    char buf[4096];
++    int r;
++    char *p;
++    int c;
++
++    for(;;) {
++        r = adb_read(fd, buf, 4096);
++        if(r == 0) goto done;
++        if(r < 0) {
++            if(errno == EINTR) continue;
++            else goto done;
++        }
++
++        c = r;
++        p = buf;
++        while(c > 0) {
++            r = write(fd, p, c);
++            if(r > 0) {
++                c -= r;
++                p += r;
++                continue;
++            }
++            if((r < 0) && (errno == EINTR)) continue;
++            goto done;
++        }
++    }
++done:
++    close(fd);
++}
++#endif
++
++static int create_service_thread(void (*func)(int, void *), void *cookie)
++{
++    stinfo *sti;
++    adb_thread_t t;
++    int s[2];
++
++    if(adb_socketpair(s)) {
++        printf("cannot create service socket pair\n");
++        return -1;
++    }
++
++    sti = malloc(sizeof(stinfo));
++    if(sti == 0) fatal("cannot allocate stinfo");
++    sti->func = func;
++    sti->cookie = cookie;
++    sti->fd = s[1];
++
++    if(adb_thread_create( &t, service_bootstrap_func, sti)){
++        free(sti);
++        adb_close(s[0]);
++        adb_close(s[1]);
++        printf("cannot create service thread\n");
++        return -1;
++    }
++
++    D("service thread started, %d:%d\n",s[0], s[1]);
++    return s[0];
++}
++
++#if !ADB_HOST
++static int create_subprocess(const char *cmd, const char *arg0, const char *arg1, pid_t *pid)
++{
++#ifdef HAVE_WIN32_PROC
++    D("create_subprocess(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1);
++    fprintf(stderr, "error: create_subprocess not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1);
++    return -1;
++#else /* !HAVE_WIN32_PROC */
++    char *devname;
++    int ptm;
++
++    ptm = unix_open("/dev/ptmx", O_RDWR); // | O_NOCTTY);
++    if(ptm < 0){
++        printf("[ cannot open /dev/ptmx - %s ]\n",strerror(errno));
++        return -1;
++    }
++    fcntl(ptm, F_SETFD, FD_CLOEXEC);
++
++    if(grantpt(ptm) || unlockpt(ptm) ||
++       ((devname = (char*) ptsname(ptm)) == 0)){
++        printf("[ trouble with /dev/ptmx - %s ]\n", strerror(errno));
++        adb_close(ptm);
++        return -1;
++    }
++
++    *pid = fork();
++    if(*pid < 0) {
++        printf("- fork failed: %s -\n", strerror(errno));
++        adb_close(ptm);
++        return -1;
++    }
++
++    if(*pid == 0){
++        int pts;
++
++        setsid();
++
++        pts = unix_open(devname, O_RDWR);
++        if(pts < 0) {
++            fprintf(stderr, "child failed to open pseudo-term slave: %s\n", devname);
++            exit(-1);
++        }
++
++        dup2(pts, 0);
++        dup2(pts, 1);
++        dup2(pts, 2);
++
++        adb_close(pts);
++        adb_close(ptm);
++
++        // set OOM adjustment to zero
++        char text[64];
++        snprintf(text, sizeof text, "/proc/%d/oom_adj", getpid());
++        int fd = adb_open(text, O_WRONLY);
++        if (fd >= 0) {
++            adb_write(fd, "0", 1);
++            adb_close(fd);
++        } else {
++           D("adb: unable to open %s\n", text);
++        }
++        execl(cmd, cmd, arg0, arg1, NULL);
++        fprintf(stderr, "- exec '%s' failed: %s (%d) -\n",
++                cmd, strerror(errno), errno);
++        exit(-1);
++    } else {
++        // Don't set child's OOM adjustment to zero.
++        // Let the child do it itself, as sometimes the parent starts
++        // running before the child has a /proc/pid/oom_adj.
++        // """adb: unable to open /proc/644/oom_adj""" seen in some logs.
++        return ptm;
++    }
++#endif /* !HAVE_WIN32_PROC */
++}
++#endif  /* !ABD_HOST */
++
++#if ADB_HOST
++#define SHELL_COMMAND "/bin/sh"
++#else
++#define SHELL_COMMAND "/system/bin/sh"
++#endif
++
++#if !ADB_HOST
++static void subproc_waiter_service(int fd, void *cookie)
++{
++    pid_t pid = (pid_t)cookie;
++
++    D("entered. fd=%d of pid=%d\n", fd, pid);
++    for (;;) {
++        int status;
++        pid_t p = waitpid(pid, &status, 0);
++        if (p == pid) {
++            D("fd=%d, post waitpid(pid=%d) status=%04x\n", fd, p, status);
++            if (WIFSIGNALED(status)) {
++                D("*** Killed by signal %d\n", WTERMSIG(status));
++                break;
++            } else if (!WIFEXITED(status)) {
++                D("*** Didn't exit!!. status %d\n", status);
++                break;
++            } else if (WEXITSTATUS(status) >= 0) {
++                D("*** Exit code %d\n", WEXITSTATUS(status));
++                break;
++            }
++         }
++    }
++    D("shell exited fd=%d of pid=%d err=%d\n", fd, pid, errno);
++    if (SHELL_EXIT_NOTIFY_FD >=0) {
++      int res;
++      res = writex(SHELL_EXIT_NOTIFY_FD, &fd, sizeof(fd));
++      D("notified shell exit via fd=%d for pid=%d res=%d errno=%d\n",
++        SHELL_EXIT_NOTIFY_FD, pid, res, errno);
++    }
++}
++
++static int create_subproc_thread(const char *name)
++{
++    stinfo *sti;
++    adb_thread_t t;
++    int ret_fd;
++    pid_t pid;
++
++    struct passwd *user = getpwuid(getuid());
++    char *shell;
++
++    if (user && user->pw_shell)
++        shell = user->pw_shell;
++    else
++        shell = SHELL_COMMAND;
++
++    if(name) {
++        ret_fd = create_subprocess(shell, "-c", name, &pid);
++    } else {
++        ret_fd = create_subprocess(shell, "-", 0, &pid);
++    }
++    D("create_subprocess() ret_fd=%d pid=%d\n", ret_fd, pid);
++
++    sti = malloc(sizeof(stinfo));
++    if(sti == 0) fatal("cannot allocate stinfo");
++    sti->func = subproc_waiter_service;
++    sti->cookie = (void*)pid;
++    sti->fd = ret_fd;
++
++    if(adb_thread_create( &t, service_bootstrap_func, sti)){
++        free(sti);
++        adb_close(ret_fd);
++        printf("cannot create service thread\n");
++        return -1;
++    }
++
++    D("service thread started, fd=%d pid=%d\n",ret_fd, pid);
++    return ret_fd;
++}
++#endif
++
++int service_to_fd(const char *name)
++{
++    int ret = -1;
++
++    if(!strncmp(name, "tcp:", 4)) {
++        int port = atoi(name + 4);
++        name = strchr(name + 4, ':');
++        if(name == 0) {
++            ret = socket_loopback_client(port, SOCK_STREAM);
++            if (ret >= 0)
++                disable_tcp_nagle(ret);
++        } else {
++#if ADB_HOST
++            adb_mutex_lock(&dns_lock);
++            ret = socket_network_client(name + 1, port, SOCK_STREAM);
++            adb_mutex_unlock(&dns_lock);
++#else
++            return -1;
++#endif
++        }
++#ifndef HAVE_WINSOCK   /* winsock doesn't implement unix domain sockets */
++    } else if(!strncmp(name, "local:", 6)) {
++        ret = socket_local_client(name + 6,
++                ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
++    } else if(!strncmp(name, "localreserved:", 14)) {
++        ret = socket_local_client(name + 14,
++                ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
++    } else if(!strncmp(name, "localabstract:", 14)) {
++        ret = socket_local_client(name + 14,
++                ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
++    } else if(!strncmp(name, "localfilesystem:", 16)) {
++        ret = socket_local_client(name + 16,
++                ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
++#endif
++#if ADB_HOST
++    } else if(!strncmp("dns:", name, 4)){
++        char *n = strdup(name + 4);
++        if(n == 0) return -1;
++        ret = create_service_thread(dns_service, n);
++#else /* !ADB_HOST */
++    } else if(!strncmp("dev:", name, 4)) {
++        ret = unix_open(name + 4, O_RDWR);
++    } else if(!strncmp(name, "framebuffer:", 12)) {
++        ret = create_service_thread(framebuffer_service, 0);
++    } else if(recovery_mode && !strncmp(name, "recover:", 8)) {
++        ret = create_service_thread(recover_service, (void*) atoi(name + 8));
++    } else if (!strncmp(name, "jdwp:", 5)) {
++        ret = create_jdwp_connection_fd(atoi(name+5));
++    } else if (!strncmp(name, "log:", 4)) {
++        ret = create_service_thread(log_service, get_log_file_path(name + 4));
++    } else if(!HOST && !strncmp(name, "shell:", 6)) {
++        if(name[6]) {
++            ret = create_subproc_thread(name + 6);
++        } else {
++            ret = create_subproc_thread(0);
++        }
++    } else if(!strncmp(name, "sync:", 5)) {
++        ret = create_service_thread(file_sync_service, NULL);
++    } else if(!strncmp(name, "remount:", 8)) {
++        ret = create_service_thread(remount_service, NULL);
++    } else if(!strncmp(name, "reboot:", 7)) {
++        void* arg = strdup(name + 7);
++        if(arg == 0) return -1;
++        ret = create_service_thread(reboot_service, arg);
++    } else if(!strncmp(name, "root:", 5)) {
++        ret = create_service_thread(restart_root_service, NULL);
++    } else if(!strncmp(name, "backup:", 7)) {
++        char* arg = strdup(name+7);
++        if (arg == NULL) return -1;
++        ret = backup_service(BACKUP, arg);
++    } else if(!strncmp(name, "restore:", 8)) {
++        ret = backup_service(RESTORE, NULL);
++    } else if(!strncmp(name, "tcpip:", 6)) {
++        int port;
++        if (sscanf(name + 6, "%d", &port) == 0) {
++            port = 0;
++        }
++        ret = create_service_thread(restart_tcp_service, (void *)port);
++    } else if(!strncmp(name, "usb:", 4)) {
++        ret = create_service_thread(restart_usb_service, NULL);
++#endif
++#if 0
++    } else if(!strncmp(name, "echo:", 5)){
++        ret = create_service_thread(echo_service, 0);
++#endif
++    }
++    if (ret >= 0) {
++        close_on_exec(ret);
++    }
++    return ret;
++}
++
++#if ADB_HOST
++struct state_info {
++    transport_type transport;
++    char* serial;
++    int state;
++};
++
++static void wait_for_state(int fd, void* cookie)
++{
++    struct state_info* sinfo = cookie;
++    char* err = "unknown error";
++
++    D("wait_for_state %d\n", sinfo->state);
++
++    atransport *t = acquire_one_transport(sinfo->state, sinfo->transport, sinfo->serial, &err);
++    if(t != 0) {
++        writex(fd, "OKAY", 4);
++    } else {
++        sendfailmsg(fd, err);
++    }
++
++    if (sinfo->serial)
++        free(sinfo->serial);
++    free(sinfo);
++    adb_close(fd);
++    D("wait_for_state is done\n");
++}
++#endif
++
++#if ADB_HOST
++asocket*  host_service_to_socket(const char*  name, const char *serial)
++{
++    if (!strcmp(name,"track-devices")) {
++        return create_device_tracker();
++    } else if (!strncmp(name, "wait-for-", strlen("wait-for-"))) {
++        struct state_info* sinfo = malloc(sizeof(struct state_info));
++
++        if (serial)
++            sinfo->serial = strdup(serial);
++        else
++            sinfo->serial = NULL;
++
++        name += strlen("wait-for-");
++
++        if (!strncmp(name, "local", strlen("local"))) {
++            sinfo->transport = kTransportLocal;
++            sinfo->state = CS_DEVICE;
++        } else if (!strncmp(name, "usb", strlen("usb"))) {
++            sinfo->transport = kTransportUsb;
++            sinfo->state = CS_DEVICE;
++        } else if (!strncmp(name, "any", strlen("any"))) {
++            sinfo->transport = kTransportAny;
++            sinfo->state = CS_DEVICE;
++        } else {
++            free(sinfo);
++            return NULL;
++        }
++
++        int fd = create_service_thread(wait_for_state, sinfo);
++        return create_local_socket(fd);
++    }
++    return NULL;
++}
++#endif /* ADB_HOST */
+Index: android-tools-4.2.2+git20130218/core/adbd/sockets.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/sockets.c        2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,873 @@
++/*
++ * Copyright (C) 2007 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <errno.h>
++#include <string.h>
++#include <ctype.h>
++
++#include "sysdeps.h"
++
++#define  TRACE_TAG  TRACE_SOCKETS
++#include "adb.h"
++
++ADB_MUTEX_DEFINE( socket_list_lock );
++
++static void local_socket_close_locked(asocket *s);
++
++int sendfailmsg(int fd, const char *reason)
++{
++    char buf[9];
++    int len;
++    len = strlen(reason);
++    if(len > 0xffff) len = 0xffff;
++    snprintf(buf, sizeof buf, "FAIL%04x", len);
++    if(writex(fd, buf, 8)) return -1;
++    return writex(fd, reason, len);
++}
++
++//extern int online;
++
++static unsigned local_socket_next_id = 1;
++
++static asocket local_socket_list = {
++    .next = &local_socket_list,
++    .prev = &local_socket_list,
++};
++
++/* the the list of currently closing local sockets.
++** these have no peer anymore, but still packets to
++** write to their fd.
++*/
++static asocket local_socket_closing_list = {
++    .next = &local_socket_closing_list,
++    .prev = &local_socket_closing_list,
++};
++
++asocket *find_local_socket(unsigned id)
++{
++    asocket *s;
++    asocket *result = NULL;
++
++    adb_mutex_lock(&socket_list_lock);
++    for (s = local_socket_list.next; s != &local_socket_list; s = s->next) {
++        if (s->id == id) {
++            result = s;
++            break;
++        }
++    }
++    adb_mutex_unlock(&socket_list_lock);
++
++    return result;
++}
++
++static void
++insert_local_socket(asocket*  s, asocket*  list)
++{
++    s->next       = list;
++    s->prev       = s->next->prev;
++    s->prev->next = s;
++    s->next->prev = s;
++}
++
++
++void install_local_socket(asocket *s)
++{
++    adb_mutex_lock(&socket_list_lock);
++
++    s->id = local_socket_next_id++;
++    insert_local_socket(s, &local_socket_list);
++
++    adb_mutex_unlock(&socket_list_lock);
++}
++
++void remove_socket(asocket *s)
++{
++    // socket_list_lock should already be held
++    if (s->prev && s->next)
++    {
++        s->prev->next = s->next;
++        s->next->prev = s->prev;
++        s->next = 0;
++        s->prev = 0;
++        s->id = 0;
++    }
++}
++
++void close_all_sockets(atransport *t)
++{
++    asocket *s;
++
++        /* this is a little gross, but since s->close() *will* modify
++        ** the list out from under you, your options are limited.
++        */
++    adb_mutex_lock(&socket_list_lock);
++restart:
++    for(s = local_socket_list.next; s != &local_socket_list; s = s->next){
++        if(s->transport == t || (s->peer && s->peer->transport == t)) {
++            local_socket_close_locked(s);
++            goto restart;
++        }
++    }
++    adb_mutex_unlock(&socket_list_lock);
++}
++
++static int local_socket_enqueue(asocket *s, apacket *p)
++{
++    D("LS(%d): enqueue %d\n", s->id, p->len);
++
++    p->ptr = p->data;
++
++        /* if there is already data queue'd, we will receive
++        ** events when it's time to write.  just add this to
++        ** the tail
++        */
++    if(s->pkt_first) {
++        goto enqueue;
++    }
++
++        /* write as much as we can, until we
++        ** would block or there is an error/eof
++        */
++    while(p->len > 0) {
++        int r = adb_write(s->fd, p->ptr, p->len);
++        if(r > 0) {
++            p->len -= r;
++            p->ptr += r;
++            continue;
++        }
++        if((r == 0) || (errno != EAGAIN)) {
++            D( "LS(%d): not ready, errno=%d: %s\n", s->id, errno, strerror(errno) );
++            s->close(s);
++            return 1; /* not ready (error) */
++        } else {
++            break;
++        }
++    }
++
++    if(p->len == 0) {
++        put_apacket(p);
++        return 0; /* ready for more data */
++    }
++
++enqueue:
++    p->next = 0;
++    if(s->pkt_first) {
++        s->pkt_last->next = p;
++    } else {
++        s->pkt_first = p;
++    }
++    s->pkt_last = p;
++
++        /* make sure we are notified when we can drain the queue */
++    fdevent_add(&s->fde, FDE_WRITE);
++
++    return 1; /* not ready (backlog) */
++}
++
++static void local_socket_ready(asocket *s)
++{
++        /* far side is ready for data, pay attention to
++           readable events */
++    fdevent_add(&s->fde, FDE_READ);
++//    D("LS(%d): ready()\n", s->id);
++}
++
++static void local_socket_close(asocket *s)
++{
++    adb_mutex_lock(&socket_list_lock);
++    local_socket_close_locked(s);
++    adb_mutex_unlock(&socket_list_lock);
++}
++
++// be sure to hold the socket list lock when calling this
++static void local_socket_destroy(asocket  *s)
++{
++    apacket *p, *n;
++    int exit_on_close = s->exit_on_close;
++
++    D("LS(%d): destroying fde.fd=%d\n", s->id, s->fde.fd);
++
++        /* IMPORTANT: the remove closes the fd
++        ** that belongs to this socket
++        */
++    fdevent_remove(&s->fde);
++
++        /* dispose of any unwritten data */
++    for(p = s->pkt_first; p; p = n) {
++        D("LS(%d): discarding %d bytes\n", s->id, p->len);
++        n = p->next;
++        put_apacket(p);
++    }
++    remove_socket(s);
++    free(s);
++
++    if (exit_on_close) {
++        D("local_socket_destroy: exiting\n");
++        exit(1);
++    }
++}
++
++
++static void local_socket_close_locked(asocket *s)
++{
++    D("entered. LS(%d) fd=%d\n", s->id, s->fd);
++    if(s->peer) {
++        D("LS(%d): closing peer. peer->id=%d peer->fd=%d\n",
++          s->id, s->peer->id, s->peer->fd);
++        s->peer->peer = 0;
++        // tweak to avoid deadlock
++        if (s->peer->close == local_socket_close) {
++            local_socket_close_locked(s->peer);
++        } else {
++            s->peer->close(s->peer);
++        }
++        s->peer = 0;
++    }
++
++        /* If we are already closing, or if there are no
++        ** pending packets, destroy immediately
++        */
++    if (s->closing || s->pkt_first == NULL) {
++        int   id = s->id;
++        local_socket_destroy(s);
++        D("LS(%d): closed\n", id);
++        return;
++    }
++
++        /* otherwise, put on the closing list
++        */
++    D("LS(%d): closing\n", s->id);
++    s->closing = 1;
++    fdevent_del(&s->fde, FDE_READ);
++    remove_socket(s);
++    D("LS(%d): put on socket_closing_list fd=%d\n", s->id, s->fd);
++    insert_local_socket(s, &local_socket_closing_list);
++}
++
++static void local_socket_event_func(int fd, unsigned ev, void *_s)
++{
++    asocket *s = _s;
++
++    D("LS(%d): event_func(fd=%d(==%d), ev=%04x)\n", s->id, s->fd, fd, ev);
++
++    /* put the FDE_WRITE processing before the FDE_READ
++    ** in order to simplify the code.
++    */
++    if(ev & FDE_WRITE){
++        apacket *p;
++
++        while((p = s->pkt_first) != 0) {
++            while(p->len > 0) {
++                int r = adb_write(fd, p->ptr, p->len);
++                if(r > 0) {
++                    p->ptr += r;
++                    p->len -= r;
++                    continue;
++                }
++                if(r < 0) {
++                    /* returning here is ok because FDE_READ will
++                    ** be processed in the next iteration loop
++                    */
++                    if(errno == EAGAIN) return;
++                    if(errno == EINTR) continue;
++                }
++                D(" closing after write because r=%d and errno is %d\n", r, errno);
++                s->close(s);
++                return;
++            }
++
++            if(p->len == 0) {
++                s->pkt_first = p->next;
++                if(s->pkt_first == 0) s->pkt_last = 0;
++                put_apacket(p);
++            }
++        }
++
++            /* if we sent the last packet of a closing socket,
++            ** we can now destroy it.
++            */
++        if (s->closing) {
++            D(" closing because 'closing' is set after write\n");
++            s->close(s);
++            return;
++        }
++
++            /* no more packets queued, so we can ignore
++            ** writable events again and tell our peer
++            ** to resume writing
++            */
++        fdevent_del(&s->fde, FDE_WRITE);
++        s->peer->ready(s->peer);
++    }
++
++
++    if(ev & FDE_READ){
++        apacket *p = get_apacket();
++        unsigned char *x = p->data;
++        size_t avail = MAX_PAYLOAD;
++        int r;
++        int is_eof = 0;
++
++        while(avail > 0) {
++            r = adb_read(fd, x, avail);
++            D("LS(%d): post adb_read(fd=%d,...) r=%d (errno=%d) avail=%d\n", s->id, s->fd, r, r<0?errno:0, avail);
++            if(r > 0) {
++                avail -= r;
++                x += r;
++                continue;
++            }
++            if(r < 0) {
++                if(errno == EAGAIN) break;
++                if(errno == EINTR) continue;
++            }
++
++                /* r = 0 or unhandled error */
++            is_eof = 1;
++            break;
++        }
++        D("LS(%d): fd=%d post avail loop. r=%d is_eof=%d forced_eof=%d\n",
++          s->id, s->fd, r, is_eof, s->fde.force_eof);
++        if((avail == MAX_PAYLOAD) || (s->peer == 0)) {
++            put_apacket(p);
++        } else {
++            p->len = MAX_PAYLOAD - avail;
++
++            r = s->peer->enqueue(s->peer, p);
++            D("LS(%d): fd=%d post peer->enqueue(). r=%d\n", s->id, s->fd, r);
++
++            if(r < 0) {
++                    /* error return means they closed us as a side-effect
++                    ** and we must return immediately.
++                    **
++                    ** note that if we still have buffered packets, the
++                    ** socket will be placed on the closing socket list.
++                    ** this handler function will be called again
++                    ** to process FDE_WRITE events.
++                    */
++                return;
++            }
++
++            if(r > 0) {
++                    /* if the remote cannot accept further events,
++                    ** we disable notification of READs.  They'll
++                    ** be enabled again when we get a call to ready()
++                    */
++                fdevent_del(&s->fde, FDE_READ);
++            }
++        }
++        /* Don't allow a forced eof if data is still there */
++        if((s->fde.force_eof && !r) || is_eof) {
++            D(" closing because is_eof=%d r=%d s->fde.force_eof=%d\n", is_eof, r, s->fde.force_eof);
++            s->close(s);
++        }
++    }
++
++    if(ev & FDE_ERROR){
++            /* this should be caught be the next read or write
++            ** catching it here means we may skip the last few
++            ** bytes of readable data.
++            */
++//        s->close(s);
++        D("LS(%d): FDE_ERROR (fd=%d)\n", s->id, s->fd);
++
++        return;
++    }
++}
++
++asocket *create_local_socket(int fd)
++{
++    asocket *s = calloc(1, sizeof(asocket));
++    if (s == NULL) fatal("cannot allocate socket");
++    s->fd = fd;
++    s->enqueue = local_socket_enqueue;
++    s->ready = local_socket_ready;
++    s->close = local_socket_close;
++    install_local_socket(s);
++
++    fdevent_install(&s->fde, fd, local_socket_event_func, s);
++/*    fdevent_add(&s->fde, FDE_ERROR); */
++    //fprintf(stderr, "Created local socket in create_local_socket \n");
++    D("LS(%d): created (fd=%d)\n", s->id, s->fd);
++    return s;
++}
++
++asocket *create_local_service_socket(const char *name)
++{
++    asocket *s;
++    int fd;
++
++#if !ADB_HOST
++    if (!strcmp(name,"jdwp")) {
++        return create_jdwp_service_socket();
++    }
++    if (!strcmp(name,"track-jdwp")) {
++        return create_jdwp_tracker_service_socket();
++    }
++#endif
++    fd = service_to_fd(name);
++    if(fd < 0) return 0;
++
++    s = create_local_socket(fd);
++    D("LS(%d): bound to '%s' via %d\n", s->id, name, fd);
++
++#if !ADB_HOST
++    if ((!strncmp(name, "root:", 5) && getuid() != 0)
++        || !strncmp(name, "usb:", 4)
++        || !strncmp(name, "tcpip:", 6)) {
++        D("LS(%d): enabling exit_on_close\n", s->id);
++        s->exit_on_close = 1;
++    }
++#endif
++
++    return s;
++}
++
++#if ADB_HOST
++static asocket *create_host_service_socket(const char *name, const char* serial)
++{
++    asocket *s;
++
++    s = host_service_to_socket(name, serial);
++
++    if (s != NULL) {
++        D("LS(%d) bound to '%s'\n", s->id, name);
++        return s;
++    }
++
++    return s;
++}
++#endif /* ADB_HOST */
++
++/* a Remote socket is used to send/receive data to/from a given transport object
++** it needs to be closed when the transport is forcibly destroyed by the user
++*/
++typedef struct aremotesocket {
++    asocket      socket;
++    adisconnect  disconnect;
++} aremotesocket;
++
++static int remote_socket_enqueue(asocket *s, apacket *p)
++{
++    D("entered remote_socket_enqueue RS(%d) WRITE fd=%d peer.fd=%d\n",
++      s->id, s->fd, s->peer->fd);
++    p->msg.command = A_WRTE;
++    p->msg.arg0 = s->peer->id;
++    p->msg.arg1 = s->id;
++    p->msg.data_length = p->len;
++    send_packet(p, s->transport);
++    return 1;
++}
++
++static void remote_socket_ready(asocket *s)
++{
++    D("entered remote_socket_ready RS(%d) OKAY fd=%d peer.fd=%d\n",
++      s->id, s->fd, s->peer->fd);
++    apacket *p = get_apacket();
++    p->msg.command = A_OKAY;
++    p->msg.arg0 = s->peer->id;
++    p->msg.arg1 = s->id;
++    send_packet(p, s->transport);
++}
++
++static void remote_socket_close(asocket *s)
++{
++    D("entered remote_socket_close RS(%d) CLOSE fd=%d peer->fd=%d\n",
++      s->id, s->fd, s->peer?s->peer->fd:-1);
++    apacket *p = get_apacket();
++    p->msg.command = A_CLSE;
++    if(s->peer) {
++        p->msg.arg0 = s->peer->id;
++        s->peer->peer = 0;
++        D("RS(%d) peer->close()ing peer->id=%d peer->fd=%d\n",
++          s->id, s->peer->id, s->peer->fd);
++        s->peer->close(s->peer);
++    }
++    p->msg.arg1 = s->id;
++    send_packet(p, s->transport);
++    D("RS(%d): closed\n", s->id);
++    remove_transport_disconnect( s->transport, &((aremotesocket*)s)->disconnect );
++    free(s);
++}
++
++static void remote_socket_disconnect(void*  _s, atransport*  t)
++{
++    asocket*  s    = _s;
++    asocket*  peer = s->peer;
++
++    D("remote_socket_disconnect RS(%d)\n", s->id);
++    if (peer) {
++        peer->peer = NULL;
++        peer->close(peer);
++    }
++    remove_transport_disconnect( s->transport, &((aremotesocket*)s)->disconnect );
++    free(s);
++}
++
++asocket *create_remote_socket(unsigned id, atransport *t)
++{
++    asocket *s = calloc(1, sizeof(aremotesocket));
++    adisconnect*  dis = &((aremotesocket*)s)->disconnect;
++
++    if (s == NULL) fatal("cannot allocate socket");
++    s->id = id;
++    s->enqueue = remote_socket_enqueue;
++    s->ready = remote_socket_ready;
++    s->close = remote_socket_close;
++    s->transport = t;
++
++    dis->func   = remote_socket_disconnect;
++    dis->opaque = s;
++    add_transport_disconnect( t, dis );
++    D("RS(%d): created\n", s->id);
++    return s;
++}
++
++void connect_to_remote(asocket *s, const char *destination)
++{
++    D("Connect_to_remote call RS(%d) fd=%d\n", s->id, s->fd);
++    apacket *p = get_apacket();
++    int len = strlen(destination) + 1;
++
++    if(len > (MAX_PAYLOAD-1)) {
++        fatal("destination oversized");
++    }
++
++    D("LS(%d): connect('%s')\n", s->id, destination);
++    p->msg.command = A_OPEN;
++    p->msg.arg0 = s->id;
++    p->msg.data_length = len;
++    strcpy((char*) p->data, destination);
++    send_packet(p, s->transport);
++}
++
++
++/* this is used by magic sockets to rig local sockets to
++   send the go-ahead message when they connect */
++static void local_socket_ready_notify(asocket *s)
++{
++    s->ready = local_socket_ready;
++    s->close = local_socket_close;
++    adb_write(s->fd, "OKAY", 4);
++    s->ready(s);
++}
++
++/* this is used by magic sockets to rig local sockets to
++   send the failure message if they are closed before
++   connected (to avoid closing them without a status message) */
++static void local_socket_close_notify(asocket *s)
++{
++    s->ready = local_socket_ready;
++    s->close = local_socket_close;
++    sendfailmsg(s->fd, "closed");
++    s->close(s);
++}
++
++unsigned unhex(unsigned char *s, int len)
++{
++    unsigned n = 0, c;
++
++    while(len-- > 0) {
++        switch((c = *s++)) {
++        case '0': case '1': case '2':
++        case '3': case '4': case '5':
++        case '6': case '7': case '8':
++        case '9':
++            c -= '0';
++            break;
++        case 'a': case 'b': case 'c':
++        case 'd': case 'e': case 'f':
++            c = c - 'a' + 10;
++            break;
++        case 'A': case 'B': case 'C':
++        case 'D': case 'E': case 'F':
++            c = c - 'A' + 10;
++            break;
++        default:
++            return 0xffffffff;
++        }
++
++        n = (n << 4) | c;
++    }
++
++    return n;
++}
++
++#define PREFIX(str) { str, sizeof(str) - 1 }
++static const struct prefix_struct {
++    const char *str;
++    const size_t len;
++} prefixes[] = {
++    PREFIX("usb:"),
++    PREFIX("product:"),
++    PREFIX("model:"),
++    PREFIX("device:"),
++};
++static const int num_prefixes = (sizeof(prefixes) / sizeof(prefixes[0]));
++
++/* skip_host_serial return the position in a string
++   skipping over the 'serial' parameter in the ADB protocol,
++   where parameter string may be a host:port string containing
++   the protocol delimiter (colon). */
++char *skip_host_serial(char *service) {
++    char *first_colon, *serial_end;
++    int i;
++
++    for (i = 0; i < num_prefixes; i++) {
++        if (!strncmp(service, prefixes[i].str, prefixes[i].len))
++            return strchr(service + prefixes[i].len, ':');
++    }
++
++    first_colon = strchr(service, ':');
++    if (!first_colon) {
++        /* No colon in service string. */
++        return NULL;
++    }
++    serial_end = first_colon;
++    if (isdigit(serial_end[1])) {
++        serial_end++;
++        while ((*serial_end) && isdigit(*serial_end)) {
++            serial_end++;
++        }
++        if ((*serial_end) != ':') {
++            // Something other than numbers was found, reset the end.
++            serial_end = first_colon;
++        }
++    }
++    return serial_end;
++}
++
++static int smart_socket_enqueue(asocket *s, apacket *p)
++{
++    unsigned len;
++#if ADB_HOST
++    char *service = NULL;
++    char* serial = NULL;
++    transport_type ttype = kTransportAny;
++#endif
++
++    D("SS(%d): enqueue %d\n", s->id, p->len);
++
++    if(s->pkt_first == 0) {
++        s->pkt_first = p;
++        s->pkt_last = p;
++    } else {
++        if((s->pkt_first->len + p->len) > MAX_PAYLOAD) {
++            D("SS(%d): overflow\n", s->id);
++            put_apacket(p);
++            goto fail;
++        }
++
++        memcpy(s->pkt_first->data + s->pkt_first->len,
++               p->data, p->len);
++        s->pkt_first->len += p->len;
++        put_apacket(p);
++
++        p = s->pkt_first;
++    }
++
++        /* don't bother if we can't decode the length */
++    if(p->len < 4) return 0;
++
++    len = unhex(p->data, 4);
++    if((len < 1) ||  (len > 1024)) {
++        D("SS(%d): bad size (%d)\n", s->id, len);
++        goto fail;
++    }
++
++    D("SS(%d): len is %d\n", s->id, len );
++        /* can't do anything until we have the full header */
++    if((len + 4) > p->len) {
++        D("SS(%d): waiting for %d more bytes\n", s->id, len+4 - p->len);
++        return 0;
++    }
++
++    p->data[len + 4] = 0;
++
++    D("SS(%d): '%s'\n", s->id, (char*) (p->data + 4));
++
++#if ADB_HOST
++    service = (char *)p->data + 4;
++    if(!strncmp(service, "host-serial:", strlen("host-serial:"))) {
++        char* serial_end;
++        service += strlen("host-serial:");
++
++        // serial number should follow "host:" and could be a host:port string.
++        serial_end = skip_host_serial(service);
++        if (serial_end) {
++            *serial_end = 0; // terminate string
++            serial = service;
++            service = serial_end + 1;
++        }
++    } else if (!strncmp(service, "host-usb:", strlen("host-usb:"))) {
++        ttype = kTransportUsb;
++        service += strlen("host-usb:");
++    } else if (!strncmp(service, "host-local:", strlen("host-local:"))) {
++        ttype = kTransportLocal;
++        service += strlen("host-local:");
++    } else if (!strncmp(service, "host:", strlen("host:"))) {
++        ttype = kTransportAny;
++        service += strlen("host:");
++    } else {
++        service = NULL;
++    }
++
++    if (service) {
++        asocket *s2;
++
++            /* some requests are handled immediately -- in that
++            ** case the handle_host_request() routine has sent
++            ** the OKAY or FAIL message and all we have to do
++            ** is clean up.
++            */
++        if(handle_host_request(service, ttype, serial, s->peer->fd, s) == 0) {
++                /* XXX fail message? */
++            D( "SS(%d): handled host service '%s'\n", s->id, service );
++            goto fail;
++        }
++        if (!strncmp(service, "transport", strlen("transport"))) {
++            D( "SS(%d): okay transport\n", s->id );
++            p->len = 0;
++            return 0;
++        }
++
++            /* try to find a local service with this name.
++            ** if no such service exists, we'll fail out
++            ** and tear down here.
++            */
++        s2 = create_host_service_socket(service, serial);
++        if(s2 == 0) {
++            D( "SS(%d): couldn't create host service '%s'\n", s->id, service );
++            sendfailmsg(s->peer->fd, "unknown host service");
++            goto fail;
++        }
++
++            /* we've connected to a local host service,
++            ** so we make our peer back into a regular
++            ** local socket and bind it to the new local
++            ** service socket, acknowledge the successful
++            ** connection, and close this smart socket now
++            ** that its work is done.
++            */
++        adb_write(s->peer->fd, "OKAY", 4);
++
++        s->peer->ready = local_socket_ready;
++        s->peer->close = local_socket_close;
++        s->peer->peer = s2;
++        s2->peer = s->peer;
++        s->peer = 0;
++        D( "SS(%d): okay\n", s->id );
++        s->close(s);
++
++            /* initial state is "ready" */
++        s2->ready(s2);
++        return 0;
++    }
++#else /* !ADB_HOST */
++    if (s->transport == NULL) {
++        char* error_string = "unknown failure";
++        s->transport = acquire_one_transport (CS_ANY,
++                kTransportAny, NULL, &error_string);
++
++        if (s->transport == NULL) {
++            sendfailmsg(s->peer->fd, error_string);
++            goto fail;
++        }
++    }
++#endif
++
++    if(!(s->transport) || (s->transport->connection_state == CS_OFFLINE)) {
++           /* if there's no remote we fail the connection
++            ** right here and terminate it
++            */
++        sendfailmsg(s->peer->fd, "device offline (x)");
++        goto fail;
++    }
++
++
++        /* instrument our peer to pass the success or fail
++        ** message back once it connects or closes, then
++        ** detach from it, request the connection, and
++        ** tear down
++        */
++    s->peer->ready = local_socket_ready_notify;
++    s->peer->close = local_socket_close_notify;
++    s->peer->peer = 0;
++        /* give him our transport and upref it */
++    s->peer->transport = s->transport;
++
++    connect_to_remote(s->peer, (char*) (p->data + 4));
++    s->peer = 0;
++    s->close(s);
++    return 1;
++
++fail:
++        /* we're going to close our peer as a side-effect, so
++        ** return -1 to signal that state to the local socket
++        ** who is enqueueing against us
++        */
++    s->close(s);
++    return -1;
++}
++
++static void smart_socket_ready(asocket *s)
++{
++    D("SS(%d): ready\n", s->id);
++}
++
++static void smart_socket_close(asocket *s)
++{
++    D("SS(%d): closed\n", s->id);
++    if(s->pkt_first){
++        put_apacket(s->pkt_first);
++    }
++    if(s->peer) {
++        s->peer->peer = 0;
++        s->peer->close(s->peer);
++        s->peer = 0;
++    }
++    free(s);
++}
++
++asocket *create_smart_socket(void (*action_cb)(asocket *s, const char *act))
++{
++    D("Creating smart socket \n");
++    asocket *s = calloc(1, sizeof(asocket));
++    if (s == NULL) fatal("cannot allocate socket");
++    s->enqueue = smart_socket_enqueue;
++    s->ready = smart_socket_ready;
++    s->close = smart_socket_close;
++    s->extra = action_cb;
++
++    D("SS(%d): created %p\n", s->id, action_cb);
++    return s;
++}
++
++void smart_socket_action(asocket *s, const char *act)
++{
++
++}
++
++void connect_to_smartsocket(asocket *s)
++{
++    D("Connecting to smart socket \n");
++    asocket *ss = create_smart_socket(smart_socket_action);
++    s->peer = ss;
++    ss->peer = s;
++    s->ready(s);
++}
+Index: android-tools-4.2.2+git20130218/core/adbd/sysdeps.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/sysdeps.h        2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,522 @@
++/*
++ * Copyright (C) 2007 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++/* this file contains system-dependent definitions used by ADB
++ * they're related to threads, sockets and file descriptors
++ */
++#ifndef _ADB_SYSDEPS_H
++#define _ADB_SYSDEPS_H
++
++#ifdef __CYGWIN__
++#  undef _WIN32
++#endif
++
++#ifdef _WIN32
++
++#include <windows.h>
++#include <winsock2.h>
++#include <ws2tcpip.h>
++#include <process.h>
++#include <fcntl.h>
++#include <io.h>
++#include <sys/stat.h>
++#include <errno.h>
++#include <ctype.h>
++
++#define OS_PATH_SEPARATOR '\\'
++#define OS_PATH_SEPARATOR_STR "\\"
++#define ENV_PATH_SEPARATOR_STR ";"
++
++typedef CRITICAL_SECTION          adb_mutex_t;
++
++#define  ADB_MUTEX_DEFINE(x)     adb_mutex_t   x
++
++/* declare all mutexes */
++/* For win32, adb_sysdeps_init() will do the mutex runtime initialization. */
++#define  ADB_MUTEX(x)   extern adb_mutex_t  x;
++#include "mutex_list.h"
++
++extern void  adb_sysdeps_init(void);
++
++static __inline__ void adb_mutex_lock( adb_mutex_t*  lock )
++{
++    EnterCriticalSection( lock );
++}
++
++static __inline__ void  adb_mutex_unlock( adb_mutex_t*  lock )
++{
++    LeaveCriticalSection( lock );
++}
++
++typedef struct { unsigned  tid; }  adb_thread_t;
++
++typedef  void*  (*adb_thread_func_t)(void*  arg);
++
++typedef  void (*win_thread_func_t)(void*  arg);
++
++static __inline__ int  adb_thread_create( adb_thread_t  *thread, adb_thread_func_t  func, void*  arg)
++{
++    thread->tid = _beginthread( (win_thread_func_t)func, 0, arg );
++    if (thread->tid == (unsigned)-1L) {
++        return -1;
++    }
++    return 0;
++}
++
++static __inline__ void  close_on_exec(int  fd)
++{
++    /* nothing really */
++}
++
++extern void  disable_tcp_nagle(int  fd);
++
++#define  lstat    stat   /* no symlinks on Win32 */
++
++#define  S_ISLNK(m)   0   /* no symlinks on Win32 */
++
++static __inline__  int    adb_unlink(const char*  path)
++{
++    int  rc = unlink(path);
++
++    if (rc == -1 && errno == EACCES) {
++        /* unlink returns EACCES when the file is read-only, so we first */
++        /* try to make it writable, then unlink again...                  */
++        rc = chmod(path, _S_IREAD|_S_IWRITE );
++        if (rc == 0)
++            rc = unlink(path);
++    }
++    return rc;
++}
++#undef  unlink
++#define unlink  ___xxx_unlink
++
++static __inline__ int  adb_mkdir(const char*  path, int mode)
++{
++      return _mkdir(path);
++}
++#undef   mkdir
++#define  mkdir  ___xxx_mkdir
++
++extern int  adb_open(const char*  path, int  options);
++extern int  adb_creat(const char*  path, int  mode);
++extern int  adb_read(int  fd, void* buf, int len);
++extern int  adb_write(int  fd, const void*  buf, int  len);
++extern int  adb_lseek(int  fd, int  pos, int  where);
++extern int  adb_shutdown(int  fd);
++extern int  adb_close(int  fd);
++
++static __inline__ int  unix_close(int fd)
++{
++    return close(fd);
++}
++#undef   close
++#define  close   ____xxx_close
++
++static __inline__  int  unix_read(int  fd, void*  buf, size_t  len)
++{
++    return read(fd, buf, len);
++}
++#undef   read
++#define  read  ___xxx_read
++
++static __inline__  int  unix_write(int  fd, const void*  buf, size_t  len)
++{
++    return write(fd, buf, len);
++}
++#undef   write
++#define  write  ___xxx_write
++
++static __inline__ int  adb_open_mode(const char* path, int options, int mode)
++{
++    return adb_open(path, options);
++}
++
++static __inline__ int  unix_open(const char*  path, int options,...)
++{
++    if ((options & O_CREAT) == 0)
++    {
++        return  open(path, options);
++    }
++    else
++    {
++        int      mode;
++        va_list  args;
++        va_start( args, options );
++        mode = va_arg( args, int );
++        va_end( args );
++        return open(path, options, mode);
++    }
++}
++#define  open    ___xxx_unix_open
++
++
++/* normally provided by <cutils/misc.h> */
++extern void*  load_file(const char*  pathname, unsigned*  psize);
++
++/* normally provided by <cutils/sockets.h> */
++extern int socket_loopback_client(int port, int type);
++extern int socket_network_client(const char *host, int port, int type);
++extern int socket_loopback_server(int port, int type);
++extern int socket_inaddr_any_server(int port, int type);
++
++/* normally provided by "fdevent.h" */
++
++#define FDE_READ              0x0001
++#define FDE_WRITE             0x0002
++#define FDE_ERROR             0x0004
++#define FDE_DONT_CLOSE        0x0080
++
++typedef struct fdevent fdevent;
++
++typedef void (*fd_func)(int fd, unsigned events, void *userdata);
++
++fdevent *fdevent_create(int fd, fd_func func, void *arg);
++void     fdevent_destroy(fdevent *fde);
++void     fdevent_install(fdevent *fde, int fd, fd_func func, void *arg);
++void     fdevent_remove(fdevent *item);
++void     fdevent_set(fdevent *fde, unsigned events);
++void     fdevent_add(fdevent *fde, unsigned events);
++void     fdevent_del(fdevent *fde, unsigned events);
++void     fdevent_loop();
++
++struct fdevent {
++    fdevent *next;
++    fdevent *prev;
++
++    int fd;
++    int force_eof;
++
++    unsigned short state;
++    unsigned short events;
++
++    fd_func func;
++    void *arg;
++};
++
++static __inline__ void  adb_sleep_ms( int  mseconds )
++{
++    Sleep( mseconds );
++}
++
++extern int  adb_socket_accept(int  serverfd, struct sockaddr*  addr, socklen_t  *addrlen);
++
++#undef   accept
++#define  accept  ___xxx_accept
++
++static __inline__  int  adb_socket_setbufsize( int   fd, int  bufsize )
++{
++    int opt = bufsize;
++    return setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char*)&opt, sizeof(opt));
++}
++
++extern int  adb_socketpair( int  sv[2] );
++
++static __inline__  char*  adb_dirstart( const char*  path )
++{
++    char*  p  = strchr(path, '/');
++    char*  p2 = strchr(path, '\\');
++
++    if ( !p )
++        p = p2;
++    else if ( p2 && p2 > p )
++        p = p2;
++
++    return p;
++}
++
++static __inline__  char*  adb_dirstop( const char*  path )
++{
++    char*  p  = strrchr(path, '/');
++    char*  p2 = strrchr(path, '\\');
++
++    if ( !p )
++        p = p2;
++    else if ( p2 && p2 > p )
++        p = p2;
++
++    return p;
++}
++
++static __inline__  int  adb_is_absolute_host_path( const char*  path )
++{
++    return isalpha(path[0]) && path[1] == ':' && path[2] == '\\';
++}
++
++extern char*  adb_strtok_r(char *str, const char *delim, char **saveptr);
++
++#else /* !_WIN32 a.k.a. Unix */
++
++#include "fdevent.h"
++#include <cutils/sockets.h>
++#include <cutils/properties.h>
++#include <cutils/misc.h>
++#include <signal.h>
++#include <sys/wait.h>
++#include <sys/stat.h>
++#include <fcntl.h>
++
++#include <pthread.h>
++#include <unistd.h>
++#include <fcntl.h>
++#include <stdarg.h>
++#include <netinet/in.h>
++#include <netinet/tcp.h>
++#include <string.h>
++#include <unistd.h>
++
++/*
++ * TEMP_FAILURE_RETRY is defined by some, but not all, versions of
++ * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
++ * not already defined, then define it here.
++ */
++#ifndef TEMP_FAILURE_RETRY
++/* Used to retry syscalls that can return EINTR. */
++#define TEMP_FAILURE_RETRY(exp) ({         \
++    typeof (exp) _rc;                      \
++    do {                                   \
++        _rc = (exp);                       \
++    } while (_rc == -1 && errno == EINTR); \
++    _rc; })
++#endif
++
++#define OS_PATH_SEPARATOR '/'
++#define OS_PATH_SEPARATOR_STR "/"
++#define ENV_PATH_SEPARATOR_STR ":"
++
++typedef  pthread_mutex_t          adb_mutex_t;
++
++#define  ADB_MUTEX_INITIALIZER    PTHREAD_MUTEX_INITIALIZER
++#define  adb_mutex_init           pthread_mutex_init
++#define  adb_mutex_lock           pthread_mutex_lock
++#define  adb_mutex_unlock         pthread_mutex_unlock
++#define  adb_mutex_destroy        pthread_mutex_destroy
++
++#define  ADB_MUTEX_DEFINE(m)      adb_mutex_t   m = PTHREAD_MUTEX_INITIALIZER
++
++#define  adb_cond_t               pthread_cond_t
++#define  adb_cond_init            pthread_cond_init
++#define  adb_cond_wait            pthread_cond_wait
++#define  adb_cond_broadcast       pthread_cond_broadcast
++#define  adb_cond_signal          pthread_cond_signal
++#define  adb_cond_destroy         pthread_cond_destroy
++
++/* declare all mutexes */
++#define  ADB_MUTEX(x)   extern adb_mutex_t  x;
++#include "mutex_list.h"
++
++static __inline__ void  close_on_exec(int  fd)
++{
++    fcntl( fd, F_SETFD, FD_CLOEXEC );
++}
++
++static __inline__ int  unix_open(const char*  path, int options,...)
++{
++    if ((options & O_CREAT) == 0)
++    {
++        return  TEMP_FAILURE_RETRY( open(path, options) );
++    }
++    else
++    {
++        int      mode;
++        va_list  args;
++        va_start( args, options );
++        mode = va_arg( args, int );
++        va_end( args );
++        return TEMP_FAILURE_RETRY( open( path, options, mode ) );
++    }
++}
++
++static __inline__ int  adb_open_mode( const char*  pathname, int  options, int  mode )
++{
++    return TEMP_FAILURE_RETRY( open( pathname, options, mode ) );
++}
++
++
++static __inline__ int  adb_open( const char*  pathname, int  options )
++{
++    int  fd = TEMP_FAILURE_RETRY( open( pathname, options ) );
++    if (fd < 0)
++        return -1;
++    close_on_exec( fd );
++    return fd;
++}
++#undef   open
++#define  open    ___xxx_open
++
++static __inline__ int  adb_shutdown(int fd)
++{
++    return shutdown(fd, SHUT_RDWR);
++}
++#undef   shutdown
++#define  shutdown   ____xxx_shutdown
++
++static __inline__ int  adb_close(int fd)
++{
++    return close(fd);
++}
++#undef   close
++#define  close   ____xxx_close
++
++
++static __inline__  int  adb_read(int  fd, void*  buf, size_t  len)
++{
++    return TEMP_FAILURE_RETRY( read( fd, buf, len ) );
++}
++
++#undef   read
++#define  read  ___xxx_read
++
++static __inline__  int  adb_write(int  fd, const void*  buf, size_t  len)
++{
++    return TEMP_FAILURE_RETRY( write( fd, buf, len ) );
++}
++#undef   write
++#define  write  ___xxx_write
++
++static __inline__ int   adb_lseek(int  fd, int  pos, int  where)
++{
++    return lseek(fd, pos, where);
++}
++#undef   lseek
++#define  lseek   ___xxx_lseek
++
++static __inline__  int    adb_unlink(const char*  path)
++{
++    return  unlink(path);
++}
++#undef  unlink
++#define unlink  ___xxx_unlink
++
++static __inline__  int  adb_creat(const char*  path, int  mode)
++{
++    int  fd = TEMP_FAILURE_RETRY( creat( path, mode ) );
++
++    if ( fd < 0 )
++        return -1;
++
++    close_on_exec(fd);
++    return fd;
++}
++#undef   creat
++#define  creat  ___xxx_creat
++
++static __inline__ int  adb_socket_accept(int  serverfd, struct sockaddr*  addr, socklen_t  *addrlen)
++{
++    int fd;
++
++    fd = TEMP_FAILURE_RETRY( accept( serverfd, addr, addrlen ) );
++    if (fd >= 0)
++        close_on_exec(fd);
++
++    return fd;
++}
++
++#undef   accept
++#define  accept  ___xxx_accept
++
++#define  unix_read   adb_read
++#define  unix_write  adb_write
++#define  unix_close  adb_close
++
++typedef  pthread_t                 adb_thread_t;
++
++typedef void*  (*adb_thread_func_t)( void*  arg );
++
++static __inline__ int  adb_thread_create( adb_thread_t  *pthread, adb_thread_func_t  start, void*  arg )
++{
++    pthread_attr_t   attr;
++
++    pthread_attr_init (&attr);
++    pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
++
++    return pthread_create( pthread, &attr, start, arg );
++}
++
++static __inline__  int  adb_socket_setbufsize( int   fd, int  bufsize )
++{
++    int opt = bufsize;
++    return setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
++}
++
++static __inline__ void  disable_tcp_nagle(int fd)
++{
++    int  on = 1;
++    setsockopt( fd, IPPROTO_TCP, TCP_NODELAY, (void*)&on, sizeof(on) );
++}
++
++
++static __inline__ int  unix_socketpair( int  d, int  type, int  protocol, int sv[2] )
++{
++    return socketpair( d, type, protocol, sv );
++}
++
++static __inline__ int  adb_socketpair( int  sv[2] )
++{
++    int  rc;
++
++    rc = unix_socketpair( AF_UNIX, SOCK_STREAM, 0, sv );
++    if (rc < 0)
++        return -1;
++
++    close_on_exec( sv[0] );
++    close_on_exec( sv[1] );
++    return 0;
++}
++
++#undef   socketpair
++#define  socketpair   ___xxx_socketpair
++
++static __inline__ void  adb_sleep_ms( int  mseconds )
++{
++    usleep( mseconds*1000 );
++}
++
++static __inline__ int  adb_mkdir(const char*  path, int mode)
++{
++    return mkdir(path, mode);
++}
++#undef   mkdir
++#define  mkdir  ___xxx_mkdir
++
++static __inline__ void  adb_sysdeps_init(void)
++{
++}
++
++static __inline__ char*  adb_dirstart(const char*  path)
++{
++    return strchr(path, '/');
++}
++
++static __inline__ char*  adb_dirstop(const char*  path)
++{
++    return strrchr(path, '/');
++}
++
++static __inline__  int  adb_is_absolute_host_path( const char*  path )
++{
++    return path[0] == '/';
++}
++
++static __inline__ char*  adb_strtok_r(char *str, const char *delim, char **saveptr)
++{
++    return strtok_r(str, delim, saveptr);
++}
++#undef   strtok_r
++#define  strtok_r  ___xxx_strtok_r
++
++#endif /* !_WIN32 */
++
++#endif /* _ADB_SYSDEPS_H */
+Index: android-tools-4.2.2+git20130218/core/adbd/sysdeps_win32.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/sysdeps_win32.c  2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,2220 @@
++#include "sysdeps.h"
++#include <windows.h>
++#include <winsock2.h>
++#include <stdio.h>
++#include <errno.h>
++#define  TRACE_TAG  TRACE_SYSDEPS
++#include "adb.h"
++
++extern void fatal(const char *fmt, ...);
++
++#define assert(cond)  do { if (!(cond)) fatal( "assertion failed '%s' on %s:%ld\n", #cond, __FILE__, __LINE__ ); } while (0)
++
++/**************************************************************************/
++/**************************************************************************/
++/*****                                                                *****/
++/*****      replaces libs/cutils/load_file.c                          *****/
++/*****                                                                *****/
++/**************************************************************************/
++/**************************************************************************/
++
++void *load_file(const char *fn, unsigned *_sz)
++{
++    HANDLE    file;
++    char     *data;
++    DWORD     file_size;
++
++    file = CreateFile( fn,
++                       GENERIC_READ,
++                       FILE_SHARE_READ,
++                       NULL,
++                       OPEN_EXISTING,
++                       0,
++                       NULL );
++
++    if (file == INVALID_HANDLE_VALUE)
++        return NULL;
++
++    file_size = GetFileSize( file, NULL );
++    data      = NULL;
++
++    if (file_size > 0) {
++        data = (char*) malloc( file_size + 1 );
++        if (data == NULL) {
++            D("load_file: could not allocate %ld bytes\n", file_size );
++            file_size = 0;
++        } else {
++            DWORD  out_bytes;
++
++            if ( !ReadFile( file, data, file_size, &out_bytes, NULL ) ||
++                 out_bytes != file_size )
++            {
++                D("load_file: could not read %ld bytes from '%s'\n", file_size, fn);
++                free(data);
++                data      = NULL;
++                file_size = 0;
++            }
++        }
++    }
++    CloseHandle( file );
++
++    *_sz = (unsigned) file_size;
++    return  data;
++}
++
++/**************************************************************************/
++/**************************************************************************/
++/*****                                                                *****/
++/*****    common file descriptor handling                             *****/
++/*****                                                                *****/
++/**************************************************************************/
++/**************************************************************************/
++
++typedef const struct FHClassRec_*   FHClass;
++
++typedef struct FHRec_*          FH;
++
++typedef struct EventHookRec_*  EventHook;
++
++typedef struct FHClassRec_
++{
++    void (*_fh_init) ( FH  f );
++    int  (*_fh_close)( FH  f );
++    int  (*_fh_lseek)( FH  f, int  pos, int  origin );
++    int  (*_fh_read) ( FH  f, void*  buf, int  len );
++    int  (*_fh_write)( FH  f, const void*  buf, int  len );
++    void (*_fh_hook) ( FH  f, int  events, EventHook  hook );
++
++} FHClassRec;
++
++/* used to emulate unix-domain socket pairs */
++typedef struct SocketPairRec_*  SocketPair;
++
++typedef struct FHRec_
++{
++    FHClass    clazz;
++    int        used;
++    int        eof;
++    union {
++        HANDLE      handle;
++        SOCKET      socket;
++        SocketPair  pair;
++    } u;
++
++    HANDLE    event;
++    int       mask;
++
++    char  name[32];
++
++} FHRec;
++
++#define  fh_handle  u.handle
++#define  fh_socket  u.socket
++#define  fh_pair    u.pair
++
++#define  WIN32_FH_BASE    100
++
++#define  WIN32_MAX_FHS    128
++
++static adb_mutex_t   _win32_lock;
++static  FHRec        _win32_fhs[ WIN32_MAX_FHS ];
++static  int          _win32_fh_count;
++
++static FH
++_fh_from_int( int   fd )
++{
++    FH  f;
++
++    fd -= WIN32_FH_BASE;
++
++    if (fd < 0 || fd >= _win32_fh_count) {
++        D( "_fh_from_int: invalid fd %d\n", fd + WIN32_FH_BASE );
++        errno = EBADF;
++        return NULL;
++    }
++
++    f = &_win32_fhs[fd];
++
++    if (f->used == 0) {
++        D( "_fh_from_int: invalid fd %d\n", fd + WIN32_FH_BASE );
++        errno = EBADF;
++        return NULL;
++    }
++
++    return f;
++}
++
++
++static int
++_fh_to_int( FH  f )
++{
++    if (f && f->used && f >= _win32_fhs && f < _win32_fhs + WIN32_MAX_FHS)
++        return (int)(f - _win32_fhs) + WIN32_FH_BASE;
++
++    return -1;
++}
++
++static FH
++_fh_alloc( FHClass  clazz )
++{
++    int  nn;
++    FH   f = NULL;
++
++    adb_mutex_lock( &_win32_lock );
++
++    if (_win32_fh_count < WIN32_MAX_FHS) {
++        f = &_win32_fhs[ _win32_fh_count++ ];
++        goto Exit;
++    }
++
++    for (nn = 0; nn < WIN32_MAX_FHS; nn++) {
++        if ( _win32_fhs[nn].clazz == NULL) {
++            f = &_win32_fhs[nn];
++            goto Exit;
++        }
++    }
++    D( "_fh_alloc: no more free file descriptors\n" );
++Exit:
++    if (f) {
++        f->clazz = clazz;
++        f->used  = 1;
++        f->eof   = 0;
++        clazz->_fh_init(f);
++    }
++    adb_mutex_unlock( &_win32_lock );
++    return f;
++}
++
++
++static int
++_fh_close( FH   f )
++{
++    if ( f->used ) {
++        f->clazz->_fh_close( f );
++        f->used = 0;
++        f->eof  = 0;
++        f->clazz = NULL;
++    }
++    return 0;
++}
++
++/* forward definitions */
++static const FHClassRec   _fh_file_class;
++static const FHClassRec   _fh_socket_class;
++
++/**************************************************************************/
++/**************************************************************************/
++/*****                                                                *****/
++/*****    file-based descriptor handling                              *****/
++/*****                                                                *****/
++/**************************************************************************/
++/**************************************************************************/
++
++static void
++_fh_file_init( FH  f )
++{
++    f->fh_handle = INVALID_HANDLE_VALUE;
++}
++
++static int
++_fh_file_close( FH  f )
++{
++    CloseHandle( f->fh_handle );
++    f->fh_handle = INVALID_HANDLE_VALUE;
++    return 0;
++}
++
++static int
++_fh_file_read( FH  f,  void*  buf, int   len )
++{
++    DWORD  read_bytes;
++
++    if ( !ReadFile( f->fh_handle, buf, (DWORD)len, &read_bytes, NULL ) ) {
++        D( "adb_read: could not read %d bytes from %s\n", len, f->name );
++        errno = EIO;
++        return -1;
++    } else if (read_bytes < (DWORD)len) {
++        f->eof = 1;
++    }
++    return (int)read_bytes;
++}
++
++static int
++_fh_file_write( FH  f,  const void*  buf, int   len )
++{
++    DWORD  wrote_bytes;
++
++    if ( !WriteFile( f->fh_handle, buf, (DWORD)len, &wrote_bytes, NULL ) ) {
++        D( "adb_file_write: could not write %d bytes from %s\n", len, f->name );
++        errno = EIO;
++        return -1;
++    } else if (wrote_bytes < (DWORD)len) {
++        f->eof = 1;
++    }
++    return  (int)wrote_bytes;
++}
++
++static int
++_fh_file_lseek( FH  f, int  pos, int  origin )
++{
++    DWORD  method;
++    DWORD  result;
++
++    switch (origin)
++    {
++        case SEEK_SET:  method = FILE_BEGIN; break;
++        case SEEK_CUR:  method = FILE_CURRENT; break;
++        case SEEK_END:  method = FILE_END; break;
++        default:
++            errno = EINVAL;
++            return -1;
++    }
++
++    result = SetFilePointer( f->fh_handle, pos, NULL, method );
++    if (result == INVALID_SET_FILE_POINTER) {
++        errno = EIO;
++        return -1;
++    } else {
++        f->eof = 0;
++    }
++    return (int)result;
++}
++
++static void  _fh_file_hook( FH  f, int  event, EventHook  eventhook );  /* forward */
++
++static const FHClassRec  _fh_file_class =
++{
++    _fh_file_init,
++    _fh_file_close,
++    _fh_file_lseek,
++    _fh_file_read,
++    _fh_file_write,
++    _fh_file_hook
++};
++
++/**************************************************************************/
++/**************************************************************************/
++/*****                                                                *****/
++/*****    file-based descriptor handling                              *****/
++/*****                                                                *****/
++/**************************************************************************/
++/**************************************************************************/
++
++int  adb_open(const char*  path, int  options)
++{
++    FH  f;
++
++    DWORD  desiredAccess       = 0;
++    DWORD  shareMode           = FILE_SHARE_READ | FILE_SHARE_WRITE;
++
++    switch (options) {
++        case O_RDONLY:
++            desiredAccess = GENERIC_READ;
++            break;
++        case O_WRONLY:
++            desiredAccess = GENERIC_WRITE;
++            break;
++        case O_RDWR:
++            desiredAccess = GENERIC_READ | GENERIC_WRITE;
++            break;
++        default:
++            D("adb_open: invalid options (0x%0x)\n", options);
++            errno = EINVAL;
++            return -1;
++    }
++
++    f = _fh_alloc( &_fh_file_class );
++    if ( !f ) {
++        errno = ENOMEM;
++        return -1;
++    }
++
++    f->fh_handle = CreateFile( path, desiredAccess, shareMode, NULL, OPEN_EXISTING,
++                               0, NULL );
++
++    if ( f->fh_handle == INVALID_HANDLE_VALUE ) {
++        _fh_close(f);
++        D( "adb_open: could not open '%s':", path );
++        switch (GetLastError()) {
++            case ERROR_FILE_NOT_FOUND:
++                D( "file not found\n" );
++                errno = ENOENT;
++                return -1;
++
++            case ERROR_PATH_NOT_FOUND:
++                D( "path not found\n" );
++                errno = ENOTDIR;
++                return -1;
++
++            default:
++                D( "unknown error\n" );
++                errno = ENOENT;
++                return -1;
++        }
++    }
++
++    snprintf( f->name, sizeof(f->name), "%d(%s)", _fh_to_int(f), path );
++    D( "adb_open: '%s' => fd %d\n", path, _fh_to_int(f) );
++    return _fh_to_int(f);
++}
++
++/* ignore mode on Win32 */
++int  adb_creat(const char*  path, int  mode)
++{
++    FH  f;
++
++    f = _fh_alloc( &_fh_file_class );
++    if ( !f ) {
++        errno = ENOMEM;
++        return -1;
++    }
++
++    f->fh_handle = CreateFile( path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
++                               NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
++                               NULL );
++
++    if ( f->fh_handle == INVALID_HANDLE_VALUE ) {
++        _fh_close(f);
++        D( "adb_creat: could not open '%s':", path );
++        switch (GetLastError()) {
++            case ERROR_FILE_NOT_FOUND:
++                D( "file not found\n" );
++                errno = ENOENT;
++                return -1;
++
++            case ERROR_PATH_NOT_FOUND:
++                D( "path not found\n" );
++                errno = ENOTDIR;
++                return -1;
++
++            default:
++                D( "unknown error\n" );
++                errno = ENOENT;
++                return -1;
++        }
++    }
++    snprintf( f->name, sizeof(f->name), "%d(%s)", _fh_to_int(f), path );
++    D( "adb_creat: '%s' => fd %d\n", path, _fh_to_int(f) );
++    return _fh_to_int(f);
++}
++
++
++int  adb_read(int  fd, void* buf, int len)
++{
++    FH     f = _fh_from_int(fd);
++
++    if (f == NULL) {
++        return -1;
++    }
++
++    return f->clazz->_fh_read( f, buf, len );
++}
++
++
++int  adb_write(int  fd, const void*  buf, int  len)
++{
++    FH     f = _fh_from_int(fd);
++
++    if (f == NULL) {
++        return -1;
++    }
++
++    return f->clazz->_fh_write(f, buf, len);
++}
++
++
++int  adb_lseek(int  fd, int  pos, int  where)
++{
++    FH     f = _fh_from_int(fd);
++
++    if (!f) {
++        return -1;
++    }
++
++    return f->clazz->_fh_lseek(f, pos, where);
++}
++
++
++int  adb_shutdown(int  fd)
++{
++    FH   f = _fh_from_int(fd);
++
++    if (!f) {
++        return -1;
++    }
++
++    D( "adb_shutdown: %s\n", f->name);
++    shutdown( f->fh_socket, SD_BOTH );
++    return 0;
++}
++
++
++int  adb_close(int  fd)
++{
++    FH   f = _fh_from_int(fd);
++
++    if (!f) {
++        return -1;
++    }
++
++    D( "adb_close: %s\n", f->name);
++    _fh_close(f);
++    return 0;
++}
++
++/**************************************************************************/
++/**************************************************************************/
++/*****                                                                *****/
++/*****    socket-based file descriptors                               *****/
++/*****                                                                *****/
++/**************************************************************************/
++/**************************************************************************/
++
++static void
++_socket_set_errno( void )
++{
++    switch (WSAGetLastError()) {
++    case 0:              errno = 0; break;
++    case WSAEWOULDBLOCK: errno = EAGAIN; break;
++    case WSAEINTR:       errno = EINTR; break;
++    default:
++        D( "_socket_set_errno: unhandled value %d\n", WSAGetLastError() );
++        errno = EINVAL;
++    }
++}
++
++static void
++_fh_socket_init( FH  f )
++{
++    f->fh_socket = INVALID_SOCKET;
++    f->event     = WSACreateEvent();
++    f->mask      = 0;
++}
++
++static int
++_fh_socket_close( FH  f )
++{
++    /* gently tell any peer that we're closing the socket */
++    shutdown( f->fh_socket, SD_BOTH );
++    closesocket( f->fh_socket );
++    f->fh_socket = INVALID_SOCKET;
++    CloseHandle( f->event );
++    f->mask = 0;
++    return 0;
++}
++
++static int
++_fh_socket_lseek( FH  f, int pos, int origin )
++{
++    errno = EPIPE;
++    return -1;
++}
++
++static int
++_fh_socket_read( FH  f, void*  buf, int  len )
++{
++    int  result = recv( f->fh_socket, buf, len, 0 );
++    if (result == SOCKET_ERROR) {
++        _socket_set_errno();
++        result = -1;
++    }
++    return  result;
++}
++
++static int
++_fh_socket_write( FH  f, const void*  buf, int  len )
++{
++    int  result = send( f->fh_socket, buf, len, 0 );
++    if (result == SOCKET_ERROR) {
++        _socket_set_errno();
++        result = -1;
++    }
++    return result;
++}
++
++static void  _fh_socket_hook( FH  f, int  event, EventHook  hook );  /* forward */
++
++static const FHClassRec  _fh_socket_class =
++{
++    _fh_socket_init,
++    _fh_socket_close,
++    _fh_socket_lseek,
++    _fh_socket_read,
++    _fh_socket_write,
++    _fh_socket_hook
++};
++
++/**************************************************************************/
++/**************************************************************************/
++/*****                                                                *****/
++/*****    replacement for libs/cutils/socket_xxxx.c                   *****/
++/*****                                                                *****/
++/**************************************************************************/
++/**************************************************************************/
++
++#include <winsock2.h>
++
++static int  _winsock_init;
++
++static void
++_cleanup_winsock( void )
++{
++    WSACleanup();
++}
++
++static void
++_init_winsock( void )
++{
++    if (!_winsock_init) {
++        WSADATA  wsaData;
++        int      rc = WSAStartup( MAKEWORD(2,2), &wsaData);
++        if (rc != 0) {
++            fatal( "adb: could not initialize Winsock\n" );
++        }
++        atexit( _cleanup_winsock );
++        _winsock_init = 1;
++    }
++}
++
++int socket_loopback_client(int port, int type)
++{
++    FH  f = _fh_alloc( &_fh_socket_class );
++    struct sockaddr_in addr;
++    SOCKET  s;
++
++    if (!f)
++        return -1;
++
++    if (!_winsock_init)
++        _init_winsock();
++
++    memset(&addr, 0, sizeof(addr));
++    addr.sin_family = AF_INET;
++    addr.sin_port = htons(port);
++    addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
++
++    s = socket(AF_INET, type, 0);
++    if(s == INVALID_SOCKET) {
++        D("socket_loopback_client: could not create socket\n" );
++        _fh_close(f);
++        return -1;
++    }
++
++    f->fh_socket = s;
++    if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
++        D("socket_loopback_client: could not connect to %s:%d\n", type != SOCK_STREAM ? "udp" : "tcp", port );
++        _fh_close(f);
++        return -1;
++    }
++    snprintf( f->name, sizeof(f->name), "%d(lo-client:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port );
++    D( "socket_loopback_client: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) );
++    return _fh_to_int(f);
++}
++
++#define LISTEN_BACKLOG 4
++
++int socket_loopback_server(int port, int type)
++{
++    FH   f = _fh_alloc( &_fh_socket_class );
++    struct sockaddr_in addr;
++    SOCKET  s;
++    int  n;
++
++    if (!f) {
++        return -1;
++    }
++
++    if (!_winsock_init)
++        _init_winsock();
++
++    memset(&addr, 0, sizeof(addr));
++    addr.sin_family = AF_INET;
++    addr.sin_port = htons(port);
++    addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
++
++    s = socket(AF_INET, type, 0);
++    if(s == INVALID_SOCKET) return -1;
++
++    f->fh_socket = s;
++
++    n = 1;
++    setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*)&n, sizeof(n));
++
++    if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
++        _fh_close(f);
++        return -1;
++    }
++    if (type == SOCK_STREAM) {
++        int ret;
++
++        ret = listen(s, LISTEN_BACKLOG);
++        if (ret < 0) {
++            _fh_close(f);
++            return -1;
++        }
++    }
++    snprintf( f->name, sizeof(f->name), "%d(lo-server:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port );
++    D( "socket_loopback_server: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) );
++    return _fh_to_int(f);
++}
++
++
++int socket_network_client(const char *host, int port, int type)
++{
++    FH  f = _fh_alloc( &_fh_socket_class );
++    struct hostent *hp;
++    struct sockaddr_in addr;
++    SOCKET s;
++
++    if (!f)
++        return -1;
++
++    if (!_winsock_init)
++        _init_winsock();
++
++    hp = gethostbyname(host);
++    if(hp == 0) {
++        _fh_close(f);
++        return -1;
++    }
++
++    memset(&addr, 0, sizeof(addr));
++    addr.sin_family = hp->h_addrtype;
++    addr.sin_port = htons(port);
++    memcpy(&addr.sin_addr, hp->h_addr, hp->h_length);
++
++    s = socket(hp->h_addrtype, type, 0);
++    if(s == INVALID_SOCKET) {
++        _fh_close(f);
++        return -1;
++    }
++    f->fh_socket = s;
++
++    if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
++        _fh_close(f);
++        return -1;
++    }
++
++    snprintf( f->name, sizeof(f->name), "%d(net-client:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port );
++    D( "socket_network_client: host '%s' port %d type %s => fd %d\n", host, port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) );
++    return _fh_to_int(f);
++}
++
++
++int socket_inaddr_any_server(int port, int type)
++{
++    FH  f = _fh_alloc( &_fh_socket_class );
++    struct sockaddr_in addr;
++    SOCKET  s;
++    int n;
++
++    if (!f)
++        return -1;
++
++    if (!_winsock_init)
++        _init_winsock();
++
++    memset(&addr, 0, sizeof(addr));
++    addr.sin_family = AF_INET;
++    addr.sin_port = htons(port);
++    addr.sin_addr.s_addr = htonl(INADDR_ANY);
++
++    s = socket(AF_INET, type, 0);
++    if(s == INVALID_SOCKET) {
++        _fh_close(f);
++        return -1;
++    }
++
++    f->fh_socket = s;
++    n = 1;
++    setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*)&n, sizeof(n));
++
++    if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
++        _fh_close(f);
++        return -1;
++    }
++
++    if (type == SOCK_STREAM) {
++        int ret;
++
++        ret = listen(s, LISTEN_BACKLOG);
++        if (ret < 0) {
++            _fh_close(f);
++            return -1;
++        }
++    }
++    snprintf( f->name, sizeof(f->name), "%d(any-server:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port );
++    D( "socket_inaddr_server: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) );
++    return _fh_to_int(f);
++}
++
++#undef accept
++int  adb_socket_accept(int  serverfd, struct sockaddr*  addr, socklen_t  *addrlen)
++{
++    FH   serverfh = _fh_from_int(serverfd);
++    FH   fh;
++
++    if ( !serverfh || serverfh->clazz != &_fh_socket_class ) {
++        D( "adb_socket_accept: invalid fd %d\n", serverfd );
++        return -1;
++    }
++
++    fh = _fh_alloc( &_fh_socket_class );
++    if (!fh) {
++        D( "adb_socket_accept: not enough memory to allocate accepted socket descriptor\n" );
++        return -1;
++    }
++
++    fh->fh_socket = accept( serverfh->fh_socket, addr, addrlen );
++    if (fh->fh_socket == INVALID_SOCKET) {
++        _fh_close( fh );
++        D( "adb_socket_accept: accept on fd %d return error %ld\n", serverfd, GetLastError() );
++        return -1;
++    }
++
++    snprintf( fh->name, sizeof(fh->name), "%d(accept:%s)", _fh_to_int(fh), serverfh->name );
++    D( "adb_socket_accept on fd %d returns fd %d\n", serverfd, _fh_to_int(fh) );
++    return  _fh_to_int(fh);
++}
++
++
++void  disable_tcp_nagle(int fd)
++{
++    FH   fh = _fh_from_int(fd);
++    int  on = 1;
++
++    if ( !fh || fh->clazz != &_fh_socket_class )
++        return;
++
++    setsockopt( fh->fh_socket, IPPROTO_TCP, TCP_NODELAY, (const char*)&on, sizeof(on) );
++}
++
++/**************************************************************************/
++/**************************************************************************/
++/*****                                                                *****/
++/*****    emulated socketpairs                                       *****/
++/*****                                                                *****/
++/**************************************************************************/
++/**************************************************************************/
++
++/* we implement socketpairs directly in use space for the following reasons:
++ *   - it avoids copying data from/to the Nt kernel
++ *   - it allows us to implement fdevent hooks easily and cheaply, something
++ *     that is not possible with standard Win32 pipes !!
++ *
++ * basically, we use two circular buffers, each one corresponding to a given
++ * direction.
++ *
++ * each buffer is implemented as two regions:
++ *
++ *   region A which is (a_start,a_end)
++ *   region B which is (0, b_end)  with b_end <= a_start
++ *
++ * an empty buffer has:  a_start = a_end = b_end = 0
++ *
++ * a_start is the pointer where we start reading data
++ * a_end is the pointer where we start writing data, unless it is BUFFER_SIZE,
++ * then you start writing at b_end
++ *
++ * the buffer is full when  b_end == a_start && a_end == BUFFER_SIZE
++ *
++ * there is room when b_end < a_start || a_end < BUFER_SIZE
++ *
++ * when reading, a_start is incremented, it a_start meets a_end, then
++ * we do:  a_start = 0, a_end = b_end, b_end = 0, and keep going on..
++ */
++
++#define  BIP_BUFFER_SIZE   4096
++
++#if 0
++#include <stdio.h>
++#  define  BIPD(x)      D x
++#  define  BIPDUMP   bip_dump_hex
++
++static void  bip_dump_hex( const unsigned char*  ptr, size_t  len )
++{
++    int  nn, len2 = len;
++
++    if (len2 > 8) len2 = 8;
++
++    for (nn = 0; nn < len2; nn++)
++        printf("%02x", ptr[nn]);
++    printf("  ");
++
++    for (nn = 0; nn < len2; nn++) {
++        int  c = ptr[nn];
++        if (c < 32 || c > 127)
++            c = '.';
++        printf("%c", c);
++    }
++    printf("\n");
++    fflush(stdout);
++}
++
++#else
++#  define  BIPD(x)        do {} while (0)
++#  define  BIPDUMP(p,l)   BIPD(p)
++#endif
++
++typedef struct BipBufferRec_
++{
++    int                a_start;
++    int                a_end;
++    int                b_end;
++    int                fdin;
++    int                fdout;
++    int                closed;
++    int                can_write;  /* boolean */
++    HANDLE             evt_write;  /* event signaled when one can write to a buffer  */
++    int                can_read;   /* boolean */
++    HANDLE             evt_read;   /* event signaled when one can read from a buffer */
++    CRITICAL_SECTION  lock;
++    unsigned char      buff[ BIP_BUFFER_SIZE ];
++
++} BipBufferRec, *BipBuffer;
++
++static void
++bip_buffer_init( BipBuffer  buffer )
++{
++    D( "bit_buffer_init %p\n", buffer );
++    buffer->a_start   = 0;
++    buffer->a_end     = 0;
++    buffer->b_end     = 0;
++    buffer->can_write = 1;
++    buffer->can_read  = 0;
++    buffer->fdin      = 0;
++    buffer->fdout     = 0;
++    buffer->closed    = 0;
++    buffer->evt_write = CreateEvent( NULL, TRUE, TRUE, NULL );
++    buffer->evt_read  = CreateEvent( NULL, TRUE, FALSE, NULL );
++    InitializeCriticalSection( &buffer->lock );
++}
++
++static void
++bip_buffer_close( BipBuffer  bip )
++{
++    bip->closed = 1;
++
++    if (!bip->can_read) {
++        SetEvent( bip->evt_read );
++    }
++    if (!bip->can_write) {
++        SetEvent( bip->evt_write );
++    }
++}
++
++static void
++bip_buffer_done( BipBuffer  bip )
++{
++    BIPD(( "bip_buffer_done: %d->%d\n", bip->fdin, bip->fdout ));
++    CloseHandle( bip->evt_read );
++    CloseHandle( bip->evt_write );
++    DeleteCriticalSection( &bip->lock );
++}
++
++static int
++bip_buffer_write( BipBuffer  bip, const void* src, int  len )
++{
++    int  avail, count = 0;
++
++    if (len <= 0)
++        return 0;
++
++    BIPD(( "bip_buffer_write: enter %d->%d len %d\n", bip->fdin, bip->fdout, len ));
++    BIPDUMP( src, len );
++
++    EnterCriticalSection( &bip->lock );
++
++    while (!bip->can_write) {
++        int  ret;
++        LeaveCriticalSection( &bip->lock );
++
++        if (bip->closed) {
++            errno = EPIPE;
++            return -1;
++        }
++        /* spinlocking here is probably unfair, but let's live with it */
++        ret = WaitForSingleObject( bip->evt_write, INFINITE );
++        if (ret != WAIT_OBJECT_0) {  /* buffer probably closed */
++            D( "bip_buffer_write: error %d->%d WaitForSingleObject returned %d, error %ld\n", bip->fdin, bip->fdout, ret, GetLastError() );
++            return 0;
++        }
++        if (bip->closed) {
++            errno = EPIPE;
++            return -1;
++        }
++        EnterCriticalSection( &bip->lock );
++    }
++
++    BIPD(( "bip_buffer_write: exec %d->%d len %d\n", bip->fdin, bip->fdout, len ));
++
++    avail = BIP_BUFFER_SIZE - bip->a_end;
++    if (avail > 0)
++    {
++        /* we can append to region A */
++        if (avail > len)
++            avail = len;
++
++        memcpy( bip->buff + bip->a_end, src, avail );
++        src   += avail;
++        count += avail;
++        len   -= avail;
++
++        bip->a_end += avail;
++        if (bip->a_end == BIP_BUFFER_SIZE && bip->a_start == 0) {
++            bip->can_write = 0;
++            ResetEvent( bip->evt_write );
++            goto Exit;
++        }
++    }
++
++    if (len == 0)
++        goto Exit;
++
++    avail = bip->a_start - bip->b_end;
++    assert( avail > 0 );  /* since can_write is TRUE */
++
++    if (avail > len)
++        avail = len;
++
++    memcpy( bip->buff + bip->b_end, src, avail );
++    count += avail;
++    bip->b_end += avail;
++
++    if (bip->b_end == bip->a_start) {
++        bip->can_write = 0;
++        ResetEvent( bip->evt_write );
++    }
++
++Exit:
++    assert( count > 0 );
++
++    if ( !bip->can_read ) {
++        bip->can_read = 1;
++        SetEvent( bip->evt_read );
++    }
++
++    BIPD(( "bip_buffer_write: exit %d->%d count %d (as=%d ae=%d be=%d cw=%d cr=%d\n",
++            bip->fdin, bip->fdout, count, bip->a_start, bip->a_end, bip->b_end, bip->can_write, bip->can_read ));
++    LeaveCriticalSection( &bip->lock );
++
++    return count;
++ }
++
++static int
++bip_buffer_read( BipBuffer  bip, void*  dst, int  len )
++{
++    int  avail, count = 0;
++
++    if (len <= 0)
++        return 0;
++
++    BIPD(( "bip_buffer_read: enter %d->%d len %d\n", bip->fdin, bip->fdout, len ));
++
++    EnterCriticalSection( &bip->lock );
++    while ( !bip->can_read )
++    {
++#if 0
++        LeaveCriticalSection( &bip->lock );
++        errno = EAGAIN;
++        return -1;
++#else
++        int  ret;
++        LeaveCriticalSection( &bip->lock );
++
++        if (bip->closed) {
++            errno = EPIPE;
++            return -1;
++        }
++
++        ret = WaitForSingleObject( bip->evt_read, INFINITE );
++        if (ret != WAIT_OBJECT_0) { /* probably closed buffer */
++            D( "bip_buffer_read: error %d->%d WaitForSingleObject returned %d, error %ld\n", bip->fdin, bip->fdout, ret, GetLastError());
++            return 0;
++        }
++        if (bip->closed) {
++            errno = EPIPE;
++            return -1;
++        }
++        EnterCriticalSection( &bip->lock );
++#endif
++    }
++
++    BIPD(( "bip_buffer_read: exec %d->%d len %d\n", bip->fdin, bip->fdout, len ));
++
++    avail = bip->a_end - bip->a_start;
++    assert( avail > 0 );  /* since can_read is TRUE */
++
++    if (avail > len)
++        avail = len;
++
++    memcpy( dst, bip->buff + bip->a_start, avail );
++    dst   += avail;
++    count += avail;
++    len   -= avail;
++
++    bip->a_start += avail;
++    if (bip->a_start < bip->a_end)
++        goto Exit;
++
++    bip->a_start = 0;
++    bip->a_end   = bip->b_end;
++    bip->b_end   = 0;
++
++    avail = bip->a_end;
++    if (avail > 0) {
++        if (avail > len)
++            avail = len;
++        memcpy( dst, bip->buff, avail );
++        count += avail;
++        bip->a_start += avail;
++
++        if ( bip->a_start < bip->a_end )
++            goto Exit;
++
++        bip->a_start = bip->a_end = 0;
++    }
++
++    bip->can_read = 0;
++    ResetEvent( bip->evt_read );
++
++Exit:
++    assert( count > 0 );
++
++    if (!bip->can_write ) {
++        bip->can_write = 1;
++        SetEvent( bip->evt_write );
++    }
++
++    BIPDUMP( (const unsigned char*)dst - count, count );
++    BIPD(( "bip_buffer_read: exit %d->%d count %d (as=%d ae=%d be=%d cw=%d cr=%d\n",
++            bip->fdin, bip->fdout, count, bip->a_start, bip->a_end, bip->b_end, bip->can_write, bip->can_read ));
++    LeaveCriticalSection( &bip->lock );
++
++    return count;
++}
++
++typedef struct SocketPairRec_
++{
++    BipBufferRec  a2b_bip;
++    BipBufferRec  b2a_bip;
++    FH            a_fd;
++    int           used;
++
++} SocketPairRec;
++
++void _fh_socketpair_init( FH  f )
++{
++    f->fh_pair = NULL;
++}
++
++static int
++_fh_socketpair_close( FH  f )
++{
++    if ( f->fh_pair ) {
++        SocketPair  pair = f->fh_pair;
++
++        if ( f == pair->a_fd ) {
++            pair->a_fd = NULL;
++        }
++
++        bip_buffer_close( &pair->b2a_bip );
++        bip_buffer_close( &pair->a2b_bip );
++
++        if ( --pair->used == 0 ) {
++            bip_buffer_done( &pair->b2a_bip );
++            bip_buffer_done( &pair->a2b_bip );
++            free( pair );
++        }
++        f->fh_pair = NULL;
++    }
++    return 0;
++}
++
++static int
++_fh_socketpair_lseek( FH  f, int pos, int  origin )
++{
++    errno = ESPIPE;
++    return -1;
++}
++
++static int
++_fh_socketpair_read( FH  f, void* buf, int  len )
++{
++    SocketPair  pair = f->fh_pair;
++    BipBuffer   bip;
++
++    if (!pair)
++        return -1;
++
++    if ( f == pair->a_fd )
++        bip = &pair->b2a_bip;
++    else
++        bip = &pair->a2b_bip;
++
++    return bip_buffer_read( bip, buf, len );
++}
++
++static int
++_fh_socketpair_write( FH  f, const void*  buf, int  len )
++{
++    SocketPair  pair = f->fh_pair;
++    BipBuffer   bip;
++
++    if (!pair)
++        return -1;
++
++    if ( f == pair->a_fd )
++        bip = &pair->a2b_bip;
++    else
++        bip = &pair->b2a_bip;
++
++    return bip_buffer_write( bip, buf, len );
++}
++
++
++static void  _fh_socketpair_hook( FH  f, int  event, EventHook  hook );  /* forward */
++
++static const FHClassRec  _fh_socketpair_class =
++{
++    _fh_socketpair_init,
++    _fh_socketpair_close,
++    _fh_socketpair_lseek,
++    _fh_socketpair_read,
++    _fh_socketpair_write,
++    _fh_socketpair_hook
++};
++
++
++int  adb_socketpair( int  sv[2] )
++{
++    FH          fa, fb;
++    SocketPair  pair;
++
++    fa = _fh_alloc( &_fh_socketpair_class );
++    fb = _fh_alloc( &_fh_socketpair_class );
++
++    if (!fa || !fb)
++        goto Fail;
++
++    pair = malloc( sizeof(*pair) );
++    if (pair == NULL) {
++        D("adb_socketpair: not enough memory to allocate pipes\n" );
++        goto Fail;
++    }
++
++    bip_buffer_init( &pair->a2b_bip );
++    bip_buffer_init( &pair->b2a_bip );
++
++    fa->fh_pair = pair;
++    fb->fh_pair = pair;
++    pair->used  = 2;
++    pair->a_fd  = fa;
++
++    sv[0] = _fh_to_int(fa);
++    sv[1] = _fh_to_int(fb);
++
++    pair->a2b_bip.fdin  = sv[0];
++    pair->a2b_bip.fdout = sv[1];
++    pair->b2a_bip.fdin  = sv[1];
++    pair->b2a_bip.fdout = sv[0];
++
++    snprintf( fa->name, sizeof(fa->name), "%d(pair:%d)", sv[0], sv[1] );
++    snprintf( fb->name, sizeof(fb->name), "%d(pair:%d)", sv[1], sv[0] );
++    D( "adb_socketpair: returns (%d, %d)\n", sv[0], sv[1] );
++    return 0;
++
++Fail:
++    _fh_close(fb);
++    _fh_close(fa);
++    return -1;
++}
++
++/**************************************************************************/
++/**************************************************************************/
++/*****                                                                *****/
++/*****    fdevents emulation                                          *****/
++/*****                                                                *****/
++/*****   this is a very simple implementation, we rely on the fact    *****/
++/*****   that ADB doesn't use FDE_ERROR.                              *****/
++/*****                                                                *****/
++/**************************************************************************/
++/**************************************************************************/
++
++#define FATAL(x...) fatal(__FUNCTION__, x)
++
++#if DEBUG
++static void dump_fde(fdevent *fde, const char *info)
++{
++    fprintf(stderr,"FDE #%03d %c%c%c %s\n", fde->fd,
++            fde->state & FDE_READ ? 'R' : ' ',
++            fde->state & FDE_WRITE ? 'W' : ' ',
++            fde->state & FDE_ERROR ? 'E' : ' ',
++            info);
++}
++#else
++#define dump_fde(fde, info) do { } while(0)
++#endif
++
++#define FDE_EVENTMASK  0x00ff
++#define FDE_STATEMASK  0xff00
++
++#define FDE_ACTIVE     0x0100
++#define FDE_PENDING    0x0200
++#define FDE_CREATED    0x0400
++
++static void fdevent_plist_enqueue(fdevent *node);
++static void fdevent_plist_remove(fdevent *node);
++static fdevent *fdevent_plist_dequeue(void);
++
++static fdevent list_pending = {
++    .next = &list_pending,
++    .prev = &list_pending,
++};
++
++static fdevent **fd_table = 0;
++static int       fd_table_max = 0;
++
++typedef struct EventLooperRec_*  EventLooper;
++
++typedef struct EventHookRec_
++{
++    EventHook    next;
++    FH           fh;
++    HANDLE       h;
++    int          wanted;   /* wanted event flags */
++    int          ready;    /* ready event flags  */
++    void*        aux;
++    void        (*prepare)( EventHook  hook );
++    int         (*start)  ( EventHook  hook );
++    void        (*stop)   ( EventHook  hook );
++    int         (*check)  ( EventHook  hook );
++    int         (*peek)   ( EventHook  hook );
++} EventHookRec;
++
++static EventHook  _free_hooks;
++
++static EventHook
++event_hook_alloc( FH  fh )
++{
++    EventHook  hook = _free_hooks;
++    if (hook != NULL)
++        _free_hooks = hook->next;
++    else {
++        hook = malloc( sizeof(*hook) );
++        if (hook == NULL)
++            fatal( "could not allocate event hook\n" );
++    }
++    hook->next   = NULL;
++    hook->fh     = fh;
++    hook->wanted = 0;
++    hook->ready  = 0;
++    hook->h      = INVALID_HANDLE_VALUE;
++    hook->aux    = NULL;
++
++    hook->prepare = NULL;
++    hook->start   = NULL;
++    hook->stop    = NULL;
++    hook->check   = NULL;
++    hook->peek    = NULL;
++
++    return hook;
++}
++
++static void
++event_hook_free( EventHook  hook )
++{
++    hook->fh     = NULL;
++    hook->wanted = 0;
++    hook->ready  = 0;
++    hook->next   = _free_hooks;
++    _free_hooks  = hook;
++}
++
++
++static void
++event_hook_signal( EventHook  hook )
++{
++    FH        f   = hook->fh;
++    int       fd  = _fh_to_int(f);
++    fdevent*  fde = fd_table[ fd - WIN32_FH_BASE ];
++
++    if (fde != NULL && fde->fd == fd) {
++        if ((fde->state & FDE_PENDING) == 0) {
++            fde->state |= FDE_PENDING;
++            fdevent_plist_enqueue( fde );
++        }
++        fde->events |= hook->wanted;
++    }
++}
++
++
++#define  MAX_LOOPER_HANDLES  WIN32_MAX_FHS
++
++typedef struct EventLooperRec_
++{
++    EventHook    hooks;
++    HANDLE       htab[ MAX_LOOPER_HANDLES ];
++    int          htab_count;
++
++} EventLooperRec;
++
++static EventHook*
++event_looper_find_p( EventLooper  looper, FH  fh )
++{
++    EventHook  *pnode = &looper->hooks;
++    EventHook   node  = *pnode;
++    for (;;) {
++        if ( node == NULL || node->fh == fh )
++            break;
++        pnode = &node->next;
++        node  = *pnode;
++    }
++    return  pnode;
++}
++
++static void
++event_looper_hook( EventLooper  looper, int  fd, int  events )
++{
++    FH          f = _fh_from_int(fd);
++    EventHook  *pnode;
++    EventHook   node;
++
++    if (f == NULL)  /* invalid arg */ {
++        D("event_looper_hook: invalid fd=%d\n", fd);
++        return;
++    }
++
++    pnode = event_looper_find_p( looper, f );
++    node  = *pnode;
++    if ( node == NULL ) {
++        node       = event_hook_alloc( f );
++        node->next = *pnode;
++        *pnode     = node;
++    }
++
++    if ( (node->wanted & events) != events ) {
++        /* this should update start/stop/check/peek */
++        D("event_looper_hook: call hook for %d (new=%x, old=%x)\n",
++           fd, node->wanted, events);
++        f->clazz->_fh_hook( f, events & ~node->wanted, node );
++        node->wanted |= events;
++    } else {
++        D("event_looper_hook: ignoring events %x for %d wanted=%x)\n",
++           events, fd, node->wanted);
++    }
++}
++
++static void
++event_looper_unhook( EventLooper  looper, int  fd, int  events )
++{
++    FH          fh    = _fh_from_int(fd);
++    EventHook  *pnode = event_looper_find_p( looper, fh );
++    EventHook   node  = *pnode;
++
++    if (node != NULL) {
++        int  events2 = events & node->wanted;
++        if ( events2 == 0 ) {
++            D( "event_looper_unhook: events %x not registered for fd %d\n", events, fd );
++            return;
++        }
++        node->wanted &= ~events2;
++        if (!node->wanted) {
++            *pnode = node->next;
++            event_hook_free( node );
++        }
++    }
++}
++
++/*
++ * A fixer for WaitForMultipleObjects on condition that there are more than 64
++ * handles to wait on.
++ *
++ * In cetain cases DDMS may establish more than 64 connections with ADB. For
++ * instance, this may happen if there are more than 64 processes running on a
++ * device, or there are multiple devices connected (including the emulator) with
++ * the combined number of running processes greater than 64. In this case using
++ * WaitForMultipleObjects to wait on connection events simply wouldn't cut,
++ * because of the API limitations (64 handles max). So, we need to provide a way
++ * to scale WaitForMultipleObjects to accept an arbitrary number of handles. The
++ * easiest (and "Microsoft recommended") way to do that would be dividing the
++ * handle array into chunks with the chunk size less than 64, and fire up as many
++ * waiting threads as there are chunks. Then each thread would wait on a chunk of
++ * handles, and will report back to the caller which handle has been set.
++ * Here is the implementation of that algorithm.
++ */
++
++/* Number of handles to wait on in each wating thread. */
++#define WAIT_ALL_CHUNK_SIZE 63
++
++/* Descriptor for a wating thread */
++typedef struct WaitForAllParam {
++    /* A handle to an event to signal when waiting is over. This handle is shared
++     * accross all the waiting threads, so each waiting thread knows when any
++     * other thread has exited, so it can exit too. */
++    HANDLE          main_event;
++    /* Upon exit from a waiting thread contains the index of the handle that has
++     * been signaled. The index is an absolute index of the signaled handle in
++     * the original array. This pointer is shared accross all the waiting threads
++     * and it's not guaranteed (due to a race condition) that when all the
++     * waiting threads exit, the value contained here would indicate the first
++     * handle that was signaled. This is fine, because the caller cares only
++     * about any handle being signaled. It doesn't care about the order, nor
++     * about the whole list of handles that were signaled. */
++    LONG volatile   *signaled_index;
++    /* Array of handles to wait on in a waiting thread. */
++    HANDLE*         handles;
++    /* Number of handles in 'handles' array to wait on. */
++    int             handles_count;
++    /* Index inside the main array of the first handle in the 'handles' array. */
++    int             first_handle_index;
++    /* Waiting thread handle. */
++    HANDLE          thread;
++} WaitForAllParam;
++
++/* Waiting thread routine. */
++static unsigned __stdcall
++_in_waiter_thread(void*  arg)
++{
++    HANDLE wait_on[WAIT_ALL_CHUNK_SIZE + 1];
++    int res;
++    WaitForAllParam* const param = (WaitForAllParam*)arg;
++
++    /* We have to wait on the main_event in order to be notified when any of the
++     * sibling threads is exiting. */
++    wait_on[0] = param->main_event;
++    /* The rest of the handles go behind the main event handle. */
++    memcpy(wait_on + 1, param->handles, param->handles_count * sizeof(HANDLE));
++
++    res = WaitForMultipleObjects(param->handles_count + 1, wait_on, FALSE, INFINITE);
++    if (res > 0 && res < (param->handles_count + 1)) {
++        /* One of the original handles got signaled. Save its absolute index into
++         * the output variable. */
++        InterlockedCompareExchange(param->signaled_index,
++                                   res - 1L + param->first_handle_index, -1L);
++    }
++
++    /* Notify the caller (and the siblings) that the wait is over. */
++    SetEvent(param->main_event);
++
++    _endthreadex(0);
++    return 0;
++}
++
++/* WaitForMultipeObjects fixer routine.
++ * Param:
++ *  handles Array of handles to wait on.
++ *  handles_count Number of handles in the array.
++ * Return:
++ *  (>= 0 && < handles_count) - Index of the signaled handle in the array, or
++ *  WAIT_FAILED on an error.
++ */
++static int
++_wait_for_all(HANDLE* handles, int handles_count)
++{
++    WaitForAllParam* threads;
++    HANDLE main_event;
++    int chunks, chunk, remains;
++
++    /* This variable is going to be accessed by several threads at the same time,
++     * this is bound to fail randomly when the core is run on multi-core machines.
++     * To solve this, we need to do the following (1 _and_ 2):
++     * 1. Use the "volatile" qualifier to ensure the compiler doesn't optimize
++     *    out the reads/writes in this function unexpectedly.
++     * 2. Ensure correct memory ordering. The "simple" way to do that is to wrap
++     *    all accesses inside a critical section. But we can also use
++     *    InterlockedCompareExchange() which always provide a full memory barrier
++     *    on Win32.
++     */
++    volatile LONG sig_index = -1;
++
++    /* Calculate number of chunks, and allocate thread param array. */
++    chunks = handles_count / WAIT_ALL_CHUNK_SIZE;
++    remains = handles_count % WAIT_ALL_CHUNK_SIZE;
++    threads = (WaitForAllParam*)malloc((chunks + (remains ? 1 : 0)) *
++                                        sizeof(WaitForAllParam));
++    if (threads == NULL) {
++        D("Unable to allocate thread array for %d handles.", handles_count);
++        return (int)WAIT_FAILED;
++    }
++
++    /* Create main event to wait on for all waiting threads. This is a "manualy
++     * reset" event that will remain set once it was set. */
++    main_event = CreateEvent(NULL, TRUE, FALSE, NULL);
++    if (main_event == NULL) {
++        D("Unable to create main event. Error: %d", GetLastError());
++        free(threads);
++        return (int)WAIT_FAILED;
++    }
++
++    /*
++     * Initialize waiting thread parameters.
++     */
++
++    for (chunk = 0; chunk < chunks; chunk++) {
++        threads[chunk].main_event = main_event;
++        threads[chunk].signaled_index = &sig_index;
++        threads[chunk].first_handle_index = WAIT_ALL_CHUNK_SIZE * chunk;
++        threads[chunk].handles = handles + threads[chunk].first_handle_index;
++        threads[chunk].handles_count = WAIT_ALL_CHUNK_SIZE;
++    }
++    if (remains) {
++        threads[chunk].main_event = main_event;
++        threads[chunk].signaled_index = &sig_index;
++        threads[chunk].first_handle_index = WAIT_ALL_CHUNK_SIZE * chunk;
++        threads[chunk].handles = handles + threads[chunk].first_handle_index;
++        threads[chunk].handles_count = remains;
++        chunks++;
++    }
++
++    /* Start the waiting threads. */
++    for (chunk = 0; chunk < chunks; chunk++) {
++        /* Note that using adb_thread_create is not appropriate here, since we
++         * need a handle to wait on for thread termination. */
++        threads[chunk].thread = (HANDLE)_beginthreadex(NULL, 0, _in_waiter_thread,
++                                                       &threads[chunk], 0, NULL);
++        if (threads[chunk].thread == NULL) {
++            /* Unable to create a waiter thread. Collapse. */
++            D("Unable to create a waiting thread %d of %d. errno=%d",
++              chunk, chunks, errno);
++            chunks = chunk;
++            SetEvent(main_event);
++            break;
++        }
++    }
++
++    /* Wait on any of the threads to get signaled. */
++    WaitForSingleObject(main_event, INFINITE);
++
++    /* Wait on all the waiting threads to exit. */
++    for (chunk = 0; chunk < chunks; chunk++) {
++        WaitForSingleObject(threads[chunk].thread, INFINITE);
++        CloseHandle(threads[chunk].thread);
++    }
++
++    CloseHandle(main_event);
++    free(threads);
++
++
++    const int ret = (int)InterlockedCompareExchange(&sig_index, -1, -1);
++    return (ret >= 0) ? ret : (int)WAIT_FAILED;
++}
++
++static EventLooperRec  win32_looper;
++
++static void fdevent_init(void)
++{
++    win32_looper.htab_count = 0;
++    win32_looper.hooks      = NULL;
++}
++
++static void fdevent_connect(fdevent *fde)
++{
++    EventLooper  looper = &win32_looper;
++    int          events = fde->state & FDE_EVENTMASK;
++
++    if (events != 0)
++        event_looper_hook( looper, fde->fd, events );
++}
++
++static void fdevent_disconnect(fdevent *fde)
++{
++    EventLooper  looper = &win32_looper;
++    int          events = fde->state & FDE_EVENTMASK;
++
++    if (events != 0)
++        event_looper_unhook( looper, fde->fd, events );
++}
++
++static void fdevent_update(fdevent *fde, unsigned events)
++{
++    EventLooper  looper  = &win32_looper;
++    unsigned     events0 = fde->state & FDE_EVENTMASK;
++
++    if (events != events0) {
++        int  removes = events0 & ~events;
++        int  adds    = events  & ~events0;
++        if (removes) {
++            D("fdevent_update: remove %x from %d\n", removes, fde->fd);
++            event_looper_unhook( looper, fde->fd, removes );
++        }
++        if (adds) {
++            D("fdevent_update: add %x to %d\n", adds, fde->fd);
++            event_looper_hook  ( looper, fde->fd, adds );
++        }
++    }
++}
++
++static void fdevent_process()
++{
++    EventLooper  looper = &win32_looper;
++    EventHook    hook;
++    int          gotone = 0;
++
++    /* if we have at least one ready hook, execute it/them */
++    for (hook = looper->hooks; hook; hook = hook->next) {
++        hook->ready = 0;
++        if (hook->prepare) {
++            hook->prepare(hook);
++            if (hook->ready != 0) {
++                event_hook_signal( hook );
++                gotone = 1;
++            }
++        }
++    }
++
++    /* nothing's ready yet, so wait for something to happen */
++    if (!gotone)
++    {
++        looper->htab_count = 0;
++
++        for (hook = looper->hooks; hook; hook = hook->next)
++        {
++            if (hook->start && !hook->start(hook)) {
++                D( "fdevent_process: error when starting a hook\n" );
++                return;
++            }
++            if (hook->h != INVALID_HANDLE_VALUE) {
++                int  nn;
++
++                for (nn = 0; nn < looper->htab_count; nn++)
++                {
++                    if ( looper->htab[nn] == hook->h )
++                        goto DontAdd;
++                }
++                looper->htab[ looper->htab_count++ ] = hook->h;
++            DontAdd:
++                ;
++            }
++        }
++
++        if (looper->htab_count == 0) {
++            D( "fdevent_process: nothing to wait for !!\n" );
++            return;
++        }
++
++        do
++        {
++            int   wait_ret;
++
++            D( "adb_win32: waiting for %d events\n", looper->htab_count );
++            if (looper->htab_count > MAXIMUM_WAIT_OBJECTS) {
++                D("handle count %d exceeds MAXIMUM_WAIT_OBJECTS.\n", looper->htab_count);
++                wait_ret = _wait_for_all(looper->htab, looper->htab_count);
++            } else {
++                wait_ret = WaitForMultipleObjects( looper->htab_count, looper->htab, FALSE, INFINITE );
++            }
++            if (wait_ret == (int)WAIT_FAILED) {
++                D( "adb_win32: wait failed, error %ld\n", GetLastError() );
++            } else {
++                D( "adb_win32: got one (index %d)\n", wait_ret );
++
++                /* according to Cygwin, some objects like consoles wake up on "inappropriate" events
++                 * like mouse movements. we need to filter these with the "check" function
++                 */
++                if ((unsigned)wait_ret < (unsigned)looper->htab_count)
++                {
++                    for (hook = looper->hooks; hook; hook = hook->next)
++                    {
++                        if ( looper->htab[wait_ret] == hook->h       &&
++                         (!hook->check || hook->check(hook)) )
++                        {
++                            D( "adb_win32: signaling %s for %x\n", hook->fh->name, hook->ready );
++                            event_hook_signal( hook );
++                            gotone = 1;
++                            break;
++                        }
++                    }
++                }
++            }
++        }
++        while (!gotone);
++
++        for (hook = looper->hooks; hook; hook = hook->next) {
++            if (hook->stop)
++                hook->stop( hook );
++        }
++    }
++
++    for (hook = looper->hooks; hook; hook = hook->next) {
++        if (hook->peek && hook->peek(hook))
++                event_hook_signal( hook );
++    }
++}
++
++
++static void fdevent_register(fdevent *fde)
++{
++    int  fd = fde->fd - WIN32_FH_BASE;
++
++    if(fd < 0) {
++        FATAL("bogus negative fd (%d)\n", fde->fd);
++    }
++
++    if(fd >= fd_table_max) {
++        int oldmax = fd_table_max;
++        if(fde->fd > 32000) {
++            FATAL("bogus huuuuge fd (%d)\n", fde->fd);
++        }
++        if(fd_table_max == 0) {
++            fdevent_init();
++            fd_table_max = 256;
++        }
++        while(fd_table_max <= fd) {
++            fd_table_max *= 2;
++        }
++        fd_table = realloc(fd_table, sizeof(fdevent*) * fd_table_max);
++        if(fd_table == 0) {
++            FATAL("could not expand fd_table to %d entries\n", fd_table_max);
++        }
++        memset(fd_table + oldmax, 0, sizeof(int) * (fd_table_max - oldmax));
++    }
++
++    fd_table[fd] = fde;
++}
++
++static void fdevent_unregister(fdevent *fde)
++{
++    int  fd = fde->fd - WIN32_FH_BASE;
++
++    if((fd < 0) || (fd >= fd_table_max)) {
++        FATAL("fd out of range (%d)\n", fde->fd);
++    }
++
++    if(fd_table[fd] != fde) {
++        FATAL("fd_table out of sync");
++    }
++
++    fd_table[fd] = 0;
++
++    if(!(fde->state & FDE_DONT_CLOSE)) {
++        dump_fde(fde, "close");
++        adb_close(fde->fd);
++    }
++}
++
++static void fdevent_plist_enqueue(fdevent *node)
++{
++    fdevent *list = &list_pending;
++
++    node->next = list;
++    node->prev = list->prev;
++    node->prev->next = node;
++    list->prev = node;
++}
++
++static void fdevent_plist_remove(fdevent *node)
++{
++    node->prev->next = node->next;
++    node->next->prev = node->prev;
++    node->next = 0;
++    node->prev = 0;
++}
++
++static fdevent *fdevent_plist_dequeue(void)
++{
++    fdevent *list = &list_pending;
++    fdevent *node = list->next;
++
++    if(node == list) return 0;
++
++    list->next = node->next;
++    list->next->prev = list;
++    node->next = 0;
++    node->prev = 0;
++
++    return node;
++}
++
++fdevent *fdevent_create(int fd, fd_func func, void *arg)
++{
++    fdevent *fde = (fdevent*) malloc(sizeof(fdevent));
++    if(fde == 0) return 0;
++    fdevent_install(fde, fd, func, arg);
++    fde->state |= FDE_CREATED;
++    return fde;
++}
++
++void fdevent_destroy(fdevent *fde)
++{
++    if(fde == 0) return;
++    if(!(fde->state & FDE_CREATED)) {
++        FATAL("fde %p not created by fdevent_create()\n", fde);
++    }
++    fdevent_remove(fde);
++}
++
++void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg)
++{
++    memset(fde, 0, sizeof(fdevent));
++    fde->state = FDE_ACTIVE;
++    fde->fd = fd;
++    fde->func = func;
++    fde->arg = arg;
++
++    fdevent_register(fde);
++    dump_fde(fde, "connect");
++    fdevent_connect(fde);
++    fde->state |= FDE_ACTIVE;
++}
++
++void fdevent_remove(fdevent *fde)
++{
++    if(fde->state & FDE_PENDING) {
++        fdevent_plist_remove(fde);
++    }
++
++    if(fde->state & FDE_ACTIVE) {
++        fdevent_disconnect(fde);
++        dump_fde(fde, "disconnect");
++        fdevent_unregister(fde);
++    }
++
++    fde->state = 0;
++    fde->events = 0;
++}
++
++
++void fdevent_set(fdevent *fde, unsigned events)
++{
++    events &= FDE_EVENTMASK;
++
++    if((fde->state & FDE_EVENTMASK) == (int)events) return;
++
++    if(fde->state & FDE_ACTIVE) {
++        fdevent_update(fde, events);
++        dump_fde(fde, "update");
++    }
++
++    fde->state = (fde->state & FDE_STATEMASK) | events;
++
++    if(fde->state & FDE_PENDING) {
++            /* if we're pending, make sure
++            ** we don't signal an event that
++            ** is no longer wanted.
++            */
++        fde->events &= (~events);
++        if(fde->events == 0) {
++            fdevent_plist_remove(fde);
++            fde->state &= (~FDE_PENDING);
++        }
++    }
++}
++
++void fdevent_add(fdevent *fde, unsigned events)
++{
++    fdevent_set(
++        fde, (fde->state & FDE_EVENTMASK) | (events & FDE_EVENTMASK));
++}
++
++void fdevent_del(fdevent *fde, unsigned events)
++{
++    fdevent_set(
++        fde, (fde->state & FDE_EVENTMASK) & (~(events & FDE_EVENTMASK)));
++}
++
++void fdevent_loop()
++{
++    fdevent *fde;
++
++    for(;;) {
++#if DEBUG
++        fprintf(stderr,"--- ---- waiting for events\n");
++#endif
++        fdevent_process();
++
++        while((fde = fdevent_plist_dequeue())) {
++            unsigned events = fde->events;
++            fde->events = 0;
++            fde->state &= (~FDE_PENDING);
++            dump_fde(fde, "callback");
++            fde->func(fde->fd, events, fde->arg);
++        }
++    }
++}
++
++/**  FILE EVENT HOOKS
++ **/
++
++static void  _event_file_prepare( EventHook  hook )
++{
++    if (hook->wanted & (FDE_READ|FDE_WRITE)) {
++        /* we can always read/write */
++        hook->ready |= hook->wanted & (FDE_READ|FDE_WRITE);
++    }
++}
++
++static int  _event_file_peek( EventHook  hook )
++{
++    return (hook->wanted & (FDE_READ|FDE_WRITE));
++}
++
++static void  _fh_file_hook( FH  f, int  events, EventHook  hook )
++{
++    hook->h       = f->fh_handle;
++    hook->prepare = _event_file_prepare;
++    hook->peek    = _event_file_peek;
++}
++
++/** SOCKET EVENT HOOKS
++ **/
++
++static void  _event_socket_verify( EventHook  hook, WSANETWORKEVENTS*  evts )
++{
++    if ( evts->lNetworkEvents & (FD_READ|FD_ACCEPT|FD_CLOSE) ) {
++        if (hook->wanted & FDE_READ)
++            hook->ready |= FDE_READ;
++        if ((evts->iErrorCode[FD_READ] != 0) && hook->wanted & FDE_ERROR)
++            hook->ready |= FDE_ERROR;
++    }
++    if ( evts->lNetworkEvents & (FD_WRITE|FD_CONNECT|FD_CLOSE) ) {
++        if (hook->wanted & FDE_WRITE)
++            hook->ready |= FDE_WRITE;
++        if ((evts->iErrorCode[FD_WRITE] != 0) && hook->wanted & FDE_ERROR)
++            hook->ready |= FDE_ERROR;
++    }
++    if ( evts->lNetworkEvents & FD_OOB ) {
++        if (hook->wanted & FDE_ERROR)
++            hook->ready |= FDE_ERROR;
++    }
++}
++
++static void  _event_socket_prepare( EventHook  hook )
++{
++    WSANETWORKEVENTS  evts;
++
++    /* look if some of the events we want already happened ? */
++    if (!WSAEnumNetworkEvents( hook->fh->fh_socket, NULL, &evts ))
++        _event_socket_verify( hook, &evts );
++}
++
++static int  _socket_wanted_to_flags( int  wanted )
++{
++    int  flags = 0;
++    if (wanted & FDE_READ)
++        flags |= FD_READ | FD_ACCEPT | FD_CLOSE;
++
++    if (wanted & FDE_WRITE)
++        flags |= FD_WRITE | FD_CONNECT | FD_CLOSE;
++
++    if (wanted & FDE_ERROR)
++        flags |= FD_OOB;
++
++    return flags;
++}
++
++static int _event_socket_start( EventHook  hook )
++{
++    /* create an event which we're going to wait for */
++    FH    fh    = hook->fh;
++    long  flags = _socket_wanted_to_flags( hook->wanted );
++
++    hook->h = fh->event;
++    if (hook->h == INVALID_HANDLE_VALUE) {
++        D( "_event_socket_start: no event for %s\n", fh->name );
++        return 0;
++    }
++
++    if ( flags != fh->mask ) {
++        D( "_event_socket_start: hooking %s for %x (flags %ld)\n", hook->fh->name, hook->wanted, flags );
++        if ( WSAEventSelect( fh->fh_socket, hook->h, flags ) ) {
++            D( "_event_socket_start: WSAEventSelect() for %s failed, error %d\n", hook->fh->name, WSAGetLastError() );
++            CloseHandle( hook->h );
++            hook->h = INVALID_HANDLE_VALUE;
++            exit(1);
++            return 0;
++        }
++        fh->mask = flags;
++    }
++    return 1;
++}
++
++static void _event_socket_stop( EventHook  hook )
++{
++    hook->h = INVALID_HANDLE_VALUE;
++}
++
++static int  _event_socket_check( EventHook  hook )
++{
++    int               result = 0;
++    FH                fh = hook->fh;
++    WSANETWORKEVENTS  evts;
++
++    if (!WSAEnumNetworkEvents( fh->fh_socket, hook->h, &evts ) ) {
++        _event_socket_verify( hook, &evts );
++        result = (hook->ready != 0);
++        if (result) {
++            ResetEvent( hook->h );
++        }
++    }
++    D( "_event_socket_check %s returns %d\n", fh->name, result );
++    return  result;
++}
++
++static int  _event_socket_peek( EventHook  hook )
++{
++    WSANETWORKEVENTS  evts;
++    FH                fh = hook->fh;
++
++    /* look if some of the events we want already happened ? */
++    if (!WSAEnumNetworkEvents( fh->fh_socket, NULL, &evts )) {
++        _event_socket_verify( hook, &evts );
++        if (hook->ready)
++            ResetEvent( hook->h );
++    }
++
++    return hook->ready != 0;
++}
++
++
++
++static void  _fh_socket_hook( FH  f, int  events, EventHook  hook )
++{
++    hook->prepare = _event_socket_prepare;
++    hook->start   = _event_socket_start;
++    hook->stop    = _event_socket_stop;
++    hook->check   = _event_socket_check;
++    hook->peek    = _event_socket_peek;
++
++    _event_socket_start( hook );
++}
++
++/** SOCKETPAIR EVENT HOOKS
++ **/
++
++static void  _event_socketpair_prepare( EventHook  hook )
++{
++    FH          fh   = hook->fh;
++    SocketPair  pair = fh->fh_pair;
++    BipBuffer   rbip = (pair->a_fd == fh) ? &pair->b2a_bip : &pair->a2b_bip;
++    BipBuffer   wbip = (pair->a_fd == fh) ? &pair->a2b_bip : &pair->b2a_bip;
++
++    if (hook->wanted & FDE_READ && rbip->can_read)
++        hook->ready |= FDE_READ;
++
++    if (hook->wanted & FDE_WRITE && wbip->can_write)
++        hook->ready |= FDE_WRITE;
++ }
++
++ static int  _event_socketpair_start( EventHook  hook )
++ {
++    FH          fh   = hook->fh;
++    SocketPair  pair = fh->fh_pair;
++    BipBuffer   rbip = (pair->a_fd == fh) ? &pair->b2a_bip : &pair->a2b_bip;
++    BipBuffer   wbip = (pair->a_fd == fh) ? &pair->a2b_bip : &pair->b2a_bip;
++
++    if (hook->wanted == FDE_READ)
++        hook->h = rbip->evt_read;
++
++    else if (hook->wanted == FDE_WRITE)
++        hook->h = wbip->evt_write;
++
++    else {
++        D("_event_socketpair_start: can't handle FDE_READ+FDE_WRITE\n" );
++        return 0;
++    }
++    D( "_event_socketpair_start: hook %s for %x wanted=%x\n",
++       hook->fh->name, _fh_to_int(fh), hook->wanted);
++    return 1;
++}
++
++static int  _event_socketpair_peek( EventHook  hook )
++{
++    _event_socketpair_prepare( hook );
++    return hook->ready != 0;
++}
++
++static void  _fh_socketpair_hook( FH  fh, int  events, EventHook  hook )
++{
++    hook->prepare = _event_socketpair_prepare;
++    hook->start   = _event_socketpair_start;
++    hook->peek    = _event_socketpair_peek;
++}
++
++
++void
++adb_sysdeps_init( void )
++{
++#define  ADB_MUTEX(x)  InitializeCriticalSection( & x );
++#include "mutex_list.h"
++    InitializeCriticalSection( &_win32_lock );
++}
++
++/* Windows doesn't have strtok_r.  Use the one from bionic. */
++
++/*
++ * Copyright (c) 1988 Regents of the University of California.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. Neither the name of the University nor the names of its contributors
++ *    may be used to endorse or promote products derived from this software
++ *    without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ */
++
++char *
++adb_strtok_r(char *s, const char *delim, char **last)
++{
++      char *spanp;
++      int c, sc;
++      char *tok;
++
++
++      if (s == NULL && (s = *last) == NULL)
++              return (NULL);
++
++      /*
++       * Skip (span) leading delimiters (s += strspn(s, delim), sort of).
++       */
++cont:
++      c = *s++;
++      for (spanp = (char *)delim; (sc = *spanp++) != 0;) {
++              if (c == sc)
++                      goto cont;
++      }
++
++      if (c == 0) {           /* no non-delimiter characters */
++              *last = NULL;
++              return (NULL);
++      }
++      tok = s - 1;
++
++      /*
++       * Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
++       * Note that delim must have one NUL; we stop if we see that, too.
++       */
++      for (;;) {
++              c = *s++;
++              spanp = (char *)delim;
++              do {
++                      if ((sc = *spanp++) == c) {
++                              if (c == 0)
++                                      s = NULL;
++                              else
++                                      s[-1] = 0;
++                              *last = s;
++                              return (tok);
++                      }
++              } while (sc != 0);
++      }
++      /* NOTREACHED */
++}
+Index: android-tools-4.2.2+git20130218/core/adbd/test_track_devices.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/test_track_devices.c     2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,97 @@
++/* a simple test program, connects to ADB server, and opens a track-devices session */
++#include <netdb.h>
++#include <sys/socket.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <errno.h>
++#include <memory.h>
++
++static void
++panic( const char*  msg )
++{
++    fprintf(stderr, "PANIC: %s: %s\n", msg, strerror(errno));
++    exit(1);
++}
++
++static int
++unix_write( int  fd, const char*  buf, int  len )
++{
++    int  result = 0;
++    while (len > 0) {
++        int  len2 = write(fd, buf, len);
++        if (len2 < 0) {
++            if (errno == EINTR || errno == EAGAIN)
++                continue;
++            return -1;
++        }
++        result += len2;
++        len -= len2;
++        buf += len2;
++    }
++    return  result;
++}
++
++static int
++unix_read( int  fd, char*  buf, int  len )
++{
++    int  result = 0;
++    while (len > 0) {
++        int  len2 = read(fd, buf, len);
++        if (len2 < 0) {
++            if (errno == EINTR || errno == EAGAIN)
++                continue;
++            return -1;
++        }
++        result += len2;
++        len -= len2;
++        buf += len2;
++    }
++    return  result;
++}
++
++
++int  main( void )
++{
++    int                  ret, s;
++    struct sockaddr_in   server;
++    char                 buffer[1024];
++    const char*          request = "host:track-devices";
++    int                  len;
++
++    memset( &server, 0, sizeof(server) );
++    server.sin_family      = AF_INET;
++    server.sin_port        = htons(5037);
++    server.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
++
++    s = socket( PF_INET, SOCK_STREAM, 0 );
++    ret = connect( s, (struct sockaddr*) &server, sizeof(server) );
++    if (ret < 0) panic( "could not connect to server" );
++
++    /* send the request */
++    len = snprintf( buffer, sizeof buffer, "%04x%s", strlen(request), request );
++    if (unix_write(s, buffer, len) < 0)
++        panic( "could not send request" );
++
++    /* read the OKAY answer */
++    if (unix_read(s, buffer, 4) != 4)
++        panic( "could not read request" );
++
++    printf( "server answer: %.*s\n", 4, buffer );
++
++    /* now loop */
++    for (;;) {
++        char  head[5] = "0000";
++
++        if (unix_read(s, head, 4) < 0)
++            panic("could not read length");
++
++        if ( sscanf( head, "%04x", &len ) != 1 )
++            panic("could not decode length");
++
++        if (unix_read(s, buffer, len) != len)
++            panic("could not read data");
++
++        printf( "received header %.*s (%d bytes):\n%.*s", 4, head, len, len, buffer );
++    }
++    close(s);
++}
+Index: android-tools-4.2.2+git20130218/core/adbd/test_track_jdwp.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/test_track_jdwp.c        2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,97 @@
++/* a simple test program, connects to ADB server, and opens a track-devices session */
++#include <netdb.h>
++#include <sys/socket.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <errno.h>
++#include <memory.h>
++
++static void
++panic( const char*  msg )
++{
++    fprintf(stderr, "PANIC: %s: %s\n", msg, strerror(errno));
++    exit(1);
++}
++
++static int
++unix_write( int  fd, const char*  buf, int  len )
++{
++    int  result = 0;
++    while (len > 0) {
++        int  len2 = write(fd, buf, len);
++        if (len2 < 0) {
++            if (errno == EINTR || errno == EAGAIN)
++                continue;
++            return -1;
++        }
++        result += len2;
++        len -= len2;
++        buf += len2;
++    }
++    return  result;
++}
++
++static int
++unix_read( int  fd, char*  buf, int  len )
++{
++    int  result = 0;
++    while (len > 0) {
++        int  len2 = read(fd, buf, len);
++        if (len2 < 0) {
++            if (errno == EINTR || errno == EAGAIN)
++                continue;
++            return -1;
++        }
++        result += len2;
++        len -= len2;
++        buf += len2;
++    }
++    return  result;
++}
++
++
++int  main( void )
++{
++    int                  ret, s;
++    struct sockaddr_in   server;
++    char                 buffer[1024];
++    const char*          request = "track-jdwp";
++    int                  len;
++
++    memset( &server, 0, sizeof(server) );
++    server.sin_family      = AF_INET;
++    server.sin_port        = htons(5037);
++    server.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
++
++    s = socket( PF_INET, SOCK_STREAM, 0 );
++    ret = connect( s, (struct sockaddr*) &server, sizeof(server) );
++    if (ret < 0) panic( "could not connect to server" );
++
++    /* send the request */
++    len = snprintf( buffer, sizeof buffer, "%04x%s", strlen(request), request );
++    if (unix_write(s, buffer, len) < 0)
++        panic( "could not send request" );
++
++    /* read the OKAY answer */
++    if (unix_read(s, buffer, 4) != 4)
++        panic( "could not read request" );
++
++    printf( "server answer: %.*s\n", 4, buffer );
++
++    /* now loop */
++    for (;;) {
++        char  head[5] = "0000";
++
++        if (unix_read(s, head, 4) < 0)
++            panic("could not read length");
++
++        if ( sscanf( head, "%04x", &len ) != 1 )
++            panic("could not decode length");
++
++        if (unix_read(s, buffer, len) != len)
++            panic("could not read data");
++
++        printf( "received header %.*s (%d bytes):\n%.*s", 4, head, len, len, buffer );
++    }
++    close(s);
++}
+Index: android-tools-4.2.2+git20130218/core/adbd/transport.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/transport.c      2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,1186 @@
++/*
++ * Copyright (C) 2007 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include <errno.h>
++
++#include "sysdeps.h"
++
++#define   TRACE_TAG  TRACE_TRANSPORT
++#include "adb.h"
++
++static void transport_unref(atransport *t);
++
++static atransport transport_list = {
++    .next = &transport_list,
++    .prev = &transport_list,
++};
++
++ADB_MUTEX_DEFINE( transport_lock );
++
++#if ADB_TRACE
++#define MAX_DUMP_HEX_LEN 16
++static void  dump_hex( const unsigned char*  ptr, size_t  len )
++{
++    int  nn, len2 = len;
++    // Build a string instead of logging each character.
++    // MAX chars in 2 digit hex, one space, MAX chars, one '\0'.
++    char buffer[MAX_DUMP_HEX_LEN *2 + 1 + MAX_DUMP_HEX_LEN + 1 ], *pb = buffer;
++
++    if (len2 > MAX_DUMP_HEX_LEN) len2 = MAX_DUMP_HEX_LEN;
++
++    for (nn = 0; nn < len2; nn++) {
++        sprintf(pb, "%02x", ptr[nn]);
++        pb += 2;
++    }
++    sprintf(pb++, " ");
++
++    for (nn = 0; nn < len2; nn++) {
++        int  c = ptr[nn];
++        if (c < 32 || c > 127)
++            c = '.';
++        *pb++ =  c;
++    }
++    *pb++ = '\0';
++    DR("%s\n", buffer);
++}
++#endif
++
++void
++kick_transport(atransport*  t)
++{
++    if (t && !t->kicked)
++    {
++        int  kicked;
++
++        adb_mutex_lock(&transport_lock);
++        kicked = t->kicked;
++        if (!kicked)
++            t->kicked = 1;
++        adb_mutex_unlock(&transport_lock);
++
++        if (!kicked)
++            t->kick(t);
++    }
++}
++
++void
++run_transport_disconnects(atransport*  t)
++{
++    adisconnect*  dis = t->disconnects.next;
++
++    D("%s: run_transport_disconnects\n", t->serial);
++    while (dis != &t->disconnects) {
++        adisconnect*  next = dis->next;
++        dis->func( dis->opaque, t );
++        dis = next;
++    }
++}
++
++#if ADB_TRACE
++static void
++dump_packet(const char* name, const char* func, apacket* p)
++{
++    unsigned  command = p->msg.command;
++    int       len     = p->msg.data_length;
++    char      cmd[9];
++    char      arg0[12], arg1[12];
++    int       n;
++
++    for (n = 0; n < 4; n++) {
++        int  b = (command >> (n*8)) & 255;
++        if (b < 32 || b >= 127)
++            break;
++        cmd[n] = (char)b;
++    }
++    if (n == 4) {
++        cmd[4] = 0;
++    } else {
++        /* There is some non-ASCII name in the command, so dump
++            * the hexadecimal value instead */
++        snprintf(cmd, sizeof cmd, "%08x", command);
++    }
++
++    if (p->msg.arg0 < 256U)
++        snprintf(arg0, sizeof arg0, "%d", p->msg.arg0);
++    else
++        snprintf(arg0, sizeof arg0, "0x%x", p->msg.arg0);
++
++    if (p->msg.arg1 < 256U)
++        snprintf(arg1, sizeof arg1, "%d", p->msg.arg1);
++    else
++        snprintf(arg1, sizeof arg1, "0x%x", p->msg.arg1);
++
++    D("%s: %s: [%s] arg0=%s arg1=%s (len=%d) ",
++        name, func, cmd, arg0, arg1, len);
++    dump_hex(p->data, len);
++}
++#endif /* ADB_TRACE */
++
++static int
++read_packet(int  fd, const char* name, apacket** ppacket)
++{
++    char *p = (char*)ppacket;  /* really read a packet address */
++    int   r;
++    int   len = sizeof(*ppacket);
++    char  buff[8];
++    if (!name) {
++        snprintf(buff, sizeof buff, "fd=%d", fd);
++        name = buff;
++    }
++    while(len > 0) {
++        r = adb_read(fd, p, len);
++        if(r > 0) {
++            len -= r;
++            p   += r;
++        } else {
++            D("%s: read_packet (fd=%d), error ret=%d errno=%d: %s\n", name, fd, r, errno, strerror(errno));
++            if((r < 0) && (errno == EINTR)) continue;
++            return -1;
++        }
++    }
++
++#if ADB_TRACE
++    if (ADB_TRACING) {
++        dump_packet(name, "from remote", *ppacket);
++    }
++#endif
++    return 0;
++}
++
++static int
++write_packet(int  fd, const char* name, apacket** ppacket)
++{
++    char *p = (char*) ppacket;  /* we really write the packet address */
++    int r, len = sizeof(ppacket);
++    char buff[8];
++    if (!name) {
++        snprintf(buff, sizeof buff, "fd=%d", fd);
++        name = buff;
++    }
++
++#if ADB_TRACE
++    if (ADB_TRACING) {
++        dump_packet(name, "to remote", *ppacket);
++    }
++#endif
++    len = sizeof(ppacket);
++    while(len > 0) {
++        r = adb_write(fd, p, len);
++        if(r > 0) {
++            len -= r;
++            p += r;
++        } else {
++            D("%s: write_packet (fd=%d) error ret=%d errno=%d: %s\n", name, fd, r, errno, strerror(errno));
++            if((r < 0) && (errno == EINTR)) continue;
++            return -1;
++        }
++    }
++    return 0;
++}
++
++static void transport_socket_events(int fd, unsigned events, void *_t)
++{
++    atransport *t = _t;
++    D("transport_socket_events(fd=%d, events=%04x,...)\n", fd, events);
++    if(events & FDE_READ){
++        apacket *p = 0;
++        if(read_packet(fd, t->serial, &p)){
++            D("%s: failed to read packet from transport socket on fd %d\n", t->serial, fd);
++        } else {
++            handle_packet(p, (atransport *) _t);
++        }
++    }
++}
++
++void send_packet(apacket *p, atransport *t)
++{
++    unsigned char *x;
++    unsigned sum;
++    unsigned count;
++
++    p->msg.magic = p->msg.command ^ 0xffffffff;
++
++    count = p->msg.data_length;
++    x = (unsigned char *) p->data;
++    sum = 0;
++    while(count-- > 0){
++        sum += *x++;
++    }
++    p->msg.data_check = sum;
++
++    print_packet("send", p);
++
++    if (t == NULL) {
++        D("Transport is null \n");
++        // Zap errno because print_packet() and other stuff have errno effect.
++        errno = 0;
++        fatal_errno("Transport is null");
++    }
++
++    if(write_packet(t->transport_socket, t->serial, &p)){
++        fatal_errno("cannot enqueue packet on transport socket");
++    }
++}
++
++/* The transport is opened by transport_register_func before
++** the input and output threads are started.
++**
++** The output thread issues a SYNC(1, token) message to let
++** the input thread know to start things up.  In the event
++** of transport IO failure, the output thread will post a
++** SYNC(0,0) message to ensure shutdown.
++**
++** The transport will not actually be closed until both
++** threads exit, but the input thread will kick the transport
++** on its way out to disconnect the underlying device.
++*/
++
++static void *output_thread(void *_t)
++{
++    atransport *t = _t;
++    apacket *p;
++
++    D("%s: starting transport output thread on fd %d, SYNC online (%d)\n",
++       t->serial, t->fd, t->sync_token + 1);
++    p = get_apacket();
++    p->msg.command = A_SYNC;
++    p->msg.arg0 = 1;
++    p->msg.arg1 = ++(t->sync_token);
++    p->msg.magic = A_SYNC ^ 0xffffffff;
++    if(write_packet(t->fd, t->serial, &p)) {
++        put_apacket(p);
++        D("%s: failed to write SYNC packet\n", t->serial);
++        goto oops;
++    }
++
++    D("%s: data pump started\n", t->serial);
++    for(;;) {
++        p = get_apacket();
++
++        if(t->read_from_remote(p, t) == 0){
++            D("%s: received remote packet, sending to transport\n",
++              t->serial);
++            if(write_packet(t->fd, t->serial, &p)){
++                put_apacket(p);
++                D("%s: failed to write apacket to transport\n", t->serial);
++                goto oops;
++            }
++        } else {
++            D("%s: remote read failed for transport\n", t->serial);
++            put_apacket(p);
++            break;
++        }
++    }
++
++    D("%s: SYNC offline for transport\n", t->serial);
++    p = get_apacket();
++    p->msg.command = A_SYNC;
++    p->msg.arg0 = 0;
++    p->msg.arg1 = 0;
++    p->msg.magic = A_SYNC ^ 0xffffffff;
++    if(write_packet(t->fd, t->serial, &p)) {
++        put_apacket(p);
++        D("%s: failed to write SYNC apacket to transport", t->serial);
++    }
++
++oops:
++    D("%s: transport output thread is exiting\n", t->serial);
++    kick_transport(t);
++    transport_unref(t);
++    return 0;
++}
++
++static void *input_thread(void *_t)
++{
++    atransport *t = _t;
++    apacket *p;
++    int active = 0;
++
++    D("%s: starting transport input thread, reading from fd %d\n",
++       t->serial, t->fd);
++
++    for(;;){
++        if(read_packet(t->fd, t->serial, &p)) {
++            D("%s: failed to read apacket from transport on fd %d\n",
++               t->serial, t->fd );
++            break;
++        }
++        if(p->msg.command == A_SYNC){
++            if(p->msg.arg0 == 0) {
++                D("%s: transport SYNC offline\n", t->serial);
++                put_apacket(p);
++                break;
++            } else {
++                if(p->msg.arg1 == t->sync_token) {
++                    D("%s: transport SYNC online\n", t->serial);
++                    active = 1;
++                } else {
++                    D("%s: transport ignoring SYNC %d != %d\n",
++                      t->serial, p->msg.arg1, t->sync_token);
++                }
++            }
++        } else {
++            if(active) {
++                D("%s: transport got packet, sending to remote\n", t->serial);
++                t->write_to_remote(p, t);
++            } else {
++                D("%s: transport ignoring packet while offline\n", t->serial);
++            }
++        }
++
++        put_apacket(p);
++    }
++
++    // this is necessary to avoid a race condition that occured when a transport closes
++    // while a client socket is still active.
++    close_all_sockets(t);
++
++    D("%s: transport input thread is exiting, fd %d\n", t->serial, t->fd);
++    kick_transport(t);
++    transport_unref(t);
++    return 0;
++}
++
++
++static int transport_registration_send = -1;
++static int transport_registration_recv = -1;
++static fdevent transport_registration_fde;
++
++
++#if ADB_HOST
++static int list_transports_msg(char*  buffer, size_t  bufferlen)
++{
++    char  head[5];
++    int   len;
++
++    len = list_transports(buffer+4, bufferlen-4, 0);
++    snprintf(head, sizeof(head), "%04x", len);
++    memcpy(buffer, head, 4);
++    len += 4;
++    return len;
++}
++
++/* this adds support required by the 'track-devices' service.
++ * this is used to send the content of "list_transport" to any
++ * number of client connections that want it through a single
++ * live TCP connection
++ */
++typedef struct device_tracker  device_tracker;
++struct device_tracker {
++    asocket          socket;
++    int              update_needed;
++    device_tracker*  next;
++};
++
++/* linked list of all device trackers */
++static device_tracker*   device_tracker_list;
++
++static void
++device_tracker_remove( device_tracker*  tracker )
++{
++    device_tracker**  pnode = &device_tracker_list;
++    device_tracker*   node  = *pnode;
++
++    adb_mutex_lock( &transport_lock );
++    while (node) {
++        if (node == tracker) {
++            *pnode = node->next;
++            break;
++        }
++        pnode = &node->next;
++        node  = *pnode;
++    }
++    adb_mutex_unlock( &transport_lock );
++}
++
++static void
++device_tracker_close( asocket*  socket )
++{
++    device_tracker*  tracker = (device_tracker*) socket;
++    asocket*         peer    = socket->peer;
++
++    D( "device tracker %p removed\n", tracker);
++    if (peer) {
++        peer->peer = NULL;
++        peer->close(peer);
++    }
++    device_tracker_remove(tracker);
++    free(tracker);
++}
++
++static int
++device_tracker_enqueue( asocket*  socket, apacket*  p )
++{
++    /* you can't read from a device tracker, close immediately */
++    put_apacket(p);
++    device_tracker_close(socket);
++    return -1;
++}
++
++static int
++device_tracker_send( device_tracker*  tracker,
++                     const char*      buffer,
++                     int              len )
++{
++    apacket*  p = get_apacket();
++    asocket*  peer = tracker->socket.peer;
++
++    memcpy(p->data, buffer, len);
++    p->len = len;
++    return peer->enqueue( peer, p );
++}
++
++
++static void
++device_tracker_ready( asocket*  socket )
++{
++    device_tracker*  tracker = (device_tracker*) socket;
++
++    /* we want to send the device list when the tracker connects
++    * for the first time, even if no update occured */
++    if (tracker->update_needed > 0) {
++        char  buffer[1024];
++        int   len;
++
++        tracker->update_needed = 0;
++
++        len = list_transports_msg(buffer, sizeof(buffer));
++        device_tracker_send(tracker, buffer, len);
++    }
++}
++
++
++asocket*
++create_device_tracker(void)
++{
++    device_tracker*  tracker = calloc(1,sizeof(*tracker));
++
++    if(tracker == 0) fatal("cannot allocate device tracker");
++
++    D( "device tracker %p created\n", tracker);
++
++    tracker->socket.enqueue = device_tracker_enqueue;
++    tracker->socket.ready   = device_tracker_ready;
++    tracker->socket.close   = device_tracker_close;
++    tracker->update_needed  = 1;
++
++    tracker->next       = device_tracker_list;
++    device_tracker_list = tracker;
++
++    return &tracker->socket;
++}
++
++
++/* call this function each time the transport list has changed */
++void  update_transports(void)
++{
++    char             buffer[1024];
++    int              len;
++    device_tracker*  tracker;
++
++    len = list_transports_msg(buffer, sizeof(buffer));
++
++    tracker = device_tracker_list;
++    while (tracker != NULL) {
++        device_tracker*  next = tracker->next;
++        /* note: this may destroy the tracker if the connection is closed */
++        device_tracker_send(tracker, buffer, len);
++        tracker = next;
++    }
++}
++#else
++void  update_transports(void)
++{
++    // nothing to do on the device side
++}
++#endif // ADB_HOST
++
++typedef struct tmsg tmsg;
++struct tmsg
++{
++    atransport *transport;
++    int         action;
++};
++
++static int
++transport_read_action(int  fd, struct tmsg*  m)
++{
++    char *p   = (char*)m;
++    int   len = sizeof(*m);
++    int   r;
++
++    while(len > 0) {
++        r = adb_read(fd, p, len);
++        if(r > 0) {
++            len -= r;
++            p   += r;
++        } else {
++            if((r < 0) && (errno == EINTR)) continue;
++            D("transport_read_action: on fd %d, error %d: %s\n",
++              fd, errno, strerror(errno));
++            return -1;
++        }
++    }
++    return 0;
++}
++
++static int
++transport_write_action(int  fd, struct tmsg*  m)
++{
++    char *p   = (char*)m;
++    int   len = sizeof(*m);
++    int   r;
++
++    while(len > 0) {
++        r = adb_write(fd, p, len);
++        if(r > 0) {
++            len -= r;
++            p   += r;
++        } else {
++            if((r < 0) && (errno == EINTR)) continue;
++            D("transport_write_action: on fd %d, error %d: %s\n",
++              fd, errno, strerror(errno));
++            return -1;
++        }
++    }
++    return 0;
++}
++
++static void transport_registration_func(int _fd, unsigned ev, void *data)
++{
++    tmsg m;
++    adb_thread_t output_thread_ptr;
++    adb_thread_t input_thread_ptr;
++    int s[2];
++    atransport *t;
++
++    if(!(ev & FDE_READ)) {
++        return;
++    }
++
++    if(transport_read_action(_fd, &m)) {
++        fatal_errno("cannot read transport registration socket");
++    }
++
++    t = m.transport;
++
++    if(m.action == 0){
++        D("transport: %s removing and free'ing %d\n", t->serial, t->transport_socket);
++
++            /* IMPORTANT: the remove closes one half of the
++            ** socket pair.  The close closes the other half.
++            */
++        fdevent_remove(&(t->transport_fde));
++        adb_close(t->fd);
++
++        adb_mutex_lock(&transport_lock);
++        t->next->prev = t->prev;
++        t->prev->next = t->next;
++        adb_mutex_unlock(&transport_lock);
++
++        run_transport_disconnects(t);
++
++        if (t->product)
++            free(t->product);
++        if (t->serial)
++            free(t->serial);
++        if (t->model)
++            free(t->model);
++        if (t->device)
++            free(t->device);
++        if (t->devpath)
++            free(t->devpath);
++
++        memset(t,0xee,sizeof(atransport));
++        free(t);
++
++        update_transports();
++        return;
++    }
++
++    /* don't create transport threads for inaccessible devices */
++    if (t->connection_state != CS_NOPERM) {
++        /* initial references are the two threads */
++        t->ref_count = 2;
++
++        if(adb_socketpair(s)) {
++            fatal_errno("cannot open transport socketpair");
++        }
++
++        D("transport: %s (%d,%d) starting\n", t->serial, s[0], s[1]);
++
++        t->transport_socket = s[0];
++        t->fd = s[1];
++
++        fdevent_install(&(t->transport_fde),
++                        t->transport_socket,
++                        transport_socket_events,
++                        t);
++
++        fdevent_set(&(t->transport_fde), FDE_READ);
++
++        if(adb_thread_create(&input_thread_ptr, input_thread, t)){
++            fatal_errno("cannot create input thread");
++        }
++
++        if(adb_thread_create(&output_thread_ptr, output_thread, t)){
++            fatal_errno("cannot create output thread");
++        }
++    }
++
++        /* put us on the master device list */
++    adb_mutex_lock(&transport_lock);
++    t->next = &transport_list;
++    t->prev = transport_list.prev;
++    t->next->prev = t;
++    t->prev->next = t;
++    adb_mutex_unlock(&transport_lock);
++
++    t->disconnects.next = t->disconnects.prev = &t->disconnects;
++
++    update_transports();
++}
++
++void init_transport_registration(void)
++{
++    int s[2];
++
++    if(adb_socketpair(s)){
++        fatal_errno("cannot open transport registration socketpair");
++    }
++
++    transport_registration_send = s[0];
++    transport_registration_recv = s[1];
++
++    fdevent_install(&transport_registration_fde,
++                    transport_registration_recv,
++                    transport_registration_func,
++                    0);
++
++    fdevent_set(&transport_registration_fde, FDE_READ);
++}
++
++/* the fdevent select pump is single threaded */
++static void register_transport(atransport *transport)
++{
++    tmsg m;
++    m.transport = transport;
++    m.action = 1;
++    D("transport: %s registered\n", transport->serial);
++    if(transport_write_action(transport_registration_send, &m)) {
++        fatal_errno("cannot write transport registration socket\n");
++    }
++}
++
++static void remove_transport(atransport *transport)
++{
++    tmsg m;
++    m.transport = transport;
++    m.action = 0;
++    D("transport: %s removed\n", transport->serial);
++    if(transport_write_action(transport_registration_send, &m)) {
++        fatal_errno("cannot write transport registration socket\n");
++    }
++}
++
++
++static void transport_unref_locked(atransport *t)
++{
++    t->ref_count--;
++    if (t->ref_count == 0) {
++        D("transport: %s unref (kicking and closing)\n", t->serial);
++        if (!t->kicked) {
++            t->kicked = 1;
++            t->kick(t);
++        }
++        t->close(t);
++        remove_transport(t);
++    } else {
++        D("transport: %s unref (count=%d)\n", t->serial, t->ref_count);
++    }
++}
++
++static void transport_unref(atransport *t)
++{
++    if (t) {
++        adb_mutex_lock(&transport_lock);
++        transport_unref_locked(t);
++        adb_mutex_unlock(&transport_lock);
++    }
++}
++
++void add_transport_disconnect(atransport*  t, adisconnect*  dis)
++{
++    adb_mutex_lock(&transport_lock);
++    dis->next       = &t->disconnects;
++    dis->prev       = dis->next->prev;
++    dis->prev->next = dis;
++    dis->next->prev = dis;
++    adb_mutex_unlock(&transport_lock);
++}
++
++void remove_transport_disconnect(atransport*  t, adisconnect*  dis)
++{
++    dis->prev->next = dis->next;
++    dis->next->prev = dis->prev;
++    dis->next = dis->prev = dis;
++}
++
++static int qual_char_is_invalid(char ch)
++{
++    if ('A' <= ch && ch <= 'Z')
++        return 0;
++    if ('a' <= ch && ch <= 'z')
++        return 0;
++    if ('0' <= ch && ch <= '9')
++        return 0;
++    return 1;
++}
++
++static int qual_match(const char *to_test,
++                      const char *prefix, const char *qual, int sanitize_qual)
++{
++    if (!to_test || !*to_test)
++        /* Return true if both the qual and to_test are null strings. */
++        return !qual || !*qual;
++
++    if (!qual)
++        return 0;
++
++    if (prefix) {
++        while (*prefix) {
++            if (*prefix++ != *to_test++)
++                return 0;
++        }
++    }
++
++    while (*qual) {
++        char ch = *qual++;
++        if (sanitize_qual && qual_char_is_invalid(ch))
++            ch = '_';
++        if (ch != *to_test++)
++            return 0;
++    }
++
++    /* Everything matched so far.  Return true if *to_test is a NUL. */
++    return !*to_test;
++}
++
++atransport *acquire_one_transport(int state, transport_type ttype, const char* serial, char** error_out)
++{
++    atransport *t;
++    atransport *result = NULL;
++    int ambiguous = 0;
++
++retry:
++    if (error_out)
++        *error_out = "device not found";
++
++    adb_mutex_lock(&transport_lock);
++    for (t = transport_list.next; t != &transport_list; t = t->next) {
++        if (t->connection_state == CS_NOPERM) {
++        if (error_out)
++            *error_out = "insufficient permissions for device";
++            continue;
++        }
++
++        /* check for matching serial number */
++        if (serial) {
++            if ((t->serial && !strcmp(serial, t->serial)) ||
++                (t->devpath && !strcmp(serial, t->devpath)) ||
++                qual_match(serial, "product:", t->product, 0) ||
++                qual_match(serial, "model:", t->model, 1) ||
++                qual_match(serial, "device:", t->device, 0)) {
++                if (result) {
++                    if (error_out)
++                        *error_out = "more than one device";
++                    ambiguous = 1;
++                    result = NULL;
++                    break;
++                }
++                result = t;
++            }
++        } else {
++            if (ttype == kTransportUsb && t->type == kTransportUsb) {
++                if (result) {
++                    if (error_out)
++                        *error_out = "more than one device";
++                    ambiguous = 1;
++                    result = NULL;
++                    break;
++                }
++                result = t;
++            } else if (ttype == kTransportLocal && t->type == kTransportLocal) {
++                if (result) {
++                    if (error_out)
++                        *error_out = "more than one emulator";
++                    ambiguous = 1;
++                    result = NULL;
++                    break;
++                }
++                result = t;
++            } else if (ttype == kTransportAny) {
++                if (result) {
++                    if (error_out)
++                        *error_out = "more than one device and emulator";
++                    ambiguous = 1;
++                    result = NULL;
++                    break;
++                }
++                result = t;
++            }
++        }
++    }
++    adb_mutex_unlock(&transport_lock);
++
++    if (result) {
++         /* offline devices are ignored -- they are either being born or dying */
++        if (result && result->connection_state == CS_OFFLINE) {
++            if (error_out)
++                *error_out = "device offline";
++            result = NULL;
++        }
++         /* check for required connection state */
++        if (result && state != CS_ANY && result->connection_state != state) {
++            if (error_out)
++                *error_out = "invalid device state";
++            result = NULL;
++        }
++    }
++
++    if (result) {
++        /* found one that we can take */
++        if (error_out)
++            *error_out = NULL;
++    } else if (state != CS_ANY && (serial || !ambiguous)) {
++        adb_sleep_ms(1000);
++        goto retry;
++    }
++
++    return result;
++}
++
++#if ADB_HOST
++static const char *statename(atransport *t)
++{
++    switch(t->connection_state){
++    case CS_OFFLINE: return "offline";
++    case CS_BOOTLOADER: return "bootloader";
++    case CS_DEVICE: return "device";
++    case CS_HOST: return "host";
++    case CS_RECOVERY: return "recovery";
++    case CS_SIDELOAD: return "sideload";
++    case CS_NOPERM: return "no permissions";
++    default: return "unknown";
++    }
++}
++
++static void add_qual(char **buf, size_t *buf_size,
++                     const char *prefix, const char *qual, int sanitize_qual)
++{
++    size_t len;
++    int prefix_len;
++
++    if (!buf || !*buf || !buf_size || !*buf_size || !qual || !*qual)
++        return;
++
++    len = snprintf(*buf, *buf_size, "%s%n%s", prefix, &prefix_len, qual);
++
++    if (sanitize_qual) {
++        char *cp;
++        for (cp = *buf + prefix_len; cp < *buf + len; cp++) {
++            if (qual_char_is_invalid(*cp))
++                *cp = '_';
++        }
++    }
++
++    *buf_size -= len;
++    *buf += len;
++}
++
++static size_t format_transport(atransport *t, char *buf, size_t bufsize,
++                               int long_listing)
++{
++    const char* serial = t->serial;
++    if (!serial || !serial[0])
++        serial = "????????????";
++
++    if (!long_listing) {
++        return snprintf(buf, bufsize, "%s\t%s\n", serial, statename(t));
++    } else {
++        size_t len, remaining = bufsize;
++
++        len = snprintf(buf, remaining, "%-22s %s", serial, statename(t));
++        remaining -= len;
++        buf += len;
++
++        add_qual(&buf, &remaining, " ", t->devpath, 0);
++        add_qual(&buf, &remaining, " product:", t->product, 0);
++        add_qual(&buf, &remaining, " model:", t->model, 1);
++        add_qual(&buf, &remaining, " device:", t->device, 0);
++
++        len = snprintf(buf, remaining, "\n");
++        remaining -= len;
++
++        return bufsize - remaining;
++    }
++}
++
++int list_transports(char *buf, size_t  bufsize, int long_listing)
++{
++    char*       p   = buf;
++    char*       end = buf + bufsize;
++    int         len;
++    atransport *t;
++
++        /* XXX OVERRUN PROBLEMS XXX */
++    adb_mutex_lock(&transport_lock);
++    for(t = transport_list.next; t != &transport_list; t = t->next) {
++        len = format_transport(t, p, end - p, long_listing);
++        if (p + len >= end) {
++            /* discard last line if buffer is too short */
++            break;
++        }
++        p += len;
++    }
++    p[0] = 0;
++    adb_mutex_unlock(&transport_lock);
++    return p - buf;
++}
++
++
++/* hack for osx */
++void close_usb_devices()
++{
++    atransport *t;
++
++    adb_mutex_lock(&transport_lock);
++    for(t = transport_list.next; t != &transport_list; t = t->next) {
++        if ( !t->kicked ) {
++            t->kicked = 1;
++            t->kick(t);
++        }
++    }
++    adb_mutex_unlock(&transport_lock);
++}
++#endif // ADB_HOST
++
++void register_socket_transport(int s, const char *serial, int port, int local)
++{
++    atransport *t = calloc(1, sizeof(atransport));
++    char buff[32];
++
++    if (!serial) {
++        snprintf(buff, sizeof buff, "T-%p", t);
++        serial = buff;
++    }
++    D("transport: %s init'ing for socket %d, on port %d\n", serial, s, port);
++    if ( init_socket_transport(t, s, port, local) < 0 ) {
++        adb_close(s);
++        free(t);
++        return;
++    }
++    if(serial) {
++        t->serial = strdup(serial);
++    }
++    register_transport(t);
++}
++
++#if ADB_HOST
++atransport *find_transport(const char *serial)
++{
++    atransport *t;
++
++    adb_mutex_lock(&transport_lock);
++    for(t = transport_list.next; t != &transport_list; t = t->next) {
++        if (t->serial && !strcmp(serial, t->serial)) {
++            break;
++        }
++     }
++    adb_mutex_unlock(&transport_lock);
++
++    if (t != &transport_list)
++        return t;
++    else
++        return 0;
++}
++
++void unregister_transport(atransport *t)
++{
++    adb_mutex_lock(&transport_lock);
++    t->next->prev = t->prev;
++    t->prev->next = t->next;
++    adb_mutex_unlock(&transport_lock);
++
++    kick_transport(t);
++    transport_unref(t);
++}
++
++// unregisters all non-emulator TCP transports
++void unregister_all_tcp_transports()
++{
++    atransport *t, *next;
++    adb_mutex_lock(&transport_lock);
++    for (t = transport_list.next; t != &transport_list; t = next) {
++        next = t->next;
++        if (t->type == kTransportLocal && t->adb_port == 0) {
++            t->next->prev = t->prev;
++            t->prev->next = next;
++            // we cannot call kick_transport when holding transport_lock
++            if (!t->kicked)
++            {
++                t->kicked = 1;
++                t->kick(t);
++            }
++            transport_unref_locked(t);
++        }
++     }
++
++    adb_mutex_unlock(&transport_lock);
++}
++
++#endif
++
++void register_usb_transport(usb_handle *usb, const char *serial, const char *devpath, unsigned writeable)
++{
++    atransport *t = calloc(1, sizeof(atransport));
++    D("transport: %p init'ing for usb_handle %p (sn='%s')\n", t, usb,
++      serial ? serial : "");
++    init_usb_transport(t, usb, (writeable ? CS_OFFLINE : CS_NOPERM));
++    if(serial) {
++        t->serial = strdup(serial);
++    }
++    if(devpath) {
++        t->devpath = strdup(devpath);
++    }
++    register_transport(t);
++}
++
++/* this should only be used for transports with connection_state == CS_NOPERM */
++void unregister_usb_transport(usb_handle *usb)
++{
++    atransport *t;
++    adb_mutex_lock(&transport_lock);
++    for(t = transport_list.next; t != &transport_list; t = t->next) {
++        if (t->usb == usb && t->connection_state == CS_NOPERM) {
++            t->next->prev = t->prev;
++            t->prev->next = t->next;
++            break;
++        }
++     }
++    adb_mutex_unlock(&transport_lock);
++}
++
++#undef TRACE_TAG
++#define TRACE_TAG  TRACE_RWX
++
++int readx(int fd, void *ptr, size_t len)
++{
++    char *p = ptr;
++    int r;
++#if ADB_TRACE
++    int  len0 = len;
++#endif
++    D("readx: fd=%d wanted=%d\n", fd, (int)len);
++    while(len > 0) {
++        r = adb_read(fd, p, len);
++        if(r > 0) {
++            len -= r;
++            p += r;
++        } else {
++            if (r < 0) {
++                D("readx: fd=%d error %d: %s\n", fd, errno, strerror(errno));
++                if (errno == EINTR)
++                    continue;
++            } else {
++                D("readx: fd=%d disconnected\n", fd);
++            }
++            return -1;
++        }
++    }
++
++#if ADB_TRACE
++    D("readx: fd=%d wanted=%d got=%d\n", fd, len0, len0 - len);
++    dump_hex( ptr, len0 );
++#endif
++    return 0;
++}
++
++int writex(int fd, const void *ptr, size_t len)
++{
++    char *p = (char*) ptr;
++    int r;
++
++#if ADB_TRACE
++    D("writex: fd=%d len=%d: ", fd, (int)len);
++    dump_hex( ptr, len );
++#endif
++    while(len > 0) {
++        r = adb_write(fd, p, len);
++        if(r > 0) {
++            len -= r;
++            p += r;
++        } else {
++            if (r < 0) {
++                D("writex: fd=%d error %d: %s\n", fd, errno, strerror(errno));
++                if (errno == EINTR)
++                    continue;
++            } else {
++                D("writex: fd=%d disconnected\n", fd);
++            }
++            return -1;
++        }
++    }
++    return 0;
++}
++
++int check_header(apacket *p)
++{
++    if(p->msg.magic != (p->msg.command ^ 0xffffffff)) {
++        D("check_header(): invalid magic\n");
++        return -1;
++    }
++
++    if(p->msg.data_length > MAX_PAYLOAD) {
++        D("check_header(): %d > MAX_PAYLOAD\n", p->msg.data_length);
++        return -1;
++    }
++
++    return 0;
++}
++
++int check_data(apacket *p)
++{
++    unsigned count, sum;
++    unsigned char *x;
++
++    count = p->msg.data_length;
++    x = p->data;
++    sum = 0;
++    while(count-- > 0) {
++        sum += *x++;
++    }
++
++    if(sum != p->msg.data_check) {
++        return -1;
++    } else {
++        return 0;
++    }
++}
+Index: android-tools-4.2.2+git20130218/core/adbd/transport.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/transport.h      2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,26 @@
++/*
++ * Copyright (C) 2011 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#ifndef __TRANSPORT_H
++#define __TRANSPORT_H
++
++/* convenience wrappers around read/write that will retry on
++** EINTR and/or short read/write.  Returns 0 on success, -1
++** on error or EOF.
++*/
++int readx(int fd, void *ptr, size_t len);
++int writex(int fd, const void *ptr, size_t len);
++#endif   /* __TRANSPORT_H */
+Index: android-tools-4.2.2+git20130218/core/adbd/transport_local.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/transport_local.c        2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,441 @@
++/*
++ * Copyright (C) 2007 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <errno.h>
++
++#include "sysdeps.h"
++#include <sys/types.h>
++
++#define  TRACE_TAG  TRACE_TRANSPORT
++#include "adb.h"
++
++#ifdef HAVE_BIG_ENDIAN
++#define H4(x) (((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24)
++static inline void fix_endians(apacket *p)
++{
++    p->msg.command     = H4(p->msg.command);
++    p->msg.arg0        = H4(p->msg.arg0);
++    p->msg.arg1        = H4(p->msg.arg1);
++    p->msg.data_length = H4(p->msg.data_length);
++    p->msg.data_check  = H4(p->msg.data_check);
++    p->msg.magic       = H4(p->msg.magic);
++}
++#else
++#define fix_endians(p) do {} while (0)
++#endif
++
++#if ADB_HOST
++/* we keep a list of opened transports. The atransport struct knows to which
++ * local transport it is connected. The list is used to detect when we're
++ * trying to connect twice to a given local transport.
++ */
++#define  ADB_LOCAL_TRANSPORT_MAX  16
++
++ADB_MUTEX_DEFINE( local_transports_lock );
++
++static atransport*  local_transports[ ADB_LOCAL_TRANSPORT_MAX ];
++#endif /* ADB_HOST */
++
++static int remote_read(apacket *p, atransport *t)
++{
++    if(readx(t->sfd, &p->msg, sizeof(amessage))){
++        D("remote local: read terminated (message)\n");
++        return -1;
++    }
++
++    fix_endians(p);
++
++#if 0 && defined HAVE_BIG_ENDIAN
++    D("read remote packet: %04x arg0=%0x arg1=%0x data_length=%0x data_check=%0x magic=%0x\n",
++      p->msg.command, p->msg.arg0, p->msg.arg1, p->msg.data_length, p->msg.data_check, p->msg.magic);
++#endif
++    if(check_header(p)) {
++        D("bad header: terminated (data)\n");
++        return -1;
++    }
++
++    if(readx(t->sfd, p->data, p->msg.data_length)){
++        D("remote local: terminated (data)\n");
++        return -1;
++    }
++
++    if(check_data(p)) {
++        D("bad data: terminated (data)\n");
++        return -1;
++    }
++
++    return 0;
++}
++
++static int remote_write(apacket *p, atransport *t)
++{
++    int   length = p->msg.data_length;
++
++    fix_endians(p);
++
++#if 0 && defined HAVE_BIG_ENDIAN
++    D("write remote packet: %04x arg0=%0x arg1=%0x data_length=%0x data_check=%0x magic=%0x\n",
++      p->msg.command, p->msg.arg0, p->msg.arg1, p->msg.data_length, p->msg.data_check, p->msg.magic);
++#endif
++    if(writex(t->sfd, &p->msg, sizeof(amessage) + length)) {
++        D("remote local: write terminated\n");
++        return -1;
++    }
++
++    return 0;
++}
++
++
++int local_connect(int port) {
++    return local_connect_arbitrary_ports(port-1, port);
++}
++
++int local_connect_arbitrary_ports(int console_port, int adb_port)
++{
++    char buf[64];
++    int  fd = -1;
++
++#if ADB_HOST
++    const char *host = getenv("ADBHOST");
++    if (host) {
++        fd = socket_network_client(host, adb_port, SOCK_STREAM);
++    }
++#endif
++    if (fd < 0) {
++        fd = socket_loopback_client(adb_port, SOCK_STREAM);
++    }
++
++    if (fd >= 0) {
++        D("client: connected on remote on fd %d\n", fd);
++        close_on_exec(fd);
++        disable_tcp_nagle(fd);
++        snprintf(buf, sizeof buf, "%s%d", LOCAL_CLIENT_PREFIX, console_port);
++        register_socket_transport(fd, buf, adb_port, 1);
++        return 0;
++    }
++    return -1;
++}
++
++
++static void *client_socket_thread(void *x)
++{
++#if ADB_HOST
++    int  port  = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
++    int  count = ADB_LOCAL_TRANSPORT_MAX;
++
++    D("transport: client_socket_thread() starting\n");
++
++    /* try to connect to any number of running emulator instances     */
++    /* this is only done when ADB starts up. later, each new emulator */
++    /* will send a message to ADB to indicate that is is starting up  */
++    for ( ; count > 0; count--, port += 2 ) {
++        (void) local_connect(port);
++    }
++#endif
++    return 0;
++}
++
++static void *server_socket_thread(void * arg)
++{
++    int serverfd, fd;
++    struct sockaddr addr;
++    socklen_t alen;
++    int port = (int)arg;
++
++    D("transport: server_socket_thread() starting\n");
++    serverfd = -1;
++    for(;;) {
++        if(serverfd == -1) {
++            serverfd = socket_inaddr_any_server(port, SOCK_STREAM);
++            if(serverfd < 0) {
++                D("server: cannot bind socket yet\n");
++                adb_sleep_ms(1000);
++                continue;
++            }
++            close_on_exec(serverfd);
++        }
++
++        alen = sizeof(addr);
++        D("server: trying to get new connection from %d\n", port);
++        fd = adb_socket_accept(serverfd, &addr, &alen);
++        if(fd >= 0) {
++            D("server: new connection on fd %d\n", fd);
++            close_on_exec(fd);
++            disable_tcp_nagle(fd);
++            register_socket_transport(fd, "host", port, 1);
++        }
++    }
++    D("transport: server_socket_thread() exiting\n");
++    return 0;
++}
++
++/* This is relevant only for ADB daemon running inside the emulator. */
++#if !ADB_HOST
++/*
++ * Redefine open and write for qemu_pipe.h that contains inlined references
++ * to those routines. We will redifine them back after qemu_pipe.h inclusion.
++ */
++#undef open
++#undef write
++#define open    adb_open
++#define write   adb_write
++#include "qemu_pipe.h"
++#undef open
++#undef write
++#define open    ___xxx_open
++#define write   ___xxx_write
++
++/* A worker thread that monitors host connections, and registers a transport for
++ * every new host connection. This thread replaces server_socket_thread on
++ * condition that adbd daemon runs inside the emulator, and emulator uses QEMUD
++ * pipe to communicate with adbd daemon inside the guest. This is done in order
++ * to provide more robust communication channel between ADB host and guest. The
++ * main issue with server_socket_thread approach is that it runs on top of TCP,
++ * and thus is sensitive to network disruptions. For instance, the
++ * ConnectionManager may decide to reset all network connections, in which case
++ * the connection between ADB host and guest will be lost. To make ADB traffic
++ * independent from the network, we use here 'adb' QEMUD service to transfer data
++ * between the host, and the guest. See external/qemu/android/adb-*.* that
++ * implements the emulator's side of the protocol. Another advantage of using
++ * QEMUD approach is that ADB will be up much sooner, since it doesn't depend
++ * anymore on network being set up.
++ * The guest side of the protocol contains the following phases:
++ * - Connect with adb QEMUD service. In this phase a handle to 'adb' QEMUD service
++ *   is opened, and it becomes clear whether or not emulator supports that
++ *   protocol.
++ * - Wait for the ADB host to create connection with the guest. This is done by
++ *   sending an 'accept' request to the adb QEMUD service, and waiting on
++ *   response.
++ * - When new ADB host connection is accepted, the connection with adb QEMUD
++ *   service is registered as the transport, and a 'start' request is sent to the
++ *   adb QEMUD service, indicating that the guest is ready to receive messages.
++ *   Note that the guest will ignore messages sent down from the emulator before
++ *   the transport registration is completed. That's why we need to send the
++ *   'start' request after the transport is registered.
++ */
++static void *qemu_socket_thread(void * arg)
++{
++/* 'accept' request to the adb QEMUD service. */
++static const char _accept_req[] = "accept";
++/* 'start' request to the adb QEMUD service. */
++static const char _start_req[]  = "start";
++/* 'ok' reply from the adb QEMUD service. */
++static const char _ok_resp[]    = "ok";
++
++    const int port = (int)arg;
++    int res, fd;
++    char tmp[256];
++    char con_name[32];
++
++    D("transport: qemu_socket_thread() starting\n");
++
++    /* adb QEMUD service connection request. */
++    snprintf(con_name, sizeof(con_name), "qemud:adb:%d", port);
++
++    /* Connect to the adb QEMUD service. */
++    fd = qemu_pipe_open(con_name);
++    if (fd < 0) {
++        /* This could be an older version of the emulator, that doesn't
++         * implement adb QEMUD service. Fall back to the old TCP way. */
++        adb_thread_t thr;
++        D("adb service is not available. Falling back to TCP socket.\n");
++        adb_thread_create(&thr, server_socket_thread, arg);
++        return 0;
++    }
++
++    for(;;) {
++        /*
++         * Wait till the host creates a new connection.
++         */
++
++        /* Send the 'accept' request. */
++        res = adb_write(fd, _accept_req, strlen(_accept_req));
++        if ((size_t)res == strlen(_accept_req)) {
++            /* Wait for the response. In the response we expect 'ok' on success,
++             * or 'ko' on failure. */
++            res = adb_read(fd, tmp, sizeof(tmp));
++            if (res != 2 || memcmp(tmp, _ok_resp, 2)) {
++                D("Accepting ADB host connection has failed.\n");
++                adb_close(fd);
++            } else {
++                /* Host is connected. Register the transport, and start the
++                 * exchange. */
++                register_socket_transport(fd, "host", port, 1);
++                adb_write(fd, _start_req, strlen(_start_req));
++            }
++
++            /* Prepare for accepting of the next ADB host connection. */
++            fd = qemu_pipe_open(con_name);
++            if (fd < 0) {
++                D("adb service become unavailable.\n");
++                return 0;
++            }
++        } else {
++            D("Unable to send the '%s' request to ADB service.\n", _accept_req);
++            return 0;
++        }
++    }
++    D("transport: qemu_socket_thread() exiting\n");
++    return 0;
++}
++#endif  // !ADB_HOST
++
++void local_init(int port)
++{
++    adb_thread_t thr;
++    void* (*func)(void *);
++
++    if(HOST) {
++        func = client_socket_thread;
++    } else {
++#if ADB_HOST
++        func = server_socket_thread;
++#else
++        /* For the adbd daemon in the system image we need to distinguish
++         * between the device, and the emulator. */
++        char is_qemu[PROPERTY_VALUE_MAX];
++        //property_get("ro.kernel.qemu", is_qemu, "");
++        //if (!strcmp(is_qemu, "1")) {
++            /* Running inside the emulator: use QEMUD pipe as the transport. */
++        //    func = qemu_socket_thread;
++        //} else {
++            /* Running inside the device: use TCP socket as the transport. */
++            func = server_socket_thread;
++            //}
++#endif // !ADB_HOST
++    }
++
++    D("transport: local %s init\n", HOST ? "client" : "server");
++
++    if(adb_thread_create(&thr, func, (void *)port)) {
++        fatal_errno("cannot create local socket %s thread",
++                    HOST ? "client" : "server");
++    }
++}
++
++static void remote_kick(atransport *t)
++{
++    int fd = t->sfd;
++    t->sfd = -1;
++    adb_shutdown(fd);
++    adb_close(fd);
++
++#if ADB_HOST
++    if(HOST) {
++        int  nn;
++        adb_mutex_lock( &local_transports_lock );
++        for (nn = 0; nn < ADB_LOCAL_TRANSPORT_MAX; nn++) {
++            if (local_transports[nn] == t) {
++                local_transports[nn] = NULL;
++                break;
++            }
++        }
++        adb_mutex_unlock( &local_transports_lock );
++    }
++#endif
++}
++
++static void remote_close(atransport *t)
++{
++    adb_close(t->fd);
++}
++
++
++#if ADB_HOST
++/* Only call this function if you already hold local_transports_lock. */
++atransport* find_emulator_transport_by_adb_port_locked(int adb_port)
++{
++    int i;
++    for (i = 0; i < ADB_LOCAL_TRANSPORT_MAX; i++) {
++        if (local_transports[i] && local_transports[i]->adb_port == adb_port) {
++            return local_transports[i];
++        }
++    }
++    return NULL;
++}
++
++atransport* find_emulator_transport_by_adb_port(int adb_port)
++{
++    adb_mutex_lock( &local_transports_lock );
++    atransport* result = find_emulator_transport_by_adb_port_locked(adb_port);
++    adb_mutex_unlock( &local_transports_lock );
++    return result;
++}
++
++/* Only call this function if you already hold local_transports_lock. */
++int get_available_local_transport_index_locked()
++{
++    int i;
++    for (i = 0; i < ADB_LOCAL_TRANSPORT_MAX; i++) {
++        if (local_transports[i] == NULL) {
++            return i;
++        }
++    }
++    return -1;
++}
++
++int get_available_local_transport_index()
++{
++    adb_mutex_lock( &local_transports_lock );
++    int result = get_available_local_transport_index_locked();
++    adb_mutex_unlock( &local_transports_lock );
++    return result;
++}
++#endif
++
++int init_socket_transport(atransport *t, int s, int adb_port, int local)
++{
++    int  fail = 0;
++
++    t->kick = remote_kick;
++    t->close = remote_close;
++    t->read_from_remote = remote_read;
++    t->write_to_remote = remote_write;
++    t->sfd = s;
++    t->sync_token = 1;
++    t->connection_state = CS_OFFLINE;
++    t->type = kTransportLocal;
++    t->adb_port = 0;
++
++#if ADB_HOST
++    if (HOST && local) {
++        adb_mutex_lock( &local_transports_lock );
++        {
++            t->adb_port = adb_port;
++            atransport* existing_transport =
++                    find_emulator_transport_by_adb_port_locked(adb_port);
++            int index = get_available_local_transport_index_locked();
++            if (existing_transport != NULL) {
++                D("local transport for port %d already registered (%p)?\n",
++                adb_port, existing_transport);
++                fail = -1;
++            } else if (index < 0) {
++                // Too many emulators.
++                D("cannot register more emulators. Maximum is %d\n",
++                        ADB_LOCAL_TRANSPORT_MAX);
++                fail = -1;
++            } else {
++                local_transports[index] = t;
++            }
++       }
++       adb_mutex_unlock( &local_transports_lock );
++    }
++#endif
++    return fail;
++}
+Index: android-tools-4.2.2+git20130218/core/adbd/transport_usb.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/transport_usb.c  2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,148 @@
++/*
++ * Copyright (C) 2007 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++
++#include <sysdeps.h>
++
++#define  TRACE_TAG  TRACE_TRANSPORT
++#include "adb.h"
++
++#if ADB_HOST
++#include "usb_vendors.h"
++#endif
++
++#ifdef HAVE_BIG_ENDIAN
++#define H4(x) (((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24)
++static inline void fix_endians(apacket *p)
++{
++    p->msg.command     = H4(p->msg.command);
++    p->msg.arg0        = H4(p->msg.arg0);
++    p->msg.arg1        = H4(p->msg.arg1);
++    p->msg.data_length = H4(p->msg.data_length);
++    p->msg.data_check  = H4(p->msg.data_check);
++    p->msg.magic       = H4(p->msg.magic);
++}
++unsigned host_to_le32(unsigned n)
++{
++    return H4(n);
++}
++#else
++#define fix_endians(p) do {} while (0)
++unsigned host_to_le32(unsigned n)
++{
++    return n;
++}
++#endif
++
++static int remote_read(apacket *p, atransport *t)
++{
++    if(usb_read(t->usb, &p->msg, sizeof(amessage))){
++        D("remote usb: read terminated (message)\n");
++        return -1;
++    }
++
++    fix_endians(p);
++
++    if(check_header(p)) {
++        D("remote usb: check_header failed\n");
++        return -1;
++    }
++
++    if(p->msg.data_length) {
++        if(usb_read(t->usb, p->data, p->msg.data_length)){
++            D("remote usb: terminated (data)\n");
++            return -1;
++        }
++    }
++
++    if(check_data(p)) {
++        D("remote usb: check_data failed\n");
++        return -1;
++    }
++
++    return 0;
++}
++
++static int remote_write(apacket *p, atransport *t)
++{
++    unsigned size = p->msg.data_length;
++
++    fix_endians(p);
++
++    if(usb_write(t->usb, &p->msg, sizeof(amessage))) {
++        D("remote usb: 1 - write terminated\n");
++        return -1;
++    }
++    if(p->msg.data_length == 0) return 0;
++    if(usb_write(t->usb, &p->data, size)) {
++        D("remote usb: 2 - write terminated\n");
++        return -1;
++    }
++
++    return 0;
++}
++
++static void remote_close(atransport *t)
++{
++    usb_close(t->usb);
++    t->usb = 0;
++}
++
++static void remote_kick(atransport *t)
++{
++    usb_kick(t->usb);
++}
++
++void init_usb_transport(atransport *t, usb_handle *h, int state)
++{
++    D("transport: usb\n");
++    t->close = remote_close;
++    t->kick = remote_kick;
++    t->read_from_remote = remote_read;
++    t->write_to_remote = remote_write;
++    t->sync_token = 1;
++    t->connection_state = state;
++    t->type = kTransportUsb;
++    t->usb = h;
++
++#if ADB_HOST
++    HOST = 1;
++#else
++    HOST = 0;
++#endif
++}
++
++#if ADB_HOST
++int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol)
++{
++    unsigned i;
++    for (i = 0; i < vendorIdCount; i++) {
++        if (vid == vendorIds[i]) {
++            if (usb_class == ADB_CLASS && usb_subclass == ADB_SUBCLASS &&
++                    usb_protocol == ADB_PROTOCOL) {
++                return 1;
++            }
++
++            return 0;
++        }
++    }
++
++    return 0;
++}
++#endif
+Index: android-tools-4.2.2+git20130218/core/adbd/usb_libusb.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/usb_libusb.c     2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,657 @@
++/* 
++ * Copyright (C) 2009 bsdroid project
++ *               Alexey Tarasov <tarasov@dodologics.com>
++ *   
++ * Copyright (C) 2007 The Android Open Source Project
++ * 
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include <sys/endian.h>
++#include <sys/ioctl.h>
++#include <sys/types.h>
++#include <sys/uio.h>
++
++#include <err.h>
++#include <errno.h>
++#include <poll.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <strings.h>
++#include <string.h>
++#include <sysexits.h>
++#include <unistd.h>
++#include <libusb.h>
++#include "sysdeps.h"
++
++#define   TRACE_TAG  TRACE_USB
++#include "adb.h"
++
++static adb_mutex_t usb_lock = ADB_MUTEX_INITIALIZER;
++static libusb_context *ctx = NULL;
++
++struct usb_handle
++{
++    usb_handle            *prev;
++    usb_handle            *next;
++
++    libusb_device         *dev;
++    libusb_device_handle  *devh;
++    int                   interface;
++    uint8_t               dev_bus;
++    uint8_t               dev_addr;
++      
++    int                   zero_mask;
++    unsigned char         end_point_address[2];
++    char                  serial[128];
++    
++    adb_cond_t            notify;
++    adb_mutex_t           lock;
++};
++
++static struct usb_handle handle_list = {
++        .prev = &handle_list,
++        .next = &handle_list,
++};
++
++void
++usb_cleanup()
++{
++      libusb_exit(ctx);
++}
++
++void
++report_bulk_libusb_error(int r)
++{
++    switch (r) {
++    case LIBUSB_ERROR_TIMEOUT:
++        D("Transfer timeout\n");
++        break;
++
++    case LIBUSB_ERROR_PIPE:
++        D("Control request is not supported\n");
++        break;
++
++    case LIBUSB_ERROR_OVERFLOW:
++        D("Device offered more data\n");
++        break;
++
++    case LIBUSB_ERROR_NO_DEVICE :
++        D("Device was disconnected\n");
++        break;
++
++    default:
++        D("Error %d during transfer\n", r);
++        break;
++    };
++}
++
++static int
++usb_bulk_write(usb_handle *uh, const void *data, int len)
++{
++    int r = 0;
++    int transferred = 0;
++
++    r = libusb_bulk_transfer(uh->devh, uh->end_point_address[1], (void *)data, len,
++                             &transferred, 0);
++   
++    if (r != 0) {
++        D("usb_bulk_write(): ");
++        report_bulk_libusb_error(r);
++        return r;
++    }
++   
++    return (transferred);
++}
++
++static int
++usb_bulk_read(usb_handle *uh, void *data, int len)
++{
++    int r = 0;
++    int transferred = 0;
++
++    r = libusb_bulk_transfer(uh->devh, uh->end_point_address[0], data, len,
++                             &transferred, 0);
++
++    if (r != 0) {
++        D("usb_bulk_read(): ");
++        report_bulk_libusb_error(r);
++        return r;
++    }
++   
++    return (transferred);
++}
++
++int
++usb_write(struct usb_handle *uh, const void *_data, int len)
++{
++    unsigned char *data = (unsigned char*) _data;
++    int n;
++    int need_zero = 0;
++
++    if (uh->zero_mask == 1) {
++        if (!(len & uh->zero_mask)) {
++            need_zero = 1;
++        }
++    }
++
++    D("usb_write(): %p:%d -> transport %p\n", _data, len, uh);
++    
++    while (len > 0) {
++        int xfer = (len > 4096) ? 4096 : len;
++
++        n = usb_bulk_write(uh, data, xfer);
++        
++        if (n != xfer) {
++            D("usb_write(): failed for transport %p (%d bytes left)\n", uh, len);
++            return -1;
++        }
++
++        len -= xfer;
++        data += xfer;
++    }
++
++    if (need_zero){
++        n = usb_bulk_write(uh, _data, 0);
++        
++        if (n < 0) {
++            D("usb_write(): failed to finish operation for transport %p\n", uh);
++        }
++        return n;
++    }
++
++    return 0;
++}
++
++int
++usb_read(struct usb_handle *uh, void *_data, int len)
++{
++    unsigned char *data = (unsigned char*) _data;
++    int n;
++
++    D("usb_read(): %p:%d <- transport %p\n", _data, len, uh);
++    
++    while (len > 0) {
++        int xfer = (len > 4096) ? 4096 : len;
++
++        n = usb_bulk_read(uh, data, xfer);
++        
++        if (n != xfer) {
++            if (n > 0) {
++                data += n;
++                len -= n;
++                continue;
++            }
++            
++            D("usb_read(): failed for transport %p (%d bytes left)\n", uh, len);
++            return -1;
++        }
++
++        len -= xfer;
++        data += xfer;
++    }
++
++    return 0;
++ }
++
++int
++usb_close(struct usb_handle *h)
++{
++    D("usb_close(): closing transport %p\n", h);
++    adb_mutex_lock(&usb_lock);
++    
++    h->next->prev = h->prev;
++    h->prev->next = h->next;
++    h->prev = NULL;
++    h->next = NULL;
++
++    libusb_release_interface(h->devh, h->interface);
++    libusb_close(h->devh);
++    libusb_unref_device(h->dev);
++    
++    adb_mutex_unlock(&usb_lock);
++
++    free(h);
++
++    return (0);
++}
++
++void usb_kick(struct usb_handle *h)
++{
++    D("usb_cick(): kicking transport %p\n", h);
++    
++    adb_mutex_lock(&h->lock);
++    unregister_usb_transport(h);
++    adb_mutex_unlock(&h->lock);
++    
++    h->next->prev = h->prev;
++    h->prev->next = h->next;
++    h->prev = NULL;
++    h->next = NULL;
++
++    libusb_release_interface(h->devh, h->interface);
++    libusb_close(h->devh);
++    libusb_unref_device(h->dev);
++    free(h);
++}
++
++int
++check_usb_interface(libusb_interface *interface,
++                    libusb_device_descriptor *desc,
++                    struct usb_handle *uh)
++{    
++    int e;
++    
++    if (interface->num_altsetting == 0) {
++        D("check_usb_interface(): No interface settings\n");
++        return -1;
++    }
++    
++    libusb_interface_descriptor *idesc = &interface->altsetting[0];
++    
++    if (idesc->bNumEndpoints != 2) {
++        D("check_usb_interface(): Interface have not 2 endpoints, ignoring\n");
++        return -1;
++    }
++
++    for (e = 0; e < idesc->bNumEndpoints; e++) {
++        libusb_endpoint_descriptor *edesc = &idesc->endpoint[e];
++        
++        if (edesc->bmAttributes != LIBUSB_TRANSFER_TYPE_BULK) {
++            D("check_usb_interface(): Endpoint (%u) is not bulk (%u), ignoring\n",
++                    edesc->bmAttributes, LIBUSB_TRANSFER_TYPE_BULK);
++            return -1;
++        }
++        
++        if (edesc->bEndpointAddress & LIBUSB_ENDPOINT_IN)
++            uh->end_point_address[0] = edesc->bEndpointAddress;
++        else
++            uh->end_point_address[1] = edesc->bEndpointAddress;
++        
++            /* aproto 01 needs 0 termination */
++        if (idesc->bInterfaceProtocol == 0x01) {
++            uh->zero_mask = edesc->wMaxPacketSize - 1;
++            D("check_usb_interface(): Forced Android interface protocol v.1\n");
++        }
++    }
++
++    D("check_usb_interface(): Device: %04x:%04x "
++      "iclass: %x, isclass: %x, iproto: %x ep: %x/%x-> ",
++        desc->idVendor, desc->idProduct, idesc->bInterfaceClass,
++      idesc->bInterfaceSubClass, idesc->bInterfaceProtocol,
++      uh->end_point_address[0], uh->end_point_address[1]);
++    
++    if (!is_adb_interface(desc->idVendor, desc->idProduct,
++            idesc->bInterfaceClass, idesc->bInterfaceSubClass,
++            idesc->bInterfaceProtocol))
++    {
++        D("not matches\n");
++        return -1;
++    }
++
++    D("matches\n");
++    return 1;
++}
++
++int
++check_usb_interfaces(libusb_config_descriptor *config,
++                     libusb_device_descriptor *desc, struct usb_handle *uh)
++{  
++    int i;
++    
++    for (i = 0; i < config->bNumInterfaces; ++i) {
++        if (check_usb_interface(&config->interface[i], desc, uh) != -1) {
++            /* found some interface and saved information about it */
++            D("check_usb_interfaces(): Interface %d of %04x:%04x "
++              "matches Android device\n", i, desc->idVendor,
++            desc->idProduct);
++            
++            return  i;
++        }
++    }
++    
++    return -1;
++}
++
++int
++register_device(struct usb_handle *uh, const char *serial)
++{
++    D("register_device(): Registering %p [%s] as USB transport\n",
++       uh, serial);
++
++    struct usb_handle *usb= NULL;
++
++    usb = calloc(1, sizeof(struct usb_handle));
++    memcpy(usb, uh, sizeof(struct usb_handle));
++    strcpy(usb->serial, uh->serial);
++
++    adb_cond_init(&usb->notify, 0);
++    adb_mutex_init(&usb->lock, 0);
++
++    adb_mutex_lock(&usb_lock);
++    
++    usb->next = &handle_list;
++    usb->prev = handle_list.prev;
++    usb->prev->next = usb;
++    usb->next->prev = usb;
++
++    adb_mutex_unlock(&usb_lock);
++
++    register_usb_transport(usb, serial, NULL, 1); 
++
++    return (1);
++}
++
++int
++already_registered(usb_handle *uh)
++{
++    struct usb_handle *usb= NULL;
++    int exists = 0;
++    
++    adb_mutex_lock(&usb_lock);
++
++    for (usb = handle_list.next; usb != &handle_list; usb = usb->next) {
++        if ((usb->dev_bus == uh->dev_bus) &&
++            (usb->dev_addr == uh->dev_addr))
++        {
++            exists = 1;
++            break;
++        }
++    }
++
++    adb_mutex_unlock(&usb_lock);
++
++    return exists;
++}
++
++void
++check_device(libusb_device *dev) 
++{
++    struct usb_handle uh;
++    int i = 0;
++    int found = -1;
++    char serial[256] = {0};
++
++    libusb_device_descriptor desc;
++    libusb_config_descriptor *config = NULL;
++    
++    int r = libusb_get_device_descriptor(dev, &desc);
++
++    if (r != LIBUSB_SUCCESS) {
++        D("check_device(): Failed to get device descriptor\n");
++        return;
++    }
++    
++    if ((desc.idVendor == 0) && (desc.idProduct == 0))
++        return;
++    
++    D("check_device(): Probing usb device %04x:%04x\n",
++        desc.idVendor, desc.idProduct);
++    
++    if (!is_adb_interface (desc.idVendor, desc.idProduct,
++                           ADB_CLASS, ADB_SUBCLASS, ADB_PROTOCOL))
++    {
++        D("check_device(): Ignored due unknown vendor id\n");
++        return;
++    }
++    
++    uh.dev_bus = libusb_get_bus_number(dev);
++    uh.dev_addr = libusb_get_device_address(dev);
++    
++    if (already_registered(&uh)) {
++        D("check_device(): Device (bus: %d, address: %d) "
++          "is already registered\n", uh.dev_bus, uh.dev_addr);
++        return;
++    }
++    
++    D("check_device(): Device bus: %d, address: %d\n",
++        uh.dev_bus, uh.dev_addr);
++
++    r = libusb_get_active_config_descriptor(dev, &config);
++    
++    if (r != 0) {
++        if (r == LIBUSB_ERROR_NOT_FOUND) {
++            D("check_device(): Device %4x:%4x is unconfigured\n", 
++                desc.idVendor, desc.idProduct);
++            return;
++        }
++        
++        D("check_device(): Failed to get configuration for %4x:%4x\n",
++            desc.idVendor, desc.idProduct);
++        return;
++    }
++    
++    if (config == NULL) {
++        D("check_device(): Sanity check failed after "
++          "getting active config\n");
++        return;
++    }
++    
++    if (config->interface != NULL) {
++        found = check_usb_interfaces(config, &desc, &uh);
++    }
++    
++    /* not needed anymore */
++    libusb_free_config_descriptor(config);
++    
++    r = libusb_open(dev, &uh.devh);
++    uh.dev = dev;
++
++    if (r != 0) {
++        switch (r) {
++            case LIBUSB_ERROR_NO_MEM:
++                D("check_device(): Memory allocation problem\n");
++                break;
++                
++            case LIBUSB_ERROR_ACCESS:
++                D("check_device(): Permissions problem, "
++                  "current user priveleges are messed up?\n");
++                break;
++                
++            case LIBUSB_ERROR_NO_DEVICE:
++                D("check_device(): Device disconected, bad cable?\n");
++                break;
++            
++            default:
++                D("check_device(): libusb triggered error %d\n", r);
++        }
++        // skip rest
++        found = -1;
++    }
++    
++    if (found >= 0) {
++        D("check_device(): Device matches Android interface\n");
++        // read the device's serial number
++        memset(serial, 0, sizeof(serial));
++        uh.interface = found;
++        
++        r = libusb_claim_interface(uh.devh, uh.interface);
++        
++        if (r < 0) {
++            D("check_device(): Failed to claim interface %d\n",
++                uh.interface);
++
++            goto fail;
++        }
++
++        if (desc.iSerialNumber) {
++            // reading serial
++            uint16_t    buffer[128] = {0};
++            uint16_t    languages[128] = {0};
++            int languageCount = 0;
++
++            memset(languages, 0, sizeof(languages));
++            r = libusb_control_transfer(uh.devh, 
++                LIBUSB_ENDPOINT_IN |  LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE,
++                LIBUSB_REQUEST_GET_DESCRIPTOR, LIBUSB_DT_STRING << 8,
++              0, (uint8_t *)languages, sizeof(languages), 0);
++
++            if (r <= 0) {
++                D("check_device(): Failed to get languages count\n");
++                goto fail;
++            } 
++            
++            languageCount = (r - 2) / 2;
++            
++            for (i = 1; i <= languageCount; ++i) {
++                memset(buffer, 0, sizeof(buffer));
++
++                r = libusb_control_transfer(uh.devh, 
++                    LIBUSB_ENDPOINT_IN |  LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE,
++                    LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_STRING << 8) | desc.iSerialNumber,
++                  languages[i], (uint8_t *)buffer, sizeof(buffer), 0);
++            
++                if (r > 0) { /* converting serial */
++                    int j = 0;
++                    r /= 2;
++                
++                    for (j = 1; j < r; ++j)
++                        serial[j - 1] = buffer[j];
++                
++                    serial[j - 1] = '\0';
++                    break; /* languagesCount cycle */
++                }
++            }
++            
++            if (register_device(&uh, serial) == 0) {
++                D("check_device(): Failed to register device\n");
++                goto fail_interface;
++            }
++            
++            libusb_ref_device(dev);
++        }
++    }
++    
++    return;
++
++fail_interface:
++    libusb_release_interface(uh.devh, uh.interface);
++
++fail:
++    libusb_close(uh.devh);
++    uh.devh = NULL;
++}
++
++int
++check_device_connected(struct usb_handle *uh)
++{
++    int r = libusb_kernel_driver_active(uh->devh, uh->interface);
++    
++    if (r == LIBUSB_ERROR_NO_DEVICE)
++        return 0;
++    
++    if (r < 0)
++        return -1;
++    
++    return 1;
++}
++
++void
++kick_disconnected()
++{
++    struct usb_handle *usb= NULL;
++    
++    adb_mutex_lock(&usb_lock);
++
++    for (usb = handle_list.next; usb != &handle_list; usb = usb->next) {
++        
++        if (check_device_connected(usb) == 0) {
++            D("kick_disconnected(): Transport %p is not online anymore\n",
++                usb);
++
++            usb_kick(usb);
++        }
++    }
++    
++    adb_mutex_unlock(&usb_lock);
++}
++
++void
++scan_usb_devices()
++{
++    D("scan_usb_devices(): started\n");
++    
++    libusb_device **devs= NULL;
++    libusb_device *dev= NULL;
++    ssize_t cnt = libusb_get_device_list(ctx, &devs);
++
++    if (cnt < 0) {
++        D("scan_usb_devices(): Failed to get device list (error: %d)\n",
++            cnt);
++
++        return;
++    }
++    
++    int i = 0;
++
++    while ((dev = devs[i++]) != NULL) {
++        check_device(dev);
++    }
++
++    libusb_free_device_list(devs, 1);
++}
++
++void *
++device_poll_thread(void* unused)
++{
++    D("device_poll_thread(): Created USB scan thread\n");
++    
++    for (;;) {
++        sleep(5);
++        kick_disconnected();
++        scan_usb_devices();
++    }
++
++    /* never reaching this point */
++    return (NULL);
++}
++
++static void
++sigalrm_handler(int signo)
++{
++    /* nothing */
++}
++
++void
++usb_init()
++{
++    D("usb_init(): started\n");
++    adb_thread_t        tid;
++    struct sigaction actions;
++
++    int r = libusb_init(&ctx);
++
++    if (r != LIBUSB_SUCCESS) {
++        err(EX_IOERR, "Failed to init libusb\n");
++    }
++
++    memset(&actions, 0, sizeof(actions));
++    
++    sigemptyset(&actions.sa_mask);
++    
++    actions.sa_flags = 0;
++    actions.sa_handler = sigalrm_handler;
++    
++    sigaction(SIGALRM, &actions, NULL);
++
++      /* initial device scan */
++      scan_usb_devices();
++      
++      /* starting USB event polling thread */
++    if (adb_thread_create(&tid, device_poll_thread, NULL)) {
++            err(EX_IOERR, "cannot create USB scan thread\n");
++    }
++    
++    D("usb_init(): finished\n");
++}
++
+Index: android-tools-4.2.2+git20130218/core/adbd/usb_linux.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/usb_linux.c      2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,715 @@
++/*
++ * Copyright (C) 2007 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++
++#include <sys/ioctl.h>
++#include <sys/types.h>
++#include <sys/time.h>
++#include <dirent.h>
++#include <fcntl.h>
++#include <errno.h>
++#include <ctype.h>
++
++#include <linux/usbdevice_fs.h>
++#include <linux/version.h>
++#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20)
++#include <linux/usb/ch9.h>
++#else
++#include <linux/usb_ch9.h>
++#endif
++#include <asm/byteorder.h>
++
++#include "sysdeps.h"
++
++#define   TRACE_TAG  TRACE_USB
++#include "adb.h"
++
++
++/* usb scan debugging is waaaay too verbose */
++#define DBGX(x...)
++
++ADB_MUTEX_DEFINE( usb_lock );
++
++struct usb_handle
++{
++    usb_handle *prev;
++    usb_handle *next;
++
++    char fname[64];
++    int desc;
++    unsigned char ep_in;
++    unsigned char ep_out;
++
++    unsigned zero_mask;
++    unsigned writeable;
++
++    struct usbdevfs_urb urb_in;
++    struct usbdevfs_urb urb_out;
++
++    int urb_in_busy;
++    int urb_out_busy;
++    int dead;
++
++    adb_cond_t notify;
++    adb_mutex_t lock;
++
++    // for garbage collecting disconnected devices
++    int mark;
++
++    // ID of thread currently in REAPURB
++    pthread_t reaper_thread;
++};
++
++static usb_handle handle_list = {
++    .prev = &handle_list,
++    .next = &handle_list,
++};
++
++static int known_device(const char *dev_name)
++{
++    usb_handle *usb;
++
++    adb_mutex_lock(&usb_lock);
++    for(usb = handle_list.next; usb != &handle_list; usb = usb->next){
++        if(!strcmp(usb->fname, dev_name)) {
++            // set mark flag to indicate this device is still alive
++            usb->mark = 1;
++            adb_mutex_unlock(&usb_lock);
++            return 1;
++        }
++    }
++    adb_mutex_unlock(&usb_lock);
++    return 0;
++}
++
++static void kick_disconnected_devices()
++{
++    usb_handle *usb;
++
++    adb_mutex_lock(&usb_lock);
++    // kick any devices in the device list that were not found in the device scan
++    for(usb = handle_list.next; usb != &handle_list; usb = usb->next){
++        if (usb->mark == 0) {
++            usb_kick(usb);
++        } else {
++            usb->mark = 0;
++        }
++    }
++    adb_mutex_unlock(&usb_lock);
++
++}
++
++static void register_device(const char *dev_name, const char *devpath,
++                            unsigned char ep_in, unsigned char ep_out,
++                            int ifc, int serial_index, unsigned zero_mask);
++
++static inline int badname(const char *name)
++{
++    while(*name) {
++        if(!isdigit(*name++)) return 1;
++    }
++    return 0;
++}
++
++static void find_usb_device(const char *base,
++        void (*register_device_callback)
++                (const char *, const char *, unsigned char, unsigned char, int, int, unsigned))
++{
++    char busname[32], devname[32];
++    unsigned char local_ep_in, local_ep_out;
++    DIR *busdir , *devdir ;
++    struct dirent *de;
++    int fd ;
++
++    busdir = opendir(base);
++    if(busdir == 0) return;
++
++    while((de = readdir(busdir)) != 0) {
++        if(badname(de->d_name)) continue;
++
++        snprintf(busname, sizeof busname, "%s/%s", base, de->d_name);
++        devdir = opendir(busname);
++        if(devdir == 0) continue;
++
++//        DBGX("[ scanning %s ]\n", busname);
++        while((de = readdir(devdir))) {
++            unsigned char devdesc[4096];
++            unsigned char* bufptr = devdesc;
++            unsigned char* bufend;
++            struct usb_device_descriptor* device;
++            struct usb_config_descriptor* config;
++            struct usb_interface_descriptor* interface;
++            struct usb_endpoint_descriptor *ep1, *ep2;
++            unsigned zero_mask = 0;
++            unsigned vid, pid;
++            size_t desclength;
++
++            if(badname(de->d_name)) continue;
++            snprintf(devname, sizeof devname, "%s/%s", busname, de->d_name);
++
++            if(known_device(devname)) {
++                DBGX("skipping %s\n", devname);
++                continue;
++            }
++
++//            DBGX("[ scanning %s ]\n", devname);
++            if((fd = unix_open(devname, O_RDONLY)) < 0) {
++                continue;
++            }
++
++            desclength = adb_read(fd, devdesc, sizeof(devdesc));
++            bufend = bufptr + desclength;
++
++                // should have device and configuration descriptors, and atleast two endpoints
++            if (desclength < USB_DT_DEVICE_SIZE + USB_DT_CONFIG_SIZE) {
++                D("desclength %d is too small\n", desclength);
++                adb_close(fd);
++                continue;
++            }
++
++            device = (struct usb_device_descriptor*)bufptr;
++            bufptr += USB_DT_DEVICE_SIZE;
++
++            if((device->bLength != USB_DT_DEVICE_SIZE) || (device->bDescriptorType != USB_DT_DEVICE)) {
++                adb_close(fd);
++                continue;
++            }
++
++            vid = device->idVendor;
++            pid = device->idProduct;
++            DBGX("[ %s is V:%04x P:%04x ]\n", devname, vid, pid);
++
++                // should have config descriptor next
++            config = (struct usb_config_descriptor *)bufptr;
++            bufptr += USB_DT_CONFIG_SIZE;
++            if (config->bLength != USB_DT_CONFIG_SIZE || config->bDescriptorType != USB_DT_CONFIG) {
++                D("usb_config_descriptor not found\n");
++                adb_close(fd);
++                continue;
++            }
++
++                // loop through all the descriptors and look for the ADB interface
++            while (bufptr < bufend) {
++                unsigned char length = bufptr[0];
++                unsigned char type = bufptr[1];
++
++                if (type == USB_DT_INTERFACE) {
++                    interface = (struct usb_interface_descriptor *)bufptr;
++                    bufptr += length;
++
++                    if (length != USB_DT_INTERFACE_SIZE) {
++                        D("interface descriptor has wrong size\n");
++                        break;
++                    }
++
++                    DBGX("bInterfaceClass: %d,  bInterfaceSubClass: %d,"
++                         "bInterfaceProtocol: %d, bNumEndpoints: %d\n",
++                         interface->bInterfaceClass, interface->bInterfaceSubClass,
++                         interface->bInterfaceProtocol, interface->bNumEndpoints);
++
++                    if (interface->bNumEndpoints == 2 &&
++                            is_adb_interface(vid, pid, interface->bInterfaceClass,
++                            interface->bInterfaceSubClass, interface->bInterfaceProtocol))  {
++
++                        struct stat st;
++                        char pathbuf[128];
++                        char link[256];
++                        char *devpath = NULL;
++
++                        DBGX("looking for bulk endpoints\n");
++                            // looks like ADB...
++                        ep1 = (struct usb_endpoint_descriptor *)bufptr;
++                        bufptr += USB_DT_ENDPOINT_SIZE;
++                        ep2 = (struct usb_endpoint_descriptor *)bufptr;
++                        bufptr += USB_DT_ENDPOINT_SIZE;
++
++                        if (bufptr > devdesc + desclength ||
++                            ep1->bLength != USB_DT_ENDPOINT_SIZE ||
++                            ep1->bDescriptorType != USB_DT_ENDPOINT ||
++                            ep2->bLength != USB_DT_ENDPOINT_SIZE ||
++                            ep2->bDescriptorType != USB_DT_ENDPOINT) {
++                            D("endpoints not found\n");
++                            break;
++                        }
++
++                            // both endpoints should be bulk
++                        if (ep1->bmAttributes != USB_ENDPOINT_XFER_BULK ||
++                            ep2->bmAttributes != USB_ENDPOINT_XFER_BULK) {
++                            D("bulk endpoints not found\n");
++                            continue;
++                        }
++                            /* aproto 01 needs 0 termination */
++                        if(interface->bInterfaceProtocol == 0x01) {
++                            zero_mask = ep1->wMaxPacketSize - 1;
++                        }
++
++                            // we have a match.  now we just need to figure out which is in and which is out.
++                        if (ep1->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
++                            local_ep_in = ep1->bEndpointAddress;
++                            local_ep_out = ep2->bEndpointAddress;
++                        } else {
++                            local_ep_in = ep2->bEndpointAddress;
++                            local_ep_out = ep1->bEndpointAddress;
++                        }
++
++                            // Determine the device path
++                        if (!fstat(fd, &st) && S_ISCHR(st.st_mode)) {
++                            char *slash;
++                            ssize_t link_len;
++                            snprintf(pathbuf, sizeof(pathbuf), "/sys/dev/char/%d:%d",
++                                     major(st.st_rdev), minor(st.st_rdev));
++                            link_len = readlink(pathbuf, link, sizeof(link) - 1);
++                            if (link_len > 0) {
++                                link[link_len] = '\0';
++                                slash = strrchr(link, '/');
++                                if (slash) {
++                                    snprintf(pathbuf, sizeof(pathbuf),
++                                             "usb:%s", slash + 1);
++                                    devpath = pathbuf;
++                                }
++                            }
++                        }
++
++                        register_device_callback(devname, devpath,
++                                local_ep_in, local_ep_out,
++                                interface->bInterfaceNumber, device->iSerialNumber, zero_mask);
++                        break;
++                    }
++                } else {
++                    bufptr += length;
++                }
++            } // end of while
++
++            adb_close(fd);
++        } // end of devdir while
++        closedir(devdir);
++    } //end of busdir while
++    closedir(busdir);
++}
++
++void usb_cleanup()
++{
++}
++
++static int usb_bulk_write(usb_handle *h, const void *data, int len)
++{
++    struct usbdevfs_urb *urb = &h->urb_out;
++    int res;
++    struct timeval tv;
++    struct timespec ts;
++
++    memset(urb, 0, sizeof(*urb));
++    urb->type = USBDEVFS_URB_TYPE_BULK;
++    urb->endpoint = h->ep_out;
++    urb->status = -1;
++    urb->buffer = (void*) data;
++    urb->buffer_length = len;
++
++    D("++ write ++\n");
++
++    adb_mutex_lock(&h->lock);
++    if(h->dead) {
++        res = -1;
++        goto fail;
++    }
++    do {
++        res = ioctl(h->desc, USBDEVFS_SUBMITURB, urb);
++    } while((res < 0) && (errno == EINTR));
++
++    if(res < 0) {
++        goto fail;
++    }
++
++    res = -1;
++    h->urb_out_busy = 1;
++    for(;;) {
++        /* time out after five seconds */
++        gettimeofday(&tv, NULL);
++        ts.tv_sec = tv.tv_sec + 5;
++        ts.tv_nsec = tv.tv_usec * 1000L;
++        res = pthread_cond_timedwait(&h->notify, &h->lock, &ts);
++        if(res < 0 || h->dead) {
++            break;
++        }
++        if(h->urb_out_busy == 0) {
++            if(urb->status == 0) {
++                res = urb->actual_length;
++            }
++            break;
++        }
++    }
++fail:
++    adb_mutex_unlock(&h->lock);
++    D("-- write --\n");
++    return res;
++}
++
++static int usb_bulk_read(usb_handle *h, void *data, int len)
++{
++    struct usbdevfs_urb *urb = &h->urb_in;
++    struct usbdevfs_urb *out = NULL;
++    int res;
++
++    memset(urb, 0, sizeof(*urb));
++    urb->type = USBDEVFS_URB_TYPE_BULK;
++    urb->endpoint = h->ep_in;
++    urb->status = -1;
++    urb->buffer = data;
++    urb->buffer_length = len;
++
++
++    adb_mutex_lock(&h->lock);
++    if(h->dead) {
++        res = -1;
++        goto fail;
++    }
++    do {
++        res = ioctl(h->desc, USBDEVFS_SUBMITURB, urb);
++    } while((res < 0) && (errno == EINTR));
++
++    if(res < 0) {
++        goto fail;
++    }
++
++    h->urb_in_busy = 1;
++    for(;;) {
++        D("[ reap urb - wait ]\n");
++        h->reaper_thread = pthread_self();
++        adb_mutex_unlock(&h->lock);
++        res = ioctl(h->desc, USBDEVFS_REAPURB, &out);
++        int saved_errno = errno;
++        adb_mutex_lock(&h->lock);
++        h->reaper_thread = 0;
++        if(h->dead) {
++            res = -1;
++            break;
++        }
++        if(res < 0) {
++            if(saved_errno == EINTR) {
++                continue;
++            }
++            D("[ reap urb - error ]\n");
++            break;
++        }
++        D("[ urb @%p status = %d, actual = %d ]\n",
++            out, out->status, out->actual_length);
++
++        if(out == &h->urb_in) {
++            D("[ reap urb - IN complete ]\n");
++            h->urb_in_busy = 0;
++            if(urb->status == 0) {
++                res = urb->actual_length;
++            } else {
++                res = -1;
++            }
++            break;
++        }
++        if(out == &h->urb_out) {
++            D("[ reap urb - OUT compelete ]\n");
++            h->urb_out_busy = 0;
++            adb_cond_broadcast(&h->notify);
++        }
++    }
++fail:
++    adb_mutex_unlock(&h->lock);
++    return res;
++}
++
++
++int usb_write(usb_handle *h, const void *_data, int len)
++{
++    unsigned char *data = (unsigned char*) _data;
++    int n;
++    int need_zero = 0;
++
++    if(h->zero_mask) {
++            /* if we need 0-markers and our transfer
++            ** is an even multiple of the packet size,
++            ** we make note of it
++            */
++        if(!(len & h->zero_mask)) {
++            need_zero = 1;
++        }
++    }
++
++    while(len > 0) {
++        int xfer = (len > 4096) ? 4096 : len;
++
++        n = usb_bulk_write(h, data, xfer);
++        if(n != xfer) {
++            D("ERROR: n = %d, errno = %d (%s)\n",
++                n, errno, strerror(errno));
++            return -1;
++        }
++
++        len -= xfer;
++        data += xfer;
++    }
++
++    if(need_zero){
++        n = usb_bulk_write(h, _data, 0);
++        return n;
++    }
++
++    return 0;
++}
++
++int usb_read(usb_handle *h, void *_data, int len)
++{
++    unsigned char *data = (unsigned char*) _data;
++    int n;
++
++    D("++ usb_read ++\n");
++    while(len > 0) {
++        int xfer = (len > 4096) ? 4096 : len;
++
++        D("[ usb read %d fd = %d], fname=%s\n", xfer, h->desc, h->fname);
++        n = usb_bulk_read(h, data, xfer);
++        D("[ usb read %d ] = %d, fname=%s\n", xfer, n, h->fname);
++        if(n != xfer) {
++            if((errno == ETIMEDOUT) && (h->desc != -1)) {
++                D("[ timeout ]\n");
++                if(n > 0){
++                    data += n;
++                    len -= n;
++                }
++                continue;
++            }
++            D("ERROR: n = %d, errno = %d (%s)\n",
++                n, errno, strerror(errno));
++            return -1;
++        }
++
++        len -= xfer;
++        data += xfer;
++    }
++
++    D("-- usb_read --\n");
++    return 0;
++}
++
++void usb_kick(usb_handle *h)
++{
++    D("[ kicking %p (fd = %d) ]\n", h, h->desc);
++    adb_mutex_lock(&h->lock);
++    if(h->dead == 0) {
++        h->dead = 1;
++
++        if (h->writeable) {
++            /* HACK ALERT!
++            ** Sometimes we get stuck in ioctl(USBDEVFS_REAPURB).
++            ** This is a workaround for that problem.
++            */
++            if (h->reaper_thread) {
++                pthread_kill(h->reaper_thread, SIGALRM);
++            }
++
++            /* cancel any pending transactions
++            ** these will quietly fail if the txns are not active,
++            ** but this ensures that a reader blocked on REAPURB
++            ** will get unblocked
++            */
++            ioctl(h->desc, USBDEVFS_DISCARDURB, &h->urb_in);
++            ioctl(h->desc, USBDEVFS_DISCARDURB, &h->urb_out);
++            h->urb_in.status = -ENODEV;
++            h->urb_out.status = -ENODEV;
++            h->urb_in_busy = 0;
++            h->urb_out_busy = 0;
++            adb_cond_broadcast(&h->notify);
++        } else {
++            unregister_usb_transport(h);
++        }
++    }
++    adb_mutex_unlock(&h->lock);
++}
++
++int usb_close(usb_handle *h)
++{
++    D("[ usb close ... ]\n");
++    adb_mutex_lock(&usb_lock);
++    h->next->prev = h->prev;
++    h->prev->next = h->next;
++    h->prev = 0;
++    h->next = 0;
++
++    adb_close(h->desc);
++    D("[ usb closed %p (fd = %d) ]\n", h, h->desc);
++    adb_mutex_unlock(&usb_lock);
++
++    free(h);
++    return 0;
++}
++
++static void register_device(const char *dev_name, const char *devpath,
++                            unsigned char ep_in, unsigned char ep_out,
++                            int interface, int serial_index, unsigned zero_mask)
++{
++    usb_handle* usb = 0;
++    int n = 0;
++    char serial[256];
++
++        /* Since Linux will not reassign the device ID (and dev_name)
++        ** as long as the device is open, we can add to the list here
++        ** once we open it and remove from the list when we're finally
++        ** closed and everything will work out fine.
++        **
++        ** If we have a usb_handle on the list 'o handles with a matching
++        ** name, we have no further work to do.
++        */
++    adb_mutex_lock(&usb_lock);
++    for(usb = handle_list.next; usb != &handle_list; usb = usb->next){
++        if(!strcmp(usb->fname, dev_name)) {
++            adb_mutex_unlock(&usb_lock);
++            return;
++        }
++    }
++    adb_mutex_unlock(&usb_lock);
++
++    D("[ usb located new device %s (%d/%d/%d) ]\n",
++        dev_name, ep_in, ep_out, interface);
++    usb = calloc(1, sizeof(usb_handle));
++    strcpy(usb->fname, dev_name);
++    usb->ep_in = ep_in;
++    usb->ep_out = ep_out;
++    usb->zero_mask = zero_mask;
++    usb->writeable = 1;
++
++    adb_cond_init(&usb->notify, 0);
++    adb_mutex_init(&usb->lock, 0);
++    /* initialize mark to 1 so we don't get garbage collected after the device scan */
++    usb->mark = 1;
++    usb->reaper_thread = 0;
++
++    usb->desc = unix_open(usb->fname, O_RDWR);
++    if(usb->desc < 0) {
++        /* if we fail, see if have read-only access */
++        usb->desc = unix_open(usb->fname, O_RDONLY);
++        if(usb->desc < 0) goto fail;
++        usb->writeable = 0;
++        D("[ usb open read-only %s fd = %d]\n", usb->fname, usb->desc);
++    } else {
++        D("[ usb open %s fd = %d]\n", usb->fname, usb->desc);
++        n = ioctl(usb->desc, USBDEVFS_CLAIMINTERFACE, &interface);
++        if(n != 0) goto fail;
++    }
++
++        /* read the device's serial number */
++    serial[0] = 0;
++    memset(serial, 0, sizeof(serial));
++    if (serial_index) {
++        struct usbdevfs_ctrltransfer  ctrl;
++        __u16 buffer[128];
++        __u16 languages[128];
++        int i, result;
++        int languageCount = 0;
++
++        memset(languages, 0, sizeof(languages));
++        memset(&ctrl, 0, sizeof(ctrl));
++
++            // read list of supported languages
++        ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
++        ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
++        ctrl.wValue = (USB_DT_STRING << 8) | 0;
++        ctrl.wIndex = 0;
++        ctrl.wLength = sizeof(languages);
++        ctrl.data = languages;
++        ctrl.timeout = 1000;
++
++        result = ioctl(usb->desc, USBDEVFS_CONTROL, &ctrl);
++        if (result > 0)
++            languageCount = (result - 2) / 2;
++
++        for (i = 1; i <= languageCount; i++) {
++            memset(buffer, 0, sizeof(buffer));
++            memset(&ctrl, 0, sizeof(ctrl));
++
++            ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
++            ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
++            ctrl.wValue = (USB_DT_STRING << 8) | serial_index;
++            ctrl.wIndex = __le16_to_cpu(languages[i]);
++            ctrl.wLength = sizeof(buffer);
++            ctrl.data = buffer;
++            ctrl.timeout = 1000;
++
++            result = ioctl(usb->desc, USBDEVFS_CONTROL, &ctrl);
++            if (result > 0) {
++                int i;
++                // skip first word, and copy the rest to the serial string, changing shorts to bytes.
++                result /= 2;
++                for (i = 1; i < result; i++)
++                    serial[i - 1] = __le16_to_cpu(buffer[i]);
++                serial[i - 1] = 0;
++                break;
++            }
++        }
++    }
++
++        /* add to the end of the active handles */
++    adb_mutex_lock(&usb_lock);
++    usb->next = &handle_list;
++    usb->prev = handle_list.prev;
++    usb->prev->next = usb;
++    usb->next->prev = usb;
++    adb_mutex_unlock(&usb_lock);
++
++    register_usb_transport(usb, serial, devpath, usb->writeable);
++    return;
++
++fail:
++    D("[ usb open %s error=%d, err_str = %s]\n",
++        usb->fname,  errno, strerror(errno));
++    if(usb->desc >= 0) {
++        adb_close(usb->desc);
++    }
++    free(usb);
++}
++
++void* device_poll_thread(void* unused)
++{
++    D("Created device thread\n");
++    for(;;) {
++            /* XXX use inotify */
++        find_usb_device("/dev/bus/usb", register_device);
++        kick_disconnected_devices();
++        sleep(1);
++    }
++    return NULL;
++}
++
++static void sigalrm_handler(int signo)
++{
++    // don't need to do anything here
++}
++
++void usb_init()
++{
++    adb_thread_t tid;
++    struct sigaction    actions;
++
++    memset(&actions, 0, sizeof(actions));
++    sigemptyset(&actions.sa_mask);
++    actions.sa_flags = 0;
++    actions.sa_handler = sigalrm_handler;
++    sigaction(SIGALRM,& actions, NULL);
++
++    if(adb_thread_create(&tid, device_poll_thread, NULL)){
++        fatal_errno("cannot create input thread");
++    }
++}
+Index: android-tools-4.2.2+git20130218/core/adbd/usb_linux_client.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/usb_linux_client.c       2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,492 @@
++/*
++ * Copyright (C) 2007 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++
++#include <linux/usb/ch9.h>
++#include <linux/usb/functionfs.h>
++#include <sys/ioctl.h>
++#include <sys/types.h>
++#include <dirent.h>
++#include <errno.h>
++
++#include "sysdeps.h"
++
++#define   TRACE_TAG  TRACE_USB
++#include "adb.h"
++
++#define MAX_PACKET_SIZE_FS    64
++#define MAX_PACKET_SIZE_HS    512
++
++#define cpu_to_le16(x)  htole16(x)
++#define cpu_to_le32(x)  htole32(x)
++
++struct usb_handle
++{
++    adb_cond_t notify;
++    adb_mutex_t lock;
++
++    int (*write)(usb_handle *h, const void *data, int len);
++    int (*read)(usb_handle *h, void *data, int len);
++    void (*kick)(usb_handle *h);
++
++    // Legacy f_adb
++    int fd;
++
++    // FunctionFS
++    int control;
++    int bulk_out; /* "out" from the host's perspective => source for adbd */
++    int bulk_in;  /* "in" from the host's perspective => sink for adbd */
++};
++
++static const struct {
++    struct usb_functionfs_descs_head header;
++    struct {
++        struct usb_interface_descriptor intf;
++        struct usb_endpoint_descriptor_no_audio source;
++        struct usb_endpoint_descriptor_no_audio sink;
++    } __attribute__((packed)) fs_descs, hs_descs;
++} __attribute__((packed)) descriptors = {
++    .header = {
++        .magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC),
++        .length = cpu_to_le32(sizeof(descriptors)),
++        .fs_count = 3,
++        .hs_count = 3,
++    },
++    .fs_descs = {
++        .intf = {
++            .bLength = sizeof(descriptors.fs_descs.intf),
++            .bDescriptorType = USB_DT_INTERFACE,
++            .bInterfaceNumber = 0,
++            .bNumEndpoints = 2,
++            .bInterfaceClass = ADB_CLASS,
++            .bInterfaceSubClass = ADB_SUBCLASS,
++            .bInterfaceProtocol = ADB_PROTOCOL,
++            .iInterface = 1, /* first string from the provided table */
++        },
++        .source = {
++            .bLength = sizeof(descriptors.fs_descs.source),
++            .bDescriptorType = USB_DT_ENDPOINT,
++            .bEndpointAddress = 1 | USB_DIR_OUT,
++            .bmAttributes = USB_ENDPOINT_XFER_BULK,
++            .wMaxPacketSize = MAX_PACKET_SIZE_FS,
++        },
++        .sink = {
++            .bLength = sizeof(descriptors.fs_descs.sink),
++            .bDescriptorType = USB_DT_ENDPOINT,
++            .bEndpointAddress = 2 | USB_DIR_IN,
++            .bmAttributes = USB_ENDPOINT_XFER_BULK,
++            .wMaxPacketSize = MAX_PACKET_SIZE_FS,
++        },
++    },
++    .hs_descs = {
++        .intf = {
++            .bLength = sizeof(descriptors.hs_descs.intf),
++            .bDescriptorType = USB_DT_INTERFACE,
++            .bInterfaceNumber = 0,
++            .bNumEndpoints = 2,
++            .bInterfaceClass = ADB_CLASS,
++            .bInterfaceSubClass = ADB_SUBCLASS,
++            .bInterfaceProtocol = ADB_PROTOCOL,
++            .iInterface = 1, /* first string from the provided table */
++        },
++        .source = {
++            .bLength = sizeof(descriptors.hs_descs.source),
++            .bDescriptorType = USB_DT_ENDPOINT,
++            .bEndpointAddress = 1 | USB_DIR_OUT,
++            .bmAttributes = USB_ENDPOINT_XFER_BULK,
++            .wMaxPacketSize = MAX_PACKET_SIZE_HS,
++        },
++        .sink = {
++            .bLength = sizeof(descriptors.hs_descs.sink),
++            .bDescriptorType = USB_DT_ENDPOINT,
++            .bEndpointAddress = 2 | USB_DIR_IN,
++            .bmAttributes = USB_ENDPOINT_XFER_BULK,
++            .wMaxPacketSize = MAX_PACKET_SIZE_HS,
++        },
++    },
++};
++
++#define STR_INTERFACE_ "ADB Interface"
++
++static const struct {
++    struct usb_functionfs_strings_head header;
++    struct {
++        __le16 code;
++        const char str1[sizeof(STR_INTERFACE_)];
++    } __attribute__((packed)) lang0;
++} __attribute__((packed)) strings = {
++    .header = {
++        .magic = cpu_to_le32(FUNCTIONFS_STRINGS_MAGIC),
++        .length = cpu_to_le32(sizeof(strings)),
++        .str_count = cpu_to_le32(1),
++        .lang_count = cpu_to_le32(1),
++    },
++    .lang0 = {
++        cpu_to_le16(0x0409), /* en-us */
++        STR_INTERFACE_,
++    },
++};
++
++
++
++static void *usb_adb_open_thread(void *x)
++{
++    struct usb_handle *usb = (struct usb_handle *)x;
++    int fd;
++
++    while (1) {
++        // wait until the USB device needs opening
++        adb_mutex_lock(&usb->lock);
++        while (usb->fd != -1)
++            adb_cond_wait(&usb->notify, &usb->lock);
++        adb_mutex_unlock(&usb->lock);
++
++        D("[ usb_thread - opening device ]\n");
++        do {
++            /* XXX use inotify? */
++            fd = unix_open("/dev/android_adb", O_RDWR);
++            if (fd < 0) {
++                // to support older kernels
++                fd = unix_open("/dev/android", O_RDWR);
++            }
++            if (fd < 0) {
++                adb_sleep_ms(1000);
++            }
++        } while (fd < 0);
++        D("[ opening device succeeded ]\n");
++
++        close_on_exec(fd);
++        usb->fd = fd;
++
++        D("[ usb_thread - registering device ]\n");
++        register_usb_transport(usb, 0, 0, 1);
++    }
++
++    // never gets here
++    return 0;
++}
++
++static int usb_adb_write(usb_handle *h, const void *data, int len)
++{
++    int n;
++
++    D("about to write (fd=%d, len=%d)\n", h->fd, len);
++    n = adb_write(h->fd, data, len);
++    if(n != len) {
++        D("ERROR: fd = %d, n = %d, errno = %d (%s)\n",
++            h->fd, n, errno, strerror(errno));
++        return -1;
++    }
++    D("[ done fd=%d ]\n", h->fd);
++    return 0;
++}
++
++static int usb_adb_read(usb_handle *h, void *data, int len)
++{
++    int n;
++
++    D("about to read (fd=%d, len=%d)\n", h->fd, len);
++    n = adb_read(h->fd, data, len);
++    if(n != len) {
++        D("ERROR: fd = %d, n = %d, errno = %d (%s)\n",
++            h->fd, n, errno, strerror(errno));
++        return -1;
++    }
++    D("[ done fd=%d ]\n", h->fd);
++    return 0;
++}
++
++static void usb_adb_kick(usb_handle *h)
++{
++    D("usb_kick\n");
++    adb_mutex_lock(&h->lock);
++    adb_close(h->fd);
++    h->fd = -1;
++
++    // notify usb_adb_open_thread that we are disconnected
++    adb_cond_signal(&h->notify);
++    adb_mutex_unlock(&h->lock);
++}
++
++static void usb_adb_init()
++{
++    usb_handle *h;
++    adb_thread_t tid;
++    int fd;
++
++    h = calloc(1, sizeof(usb_handle));
++
++    h->write = usb_adb_write;
++    h->read = usb_adb_read;
++    h->kick = usb_adb_kick;
++    h->fd = -1;
++
++    adb_cond_init(&h->notify, 0);
++    adb_mutex_init(&h->lock, 0);
++
++    // Open the file /dev/android_adb_enable to trigger 
++    // the enabling of the adb USB function in the kernel.
++    // We never touch this file again - just leave it open
++    // indefinitely so the kernel will know when we are running
++    // and when we are not.
++    fd = unix_open("/dev/android_adb_enable", O_RDWR);
++    if (fd < 0) {
++       D("failed to open /dev/android_adb_enable\n");
++    } else {
++        close_on_exec(fd);
++    }
++
++    D("[ usb_init - starting thread ]\n");
++    if(adb_thread_create(&tid, usb_adb_open_thread, h)){
++        fatal_errno("cannot create usb thread");
++    }
++}
++
++
++static void init_functionfs(struct usb_handle *h)
++{
++    ssize_t ret;
++
++    D("OPENING %s\n", USB_FFS_ADB_EP0);
++    h->control = adb_open(USB_FFS_ADB_EP0, O_RDWR);
++    if (h->control < 0) {
++        D("[ %s: cannot open control endpoint: errno=%d]\n", USB_FFS_ADB_EP0, errno);
++        goto err;
++    }
++
++    ret = adb_write(h->control, &descriptors, sizeof(descriptors));
++    if (ret < 0) {
++        D("[ %s: write descriptors failed: errno=%d ]\n", USB_FFS_ADB_EP0, errno);
++        goto err;
++    }
++
++    ret = adb_write(h->control, &strings, sizeof(strings));
++    if (ret < 0) {
++        D("[ %s: writing strings failed: errno=%d]\n", USB_FFS_ADB_EP0, errno);
++        goto err;
++    }
++
++    h->bulk_out = adb_open(USB_FFS_ADB_OUT, O_RDWR);
++    if (h->bulk_out < 0) {
++        D("[ %s: cannot open bulk-out ep: errno=%d ]\n", USB_FFS_ADB_OUT, errno);
++        goto err;
++    }
++
++    h->bulk_in = adb_open(USB_FFS_ADB_IN, O_RDWR);
++    if (h->bulk_in < 0) {
++        D("[ %s: cannot open bulk-in ep: errno=%d ]\n", USB_FFS_ADB_IN, errno);
++        goto err;
++    }
++
++    return;
++
++err:
++    if (h->bulk_in > 0) {
++        adb_close(h->bulk_in);
++        h->bulk_in = -1;
++    }
++    if (h->bulk_out > 0) {
++        adb_close(h->bulk_out);
++        h->bulk_out = -1;
++    }
++    if (h->control > 0) {
++        adb_close(h->control);
++        h->control = -1;
++    }
++    return;
++}
++
++static void *usb_ffs_open_thread(void *x)
++{
++    struct usb_handle *usb = (struct usb_handle *)x;
++
++    while (1) {
++        // wait until the USB device needs opening
++        adb_mutex_lock(&usb->lock);
++        while (usb->control != -1)
++            adb_cond_wait(&usb->notify, &usb->lock);
++        adb_mutex_unlock(&usb->lock);
++
++        while (1) {
++            init_functionfs(usb);
++
++            if (usb->control >= 0)
++                break;
++
++            adb_sleep_ms(1000);
++        }
++
++        D("[ usb_thread - registering device ]\n");
++        register_usb_transport(usb, 0, 0, 1);
++    }
++
++    // never gets here
++    return 0;
++}
++
++static int bulk_write(int bulk_in, const char *buf, size_t length)
++{
++    size_t count = 0;
++    int ret;
++
++    do {
++        ret = adb_write(bulk_in, buf + count, length - count);
++        if (ret < 0) {
++            if (errno != EINTR)
++                return ret;
++        } else {
++            count += ret;
++        }
++    } while (count < length);
++
++    D("[ bulk_write done fd=%d ]\n", bulk_in);
++    return count;
++}
++
++static int usb_ffs_write(usb_handle *h, const void *data, int len)
++{
++    int n;
++
++    D("about to write (fd=%d, len=%d)\n", h->bulk_in, len);
++    n = bulk_write(h->bulk_in, data, len);
++    if (n != len) {
++        D("ERROR: fd = %d, n = %d, errno = %d (%s)\n",
++            h->bulk_in, n, errno, strerror(errno));
++        return -1;
++    }
++    D("[ done fd=%d ]\n", h->bulk_in);
++    return 0;
++}
++
++static int bulk_read(int bulk_out, char *buf, size_t length)
++{
++    size_t count = 0;
++    int ret;
++
++    do {
++        ret = adb_read(bulk_out, buf + count, length - count);
++        if (ret < 0) {
++            if (errno != EINTR) {
++                D("[ bulk_read failed fd=%d length=%d count=%d ]\n",
++                                           bulk_out, length, count);
++                return ret;
++            }
++        } else {
++            count += ret;
++        }
++    } while (count < length);
++
++    return count;
++}
++
++static int usb_ffs_read(usb_handle *h, void *data, int len)
++{
++    int n;
++
++    D("about to read (fd=%d, len=%d)\n", h->bulk_out, len);
++    n = bulk_read(h->bulk_out, data, len);
++    if (n != len) {
++        D("ERROR: fd = %d, n = %d, errno = %d (%s)\n",
++            h->bulk_out, n, errno, strerror(errno));
++        return -1;
++    }
++    D("[ done fd=%d ]\n", h->bulk_out);
++    return 0;
++}
++
++static void usb_ffs_kick(usb_handle *h)
++{
++    int err;
++
++    err = ioctl(h->bulk_in, FUNCTIONFS_CLEAR_HALT);
++    if (err < 0)
++        D("[ kick: source (fd=%d) clear halt failed (%d) ]", h->bulk_in, errno);
++
++    err = ioctl(h->bulk_out, FUNCTIONFS_CLEAR_HALT);
++    if (err < 0)
++        D("[ kick: sink (fd=%d) clear halt failed (%d) ]", h->bulk_out, errno);
++
++    adb_mutex_lock(&h->lock);
++    adb_close(h->control);
++    adb_close(h->bulk_out);
++    adb_close(h->bulk_in);
++    h->control = h->bulk_out = h->bulk_in = -1;
++
++    // notify usb_ffs_open_thread that we are disconnected
++    adb_cond_signal(&h->notify);
++    adb_mutex_unlock(&h->lock);
++}
++
++static void usb_ffs_init()
++{
++    usb_handle *h;
++    adb_thread_t tid;
++
++    D("[ usb_init - using FunctionFS ]\n");
++
++    h = calloc(1, sizeof(usb_handle));
++
++    h->write = usb_ffs_write;
++    h->read = usb_ffs_read;
++    h->kick = usb_ffs_kick;
++
++    h->control  = -1;
++    h->bulk_out = -1;
++    h->bulk_out = -1;
++
++    adb_cond_init(&h->notify, 0);
++    adb_mutex_init(&h->lock, 0);
++
++    D("[ usb_init - starting thread ]\n");
++    if (adb_thread_create(&tid, usb_ffs_open_thread, h)){
++        fatal_errno("[ cannot create usb thread ]\n");
++    }
++}
++
++void usb_init()
++{
++    if (access(USB_FFS_ADB_EP0, F_OK) == 0)
++        usb_ffs_init();
++    else
++        usb_adb_init();
++}
++
++void usb_cleanup()
++{
++}
++
++int usb_write(usb_handle *h, const void *data, int len)
++{
++    return h->write(h, data, len);
++}
++
++int usb_read(usb_handle *h, void *data, int len)
++{
++    return h->read(h, data, len);
++}
++int usb_close(usb_handle *h)
++{
++    return 0;
++}
++
++void usb_kick(usb_handle *h)
++{
++    h->kick(h);
++}
+Index: android-tools-4.2.2+git20130218/core/adbd/usb_osx.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/usb_osx.c        2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,545 @@
++/*
++ * Copyright (C) 2007 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include <CoreFoundation/CoreFoundation.h>
++
++#include <IOKit/IOKitLib.h>
++#include <IOKit/IOCFPlugIn.h>
++#include <IOKit/usb/IOUSBLib.h>
++#include <IOKit/IOMessage.h>
++#include <mach/mach_port.h>
++
++#include "sysdeps.h"
++
++#include <stdio.h>
++
++#define TRACE_TAG   TRACE_USB
++#include "adb.h"
++#include "usb_vendors.h"
++
++#define  DBG   D
++
++static IONotificationPortRef    notificationPort = 0;
++static io_iterator_t*           notificationIterators;
++
++struct usb_handle
++{
++    UInt8                     bulkIn;
++    UInt8                     bulkOut;
++    IOUSBInterfaceInterface   **interface;
++    io_object_t               usbNotification;
++    unsigned int              zero_mask;
++};
++
++static CFRunLoopRef currentRunLoop = 0;
++static pthread_mutex_t start_lock;
++static pthread_cond_t start_cond;
++
++
++static void AndroidInterfaceAdded(void *refCon, io_iterator_t iterator);
++static void AndroidInterfaceNotify(void *refCon, io_iterator_t iterator,
++                                   natural_t messageType,
++                                   void *messageArgument);
++static usb_handle* CheckInterface(IOUSBInterfaceInterface **iface,
++                                  UInt16 vendor, UInt16 product);
++
++static int
++InitUSB()
++{
++    CFMutableDictionaryRef  matchingDict;
++    CFRunLoopSourceRef      runLoopSource;
++    SInt32                  vendor, if_subclass, if_protocol;
++    unsigned                i;
++
++    //* To set up asynchronous notifications, create a notification port and
++    //* add its run loop event source to the program's run loop
++    notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
++    runLoopSource = IONotificationPortGetRunLoopSource(notificationPort);
++    CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode);
++
++    memset(notificationIterators, 0, sizeof(notificationIterators));
++
++    //* loop through all supported vendors
++    for (i = 0; i < vendorIdCount; i++) {
++        //* Create our matching dictionary to find the Android device's
++        //* adb interface
++        //* IOServiceAddMatchingNotification consumes the reference, so we do
++        //* not need to release this
++        matchingDict = IOServiceMatching(kIOUSBInterfaceClassName);
++
++        if (!matchingDict) {
++            DBG("ERR: Couldn't create USB matching dictionary.\n");
++            return -1;
++        }
++
++        //* Match based on vendor id, interface subclass and protocol
++        vendor = vendorIds[i];
++        if_subclass = ADB_SUBCLASS;
++        if_protocol = ADB_PROTOCOL;
++        CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorID),
++                             CFNumberCreate(kCFAllocatorDefault,
++                                            kCFNumberSInt32Type, &vendor));
++        CFDictionarySetValue(matchingDict, CFSTR(kUSBInterfaceSubClass),
++                             CFNumberCreate(kCFAllocatorDefault,
++                                            kCFNumberSInt32Type, &if_subclass));
++        CFDictionarySetValue(matchingDict, CFSTR(kUSBInterfaceProtocol),
++                             CFNumberCreate(kCFAllocatorDefault,
++                                            kCFNumberSInt32Type, &if_protocol));
++        IOServiceAddMatchingNotification(
++                notificationPort,
++                kIOFirstMatchNotification,
++                matchingDict,
++                AndroidInterfaceAdded,
++                NULL,
++                &notificationIterators[i]);
++
++        //* Iterate over set of matching interfaces to access already-present
++        //* devices and to arm the notification
++        AndroidInterfaceAdded(NULL, notificationIterators[i]);
++    }
++
++    return 0;
++}
++
++static void
++AndroidInterfaceAdded(void *refCon, io_iterator_t iterator)
++{
++    kern_return_t            kr;
++    io_service_t             usbDevice;
++    io_service_t             usbInterface;
++    IOCFPlugInInterface      **plugInInterface = NULL;
++    IOUSBInterfaceInterface220  **iface = NULL;
++    IOUSBDeviceInterface197  **dev = NULL;
++    HRESULT                  result;
++    SInt32                   score;
++    UInt32                   locationId;
++    UInt16                   vendor;
++    UInt16                   product;
++    UInt8                    serialIndex;
++    char                     serial[256];
++    char                     devpathBuf[64];
++    char                     *devpath = NULL;
++
++    while ((usbInterface = IOIteratorNext(iterator))) {
++        //* Create an intermediate interface plugin
++        kr = IOCreatePlugInInterfaceForService(usbInterface,
++                                               kIOUSBInterfaceUserClientTypeID,
++                                               kIOCFPlugInInterfaceID,
++                                               &plugInInterface, &score);
++        IOObjectRelease(usbInterface);
++        if ((kIOReturnSuccess != kr) || (!plugInInterface)) {
++            DBG("ERR: Unable to create an interface plug-in (%08x)\n", kr);
++            continue;
++        }
++
++        //* This gets us the interface object
++        result = (*plugInInterface)->QueryInterface(plugInInterface,
++                CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID)
++                &iface);
++        //* We only needed the plugin to get the interface, so discard it
++        (*plugInInterface)->Release(plugInInterface);
++        if (result || !iface) {
++            DBG("ERR: Couldn't query the interface (%08x)\n", (int) result);
++            continue;
++        }
++
++        //* this gets us an ioservice, with which we will find the actual
++        //* device; after getting a plugin, and querying the interface, of
++        //* course.
++        //* Gotta love OS X
++        kr = (*iface)->GetDevice(iface, &usbDevice);
++        if (kIOReturnSuccess != kr || !usbDevice) {
++            DBG("ERR: Couldn't grab device from interface (%08x)\n", kr);
++            continue;
++        }
++
++        plugInInterface = NULL;
++        score = 0;
++        //* create an intermediate device plugin
++        kr = IOCreatePlugInInterfaceForService(usbDevice,
++                                               kIOUSBDeviceUserClientTypeID,
++                                               kIOCFPlugInInterfaceID,
++                                               &plugInInterface, &score);
++        //* only needed this to find the plugin
++        (void)IOObjectRelease(usbDevice);
++        if ((kIOReturnSuccess != kr) || (!plugInInterface)) {
++            DBG("ERR: Unable to create a device plug-in (%08x)\n", kr);
++            continue;
++        }
++
++        result = (*plugInInterface)->QueryInterface(plugInInterface,
++                CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID) &dev);
++        //* only needed this to query the plugin
++        (*plugInInterface)->Release(plugInInterface);
++        if (result || !dev) {
++            DBG("ERR: Couldn't create a device interface (%08x)\n",
++                (int) result);
++            continue;
++        }
++
++        //* Now after all that, we actually have a ref to the device and
++        //* the interface that matched our criteria
++
++        kr = (*dev)->GetDeviceVendor(dev, &vendor);
++        kr = (*dev)->GetDeviceProduct(dev, &product);
++        kr = (*dev)->GetLocationID(dev, &locationId);
++        if (kr == 0) {
++            snprintf(devpathBuf, sizeof(devpathBuf), "usb:%lX", locationId);
++            devpath = devpathBuf;
++        }
++        kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex);
++
++      if (serialIndex > 0) {
++              IOUSBDevRequest req;
++              UInt16          buffer[256];
++              UInt16          languages[128];
++
++              memset(languages, 0, sizeof(languages));
++
++              req.bmRequestType =
++                      USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
++              req.bRequest = kUSBRqGetDescriptor;
++              req.wValue = (kUSBStringDesc << 8) | 0;
++              req.wIndex = 0;
++              req.pData = languages;
++              req.wLength = sizeof(languages);
++              kr = (*dev)->DeviceRequest(dev, &req);
++
++              if (kr == kIOReturnSuccess && req.wLenDone > 0) {
++
++                      int langCount = (req.wLenDone - 2) / 2, lang;
++
++                      for (lang = 1; lang <= langCount; lang++) {
++
++                                memset(buffer, 0, sizeof(buffer));
++                                memset(&req, 0, sizeof(req));
++
++                              req.bmRequestType =
++                                      USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
++                              req.bRequest = kUSBRqGetDescriptor;
++                              req.wValue = (kUSBStringDesc << 8) | serialIndex;
++                              req.wIndex = languages[lang];
++                              req.pData = buffer;
++                              req.wLength = sizeof(buffer);
++                              kr = (*dev)->DeviceRequest(dev, &req);
++
++                              if (kr == kIOReturnSuccess && req.wLenDone > 0) {
++                                      int i, count;
++
++                                      // skip first word, and copy the rest to the serial string,
++                                      // changing shorts to bytes.
++                                      count = (req.wLenDone - 1) / 2;
++                                      for (i = 0; i < count; i++)
++                                              serial[i] = buffer[i + 1];
++                                      serial[i] = 0;
++                                        break;
++                              }
++                      }
++              }
++      }
++        (*dev)->Release(dev);
++
++        DBG("INFO: Found vid=%04x pid=%04x serial=%s\n", vendor, product,
++            serial);
++
++        usb_handle* handle = CheckInterface((IOUSBInterfaceInterface**)iface,
++                                            vendor, product);
++        if (handle == NULL) {
++            DBG("ERR: Could not find device interface: %08x\n", kr);
++            (*iface)->Release(iface);
++            continue;
++        }
++
++        DBG("AndroidDeviceAdded calling register_usb_transport\n");
++        register_usb_transport(handle, (serial[0] ? serial : NULL), devpath, 1);
++
++        // Register for an interest notification of this device being removed.
++        // Pass the reference to our private data as the refCon for the
++        // notification.
++        kr = IOServiceAddInterestNotification(notificationPort,
++                usbInterface,
++                kIOGeneralInterest,
++                AndroidInterfaceNotify,
++                handle,
++                &handle->usbNotification);
++
++        if (kIOReturnSuccess != kr) {
++            DBG("ERR: Unable to create interest notification (%08x)\n", kr);
++        }
++    }
++}
++
++static void
++AndroidInterfaceNotify(void *refCon, io_service_t service, natural_t messageType, void *messageArgument)
++{
++    usb_handle *handle = (usb_handle *)refCon;
++
++    if (messageType == kIOMessageServiceIsTerminated) {
++        if (!handle) {
++            DBG("ERR: NULL handle\n");
++            return;
++        }
++        DBG("AndroidInterfaceNotify\n");
++        IOObjectRelease(handle->usbNotification);
++        usb_kick(handle);
++    }
++}
++
++//* TODO: simplify this further since we only register to get ADB interface
++//* subclass+protocol events
++static usb_handle*
++CheckInterface(IOUSBInterfaceInterface **interface, UInt16 vendor, UInt16 product)
++{
++    usb_handle*                 handle = NULL;
++    IOReturn                    kr;
++    UInt8  interfaceNumEndpoints, interfaceClass, interfaceSubClass, interfaceProtocol;
++    UInt8  endpoint;
++
++
++    //* Now open the interface.  This will cause the pipes associated with
++    //* the endpoints in the interface descriptor to be instantiated
++    kr = (*interface)->USBInterfaceOpen(interface);
++    if (kr != kIOReturnSuccess) {
++        DBG("ERR: Could not open interface: (%08x)\n", kr);
++        return NULL;
++    }
++
++    //* Get the number of endpoints associated with this interface
++    kr = (*interface)->GetNumEndpoints(interface, &interfaceNumEndpoints);
++    if (kr != kIOReturnSuccess) {
++        DBG("ERR: Unable to get number of endpoints: (%08x)\n", kr);
++        goto err_get_num_ep;
++    }
++
++    //* Get interface class, subclass and protocol
++    if ((*interface)->GetInterfaceClass(interface, &interfaceClass) != kIOReturnSuccess ||
++            (*interface)->GetInterfaceSubClass(interface, &interfaceSubClass) != kIOReturnSuccess ||
++            (*interface)->GetInterfaceProtocol(interface, &interfaceProtocol) != kIOReturnSuccess) {
++            DBG("ERR: Unable to get interface class, subclass and protocol\n");
++            goto err_get_interface_class;
++    }
++
++    //* check to make sure interface class, subclass and protocol match ADB
++    //* avoid opening mass storage endpoints
++    if (!is_adb_interface(vendor, product, interfaceClass,
++                interfaceSubClass, interfaceProtocol))
++        goto err_bad_adb_interface;
++
++    handle = calloc(1, sizeof(usb_handle));
++
++    //* Iterate over the endpoints for this interface and find the first
++    //* bulk in/out pipes available.  These will be our read/write pipes.
++    for (endpoint = 0; endpoint <= interfaceNumEndpoints; endpoint++) {
++        UInt8   transferType;
++        UInt16  maxPacketSize;
++        UInt8   interval;
++        UInt8   number;
++        UInt8   direction;
++
++        kr = (*interface)->GetPipeProperties(interface, endpoint, &direction,
++                &number, &transferType, &maxPacketSize, &interval);
++
++        if (kIOReturnSuccess == kr) {
++            if (kUSBBulk != transferType)
++                continue;
++
++            if (kUSBIn == direction)
++                handle->bulkIn = endpoint;
++
++            if (kUSBOut == direction)
++                handle->bulkOut = endpoint;
++
++            handle->zero_mask = maxPacketSize - 1;
++        } else {
++            DBG("ERR: FindDeviceInterface - could not get pipe properties\n");
++            goto err_get_pipe_props;
++        }
++    }
++
++    handle->interface = interface;
++    return handle;
++
++err_get_pipe_props:
++    free(handle);
++err_bad_adb_interface:
++err_get_interface_class:
++err_get_num_ep:
++    (*interface)->USBInterfaceClose(interface);
++    return NULL;
++}
++
++
++void* RunLoopThread(void* unused)
++{
++    unsigned i;
++
++    InitUSB();
++
++    currentRunLoop = CFRunLoopGetCurrent();
++
++    // Signal the parent that we are running
++    adb_mutex_lock(&start_lock);
++    adb_cond_signal(&start_cond);
++    adb_mutex_unlock(&start_lock);
++
++    CFRunLoopRun();
++    currentRunLoop = 0;
++
++    for (i = 0; i < vendorIdCount; i++) {
++        IOObjectRelease(notificationIterators[i]);
++    }
++    IONotificationPortDestroy(notificationPort);
++
++    DBG("RunLoopThread done\n");
++    return NULL;    
++}
++
++
++static int initialized = 0;
++void usb_init()
++{
++    if (!initialized)
++    {
++        adb_thread_t    tid;
++
++        notificationIterators = (io_iterator_t*)malloc(
++            vendorIdCount * sizeof(io_iterator_t));
++
++        adb_mutex_init(&start_lock, NULL);
++        adb_cond_init(&start_cond, NULL);
++
++        if(adb_thread_create(&tid, RunLoopThread, NULL))
++            fatal_errno("cannot create input thread");
++
++        // Wait for initialization to finish
++        adb_mutex_lock(&start_lock);
++        adb_cond_wait(&start_cond, &start_lock);
++        adb_mutex_unlock(&start_lock);
++
++        adb_mutex_destroy(&start_lock);
++        adb_cond_destroy(&start_cond);
++
++        initialized = 1;
++    }
++}
++
++void usb_cleanup()
++{
++    DBG("usb_cleanup\n");
++    close_usb_devices();
++    if (currentRunLoop)
++        CFRunLoopStop(currentRunLoop);
++
++    if (notificationIterators != NULL) {
++        free(notificationIterators);
++        notificationIterators = NULL;
++    }
++}
++
++int usb_write(usb_handle *handle, const void *buf, int len)
++{
++    IOReturn    result;
++
++    if (!len)
++        return 0;
++
++    if (!handle)
++        return -1;
++
++    if (NULL == handle->interface) {
++        DBG("ERR: usb_write interface was null\n");
++        return -1;
++    }
++
++    if (0 == handle->bulkOut) {
++        DBG("ERR: bulkOut endpoint not assigned\n");
++        return -1;
++    }
++
++    result =
++        (*handle->interface)->WritePipe(
++                              handle->interface, handle->bulkOut, (void *)buf, len);
++
++    if ((result == 0) && (handle->zero_mask)) {
++        /* we need 0-markers and our transfer */
++        if(!(len & handle->zero_mask)) {
++            result =
++                (*handle->interface)->WritePipe(
++                        handle->interface, handle->bulkOut, (void *)buf, 0);
++        }
++    }
++
++    if (0 == result)
++        return 0;
++
++    DBG("ERR: usb_write failed with status %d\n", result);
++    return -1;
++}
++
++int usb_read(usb_handle *handle, void *buf, int len)
++{
++    IOReturn result;
++    UInt32  numBytes = len;
++
++    if (!len) {
++        return 0;
++    }
++
++    if (!handle) {
++        return -1;
++    }
++
++    if (NULL == handle->interface) {
++        DBG("ERR: usb_read interface was null\n");
++        return -1;
++    }
++
++    if (0 == handle->bulkIn) {
++        DBG("ERR: bulkIn endpoint not assigned\n");
++        return -1;
++    }
++
++    result =
++      (*handle->interface)->ReadPipe(handle->interface,
++                                    handle->bulkIn, buf, &numBytes);
++
++    if (0 == result)
++        return 0;
++    else {
++        DBG("ERR: usb_read failed with status %d\n", result);
++    }
++
++    return -1;
++}
++
++int usb_close(usb_handle *handle)
++{
++    return 0;
++}
++
++void usb_kick(usb_handle *handle)
++{
++    /* release the interface */
++    if (!handle)
++        return;
++
++    if (handle->interface)
++    {
++        (*handle->interface)->USBInterfaceClose(handle->interface);
++        (*handle->interface)->Release(handle->interface);
++        handle->interface = 0;
++    }
++}
+Index: android-tools-4.2.2+git20130218/core/adbd/usb_vendors.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/usb_vendors.c    2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,273 @@
++/*
++ * Copyright (C) 2009 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include "usb_vendors.h"
++
++#include <stdio.h>
++
++#ifdef _WIN32
++#  define WIN32_LEAN_AND_MEAN
++#  include "windows.h"
++#  include "shlobj.h"
++#else
++#  include <unistd.h>
++#  include <sys/stat.h>
++#endif
++
++#include "sysdeps.h"
++#include "adb.h"
++
++#define ANDROID_PATH            ".android"
++#define ANDROID_ADB_INI         "adb_usb.ini"
++
++#define TRACE_TAG               TRACE_USB
++
++// Google's USB Vendor ID
++#define VENDOR_ID_GOOGLE        0x18d1
++// Intel's USB Vendor ID
++#define VENDOR_ID_INTEL         0x8087
++// HTC's USB Vendor ID
++#define VENDOR_ID_HTC           0x0bb4
++// Samsung's USB Vendor ID
++#define VENDOR_ID_SAMSUNG       0x04e8
++// Motorola's USB Vendor ID
++#define VENDOR_ID_MOTOROLA      0x22b8
++// LG's USB Vendor ID
++#define VENDOR_ID_LGE           0x1004
++// Huawei's USB Vendor ID
++#define VENDOR_ID_HUAWEI        0x12D1
++// Acer's USB Vendor ID
++#define VENDOR_ID_ACER          0x0502
++// Sony Ericsson's USB Vendor ID
++#define VENDOR_ID_SONY_ERICSSON 0x0FCE
++// Foxconn's USB Vendor ID
++#define VENDOR_ID_FOXCONN       0x0489
++// Dell's USB Vendor ID
++#define VENDOR_ID_DELL          0x413c
++// Nvidia's USB Vendor ID
++#define VENDOR_ID_NVIDIA        0x0955
++// Garmin-Asus's USB Vendor ID
++#define VENDOR_ID_GARMIN_ASUS   0x091E
++// Sharp's USB Vendor ID
++#define VENDOR_ID_SHARP         0x04dd
++// ZTE's USB Vendor ID
++#define VENDOR_ID_ZTE           0x19D2
++// Kyocera's USB Vendor ID
++#define VENDOR_ID_KYOCERA       0x0482
++// Pantech's USB Vendor ID
++#define VENDOR_ID_PANTECH       0x10A9
++// Qualcomm's USB Vendor ID
++#define VENDOR_ID_QUALCOMM      0x05c6
++// On-The-Go-Video's USB Vendor ID
++#define VENDOR_ID_OTGV          0x2257
++// NEC's USB Vendor ID
++#define VENDOR_ID_NEC           0x0409
++// Panasonic Mobile Communication's USB Vendor ID
++#define VENDOR_ID_PMC           0x04DA
++// Toshiba's USB Vendor ID
++#define VENDOR_ID_TOSHIBA       0x0930
++// SK Telesys's USB Vendor ID
++#define VENDOR_ID_SK_TELESYS    0x1F53
++// KT Tech's USB Vendor ID
++#define VENDOR_ID_KT_TECH       0x2116
++// Asus's USB Vendor ID
++#define VENDOR_ID_ASUS          0x0b05
++// Philips's USB Vendor ID
++#define VENDOR_ID_PHILIPS       0x0471
++// Texas Instruments's USB Vendor ID
++#define VENDOR_ID_TI            0x0451
++// Funai's USB Vendor ID
++#define VENDOR_ID_FUNAI         0x0F1C
++// Gigabyte's USB Vendor ID
++#define VENDOR_ID_GIGABYTE      0x0414
++// IRiver's USB Vendor ID
++#define VENDOR_ID_IRIVER        0x2420
++// Compal's USB Vendor ID
++#define VENDOR_ID_COMPAL        0x1219
++// T & A Mobile Phones' USB Vendor ID
++#define VENDOR_ID_T_AND_A       0x1BBB
++// LenovoMobile's USB Vendor ID
++#define VENDOR_ID_LENOVOMOBILE  0x2006
++// Lenovo's USB Vendor ID
++#define VENDOR_ID_LENOVO        0x17EF
++// Vizio's USB Vendor ID
++#define VENDOR_ID_VIZIO         0xE040
++// K-Touch's USB Vendor ID
++#define VENDOR_ID_K_TOUCH       0x24E3
++// Pegatron's USB Vendor ID
++#define VENDOR_ID_PEGATRON      0x1D4D
++// Archos's USB Vendor ID
++#define VENDOR_ID_ARCHOS        0x0E79
++// Positivo's USB Vendor ID
++#define VENDOR_ID_POSITIVO      0x1662
++// Fujitsu's USB Vendor ID
++#define VENDOR_ID_FUJITSU       0x04C5
++// Lumigon's USB Vendor ID
++#define VENDOR_ID_LUMIGON       0x25E3
++// Quanta's USB Vendor ID
++#define VENDOR_ID_QUANTA        0x0408
++// INQ Mobile's USB Vendor ID
++#define VENDOR_ID_INQ_MOBILE    0x2314
++// Sony's USB Vendor ID
++#define VENDOR_ID_SONY          0x054C
++// Lab126's USB Vendor ID
++#define VENDOR_ID_LAB126        0x1949
++// Yulong Coolpad's USB Vendor ID
++#define VENDOR_ID_YULONG_COOLPAD 0x1EBF
++// Kobo's USB Vendor ID
++#define VENDOR_ID_KOBO          0x2237
++// Teleepoch's USB Vendor ID
++#define VENDOR_ID_TELEEPOCH     0x2340
++
++
++/** built-in vendor list */
++int builtInVendorIds[] = {
++    VENDOR_ID_GOOGLE,
++    VENDOR_ID_INTEL,
++    VENDOR_ID_HTC,
++    VENDOR_ID_SAMSUNG,
++    VENDOR_ID_MOTOROLA,
++    VENDOR_ID_LGE,
++    VENDOR_ID_HUAWEI,
++    VENDOR_ID_ACER,
++    VENDOR_ID_SONY_ERICSSON,
++    VENDOR_ID_FOXCONN,
++    VENDOR_ID_DELL,
++    VENDOR_ID_NVIDIA,
++    VENDOR_ID_GARMIN_ASUS,
++    VENDOR_ID_SHARP,
++    VENDOR_ID_ZTE,
++    VENDOR_ID_KYOCERA,
++    VENDOR_ID_PANTECH,
++    VENDOR_ID_QUALCOMM,
++    VENDOR_ID_OTGV,
++    VENDOR_ID_NEC,
++    VENDOR_ID_PMC,
++    VENDOR_ID_TOSHIBA,
++    VENDOR_ID_SK_TELESYS,
++    VENDOR_ID_KT_TECH,
++    VENDOR_ID_ASUS,
++    VENDOR_ID_PHILIPS,
++    VENDOR_ID_TI,
++    VENDOR_ID_FUNAI,
++    VENDOR_ID_GIGABYTE,
++    VENDOR_ID_IRIVER,
++    VENDOR_ID_COMPAL,
++    VENDOR_ID_T_AND_A,
++    VENDOR_ID_LENOVOMOBILE,
++    VENDOR_ID_LENOVO,
++    VENDOR_ID_VIZIO,
++    VENDOR_ID_K_TOUCH,
++    VENDOR_ID_PEGATRON,
++    VENDOR_ID_ARCHOS,
++    VENDOR_ID_POSITIVO,
++    VENDOR_ID_FUJITSU,
++    VENDOR_ID_LUMIGON,
++    VENDOR_ID_QUANTA,
++    VENDOR_ID_INQ_MOBILE,
++    VENDOR_ID_SONY,
++    VENDOR_ID_LAB126,
++    VENDOR_ID_YULONG_COOLPAD,
++    VENDOR_ID_KOBO,
++    VENDOR_ID_TELEEPOCH,
++};
++
++#define BUILT_IN_VENDOR_COUNT    (sizeof(builtInVendorIds)/sizeof(builtInVendorIds[0]))
++
++/* max number of supported vendor ids (built-in + 3rd party). increase as needed */
++#define VENDOR_COUNT_MAX         128
++
++int vendorIds[VENDOR_COUNT_MAX];
++unsigned vendorIdCount = 0;
++
++int get_adb_usb_ini(char* buff, size_t len);
++
++void usb_vendors_init(void)
++{
++    if (VENDOR_COUNT_MAX < BUILT_IN_VENDOR_COUNT) {
++        fprintf(stderr, "VENDOR_COUNT_MAX not big enough for built-in vendor list.\n");
++        exit(2);
++    }
++
++    /* add the built-in vendors at the beginning of the array */
++    memcpy(vendorIds, builtInVendorIds, sizeof(builtInVendorIds));
++
++    /* default array size is the number of built-in vendors */
++    vendorIdCount = BUILT_IN_VENDOR_COUNT;
++
++    if (VENDOR_COUNT_MAX == BUILT_IN_VENDOR_COUNT)
++        return;
++
++    char temp[PATH_MAX];
++    if (get_adb_usb_ini(temp, sizeof(temp)) == 0) {
++        FILE * f = fopen(temp, "rt");
++
++        if (f != NULL) {
++            /* The vendor id file is pretty basic. 1 vendor id per line.
++               Lines starting with # are comments */
++            while (fgets(temp, sizeof(temp), f) != NULL) {
++                if (temp[0] == '#')
++                    continue;
++
++                long value = strtol(temp, NULL, 0);
++                if (errno == EINVAL || errno == ERANGE || value > INT_MAX || value < 0) {
++                    fprintf(stderr, "Invalid content in %s. Quitting.\n", ANDROID_ADB_INI);
++                    exit(2);
++                }
++
++                vendorIds[vendorIdCount++] = (int)value;
++
++                /* make sure we don't go beyond the array */
++                if (vendorIdCount == VENDOR_COUNT_MAX) {
++                    break;
++                }
++            }
++        }
++    }
++}
++
++/* Utils methods */
++
++/* builds the path to the adb vendor id file. returns 0 if success */
++int build_path(char* buff, size_t len, const char* format, const char* home)
++{
++    if (snprintf(buff, len, format, home, ANDROID_PATH, ANDROID_ADB_INI) >= (signed)len) {
++        return 1;
++    }
++
++    return 0;
++}
++
++/* fills buff with the path to the adb vendor id file. returns 0 if success */
++int get_adb_usb_ini(char* buff, size_t len)
++{
++#ifdef _WIN32
++    const char* home = getenv("ANDROID_SDK_HOME");
++    if (home != NULL) {
++        return build_path(buff, len, "%s\\%s\\%s", home);
++    } else {
++        char path[MAX_PATH];
++        SHGetFolderPath( NULL, CSIDL_PROFILE, NULL, 0, path);
++        return build_path(buff, len, "%s\\%s\\%s", path);
++    }
++#else
++    const char* home = getenv("HOME");
++    if (home == NULL)
++        home = "/tmp";
++
++    return build_path(buff, len, "%s/%s/%s", home);
++#endif
++}
+Index: android-tools-4.2.2+git20130218/core/adbd/usb_vendors.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/usb_vendors.h    2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,25 @@
++/*
++ * Copyright (C) 2009 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#ifndef __USB_VENDORS_H
++#define __USB_VENDORS_H
++
++extern int vendorIds[];
++extern unsigned  vendorIdCount;
++
++void usb_vendors_init(void);
++
++#endif
+Index: android-tools-4.2.2+git20130218/core/adbd/usb_windows.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/usb_windows.c    2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,515 @@
++/*
++ * Copyright (C) 2007 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include <windows.h>
++#include <winerror.h>
++#include <errno.h>
++#include <usb100.h>
++#include <adb_api.h>
++#include <stdio.h>
++
++#include "sysdeps.h"
++
++#define   TRACE_TAG  TRACE_USB
++#include "adb.h"
++
++/** Structure usb_handle describes our connection to the usb device via
++  AdbWinApi.dll. This structure is returned from usb_open() routine and
++  is expected in each subsequent call that is accessing the device.
++*/
++struct usb_handle {
++  /// Previous entry in the list of opened usb handles
++  usb_handle *prev;
++
++  /// Next entry in the list of opened usb handles
++  usb_handle *next;
++
++  /// Handle to USB interface
++  ADBAPIHANDLE  adb_interface;
++
++  /// Handle to USB read pipe (endpoint)
++  ADBAPIHANDLE  adb_read_pipe;
++
++  /// Handle to USB write pipe (endpoint)
++  ADBAPIHANDLE  adb_write_pipe;
++
++  /// Interface name
++  char*         interface_name;
++
++  /// Mask for determining when to use zero length packets
++  unsigned zero_mask;
++};
++
++/// Class ID assigned to the device by androidusb.sys
++static const GUID usb_class_id = ANDROID_USB_CLASS_ID;
++
++/// List of opened usb handles
++static usb_handle handle_list = {
++  .prev = &handle_list,
++  .next = &handle_list,
++};
++
++/// Locker for the list of opened usb handles
++ADB_MUTEX_DEFINE( usb_lock );
++
++/// Checks if there is opened usb handle in handle_list for this device.
++int known_device(const char* dev_name);
++
++/// Checks if there is opened usb handle in handle_list for this device.
++/// usb_lock mutex must be held before calling this routine.
++int known_device_locked(const char* dev_name);
++
++/// Registers opened usb handle (adds it to handle_list).
++int register_new_device(usb_handle* handle);
++
++/// Checks if interface (device) matches certain criteria
++int recognized_device(usb_handle* handle);
++
++/// Enumerates present and available interfaces (devices), opens new ones and
++/// registers usb transport for them.
++void find_devices();
++
++/// Entry point for thread that polls (every second) for new usb interfaces.
++/// This routine calls find_devices in infinite loop.
++void* device_poll_thread(void* unused);
++
++/// Initializes this module
++void usb_init();
++
++/// Cleans up this module
++void usb_cleanup();
++
++/// Opens usb interface (device) by interface (device) name.
++usb_handle* do_usb_open(const wchar_t* interface_name);
++
++/// Writes data to the opened usb handle
++int usb_write(usb_handle* handle, const void* data, int len);
++
++/// Reads data using the opened usb handle
++int usb_read(usb_handle *handle, void* data, int len);
++
++/// Cleans up opened usb handle
++void usb_cleanup_handle(usb_handle* handle);
++
++/// Cleans up (but don't close) opened usb handle
++void usb_kick(usb_handle* handle);
++
++/// Closes opened usb handle
++int usb_close(usb_handle* handle);
++
++/// Gets interface (device) name for an opened usb handle
++const char *usb_name(usb_handle* handle);
++
++int known_device_locked(const char* dev_name) {
++  usb_handle* usb;
++
++  if (NULL != dev_name) {
++    // Iterate through the list looking for the name match.
++    for(usb = handle_list.next; usb != &handle_list; usb = usb->next) {
++      // In Windows names are not case sensetive!
++      if((NULL != usb->interface_name) &&
++         (0 == stricmp(usb->interface_name, dev_name))) {
++        return 1;
++      }
++    }
++  }
++
++  return 0;
++}
++
++int known_device(const char* dev_name) {
++  int ret = 0;
++
++  if (NULL != dev_name) {
++    adb_mutex_lock(&usb_lock);
++    ret = known_device_locked(dev_name);
++    adb_mutex_unlock(&usb_lock);
++  }
++
++  return ret;
++}
++
++int register_new_device(usb_handle* handle) {
++  if (NULL == handle)
++    return 0;
++
++  adb_mutex_lock(&usb_lock);
++
++  // Check if device is already in the list
++  if (known_device_locked(handle->interface_name)) {
++    adb_mutex_unlock(&usb_lock);
++    return 0;
++  }
++
++  // Not in the list. Add this handle to the list.
++  handle->next = &handle_list;
++  handle->prev = handle_list.prev;
++  handle->prev->next = handle;
++  handle->next->prev = handle;
++
++  adb_mutex_unlock(&usb_lock);
++
++  return 1;
++}
++
++void* device_poll_thread(void* unused) {
++  D("Created device thread\n");
++
++  while(1) {
++    find_devices();
++    adb_sleep_ms(1000);
++  }
++
++  return NULL;
++}
++
++void usb_init() {
++  adb_thread_t tid;
++
++  if(adb_thread_create(&tid, device_poll_thread, NULL)) {
++    fatal_errno("cannot create input thread");
++  }
++}
++
++void usb_cleanup() {
++}
++
++usb_handle* do_usb_open(const wchar_t* interface_name) {
++  // Allocate our handle
++  usb_handle* ret = (usb_handle*)malloc(sizeof(usb_handle));
++  if (NULL == ret)
++    return NULL;
++
++  // Set linkers back to the handle
++  ret->next = ret;
++  ret->prev = ret;
++
++  // Create interface.
++  ret->adb_interface = AdbCreateInterfaceByName(interface_name);
++
++  if (NULL == ret->adb_interface) {
++    free(ret);
++    errno = GetLastError();
++    return NULL;
++  }
++
++  // Open read pipe (endpoint)
++  ret->adb_read_pipe =
++    AdbOpenDefaultBulkReadEndpoint(ret->adb_interface,
++                                   AdbOpenAccessTypeReadWrite,
++                                   AdbOpenSharingModeReadWrite);
++  if (NULL != ret->adb_read_pipe) {
++    // Open write pipe (endpoint)
++    ret->adb_write_pipe =
++      AdbOpenDefaultBulkWriteEndpoint(ret->adb_interface,
++                                      AdbOpenAccessTypeReadWrite,
++                                      AdbOpenSharingModeReadWrite);
++    if (NULL != ret->adb_write_pipe) {
++      // Save interface name
++      unsigned long name_len = 0;
++
++      // First get expected name length
++      AdbGetInterfaceName(ret->adb_interface,
++                          NULL,
++                          &name_len,
++                          true);
++      if (0 != name_len) {
++        ret->interface_name = (char*)malloc(name_len);
++
++        if (NULL != ret->interface_name) {
++          // Now save the name
++          if (AdbGetInterfaceName(ret->adb_interface,
++                                  ret->interface_name,
++                                  &name_len,
++                                  true)) {
++            // We're done at this point
++            return ret;
++          }
++        } else {
++          SetLastError(ERROR_OUTOFMEMORY);
++        }
++      }
++    }
++  }
++
++  // Something went wrong.
++  int saved_errno = GetLastError();
++  usb_cleanup_handle(ret);
++  free(ret);
++  SetLastError(saved_errno);
++
++  return NULL;
++}
++
++int usb_write(usb_handle* handle, const void* data, int len) {
++  unsigned long time_out = 5000;
++  unsigned long written = 0;
++  int ret;
++
++  D("usb_write %d\n", len);
++  if (NULL != handle) {
++    // Perform write
++    ret = AdbWriteEndpointSync(handle->adb_write_pipe,
++                               (void*)data,
++                               (unsigned long)len,
++                               &written,
++                               time_out);
++    int saved_errno = GetLastError();
++
++    if (ret) {
++      // Make sure that we've written what we were asked to write
++      D("usb_write got: %ld, expected: %d\n", written, len);
++      if (written == (unsigned long)len) {
++        if(handle->zero_mask && (len & handle->zero_mask) == 0) {
++          // Send a zero length packet
++          AdbWriteEndpointSync(handle->adb_write_pipe,
++                               (void*)data,
++                               0,
++                               &written,
++                               time_out);
++        }
++        return 0;
++      }
++    } else {
++      // assume ERROR_INVALID_HANDLE indicates we are disconnected
++      if (saved_errno == ERROR_INVALID_HANDLE)
++        usb_kick(handle);
++    }
++    errno = saved_errno;
++  } else {
++    D("usb_write NULL handle\n");
++    SetLastError(ERROR_INVALID_HANDLE);
++  }
++
++  D("usb_write failed: %d\n", errno);
++
++  return -1;
++}
++
++int usb_read(usb_handle *handle, void* data, int len) {
++  unsigned long time_out = 0;
++  unsigned long read = 0;
++  int ret;
++
++  D("usb_read %d\n", len);
++  if (NULL != handle) {
++    while (len > 0) {
++      int xfer = (len > 4096) ? 4096 : len;
++
++      ret = AdbReadEndpointSync(handle->adb_read_pipe,
++                                  (void*)data,
++                                  (unsigned long)xfer,
++                                  &read,
++                                  time_out);
++      int saved_errno = GetLastError();
++      D("usb_write got: %ld, expected: %d, errno: %d\n", read, xfer, saved_errno);
++      if (ret) {
++        data += read;
++        len -= read;
++
++        if (len == 0)
++          return 0;
++      } else {
++        // assume ERROR_INVALID_HANDLE indicates we are disconnected
++        if (saved_errno == ERROR_INVALID_HANDLE)
++          usb_kick(handle);
++        break;
++      }
++      errno = saved_errno;
++    }
++  } else {
++    D("usb_read NULL handle\n");
++    SetLastError(ERROR_INVALID_HANDLE);
++  }
++
++  D("usb_read failed: %d\n", errno);
++
++  return -1;
++}
++
++void usb_cleanup_handle(usb_handle* handle) {
++  if (NULL != handle) {
++    if (NULL != handle->interface_name)
++      free(handle->interface_name);
++    if (NULL != handle->adb_write_pipe)
++      AdbCloseHandle(handle->adb_write_pipe);
++    if (NULL != handle->adb_read_pipe)
++      AdbCloseHandle(handle->adb_read_pipe);
++    if (NULL != handle->adb_interface)
++      AdbCloseHandle(handle->adb_interface);
++
++    handle->interface_name = NULL;
++    handle->adb_write_pipe = NULL;
++    handle->adb_read_pipe = NULL;
++    handle->adb_interface = NULL;
++  }
++}
++
++void usb_kick(usb_handle* handle) {
++  if (NULL != handle) {
++    adb_mutex_lock(&usb_lock);
++
++    usb_cleanup_handle(handle);
++
++    adb_mutex_unlock(&usb_lock);
++  } else {
++    SetLastError(ERROR_INVALID_HANDLE);
++    errno = ERROR_INVALID_HANDLE;
++  }
++}
++
++int usb_close(usb_handle* handle) {
++  D("usb_close\n");
++
++  if (NULL != handle) {
++    // Remove handle from the list
++    adb_mutex_lock(&usb_lock);
++
++    if ((handle->next != handle) && (handle->prev != handle)) {
++      handle->next->prev = handle->prev;
++      handle->prev->next = handle->next;
++      handle->prev = handle;
++      handle->next = handle;
++    }
++
++    adb_mutex_unlock(&usb_lock);
++
++    // Cleanup handle
++    usb_cleanup_handle(handle);
++    free(handle);
++  }
++
++  return 0;
++}
++
++const char *usb_name(usb_handle* handle) {
++  if (NULL == handle) {
++    SetLastError(ERROR_INVALID_HANDLE);
++    errno = ERROR_INVALID_HANDLE;
++    return NULL;
++  }
++
++  return (const char*)handle->interface_name;
++}
++
++int recognized_device(usb_handle* handle) {
++  if (NULL == handle)
++    return 0;
++
++  // Check vendor and product id first
++  USB_DEVICE_DESCRIPTOR device_desc;
++
++  if (!AdbGetUsbDeviceDescriptor(handle->adb_interface,
++                                 &device_desc)) {
++    return 0;
++  }
++
++  // Then check interface properties
++  USB_INTERFACE_DESCRIPTOR interf_desc;
++
++  if (!AdbGetUsbInterfaceDescriptor(handle->adb_interface,
++                                    &interf_desc)) {
++    return 0;
++  }
++
++  // Must have two endpoints
++  if (2 != interf_desc.bNumEndpoints) {
++    return 0;
++  }
++
++  if (is_adb_interface(device_desc.idVendor, device_desc.idProduct,
++      interf_desc.bInterfaceClass, interf_desc.bInterfaceSubClass, interf_desc.bInterfaceProtocol)) {
++
++    if(interf_desc.bInterfaceProtocol == 0x01) {
++      AdbEndpointInformation endpoint_info;
++      // assuming zero is a valid bulk endpoint ID
++      if (AdbGetEndpointInformation(handle->adb_interface, 0, &endpoint_info)) {
++        handle->zero_mask = endpoint_info.max_packet_size - 1;
++      }
++    }
++
++    return 1;
++  }
++
++  return 0;
++}
++
++void find_devices() {
++        usb_handle* handle = NULL;
++  char entry_buffer[2048];
++  char interf_name[2048];
++  AdbInterfaceInfo* next_interface = (AdbInterfaceInfo*)(&entry_buffer[0]);
++  unsigned long entry_buffer_size = sizeof(entry_buffer);
++  char* copy_name;
++
++  // Enumerate all present and active interfaces.
++  ADBAPIHANDLE enum_handle =
++    AdbEnumInterfaces(usb_class_id, true, true, true);
++
++  if (NULL == enum_handle)
++    return;
++
++  while (AdbNextInterface(enum_handle, next_interface, &entry_buffer_size)) {
++    // TODO: FIXME - temp hack converting wchar_t into char.
++    // It would be better to change AdbNextInterface so it will return
++    // interface name as single char string.
++    const wchar_t* wchar_name = next_interface->device_name;
++    for(copy_name = interf_name;
++        L'\0' != *wchar_name;
++        wchar_name++, copy_name++) {
++      *copy_name = (char)(*wchar_name);
++    }
++    *copy_name = '\0';
++
++    // Lets see if we already have this device in the list
++    if (!known_device(interf_name)) {
++      // This seems to be a new device. Open it!
++        handle = do_usb_open(next_interface->device_name);
++        if (NULL != handle) {
++        // Lets see if this interface (device) belongs to us
++        if (recognized_device(handle)) {
++          D("adding a new device %s\n", interf_name);
++          char serial_number[512];
++          unsigned long serial_number_len = sizeof(serial_number);
++          if (AdbGetSerialNumber(handle->adb_interface,
++                                serial_number,
++                                &serial_number_len,
++                                true)) {
++            // Lets make sure that we don't duplicate this device
++            if (register_new_device(handle)) {
++              register_usb_transport(handle, serial_number, NULL, 1);
++            } else {
++              D("register_new_device failed for %s\n", interf_name);
++              usb_cleanup_handle(handle);
++              free(handle);
++            }
++          } else {
++            D("cannot get serial number\n");
++            usb_cleanup_handle(handle);
++            free(handle);
++          }
++        } else {
++          usb_cleanup_handle(handle);
++          free(handle);
++        }
++      }
++    }
++
++    entry_buffer_size = sizeof(entry_buffer);
++  }
++
++  AdbCloseHandle(enum_handle);
++}
+Index: android-tools-4.2.2+git20130218/core/adbd/utils.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/utils.c  2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,106 @@
++/*
++ * Copyright (C) 2008 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++#include "utils.h"
++#include <stdarg.h>
++#include <stdio.h>
++#include <string.h>
++
++char*
++buff_addc (char*  buff, char*  buffEnd, int  c)
++{
++    int  avail = buffEnd - buff;
++
++    if (avail <= 0)  /* already in overflow mode */
++        return buff;
++
++    if (avail == 1) {  /* overflowing, the last byte is reserved for zero */
++        buff[0] = 0;
++        return buff + 1;
++    }
++
++    buff[0] = (char) c;  /* add char and terminating zero */
++    buff[1] = 0;
++    return buff + 1;
++}
++
++char*
++buff_adds (char*  buff, char*  buffEnd, const char*  s)
++{
++    int  slen = strlen(s);
++
++    return buff_addb(buff, buffEnd, s, slen);
++}
++
++char*
++buff_addb (char*  buff, char*  buffEnd, const void*  data, int  len)
++{
++    int  avail = (buffEnd - buff);
++
++    if (avail <= 0 || len <= 0)  /* already overflowing */
++        return buff;
++
++    if (len > avail)
++        len = avail;
++
++    memcpy(buff, data, len);
++
++    buff += len;
++
++    /* ensure there is a terminating zero */
++    if (buff >= buffEnd) {  /* overflow */
++        buff[-1] = 0;
++    } else
++        buff[0] = 0;
++
++    return buff;
++}
++
++char*
++buff_add  (char*  buff, char*  buffEnd, const char*  format, ... )
++{
++    int      avail;
++
++    avail = (buffEnd - buff);
++
++    if (avail > 0) {
++        va_list  args;
++        int      nn;
++
++        va_start(args, format);
++        nn = vsnprintf( buff, avail, format, args);
++        va_end(args);
++
++        if (nn < 0) {
++            /* some C libraries return -1 in case of overflow,
++             * but they will also do that if the format spec is
++             * invalid. We assume ADB is not buggy enough to
++             * trigger that last case. */
++            nn = avail;
++        }
++        else if (nn > avail) {
++            nn = avail;
++        }
++
++        buff += nn;
++
++        /* ensure that there is a terminating zero */
++        if (buff >= buffEnd)
++            buff[-1] = 0;
++        else
++            buff[0] = 0;
++    }
++    return buff;
++}
+Index: android-tools-4.2.2+git20130218/core/adbd/utils.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ android-tools-4.2.2+git20130218/core/adbd/utils.h  2013-06-18 17:12:17.000000000 -0300
+@@ -0,0 +1,68 @@
++/*
++ * Copyright (C) 2008 The Android Open Source Project
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++#ifndef _ADB_UTILS_H
++#define _ADB_UTILS_H
++
++/* bounded buffer functions */
++
++/* all these functions are used to append data to a bounded buffer.
++ *
++ * after each operation, the buffer is guaranteed to be zero-terminated,
++ * even in the case of an overflow. they all return the new buffer position
++ * which allows one to use them in succession, only checking for overflows
++ * at the end. For example:
++ *
++ *    BUFF_DECL(temp,p,end,1024);
++ *    char*    p;
++ *
++ *    p = buff_addc(temp, end, '"');
++ *    p = buff_adds(temp, end, string);
++ *    p = buff_addc(temp, end, '"');
++ *
++ *    if (p >= end) {
++ *        overflow detected. note that 'temp' is
++ *        zero-terminated for safety. 
++ *    }
++ *    return strdup(temp);
++ */
++
++/* tries to add a character to the buffer, in case of overflow
++ * this will only write a terminating zero and return buffEnd.
++ */
++char*   buff_addc (char*  buff, char*  buffEnd, int  c);
++
++/* tries to add a string to the buffer */
++char*   buff_adds (char*  buff, char*  buffEnd, const char*  s);
++
++/* tries to add a bytes to the buffer. the input can contain zero bytes,
++ * but a terminating zero will always be appended at the end anyway
++ */
++char*   buff_addb (char*  buff, char*  buffEnd, const void*  data, int  len);
++
++/* tries to add a formatted string to a bounded buffer */
++char*   buff_add  (char*  buff, char*  buffEnd, const char*  format, ... );
++
++/* convenience macro used to define a bounded buffer, as well as
++ * a 'cursor' and 'end' variables all in one go.
++ *
++ * note: this doesn't place an initial terminating zero in the buffer,
++ * you need to use one of the buff_ functions for this. or simply
++ * do _cursor[0] = 0 manually.
++ */
++#define  BUFF_DECL(_buff,_cursor,_end,_size)   \
++    char   _buff[_size], *_cursor=_buff, *_end = _cursor + (_size)
++
++#endif /* _ADB_UTILS_H */
diff --git a/recipes/android-tools/android-tools/android-tools-adbd.service b/recipes/android-tools/android-tools/android-tools-adbd.service
new file mode 100644 (file)
index 0000000..88ed687
--- /dev/null
@@ -0,0 +1,12 @@
+[Unit]
+Description=Android Debug Bridge
+
+[Service]
+Type=simple
+Restart=on-failure
+ExecStartPre=/usr/bin/android-gadget-setup adb
+ExecStart=/usr/bin/adbd
+StandardOutput=null
+
+[Install]
+WantedBy=basic.target
diff --git a/recipes/android-tools/android-tools/disable-selinux-support.patch b/recipes/android-tools/android-tools/disable-selinux-support.patch
new file mode 100644 (file)
index 0000000..738f575
--- /dev/null
@@ -0,0 +1,137 @@
+diff --git a/extras/ext4_utils/make_ext4fs.c b/extras/ext4_utils/make_ext4fs.c
+index b2d1426..94e92d6 100644
+--- a/extras/ext4_utils/make_ext4fs.c
++++ b/extras/ext4_utils/make_ext4fs.c
+@@ -59,9 +59,11 @@
+ #else
++#if 0
+ #include <selinux/selinux.h>
+ #include <selinux/label.h>
+ #include <selinux/android.h>
++#endif
+ #define O_BINARY 0
+@@ -178,6 +180,7 @@ static u32 build_directory_structure(const char *full_path, const char *dir_path
+                       error("can't set android permissions - built without android support");
+ #endif
+               }
++#if 0
+ #ifndef USE_MINGW
+               if (sehnd) {
+                       if (selabel_lookup(sehnd, &dentries[i].secon, dentries[i].path, stat.st_mode) < 0) {
+@@ -188,6 +191,7 @@ static u32 build_directory_structure(const char *full_path, const char *dir_path
+                               printf("Labeling %s as %s\n", dentries[i].path, dentries[i].secon);
+               }
+ #endif
++#endif
+               if (S_ISREG(stat.st_mode)) {
+                       dentries[i].file_type = EXT4_FT_REG_FILE;
+@@ -229,10 +233,12 @@ static u32 build_directory_structure(const char *full_path, const char *dir_path
+               dentries[0].file_type = EXT4_FT_DIR;
+               dentries[0].uid = 0;
+               dentries[0].gid = 0;
++#if 0
+               if (sehnd) {
+                       if (selabel_lookup(sehnd, &dentries[0].secon, dentries[0].path, dentries[0].mode) < 0)
+                               error("cannot lookup security context for %s", dentries[0].path);
+               }
++#endif
+               entries++;
+               dirs++;
+       }
+@@ -270,9 +276,11 @@ static u32 build_directory_structure(const char *full_path, const char *dir_path
+                       dentries[i].mtime);
+               if (ret)
+                       error("failed to set permissions on %s\n", dentries[i].path);
++#if 0
+               ret = inode_set_selinux(entry_inode, dentries[i].secon);
+               if (ret)
+                       error("failed to set SELinux context on %s\n", dentries[i].path);
++#endif
+               free(dentries[i].path);
+               free(dentries[i].full_path);
+@@ -562,6 +570,7 @@ int make_ext4fs_internal(int fd, const char *_directory,
+       root_mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
+       inode_set_permissions(root_inode_num, root_mode, 0, 0, 0);
++#if 0
+ #ifndef USE_MINGW
+       if (sehnd) {
+               char *secontext = NULL;
+@@ -578,6 +587,7 @@ int make_ext4fs_internal(int fd, const char *_directory,
+               freecon(secontext);
+       }
+ #endif
++#endif
+       ext4_update_free();
+diff --git a/extras/ext4_utils/make_ext4fs_main.c b/extras/ext4_utils/make_ext4fs_main.c
+index b6c740d..ce31764 100644
+--- a/extras/ext4_utils/make_ext4fs_main.c
++++ b/extras/ext4_utils/make_ext4fs_main.c
+@@ -29,6 +29,7 @@
+ #include <private/android_filesystem_config.h>
+ #endif
++#if 0
+ #ifndef USE_MINGW
+ #include <selinux/selinux.h>
+ #include <selinux/label.h>
+@@ -36,6 +37,7 @@
+ #else
+ struct selabel_handle;
+ #endif
++#endif
+ #include "make_ext4fs.h"
+ #include "ext4_utils.h"
+@@ -72,9 +74,11 @@ int main(int argc, char **argv)
+       int exitcode;
+       int verbose = 0;
+       struct selabel_handle *sehnd = NULL;
++#if 0
+ #ifndef USE_MINGW
+       struct selinux_opt seopts[] = { { SELABEL_OPT_PATH, "" } };
+ #endif
++#endif
+       while ((opt = getopt(argc, argv, "l:j:b:g:i:I:L:a:S:fwzJsctv")) != -1) {
+               switch (opt) {
+@@ -131,6 +135,7 @@ int main(int argc, char **argv)
+                       fprintf(stderr, "Warning: -t (initialize inode tables) is deprecated\n");
+                       break;
+               case 'S':
++#if 0
+ #ifndef USE_MINGW
+                       seopts[0].value = optarg;
+                       sehnd = selabel_open(SELABEL_CTX_FILE, seopts, 1);
+@@ -139,6 +144,7 @@ int main(int argc, char **argv)
+                               exit(EXIT_FAILURE);
+                       }
+ #endif
++#endif
+                       break;
+               case 'v':
+                       verbose = 1;
+@@ -149,6 +155,7 @@ int main(int argc, char **argv)
+               }
+       }
++#if 0
+ #if !defined(HOST)
+       // Use only if -S option not requested
+       if (!sehnd && mountpoint) {
+@@ -160,6 +167,7 @@ int main(int argc, char **argv)
+               }
+       }
+ #endif
++#endif
+       if (wipe && sparse) {
+               fprintf(stderr, "Cannot specifiy both wipe and sparse\n");
diff --git a/recipes/android-tools/android-tools/mkbootimg.mk b/recipes/android-tools/android-tools/mkbootimg.mk
new file mode 100644 (file)
index 0000000..8f61479
--- /dev/null
@@ -0,0 +1,10 @@
+CFLAGS += -I../include/
+OBJS += mkbootimg.o sha.o
+
+all: mkbootimg
+
+mkbootimg: $(OBJS)
+       $(CC) -o $@ $^ $(CFLAGS) $(LDFLAGS)
+
+clean:
+       $(RM) mkbootimg $(OBJS)
diff --git a/recipes/android-tools/android-tools/reboot-syscall.patch b/recipes/android-tools/android-tools/reboot-syscall.patch
new file mode 100644 (file)
index 0000000..0055416
--- /dev/null
@@ -0,0 +1,25 @@
+Subject: port android_reboot() to call the reboot syscall via syscall() (glibc) rather than __reboot (bionic)
+Author: Loïc Minier <loic.minier@ubuntu.com>
+
+--- a/core/libcutils/android_reboot.c
++++ b/core/libcutils/android_reboot.c
+@@ -21,6 +21,8 @@
+ #include <fcntl.h>
+ #include <stdio.h>
+ #include <string.h>
++#include <linux/reboot.h>
++#include <sys/syscall.h>
+ #include <cutils/android_reboot.h>
+@@ -121,8 +123,8 @@
+             break;
+         case ANDROID_RB_RESTART2:
+-            ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
+-                           LINUX_REBOOT_CMD_RESTART2, arg);
++            ret = syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
++                          LINUX_REBOOT_CMD_RESTART2, arg);
+             break;
+         default:
diff --git a/recipes/android-tools/android-tools/remove-libselinux.patch b/recipes/android-tools/android-tools/remove-libselinux.patch
new file mode 100644 (file)
index 0000000..24690b2
--- /dev/null
@@ -0,0 +1,13 @@
+diff --git a/debian/makefiles/ext4_utils.mk b/debian/makefiles/ext4_utils.mk
+index cb64916..60e81d6 100644
+--- a/debian/makefiles/ext4_utils.mk
++++ b/debian/makefiles/ext4_utils.mk
+@@ -36,7 +36,7 @@ CPPFLAGS+= -I/usr/include
+ CPPFLAGS+= -I../../core/include
+ CPPFLAGS+= -I../../core/libsparse/include/
+-LIBS+= -lz -lselinux
++LIBS+= -lz
+ OBJS= $(SRCS:.c=.o)
diff --git a/recipes/android-tools/android-tools/sha.c b/recipes/android-tools/android-tools/sha.c
new file mode 100644 (file)
index 0000000..e089d79
--- /dev/null
@@ -0,0 +1,307 @@
+/* sha.c
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are met:
+**     * Redistributions of source code must retain the above copyright
+**       notice, this list of conditions and the following disclaimer.
+**     * Redistributions in binary form must reproduce the above copyright
+**       notice, this list of conditions and the following disclaimer in the
+**       documentation and/or other materials provided with the distribution.
+**     * Neither the name of Google Inc. nor the names of its contributors may
+**       be used to endorse or promote products derived from this software
+**       without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mincrypt/sha.h"
+
+// Some machines lack byteswap.h and endian.h.  These have to use the
+// slower code, even if they're little-endian.
+
+#if defined(HAVE_ENDIAN_H) && defined(HAVE_LITTLE_ENDIAN)
+
+#include <byteswap.h>
+#include <memory.h>
+
+// This version is about 28% faster than the generic version below,
+// but assumes little-endianness.
+
+static inline uint32_t ror27(uint32_t val) {
+    return (val >> 27) | (val << 5);
+}
+static inline uint32_t ror2(uint32_t val) {
+    return (val >> 2) | (val << 30);
+}
+static inline uint32_t ror31(uint32_t val) {
+    return (val >> 31) | (val << 1);
+}
+
+static void SHA1_Transform(SHA_CTX* ctx) {
+    uint32_t W[80];
+    register uint32_t A, B, C, D, E;
+    int t;
+
+    A = ctx->state[0];
+    B = ctx->state[1];
+    C = ctx->state[2];
+    D = ctx->state[3];
+    E = ctx->state[4];
+
+#define SHA_F1(A,B,C,D,E,t)                     \
+    E += ror27(A) +                             \
+        (W[t] = bswap_32(ctx->buf.w[t])) +      \
+        (D^(B&(C^D))) + 0x5A827999;             \
+    B = ror2(B);
+
+    for (t = 0; t < 15; t += 5) {
+        SHA_F1(A,B,C,D,E,t + 0);
+        SHA_F1(E,A,B,C,D,t + 1);
+        SHA_F1(D,E,A,B,C,t + 2);
+        SHA_F1(C,D,E,A,B,t + 3);
+        SHA_F1(B,C,D,E,A,t + 4);
+    }
+    SHA_F1(A,B,C,D,E,t + 0);  // 16th one, t == 15
+
+#undef SHA_F1
+
+#define SHA_F1(A,B,C,D,E,t)                                     \
+    E += ror27(A) +                                             \
+        (W[t] = ror31(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16])) +   \
+        (D^(B&(C^D))) + 0x5A827999;                             \
+    B = ror2(B);
+
+    SHA_F1(E,A,B,C,D,t + 1);
+    SHA_F1(D,E,A,B,C,t + 2);
+    SHA_F1(C,D,E,A,B,t + 3);
+    SHA_F1(B,C,D,E,A,t + 4);
+
+#undef SHA_F1
+
+#define SHA_F2(A,B,C,D,E,t)                                     \
+    E += ror27(A) +                                             \
+        (W[t] = ror31(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16])) +   \
+        (B^C^D) + 0x6ED9EBA1;                                   \
+    B = ror2(B);
+
+    for (t = 20; t < 40; t += 5) {
+        SHA_F2(A,B,C,D,E,t + 0);
+        SHA_F2(E,A,B,C,D,t + 1);
+        SHA_F2(D,E,A,B,C,t + 2);
+        SHA_F2(C,D,E,A,B,t + 3);
+        SHA_F2(B,C,D,E,A,t + 4);
+    }
+
+#undef SHA_F2
+
+#define SHA_F3(A,B,C,D,E,t)                                     \
+    E += ror27(A) +                                             \
+        (W[t] = ror31(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16])) +   \
+        ((B&C)|(D&(B|C))) + 0x8F1BBCDC;                         \
+    B = ror2(B);
+
+    for (; t < 60; t += 5) {
+        SHA_F3(A,B,C,D,E,t + 0);
+        SHA_F3(E,A,B,C,D,t + 1);
+        SHA_F3(D,E,A,B,C,t + 2);
+        SHA_F3(C,D,E,A,B,t + 3);
+        SHA_F3(B,C,D,E,A,t + 4);
+    }
+
+#undef SHA_F3
+
+#define SHA_F4(A,B,C,D,E,t)                                     \
+    E += ror27(A) +                                             \
+        (W[t] = ror31(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16])) +   \
+        (B^C^D) + 0xCA62C1D6;                                   \
+    B = ror2(B);
+
+    for (; t < 80; t += 5) {
+        SHA_F4(A,B,C,D,E,t + 0);
+        SHA_F4(E,A,B,C,D,t + 1);
+        SHA_F4(D,E,A,B,C,t + 2);
+        SHA_F4(C,D,E,A,B,t + 3);
+        SHA_F4(B,C,D,E,A,t + 4);
+    }
+
+#undef SHA_F4
+
+    ctx->state[0] += A;
+    ctx->state[1] += B;
+    ctx->state[2] += C;
+    ctx->state[3] += D;
+    ctx->state[4] += E;
+}
+
+void SHA_update(SHA_CTX* ctx, const void* data, int len) {
+    int i = ctx->count % sizeof(ctx->buf);
+    const uint8_t* p = (const uint8_t*)data;
+
+    ctx->count += len;
+
+    while (len > sizeof(ctx->buf) - i) {
+        memcpy(&ctx->buf.b[i], p, sizeof(ctx->buf) - i);
+        len -= sizeof(ctx->buf) - i;
+        p += sizeof(ctx->buf) - i;
+        SHA1_Transform(ctx);
+        i = 0;
+    }
+
+    while (len--) {
+        ctx->buf.b[i++] = *p++;
+        if (i == sizeof(ctx->buf)) {
+            SHA1_Transform(ctx);
+            i = 0;
+        }
+    }
+}
+
+
+const uint8_t* SHA_final(SHA_CTX* ctx) {
+    uint64_t cnt = ctx->count * 8;
+    int i;
+
+    SHA_update(ctx, (uint8_t*)"\x80", 1);
+    while ((ctx->count % sizeof(ctx->buf)) != (sizeof(ctx->buf) - 8)) {
+        SHA_update(ctx, (uint8_t*)"\0", 1);
+    }
+    for (i = 0; i < 8; ++i) {
+        uint8_t tmp = cnt >> ((7 - i) * 8);
+        SHA_update(ctx, &tmp, 1);
+    }
+
+    for (i = 0; i < 5; i++) {
+        ctx->buf.w[i] = bswap_32(ctx->state[i]);
+    }
+
+    return ctx->buf.b;
+}
+
+#else   // #if defined(HAVE_ENDIAN_H) && defined(HAVE_LITTLE_ENDIAN)
+
+#define rol(bits, value) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+static void SHA1_transform(SHA_CTX *ctx) {
+    uint32_t W[80];
+    uint32_t A, B, C, D, E;
+    uint8_t *p = ctx->buf;
+    int t;
+
+    for(t = 0; t < 16; ++t) {
+        uint32_t tmp =  *p++ << 24;
+        tmp |= *p++ << 16;
+        tmp |= *p++ << 8;
+        tmp |= *p++;
+        W[t] = tmp;
+    }
+
+    for(; t < 80; t++) {
+        W[t] = rol(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
+    }
+
+    A = ctx->state[0];
+    B = ctx->state[1];
+    C = ctx->state[2];
+    D = ctx->state[3];
+    E = ctx->state[4];
+
+    for(t = 0; t < 80; t++) {
+        uint32_t tmp = rol(5,A) + E + W[t];
+
+        if (t < 20)
+            tmp += (D^(B&(C^D))) + 0x5A827999;
+        else if ( t < 40)
+            tmp += (B^C^D) + 0x6ED9EBA1;
+        else if ( t < 60)
+            tmp += ((B&C)|(D&(B|C))) + 0x8F1BBCDC;
+        else
+            tmp += (B^C^D) + 0xCA62C1D6;
+
+        E = D;
+        D = C;
+        C = rol(30,B);
+        B = A;
+        A = tmp;
+    }
+
+    ctx->state[0] += A;
+    ctx->state[1] += B;
+    ctx->state[2] += C;
+    ctx->state[3] += D;
+    ctx->state[4] += E;
+}
+
+void SHA_update(SHA_CTX *ctx, const void *data, int len) {
+    int i = ctx->count % sizeof(ctx->buf);
+    const uint8_t* p = (const uint8_t*)data;
+
+    ctx->count += len;
+
+    while (len--) {
+        ctx->buf[i++] = *p++;
+        if (i == sizeof(ctx->buf)) {
+            SHA1_transform(ctx);
+            i = 0;
+        }
+    }
+}
+const uint8_t *SHA_final(SHA_CTX *ctx) {
+    uint8_t *p = ctx->buf;
+    uint64_t cnt = ctx->count * 8;
+    int i;
+
+    SHA_update(ctx, (uint8_t*)"\x80", 1);
+    while ((ctx->count % sizeof(ctx->buf)) != (sizeof(ctx->buf) - 8)) {
+        SHA_update(ctx, (uint8_t*)"\0", 1);
+    }
+    for (i = 0; i < 8; ++i) {
+        uint8_t tmp = cnt >> ((7 - i) * 8);
+        SHA_update(ctx, &tmp, 1);
+    }
+
+    for (i = 0; i < 5; i++) {
+        uint32_t tmp = ctx->state[i];
+        *p++ = tmp >> 24;
+        *p++ = tmp >> 16;
+        *p++ = tmp >> 8;
+        *p++ = tmp >> 0;
+    }
+
+    return ctx->buf;
+}
+
+#endif // endianness
+
+void SHA_init(SHA_CTX* ctx) {
+    ctx->state[0] = 0x67452301;
+    ctx->state[1] = 0xEFCDAB89;
+    ctx->state[2] = 0x98BADCFE;
+    ctx->state[3] = 0x10325476;
+    ctx->state[4] = 0xC3D2E1F0;
+    ctx->count = 0;
+}
+
+/* Convenience function */
+const uint8_t* SHA(const void *data, int len, uint8_t *digest) {
+    const uint8_t *p;
+    int i;
+    SHA_CTX ctx;
+    SHA_init(&ctx);
+    SHA_update(&ctx, data, len);
+    p = SHA_final(&ctx);
+    for (i = 0; i < SHA_DIGEST_SIZE; ++i) {
+        digest[i] = *p++;
+    }
+    return digest;
+}
diff --git a/recipes/android-tools/android-tools_4.2.2.bb b/recipes/android-tools/android-tools_4.2.2.bb
new file mode 100644 (file)
index 0000000..996e2dd
--- /dev/null
@@ -0,0 +1,102 @@
+DESCRIPTION = "Different utilities from Android - based on the corresponding ubuntu \
+package"
+SECTION = "console/utils"
+LICENSE = "Apache-2.0 GPL-2.0 BSD-2-Clause BSD-3-Clause"
+LIC_FILES_CHKSUM = " \
+  file://${COMMON_LICENSE_DIR}/Apache-2.0;md5=89aea4e17d99a7cacdbeed46a0096b10 \
+  file://${COMMON_LICENSE_DIR}/GPL-2.0;md5=801f80980d171dd6425610833a22dbe6 \
+  file://${COMMON_LICENSE_DIR}/BSD-2-Clause;md5=8bef8e6712b1be5aa76af1ebde9d6378 \
+  file://${COMMON_LICENSE_DIR}/BSD-3-Clause;md5=550794465ba0ec5312d6919e203a55f9 \
+  file://${WORKDIR}/debian/copyright;md5=141efd1050596168ca05ced04e4f498b \
+"
+
+DEPENDS = "zlib openssl"
+# RDEPENDS_${PN} = "${PN}-conf"
+
+# Use same version than ubuntu does here
+BASE_PV = "4.2.2+git20130218"
+PV = "${BASE_PV}-3ubuntu13"
+
+# BBCLASSEXTEND += "native"
+
+SRC_URI = " \
+    https://launchpad.net/ubuntu/+archive/primary/+files/android-tools_${BASE_PV}.orig.tar.xz;name=source \
+    https://launchpad.net/ubuntu/+archive/primary/+files/android-tools_${PV}.debian.tar.gz;name=debian \
+    file://add_adbd.patch;patch=1 \
+    file://reboot-syscall.patch;patch=1 \
+    file://adbd-disable-client-authentication.patch;patch=1 \
+    file://disable-selinux-support.patch;patch=1 \
+#    file://remove-libselinux.patch;patch=1 \
+#    file://android-tools-adbd.service \
+    file://mkbootimg.mk \
+    file://sha.c \
+"
+S = "${WORKDIR}/android-tools"
+
+SRC_URI[source.md5sum] = "0e653b129ab0c95bdffa91410c8b55be"
+SRC_URI[source.sha256sum] = "9bfba987e1351b12aa983787b9ae4424ab752e9e646d8e93771538dc1e5d932f"
+SRC_URI[debian.md5sum] = "5e409d01caf3c33fc60a2100464754ff"
+SRC_URI[debian.sha256sum] = "320757edc8af015f40335c41dc96bf37e2d50c9f3a40a31e64264ff6e2dba5e3"
+
+# inherit systemd
+# SYSTEMD_SERVICE_${PN} = "android-tools-adbd.service"
+
+# disable environment-overrides
+EXTRA_OEMAKE = "MAKEFLAGS="
+
+do_compile() {
+    # Setting both variables below causing our makefiles to not work with implicit make
+    # rules
+    #unset CFLAGS
+    #unset CPPFLAGS
+    #unset MAKEFLAGS
+
+    sed -i "s%^CPPFLAGS+= -I/usr/include%# we don't want to include headers from host CPPFLAGS+= -I/usr/include%g" ${WORKDIR}/debian/makefiles/ext4_utils.mk
+    sed -i 's/-lselinux//' ${WORKDIR}/debian/makefiles/ext4_utils.mk
+
+    sed -i 's/$(LDFLAGS) $(OBJS)/$(LDFLAGS) $^/' ${WORKDIR}/debian/makefiles/fastboot.mk
+    sed -i 's/-lselinux//' ${WORKDIR}/debian/makefiles/fastboot.mk
+
+    #oe_runmake -f ${WORKDIR}/debian/makefiles/adbd.mk -C ${S}/core/adbd clean
+    #oe_runmake -f ${WORKDIR}/debian/makefiles/adbd.mk -C ${S}/core/adbd
+
+    oe_runmake -f ${WORKDIR}/debian/makefiles/ext4_utils.mk -C ${S}/extras/ext4_utils clean
+    oe_runmake -f ${WORKDIR}/debian/makefiles/ext4_utils.mk -C ${S}/extras/ext4_utils
+
+    oe_runmake -f ${WORKDIR}/debian/makefiles/adb.mk -C ${S}/core/adb clean
+    oe_runmake -f ${WORKDIR}/debian/makefiles/adb.mk -C ${S}/core/adb
+
+    oe_runmake -f ${WORKDIR}/debian/makefiles/fastboot.mk -C ${S}/core/fastboot clean
+    oe_runmake -f ${WORKDIR}/debian/makefiles/fastboot.mk -C ${S}/core/fastboot
+
+    cp ${WORKDIR}/sha.c ${S}/core/mkbootimg/
+    oe_runmake -f ${WORKDIR}/mkbootimg.mk -C ${S}/core/mkbootimg clean
+    oe_runmake -f ${WORKDIR}/mkbootimg.mk -C ${S}/core/mkbootimg
+}
+
+do_install() {
+    install -d ${D}${bindir}
+    #install -m 0755 ${S}/core/adbd/adbd ${D}${bindir}
+    install -m 0755 ${S}/extras/ext4_utils/make_ext4fs ${D}${bindir}
+    install -m 0755 ${S}/core/adb/adb ${D}${bindir}
+    install -m 0755 ${S}/core/fastboot/fastboot ${D}${bindir}
+    install -m 0755 ${S}/core/mkbootimg/mkbootimg ${D}${bindir}
+
+    #install -d ${D}${systemd_unitdir}/system
+    #install -m 0644 ${WORKDIR}/android-tools-adbd.service ${D}${systemd_unitdir}/system
+}
+
+PACKAGES += " \
+#  ${PN}-adbd \
+  ${PN}-fsutils \
+  ${PN}-adb \
+  ${PN}-fastboot \
+  ${PN}-mkbootimg \
+"
+
+FILES_${PN} = ""
+#FILES_${PN}-adbd += "${bindir}/adbd"
+FILES_${PN}-fsutils += "${bindir}/make_ext4fs"
+FILES_${PN}-adb += "${bindir}/adb"
+FILES_${PN}-fastboot += "${bindir}/fastboot"
+FILES_${PN}-mkbootimg += "${bindir}/mkbootimg"