From 4cdf9a80958e768aef0416cf2e06fa7f26bdb980 Mon Sep 17 00:00:00 2001 From: Khem Raj Date: Thu, 31 Mar 2016 10:14:26 -0700 Subject: android-tools: Fix, enhance and move from meta-shr 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 Signed-off-by: Martin Jansa --- .../adbd-disable-client-authentication.patch | 16 + .../android-tools/android-tools/add_adbd.patch | 20218 +++++++++++++++++++ .../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 + 6 files changed, 20491 insertions(+) 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/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/adbd-disable-client-authentication.patch b/meta-oe/recipes-devtools/android-tools/android-tools/adbd-disable-client-authentication.patch new file mode 100644 index 0000000000..9539160646 --- /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 0000000000..561978f886 --- /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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 ++#include ++#include ++#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 ++ ++/* ++ * 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: ++ // ++ // " " " " "\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 ,", ++ 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:... here ++ if (createForward && !strncmp(local, "norebind:", 9)) { ++ no_rebind = 1; ++ local = strchr(local, ':') + 1; ++ } ++ ++ remote = strchr(local,';'); ++ ++ if (createForward) { ++ // Check forward: parameter format: ';' ++ 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: '' ++ 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 ++ ++#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 ++#include ++#include ++#include ++#include ++ ++#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 ++ ++#ifdef _WIN32 ++# define WIN32_LEAN_AND_MEAN ++# include "windows.h" ++# include "shlobj.h" ++#else ++# include ++# include ++# include ++#endif ++#include ++ ++#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 ++ ++#include ++#include ++#include ++#include ++#include ++ ++#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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 ++ * with a 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 ++#include ++#include ++ ++/* 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 ++#include ++ ++/* ++ * 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 ++# 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 ++ ++#ifndef BYTE_ORDER ++#if (BSD >= 199103) ++# include ++#else ++#ifdef __linux ++# include ++#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 ++#include ++ ++#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 ++#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 ++#include ++#include ++#include ++#include ++#include "arpa_nameser.h" ++ ++#include ++#include ++#ifdef ANDROID_CHANGES ++#include "resolv_private.h" ++#else ++#include ++#endif ++#include ++ ++#include ++#include ++ ++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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "sysdeps.h" ++ ++#ifdef HAVE_TERMIO_H ++#include ++#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 - directs command to the device or emulator with the given\n" ++ " serial number or qualifier. Overrides ANDROID_SERIAL\n" ++ " environment variable.\n" ++ " -p - 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 [:] - connect to a device via TCP/IP\n" ++ " Port 5555 is used by default if no port number is specified.\n" ++ " disconnect [[:]] - 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 - copy file/dir to device\n" ++ " adb pull [] - copy file/dir from device\n" ++ " adb sync [ ] - 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 - run remote shell command\n" ++ " adb emu - run emulator console command\n" ++ " adb logcat [ ] - 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" ++ " \" \" \" \" \"\\n\"\n" ++ " adb forward - forward socket connections\n" ++ " forward specs are one of: \n" ++ " tcp:\n" ++ " localabstract:\n" ++ " localreserved:\n" ++ " localfilesystem:\n" ++ " dev:\n" ++ " jdwp: (remote only)\n" ++ " adb forward --no-rebind \n" ++ " - same as 'adb forward ' but fails\n" ++ " if is already forwarded\n" ++ " adb forward --remove - 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 --key --iv ] \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] - 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 ] [-apk|-noapk] [-shared|-noshared] [-all] [-system|-nosystem] []\n" ++ " - write an archive of the device's data to .\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" ++ " ( 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 - restore device contents from the 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: \n" ++ " adb get-devpath - prints: \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 - restarts the adbd daemon listening on TCP on the specified port" ++ "\n" ++ "networking:\n" ++ " adb ppp [parameters] - Run PPP over USB.\n" ++ " Note: you should not automatically start a PPP connection.\n" ++ " 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 [ ]\n" ++ " can be interpreted in several ways:\n" ++ "\n" ++ " - If 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 ++ * ++ */ ++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 [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; ++} ++ ++/* 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 , 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 [:]\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 [[:]]\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 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 ++ else if (remove) { ++ if (argc != 2) ++ return usage(); ++ snprintf(buf, sizeof buf, "%s:killforward:%s", host_prefix, argv[1]); ++ } ++ // Or implement one of: ++ // forward ++ // forward --no-rebind ++ 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 ++ ++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 ++** ++** 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 ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++ ++#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 ++ ++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 ++#else ++#include ++#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 /* 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++#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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "fdevent.h" ++#include "adb.h" ++ ++#include ++#include ++#include ++ ++/* 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 ++#include ++ ++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 ++ * ++ * 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 ++#include ++#include ++#include ++ ++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 ++#include ++#include ++#include ++ ++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 ++#include ++#include ++ ++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 ++#include ++#include ++#include ++ ++/* 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 | ++ | | ++ | | ++ ++ 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: jdwp:" ++ ++ "jdwp:" 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 ++#include ++ ++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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#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 ++#include ++#include ++#include ++#include /* for pthread_once() */ ++#include ++#include ++#include ++ ++#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 ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 ++#include ++#include ++#include ++#include ++#include ++ ++#include "sysdeps.h" ++ ++#define TRACE_TAG TRACE_SERVICES ++#include "adb.h" ++#include "file_sync_service.h" ++ ++#if ADB_HOST ++# ifndef HAVE_WINSOCK ++# include ++# include ++# include ++# endif ++#else ++# include ++#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 ++#include ++#include ++#include ++#include ++#include ++ ++#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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 */ ++extern void* load_file(const char* pathname, unsigned* psize); ++ ++/* normally provided by */ ++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 ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * TEMP_FAILURE_RETRY is defined by some, but not all, versions of ++ * . (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 ++#include ++#include ++#include ++#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 ++ ++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 ++# 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 ++#include ++#include ++#include ++#include ++#include ++ ++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 ++#include ++#include ++#include ++#include ++#include ++ ++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 ++#include ++#include ++#include ++#include ++ ++#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 ++#include ++#include ++#include ++ ++#include "sysdeps.h" ++#include ++ ++#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 ++#include ++#include ++ ++#include ++ ++#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 ++ * ++ * 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 ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#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 ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20) ++#include ++#else ++#include ++#endif ++#include ++ ++#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 ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "sysdeps.h" ++ ++#include ++ ++#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 ++ ++#ifdef _WIN32 ++# define WIN32_LEAN_AND_MEAN ++# include "windows.h" ++# include "shlobj.h" ++#else ++# include ++# include ++#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 ++#include ++#include ++#include ++#include ++#include ++ ++#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 ++#include ++#include ++ ++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/disable-selinux-support.patch b/meta-oe/recipes-devtools/android-tools/android-tools/disable-selinux-support.patch new file mode 100644 index 0000000000..738f575c23 --- /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 + #include + #include ++#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 + #endif + ++#if 0 + #ifndef USE_MINGW + #include + #include +@@ -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 0000000000..005541632a --- /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 + +--- a/core/libcutils/android_reboot.c ++++ b/core/libcutils/android_reboot.c +@@ -21,6 +21,8 @@ + #include + #include + #include ++#include ++#include + + #include + +@@ -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 0000000000..24690b200e --- /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 0000000000..9b004b54a7 --- /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 \ +" + -- cgit 1.2.3-korg