* [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, ×tamp, &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, ×tamp, &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,
++ ¬ificationIterators[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, ×tamp, &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, ×tamp, &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,
++ ¬ificationIterators[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.