All of lore.kernel.org
 help / color / mirror / Atom feed
* [meta-oe][PATCH] android-tools: Fix, enhance and move from meta-shr
@ 2016-07-01  5:14 Khem Raj
  2016-07-02 15:41 ` Fathi Boudra
  0 siblings, 1 reply; 7+ messages in thread
From: Khem Raj @ 2016-07-01  5:14 UTC (permalink / raw)
  To: openembedded-devel

android tools offer filsystem tools for creating sparse
images, so package them in package of its own.

Fix src uri to latest

Signed-off-by: Khem Raj <raj.khem@gmail.com>
---
 .../android-tools-conf/android-gadget-setup        |    25 +
 .../android-tools/android-tools-conf_1.0.bb        |    13 +
 .../adbd-disable-client-authentication.patch       |    16 +
 .../android-tools/android-tools/add_adbd.patch     | 20218 +++++++++++++++++++
 .../android-tools/android-tools-adbd.service       |    12 +
 .../android-tools/disable-selinux-support.patch    |   137 +
 .../android-tools/reboot-syscall.patch             |    25 +
 .../android-tools/remove-libselinux.patch          |    13 +
 .../android-tools/android-tools_4.2.2.bb           |    82 +
 9 files changed, 20541 insertions(+)
 create mode 100644 meta-oe/recipes-devtools/android-tools/android-tools-conf/android-gadget-setup
 create mode 100644 meta-oe/recipes-devtools/android-tools/android-tools-conf_1.0.bb
 create mode 100644 meta-oe/recipes-devtools/android-tools/android-tools/adbd-disable-client-authentication.patch
 create mode 100644 meta-oe/recipes-devtools/android-tools/android-tools/add_adbd.patch
 create mode 100644 meta-oe/recipes-devtools/android-tools/android-tools/android-tools-adbd.service
 create mode 100644 meta-oe/recipes-devtools/android-tools/android-tools/disable-selinux-support.patch
 create mode 100644 meta-oe/recipes-devtools/android-tools/android-tools/reboot-syscall.patch
 create mode 100644 meta-oe/recipes-devtools/android-tools/android-tools/remove-libselinux.patch
 create mode 100644 meta-oe/recipes-devtools/android-tools/android-tools_4.2.2.bb

diff --git a/meta-oe/recipes-devtools/android-tools/android-tools-conf/android-gadget-setup b/meta-oe/recipes-devtools/android-tools/android-tools-conf/android-gadget-setup
new file mode 100644
index 0000000..f7d9973
--- /dev/null
+++ b/meta-oe/recipes-devtools/android-tools/android-tools-conf/android-gadget-setup
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+# TODO enable the lines below once we have support for getprop
+# retrieve the product info from Android
+# manufacturer=$(getprop ro.product.manufacturer Android)
+# model=$(getprop ro.product.model Android)
+# serial=$(getprop ro.serialno 0123456789ABCDEF)
+
+manufacturer="$(cat /system/build.prop | grep -o 'ro.product.manufacturer=.*' | cut -d'=' -f 2)"
+model="$(cat /system/build.prop | grep -o 'ro.product.model=.*' | cut -d'=' -f 2)"
+# get the device serial number from /proc/cmdline directly(since we have no getprop on
+# GNU/Linux)
+serial="$(cat /proc/cmdline | sed 's/.*androidboot.serialno=//' | sed 's/ .*//')"
+
+echo $serial > /sys/class/android_usb/android0/iSerial
+echo $manufacturer > /sys/class/android_usb/android0/iManufacturer
+echo $model > /sys/class/android_usb/android0/iProduct
+
+echo "0" > /sys/class/android_usb/android0/enable
+echo "18d1" > /sys/class/android_usbid_usb/android0/idVendor
+echo "D002" > /sys/class/android_usb/android0/idProduct
+echo "adb" > /sys/class/android_usb/android0/functions
+echo "1" >  /sys/class/android_usb/android0/enable
+
+sleep 4
diff --git a/meta-oe/recipes-devtools/android-tools/android-tools-conf_1.0.bb b/meta-oe/recipes-devtools/android-tools/android-tools-conf_1.0.bb
new file mode 100644
index 0000000..af98f92
--- /dev/null
+++ b/meta-oe/recipes-devtools/android-tools/android-tools-conf_1.0.bb
@@ -0,0 +1,13 @@
+DESCRIPTION = "Different utilities from Android - corressponding configuration files"
+SECTION = "console/utils"
+LICENSE = "MIT"
+LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
+
+SRC_URI = "file://android-gadget-setup"
+
+PACKAGE_ARCH = "${MACHINE_ARCH}"
+
+do_install() {
+    install -d ${D}${bindir}
+    install -m 0755 ${WORKDIR}/android-gadget-setup ${D}${bindir}
+}
diff --git a/meta-oe/recipes-devtools/android-tools/android-tools/adbd-disable-client-authentication.patch b/meta-oe/recipes-devtools/android-tools/android-tools/adbd-disable-client-authentication.patch
new file mode 100644
index 0000000..9539160
--- /dev/null
+++ b/meta-oe/recipes-devtools/android-tools/android-tools/adbd-disable-client-authentication.patch
@@ -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/meta-oe/recipes-devtools/android-tools/android-tools/add_adbd.patch b/meta-oe/recipes-devtools/android-tools/android-tools/add_adbd.patch
new file mode 100644
index 0000000..561978f
--- /dev/null
+++ b/meta-oe/recipes-devtools/android-tools/android-tools/add_adbd.patch
@@ -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/meta-oe/recipes-devtools/android-tools/android-tools/android-tools-adbd.service b/meta-oe/recipes-devtools/android-tools/android-tools/android-tools-adbd.service
new file mode 100644
index 0000000..88ed687
--- /dev/null
+++ b/meta-oe/recipes-devtools/android-tools/android-tools/android-tools-adbd.service
@@ -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/meta-oe/recipes-devtools/android-tools/android-tools/disable-selinux-support.patch b/meta-oe/recipes-devtools/android-tools/android-tools/disable-selinux-support.patch
new file mode 100644
index 0000000..738f575
--- /dev/null
+++ b/meta-oe/recipes-devtools/android-tools/android-tools/disable-selinux-support.patch
@@ -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/meta-oe/recipes-devtools/android-tools/android-tools/reboot-syscall.patch b/meta-oe/recipes-devtools/android-tools/android-tools/reboot-syscall.patch
new file mode 100644
index 0000000..0055416
--- /dev/null
+++ b/meta-oe/recipes-devtools/android-tools/android-tools/reboot-syscall.patch
@@ -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/meta-oe/recipes-devtools/android-tools/android-tools/remove-libselinux.patch b/meta-oe/recipes-devtools/android-tools/android-tools/remove-libselinux.patch
new file mode 100644
index 0000000..24690b2
--- /dev/null
+++ b/meta-oe/recipes-devtools/android-tools/android-tools/remove-libselinux.patch
@@ -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/meta-oe/recipes-devtools/android-tools/android-tools_4.2.2.bb b/meta-oe/recipes-devtools/android-tools/android-tools_4.2.2.bb
new file mode 100644
index 0000000..9b004b5
--- /dev/null
+++ b/meta-oe/recipes-devtools/android-tools/android-tools_4.2.2.bb
@@ -0,0 +1,82 @@
+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_${BPN} = "${BPN}-conf"
+
+# Use same version than ubuntu does here
+BASE_PV = "4.2.2+git20130218"
+PV = "${BASE_PV}-3ubuntu13"
+
+BBCLASSEXTEND += "native"
+SRC_URI = " \
+    http://archive.ubuntu.com/ubuntu/pool/main/a/android-tools/android-tools_${BASE_PV}.orig.tar.xz;name=source \
+    http://archive.ubuntu.com/ubuntu/pool/main/a/android-tools/android-tools_${BASE_PV}-3ubuntu42.debian.tar.xz;name=debian \
+    file://add_adbd.patch \
+    file://reboot-syscall.patch \
+    file://adbd-disable-client-authentication.patch \
+    file://disable-selinux-support.patch \
+    file://remove-libselinux.patch;patchdir=.. \
+    file://android-tools-adbd.service \
+"
+S = "${WORKDIR}/android-tools"
+
+SRC_URI[source.md5sum] = "0e653b129ab0c95bdffa91410c8b55be"
+SRC_URI[source.sha256sum] = "9bfba987e1351b12aa983787b9ae4424ab752e9e646d8e93771538dc1e5d932f"
+SRC_URI[debian.md5sum] = "1dce6912e729e34e0ea74c100d977471"
+SRC_URI[debian.sha256sum] = "2475f95aa3bf22423a1a604915c1fd77896c7a2eb7b8e6b47ae30751fac63b2b"
+
+inherit systemd
+
+SYSTEMD_SERVICE_${PN} = "android-tools-adbd.service"
+
+do_compile() {
+    # Setting both variables below causing our makefiles to not work with implicit make
+    # rules
+    unset CFLAGS
+    unset CPPFLAGS
+
+    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
+
+    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
+}
+
+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}/extras/ext4_utils/ext2simg ${D}${bindir}
+    install -m 0755 ${S}/extras/ext4_utils/ext4fixup ${D}${bindir}
+    install -m 0755 ${S}/extras/ext4_utils/img2simg ${D}${bindir}
+    install -m 0755 ${S}/extras/ext4_utils/simg2img ${D}${bindir}
+    install -m 0755 ${S}/extras/ext4_utils/simg2simg ${D}${bindir}
+    install -m 0755 ${S}/extras/ext4_utils/test_ext4fixup ${D}${bindir}
+
+    install -d ${D}${systemd_unitdir}/system
+    install -m 0644 ${WORKDIR}/android-tools-adbd.service ${D}${systemd_unitdir}/system
+}
+
+PACKAGES += "${PN}-fstools"
+
+FILES_${PN}-fstools = "\
+  ${bindir}/ext2simg \
+  ${bindir}/ext4fixup \
+  ${bindir}/img2simg \
+  ${bindir}/simg2img \
+  ${bindir}/simg2simg \
+  ${bindir}/test_ext4fixup \
+"
+
-- 
2.9.0



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [meta-oe][PATCH] android-tools: Fix, enhance and move from meta-shr
  2016-07-01  5:14 [meta-oe][PATCH] android-tools: Fix, enhance and move from meta-shr Khem Raj
@ 2016-07-02 15:41 ` Fathi Boudra
  2016-07-02 17:15   ` Khem Raj
  0 siblings, 1 reply; 7+ messages in thread
From: Fathi Boudra @ 2016-07-02 15:41 UTC (permalink / raw)
  To: openembedded-devel

Hi Khem,

On 1 July 2016 at 08:14, Khem Raj <raj.khem@gmail.com> wrote:
> android tools offer filsystem tools for creating sparse
> images, so package them in package of its own.

fwiw, I plan to rework android-tools recipes for:
https://bugs.linaro.org/show_bug.cgi?id=2179

It's currently based on Ubuntu package, forked for Ubuntu phone.
I've updated Debian package built from AOSP source and up-to-date.
I've dropped the ubuntu-ism which will never be upstreamed.

The plan is to be closer to the upstream AOSP source code and be able
to update the recipe regularly.

Obviously, it doesn't prevent to get current recipe moved to meta-oe.
It's just a heads up :)

Cheers,
Fathi


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [meta-oe][PATCH] android-tools: Fix, enhance and move from meta-shr
  2016-07-02 15:41 ` Fathi Boudra
@ 2016-07-02 17:15   ` Khem Raj
  2016-07-04  6:54     ` Nicolas Dechesne
  0 siblings, 1 reply; 7+ messages in thread
From: Khem Raj @ 2016-07-02 17:15 UTC (permalink / raw)
  To: openembedded-devel

On Jul 2, 2016 8:42 AM, "Fathi Boudra" <fathi.boudra@linaro.org> wrote:
>
> Hi Khem,
>
> On 1 July 2016 at 08:14, Khem Raj <raj.khem@gmail.com> wrote:
> > android tools offer filsystem tools for creating sparse
> > images, so package them in package of its own.
>
> fwiw, I plan to rework android-tools recipes for:
> https://bugs.linaro.org/show_bug.cgi?id=2179
>
> It's currently based on Ubuntu package, forked for Ubuntu phone.
> I've updated Debian package built from AOSP source and up-to-date.
> I've dropped the ubuntu-ism which will never be upstreamed.
>
> The plan is to be closer to the upstream AOSP source code and be able
> to update the recipe regularly.
>
> Obviously, it doesn't prevent to get current recipe moved to meta-oe.
> It's just a heads up :)

Thanks for.update. I think this really should go into oe core. Since sparse
file system is across many devices
>
> Cheers,
> Fathi
> --
> _______________________________________________
> Openembedded-devel mailing list
> Openembedded-devel@lists.openembedded.org
> http://lists.openembedded.org/mailman/listinfo/openembedded-devel


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [meta-oe][PATCH] android-tools: Fix, enhance and move from meta-shr
  2016-07-02 17:15   ` Khem Raj
@ 2016-07-04  6:54     ` Nicolas Dechesne
  0 siblings, 0 replies; 7+ messages in thread
From: Nicolas Dechesne @ 2016-07-04  6:54 UTC (permalink / raw)
  To: openembedded-devel

On Sat, Jul 2, 2016 at 7:15 PM, Khem Raj <raj.khem@gmail.com> wrote:
>> Obviously, it doesn't prevent to get current recipe moved to meta-oe.
>> It's just a heads up :)
>
> Thanks for.update. I think this really should go into oe core. Since sparse
> file system is across many devices

+1. for sure.. that would be very nice.


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [meta-oe][PATCH] android-tools: Fix, enhance and move from meta-shr
  2016-04-25  0:11 ` Khem Raj
@ 2016-04-25  8:32   ` Martin Jansa
  0 siblings, 0 replies; 7+ messages in thread
From: Martin Jansa @ 2016-04-25  8:32 UTC (permalink / raw)
  To: openembedded-devel

What was broken in the version in SHR? It builds fine here.

On Mon, Apr 25, 2016 at 2:11 AM, Khem Raj <raj.khem@gmail.com> wrote:

> ping^1
>
> On Thu, Mar 31, 2016 at 10:14 AM Khem Raj <raj.khem@gmail.com> wrote:
>
> > android tools offer filsystem tools for creating sparse
> > images, so package them in package of its own.
> >
> > Fix src uri to latest
> >
> > Signed-off-by: Khem Raj <raj.khem@gmail.com>
> > ---
> >  .../android-tools-conf/android-gadget-setup        |    25 +
> >  .../android-tools/android-tools-conf_1.0.bb        |    13 +
> >  .../adbd-disable-client-authentication.patch       |    16 +
> >  .../android-tools/android-tools/add_adbd.patch     | 20218
> > +++++++++++++++++++
> >  .../android-tools/android-tools-adbd.service       |    12 +
> >  .../android-tools/disable-selinux-support.patch    |   137 +
> >  .../android-tools/reboot-syscall.patch             |    25 +
> >  .../android-tools/remove-libselinux.patch          |    13 +
> >  .../android-tools/android-tools_4.2.2.bb           |    82 +
> >  9 files changed, 20541 insertions(+)
> >  create mode 100644
> >
> meta-oe/recipes-devtools/android-tools/android-tools-conf/android-gadget-setup
> >  create mode 100644 meta-oe/recipes-devtools/android-tools/
> > android-tools-conf_1.0.bb
> >  create mode 100644
> >
> meta-oe/recipes-devtools/android-tools/android-tools/adbd-disable-client-authentication.patch
> >  create mode 100644
> > meta-oe/recipes-devtools/android-tools/android-tools/add_adbd.patch
> >  create mode 100644
> >
> meta-oe/recipes-devtools/android-tools/android-tools/android-tools-adbd.service
> >  create mode 100644
> >
> meta-oe/recipes-devtools/android-tools/android-tools/disable-selinux-support.patch
> >  create mode 100644
> > meta-oe/recipes-devtools/android-tools/android-tools/reboot-syscall.patch
> >  create mode 100644
> >
> meta-oe/recipes-devtools/android-tools/android-tools/remove-libselinux.patch
> >  create mode 100644 meta-oe/recipes-devtools/android-tools/
> > android-tools_4.2.2.bb
> >
> > diff --git
> >
> a/meta-oe/recipes-devtools/android-tools/android-tools-conf/android-gadget-setup
> >
> b/meta-oe/recipes-devtools/android-tools/android-tools-conf/android-gadget-setup
> > new file mode 100644
> > index 0000000..f7d9973
> > --- /dev/null
> > +++
> >
> b/meta-oe/recipes-devtools/android-tools/android-tools-conf/android-gadget-setup
> > @@ -0,0 +1,25 @@
> > +#!/bin/sh
> > +
> > +# TODO enable the lines below once we have support for getprop
> > +# retrieve the product info from Android
> > +# manufacturer=$(getprop ro.product.manufacturer Android)
> > +# model=$(getprop ro.product.model Android)
> > +# serial=$(getprop ro.serialno 0123456789ABCDEF)
> > +
> > +manufacturer="$(cat /system/build.prop | grep -o
> > 'ro.product.manufacturer=.*' | cut -d'=' -f 2)"
> > +model="$(cat /system/build.prop | grep -o 'ro.product.model=.*' | cut
> > -d'=' -f 2)"
> > +# get the device serial number from /proc/cmdline directly(since we have
> > no getprop on
> > +# GNU/Linux)
> > +serial="$(cat /proc/cmdline | sed 's/.*androidboot.serialno=//' | sed
> 's/
> > .*//')"
> > +
> > +echo $serial > /sys/class/android_usb/android0/iSerial
> > +echo $manufacturer > /sys/class/android_usb/android0/iManufacturer
> > +echo $model > /sys/class/android_usb/android0/iProduct
> > +
> > +echo "0" > /sys/class/android_usb/android0/enable
> > +echo "18d1" > /sys/class/android_usbid_usb/android0/idVendor
> > +echo "D002" > /sys/class/android_usb/android0/idProduct
> > +echo "adb" > /sys/class/android_usb/android0/functions
> > +echo "1" >  /sys/class/android_usb/android0/enable
> > +
> > +sleep 4
> > diff --git a/meta-oe/recipes-devtools/android-tools/
> > android-tools-conf_1.0.bb b/meta-oe/recipes-devtools/android-tools/
> > android-tools-conf_1.0.bb
> > new file mode 100644
> > index 0000000..af98f92
> > --- /dev/null
> > +++ b/meta-oe/recipes-devtools/android-tools/android-tools-conf_1.0.bb
> > @@ -0,0 +1,13 @@
> > +DESCRIPTION = "Different utilities from Android - corressponding
> > configuration files"
> > +SECTION = "console/utils"
> > +LICENSE = "MIT"
> > +LIC_FILES_CHKSUM =
> > "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
> > +
> > +SRC_URI = "file://android-gadget-setup"
> > +
> > +PACKAGE_ARCH = "${MACHINE_ARCH}"
> > +
> > +do_install() {
> > +    install -d ${D}${bindir}
> > +    install -m 0755 ${WORKDIR}/android-gadget-setup ${D}${bindir}
> > +}
> > diff --git
> >
> a/meta-oe/recipes-devtools/android-tools/android-tools/adbd-disable-client-authentication.patch
> >
> b/meta-oe/recipes-devtools/android-tools/android-tools/adbd-disable-client-authentication.patch
> > new file mode 100644
> > index 0000000..9539160
> > --- /dev/null
> > +++
> >
> b/meta-oe/recipes-devtools/android-tools/android-tools/adbd-disable-client-authentication.patch
> > @@ -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/meta-oe/recipes-devtools/android-tools/android-tools/add_adbd.patch
> > b/meta-oe/recipes-devtools/android-tools/android-tools/add_adbd.patch
> > new file mode 100644
> > index 0000000..561978f
> > --- /dev/null
> > +++ b/meta-oe/recipes-devtools/android-tools/android-tools/add_adbd.patch
> > @@ -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 0x4e45
> --
> _______________________________________________
> Openembedded-devel mailing list
> Openembedded-devel@lists.openembedded.org
> http://lists.openembedded.org/mailman/listinfo/openembedded-devel
>


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [meta-oe][PATCH] android-tools: Fix, enhance and move from meta-shr
  2016-03-31 17:14 Khem Raj
@ 2016-04-25  0:11 ` Khem Raj
  2016-04-25  8:32   ` Martin Jansa
  0 siblings, 1 reply; 7+ messages in thread
From: Khem Raj @ 2016-04-25  0:11 UTC (permalink / raw)
  To: openembedded-devel

ping^1

On Thu, Mar 31, 2016 at 10:14 AM Khem Raj <raj.khem@gmail.com> wrote:

> android tools offer filsystem tools for creating sparse
> images, so package them in package of its own.
>
> Fix src uri to latest
>
> Signed-off-by: Khem Raj <raj.khem@gmail.com>
> ---
>  .../android-tools-conf/android-gadget-setup        |    25 +
>  .../android-tools/android-tools-conf_1.0.bb        |    13 +
>  .../adbd-disable-client-authentication.patch       |    16 +
>  .../android-tools/android-tools/add_adbd.patch     | 20218
> +++++++++++++++++++
>  .../android-tools/android-tools-adbd.service       |    12 +
>  .../android-tools/disable-selinux-support.patch    |   137 +
>  .../android-tools/reboot-syscall.patch             |    25 +
>  .../android-tools/remove-libselinux.patch          |    13 +
>  .../android-tools/android-tools_4.2.2.bb           |    82 +
>  9 files changed, 20541 insertions(+)
>  create mode 100644
> meta-oe/recipes-devtools/android-tools/android-tools-conf/android-gadget-setup
>  create mode 100644 meta-oe/recipes-devtools/android-tools/
> android-tools-conf_1.0.bb
>  create mode 100644
> meta-oe/recipes-devtools/android-tools/android-tools/adbd-disable-client-authentication.patch
>  create mode 100644
> meta-oe/recipes-devtools/android-tools/android-tools/add_adbd.patch
>  create mode 100644
> meta-oe/recipes-devtools/android-tools/android-tools/android-tools-adbd.service
>  create mode 100644
> meta-oe/recipes-devtools/android-tools/android-tools/disable-selinux-support.patch
>  create mode 100644
> meta-oe/recipes-devtools/android-tools/android-tools/reboot-syscall.patch
>  create mode 100644
> meta-oe/recipes-devtools/android-tools/android-tools/remove-libselinux.patch
>  create mode 100644 meta-oe/recipes-devtools/android-tools/
> android-tools_4.2.2.bb
>
> diff --git
> a/meta-oe/recipes-devtools/android-tools/android-tools-conf/android-gadget-setup
> b/meta-oe/recipes-devtools/android-tools/android-tools-conf/android-gadget-setup
> new file mode 100644
> index 0000000..f7d9973
> --- /dev/null
> +++
> b/meta-oe/recipes-devtools/android-tools/android-tools-conf/android-gadget-setup
> @@ -0,0 +1,25 @@
> +#!/bin/sh
> +
> +# TODO enable the lines below once we have support for getprop
> +# retrieve the product info from Android
> +# manufacturer=$(getprop ro.product.manufacturer Android)
> +# model=$(getprop ro.product.model Android)
> +# serial=$(getprop ro.serialno 0123456789ABCDEF)
> +
> +manufacturer="$(cat /system/build.prop | grep -o
> 'ro.product.manufacturer=.*' | cut -d'=' -f 2)"
> +model="$(cat /system/build.prop | grep -o 'ro.product.model=.*' | cut
> -d'=' -f 2)"
> +# get the device serial number from /proc/cmdline directly(since we have
> no getprop on
> +# GNU/Linux)
> +serial="$(cat /proc/cmdline | sed 's/.*androidboot.serialno=//' | sed 's/
> .*//')"
> +
> +echo $serial > /sys/class/android_usb/android0/iSerial
> +echo $manufacturer > /sys/class/android_usb/android0/iManufacturer
> +echo $model > /sys/class/android_usb/android0/iProduct
> +
> +echo "0" > /sys/class/android_usb/android0/enable
> +echo "18d1" > /sys/class/android_usbid_usb/android0/idVendor
> +echo "D002" > /sys/class/android_usb/android0/idProduct
> +echo "adb" > /sys/class/android_usb/android0/functions
> +echo "1" >  /sys/class/android_usb/android0/enable
> +
> +sleep 4
> diff --git a/meta-oe/recipes-devtools/android-tools/
> android-tools-conf_1.0.bb b/meta-oe/recipes-devtools/android-tools/
> android-tools-conf_1.0.bb
> new file mode 100644
> index 0000000..af98f92
> --- /dev/null
> +++ b/meta-oe/recipes-devtools/android-tools/android-tools-conf_1.0.bb
> @@ -0,0 +1,13 @@
> +DESCRIPTION = "Different utilities from Android - corressponding
> configuration files"
> +SECTION = "console/utils"
> +LICENSE = "MIT"
> +LIC_FILES_CHKSUM =
> "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
> +
> +SRC_URI = "file://android-gadget-setup"
> +
> +PACKAGE_ARCH = "${MACHINE_ARCH}"
> +
> +do_install() {
> +    install -d ${D}${bindir}
> +    install -m 0755 ${WORKDIR}/android-gadget-setup ${D}${bindir}
> +}
> diff --git
> a/meta-oe/recipes-devtools/android-tools/android-tools/adbd-disable-client-authentication.patch
> b/meta-oe/recipes-devtools/android-tools/android-tools/adbd-disable-client-authentication.patch
> new file mode 100644
> index 0000000..9539160
> --- /dev/null
> +++
> b/meta-oe/recipes-devtools/android-tools/android-tools/adbd-disable-client-authentication.patch
> @@ -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/meta-oe/recipes-devtools/android-tools/android-tools/add_adbd.patch
> b/meta-oe/recipes-devtools/android-tools/android-tools/add_adbd.patch
> new file mode 100644
> index 0000000..561978f
> --- /dev/null
> +++ b/meta-oe/recipes-devtools/android-tools/android-tools/add_adbd.patch
> @@ -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 0x4e45


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [meta-oe][PATCH] android-tools: Fix, enhance and move from meta-shr
@ 2016-03-31 17:14 Khem Raj
  2016-04-25  0:11 ` Khem Raj
  0 siblings, 1 reply; 7+ messages in thread
From: Khem Raj @ 2016-03-31 17:14 UTC (permalink / raw)
  To: openembedded-devel

android tools offer filsystem tools for creating sparse
images, so package them in package of its own.

Fix src uri to latest

Signed-off-by: Khem Raj <raj.khem@gmail.com>
---
 .../android-tools-conf/android-gadget-setup        |    25 +
 .../android-tools/android-tools-conf_1.0.bb        |    13 +
 .../adbd-disable-client-authentication.patch       |    16 +
 .../android-tools/android-tools/add_adbd.patch     | 20218 +++++++++++++++++++
 .../android-tools/android-tools-adbd.service       |    12 +
 .../android-tools/disable-selinux-support.patch    |   137 +
 .../android-tools/reboot-syscall.patch             |    25 +
 .../android-tools/remove-libselinux.patch          |    13 +
 .../android-tools/android-tools_4.2.2.bb           |    82 +
 9 files changed, 20541 insertions(+)
 create mode 100644 meta-oe/recipes-devtools/android-tools/android-tools-conf/android-gadget-setup
 create mode 100644 meta-oe/recipes-devtools/android-tools/android-tools-conf_1.0.bb
 create mode 100644 meta-oe/recipes-devtools/android-tools/android-tools/adbd-disable-client-authentication.patch
 create mode 100644 meta-oe/recipes-devtools/android-tools/android-tools/add_adbd.patch
 create mode 100644 meta-oe/recipes-devtools/android-tools/android-tools/android-tools-adbd.service
 create mode 100644 meta-oe/recipes-devtools/android-tools/android-tools/disable-selinux-support.patch
 create mode 100644 meta-oe/recipes-devtools/android-tools/android-tools/reboot-syscall.patch
 create mode 100644 meta-oe/recipes-devtools/android-tools/android-tools/remove-libselinux.patch
 create mode 100644 meta-oe/recipes-devtools/android-tools/android-tools_4.2.2.bb

diff --git a/meta-oe/recipes-devtools/android-tools/android-tools-conf/android-gadget-setup b/meta-oe/recipes-devtools/android-tools/android-tools-conf/android-gadget-setup
new file mode 100644
index 0000000..f7d9973
--- /dev/null
+++ b/meta-oe/recipes-devtools/android-tools/android-tools-conf/android-gadget-setup
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+# TODO enable the lines below once we have support for getprop
+# retrieve the product info from Android
+# manufacturer=$(getprop ro.product.manufacturer Android)
+# model=$(getprop ro.product.model Android)
+# serial=$(getprop ro.serialno 0123456789ABCDEF)
+
+manufacturer="$(cat /system/build.prop | grep -o 'ro.product.manufacturer=.*' | cut -d'=' -f 2)"
+model="$(cat /system/build.prop | grep -o 'ro.product.model=.*' | cut -d'=' -f 2)"
+# get the device serial number from /proc/cmdline directly(since we have no getprop on
+# GNU/Linux)
+serial="$(cat /proc/cmdline | sed 's/.*androidboot.serialno=//' | sed 's/ .*//')"
+
+echo $serial > /sys/class/android_usb/android0/iSerial
+echo $manufacturer > /sys/class/android_usb/android0/iManufacturer
+echo $model > /sys/class/android_usb/android0/iProduct
+
+echo "0" > /sys/class/android_usb/android0/enable
+echo "18d1" > /sys/class/android_usbid_usb/android0/idVendor
+echo "D002" > /sys/class/android_usb/android0/idProduct
+echo "adb" > /sys/class/android_usb/android0/functions
+echo "1" >  /sys/class/android_usb/android0/enable
+
+sleep 4
diff --git a/meta-oe/recipes-devtools/android-tools/android-tools-conf_1.0.bb b/meta-oe/recipes-devtools/android-tools/android-tools-conf_1.0.bb
new file mode 100644
index 0000000..af98f92
--- /dev/null
+++ b/meta-oe/recipes-devtools/android-tools/android-tools-conf_1.0.bb
@@ -0,0 +1,13 @@
+DESCRIPTION = "Different utilities from Android - corressponding configuration files"
+SECTION = "console/utils"
+LICENSE = "MIT"
+LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
+
+SRC_URI = "file://android-gadget-setup"
+
+PACKAGE_ARCH = "${MACHINE_ARCH}"
+
+do_install() {
+    install -d ${D}${bindir}
+    install -m 0755 ${WORKDIR}/android-gadget-setup ${D}${bindir}
+}
diff --git a/meta-oe/recipes-devtools/android-tools/android-tools/adbd-disable-client-authentication.patch b/meta-oe/recipes-devtools/android-tools/android-tools/adbd-disable-client-authentication.patch
new file mode 100644
index 0000000..9539160
--- /dev/null
+++ b/meta-oe/recipes-devtools/android-tools/android-tools/adbd-disable-client-authentication.patch
@@ -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/meta-oe/recipes-devtools/android-tools/android-tools/add_adbd.patch b/meta-oe/recipes-devtools/android-tools/android-tools/add_adbd.patch
new file mode 100644
index 0000000..561978f
--- /dev/null
+++ b/meta-oe/recipes-devtools/android-tools/android-tools/add_adbd.patch
@@ -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/meta-oe/recipes-devtools/android-tools/android-tools/android-tools-adbd.service b/meta-oe/recipes-devtools/android-tools/android-tools/android-tools-adbd.service
new file mode 100644
index 0000000..88ed687
--- /dev/null
+++ b/meta-oe/recipes-devtools/android-tools/android-tools/android-tools-adbd.service
@@ -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/meta-oe/recipes-devtools/android-tools/android-tools/disable-selinux-support.patch b/meta-oe/recipes-devtools/android-tools/android-tools/disable-selinux-support.patch
new file mode 100644
index 0000000..738f575
--- /dev/null
+++ b/meta-oe/recipes-devtools/android-tools/android-tools/disable-selinux-support.patch
@@ -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/meta-oe/recipes-devtools/android-tools/android-tools/reboot-syscall.patch b/meta-oe/recipes-devtools/android-tools/android-tools/reboot-syscall.patch
new file mode 100644
index 0000000..0055416
--- /dev/null
+++ b/meta-oe/recipes-devtools/android-tools/android-tools/reboot-syscall.patch
@@ -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/meta-oe/recipes-devtools/android-tools/android-tools/remove-libselinux.patch b/meta-oe/recipes-devtools/android-tools/android-tools/remove-libselinux.patch
new file mode 100644
index 0000000..24690b2
--- /dev/null
+++ b/meta-oe/recipes-devtools/android-tools/android-tools/remove-libselinux.patch
@@ -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/meta-oe/recipes-devtools/android-tools/android-tools_4.2.2.bb b/meta-oe/recipes-devtools/android-tools/android-tools_4.2.2.bb
new file mode 100644
index 0000000..9b004b5
--- /dev/null
+++ b/meta-oe/recipes-devtools/android-tools/android-tools_4.2.2.bb
@@ -0,0 +1,82 @@
+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_${BPN} = "${BPN}-conf"
+
+# Use same version than ubuntu does here
+BASE_PV = "4.2.2+git20130218"
+PV = "${BASE_PV}-3ubuntu13"
+
+BBCLASSEXTEND += "native"
+SRC_URI = " \
+    http://archive.ubuntu.com/ubuntu/pool/main/a/android-tools/android-tools_${BASE_PV}.orig.tar.xz;name=source \
+    http://archive.ubuntu.com/ubuntu/pool/main/a/android-tools/android-tools_${BASE_PV}-3ubuntu42.debian.tar.xz;name=debian \
+    file://add_adbd.patch \
+    file://reboot-syscall.patch \
+    file://adbd-disable-client-authentication.patch \
+    file://disable-selinux-support.patch \
+    file://remove-libselinux.patch;patchdir=.. \
+    file://android-tools-adbd.service \
+"
+S = "${WORKDIR}/android-tools"
+
+SRC_URI[source.md5sum] = "0e653b129ab0c95bdffa91410c8b55be"
+SRC_URI[source.sha256sum] = "9bfba987e1351b12aa983787b9ae4424ab752e9e646d8e93771538dc1e5d932f"
+SRC_URI[debian.md5sum] = "1dce6912e729e34e0ea74c100d977471"
+SRC_URI[debian.sha256sum] = "2475f95aa3bf22423a1a604915c1fd77896c7a2eb7b8e6b47ae30751fac63b2b"
+
+inherit systemd
+
+SYSTEMD_SERVICE_${PN} = "android-tools-adbd.service"
+
+do_compile() {
+    # Setting both variables below causing our makefiles to not work with implicit make
+    # rules
+    unset CFLAGS
+    unset CPPFLAGS
+
+    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
+
+    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
+}
+
+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}/extras/ext4_utils/ext2simg ${D}${bindir}
+    install -m 0755 ${S}/extras/ext4_utils/ext4fixup ${D}${bindir}
+    install -m 0755 ${S}/extras/ext4_utils/img2simg ${D}${bindir}
+    install -m 0755 ${S}/extras/ext4_utils/simg2img ${D}${bindir}
+    install -m 0755 ${S}/extras/ext4_utils/simg2simg ${D}${bindir}
+    install -m 0755 ${S}/extras/ext4_utils/test_ext4fixup ${D}${bindir}
+
+    install -d ${D}${systemd_unitdir}/system
+    install -m 0644 ${WORKDIR}/android-tools-adbd.service ${D}${systemd_unitdir}/system
+}
+
+PACKAGES += "${PN}-fstools"
+
+FILES_${PN}-fstools = "\
+  ${bindir}/ext2simg \
+  ${bindir}/ext4fixup \
+  ${bindir}/img2simg \
+  ${bindir}/simg2img \
+  ${bindir}/simg2simg \
+  ${bindir}/test_ext4fixup \
+"
+
-- 
2.7.4



^ permalink raw reply related	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2016-07-04  6:55 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-07-01  5:14 [meta-oe][PATCH] android-tools: Fix, enhance and move from meta-shr Khem Raj
2016-07-02 15:41 ` Fathi Boudra
2016-07-02 17:15   ` Khem Raj
2016-07-04  6:54     ` Nicolas Dechesne
  -- strict thread matches above, loose matches on Subject: below --
2016-03-31 17:14 Khem Raj
2016-04-25  0:11 ` Khem Raj
2016-04-25  8:32   ` Martin Jansa

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.