20219 lines
580 KiB
Diff
Executable File
20219 lines
580 KiB
Diff
Executable File
## Description: add some description
|
|
## Origin/Author: add some origin or author
|
|
## Bug: bug URL
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/adb.c
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/adb.c 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,1719 @@
|
|
+/*
|
|
+ * Copyright (C) 2007 The Android Open Source Project
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
+ * you may not use this file except in compliance with the License.
|
|
+ * You may obtain a copy of the License at
|
|
+ *
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
+ *
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+ * See the License for the specific language governing permissions and
|
|
+ * limitations under the License.
|
|
+ */
|
|
+
|
|
+#define TRACE_TAG TRACE_ADB
|
|
+
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+#include <ctype.h>
|
|
+#include <stdarg.h>
|
|
+#include <errno.h>
|
|
+#include <stddef.h>
|
|
+#include <string.h>
|
|
+#include <time.h>
|
|
+#include <sys/time.h>
|
|
+#include <stdint.h>
|
|
+
|
|
+#include "sysdeps.h"
|
|
+#include "adb.h"
|
|
+#include "adb_auth.h"
|
|
+
|
|
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
|
+
|
|
+#if !ADB_HOST
|
|
+#include "android_filesystem_config.h"
|
|
+#include <linux/capability.h>
|
|
+#include <linux/prctl.h>
|
|
+#include <sys/mount.h>
|
|
+#else
|
|
+#include "usb_vendors.h"
|
|
+#endif
|
|
+
|
|
+#if ADB_TRACE
|
|
+ADB_MUTEX_DEFINE( D_lock );
|
|
+#endif
|
|
+
|
|
+int HOST = 0;
|
|
+int gListenAll = 0;
|
|
+
|
|
+static int auth_enabled = 0;
|
|
+
|
|
+#if !ADB_HOST
|
|
+static const char *adb_device_banner = "device";
|
|
+#endif
|
|
+
|
|
+void fatal(const char *fmt, ...)
|
|
+{
|
|
+ va_list ap;
|
|
+ va_start(ap, fmt);
|
|
+ fprintf(stderr, "error: ");
|
|
+ vfprintf(stderr, fmt, ap);
|
|
+ fprintf(stderr, "\n");
|
|
+ va_end(ap);
|
|
+ exit(-1);
|
|
+}
|
|
+
|
|
+void fatal_errno(const char *fmt, ...)
|
|
+{
|
|
+ va_list ap;
|
|
+ va_start(ap, fmt);
|
|
+ fprintf(stderr, "error: %s: ", strerror(errno));
|
|
+ vfprintf(stderr, fmt, ap);
|
|
+ fprintf(stderr, "\n");
|
|
+ va_end(ap);
|
|
+ exit(-1);
|
|
+}
|
|
+
|
|
+int adb_trace_mask;
|
|
+
|
|
+/* read a comma/space/colum/semi-column separated list of tags
|
|
+ * from the ADB_TRACE environment variable and build the trace
|
|
+ * mask from it. note that '1' and 'all' are special cases to
|
|
+ * enable all tracing
|
|
+ */
|
|
+void adb_trace_init(void)
|
|
+{
|
|
+ const char* p = getenv("ADB_TRACE");
|
|
+ const char* q;
|
|
+
|
|
+ static const struct {
|
|
+ const char* tag;
|
|
+ int flag;
|
|
+ } tags[] = {
|
|
+ { "1", 0 },
|
|
+ { "all", 0 },
|
|
+ { "adb", TRACE_ADB },
|
|
+ { "sockets", TRACE_SOCKETS },
|
|
+ { "packets", TRACE_PACKETS },
|
|
+ { "rwx", TRACE_RWX },
|
|
+ { "usb", TRACE_USB },
|
|
+ { "sync", TRACE_SYNC },
|
|
+ { "sysdeps", TRACE_SYSDEPS },
|
|
+ { "transport", TRACE_TRANSPORT },
|
|
+ { "jdwp", TRACE_JDWP },
|
|
+ { "services", TRACE_SERVICES },
|
|
+ { "auth", TRACE_AUTH },
|
|
+ { NULL, 0 }
|
|
+ };
|
|
+
|
|
+ if (p == NULL)
|
|
+ return;
|
|
+
|
|
+ /* use a comma/column/semi-colum/space separated list */
|
|
+ while (*p) {
|
|
+ int len, tagn;
|
|
+
|
|
+ q = strpbrk(p, " ,:;");
|
|
+ if (q == NULL) {
|
|
+ q = p + strlen(p);
|
|
+ }
|
|
+ len = q - p;
|
|
+
|
|
+ for (tagn = 0; tags[tagn].tag != NULL; tagn++)
|
|
+ {
|
|
+ int taglen = strlen(tags[tagn].tag);
|
|
+
|
|
+ if (len == taglen && !memcmp(tags[tagn].tag, p, len) )
|
|
+ {
|
|
+ int flag = tags[tagn].flag;
|
|
+ if (flag == 0) {
|
|
+ adb_trace_mask = ~0;
|
|
+ return;
|
|
+ }
|
|
+ adb_trace_mask |= (1 << flag);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ p = q;
|
|
+ if (*p)
|
|
+ p++;
|
|
+ }
|
|
+}
|
|
+
|
|
+#if !ADB_HOST
|
|
+/*
|
|
+ * Implements ADB tracing inside the emulator.
|
|
+ */
|
|
+
|
|
+#include <stdarg.h>
|
|
+
|
|
+/*
|
|
+ * Redefine open and write for qemu_pipe.h that contains inlined references
|
|
+ * to those routines. We will redifine them back after qemu_pipe.h inclusion.
|
|
+ */
|
|
+
|
|
+#undef open
|
|
+#undef write
|
|
+#define open adb_open
|
|
+#define write adb_write
|
|
+#include "qemu_pipe.h"
|
|
+#undef open
|
|
+#undef write
|
|
+#define open ___xxx_open
|
|
+#define write ___xxx_write
|
|
+
|
|
+/* A handle to adb-debug qemud service in the emulator. */
|
|
+int adb_debug_qemu = -1;
|
|
+
|
|
+/* Initializes connection with the adb-debug qemud service in the emulator. */
|
|
+static int adb_qemu_trace_init(void)
|
|
+{
|
|
+ char con_name[32];
|
|
+
|
|
+ if (adb_debug_qemu >= 0) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ /* adb debugging QEMUD service connection request. */
|
|
+ snprintf(con_name, sizeof(con_name), "qemud:adb-debug");
|
|
+ adb_debug_qemu = qemu_pipe_open(con_name);
|
|
+ return (adb_debug_qemu >= 0) ? 0 : -1;
|
|
+}
|
|
+
|
|
+void adb_qemu_trace(const char* fmt, ...)
|
|
+{
|
|
+ va_list args;
|
|
+ va_start(args, fmt);
|
|
+ char msg[1024];
|
|
+
|
|
+ if (adb_debug_qemu >= 0) {
|
|
+ vsnprintf(msg, sizeof(msg), fmt, args);
|
|
+ adb_write(adb_debug_qemu, msg, strlen(msg));
|
|
+ }
|
|
+}
|
|
+#endif /* !ADB_HOST */
|
|
+
|
|
+apacket *get_apacket(void)
|
|
+{
|
|
+ apacket *p = malloc(sizeof(apacket));
|
|
+ if(p == 0) fatal("failed to allocate an apacket");
|
|
+ memset(p, 0, sizeof(apacket) - MAX_PAYLOAD);
|
|
+ return p;
|
|
+}
|
|
+
|
|
+void put_apacket(apacket *p)
|
|
+{
|
|
+ free(p);
|
|
+}
|
|
+
|
|
+void handle_online(atransport *t)
|
|
+{
|
|
+ D("adb: online\n");
|
|
+ t->online = 1;
|
|
+}
|
|
+
|
|
+void handle_offline(atransport *t)
|
|
+{
|
|
+ D("adb: offline\n");
|
|
+ //Close the associated usb
|
|
+ t->online = 0;
|
|
+ run_transport_disconnects(t);
|
|
+}
|
|
+
|
|
+#if DEBUG_PACKETS
|
|
+#define DUMPMAX 32
|
|
+void print_packet(const char *label, apacket *p)
|
|
+{
|
|
+ char *tag;
|
|
+ char *x;
|
|
+ unsigned count;
|
|
+
|
|
+ switch(p->msg.command){
|
|
+ case A_SYNC: tag = "SYNC"; break;
|
|
+ case A_CNXN: tag = "CNXN" ; break;
|
|
+ case A_OPEN: tag = "OPEN"; break;
|
|
+ case A_OKAY: tag = "OKAY"; break;
|
|
+ case A_CLSE: tag = "CLSE"; break;
|
|
+ case A_WRTE: tag = "WRTE"; break;
|
|
+ case A_AUTH: tag = "AUTH"; break;
|
|
+ default: tag = "????"; break;
|
|
+ }
|
|
+
|
|
+ fprintf(stderr, "%s: %s %08x %08x %04x \"",
|
|
+ label, tag, p->msg.arg0, p->msg.arg1, p->msg.data_length);
|
|
+ count = p->msg.data_length;
|
|
+ x = (char*) p->data;
|
|
+ if(count > DUMPMAX) {
|
|
+ count = DUMPMAX;
|
|
+ tag = "\n";
|
|
+ } else {
|
|
+ tag = "\"\n";
|
|
+ }
|
|
+ while(count-- > 0){
|
|
+ if((*x >= ' ') && (*x < 127)) {
|
|
+ fputc(*x, stderr);
|
|
+ } else {
|
|
+ fputc('.', stderr);
|
|
+ }
|
|
+ x++;
|
|
+ }
|
|
+ fputs(tag, stderr);
|
|
+}
|
|
+#endif
|
|
+
|
|
+static void send_ready(unsigned local, unsigned remote, atransport *t)
|
|
+{
|
|
+ D("Calling send_ready \n");
|
|
+ apacket *p = get_apacket();
|
|
+ p->msg.command = A_OKAY;
|
|
+ p->msg.arg0 = local;
|
|
+ p->msg.arg1 = remote;
|
|
+ send_packet(p, t);
|
|
+}
|
|
+
|
|
+static void send_close(unsigned local, unsigned remote, atransport *t)
|
|
+{
|
|
+ D("Calling send_close \n");
|
|
+ apacket *p = get_apacket();
|
|
+ p->msg.command = A_CLSE;
|
|
+ p->msg.arg0 = local;
|
|
+ p->msg.arg1 = remote;
|
|
+ send_packet(p, t);
|
|
+}
|
|
+
|
|
+static size_t fill_connect_data(char *buf, size_t bufsize)
|
|
+{
|
|
+#if ADB_HOST
|
|
+ return snprintf(buf, bufsize, "host::") + 1;
|
|
+#else
|
|
+ static const char *cnxn_props[] = {
|
|
+ "ro.product.name",
|
|
+ "ro.product.model",
|
|
+ "ro.product.device",
|
|
+ };
|
|
+ static const int num_cnxn_props = ARRAY_SIZE(cnxn_props);
|
|
+ static const char *values[] = {
|
|
+ "occam",
|
|
+ "Nexus 4",
|
|
+ "mako",
|
|
+ };
|
|
+ int i;
|
|
+ size_t remaining = bufsize;
|
|
+ size_t len;
|
|
+
|
|
+ len = snprintf(buf, remaining, "%s::", adb_device_banner);
|
|
+ remaining -= len;
|
|
+ buf += len;
|
|
+ for (i = 0; i < num_cnxn_props; i++) {
|
|
+ char value[PROPERTY_VALUE_MAX];
|
|
+ //property_get(cnxn_props[i], value, "");
|
|
+ len = snprintf(buf, remaining, "%s=%s;", cnxn_props[i], values[i]);
|
|
+ remaining -= len;
|
|
+ buf += len;
|
|
+ }
|
|
+
|
|
+ return bufsize - remaining + 1;
|
|
+#endif
|
|
+}
|
|
+
|
|
+static void send_connect(atransport *t)
|
|
+{
|
|
+ D("Calling send_connect \n");
|
|
+ apacket *cp = get_apacket();
|
|
+ cp->msg.command = A_CNXN;
|
|
+ cp->msg.arg0 = A_VERSION;
|
|
+ cp->msg.arg1 = MAX_PAYLOAD;
|
|
+ cp->msg.data_length = fill_connect_data((char *)cp->data,
|
|
+ sizeof(cp->data));
|
|
+ send_packet(cp, t);
|
|
+}
|
|
+
|
|
+static void send_auth_request(atransport *t)
|
|
+{
|
|
+ D("Calling send_auth_request\n");
|
|
+ apacket *p;
|
|
+ int ret;
|
|
+
|
|
+ ret = adb_auth_generate_token(t->token, sizeof(t->token));
|
|
+ if (ret != sizeof(t->token)) {
|
|
+ D("Error generating token ret=%d\n", ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ p = get_apacket();
|
|
+ memcpy(p->data, t->token, ret);
|
|
+ p->msg.command = A_AUTH;
|
|
+ p->msg.arg0 = ADB_AUTH_TOKEN;
|
|
+ p->msg.data_length = ret;
|
|
+ send_packet(p, t);
|
|
+}
|
|
+
|
|
+static void send_auth_response(uint8_t *token, size_t token_size, atransport *t)
|
|
+{
|
|
+ D("Calling send_auth_response\n");
|
|
+ apacket *p = get_apacket();
|
|
+ int ret;
|
|
+
|
|
+ ret = adb_auth_sign(t->key, token, token_size, p->data);
|
|
+ if (!ret) {
|
|
+ D("Error signing the token\n");
|
|
+ put_apacket(p);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ p->msg.command = A_AUTH;
|
|
+ p->msg.arg0 = ADB_AUTH_SIGNATURE;
|
|
+ p->msg.data_length = ret;
|
|
+ send_packet(p, t);
|
|
+}
|
|
+
|
|
+static void send_auth_publickey(atransport *t)
|
|
+{
|
|
+ D("Calling send_auth_publickey\n");
|
|
+ apacket *p = get_apacket();
|
|
+ int ret;
|
|
+
|
|
+ ret = adb_auth_get_userkey(p->data, sizeof(p->data));
|
|
+ if (!ret) {
|
|
+ D("Failed to get user public key\n");
|
|
+ put_apacket(p);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ p->msg.command = A_AUTH;
|
|
+ p->msg.arg0 = ADB_AUTH_RSAPUBLICKEY;
|
|
+ p->msg.data_length = ret;
|
|
+ send_packet(p, t);
|
|
+}
|
|
+
|
|
+void adb_auth_verified(atransport *t)
|
|
+{
|
|
+ handle_online(t);
|
|
+ send_connect(t);
|
|
+}
|
|
+
|
|
+static char *connection_state_name(atransport *t)
|
|
+{
|
|
+ if (t == NULL) {
|
|
+ return "unknown";
|
|
+ }
|
|
+
|
|
+ switch(t->connection_state) {
|
|
+ case CS_BOOTLOADER:
|
|
+ return "bootloader";
|
|
+ case CS_DEVICE:
|
|
+ return "device";
|
|
+ case CS_OFFLINE:
|
|
+ return "offline";
|
|
+ default:
|
|
+ return "unknown";
|
|
+ }
|
|
+}
|
|
+
|
|
+/* qual_overwrite is used to overwrite a qualifier string. dst is a
|
|
+ * pointer to a char pointer. It is assumed that if *dst is non-NULL, it
|
|
+ * was malloc'ed and needs to freed. *dst will be set to a dup of src.
|
|
+ */
|
|
+static void qual_overwrite(char **dst, const char *src)
|
|
+{
|
|
+ if (!dst)
|
|
+ return;
|
|
+
|
|
+ free(*dst);
|
|
+ *dst = NULL;
|
|
+
|
|
+ if (!src || !*src)
|
|
+ return;
|
|
+
|
|
+ *dst = strdup(src);
|
|
+}
|
|
+
|
|
+void parse_banner(char *banner, atransport *t)
|
|
+{
|
|
+ static const char *prop_seps = ";";
|
|
+ static const char key_val_sep = '=';
|
|
+ char *cp;
|
|
+ char *type;
|
|
+
|
|
+ D("parse_banner: %s\n", banner);
|
|
+ type = banner;
|
|
+ cp = strchr(type, ':');
|
|
+ if (cp) {
|
|
+ *cp++ = 0;
|
|
+ /* Nothing is done with second field. */
|
|
+ cp = strchr(cp, ':');
|
|
+ if (cp) {
|
|
+ char *save;
|
|
+ char *key;
|
|
+ key = adb_strtok_r(cp + 1, prop_seps, &save);
|
|
+ while (key) {
|
|
+ cp = strchr(key, key_val_sep);
|
|
+ if (cp) {
|
|
+ *cp++ = '\0';
|
|
+ if (!strcmp(key, "ro.product.name"))
|
|
+ qual_overwrite(&t->product, cp);
|
|
+ else if (!strcmp(key, "ro.product.model"))
|
|
+ qual_overwrite(&t->model, cp);
|
|
+ else if (!strcmp(key, "ro.product.device"))
|
|
+ qual_overwrite(&t->device, cp);
|
|
+ }
|
|
+ key = adb_strtok_r(NULL, prop_seps, &save);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if(!strcmp(type, "bootloader")){
|
|
+ D("setting connection_state to CS_BOOTLOADER\n");
|
|
+ t->connection_state = CS_BOOTLOADER;
|
|
+ update_transports();
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if(!strcmp(type, "device")) {
|
|
+ D("setting connection_state to CS_DEVICE\n");
|
|
+ t->connection_state = CS_DEVICE;
|
|
+ update_transports();
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if(!strcmp(type, "recovery")) {
|
|
+ D("setting connection_state to CS_RECOVERY\n");
|
|
+ t->connection_state = CS_RECOVERY;
|
|
+ update_transports();
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if(!strcmp(type, "sideload")) {
|
|
+ D("setting connection_state to CS_SIDELOAD\n");
|
|
+ t->connection_state = CS_SIDELOAD;
|
|
+ update_transports();
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ t->connection_state = CS_HOST;
|
|
+}
|
|
+
|
|
+void handle_packet(apacket *p, atransport *t)
|
|
+{
|
|
+ asocket *s;
|
|
+
|
|
+ D("handle_packet() %c%c%c%c\n", ((char*) (&(p->msg.command)))[0],
|
|
+ ((char*) (&(p->msg.command)))[1],
|
|
+ ((char*) (&(p->msg.command)))[2],
|
|
+ ((char*) (&(p->msg.command)))[3]);
|
|
+ print_packet("recv", p);
|
|
+
|
|
+ switch(p->msg.command){
|
|
+ case A_SYNC:
|
|
+ if(p->msg.arg0){
|
|
+ send_packet(p, t);
|
|
+ if(HOST) send_connect(t);
|
|
+ } else {
|
|
+ t->connection_state = CS_OFFLINE;
|
|
+ handle_offline(t);
|
|
+ send_packet(p, t);
|
|
+ }
|
|
+ return;
|
|
+
|
|
+ case A_CNXN: /* CONNECT(version, maxdata, "system-id-string") */
|
|
+ /* XXX verify version, etc */
|
|
+ if(t->connection_state != CS_OFFLINE) {
|
|
+ t->connection_state = CS_OFFLINE;
|
|
+ handle_offline(t);
|
|
+ }
|
|
+
|
|
+ parse_banner((char*) p->data, t);
|
|
+
|
|
+ if (HOST || !auth_enabled) {
|
|
+ handle_online(t);
|
|
+ if(!HOST) send_connect(t);
|
|
+ } else {
|
|
+ send_auth_request(t);
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case A_AUTH:
|
|
+ if (p->msg.arg0 == ADB_AUTH_TOKEN) {
|
|
+ t->key = adb_auth_nextkey(t->key);
|
|
+ if (t->key) {
|
|
+ send_auth_response(p->data, p->msg.data_length, t);
|
|
+ } else {
|
|
+ /* No more private keys to try, send the public key */
|
|
+ send_auth_publickey(t);
|
|
+ }
|
|
+ } else if (p->msg.arg0 == ADB_AUTH_SIGNATURE) {
|
|
+ if (adb_auth_verify(t->token, p->data, p->msg.data_length)) {
|
|
+ adb_auth_verified(t);
|
|
+ t->failed_auth_attempts = 0;
|
|
+ } else {
|
|
+ if (t->failed_auth_attempts++ > 10)
|
|
+ adb_sleep_ms(1000);
|
|
+ send_auth_request(t);
|
|
+ }
|
|
+ } else if (p->msg.arg0 == ADB_AUTH_RSAPUBLICKEY) {
|
|
+ adb_auth_confirm_key(p->data, p->msg.data_length, t);
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case A_OPEN: /* OPEN(local-id, 0, "destination") */
|
|
+ if (t->online) {
|
|
+ char *name = (char*) p->data;
|
|
+ name[p->msg.data_length > 0 ? p->msg.data_length - 1 : 0] = 0;
|
|
+ s = create_local_service_socket(name);
|
|
+ if(s == 0) {
|
|
+ send_close(0, p->msg.arg0, t);
|
|
+ } else {
|
|
+ s->peer = create_remote_socket(p->msg.arg0, t);
|
|
+ s->peer->peer = s;
|
|
+ send_ready(s->id, s->peer->id, t);
|
|
+ s->ready(s);
|
|
+ }
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case A_OKAY: /* READY(local-id, remote-id, "") */
|
|
+ if (t->online) {
|
|
+ if((s = find_local_socket(p->msg.arg1))) {
|
|
+ if(s->peer == 0) {
|
|
+ s->peer = create_remote_socket(p->msg.arg0, t);
|
|
+ s->peer->peer = s;
|
|
+ }
|
|
+ s->ready(s);
|
|
+ }
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case A_CLSE: /* CLOSE(local-id, remote-id, "") */
|
|
+ if (t->online) {
|
|
+ if((s = find_local_socket(p->msg.arg1))) {
|
|
+ s->close(s);
|
|
+ }
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case A_WRTE:
|
|
+ if (t->online) {
|
|
+ if((s = find_local_socket(p->msg.arg1))) {
|
|
+ unsigned rid = p->msg.arg0;
|
|
+ p->len = p->msg.data_length;
|
|
+
|
|
+ if(s->enqueue(s, p) == 0) {
|
|
+ D("Enqueue the socket\n");
|
|
+ send_ready(s->id, rid, t);
|
|
+ }
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ printf("handle_packet: what is %08x?!\n", p->msg.command);
|
|
+ }
|
|
+
|
|
+ put_apacket(p);
|
|
+}
|
|
+
|
|
+alistener listener_list = {
|
|
+ .next = &listener_list,
|
|
+ .prev = &listener_list,
|
|
+};
|
|
+
|
|
+static void ss_listener_event_func(int _fd, unsigned ev, void *_l)
|
|
+{
|
|
+ asocket *s;
|
|
+
|
|
+ if(ev & FDE_READ) {
|
|
+ struct sockaddr addr;
|
|
+ socklen_t alen;
|
|
+ int fd;
|
|
+
|
|
+ alen = sizeof(addr);
|
|
+ fd = adb_socket_accept(_fd, &addr, &alen);
|
|
+ if(fd < 0) return;
|
|
+
|
|
+ adb_socket_setbufsize(fd, CHUNK_SIZE);
|
|
+
|
|
+ s = create_local_socket(fd);
|
|
+ if(s) {
|
|
+ connect_to_smartsocket(s);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ adb_close(fd);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void listener_event_func(int _fd, unsigned ev, void *_l)
|
|
+{
|
|
+ alistener *l = _l;
|
|
+ asocket *s;
|
|
+
|
|
+ if(ev & FDE_READ) {
|
|
+ struct sockaddr addr;
|
|
+ socklen_t alen;
|
|
+ int fd;
|
|
+
|
|
+ alen = sizeof(addr);
|
|
+ fd = adb_socket_accept(_fd, &addr, &alen);
|
|
+ if(fd < 0) return;
|
|
+
|
|
+ s = create_local_socket(fd);
|
|
+ if(s) {
|
|
+ s->transport = l->transport;
|
|
+ connect_to_remote(s, l->connect_to);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ adb_close(fd);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void free_listener(alistener* l)
|
|
+{
|
|
+ if (l->next) {
|
|
+ l->next->prev = l->prev;
|
|
+ l->prev->next = l->next;
|
|
+ l->next = l->prev = l;
|
|
+ }
|
|
+
|
|
+ // closes the corresponding fd
|
|
+ fdevent_remove(&l->fde);
|
|
+
|
|
+ if (l->local_name)
|
|
+ free((char*)l->local_name);
|
|
+
|
|
+ if (l->connect_to)
|
|
+ free((char*)l->connect_to);
|
|
+
|
|
+ if (l->transport) {
|
|
+ remove_transport_disconnect(l->transport, &l->disconnect);
|
|
+ }
|
|
+ free(l);
|
|
+}
|
|
+
|
|
+static void listener_disconnect(void* _l, atransport* t)
|
|
+{
|
|
+ alistener* l = _l;
|
|
+
|
|
+ free_listener(l);
|
|
+}
|
|
+
|
|
+int local_name_to_fd(const char *name)
|
|
+{
|
|
+ int port;
|
|
+
|
|
+ if(!strncmp("tcp:", name, 4)){
|
|
+ int ret;
|
|
+ port = atoi(name + 4);
|
|
+
|
|
+ if (gListenAll > 0) {
|
|
+ ret = socket_inaddr_any_server(port, SOCK_STREAM);
|
|
+ } else {
|
|
+ ret = socket_loopback_server(port, SOCK_STREAM);
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+ }
|
|
+#ifndef HAVE_WIN32_IPC /* no Unix-domain sockets on Win32 */
|
|
+ // It's non-sensical to support the "reserved" space on the adb host side
|
|
+ if(!strncmp(name, "local:", 6)) {
|
|
+ return socket_local_server(name + 6,
|
|
+ ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
|
|
+ } else if(!strncmp(name, "localabstract:", 14)) {
|
|
+ return socket_local_server(name + 14,
|
|
+ ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
|
|
+ } else if(!strncmp(name, "localfilesystem:", 16)) {
|
|
+ return socket_local_server(name + 16,
|
|
+ ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
|
|
+ }
|
|
+
|
|
+#endif
|
|
+ printf("unknown local portname '%s'\n", name);
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+// Write a single line describing a listener to a user-provided buffer.
|
|
+// Appends a trailing zero, even in case of truncation, but the function
|
|
+// returns the full line length.
|
|
+// If |buffer| is NULL, does not write but returns required size.
|
|
+static int format_listener(alistener* l, char* buffer, size_t buffer_len) {
|
|
+ // Format is simply:
|
|
+ //
|
|
+ // <device-serial> " " <local-name> " " <remote-name> "\n"
|
|
+ //
|
|
+ int local_len = strlen(l->local_name);
|
|
+ int connect_len = strlen(l->connect_to);
|
|
+ int serial_len = strlen(l->transport->serial);
|
|
+
|
|
+ if (buffer != NULL) {
|
|
+ snprintf(buffer, buffer_len, "%s %s %s\n",
|
|
+ l->transport->serial, l->local_name, l->connect_to);
|
|
+ }
|
|
+ // NOTE: snprintf() on Windows returns -1 in case of truncation, so
|
|
+ // return the computed line length instead.
|
|
+ return local_len + connect_len + serial_len + 3;
|
|
+}
|
|
+
|
|
+// Write the list of current listeners (network redirections) into a
|
|
+// user-provided buffer. Appends a trailing zero, even in case of
|
|
+// trunctaion, but return the full size in bytes.
|
|
+// If |buffer| is NULL, does not write but returns required size.
|
|
+static int format_listeners(char* buf, size_t buflen)
|
|
+{
|
|
+ alistener* l;
|
|
+ int result = 0;
|
|
+ for (l = listener_list.next; l != &listener_list; l = l->next) {
|
|
+ // Ignore special listeners like those for *smartsocket*
|
|
+ if (l->connect_to[0] == '*')
|
|
+ continue;
|
|
+ int len = format_listener(l, buf, buflen);
|
|
+ // Ensure there is space for the trailing zero.
|
|
+ result += len;
|
|
+ if (buf != NULL) {
|
|
+ buf += len;
|
|
+ buflen -= len;
|
|
+ if (buflen <= 0)
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ return result;
|
|
+}
|
|
+
|
|
+static int remove_listener(const char *local_name, atransport* transport)
|
|
+{
|
|
+ alistener *l;
|
|
+
|
|
+ for (l = listener_list.next; l != &listener_list; l = l->next) {
|
|
+ if (!strcmp(local_name, l->local_name)) {
|
|
+ listener_disconnect(l, l->transport);
|
|
+ return 0;
|
|
+ }
|
|
+ }
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+static void remove_all_listeners(void)
|
|
+{
|
|
+ alistener *l, *l_next;
|
|
+ for (l = listener_list.next; l != &listener_list; l = l_next) {
|
|
+ l_next = l->next;
|
|
+ // Never remove smart sockets.
|
|
+ if (l->connect_to[0] == '*')
|
|
+ continue;
|
|
+ listener_disconnect(l, l->transport);
|
|
+ }
|
|
+}
|
|
+
|
|
+// error/status codes for install_listener.
|
|
+typedef enum {
|
|
+ INSTALL_STATUS_OK = 0,
|
|
+ INSTALL_STATUS_INTERNAL_ERROR = -1,
|
|
+ INSTALL_STATUS_CANNOT_BIND = -2,
|
|
+ INSTALL_STATUS_CANNOT_REBIND = -3,
|
|
+} install_status_t;
|
|
+
|
|
+static install_status_t install_listener(const char *local_name,
|
|
+ const char *connect_to,
|
|
+ atransport* transport,
|
|
+ int no_rebind)
|
|
+{
|
|
+ alistener *l;
|
|
+
|
|
+ printf("install_listener('%s','%s')\n", local_name, connect_to);
|
|
+
|
|
+ for(l = listener_list.next; l != &listener_list; l = l->next){
|
|
+ if(strcmp(local_name, l->local_name) == 0) {
|
|
+ char *cto;
|
|
+
|
|
+ /* can't repurpose a smartsocket */
|
|
+ if(l->connect_to[0] == '*') {
|
|
+ return INSTALL_STATUS_INTERNAL_ERROR;
|
|
+ }
|
|
+
|
|
+ /* can't repurpose a listener if 'no_rebind' is true */
|
|
+ if (no_rebind) {
|
|
+ return INSTALL_STATUS_CANNOT_REBIND;
|
|
+ }
|
|
+
|
|
+ cto = strdup(connect_to);
|
|
+ if(cto == 0) {
|
|
+ return INSTALL_STATUS_INTERNAL_ERROR;
|
|
+ }
|
|
+
|
|
+ //printf("rebinding '%s' to '%s'\n", local_name, connect_to);
|
|
+ free((void*) l->connect_to);
|
|
+ l->connect_to = cto;
|
|
+ if (l->transport != transport) {
|
|
+ remove_transport_disconnect(l->transport, &l->disconnect);
|
|
+ l->transport = transport;
|
|
+ add_transport_disconnect(l->transport, &l->disconnect);
|
|
+ }
|
|
+ return INSTALL_STATUS_OK;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if((l = calloc(1, sizeof(alistener))) == 0) goto nomem;
|
|
+ if((l->local_name = strdup(local_name)) == 0) goto nomem;
|
|
+ if((l->connect_to = strdup(connect_to)) == 0) goto nomem;
|
|
+
|
|
+
|
|
+ l->fd = local_name_to_fd(local_name);
|
|
+ if(l->fd < 0) {
|
|
+ free((void*) l->local_name);
|
|
+ free((void*) l->connect_to);
|
|
+ free(l);
|
|
+ printf("cannot bind '%s'\n", local_name);
|
|
+ return -2;
|
|
+ }
|
|
+
|
|
+ close_on_exec(l->fd);
|
|
+ if(!strcmp(l->connect_to, "*smartsocket*")) {
|
|
+ fdevent_install(&l->fde, l->fd, ss_listener_event_func, l);
|
|
+ } else {
|
|
+ fdevent_install(&l->fde, l->fd, listener_event_func, l);
|
|
+ }
|
|
+ fdevent_set(&l->fde, FDE_READ);
|
|
+
|
|
+ l->next = &listener_list;
|
|
+ l->prev = listener_list.prev;
|
|
+ l->next->prev = l;
|
|
+ l->prev->next = l;
|
|
+ l->transport = transport;
|
|
+
|
|
+ if (transport) {
|
|
+ l->disconnect.opaque = l;
|
|
+ l->disconnect.func = listener_disconnect;
|
|
+ add_transport_disconnect(transport, &l->disconnect);
|
|
+ }
|
|
+ return INSTALL_STATUS_OK;
|
|
+
|
|
+nomem:
|
|
+ fatal("cannot allocate listener");
|
|
+ return INSTALL_STATUS_INTERNAL_ERROR;
|
|
+}
|
|
+
|
|
+#ifdef HAVE_WIN32_PROC
|
|
+static BOOL WINAPI ctrlc_handler(DWORD type)
|
|
+{
|
|
+ exit(STATUS_CONTROL_C_EXIT);
|
|
+ return TRUE;
|
|
+}
|
|
+#endif
|
|
+
|
|
+static void adb_cleanup(void)
|
|
+{
|
|
+ usb_cleanup();
|
|
+}
|
|
+
|
|
+void start_logging(void)
|
|
+{
|
|
+#ifdef HAVE_WIN32_PROC
|
|
+ char temp[ MAX_PATH ];
|
|
+ FILE* fnul;
|
|
+ FILE* flog;
|
|
+
|
|
+ GetTempPath( sizeof(temp) - 8, temp );
|
|
+ strcat( temp, "adb.log" );
|
|
+
|
|
+ /* Win32 specific redirections */
|
|
+ fnul = fopen( "NUL", "rt" );
|
|
+ if (fnul != NULL)
|
|
+ stdin[0] = fnul[0];
|
|
+
|
|
+ flog = fopen( temp, "at" );
|
|
+ if (flog == NULL)
|
|
+ flog = fnul;
|
|
+
|
|
+ setvbuf( flog, NULL, _IONBF, 0 );
|
|
+
|
|
+ stdout[0] = flog[0];
|
|
+ stderr[0] = flog[0];
|
|
+ fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid());
|
|
+#else
|
|
+ int fd;
|
|
+
|
|
+ fd = unix_open("/dev/null", O_RDONLY);
|
|
+ dup2(fd, 0);
|
|
+ adb_close(fd);
|
|
+
|
|
+ fd = unix_open("/tmp/adb.log", O_WRONLY | O_CREAT | O_APPEND, 0640);
|
|
+ if(fd < 0) {
|
|
+ fd = unix_open("/dev/null", O_WRONLY);
|
|
+ }
|
|
+ dup2(fd, 1);
|
|
+ dup2(fd, 2);
|
|
+ adb_close(fd);
|
|
+ fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid());
|
|
+#endif
|
|
+}
|
|
+
|
|
+#if !ADB_HOST
|
|
+void start_device_log(void)
|
|
+{
|
|
+ int fd;
|
|
+ char path[PATH_MAX];
|
|
+ struct tm now;
|
|
+ time_t t;
|
|
+ char value[PROPERTY_VALUE_MAX];
|
|
+
|
|
+ // read the trace mask from persistent property persist.adb.trace_mask
|
|
+ // give up if the property is not set or cannot be parsed
|
|
+ //property_get("persist.adb.trace_mask", value, "");
|
|
+ //if (sscanf(value, "%x", &adb_trace_mask) != 1)
|
|
+ return;
|
|
+
|
|
+ adb_mkdir("/data/adb", 0775);
|
|
+ tzset();
|
|
+ time(&t);
|
|
+ localtime_r(&t, &now);
|
|
+ strftime(path, sizeof(path),
|
|
+ "/data/adb/adb-%Y-%m-%d-%H-%M-%S.txt",
|
|
+ &now);
|
|
+ fd = unix_open(path, O_WRONLY | O_CREAT | O_TRUNC, 0640);
|
|
+ if (fd < 0)
|
|
+ return;
|
|
+
|
|
+ // redirect stdout and stderr to the log file
|
|
+ dup2(fd, 1);
|
|
+ dup2(fd, 2);
|
|
+ fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid());
|
|
+ adb_close(fd);
|
|
+
|
|
+ fd = unix_open("/dev/null", O_RDONLY);
|
|
+ dup2(fd, 0);
|
|
+ adb_close(fd);
|
|
+}
|
|
+#endif
|
|
+
|
|
+#if ADB_HOST
|
|
+int launch_server(int server_port)
|
|
+{
|
|
+#ifdef HAVE_WIN32_PROC
|
|
+ /* we need to start the server in the background */
|
|
+ /* we create a PIPE that will be used to wait for the server's "OK" */
|
|
+ /* message since the pipe handles must be inheritable, we use a */
|
|
+ /* security attribute */
|
|
+ HANDLE pipe_read, pipe_write;
|
|
+ HANDLE stdout_handle, stderr_handle;
|
|
+ SECURITY_ATTRIBUTES sa;
|
|
+ STARTUPINFO startup;
|
|
+ PROCESS_INFORMATION pinfo;
|
|
+ char program_path[ MAX_PATH ];
|
|
+ int ret;
|
|
+
|
|
+ sa.nLength = sizeof(sa);
|
|
+ sa.lpSecurityDescriptor = NULL;
|
|
+ sa.bInheritHandle = TRUE;
|
|
+
|
|
+ /* create pipe, and ensure its read handle isn't inheritable */
|
|
+ ret = CreatePipe( &pipe_read, &pipe_write, &sa, 0 );
|
|
+ if (!ret) {
|
|
+ fprintf(stderr, "CreatePipe() failure, error %ld\n", GetLastError() );
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ SetHandleInformation( pipe_read, HANDLE_FLAG_INHERIT, 0 );
|
|
+
|
|
+ /* Some programs want to launch an adb command and collect its output by
|
|
+ * calling CreateProcess with inheritable stdout/stderr handles, then
|
|
+ * using read() to get its output. When this happens, the stdout/stderr
|
|
+ * handles passed to the adb client process will also be inheritable.
|
|
+ * When starting the adb server here, care must be taken to reset them
|
|
+ * to non-inheritable.
|
|
+ * Otherwise, something bad happens: even if the adb command completes,
|
|
+ * the calling process is stuck while read()-ing from the stdout/stderr
|
|
+ * descriptors, because they're connected to corresponding handles in the
|
|
+ * adb server process (even if the latter never uses/writes to them).
|
|
+ */
|
|
+ stdout_handle = GetStdHandle( STD_OUTPUT_HANDLE );
|
|
+ stderr_handle = GetStdHandle( STD_ERROR_HANDLE );
|
|
+ if (stdout_handle != INVALID_HANDLE_VALUE) {
|
|
+ SetHandleInformation( stdout_handle, HANDLE_FLAG_INHERIT, 0 );
|
|
+ }
|
|
+ if (stderr_handle != INVALID_HANDLE_VALUE) {
|
|
+ SetHandleInformation( stderr_handle, HANDLE_FLAG_INHERIT, 0 );
|
|
+ }
|
|
+
|
|
+ ZeroMemory( &startup, sizeof(startup) );
|
|
+ startup.cb = sizeof(startup);
|
|
+ startup.hStdInput = GetStdHandle( STD_INPUT_HANDLE );
|
|
+ startup.hStdOutput = pipe_write;
|
|
+ startup.hStdError = GetStdHandle( STD_ERROR_HANDLE );
|
|
+ startup.dwFlags = STARTF_USESTDHANDLES;
|
|
+
|
|
+ ZeroMemory( &pinfo, sizeof(pinfo) );
|
|
+
|
|
+ /* get path of current program */
|
|
+ GetModuleFileName( NULL, program_path, sizeof(program_path) );
|
|
+
|
|
+ ret = CreateProcess(
|
|
+ program_path, /* program path */
|
|
+ "adb fork-server server",
|
|
+ /* the fork-server argument will set the
|
|
+ debug = 2 in the child */
|
|
+ NULL, /* process handle is not inheritable */
|
|
+ NULL, /* thread handle is not inheritable */
|
|
+ TRUE, /* yes, inherit some handles */
|
|
+ DETACHED_PROCESS, /* the new process doesn't have a console */
|
|
+ NULL, /* use parent's environment block */
|
|
+ NULL, /* use parent's starting directory */
|
|
+ &startup, /* startup info, i.e. std handles */
|
|
+ &pinfo );
|
|
+
|
|
+ CloseHandle( pipe_write );
|
|
+
|
|
+ if (!ret) {
|
|
+ fprintf(stderr, "CreateProcess failure, error %ld\n", GetLastError() );
|
|
+ CloseHandle( pipe_read );
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ CloseHandle( pinfo.hProcess );
|
|
+ CloseHandle( pinfo.hThread );
|
|
+
|
|
+ /* wait for the "OK\n" message */
|
|
+ {
|
|
+ char temp[3];
|
|
+ DWORD count;
|
|
+
|
|
+ ret = ReadFile( pipe_read, temp, 3, &count, NULL );
|
|
+ CloseHandle( pipe_read );
|
|
+ if ( !ret ) {
|
|
+ fprintf(stderr, "could not read ok from ADB Server, error = %ld\n", GetLastError() );
|
|
+ return -1;
|
|
+ }
|
|
+ if (count != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
|
|
+ fprintf(stderr, "ADB server didn't ACK\n" );
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+#elif defined(HAVE_FORKEXEC)
|
|
+ char path[PATH_MAX];
|
|
+ int fd[2];
|
|
+
|
|
+ // set up a pipe so the child can tell us when it is ready.
|
|
+ // fd[0] will be parent's end, and fd[1] will get mapped to stderr in the child.
|
|
+ if (pipe(fd)) {
|
|
+ fprintf(stderr, "pipe failed in launch_server, errno: %d\n", errno);
|
|
+ return -1;
|
|
+ }
|
|
+ get_my_path(path, PATH_MAX);
|
|
+ pid_t pid = fork();
|
|
+ if(pid < 0) return -1;
|
|
+
|
|
+ if (pid == 0) {
|
|
+ // child side of the fork
|
|
+
|
|
+ // redirect stderr to the pipe
|
|
+ // we use stderr instead of stdout due to stdout's buffering behavior.
|
|
+ adb_close(fd[0]);
|
|
+ dup2(fd[1], STDERR_FILENO);
|
|
+ adb_close(fd[1]);
|
|
+
|
|
+ char str_port[30];
|
|
+ snprintf(str_port, sizeof(str_port), "%d", server_port);
|
|
+ // child process
|
|
+ int result = execl(path, "adb", "-P", str_port, "fork-server", "server", NULL);
|
|
+ // this should not return
|
|
+ fprintf(stderr, "OOPS! execl returned %d, errno: %d\n", result, errno);
|
|
+ } else {
|
|
+ // parent side of the fork
|
|
+
|
|
+ char temp[3];
|
|
+
|
|
+ temp[0] = 'A'; temp[1] = 'B'; temp[2] = 'C';
|
|
+ // wait for the "OK\n" message
|
|
+ adb_close(fd[1]);
|
|
+ int ret = adb_read(fd[0], temp, 3);
|
|
+ int saved_errno = errno;
|
|
+ adb_close(fd[0]);
|
|
+ if (ret < 0) {
|
|
+ fprintf(stderr, "could not read ok from ADB Server, errno = %d\n", saved_errno);
|
|
+ return -1;
|
|
+ }
|
|
+ if (ret != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
|
|
+ fprintf(stderr, "ADB server didn't ACK\n" );
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ setsid();
|
|
+ }
|
|
+#else
|
|
+#error "cannot implement background server start on this platform"
|
|
+#endif
|
|
+ return 0;
|
|
+}
|
|
+#endif
|
|
+
|
|
+/* Constructs a local name of form tcp:port.
|
|
+ * target_str points to the target string, it's content will be overwritten.
|
|
+ * target_size is the capacity of the target string.
|
|
+ * server_port is the port number to use for the local name.
|
|
+ */
|
|
+void build_local_name(char* target_str, size_t target_size, int server_port)
|
|
+{
|
|
+ snprintf(target_str, target_size, "tcp:%d", server_port);
|
|
+}
|
|
+
|
|
+#if !ADB_HOST
|
|
+static int should_drop_privileges() {
|
|
+#ifndef ALLOW_ADBD_ROOT
|
|
+ return 1;
|
|
+#else /* ALLOW_ADBD_ROOT */
|
|
+ int secure = 0;
|
|
+ char value[PROPERTY_VALUE_MAX];
|
|
+
|
|
+ return 0;
|
|
+ /* run adbd in secure mode if ro.secure is set and
|
|
+ ** we are not in the emulator
|
|
+ */
|
|
+// property_get("ro.kernel.qemu", value, "");
|
|
+ if (strcmp(value, "1") != 0) {
|
|
+// property_get("ro.secure", value, "1");
|
|
+ if (strcmp(value, "1") == 0) {
|
|
+ // don't run as root if ro.secure is set...
|
|
+ secure = 1;
|
|
+
|
|
+ // ... except we allow running as root in userdebug builds if the
|
|
+ // service.adb.root property has been set by the "adb root" command
|
|
+// property_get("ro.debuggable", value, "");
|
|
+ if (strcmp(value, "1") == 0) {
|
|
+// property_get("service.adb.root", value, "");
|
|
+ if (strcmp(value, "1") == 0) {
|
|
+ secure = 0;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return secure;
|
|
+#endif /* ALLOW_ADBD_ROOT */
|
|
+}
|
|
+#endif /* !ADB_HOST */
|
|
+
|
|
+int adb_main(int is_daemon, int server_port)
|
|
+{
|
|
+#if !ADB_HOST
|
|
+ int port;
|
|
+ char value[PROPERTY_VALUE_MAX];
|
|
+
|
|
+ umask(000);
|
|
+#endif
|
|
+
|
|
+ atexit(adb_cleanup);
|
|
+#ifdef HAVE_WIN32_PROC
|
|
+ SetConsoleCtrlHandler( ctrlc_handler, TRUE );
|
|
+#elif defined(HAVE_FORKEXEC)
|
|
+ // No SIGCHLD. Let the service subproc handle its children.
|
|
+ signal(SIGPIPE, SIG_IGN);
|
|
+#endif
|
|
+
|
|
+ init_transport_registration();
|
|
+
|
|
+#if ADB_HOST
|
|
+ HOST = 1;
|
|
+ usb_vendors_init();
|
|
+ usb_init();
|
|
+ local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
|
|
+ adb_auth_init();
|
|
+
|
|
+ char local_name[30];
|
|
+ build_local_name(local_name, sizeof(local_name), server_port);
|
|
+ if(install_listener(local_name, "*smartsocket*", NULL, 0)) {
|
|
+ exit(1);
|
|
+ }
|
|
+#else
|
|
+ //property_get("ro.adb.secure", value, "0");
|
|
+ auth_enabled = 0;//!strcmp(value, "1");
|
|
+ if (auth_enabled)
|
|
+ adb_auth_init();
|
|
+
|
|
+ // Our external storage path may be different than apps, since
|
|
+ // we aren't able to bind mount after dropping root.
|
|
+ const char* adb_external_storage = getenv("ADB_EXTERNAL_STORAGE");
|
|
+ if (NULL != adb_external_storage) {
|
|
+ setenv("EXTERNAL_STORAGE", adb_external_storage, 1);
|
|
+ } else {
|
|
+ D("Warning: ADB_EXTERNAL_STORAGE is not set. Leaving EXTERNAL_STORAGE"
|
|
+ " unchanged.\n");
|
|
+ }
|
|
+
|
|
+ /* don't listen on a port (default 5037) if running in secure mode */
|
|
+ /* don't run as root if we are running in secure mode */
|
|
+ if (should_drop_privileges()) {
|
|
+ struct __user_cap_header_struct header;
|
|
+ struct __user_cap_data_struct cap[2];
|
|
+
|
|
+ if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
|
|
+ exit(1);
|
|
+ }
|
|
+
|
|
+ /* add extra groups:
|
|
+ ** AID_ADB to access the USB driver
|
|
+ ** AID_LOG to read system logs (adb logcat)
|
|
+ ** AID_INPUT to diagnose input issues (getevent)
|
|
+ ** AID_INET to diagnose network issues (netcfg, ping)
|
|
+ ** AID_GRAPHICS to access the frame buffer
|
|
+ ** AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump)
|
|
+ ** AID_SDCARD_R to allow reading from the SD card
|
|
+ ** AID_SDCARD_RW to allow writing to the SD card
|
|
+ ** AID_MOUNT to allow unmounting the SD card before rebooting
|
|
+ ** AID_NET_BW_STATS to read out qtaguid statistics
|
|
+ */
|
|
+ gid_t groups[] = { AID_ADB, AID_LOG, AID_INPUT, AID_INET, AID_GRAPHICS,
|
|
+ AID_NET_BT, AID_NET_BT_ADMIN, AID_SDCARD_R, AID_SDCARD_RW,
|
|
+ AID_MOUNT, AID_NET_BW_STATS };
|
|
+ if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
|
|
+ exit(1);
|
|
+ }
|
|
+
|
|
+ /* then switch user and group to "shell" */
|
|
+ if (setgid(AID_SHELL) != 0) {
|
|
+ exit(1);
|
|
+ }
|
|
+ if (setuid(AID_SHELL) != 0) {
|
|
+ exit(1);
|
|
+ }
|
|
+
|
|
+ memset(&header, 0, sizeof(header));
|
|
+ memset(cap, 0, sizeof(cap));
|
|
+
|
|
+ /* set CAP_SYS_BOOT capability, so "adb reboot" will succeed */
|
|
+ header.version = _LINUX_CAPABILITY_VERSION_3;
|
|
+ header.pid = 0;
|
|
+ cap[CAP_TO_INDEX(CAP_SYS_BOOT)].effective |= CAP_TO_MASK(CAP_SYS_BOOT);
|
|
+ cap[CAP_TO_INDEX(CAP_SYS_BOOT)].permitted |= CAP_TO_MASK(CAP_SYS_BOOT);
|
|
+ capset(&header, cap);
|
|
+
|
|
+ D("Local port disabled\n");
|
|
+ } else {
|
|
+ char local_name[30];
|
|
+ build_local_name(local_name, sizeof(local_name), server_port);
|
|
+ if(install_listener(local_name, "*smartsocket*", NULL, 0)) {
|
|
+ exit(1);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ int usb = 0;
|
|
+ if (access(ADB_TCP_MODE, 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 ADB TCPIP MODE\n");
|
|
+ // listen on default port
|
|
+ local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
|
|
+ }
|
|
+
|
|
+ D("adb_main(): pre init_jdwp()\n");
|
|
+ init_jdwp();
|
|
+ D("adb_main(): post init_jdwp()\n");
|
|
+#endif
|
|
+
|
|
+ if (is_daemon)
|
|
+ {
|
|
+ // inform our parent that we are up and running.
|
|
+#ifdef HAVE_WIN32_PROC
|
|
+ DWORD count;
|
|
+ WriteFile( GetStdHandle( STD_OUTPUT_HANDLE ), "OK\n", 3, &count, NULL );
|
|
+#elif defined(HAVE_FORKEXEC)
|
|
+ fprintf(stderr, "OK\n");
|
|
+#endif
|
|
+ start_logging();
|
|
+ }
|
|
+ D("Event loop starting\n");
|
|
+
|
|
+ fdevent_loop();
|
|
+
|
|
+ usb_cleanup();
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+#if ADB_HOST
|
|
+void connect_device(char* host, char* buffer, int buffer_size)
|
|
+{
|
|
+ int port, fd;
|
|
+ char* portstr = strchr(host, ':');
|
|
+ char hostbuf[100];
|
|
+ char serial[100];
|
|
+
|
|
+ strncpy(hostbuf, host, sizeof(hostbuf) - 1);
|
|
+ if (portstr) {
|
|
+ if (portstr - host >= (ptrdiff_t)sizeof(hostbuf)) {
|
|
+ snprintf(buffer, buffer_size, "bad host name %s", host);
|
|
+ return;
|
|
+ }
|
|
+ // zero terminate the host at the point we found the colon
|
|
+ hostbuf[portstr - host] = 0;
|
|
+ if (sscanf(portstr + 1, "%d", &port) == 0) {
|
|
+ snprintf(buffer, buffer_size, "bad port number %s", portstr);
|
|
+ return;
|
|
+ }
|
|
+ } else {
|
|
+ port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
|
|
+ }
|
|
+
|
|
+ snprintf(serial, sizeof(serial), "%s:%d", hostbuf, port);
|
|
+ if (find_transport(serial)) {
|
|
+ snprintf(buffer, buffer_size, "already connected to %s", serial);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ fd = socket_network_client(hostbuf, port, SOCK_STREAM);
|
|
+ if (fd < 0) {
|
|
+ snprintf(buffer, buffer_size, "unable to connect to %s:%d", host, port);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ D("client: connected on remote on fd %d\n", fd);
|
|
+ close_on_exec(fd);
|
|
+ disable_tcp_nagle(fd);
|
|
+ register_socket_transport(fd, serial, port, 0);
|
|
+ snprintf(buffer, buffer_size, "connected to %s", serial);
|
|
+}
|
|
+
|
|
+void connect_emulator(char* port_spec, char* buffer, int buffer_size)
|
|
+{
|
|
+ char* port_separator = strchr(port_spec, ',');
|
|
+ if (!port_separator) {
|
|
+ snprintf(buffer, buffer_size,
|
|
+ "unable to parse '%s' as <console port>,<adb port>",
|
|
+ port_spec);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ // Zero-terminate console port and make port_separator point to 2nd port.
|
|
+ *port_separator++ = 0;
|
|
+ int console_port = strtol(port_spec, NULL, 0);
|
|
+ int adb_port = strtol(port_separator, NULL, 0);
|
|
+ if (!(console_port > 0 && adb_port > 0)) {
|
|
+ *(port_separator - 1) = ',';
|
|
+ snprintf(buffer, buffer_size,
|
|
+ "Invalid port numbers: Expected positive numbers, got '%s'",
|
|
+ port_spec);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ /* Check if the emulator is already known.
|
|
+ * Note: There's a small but harmless race condition here: An emulator not
|
|
+ * present just yet could be registered by another invocation right
|
|
+ * after doing this check here. However, local_connect protects
|
|
+ * against double-registration too. From here, a better error message
|
|
+ * can be produced. In the case of the race condition, the very specific
|
|
+ * error message won't be shown, but the data doesn't get corrupted. */
|
|
+ atransport* known_emulator = find_emulator_transport_by_adb_port(adb_port);
|
|
+ if (known_emulator != NULL) {
|
|
+ snprintf(buffer, buffer_size,
|
|
+ "Emulator on port %d already registered.", adb_port);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ /* Check if more emulators can be registered. Similar unproblematic
|
|
+ * race condition as above. */
|
|
+ int candidate_slot = get_available_local_transport_index();
|
|
+ if (candidate_slot < 0) {
|
|
+ snprintf(buffer, buffer_size, "Cannot accept more emulators.");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ /* Preconditions met, try to connect to the emulator. */
|
|
+ if (!local_connect_arbitrary_ports(console_port, adb_port)) {
|
|
+ snprintf(buffer, buffer_size,
|
|
+ "Connected to emulator on ports %d,%d", console_port, adb_port);
|
|
+ } else {
|
|
+ snprintf(buffer, buffer_size,
|
|
+ "Could not connect to emulator on ports %d,%d",
|
|
+ console_port, adb_port);
|
|
+ }
|
|
+}
|
|
+#endif
|
|
+
|
|
+int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s)
|
|
+{
|
|
+ atransport *transport = NULL;
|
|
+ char buf[4096];
|
|
+
|
|
+ if(!strcmp(service, "kill")) {
|
|
+ fprintf(stderr,"adb server killed by remote request\n");
|
|
+ fflush(stdout);
|
|
+ adb_write(reply_fd, "OKAY", 4);
|
|
+ usb_cleanup();
|
|
+ exit(0);
|
|
+ }
|
|
+
|
|
+#if ADB_HOST
|
|
+ // "transport:" is used for switching transport with a specified serial number
|
|
+ // "transport-usb:" is used for switching transport to the only USB transport
|
|
+ // "transport-local:" is used for switching transport to the only local transport
|
|
+ // "transport-any:" is used for switching transport to the only transport
|
|
+ if (!strncmp(service, "transport", strlen("transport"))) {
|
|
+ char* error_string = "unknown failure";
|
|
+ transport_type type = kTransportAny;
|
|
+
|
|
+ if (!strncmp(service, "transport-usb", strlen("transport-usb"))) {
|
|
+ type = kTransportUsb;
|
|
+ } else if (!strncmp(service, "transport-local", strlen("transport-local"))) {
|
|
+ type = kTransportLocal;
|
|
+ } else if (!strncmp(service, "transport-any", strlen("transport-any"))) {
|
|
+ type = kTransportAny;
|
|
+ } else if (!strncmp(service, "transport:", strlen("transport:"))) {
|
|
+ service += strlen("transport:");
|
|
+ serial = service;
|
|
+ }
|
|
+
|
|
+ transport = acquire_one_transport(CS_ANY, type, serial, &error_string);
|
|
+
|
|
+ if (transport) {
|
|
+ s->transport = transport;
|
|
+ adb_write(reply_fd, "OKAY", 4);
|
|
+ } else {
|
|
+ sendfailmsg(reply_fd, error_string);
|
|
+ }
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ // return a list of all connected devices
|
|
+ if (!strncmp(service, "devices", 7)) {
|
|
+ char buffer[4096];
|
|
+ int use_long = !strcmp(service+7, "-l");
|
|
+ if (use_long || service[7] == 0) {
|
|
+ memset(buf, 0, sizeof(buf));
|
|
+ memset(buffer, 0, sizeof(buffer));
|
|
+ D("Getting device list \n");
|
|
+ list_transports(buffer, sizeof(buffer), use_long);
|
|
+ snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer),buffer);
|
|
+ D("Wrote device list \n");
|
|
+ writex(reply_fd, buf, strlen(buf));
|
|
+ return 0;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // add a new TCP transport, device or emulator
|
|
+ if (!strncmp(service, "connect:", 8)) {
|
|
+ char buffer[4096];
|
|
+ char* host = service + 8;
|
|
+ if (!strncmp(host, "emu:", 4)) {
|
|
+ connect_emulator(host + 4, buffer, sizeof(buffer));
|
|
+ } else {
|
|
+ connect_device(host, buffer, sizeof(buffer));
|
|
+ }
|
|
+ // Send response for emulator and device
|
|
+ snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer), buffer);
|
|
+ writex(reply_fd, buf, strlen(buf));
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ // remove TCP transport
|
|
+ if (!strncmp(service, "disconnect:", 11)) {
|
|
+ char buffer[4096];
|
|
+ memset(buffer, 0, sizeof(buffer));
|
|
+ char* serial = service + 11;
|
|
+ if (serial[0] == 0) {
|
|
+ // disconnect from all TCP devices
|
|
+ unregister_all_tcp_transports();
|
|
+ } else {
|
|
+ char hostbuf[100];
|
|
+ // assume port 5555 if no port is specified
|
|
+ if (!strchr(serial, ':')) {
|
|
+ snprintf(hostbuf, sizeof(hostbuf) - 1, "%s:5555", serial);
|
|
+ serial = hostbuf;
|
|
+ }
|
|
+ atransport *t = find_transport(serial);
|
|
+
|
|
+ if (t) {
|
|
+ unregister_transport(t);
|
|
+ } else {
|
|
+ snprintf(buffer, sizeof(buffer), "No such device %s", serial);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer), buffer);
|
|
+ writex(reply_fd, buf, strlen(buf));
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ // returns our value for ADB_SERVER_VERSION
|
|
+ if (!strcmp(service, "version")) {
|
|
+ char version[12];
|
|
+ snprintf(version, sizeof version, "%04x", ADB_SERVER_VERSION);
|
|
+ snprintf(buf, sizeof buf, "OKAY%04x%s", (unsigned)strlen(version), version);
|
|
+ writex(reply_fd, buf, strlen(buf));
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if(!strncmp(service,"get-serialno",strlen("get-serialno"))) {
|
|
+ char *out = "unknown";
|
|
+ transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
|
|
+ if (transport && transport->serial) {
|
|
+ out = transport->serial;
|
|
+ }
|
|
+ snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(out),out);
|
|
+ writex(reply_fd, buf, strlen(buf));
|
|
+ return 0;
|
|
+ }
|
|
+ if(!strncmp(service,"get-devpath",strlen("get-devpath"))) {
|
|
+ char *out = "unknown";
|
|
+ transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
|
|
+ if (transport && transport->devpath) {
|
|
+ out = transport->devpath;
|
|
+ }
|
|
+ snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(out),out);
|
|
+ writex(reply_fd, buf, strlen(buf));
|
|
+ return 0;
|
|
+ }
|
|
+ // indicates a new emulator instance has started
|
|
+ if (!strncmp(service,"emulator:",9)) {
|
|
+ int port = atoi(service+9);
|
|
+ local_connect(port);
|
|
+ /* we don't even need to send a reply */
|
|
+ return 0;
|
|
+ }
|
|
+#endif // ADB_HOST
|
|
+
|
|
+ if(!strcmp(service,"list-forward")) {
|
|
+ // Create the list of forward redirections.
|
|
+ char header[9];
|
|
+ int buffer_size = format_listeners(NULL, 0);
|
|
+ // Add one byte for the trailing zero.
|
|
+ char* buffer = malloc(buffer_size+1);
|
|
+ (void) format_listeners(buffer, buffer_size+1);
|
|
+ snprintf(header, sizeof header, "OKAY%04x", buffer_size);
|
|
+ writex(reply_fd, header, 8);
|
|
+ writex(reply_fd, buffer, buffer_size);
|
|
+ free(buffer);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (!strcmp(service,"killforward-all")) {
|
|
+ remove_all_listeners();
|
|
+ adb_write(reply_fd, "OKAYOKAY", 8);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if(!strncmp(service,"forward:",8) ||
|
|
+ !strncmp(service,"killforward:",12)) {
|
|
+ char *local, *remote, *err;
|
|
+ int r;
|
|
+ atransport *transport;
|
|
+
|
|
+ int createForward = strncmp(service,"kill",4);
|
|
+ int no_rebind = 0;
|
|
+
|
|
+ local = strchr(service, ':') + 1;
|
|
+
|
|
+ // Handle forward:norebind:<local>... here
|
|
+ if (createForward && !strncmp(local, "norebind:", 9)) {
|
|
+ no_rebind = 1;
|
|
+ local = strchr(local, ':') + 1;
|
|
+ }
|
|
+
|
|
+ remote = strchr(local,';');
|
|
+
|
|
+ if (createForward) {
|
|
+ // Check forward: parameter format: '<local>;<remote>'
|
|
+ if(remote == 0) {
|
|
+ sendfailmsg(reply_fd, "malformed forward spec");
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ *remote++ = 0;
|
|
+ if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')){
|
|
+ sendfailmsg(reply_fd, "malformed forward spec");
|
|
+ return 0;
|
|
+ }
|
|
+ } else {
|
|
+ // Check killforward: parameter format: '<local>'
|
|
+ if (local[0] == 0) {
|
|
+ sendfailmsg(reply_fd, "malformed forward spec");
|
|
+ return 0;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ transport = acquire_one_transport(CS_ANY, ttype, serial, &err);
|
|
+ if (!transport) {
|
|
+ sendfailmsg(reply_fd, err);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (createForward) {
|
|
+ r = install_listener(local, remote, transport, no_rebind);
|
|
+ } else {
|
|
+ r = remove_listener(local, transport);
|
|
+ }
|
|
+ if(r == 0) {
|
|
+ /* 1st OKAY is connect, 2nd OKAY is status */
|
|
+ writex(reply_fd, "OKAYOKAY", 8);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (createForward) {
|
|
+ const char* message;
|
|
+ switch (r) {
|
|
+ case INSTALL_STATUS_CANNOT_BIND:
|
|
+ message = "cannot bind to socket";
|
|
+ break;
|
|
+ case INSTALL_STATUS_CANNOT_REBIND:
|
|
+ message = "cannot rebind existing socket";
|
|
+ break;
|
|
+ default:
|
|
+ message = "internal error";
|
|
+ }
|
|
+ sendfailmsg(reply_fd, message);
|
|
+ } else {
|
|
+ sendfailmsg(reply_fd, "cannot remove listener");
|
|
+ }
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if(!strncmp(service,"get-state",strlen("get-state"))) {
|
|
+ transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
|
|
+ char *state = connection_state_name(transport);
|
|
+ snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(state),state);
|
|
+ writex(reply_fd, buf, strlen(buf));
|
|
+ return 0;
|
|
+ }
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+#if !ADB_HOST
|
|
+int recovery_mode = 0;
|
|
+#endif
|
|
+
|
|
+int main(int argc, char **argv)
|
|
+{
|
|
+#if ADB_HOST
|
|
+ adb_sysdeps_init();
|
|
+ adb_trace_init();
|
|
+ D("Handling commandline()\n");
|
|
+ return adb_commandline(argc - 1, argv + 1);
|
|
+#else
|
|
+ /* If adbd runs inside the emulator this will enable adb tracing via
|
|
+ * adb-debug qemud service in the emulator. */
|
|
+ adb_qemu_trace_init();
|
|
+ if((argc > 1) && (!strcmp(argv[1],"recovery"))) {
|
|
+ adb_device_banner = "recovery";
|
|
+ recovery_mode = 1;
|
|
+ }
|
|
+
|
|
+ start_device_log();
|
|
+ D("Handling main()\n");
|
|
+ return adb_main(0, DEFAULT_ADB_PORT);
|
|
+#endif
|
|
+}
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/adb.h
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/adb.h 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,491 @@
|
|
+/*
|
|
+ * Copyright (C) 2007 The Android Open Source Project
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
+ * you may not use this file except in compliance with the License.
|
|
+ * You may obtain a copy of the License at
|
|
+ *
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
+ *
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+ * See the License for the specific language governing permissions and
|
|
+ * limitations under the License.
|
|
+ */
|
|
+
|
|
+#ifndef __ADB_H
|
|
+#define __ADB_H
|
|
+
|
|
+#include <limits.h>
|
|
+
|
|
+#include "transport.h" /* readx(), writex() */
|
|
+
|
|
+#define MAX_PAYLOAD 4096
|
|
+
|
|
+#define A_SYNC 0x434e5953
|
|
+#define A_CNXN 0x4e584e43
|
|
+#define A_OPEN 0x4e45504f
|
|
+#define A_OKAY 0x59414b4f
|
|
+#define A_CLSE 0x45534c43
|
|
+#define A_WRTE 0x45545257
|
|
+#define A_AUTH 0x48545541
|
|
+
|
|
+#define A_VERSION 0x01000000 // ADB protocol version
|
|
+
|
|
+#define ADB_VERSION_MAJOR 1 // Used for help/version information
|
|
+#define ADB_VERSION_MINOR 0 // Used for help/version information
|
|
+
|
|
+#define ADB_SERVER_VERSION 31 // Increment this when we want to force users to start a new adb server
|
|
+
|
|
+typedef struct amessage amessage;
|
|
+typedef struct apacket apacket;
|
|
+typedef struct asocket asocket;
|
|
+typedef struct alistener alistener;
|
|
+typedef struct aservice aservice;
|
|
+typedef struct atransport atransport;
|
|
+typedef struct adisconnect adisconnect;
|
|
+typedef struct usb_handle usb_handle;
|
|
+
|
|
+struct amessage {
|
|
+ unsigned command; /* command identifier constant */
|
|
+ unsigned arg0; /* first argument */
|
|
+ unsigned arg1; /* second argument */
|
|
+ unsigned data_length; /* length of payload (0 is allowed) */
|
|
+ unsigned data_check; /* checksum of data payload */
|
|
+ unsigned magic; /* command ^ 0xffffffff */
|
|
+};
|
|
+
|
|
+struct apacket
|
|
+{
|
|
+ apacket *next;
|
|
+
|
|
+ unsigned len;
|
|
+ unsigned char *ptr;
|
|
+
|
|
+ amessage msg;
|
|
+ unsigned char data[MAX_PAYLOAD];
|
|
+};
|
|
+
|
|
+/* An asocket represents one half of a connection between a local and
|
|
+** remote entity. A local asocket is bound to a file descriptor. A
|
|
+** remote asocket is bound to the protocol engine.
|
|
+*/
|
|
+struct asocket {
|
|
+ /* chain pointers for the local/remote list of
|
|
+ ** asockets that this asocket lives in
|
|
+ */
|
|
+ asocket *next;
|
|
+ asocket *prev;
|
|
+
|
|
+ /* the unique identifier for this asocket
|
|
+ */
|
|
+ unsigned id;
|
|
+
|
|
+ /* flag: set when the socket's peer has closed
|
|
+ ** but packets are still queued for delivery
|
|
+ */
|
|
+ int closing;
|
|
+
|
|
+ /* flag: quit adbd when both ends close the
|
|
+ ** local service socket
|
|
+ */
|
|
+ int exit_on_close;
|
|
+
|
|
+ /* the asocket we are connected to
|
|
+ */
|
|
+
|
|
+ asocket *peer;
|
|
+
|
|
+ /* For local asockets, the fde is used to bind
|
|
+ ** us to our fd event system. For remote asockets
|
|
+ ** these fields are not used.
|
|
+ */
|
|
+ fdevent fde;
|
|
+ int fd;
|
|
+
|
|
+ /* queue of apackets waiting to be written
|
|
+ */
|
|
+ apacket *pkt_first;
|
|
+ apacket *pkt_last;
|
|
+
|
|
+ /* enqueue is called by our peer when it has data
|
|
+ ** for us. It should return 0 if we can accept more
|
|
+ ** data or 1 if not. If we return 1, we must call
|
|
+ ** peer->ready() when we once again are ready to
|
|
+ ** receive data.
|
|
+ */
|
|
+ int (*enqueue)(asocket *s, apacket *pkt);
|
|
+
|
|
+ /* ready is called by the peer when it is ready for
|
|
+ ** us to send data via enqueue again
|
|
+ */
|
|
+ void (*ready)(asocket *s);
|
|
+
|
|
+ /* close is called by the peer when it has gone away.
|
|
+ ** we are not allowed to make any further calls on the
|
|
+ ** peer once our close method is called.
|
|
+ */
|
|
+ void (*close)(asocket *s);
|
|
+
|
|
+ /* socket-type-specific extradata */
|
|
+ void *extra;
|
|
+
|
|
+ /* A socket is bound to atransport */
|
|
+ atransport *transport;
|
|
+};
|
|
+
|
|
+
|
|
+/* the adisconnect structure is used to record a callback that
|
|
+** will be called whenever a transport is disconnected (e.g. by the user)
|
|
+** this should be used to cleanup objects that depend on the
|
|
+** transport (e.g. remote sockets, listeners, etc...)
|
|
+*/
|
|
+struct adisconnect
|
|
+{
|
|
+ void (*func)(void* opaque, atransport* t);
|
|
+ void* opaque;
|
|
+ adisconnect* next;
|
|
+ adisconnect* prev;
|
|
+};
|
|
+
|
|
+
|
|
+/* a transport object models the connection to a remote device or emulator
|
|
+** there is one transport per connected device/emulator. a "local transport"
|
|
+** connects through TCP (for the emulator), while a "usb transport" through
|
|
+** USB (for real devices)
|
|
+**
|
|
+** note that kTransportHost doesn't really correspond to a real transport
|
|
+** object, it's a special value used to indicate that a client wants to
|
|
+** connect to a service implemented within the ADB server itself.
|
|
+*/
|
|
+typedef enum transport_type {
|
|
+ kTransportUsb,
|
|
+ kTransportLocal,
|
|
+ kTransportAny,
|
|
+ kTransportHost,
|
|
+} transport_type;
|
|
+
|
|
+#define TOKEN_SIZE 20
|
|
+
|
|
+struct atransport
|
|
+{
|
|
+ atransport *next;
|
|
+ atransport *prev;
|
|
+
|
|
+ int (*read_from_remote)(apacket *p, atransport *t);
|
|
+ int (*write_to_remote)(apacket *p, atransport *t);
|
|
+ void (*close)(atransport *t);
|
|
+ void (*kick)(atransport *t);
|
|
+
|
|
+ int fd;
|
|
+ int transport_socket;
|
|
+ fdevent transport_fde;
|
|
+ int ref_count;
|
|
+ unsigned sync_token;
|
|
+ int connection_state;
|
|
+ int online;
|
|
+ transport_type type;
|
|
+
|
|
+ /* usb handle or socket fd as needed */
|
|
+ usb_handle *usb;
|
|
+ int sfd;
|
|
+
|
|
+ /* used to identify transports for clients */
|
|
+ char *serial;
|
|
+ char *product;
|
|
+ char *model;
|
|
+ char *device;
|
|
+ char *devpath;
|
|
+ int adb_port; // Use for emulators (local transport)
|
|
+
|
|
+ /* a list of adisconnect callbacks called when the transport is kicked */
|
|
+ int kicked;
|
|
+ adisconnect disconnects;
|
|
+
|
|
+ void *key;
|
|
+ unsigned char token[TOKEN_SIZE];
|
|
+ fdevent auth_fde;
|
|
+ unsigned failed_auth_attempts;
|
|
+};
|
|
+
|
|
+
|
|
+/* A listener is an entity which binds to a local port
|
|
+** and, upon receiving a connection on that port, creates
|
|
+** an asocket to connect the new local connection to a
|
|
+** specific remote service.
|
|
+**
|
|
+** TODO: some listeners read from the new connection to
|
|
+** determine what exact service to connect to on the far
|
|
+** side.
|
|
+*/
|
|
+struct alistener
|
|
+{
|
|
+ alistener *next;
|
|
+ alistener *prev;
|
|
+
|
|
+ fdevent fde;
|
|
+ int fd;
|
|
+
|
|
+ const char *local_name;
|
|
+ const char *connect_to;
|
|
+ atransport *transport;
|
|
+ adisconnect disconnect;
|
|
+};
|
|
+
|
|
+
|
|
+void print_packet(const char *label, apacket *p);
|
|
+
|
|
+asocket *find_local_socket(unsigned id);
|
|
+void install_local_socket(asocket *s);
|
|
+void remove_socket(asocket *s);
|
|
+void close_all_sockets(atransport *t);
|
|
+
|
|
+#define LOCAL_CLIENT_PREFIX "emulator-"
|
|
+
|
|
+asocket *create_local_socket(int fd);
|
|
+asocket *create_local_service_socket(const char *destination);
|
|
+
|
|
+asocket *create_remote_socket(unsigned id, atransport *t);
|
|
+void connect_to_remote(asocket *s, const char *destination);
|
|
+void connect_to_smartsocket(asocket *s);
|
|
+
|
|
+void fatal(const char *fmt, ...);
|
|
+void fatal_errno(const char *fmt, ...);
|
|
+
|
|
+void handle_packet(apacket *p, atransport *t);
|
|
+void send_packet(apacket *p, atransport *t);
|
|
+
|
|
+void get_my_path(char *s, size_t maxLen);
|
|
+int launch_server(int server_port);
|
|
+int adb_main(int is_daemon, int server_port);
|
|
+
|
|
+
|
|
+/* transports are ref-counted
|
|
+** get_device_transport does an acquire on your behalf before returning
|
|
+*/
|
|
+void init_transport_registration(void);
|
|
+int list_transports(char *buf, size_t bufsize, int long_listing);
|
|
+void update_transports(void);
|
|
+
|
|
+asocket* create_device_tracker(void);
|
|
+
|
|
+/* Obtain a transport from the available transports.
|
|
+** If state is != CS_ANY, only transports in that state are considered.
|
|
+** If serial is non-NULL then only the device with that serial will be chosen.
|
|
+** If no suitable transport is found, error is set.
|
|
+*/
|
|
+atransport *acquire_one_transport(int state, transport_type ttype, const char* serial, char **error_out);
|
|
+void add_transport_disconnect( atransport* t, adisconnect* dis );
|
|
+void remove_transport_disconnect( atransport* t, adisconnect* dis );
|
|
+void run_transport_disconnects( atransport* t );
|
|
+void kick_transport( atransport* t );
|
|
+
|
|
+/* initialize a transport object's func pointers and state */
|
|
+#if ADB_HOST
|
|
+int get_available_local_transport_index();
|
|
+#endif
|
|
+int init_socket_transport(atransport *t, int s, int port, int local);
|
|
+void init_usb_transport(atransport *t, usb_handle *usb, int state);
|
|
+
|
|
+/* for MacOS X cleanup */
|
|
+void close_usb_devices();
|
|
+
|
|
+/* cause new transports to be init'd and added to the list */
|
|
+void register_socket_transport(int s, const char *serial, int port, int local);
|
|
+
|
|
+/* these should only be used for the "adb disconnect" command */
|
|
+void unregister_transport(atransport *t);
|
|
+void unregister_all_tcp_transports();
|
|
+
|
|
+void register_usb_transport(usb_handle *h, const char *serial, const char *devpath, unsigned writeable);
|
|
+
|
|
+/* this should only be used for transports with connection_state == CS_NOPERM */
|
|
+void unregister_usb_transport(usb_handle *usb);
|
|
+
|
|
+atransport *find_transport(const char *serial);
|
|
+#if ADB_HOST
|
|
+atransport* find_emulator_transport_by_adb_port(int adb_port);
|
|
+#endif
|
|
+
|
|
+int service_to_fd(const char *name);
|
|
+#if ADB_HOST
|
|
+asocket *host_service_to_socket(const char* name, const char *serial);
|
|
+#endif
|
|
+
|
|
+#if !ADB_HOST
|
|
+int init_jdwp(void);
|
|
+asocket* create_jdwp_service_socket();
|
|
+asocket* create_jdwp_tracker_service_socket();
|
|
+int create_jdwp_connection_fd(int jdwp_pid);
|
|
+#endif
|
|
+
|
|
+#if !ADB_HOST
|
|
+typedef enum {
|
|
+ BACKUP,
|
|
+ RESTORE
|
|
+} BackupOperation;
|
|
+int backup_service(BackupOperation operation, char* args);
|
|
+void framebuffer_service(int fd, void *cookie);
|
|
+void log_service(int fd, void *cookie);
|
|
+void remount_service(int fd, void *cookie);
|
|
+char * get_log_file_path(const char * log_name);
|
|
+#endif
|
|
+
|
|
+/* packet allocator */
|
|
+apacket *get_apacket(void);
|
|
+void put_apacket(apacket *p);
|
|
+
|
|
+int check_header(apacket *p);
|
|
+int check_data(apacket *p);
|
|
+
|
|
+/* define ADB_TRACE to 1 to enable tracing support, or 0 to disable it */
|
|
+
|
|
+#define ADB_TRACE 1
|
|
+
|
|
+/* IMPORTANT: if you change the following list, don't
|
|
+ * forget to update the corresponding 'tags' table in
|
|
+ * the adb_trace_init() function implemented in adb.c
|
|
+ */
|
|
+typedef enum {
|
|
+ TRACE_ADB = 0, /* 0x001 */
|
|
+ TRACE_SOCKETS,
|
|
+ TRACE_PACKETS,
|
|
+ TRACE_TRANSPORT,
|
|
+ TRACE_RWX, /* 0x010 */
|
|
+ TRACE_USB,
|
|
+ TRACE_SYNC,
|
|
+ TRACE_SYSDEPS,
|
|
+ TRACE_JDWP, /* 0x100 */
|
|
+ TRACE_SERVICES,
|
|
+ TRACE_AUTH,
|
|
+} AdbTrace;
|
|
+
|
|
+#if ADB_TRACE
|
|
+
|
|
+#if !ADB_HOST
|
|
+/*
|
|
+ * When running inside the emulator, guest's adbd can connect to 'adb-debug'
|
|
+ * qemud service that can display adb trace messages (on condition that emulator
|
|
+ * has been started with '-debug adb' option).
|
|
+ */
|
|
+
|
|
+/* Delivers a trace message to the emulator via QEMU pipe. */
|
|
+void adb_qemu_trace(const char* fmt, ...);
|
|
+/* Macro to use to send ADB trace messages to the emulator. */
|
|
+#define DQ(...) adb_qemu_trace(__VA_ARGS__)
|
|
+#else
|
|
+#define DQ(...) ((void)0)
|
|
+#endif /* !ADB_HOST */
|
|
+
|
|
+ extern int adb_trace_mask;
|
|
+ extern unsigned char adb_trace_output_count;
|
|
+ void adb_trace_init(void);
|
|
+
|
|
+# define ADB_TRACING ((adb_trace_mask & (1 << TRACE_TAG)) != 0)
|
|
+
|
|
+ /* you must define TRACE_TAG before using this macro */
|
|
+# define D(...) \
|
|
+ do { \
|
|
+ if (ADB_TRACING) { \
|
|
+ int save_errno = errno; \
|
|
+ adb_mutex_lock(&D_lock); \
|
|
+ fprintf(stderr, "%s::%s():", \
|
|
+ __FILE__, __FUNCTION__); \
|
|
+ errno = save_errno; \
|
|
+ fprintf(stderr, __VA_ARGS__ ); \
|
|
+ fflush(stderr); \
|
|
+ adb_mutex_unlock(&D_lock); \
|
|
+ errno = save_errno; \
|
|
+ } \
|
|
+ } while (0)
|
|
+# define DR(...) \
|
|
+ do { \
|
|
+ if (ADB_TRACING) { \
|
|
+ int save_errno = errno; \
|
|
+ adb_mutex_lock(&D_lock); \
|
|
+ errno = save_errno; \
|
|
+ fprintf(stderr, __VA_ARGS__ ); \
|
|
+ fflush(stderr); \
|
|
+ adb_mutex_unlock(&D_lock); \
|
|
+ errno = save_errno; \
|
|
+ } \
|
|
+ } while (0)
|
|
+#else
|
|
+# define D(...) ((void)0)
|
|
+# define DR(...) ((void)0)
|
|
+# define ADB_TRACING 0
|
|
+#endif
|
|
+
|
|
+
|
|
+#if !DEBUG_PACKETS
|
|
+#define print_packet(tag,p) do {} while (0)
|
|
+#endif
|
|
+
|
|
+#if ADB_HOST_ON_TARGET
|
|
+/* adb and adbd are coexisting on the target, so use 5038 for adb
|
|
+ * to avoid conflicting with adbd's usage of 5037
|
|
+ */
|
|
+# define DEFAULT_ADB_PORT 5038
|
|
+#else
|
|
+# define DEFAULT_ADB_PORT 5037
|
|
+#endif
|
|
+
|
|
+#define DEFAULT_ADB_LOCAL_TRANSPORT_PORT 5555
|
|
+
|
|
+#define ADB_CLASS 0xff
|
|
+#define ADB_SUBCLASS 0x42
|
|
+#define ADB_PROTOCOL 0x1
|
|
+
|
|
+
|
|
+void local_init(int port);
|
|
+int local_connect(int port);
|
|
+int local_connect_arbitrary_ports(int console_port, int adb_port);
|
|
+
|
|
+/* usb host/client interface */
|
|
+void usb_init();
|
|
+void usb_cleanup();
|
|
+int usb_write(usb_handle *h, const void *data, int len);
|
|
+int usb_read(usb_handle *h, void *data, int len);
|
|
+int usb_close(usb_handle *h);
|
|
+void usb_kick(usb_handle *h);
|
|
+
|
|
+/* used for USB device detection */
|
|
+#if ADB_HOST
|
|
+int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol);
|
|
+#endif
|
|
+
|
|
+unsigned host_to_le32(unsigned n);
|
|
+int adb_commandline(int argc, char **argv);
|
|
+
|
|
+int connection_state(atransport *t);
|
|
+
|
|
+#define CS_ANY -1
|
|
+#define CS_OFFLINE 0
|
|
+#define CS_BOOTLOADER 1
|
|
+#define CS_DEVICE 2
|
|
+#define CS_HOST 3
|
|
+#define CS_RECOVERY 4
|
|
+#define CS_NOPERM 5 /* Insufficient permissions to communicate with the device */
|
|
+#define CS_SIDELOAD 6
|
|
+
|
|
+extern int HOST;
|
|
+extern int SHELL_EXIT_NOTIFY_FD;
|
|
+
|
|
+#define CHUNK_SIZE (64*1024)
|
|
+
|
|
+#if !ADB_HOST
|
|
+#define USB_ADB_PATH "/dev/android_adb"
|
|
+#define ADB_TCP_MODE "/data/network_adb"
|
|
+#define USB_FFS_ADB_PATH "/dev/usb-ffs/adb/"
|
|
+#define USB_FFS_ADB_EP(x) USB_FFS_ADB_PATH#x
|
|
+
|
|
+#define USB_FFS_ADB_EP0 USB_FFS_ADB_EP(ep0)
|
|
+#define USB_FFS_ADB_OUT USB_FFS_ADB_EP(ep1)
|
|
+#define USB_FFS_ADB_IN USB_FFS_ADB_EP(ep2)
|
|
+#endif
|
|
+
|
|
+int sendfailmsg(int fd, const char *reason);
|
|
+int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s);
|
|
+
|
|
+#endif
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/adb_auth.h
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/adb_auth.h 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,54 @@
|
|
+/*
|
|
+ * Copyright (C) 2012 The Android Open Source Project
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
+ * you may not use this file except in compliance with the License.
|
|
+ * You may obtain a copy of the License at
|
|
+ *
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
+ *
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+ * See the License for the specific language governing permissions and
|
|
+ * limitations under the License.
|
|
+ */
|
|
+
|
|
+#ifndef __ADB_AUTH_H
|
|
+#define __ADB_AUTH_H
|
|
+
|
|
+void adb_auth_init(void);
|
|
+void adb_auth_verified(atransport *t);
|
|
+
|
|
+/* AUTH packets first argument */
|
|
+/* Request */
|
|
+#define ADB_AUTH_TOKEN 1
|
|
+/* Response */
|
|
+#define ADB_AUTH_SIGNATURE 2
|
|
+#define ADB_AUTH_RSAPUBLICKEY 3
|
|
+
|
|
+#if ADB_HOST
|
|
+
|
|
+int adb_auth_sign(void *key, void *token, size_t token_size, void *sig);
|
|
+void *adb_auth_nextkey(void *current);
|
|
+int adb_auth_get_userkey(unsigned char *data, size_t len);
|
|
+
|
|
+static inline int adb_auth_generate_token(void *token, size_t token_size) { return 0; }
|
|
+static inline int adb_auth_verify(void *token, void *sig, int siglen) { return 0; }
|
|
+static inline void adb_auth_confirm_key(unsigned char *data, size_t len, atransport *t) { }
|
|
+static inline void adb_auth_reload_keys(void) { }
|
|
+
|
|
+#else // !ADB_HOST
|
|
+
|
|
+static inline int adb_auth_sign(void* key, void *token, size_t token_size, void *sig) { return 0; }
|
|
+static inline void *adb_auth_nextkey(void *current) { return NULL; }
|
|
+static inline int adb_auth_get_userkey(unsigned char *data, size_t len) { return 0; }
|
|
+
|
|
+int adb_auth_generate_token(void *token, size_t token_size);
|
|
+int adb_auth_verify(void *token, void *sig, int siglen);
|
|
+void adb_auth_confirm_key(unsigned char *data, size_t len, atransport *t);
|
|
+void adb_auth_reload_keys(void);
|
|
+
|
|
+#endif // ADB_HOST
|
|
+
|
|
+#endif // __ADB_AUTH_H
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/adb_auth_client.c
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/adb_auth_client.c 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,245 @@
|
|
+/*
|
|
+ * Copyright (C) 2012 The Android Open Source Project
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
+ * you may not use this file except in compliance with the License.
|
|
+ * You may obtain a copy of the License at
|
|
+ *
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
+ *
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+ * See the License for the specific language governing permissions and
|
|
+ * limitations under the License.
|
|
+ */
|
|
+
|
|
+#include <stdio.h>
|
|
+#include <string.h>
|
|
+#include <resolv.h>
|
|
+#include <cutils/list.h>
|
|
+#include <cutils/sockets.h>
|
|
+
|
|
+#include "sysdeps.h"
|
|
+#include "adb.h"
|
|
+#include "adb_auth.h"
|
|
+#include "fdevent.h"
|
|
+#include "mincrypt/rsa.h"
|
|
+
|
|
+#define TRACE_TAG TRACE_AUTH
|
|
+
|
|
+
|
|
+struct adb_public_key {
|
|
+ struct listnode node;
|
|
+ RSAPublicKey key;
|
|
+};
|
|
+
|
|
+static struct listnode key_list;
|
|
+
|
|
+static char *key_paths[] = {
|
|
+ "/adb_keys",
|
|
+ "/data/misc/adb/adb_keys",
|
|
+ NULL
|
|
+};
|
|
+
|
|
+static fdevent listener_fde;
|
|
+static int framework_fd = -1;
|
|
+
|
|
+
|
|
+static void read_keys(const char *file, struct listnode *list)
|
|
+{
|
|
+ struct adb_public_key *key;
|
|
+ FILE *f;
|
|
+ char buf[MAX_PAYLOAD];
|
|
+ char *sep;
|
|
+ int ret;
|
|
+
|
|
+ f = fopen(file, "r");
|
|
+ if (!f) {
|
|
+ D("Can't open '%s'\n", file);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ while (fgets(buf, sizeof(buf), f)) {
|
|
+ /* Allocate 4 extra bytes to decode the base64 data in-place */
|
|
+ key = calloc(1, sizeof(*key) + 4);
|
|
+ if (!key) {
|
|
+ D("Can't malloc key\n");
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ sep = strpbrk(buf, " \t");
|
|
+ if (sep)
|
|
+ *sep = '\0';
|
|
+
|
|
+ ret = __b64_pton(buf, (u_char *)&key->key, sizeof(key->key) + 4);
|
|
+ if (ret != sizeof(key->key)) {
|
|
+ D("%s: Invalid base64 data ret=%d\n", file, ret);
|
|
+ free(key);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (key->key.len != RSANUMWORDS) {
|
|
+ D("%s: Invalid key len %d\n", file, key->key.len);
|
|
+ free(key);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ list_add_tail(list, &key->node);
|
|
+ }
|
|
+
|
|
+ fclose(f);
|
|
+}
|
|
+
|
|
+static void free_keys(struct listnode *list)
|
|
+{
|
|
+ struct listnode *item;
|
|
+
|
|
+ while (!list_empty(list)) {
|
|
+ item = list_head(list);
|
|
+ list_remove(item);
|
|
+ free(node_to_item(item, struct adb_public_key, node));
|
|
+ }
|
|
+}
|
|
+
|
|
+void adb_auth_reload_keys(void)
|
|
+{
|
|
+ char *path;
|
|
+ char **paths = key_paths;
|
|
+ struct stat buf;
|
|
+
|
|
+ free_keys(&key_list);
|
|
+
|
|
+ while ((path = *paths++)) {
|
|
+ if (!stat(path, &buf)) {
|
|
+ D("Loading keys from '%s'\n", path);
|
|
+ read_keys(path, &key_list);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+int adb_auth_generate_token(void *token, size_t token_size)
|
|
+{
|
|
+ FILE *f;
|
|
+ int ret;
|
|
+
|
|
+ f = fopen("/dev/urandom", "r");
|
|
+ if (!f)
|
|
+ return 0;
|
|
+
|
|
+ ret = fread(token, token_size, 1, f);
|
|
+
|
|
+ fclose(f);
|
|
+ return ret * token_size;
|
|
+}
|
|
+
|
|
+int adb_auth_verify(void *token, void *sig, int siglen)
|
|
+{
|
|
+ struct listnode *item;
|
|
+ struct adb_public_key *key;
|
|
+ int ret;
|
|
+
|
|
+ if (siglen != RSANUMBYTES)
|
|
+ return 0;
|
|
+
|
|
+ list_for_each(item, &key_list) {
|
|
+ key = node_to_item(item, struct adb_public_key, node);
|
|
+ ret = RSA_verify(&key->key, sig, siglen, token);
|
|
+ if (ret)
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void adb_auth_event(int fd, unsigned events, void *data)
|
|
+{
|
|
+ atransport *t = data;
|
|
+ char response[2];
|
|
+ int ret;
|
|
+
|
|
+ if (events & FDE_READ) {
|
|
+ ret = unix_read(fd, response, sizeof(response));
|
|
+ if (ret < 0) {
|
|
+ D("Disconnect");
|
|
+ fdevent_remove(&t->auth_fde);
|
|
+ framework_fd = -1;
|
|
+ }
|
|
+ else if (ret == 2 && response[0] == 'O' && response[1] == 'K') {
|
|
+ adb_auth_reload_keys();
|
|
+ adb_auth_verified(t);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+void adb_auth_confirm_key(unsigned char *key, size_t len, atransport *t)
|
|
+{
|
|
+ char msg[MAX_PAYLOAD];
|
|
+ int ret;
|
|
+
|
|
+ if (framework_fd < 0) {
|
|
+ D("Client not connected\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (key[len - 1] != '\0') {
|
|
+ D("Key must be a null-terminated string\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ ret = snprintf(msg, sizeof(msg), "PK%s", key);
|
|
+ if (ret >= (signed)sizeof(msg)) {
|
|
+ D("Key too long. ret=%d", ret);
|
|
+ return;
|
|
+ }
|
|
+ D("Sending '%s'\n", msg);
|
|
+
|
|
+ ret = unix_write(framework_fd, msg, ret);
|
|
+ if (ret < 0) {
|
|
+ D("Failed to write PK, errno=%d\n", errno);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ fdevent_install(&t->auth_fde, framework_fd, adb_auth_event, t);
|
|
+ fdevent_add(&t->auth_fde, FDE_READ);
|
|
+}
|
|
+
|
|
+static void adb_auth_listener(int fd, unsigned events, void *data)
|
|
+{
|
|
+ struct sockaddr addr;
|
|
+ socklen_t alen;
|
|
+ int s;
|
|
+
|
|
+ alen = sizeof(addr);
|
|
+
|
|
+ s = adb_socket_accept(fd, &addr, &alen);
|
|
+ if (s < 0) {
|
|
+ D("Failed to accept: errno=%d\n", errno);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ framework_fd = s;
|
|
+}
|
|
+
|
|
+void adb_auth_init(void)
|
|
+{
|
|
+ int fd, ret;
|
|
+
|
|
+ list_init(&key_list);
|
|
+ adb_auth_reload_keys();
|
|
+
|
|
+ fd = android_get_control_socket("adbd");
|
|
+ if (fd < 0) {
|
|
+ D("Failed to get adbd socket\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ ret = listen(fd, 4);
|
|
+ if (ret < 0) {
|
|
+ D("Failed to listen on '%d'\n", fd);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ fdevent_install(&listener_fde, fd, adb_auth_listener, NULL);
|
|
+ fdevent_add(&listener_fde, FDE_READ);
|
|
+}
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/adb_auth_host.c
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/adb_auth_host.c 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,426 @@
|
|
+/*
|
|
+ * Copyright (C) 2012 The Android Open Source Project
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
+ * you may not use this file except in compliance with the License.
|
|
+ * You may obtain a copy of the License at
|
|
+ *
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
+ *
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+ * See the License for the specific language governing permissions and
|
|
+ * limitations under the License.
|
|
+ */
|
|
+
|
|
+#include <stdio.h>
|
|
+
|
|
+#ifdef _WIN32
|
|
+# define WIN32_LEAN_AND_MEAN
|
|
+# include "windows.h"
|
|
+# include "shlobj.h"
|
|
+#else
|
|
+# include <sys/types.h>
|
|
+# include <sys/stat.h>
|
|
+# include <unistd.h>
|
|
+#endif
|
|
+#include <string.h>
|
|
+
|
|
+#include "sysdeps.h"
|
|
+#include "adb.h"
|
|
+#include "adb_auth.h"
|
|
+
|
|
+/* HACK: we need the RSAPublicKey struct
|
|
+ * but RSA_verify conflits with openssl */
|
|
+#define RSA_verify RSA_verify_mincrypt
|
|
+#include "mincrypt/rsa.h"
|
|
+#undef RSA_verify
|
|
+
|
|
+#include <cutils/list.h>
|
|
+
|
|
+#include <openssl/evp.h>
|
|
+#include <openssl/objects.h>
|
|
+#include <openssl/pem.h>
|
|
+#include <openssl/rsa.h>
|
|
+#include <openssl/sha.h>
|
|
+
|
|
+#define TRACE_TAG TRACE_AUTH
|
|
+
|
|
+#define ANDROID_PATH ".android"
|
|
+#define ADB_KEY_FILE "adbkey"
|
|
+
|
|
+
|
|
+struct adb_private_key {
|
|
+ struct listnode node;
|
|
+ RSA *rsa;
|
|
+};
|
|
+
|
|
+static struct listnode key_list;
|
|
+
|
|
+
|
|
+/* Convert OpenSSL RSA private key to android pre-computed RSAPublicKey format */
|
|
+static int RSA_to_RSAPublicKey(RSA *rsa, RSAPublicKey *pkey)
|
|
+{
|
|
+ int ret = 1;
|
|
+ unsigned int i;
|
|
+
|
|
+ BN_CTX* ctx = BN_CTX_new();
|
|
+ BIGNUM* r32 = BN_new();
|
|
+ BIGNUM* rr = BN_new();
|
|
+ BIGNUM* r = BN_new();
|
|
+ BIGNUM* rem = BN_new();
|
|
+ BIGNUM* n = BN_new();
|
|
+ BIGNUM* n0inv = BN_new();
|
|
+
|
|
+ if (RSA_size(rsa) != RSANUMBYTES) {
|
|
+ ret = 0;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ BN_set_bit(r32, 32);
|
|
+ BN_copy(n, rsa->n);
|
|
+ BN_set_bit(r, RSANUMWORDS * 32);
|
|
+ BN_mod_sqr(rr, r, n, ctx);
|
|
+ BN_div(NULL, rem, n, r32, ctx);
|
|
+ BN_mod_inverse(n0inv, rem, r32, ctx);
|
|
+
|
|
+ pkey->len = RSANUMWORDS;
|
|
+ pkey->n0inv = 0 - BN_get_word(n0inv);
|
|
+ for (i = 0; i < RSANUMWORDS; i++) {
|
|
+ BN_div(rr, rem, rr, r32, ctx);
|
|
+ pkey->rr[i] = BN_get_word(rem);
|
|
+ BN_div(n, rem, n, r32, ctx);
|
|
+ pkey->n[i] = BN_get_word(rem);
|
|
+ }
|
|
+ pkey->exponent = BN_get_word(rsa->e);
|
|
+
|
|
+out:
|
|
+ BN_free(n0inv);
|
|
+ BN_free(n);
|
|
+ BN_free(rem);
|
|
+ BN_free(r);
|
|
+ BN_free(rr);
|
|
+ BN_free(r32);
|
|
+ BN_CTX_free(ctx);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static void get_user_info(char *buf, size_t len)
|
|
+{
|
|
+ char hostname[1024], username[1024];
|
|
+ int ret;
|
|
+
|
|
+#ifndef _WIN32
|
|
+ ret = gethostname(hostname, sizeof(hostname));
|
|
+ if (ret < 0)
|
|
+#endif
|
|
+ strcpy(hostname, "unknown");
|
|
+
|
|
+#if !defined _WIN32 && !defined ADB_HOST_ON_TARGET
|
|
+ ret = getlogin_r(username, sizeof(username));
|
|
+ if (ret < 0)
|
|
+#endif
|
|
+ strcpy(username, "unknown");
|
|
+
|
|
+ ret = snprintf(buf, len, " %s@%s", username, hostname);
|
|
+ if (ret >= (signed)len)
|
|
+ buf[len - 1] = '\0';
|
|
+}
|
|
+
|
|
+static int write_public_keyfile(RSA *private_key, const char *private_key_path)
|
|
+{
|
|
+ RSAPublicKey pkey;
|
|
+ BIO *bio, *b64, *bfile;
|
|
+ char path[PATH_MAX], info[MAX_PAYLOAD];
|
|
+ int ret;
|
|
+
|
|
+ ret = snprintf(path, sizeof(path), "%s.pub", private_key_path);
|
|
+ if (ret >= (signed)sizeof(path))
|
|
+ return 0;
|
|
+
|
|
+ ret = RSA_to_RSAPublicKey(private_key, &pkey);
|
|
+ if (!ret) {
|
|
+ D("Failed to convert to publickey\n");
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ bfile = BIO_new_file(path, "w");
|
|
+ if (!bfile) {
|
|
+ D("Failed to open '%s'\n", path);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ D("Writing public key to '%s'\n", path);
|
|
+
|
|
+ b64 = BIO_new(BIO_f_base64());
|
|
+ BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
|
|
+
|
|
+ bio = BIO_push(b64, bfile);
|
|
+ BIO_write(bio, &pkey, sizeof(pkey));
|
|
+ BIO_flush(bio);
|
|
+ BIO_pop(b64);
|
|
+ BIO_free(b64);
|
|
+
|
|
+ get_user_info(info, sizeof(info));
|
|
+ BIO_write(bfile, info, strlen(info));
|
|
+ BIO_flush(bfile);
|
|
+ BIO_free_all(bfile);
|
|
+
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+static int generate_key(const char *file)
|
|
+{
|
|
+ EVP_PKEY* pkey = EVP_PKEY_new();
|
|
+ BIGNUM* exponent = BN_new();
|
|
+ RSA* rsa = RSA_new();
|
|
+ mode_t old_mask;
|
|
+ FILE *f = NULL;
|
|
+ int ret = 0;
|
|
+
|
|
+ D("generate_key '%s'\n", file);
|
|
+
|
|
+ if (!pkey || !exponent || !rsa) {
|
|
+ D("Failed to allocate key\n");
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ BN_set_word(exponent, RSA_F4);
|
|
+ RSA_generate_key_ex(rsa, 2048, exponent, NULL);
|
|
+ EVP_PKEY_set1_RSA(pkey, rsa);
|
|
+
|
|
+ old_mask = umask(077);
|
|
+
|
|
+ f = fopen(file, "w");
|
|
+ if (!f) {
|
|
+ D("Failed to open '%s'\n", file);
|
|
+ umask(old_mask);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ umask(old_mask);
|
|
+
|
|
+ if (!PEM_write_PrivateKey(f, pkey, NULL, NULL, 0, NULL, NULL)) {
|
|
+ D("Failed to write key\n");
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ if (!write_public_keyfile(rsa, file)) {
|
|
+ D("Failed to write public key\n");
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ ret = 1;
|
|
+
|
|
+out:
|
|
+ if (f)
|
|
+ fclose(f);
|
|
+ EVP_PKEY_free(pkey);
|
|
+ RSA_free(rsa);
|
|
+ BN_free(exponent);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int read_key(const char *file, struct listnode *list)
|
|
+{
|
|
+ struct adb_private_key *key;
|
|
+ FILE *f;
|
|
+
|
|
+ D("read_key '%s'\n", file);
|
|
+
|
|
+ f = fopen(file, "r");
|
|
+ if (!f) {
|
|
+ D("Failed to open '%s'\n", file);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ key = malloc(sizeof(*key));
|
|
+ if (!key) {
|
|
+ D("Failed to alloc key\n");
|
|
+ fclose(f);
|
|
+ return 0;
|
|
+ }
|
|
+ key->rsa = RSA_new();
|
|
+
|
|
+ if (!PEM_read_RSAPrivateKey(f, &key->rsa, NULL, NULL)) {
|
|
+ D("Failed to read key\n");
|
|
+ fclose(f);
|
|
+ RSA_free(key->rsa);
|
|
+ free(key);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ fclose(f);
|
|
+ list_add_tail(list, &key->node);
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+static int get_user_keyfilepath(char *filename, size_t len)
|
|
+{
|
|
+ const char *format, *home;
|
|
+ char android_dir[PATH_MAX];
|
|
+ struct stat buf;
|
|
+#ifdef _WIN32
|
|
+ char path[PATH_MAX];
|
|
+ home = getenv("ANDROID_SDK_HOME");
|
|
+ if (!home) {
|
|
+ SHGetFolderPath(NULL, CSIDL_PROFILE, NULL, 0, path);
|
|
+ home = path;
|
|
+ }
|
|
+ format = "%s\\%s";
|
|
+#else
|
|
+ home = getenv("HOME");
|
|
+ if (!home)
|
|
+ return -1;
|
|
+ format = "%s/%s";
|
|
+#endif
|
|
+
|
|
+ D("home '%s'\n", home);
|
|
+
|
|
+ if (snprintf(android_dir, sizeof(android_dir), format, home,
|
|
+ ANDROID_PATH) >= (int)sizeof(android_dir))
|
|
+ return -1;
|
|
+
|
|
+ if (stat(android_dir, &buf)) {
|
|
+ if (adb_mkdir(android_dir, 0750) < 0) {
|
|
+ D("Cannot mkdir '%s'", android_dir);
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return snprintf(filename, len, format, android_dir, ADB_KEY_FILE);
|
|
+}
|
|
+
|
|
+static int get_user_key(struct listnode *list)
|
|
+{
|
|
+ struct stat buf;
|
|
+ char path[PATH_MAX];
|
|
+ int ret;
|
|
+
|
|
+ ret = get_user_keyfilepath(path, sizeof(path));
|
|
+ if (ret < 0 || ret >= (signed)sizeof(path)) {
|
|
+ D("Error getting user key filename");
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ D("user key '%s'\n", path);
|
|
+
|
|
+ if (stat(path, &buf) == -1) {
|
|
+ if (!generate_key(path)) {
|
|
+ D("Failed to generate new key\n");
|
|
+ return 0;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return read_key(path, list);
|
|
+}
|
|
+
|
|
+static void get_vendor_keys(struct listnode *list)
|
|
+{
|
|
+ const char *adb_keys_path;
|
|
+ char keys_path[MAX_PAYLOAD];
|
|
+ char *path;
|
|
+ char *save;
|
|
+ struct stat buf;
|
|
+
|
|
+ adb_keys_path = getenv("ADB_VENDOR_KEYS");
|
|
+ if (!adb_keys_path)
|
|
+ return;
|
|
+ strncpy(keys_path, adb_keys_path, sizeof(keys_path));
|
|
+
|
|
+ path = adb_strtok_r(keys_path, ENV_PATH_SEPARATOR_STR, &save);
|
|
+ while (path) {
|
|
+ D("Reading: '%s'\n", path);
|
|
+
|
|
+ if (stat(path, &buf))
|
|
+ D("Can't read '%s'\n", path);
|
|
+ else if (!read_key(path, list))
|
|
+ D("Failed to read '%s'\n", path);
|
|
+
|
|
+ path = adb_strtok_r(NULL, ENV_PATH_SEPARATOR_STR, &save);
|
|
+ }
|
|
+}
|
|
+
|
|
+int adb_auth_sign(void *node, void *token, size_t token_size, void *sig)
|
|
+{
|
|
+ unsigned int len;
|
|
+ struct adb_private_key *key = node_to_item(node, struct adb_private_key, node);
|
|
+
|
|
+ if (!RSA_sign(NID_sha1, token, token_size, sig, &len, key->rsa)) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ D("adb_auth_sign len=%d\n", len);
|
|
+ return (int)len;
|
|
+}
|
|
+
|
|
+void *adb_auth_nextkey(void *current)
|
|
+{
|
|
+ struct listnode *item;
|
|
+
|
|
+ if (list_empty(&key_list))
|
|
+ return NULL;
|
|
+
|
|
+ if (!current)
|
|
+ return list_head(&key_list);
|
|
+
|
|
+ list_for_each(item, &key_list) {
|
|
+ if (item == current) {
|
|
+ /* current is the last item, we tried all the keys */
|
|
+ if (item->next == &key_list)
|
|
+ return NULL;
|
|
+ return item->next;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+int adb_auth_get_userkey(unsigned char *data, size_t len)
|
|
+{
|
|
+ char path[PATH_MAX];
|
|
+ char *file;
|
|
+ int ret;
|
|
+
|
|
+ ret = get_user_keyfilepath(path, sizeof(path) - 4);
|
|
+ if (ret < 0 || ret >= (signed)(sizeof(path) - 4)) {
|
|
+ D("Error getting user key filename");
|
|
+ return 0;
|
|
+ }
|
|
+ strcat(path, ".pub");
|
|
+
|
|
+ file = load_file(path, (unsigned*)&ret);
|
|
+ if (!file) {
|
|
+ D("Can't load '%s'\n", path);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (len < (size_t)(ret + 1)) {
|
|
+ D("%s: Content too large ret=%d\n", path, ret);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ memcpy(data, file, ret);
|
|
+ data[ret] = '\0';
|
|
+
|
|
+ return ret + 1;
|
|
+}
|
|
+
|
|
+void adb_auth_init(void)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ D("adb_auth_init\n");
|
|
+
|
|
+ list_init(&key_list);
|
|
+
|
|
+ ret = get_user_key(&key_list);
|
|
+ if (!ret) {
|
|
+ D("Failed to get user key\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ get_vendor_keys(&key_list);
|
|
+}
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/adb_client.c
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/adb_client.c 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,340 @@
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+#include <string.h>
|
|
+#include <errno.h>
|
|
+#include <limits.h>
|
|
+#include <stdarg.h>
|
|
+#include <zipfile/zipfile.h>
|
|
+#include <sys/types.h>
|
|
+#include <sys/stat.h>
|
|
+
|
|
+#include "sysdeps.h"
|
|
+
|
|
+#define TRACE_TAG TRACE_ADB
|
|
+#include "adb_client.h"
|
|
+
|
|
+static transport_type __adb_transport = kTransportAny;
|
|
+static const char* __adb_serial = NULL;
|
|
+
|
|
+static int __adb_server_port = DEFAULT_ADB_PORT;
|
|
+static const char* __adb_server_name = NULL;
|
|
+
|
|
+void adb_set_transport(transport_type type, const char* serial)
|
|
+{
|
|
+ __adb_transport = type;
|
|
+ __adb_serial = serial;
|
|
+}
|
|
+
|
|
+void adb_set_tcp_specifics(int server_port)
|
|
+{
|
|
+ __adb_server_port = server_port;
|
|
+}
|
|
+
|
|
+void adb_set_tcp_name(const char* hostname)
|
|
+{
|
|
+ __adb_server_name = hostname;
|
|
+}
|
|
+
|
|
+int adb_get_emulator_console_port(void)
|
|
+{
|
|
+ const char* serial = __adb_serial;
|
|
+ int port;
|
|
+
|
|
+ if (serial == NULL) {
|
|
+ /* if no specific device was specified, we need to look at */
|
|
+ /* the list of connected devices, and extract an emulator */
|
|
+ /* name from it. two emulators is an error */
|
|
+ char* tmp = adb_query("host:devices");
|
|
+ char* p = tmp;
|
|
+ if(!tmp) {
|
|
+ printf("no emulator connected\n");
|
|
+ return -1;
|
|
+ }
|
|
+ while (*p) {
|
|
+ char* q = strchr(p, '\n');
|
|
+ if (q != NULL)
|
|
+ *q++ = 0;
|
|
+ else
|
|
+ q = p + strlen(p);
|
|
+
|
|
+ if (!memcmp(p, LOCAL_CLIENT_PREFIX, sizeof(LOCAL_CLIENT_PREFIX)-1)) {
|
|
+ if (serial != NULL) { /* more than one emulator listed */
|
|
+ free(tmp);
|
|
+ return -2;
|
|
+ }
|
|
+ serial = p;
|
|
+ }
|
|
+
|
|
+ p = q;
|
|
+ }
|
|
+ free(tmp);
|
|
+
|
|
+ if (serial == NULL)
|
|
+ return -1; /* no emulator found */
|
|
+ }
|
|
+ else {
|
|
+ if (memcmp(serial, LOCAL_CLIENT_PREFIX, sizeof(LOCAL_CLIENT_PREFIX)-1) != 0)
|
|
+ return -1; /* not an emulator */
|
|
+ }
|
|
+
|
|
+ serial += sizeof(LOCAL_CLIENT_PREFIX)-1;
|
|
+ port = strtol(serial, NULL, 10);
|
|
+ return port;
|
|
+}
|
|
+
|
|
+static char __adb_error[256] = { 0 };
|
|
+
|
|
+const char *adb_error(void)
|
|
+{
|
|
+ return __adb_error;
|
|
+}
|
|
+
|
|
+static int switch_socket_transport(int fd)
|
|
+{
|
|
+ char service[64];
|
|
+ char tmp[5];
|
|
+ int len;
|
|
+
|
|
+ if (__adb_serial)
|
|
+ snprintf(service, sizeof service, "host:transport:%s", __adb_serial);
|
|
+ else {
|
|
+ char* transport_type = "???";
|
|
+
|
|
+ switch (__adb_transport) {
|
|
+ case kTransportUsb:
|
|
+ transport_type = "transport-usb";
|
|
+ break;
|
|
+ case kTransportLocal:
|
|
+ transport_type = "transport-local";
|
|
+ break;
|
|
+ case kTransportAny:
|
|
+ transport_type = "transport-any";
|
|
+ break;
|
|
+ case kTransportHost:
|
|
+ // no switch necessary
|
|
+ return 0;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ snprintf(service, sizeof service, "host:%s", transport_type);
|
|
+ }
|
|
+ len = strlen(service);
|
|
+ snprintf(tmp, sizeof tmp, "%04x", len);
|
|
+
|
|
+ if(writex(fd, tmp, 4) || writex(fd, service, len)) {
|
|
+ strcpy(__adb_error, "write failure during connection");
|
|
+ adb_close(fd);
|
|
+ return -1;
|
|
+ }
|
|
+ D("Switch transport in progress\n");
|
|
+
|
|
+ if(adb_status(fd)) {
|
|
+ adb_close(fd);
|
|
+ D("Switch transport failed\n");
|
|
+ return -1;
|
|
+ }
|
|
+ D("Switch transport success\n");
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int adb_status(int fd)
|
|
+{
|
|
+ unsigned char buf[5];
|
|
+ unsigned len;
|
|
+
|
|
+ if(readx(fd, buf, 4)) {
|
|
+ strcpy(__adb_error, "protocol fault (no status)");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if(!memcmp(buf, "OKAY", 4)) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if(memcmp(buf, "FAIL", 4)) {
|
|
+ sprintf(__adb_error,
|
|
+ "protocol fault (status %02x %02x %02x %02x?!)",
|
|
+ buf[0], buf[1], buf[2], buf[3]);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if(readx(fd, buf, 4)) {
|
|
+ strcpy(__adb_error, "protocol fault (status len)");
|
|
+ return -1;
|
|
+ }
|
|
+ buf[4] = 0;
|
|
+ len = strtoul((char*)buf, 0, 16);
|
|
+ if(len > 255) len = 255;
|
|
+ if(readx(fd, __adb_error, len)) {
|
|
+ strcpy(__adb_error, "protocol fault (status read)");
|
|
+ return -1;
|
|
+ }
|
|
+ __adb_error[len] = 0;
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+int _adb_connect(const char *service)
|
|
+{
|
|
+ char tmp[5];
|
|
+ int len;
|
|
+ int fd;
|
|
+
|
|
+ D("_adb_connect: %s\n", service);
|
|
+ len = strlen(service);
|
|
+ if((len < 1) || (len > 1024)) {
|
|
+ strcpy(__adb_error, "service name too long");
|
|
+ return -1;
|
|
+ }
|
|
+ snprintf(tmp, sizeof tmp, "%04x", len);
|
|
+
|
|
+ if (__adb_server_name)
|
|
+ fd = socket_network_client(__adb_server_name, __adb_server_port, SOCK_STREAM);
|
|
+ else
|
|
+ fd = socket_loopback_client(__adb_server_port, SOCK_STREAM);
|
|
+
|
|
+ if(fd < 0) {
|
|
+ strcpy(__adb_error, "cannot connect to daemon");
|
|
+ return -2;
|
|
+ }
|
|
+
|
|
+ if (memcmp(service,"host",4) != 0 && switch_socket_transport(fd)) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if(writex(fd, tmp, 4) || writex(fd, service, len)) {
|
|
+ strcpy(__adb_error, "write failure during connection");
|
|
+ adb_close(fd);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if(adb_status(fd)) {
|
|
+ adb_close(fd);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ D("_adb_connect: return fd %d\n", fd);
|
|
+ return fd;
|
|
+}
|
|
+
|
|
+int adb_connect(const char *service)
|
|
+{
|
|
+ // first query the adb server's version
|
|
+ int fd = _adb_connect("host:version");
|
|
+
|
|
+ D("adb_connect: service %s\n", service);
|
|
+ if(fd == -2 && __adb_server_name) {
|
|
+ fprintf(stderr,"** Cannot start server on remote host\n");
|
|
+ return fd;
|
|
+ } else if(fd == -2) {
|
|
+ fprintf(stdout,"* daemon not running. starting it now on port %d *\n",
|
|
+ __adb_server_port);
|
|
+ start_server:
|
|
+ if(launch_server(__adb_server_port)) {
|
|
+ fprintf(stderr,"* failed to start daemon *\n");
|
|
+ return -1;
|
|
+ } else {
|
|
+ fprintf(stdout,"* daemon started successfully *\n");
|
|
+ }
|
|
+ /* give the server some time to start properly and detect devices */
|
|
+ adb_sleep_ms(3000);
|
|
+ // fall through to _adb_connect
|
|
+ } else {
|
|
+ // if server was running, check its version to make sure it is not out of date
|
|
+ char buf[100];
|
|
+ int n;
|
|
+ int version = ADB_SERVER_VERSION - 1;
|
|
+
|
|
+ // if we have a file descriptor, then parse version result
|
|
+ if(fd >= 0) {
|
|
+ if(readx(fd, buf, 4)) goto error;
|
|
+
|
|
+ buf[4] = 0;
|
|
+ n = strtoul(buf, 0, 16);
|
|
+ if(n > (int)sizeof(buf)) goto error;
|
|
+ if(readx(fd, buf, n)) goto error;
|
|
+ adb_close(fd);
|
|
+
|
|
+ if (sscanf(buf, "%04x", &version) != 1) goto error;
|
|
+ } else {
|
|
+ // if fd is -1, then check for "unknown host service",
|
|
+ // which would indicate a version of adb that does not support the version command
|
|
+ if (strcmp(__adb_error, "unknown host service") != 0)
|
|
+ return fd;
|
|
+ }
|
|
+
|
|
+ if(version != ADB_SERVER_VERSION) {
|
|
+ printf("adb server is out of date. killing...\n");
|
|
+ fd = _adb_connect("host:kill");
|
|
+ adb_close(fd);
|
|
+
|
|
+ /* XXX can we better detect its death? */
|
|
+ adb_sleep_ms(2000);
|
|
+ goto start_server;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // if the command is start-server, we are done.
|
|
+ if (!strcmp(service, "host:start-server"))
|
|
+ return 0;
|
|
+
|
|
+ fd = _adb_connect(service);
|
|
+ if(fd == -2) {
|
|
+ fprintf(stderr,"** daemon still not running\n");
|
|
+ }
|
|
+ D("adb_connect: return fd %d\n", fd);
|
|
+
|
|
+ return fd;
|
|
+error:
|
|
+ adb_close(fd);
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+
|
|
+int adb_command(const char *service)
|
|
+{
|
|
+ int fd = adb_connect(service);
|
|
+ if(fd < 0) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if(adb_status(fd)) {
|
|
+ adb_close(fd);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+char *adb_query(const char *service)
|
|
+{
|
|
+ char buf[5];
|
|
+ unsigned n;
|
|
+ char *tmp;
|
|
+
|
|
+ D("adb_query: %s\n", service);
|
|
+ int fd = adb_connect(service);
|
|
+ if(fd < 0) {
|
|
+ fprintf(stderr,"error: %s\n", __adb_error);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if(readx(fd, buf, 4)) goto oops;
|
|
+
|
|
+ buf[4] = 0;
|
|
+ n = strtoul(buf, 0, 16);
|
|
+ if(n > 1024) goto oops;
|
|
+
|
|
+ tmp = malloc(n + 1);
|
|
+ if(tmp == 0) goto oops;
|
|
+
|
|
+ if(readx(fd, tmp, n) == 0) {
|
|
+ tmp[n] = 0;
|
|
+ adb_close(fd);
|
|
+ return tmp;
|
|
+ }
|
|
+ free(tmp);
|
|
+
|
|
+oops:
|
|
+ adb_close(fd);
|
|
+ return 0;
|
|
+}
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/adb_client.h
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/adb_client.h 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,57 @@
|
|
+#ifndef _ADB_CLIENT_H_
|
|
+#define _ADB_CLIENT_H_
|
|
+
|
|
+#include "adb.h"
|
|
+
|
|
+/* connect to adb, connect to the named service, and return
|
|
+** a valid fd for interacting with that service upon success
|
|
+** or a negative number on failure
|
|
+*/
|
|
+int adb_connect(const char *service);
|
|
+int _adb_connect(const char *service);
|
|
+
|
|
+/* connect to adb, connect to the named service, return 0 if
|
|
+** the connection succeeded AND the service returned OKAY
|
|
+*/
|
|
+int adb_command(const char *service);
|
|
+
|
|
+/* connect to adb, connect to the named service, return
|
|
+** a malloc'd string of its response upon success or NULL
|
|
+** on failure.
|
|
+*/
|
|
+char *adb_query(const char *service);
|
|
+
|
|
+/* Set the preferred transport to connect to.
|
|
+*/
|
|
+void adb_set_transport(transport_type type, const char* serial);
|
|
+
|
|
+/* Set TCP specifics of the transport to use
|
|
+*/
|
|
+void adb_set_tcp_specifics(int server_port);
|
|
+
|
|
+/* Set TCP Hostname of the transport to use
|
|
+*/
|
|
+void adb_set_tcp_name(const char* hostname);
|
|
+
|
|
+/* Return the console port of the currently connected emulator (if any)
|
|
+ * of -1 if there is no emulator, and -2 if there is more than one.
|
|
+ * assumes adb_set_transport() was alled previously...
|
|
+ */
|
|
+int adb_get_emulator_console_port(void);
|
|
+
|
|
+/* send commands to the current emulator instance. will fail if there
|
|
+ * is zero, or more than one emulator connected (or if you use -s <serial>
|
|
+ * with a <serial> that does not designate an emulator)
|
|
+ */
|
|
+int adb_send_emulator_command(int argc, char** argv);
|
|
+
|
|
+/* return verbose error string from last operation */
|
|
+const char *adb_error(void);
|
|
+
|
|
+/* read a standard adb status response (OKAY|FAIL) and
|
|
+** return 0 in the event of OKAY, -1 in the event of FAIL
|
|
+** or protocol error
|
|
+*/
|
|
+int adb_status(int fd);
|
|
+
|
|
+#endif
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/android_filesystem_config.h
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/android_filesystem_config.h 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,302 @@
|
|
+/*
|
|
+ * Copyright (C) 2007 The Android Open Source Project
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
+ * you may not use this file except in compliance with the License.
|
|
+ * You may obtain a copy of the License at
|
|
+ *
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
+ *
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+ * See the License for the specific language governing permissions and
|
|
+ * limitations under the License.
|
|
+ */
|
|
+
|
|
+/* This file is used to define the properties of the filesystem
|
|
+** images generated by build tools (mkbootfs and mkyaffs2image) and
|
|
+** by the device side of adb.
|
|
+*/
|
|
+
|
|
+#ifndef _ANDROID_FILESYSTEM_CONFIG_H_
|
|
+#define _ANDROID_FILESYSTEM_CONFIG_H_
|
|
+
|
|
+#include <string.h>
|
|
+#include <sys/stat.h>
|
|
+#include <sys/types.h>
|
|
+
|
|
+/* This is the master Users and Groups config for the platform.
|
|
+** DO NOT EVER RENUMBER.
|
|
+*/
|
|
+
|
|
+#define AID_ROOT 0 /* traditional unix root user */
|
|
+
|
|
+#define AID_SYSTEM 1000 /* system server */
|
|
+
|
|
+#define AID_RADIO 1001 /* telephony subsystem, RIL */
|
|
+#define AID_BLUETOOTH 1002 /* bluetooth subsystem */
|
|
+#define AID_GRAPHICS 1003 /* graphics devices */
|
|
+#define AID_INPUT 1004 /* input devices */
|
|
+#define AID_AUDIO 1005 /* audio devices */
|
|
+#define AID_CAMERA 1006 /* camera devices */
|
|
+#define AID_LOG 1007 /* log devices */
|
|
+#define AID_COMPASS 1008 /* compass device */
|
|
+#define AID_MOUNT 1009 /* mountd socket */
|
|
+#define AID_WIFI 1010 /* wifi subsystem */
|
|
+#define AID_ADB 1011 /* android debug bridge (adbd) */
|
|
+#define AID_INSTALL 1012 /* group for installing packages */
|
|
+#define AID_MEDIA 1013 /* mediaserver process */
|
|
+#define AID_DHCP 1014 /* dhcp client */
|
|
+#define AID_SDCARD_RW 1015 /* external storage write access */
|
|
+#define AID_VPN 1016 /* vpn system */
|
|
+#define AID_KEYSTORE 1017 /* keystore subsystem */
|
|
+#define AID_USB 1018 /* USB devices */
|
|
+#define AID_DRM 1019 /* DRM server */
|
|
+#define AID_MDNSR 1020 /* MulticastDNSResponder (service discovery) */
|
|
+#define AID_GPS 1021 /* GPS daemon */
|
|
+#define AID_UNUSED1 1022 /* deprecated, DO NOT USE */
|
|
+#define AID_MEDIA_RW 1023 /* internal media storage write access */
|
|
+#define AID_MTP 1024 /* MTP USB driver access */
|
|
+#define AID_UNUSED2 1025 /* deprecated, DO NOT USE */
|
|
+#define AID_DRMRPC 1026 /* group for drm rpc */
|
|
+#define AID_NFC 1027 /* nfc subsystem */
|
|
+#define AID_SDCARD_R 1028 /* external storage read access */
|
|
+
|
|
+#define AID_SHELL 2000 /* adb and debug shell user */
|
|
+#define AID_CACHE 2001 /* cache access */
|
|
+#define AID_DIAG 2002 /* access to diagnostic resources */
|
|
+
|
|
+/* The 3000 series are intended for use as supplemental group id's only.
|
|
+ * They indicate special Android capabilities that the kernel is aware of. */
|
|
+#define AID_NET_BT_ADMIN 3001 /* bluetooth: create any socket */
|
|
+#define AID_NET_BT 3002 /* bluetooth: create sco, rfcomm or l2cap sockets */
|
|
+#define AID_INET 3003 /* can create AF_INET and AF_INET6 sockets */
|
|
+#define AID_NET_RAW 3004 /* can create raw INET sockets */
|
|
+#define AID_NET_ADMIN 3005 /* can configure interfaces and routing tables. */
|
|
+#define AID_NET_BW_STATS 3006 /* read bandwidth statistics */
|
|
+#define AID_NET_BW_ACCT 3007 /* change bandwidth statistics accounting */
|
|
+#define AID_NET_BT_STACK 3008 /* bluetooth: access config files */
|
|
+#define AID_QCOM_ONCRPC 3009 /* can read/write /dev/oncrpc files */
|
|
+#define AID_QCOM_DIAG 3010 /* can read/write /dev/diag */
|
|
+
|
|
+#if defined(MOTOROLA_UIDS)
|
|
+#define AID_MOT_OSH 5000 /* OSH */
|
|
+#define AID_MOT_ACCY 9000 /* access to accessory */
|
|
+#define AID_MOT_PWRIC 9001 /* power IC */
|
|
+#define AID_MOT_USB 9002 /* mot usb */
|
|
+#define AID_MOT_DRM 9003 /* can access DRM resource. */
|
|
+#define AID_MOT_TCMD 9004 /* mot_tcmd */
|
|
+#define AID_MOT_SEC_RTC 9005 /* mot cpcap rtc */
|
|
+#define AID_MOT_TOMBSTONE 9006
|
|
+#define AID_MOT_TPAPI 9007 /* mot_tpapi */
|
|
+#define AID_MOT_SECCLKD 9008 /* mot_secclkd */
|
|
+#define AID_MOT_WHISPER 9009 /* Whisper Protocol access */
|
|
+#define AID_MOT_CAIF 9010 /* can create CAIF sockets */
|
|
+#define AID_MOT_DLNA 9011 /* DLNA native */
|
|
+#endif // MOTOROLA_UIDS
|
|
+
|
|
+#define AID_MISC 9998 /* access to misc storage */
|
|
+#define AID_NOBODY 9999
|
|
+
|
|
+#define AID_APP 10000 /* first app user */
|
|
+
|
|
+#define AID_ISOLATED_START 99000 /* start of uids for fully isolated sandboxed processes */
|
|
+#define AID_ISOLATED_END 99999 /* end of uids for fully isolated sandboxed processes */
|
|
+
|
|
+#define AID_USER 100000 /* offset for uid ranges for each user */
|
|
+
|
|
+#define AID_SHARED_GID_START 50000 /* start of gids for apps in each user to share */
|
|
+#define AID_SHARED_GID_END 59999 /* start of gids for apps in each user to share */
|
|
+
|
|
+#if !defined(EXCLUDE_FS_CONFIG_STRUCTURES)
|
|
+struct android_id_info {
|
|
+ const char *name;
|
|
+ unsigned aid;
|
|
+};
|
|
+
|
|
+static const struct android_id_info android_ids[] = {
|
|
+ { "root", AID_ROOT, },
|
|
+ { "system", AID_SYSTEM, },
|
|
+ { "radio", AID_RADIO, },
|
|
+ { "bluetooth", AID_BLUETOOTH, },
|
|
+ { "graphics", AID_GRAPHICS, },
|
|
+ { "input", AID_INPUT, },
|
|
+ { "audio", AID_AUDIO, },
|
|
+ { "camera", AID_CAMERA, },
|
|
+ { "log", AID_LOG, },
|
|
+ { "compass", AID_COMPASS, },
|
|
+ { "mount", AID_MOUNT, },
|
|
+ { "wifi", AID_WIFI, },
|
|
+ { "dhcp", AID_DHCP, },
|
|
+ { "adb", AID_ADB, },
|
|
+ { "install", AID_INSTALL, },
|
|
+ { "media", AID_MEDIA, },
|
|
+ { "drm", AID_DRM, },
|
|
+ { "mdnsr", AID_MDNSR, },
|
|
+ { "nfc", AID_NFC, },
|
|
+ { "drmrpc", AID_DRMRPC, },
|
|
+ { "shell", AID_SHELL, },
|
|
+ { "cache", AID_CACHE, },
|
|
+ { "diag", AID_DIAG, },
|
|
+ { "net_bt_admin", AID_NET_BT_ADMIN, },
|
|
+ { "net_bt", AID_NET_BT, },
|
|
+ { "net_bt_stack", AID_NET_BT_STACK, },
|
|
+ { "sdcard_r", AID_SDCARD_R, },
|
|
+ { "sdcard_rw", AID_SDCARD_RW, },
|
|
+ { "media_rw", AID_MEDIA_RW, },
|
|
+ { "vpn", AID_VPN, },
|
|
+ { "keystore", AID_KEYSTORE, },
|
|
+ { "usb", AID_USB, },
|
|
+ { "mtp", AID_MTP, },
|
|
+ { "gps", AID_GPS, },
|
|
+ { "inet", AID_INET, },
|
|
+ { "net_raw", AID_NET_RAW, },
|
|
+ { "net_admin", AID_NET_ADMIN, },
|
|
+ { "net_bw_stats", AID_NET_BW_STATS, },
|
|
+ { "net_bw_acct", AID_NET_BW_ACCT, },
|
|
+ { "qcom_oncrpc", AID_QCOM_ONCRPC, },
|
|
+ { "qcom_diag", AID_QCOM_DIAG, },
|
|
+#if defined(MOTOROLA_UIDS)
|
|
+ { "mot_osh", AID_MOT_OSH, },
|
|
+ { "mot_accy", AID_MOT_ACCY, },
|
|
+ { "mot_pwric", AID_MOT_PWRIC, },
|
|
+ { "mot_usb", AID_MOT_USB, },
|
|
+ { "mot_drm", AID_MOT_DRM, },
|
|
+ { "mot_tcmd", AID_MOT_TCMD, },
|
|
+ { "mot_sec_rtc", AID_MOT_SEC_RTC, },
|
|
+ { "mot_tombstone", AID_MOT_TOMBSTONE, },
|
|
+ { "mot_tpapi", AID_MOT_TPAPI, },
|
|
+ { "mot_secclkd", AID_MOT_SECCLKD, },
|
|
+ { "mot_whisper", AID_MOT_WHISPER, },
|
|
+ { "mot_caif", AID_MOT_CAIF, },
|
|
+ { "mot_dlna", AID_MOT_DLNA, },
|
|
+#endif
|
|
+ { "misc", AID_MISC, },
|
|
+ { "nobody", AID_NOBODY, },
|
|
+};
|
|
+
|
|
+#define android_id_count \
|
|
+ (sizeof(android_ids) / sizeof(android_ids[0]))
|
|
+
|
|
+struct fs_path_config {
|
|
+ unsigned mode;
|
|
+ unsigned uid;
|
|
+ unsigned gid;
|
|
+ const char *prefix;
|
|
+};
|
|
+
|
|
+/* Rules for directories.
|
|
+** These rules are applied based on "first match", so they
|
|
+** should start with the most specific path and work their
|
|
+** way up to the root.
|
|
+*/
|
|
+
|
|
+static struct fs_path_config android_dirs[] = {
|
|
+ { 00770, AID_SYSTEM, AID_CACHE, "cache" },
|
|
+ { 00771, AID_SYSTEM, AID_SYSTEM, "data/app" },
|
|
+ { 00771, AID_SYSTEM, AID_SYSTEM, "data/app-private" },
|
|
+ { 00771, AID_SYSTEM, AID_SYSTEM, "data/dalvik-cache" },
|
|
+ { 00771, AID_SYSTEM, AID_SYSTEM, "data/data" },
|
|
+ { 00771, AID_SHELL, AID_SHELL, "data/local/tmp" },
|
|
+ { 00771, AID_SHELL, AID_SHELL, "data/local" },
|
|
+ { 01771, AID_SYSTEM, AID_MISC, "data/misc" },
|
|
+ { 00770, AID_DHCP, AID_DHCP, "data/misc/dhcp" },
|
|
+ { 00775, AID_MEDIA_RW, AID_MEDIA_RW, "data/media" },
|
|
+ { 00775, AID_MEDIA_RW, AID_MEDIA_RW, "data/media/Music" },
|
|
+ { 00771, AID_SYSTEM, AID_SYSTEM, "data" },
|
|
+ { 00750, AID_ROOT, AID_SHELL, "sbin" },
|
|
+ { 00755, AID_ROOT, AID_ROOT, "system/addon.d" },
|
|
+ { 00755, AID_ROOT, AID_SHELL, "system/bin" },
|
|
+ { 00755, AID_ROOT, AID_SHELL, "system/vendor" },
|
|
+ { 00755, AID_ROOT, AID_SHELL, "system/xbin" },
|
|
+ { 00755, AID_ROOT, AID_ROOT, "system/etc/ppp" },
|
|
+ { 00777, AID_ROOT, AID_ROOT, "sdcard" },
|
|
+ { 00755, AID_ROOT, AID_ROOT, 0 },
|
|
+};
|
|
+
|
|
+/* Rules for files.
|
|
+** These rules are applied based on "first match", so they
|
|
+** should start with the most specific path and work their
|
|
+** way up to the root. Prefixes ending in * denotes wildcard
|
|
+** and will allow partial matches.
|
|
+*/
|
|
+static struct fs_path_config android_files[] = {
|
|
+ { 00440, AID_ROOT, AID_SHELL, "system/etc/init.goldfish.rc" },
|
|
+ { 00550, AID_ROOT, AID_SHELL, "system/etc/init.goldfish.sh" },
|
|
+ { 00440, AID_ROOT, AID_SHELL, "system/etc/init.trout.rc" },
|
|
+ { 00550, AID_ROOT, AID_SHELL, "system/etc/init.ril" },
|
|
+ { 00550, AID_ROOT, AID_SHELL, "system/etc/init.testmenu" },
|
|
+ { 00550, AID_DHCP, AID_SHELL, "system/etc/dhcpcd/dhcpcd-run-hooks" },
|
|
+ { 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/dbus.conf" },
|
|
+ { 00444, AID_RADIO, AID_AUDIO, "system/etc/AudioPara4.csv" },
|
|
+ { 00555, AID_ROOT, AID_ROOT, "system/etc/ppp/*" },
|
|
+ { 00555, AID_ROOT, AID_ROOT, "system/etc/rc.*" },
|
|
+ { 00755, AID_ROOT, AID_ROOT, "system/addon.d/*" },
|
|
+ { 00644, AID_SYSTEM, AID_SYSTEM, "data/app/*" },
|
|
+ { 00644, AID_MEDIA_RW, AID_MEDIA_RW, "data/media/*" },
|
|
+ { 00644, AID_SYSTEM, AID_SYSTEM, "data/app-private/*" },
|
|
+ { 00644, AID_APP, AID_APP, "data/data/*" },
|
|
+ /* the following two files are INTENTIONALLY set-gid and not set-uid.
|
|
+ * Do not change. */
|
|
+ { 02755, AID_ROOT, AID_NET_RAW, "system/bin/ping" },
|
|
+ { 02750, AID_ROOT, AID_INET, "system/bin/netcfg" },
|
|
+ /* the following five files are INTENTIONALLY set-uid, but they
|
|
+ * are NOT included on user builds. */
|
|
+ { 06755, AID_ROOT, AID_ROOT, "system/xbin/su" },
|
|
+ { 06755, AID_ROOT, AID_ROOT, "system/xbin/librank" },
|
|
+ { 06755, AID_ROOT, AID_ROOT, "system/xbin/procrank" },
|
|
+ { 06755, AID_ROOT, AID_ROOT, "system/xbin/procmem" },
|
|
+ { 06755, AID_ROOT, AID_ROOT, "system/xbin/tcpdump" },
|
|
+ { 04770, AID_ROOT, AID_RADIO, "system/bin/pppd-ril" },
|
|
+ /* the following file is INTENTIONALLY set-uid, and IS included
|
|
+ * in user builds. */
|
|
+ { 06750, AID_ROOT, AID_SHELL, "system/bin/run-as" },
|
|
+ { 06750, AID_ROOT, AID_SYSTEM, "system/bin/rebootcmd" },
|
|
+ { 00755, AID_ROOT, AID_SHELL, "system/bin/*" },
|
|
+ { 00755, AID_ROOT, AID_ROOT, "system/lib/valgrind/*" },
|
|
+ { 00755, AID_ROOT, AID_SHELL, "system/xbin/*" },
|
|
+ { 00755, AID_ROOT, AID_SHELL, "system/vendor/bin/*" },
|
|
+ { 00750, AID_ROOT, AID_SHELL, "sbin/*" },
|
|
+ { 00755, AID_ROOT, AID_ROOT, "bin/*" },
|
|
+ { 00750, AID_ROOT, AID_SHELL, "init*" },
|
|
+ { 00750, AID_ROOT, AID_SHELL, "charger*" },
|
|
+ { 00750, AID_ROOT, AID_SHELL, "sbin/fs_mgr" },
|
|
+ { 00640, AID_ROOT, AID_SHELL, "fstab.*" },
|
|
+ { 00755, AID_ROOT, AID_SHELL, "system/etc/init.d/*" },
|
|
+ { 00644, AID_ROOT, AID_ROOT, 0 },
|
|
+};
|
|
+
|
|
+static inline void fs_config(const char *path, int dir,
|
|
+ unsigned *uid, unsigned *gid, unsigned *mode)
|
|
+{
|
|
+ struct fs_path_config *pc;
|
|
+ int plen;
|
|
+
|
|
+ pc = dir ? android_dirs : android_files;
|
|
+ plen = strlen(path);
|
|
+ for(; pc->prefix; pc++){
|
|
+ int len = strlen(pc->prefix);
|
|
+ if (dir) {
|
|
+ if(plen < len) continue;
|
|
+ if(!strncmp(pc->prefix, path, len)) break;
|
|
+ continue;
|
|
+ }
|
|
+ /* If name ends in * then allow partial matches. */
|
|
+ if (pc->prefix[len -1] == '*') {
|
|
+ if(!strncmp(pc->prefix, path, len - 1)) break;
|
|
+ } else if (plen == len){
|
|
+ if(!strncmp(pc->prefix, path, len)) break;
|
|
+ }
|
|
+ }
|
|
+ *uid = pc->uid;
|
|
+ *gid = pc->gid;
|
|
+ *mode = (*mode & (~07777)) | pc->mode;
|
|
+
|
|
+#if 0
|
|
+ fprintf(stderr,"< '%s' '%s' %d %d %o >\n",
|
|
+ path, pc->prefix ? pc->prefix : "", *uid, *gid, *mode);
|
|
+#endif
|
|
+}
|
|
+#endif
|
|
+#endif
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/arpa_nameser.h
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/arpa_nameser.h 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,577 @@
|
|
+/* $NetBSD: nameser.h,v 1.19 2005/12/26 19:01:47 perry Exp $ */
|
|
+
|
|
+/*
|
|
+ * Copyright (c) 1983, 1989, 1993
|
|
+ * The Regents of the University of California. All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. Neither the name of the University nor the names of its contributors
|
|
+ * may be used to endorse or promote products derived from this software
|
|
+ * without specific prior written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
+ * SUCH DAMAGE.
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
|
|
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
|
|
+ *
|
|
+ * Permission to use, copy, modify, and distribute this software for any
|
|
+ * purpose with or without fee is hereby granted, provided that the above
|
|
+ * copyright notice and this permission notice appear in all copies.
|
|
+ *
|
|
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
|
|
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
|
|
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
|
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * Id: nameser.h,v 1.2.2.4.4.1 2004/03/09 08:33:30 marka Exp
|
|
+ */
|
|
+
|
|
+#ifndef _ARPA_NAMESER_H_
|
|
+#define _ARPA_NAMESER_H_
|
|
+
|
|
+#define BIND_4_COMPAT
|
|
+
|
|
+#include <sys/types.h>
|
|
+#include <sys/cdefs.h>
|
|
+
|
|
+/*
|
|
+ * Revision information. This is the release date in YYYYMMDD format.
|
|
+ * It can change every day so the right thing to do with it is use it
|
|
+ * in preprocessor commands such as "#if (__NAMESER > 19931104)". Do not
|
|
+ * compare for equality; rather, use it to determine whether your libbind.a
|
|
+ * contains a new enough lib/nameser/ to support the feature you need.
|
|
+ */
|
|
+
|
|
+#define __NAMESER 19991006 /* New interface version stamp. */
|
|
+
|
|
+/*
|
|
+ * Define constants based on RFC 883, RFC 1034, RFC 1035
|
|
+ */
|
|
+#define NS_PACKETSZ 512 /* default UDP packet size */
|
|
+#define NS_MAXDNAME 1025 /* maximum domain name */
|
|
+#define NS_MAXMSG 65535 /* maximum message size */
|
|
+#define NS_MAXCDNAME 255 /* maximum compressed domain name */
|
|
+#define NS_MAXLABEL 63 /* maximum length of domain label */
|
|
+#define NS_HFIXEDSZ 12 /* #/bytes of fixed data in header */
|
|
+#define NS_QFIXEDSZ 4 /* #/bytes of fixed data in query */
|
|
+#define NS_RRFIXEDSZ 10 /* #/bytes of fixed data in r record */
|
|
+#define NS_INT32SZ 4 /* #/bytes of data in a uint32_t */
|
|
+#define NS_INT16SZ 2 /* #/bytes of data in a uint16_t */
|
|
+#define NS_INT8SZ 1 /* #/bytes of data in a uint8_t */
|
|
+#define NS_INADDRSZ 4 /* IPv4 T_A */
|
|
+#define NS_IN6ADDRSZ 16 /* IPv6 T_AAAA */
|
|
+#define NS_CMPRSFLGS 0xc0 /* Flag bits indicating name compression. */
|
|
+#define NS_DEFAULTPORT 53 /* For both TCP and UDP. */
|
|
+
|
|
+/*
|
|
+ * These can be expanded with synonyms, just keep ns_parse.c:ns_parserecord()
|
|
+ * in synch with it.
|
|
+ */
|
|
+typedef enum __ns_sect {
|
|
+ ns_s_qd = 0, /* Query: Question. */
|
|
+ ns_s_zn = 0, /* Update: Zone. */
|
|
+ ns_s_an = 1, /* Query: Answer. */
|
|
+ ns_s_pr = 1, /* Update: Prerequisites. */
|
|
+ ns_s_ns = 2, /* Query: Name servers. */
|
|
+ ns_s_ud = 2, /* Update: Update. */
|
|
+ ns_s_ar = 3, /* Query|Update: Additional records. */
|
|
+ ns_s_max = 4
|
|
+} ns_sect;
|
|
+
|
|
+/*
|
|
+ * This is a message handle. It is caller allocated and has no dynamic data.
|
|
+ * This structure is intended to be opaque to all but ns_parse.c, thus the
|
|
+ * leading _'s on the member names. Use the accessor functions, not the _'s.
|
|
+ */
|
|
+typedef struct __ns_msg {
|
|
+ const u_char *_msg, *_eom;
|
|
+ uint16_t _id, _flags, _counts[ns_s_max];
|
|
+ const u_char *_sections[ns_s_max];
|
|
+ ns_sect _sect;
|
|
+ int _rrnum;
|
|
+ const u_char *_msg_ptr;
|
|
+} ns_msg;
|
|
+
|
|
+/* Private data structure - do not use from outside library. */
|
|
+struct _ns_flagdata { int mask, shift; };
|
|
+extern const struct _ns_flagdata _ns_flagdata[];
|
|
+
|
|
+/* Accessor macros - this is part of the public interface. */
|
|
+
|
|
+#define ns_msg_id(handle) ((handle)._id + 0)
|
|
+#define ns_msg_base(handle) ((handle)._msg + 0)
|
|
+#define ns_msg_end(handle) ((handle)._eom + 0)
|
|
+#define ns_msg_size(handle) ((size_t)((handle)._eom - (handle)._msg))
|
|
+#define ns_msg_count(handle, section) ((handle)._counts[section] + 0)
|
|
+
|
|
+/*
|
|
+ * This is a parsed record. It is caller allocated and has no dynamic data.
|
|
+ */
|
|
+typedef struct __ns_rr {
|
|
+ char name[NS_MAXDNAME];
|
|
+ uint16_t type;
|
|
+ uint16_t rr_class;
|
|
+ uint32_t ttl;
|
|
+ uint16_t rdlength;
|
|
+ const u_char * rdata;
|
|
+} ns_rr;
|
|
+
|
|
+/* Accessor macros - this is part of the public interface. */
|
|
+#define ns_rr_name(rr) (((rr).name[0] != '\0') ? (rr).name : ".")
|
|
+#define ns_rr_type(rr) ((ns_type)((rr).type + 0))
|
|
+#define ns_rr_class(rr) ((ns_class)((rr).rr_class + 0))
|
|
+#define ns_rr_ttl(rr) ((u_long)(rr).ttl + 0)
|
|
+#define ns_rr_rdlen(rr) ((size_t)(rr).rdlength + 0)
|
|
+#define ns_rr_rdata(rr) ((rr).rdata + 0)
|
|
+
|
|
+/*
|
|
+ * These don't have to be in the same order as in the packet flags word,
|
|
+ * and they can even overlap in some cases, but they will need to be kept
|
|
+ * in synch with ns_parse.c:ns_flagdata[].
|
|
+ */
|
|
+typedef enum __ns_flag {
|
|
+ ns_f_qr, /* Question/Response. */
|
|
+ ns_f_opcode, /* Operation code. */
|
|
+ ns_f_aa, /* Authoritative Answer. */
|
|
+ ns_f_tc, /* Truncation occurred. */
|
|
+ ns_f_rd, /* Recursion Desired. */
|
|
+ ns_f_ra, /* Recursion Available. */
|
|
+ ns_f_z, /* MBZ. */
|
|
+ ns_f_ad, /* Authentic Data (DNSSEC). */
|
|
+ ns_f_cd, /* Checking Disabled (DNSSEC). */
|
|
+ ns_f_rcode, /* Response code. */
|
|
+ ns_f_max
|
|
+} ns_flag;
|
|
+
|
|
+/*
|
|
+ * Currently defined opcodes.
|
|
+ */
|
|
+typedef enum __ns_opcode {
|
|
+ ns_o_query = 0, /* Standard query. */
|
|
+ ns_o_iquery = 1, /* Inverse query (deprecated/unsupported). */
|
|
+ ns_o_status = 2, /* Name server status query (unsupported). */
|
|
+ /* Opcode 3 is undefined/reserved. */
|
|
+ ns_o_notify = 4, /* Zone change notification. */
|
|
+ ns_o_update = 5, /* Zone update message. */
|
|
+ ns_o_max = 6
|
|
+} ns_opcode;
|
|
+
|
|
+/*
|
|
+ * Currently defined response codes.
|
|
+ */
|
|
+typedef enum __ns_rcode {
|
|
+ ns_r_noerror = 0, /* No error occurred. */
|
|
+ ns_r_formerr = 1, /* Format error. */
|
|
+ ns_r_servfail = 2, /* Server failure. */
|
|
+ ns_r_nxdomain = 3, /* Name error. */
|
|
+ ns_r_notimpl = 4, /* Unimplemented. */
|
|
+ ns_r_refused = 5, /* Operation refused. */
|
|
+ /* these are for BIND_UPDATE */
|
|
+ ns_r_yxdomain = 6, /* Name exists */
|
|
+ ns_r_yxrrset = 7, /* RRset exists */
|
|
+ ns_r_nxrrset = 8, /* RRset does not exist */
|
|
+ ns_r_notauth = 9, /* Not authoritative for zone */
|
|
+ ns_r_notzone = 10, /* Zone of record different from zone section */
|
|
+ ns_r_max = 11,
|
|
+ /* The following are EDNS extended rcodes */
|
|
+ ns_r_badvers = 16,
|
|
+ /* The following are TSIG errors */
|
|
+ ns_r_badsig = 16,
|
|
+ ns_r_badkey = 17,
|
|
+ ns_r_badtime = 18
|
|
+} ns_rcode;
|
|
+
|
|
+/* BIND_UPDATE */
|
|
+typedef enum __ns_update_operation {
|
|
+ ns_uop_delete = 0,
|
|
+ ns_uop_add = 1,
|
|
+ ns_uop_max = 2
|
|
+} ns_update_operation;
|
|
+
|
|
+/*
|
|
+ * This structure is used for TSIG authenticated messages
|
|
+ */
|
|
+struct ns_tsig_key {
|
|
+ char name[NS_MAXDNAME], alg[NS_MAXDNAME];
|
|
+ unsigned char *data;
|
|
+ int len;
|
|
+};
|
|
+typedef struct ns_tsig_key ns_tsig_key;
|
|
+
|
|
+/*
|
|
+ * This structure is used for TSIG authenticated TCP messages
|
|
+ */
|
|
+struct ns_tcp_tsig_state {
|
|
+ int counter;
|
|
+ struct dst_key *key;
|
|
+ void *ctx;
|
|
+ unsigned char sig[NS_PACKETSZ];
|
|
+ int siglen;
|
|
+};
|
|
+typedef struct ns_tcp_tsig_state ns_tcp_tsig_state;
|
|
+
|
|
+#define NS_TSIG_FUDGE 300
|
|
+#define NS_TSIG_TCP_COUNT 100
|
|
+#define NS_TSIG_ALG_HMAC_MD5 "HMAC-MD5.SIG-ALG.REG.INT"
|
|
+
|
|
+#define NS_TSIG_ERROR_NO_TSIG -10
|
|
+#define NS_TSIG_ERROR_NO_SPACE -11
|
|
+#define NS_TSIG_ERROR_FORMERR -12
|
|
+
|
|
+/*
|
|
+ * Currently defined type values for resources and queries.
|
|
+ */
|
|
+typedef enum __ns_type {
|
|
+ ns_t_invalid = 0, /* Cookie. */
|
|
+ ns_t_a = 1, /* Host address. */
|
|
+ ns_t_ns = 2, /* Authoritative server. */
|
|
+ ns_t_md = 3, /* Mail destination. */
|
|
+ ns_t_mf = 4, /* Mail forwarder. */
|
|
+ ns_t_cname = 5, /* Canonical name. */
|
|
+ ns_t_soa = 6, /* Start of authority zone. */
|
|
+ ns_t_mb = 7, /* Mailbox domain name. */
|
|
+ ns_t_mg = 8, /* Mail group member. */
|
|
+ ns_t_mr = 9, /* Mail rename name. */
|
|
+ ns_t_null = 10, /* Null resource record. */
|
|
+ ns_t_wks = 11, /* Well known service. */
|
|
+ ns_t_ptr = 12, /* Domain name pointer. */
|
|
+ ns_t_hinfo = 13, /* Host information. */
|
|
+ ns_t_minfo = 14, /* Mailbox information. */
|
|
+ ns_t_mx = 15, /* Mail routing information. */
|
|
+ ns_t_txt = 16, /* Text strings. */
|
|
+ ns_t_rp = 17, /* Responsible person. */
|
|
+ ns_t_afsdb = 18, /* AFS cell database. */
|
|
+ ns_t_x25 = 19, /* X_25 calling address. */
|
|
+ ns_t_isdn = 20, /* ISDN calling address. */
|
|
+ ns_t_rt = 21, /* Router. */
|
|
+ ns_t_nsap = 22, /* NSAP address. */
|
|
+ ns_t_nsap_ptr = 23, /* Reverse NSAP lookup (deprecated). */
|
|
+ ns_t_sig = 24, /* Security signature. */
|
|
+ ns_t_key = 25, /* Security key. */
|
|
+ ns_t_px = 26, /* X.400 mail mapping. */
|
|
+ ns_t_gpos = 27, /* Geographical position (withdrawn). */
|
|
+ ns_t_aaaa = 28, /* Ip6 Address. */
|
|
+ ns_t_loc = 29, /* Location Information. */
|
|
+ ns_t_nxt = 30, /* Next domain (security). */
|
|
+ ns_t_eid = 31, /* Endpoint identifier. */
|
|
+ ns_t_nimloc = 32, /* Nimrod Locator. */
|
|
+ ns_t_srv = 33, /* Server Selection. */
|
|
+ ns_t_atma = 34, /* ATM Address */
|
|
+ ns_t_naptr = 35, /* Naming Authority PoinTeR */
|
|
+ ns_t_kx = 36, /* Key Exchange */
|
|
+ ns_t_cert = 37, /* Certification record */
|
|
+ ns_t_a6 = 38, /* IPv6 address (deprecates AAAA) */
|
|
+ ns_t_dname = 39, /* Non-terminal DNAME (for IPv6) */
|
|
+ ns_t_sink = 40, /* Kitchen sink (experimentatl) */
|
|
+ ns_t_opt = 41, /* EDNS0 option (meta-RR) */
|
|
+ ns_t_apl = 42, /* Address prefix list (RFC 3123) */
|
|
+ ns_t_tkey = 249, /* Transaction key */
|
|
+ ns_t_tsig = 250, /* Transaction signature. */
|
|
+ ns_t_ixfr = 251, /* Incremental zone transfer. */
|
|
+ ns_t_axfr = 252, /* Transfer zone of authority. */
|
|
+ ns_t_mailb = 253, /* Transfer mailbox records. */
|
|
+ ns_t_maila = 254, /* Transfer mail agent records. */
|
|
+ ns_t_any = 255, /* Wildcard match. */
|
|
+ ns_t_zxfr = 256, /* BIND-specific, nonstandard. */
|
|
+ ns_t_max = 65536
|
|
+} ns_type;
|
|
+
|
|
+/* Exclusively a QTYPE? (not also an RTYPE) */
|
|
+#define ns_t_qt_p(t) (ns_t_xfr_p(t) || (t) == ns_t_any || \
|
|
+ (t) == ns_t_mailb || (t) == ns_t_maila)
|
|
+/* Some kind of meta-RR? (not a QTYPE, but also not an RTYPE) */
|
|
+#define ns_t_mrr_p(t) ((t) == ns_t_tsig || (t) == ns_t_opt)
|
|
+/* Exclusively an RTYPE? (not also a QTYPE or a meta-RR) */
|
|
+#define ns_t_rr_p(t) (!ns_t_qt_p(t) && !ns_t_mrr_p(t))
|
|
+#define ns_t_udp_p(t) ((t) != ns_t_axfr && (t) != ns_t_zxfr)
|
|
+#define ns_t_xfr_p(t) ((t) == ns_t_axfr || (t) == ns_t_ixfr || \
|
|
+ (t) == ns_t_zxfr)
|
|
+
|
|
+/*
|
|
+ * Values for class field
|
|
+ */
|
|
+typedef enum __ns_class {
|
|
+ ns_c_invalid = 0, /* Cookie. */
|
|
+ ns_c_in = 1, /* Internet. */
|
|
+ ns_c_2 = 2, /* unallocated/unsupported. */
|
|
+ ns_c_chaos = 3, /* MIT Chaos-net. */
|
|
+ ns_c_hs = 4, /* MIT Hesiod. */
|
|
+ /* Query class values which do not appear in resource records */
|
|
+ ns_c_none = 254, /* for prereq. sections in update requests */
|
|
+ ns_c_any = 255, /* Wildcard match. */
|
|
+ ns_c_max = 65536
|
|
+} ns_class;
|
|
+
|
|
+/* DNSSEC constants. */
|
|
+
|
|
+typedef enum __ns_key_types {
|
|
+ ns_kt_rsa = 1, /* key type RSA/MD5 */
|
|
+ ns_kt_dh = 2, /* Diffie Hellman */
|
|
+ ns_kt_dsa = 3, /* Digital Signature Standard (MANDATORY) */
|
|
+ ns_kt_private = 254 /* Private key type starts with OID */
|
|
+} ns_key_types;
|
|
+
|
|
+typedef enum __ns_cert_types {
|
|
+ cert_t_pkix = 1, /* PKIX (X.509v3) */
|
|
+ cert_t_spki = 2, /* SPKI */
|
|
+ cert_t_pgp = 3, /* PGP */
|
|
+ cert_t_url = 253, /* URL private type */
|
|
+ cert_t_oid = 254 /* OID private type */
|
|
+} ns_cert_types;
|
|
+
|
|
+/* Flags field of the KEY RR rdata. */
|
|
+#define NS_KEY_TYPEMASK 0xC000 /* Mask for "type" bits */
|
|
+#define NS_KEY_TYPE_AUTH_CONF 0x0000 /* Key usable for both */
|
|
+#define NS_KEY_TYPE_CONF_ONLY 0x8000 /* Key usable for confidentiality */
|
|
+#define NS_KEY_TYPE_AUTH_ONLY 0x4000 /* Key usable for authentication */
|
|
+#define NS_KEY_TYPE_NO_KEY 0xC000 /* No key usable for either; no key */
|
|
+/* The type bits can also be interpreted independently, as single bits: */
|
|
+#define NS_KEY_NO_AUTH 0x8000 /* Key unusable for authentication */
|
|
+#define NS_KEY_NO_CONF 0x4000 /* Key unusable for confidentiality */
|
|
+#define NS_KEY_RESERVED2 0x2000 /* Security is *mandatory* if bit=0 */
|
|
+#define NS_KEY_EXTENDED_FLAGS 0x1000 /* reserved - must be zero */
|
|
+#define NS_KEY_RESERVED4 0x0800 /* reserved - must be zero */
|
|
+#define NS_KEY_RESERVED5 0x0400 /* reserved - must be zero */
|
|
+#define NS_KEY_NAME_TYPE 0x0300 /* these bits determine the type */
|
|
+#define NS_KEY_NAME_USER 0x0000 /* key is assoc. with user */
|
|
+#define NS_KEY_NAME_ENTITY 0x0200 /* key is assoc. with entity eg host */
|
|
+#define NS_KEY_NAME_ZONE 0x0100 /* key is zone key */
|
|
+#define NS_KEY_NAME_RESERVED 0x0300 /* reserved meaning */
|
|
+#define NS_KEY_RESERVED8 0x0080 /* reserved - must be zero */
|
|
+#define NS_KEY_RESERVED9 0x0040 /* reserved - must be zero */
|
|
+#define NS_KEY_RESERVED10 0x0020 /* reserved - must be zero */
|
|
+#define NS_KEY_RESERVED11 0x0010 /* reserved - must be zero */
|
|
+#define NS_KEY_SIGNATORYMASK 0x000F /* key can sign RR's of same name */
|
|
+#define NS_KEY_RESERVED_BITMASK ( NS_KEY_RESERVED2 | \
|
|
+ NS_KEY_RESERVED4 | \
|
|
+ NS_KEY_RESERVED5 | \
|
|
+ NS_KEY_RESERVED8 | \
|
|
+ NS_KEY_RESERVED9 | \
|
|
+ NS_KEY_RESERVED10 | \
|
|
+ NS_KEY_RESERVED11 )
|
|
+#define NS_KEY_RESERVED_BITMASK2 0xFFFF /* no bits defined here */
|
|
+
|
|
+/* The Algorithm field of the KEY and SIG RR's is an integer, {1..254} */
|
|
+#define NS_ALG_MD5RSA 1 /* MD5 with RSA */
|
|
+#define NS_ALG_DH 2 /* Diffie Hellman KEY */
|
|
+#define NS_ALG_DSA 3 /* DSA KEY */
|
|
+#define NS_ALG_DSS NS_ALG_DSA
|
|
+#define NS_ALG_EXPIRE_ONLY 253 /* No alg, no security */
|
|
+#define NS_ALG_PRIVATE_OID 254 /* Key begins with OID giving alg */
|
|
+
|
|
+/* Protocol values */
|
|
+/* value 0 is reserved */
|
|
+#define NS_KEY_PROT_TLS 1
|
|
+#define NS_KEY_PROT_EMAIL 2
|
|
+#define NS_KEY_PROT_DNSSEC 3
|
|
+#define NS_KEY_PROT_IPSEC 4
|
|
+#define NS_KEY_PROT_ANY 255
|
|
+
|
|
+/* Signatures */
|
|
+#define NS_MD5RSA_MIN_BITS 512 /* Size of a mod or exp in bits */
|
|
+#define NS_MD5RSA_MAX_BITS 4096
|
|
+ /* Total of binary mod and exp */
|
|
+#define NS_MD5RSA_MAX_BYTES ((NS_MD5RSA_MAX_BITS+7/8)*2+3)
|
|
+ /* Max length of text sig block */
|
|
+#define NS_MD5RSA_MAX_BASE64 (((NS_MD5RSA_MAX_BYTES+2)/3)*4)
|
|
+#define NS_MD5RSA_MIN_SIZE ((NS_MD5RSA_MIN_BITS+7)/8)
|
|
+#define NS_MD5RSA_MAX_SIZE ((NS_MD5RSA_MAX_BITS+7)/8)
|
|
+
|
|
+#define NS_DSA_SIG_SIZE 41
|
|
+#define NS_DSA_MIN_SIZE 213
|
|
+#define NS_DSA_MAX_BYTES 405
|
|
+
|
|
+/* Offsets into SIG record rdata to find various values */
|
|
+#define NS_SIG_TYPE 0 /* Type flags */
|
|
+#define NS_SIG_ALG 2 /* Algorithm */
|
|
+#define NS_SIG_LABELS 3 /* How many labels in name */
|
|
+#define NS_SIG_OTTL 4 /* Original TTL */
|
|
+#define NS_SIG_EXPIR 8 /* Expiration time */
|
|
+#define NS_SIG_SIGNED 12 /* Signature time */
|
|
+#define NS_SIG_FOOT 16 /* Key footprint */
|
|
+#define NS_SIG_SIGNER 18 /* Domain name of who signed it */
|
|
+
|
|
+/* How RR types are represented as bit-flags in NXT records */
|
|
+#define NS_NXT_BITS 8
|
|
+#define NS_NXT_BIT_SET( n,p) (p[(n)/NS_NXT_BITS] |= (0x80>>((n)%NS_NXT_BITS)))
|
|
+#define NS_NXT_BIT_CLEAR(n,p) (p[(n)/NS_NXT_BITS] &= ~(0x80>>((n)%NS_NXT_BITS)))
|
|
+#define NS_NXT_BIT_ISSET(n,p) (p[(n)/NS_NXT_BITS] & (0x80>>((n)%NS_NXT_BITS)))
|
|
+#define NS_NXT_MAX 127
|
|
+
|
|
+/*
|
|
+ * EDNS0 extended flags, host order.
|
|
+ */
|
|
+#define NS_OPT_DNSSEC_OK 0x8000U
|
|
+
|
|
+/*
|
|
+ * Inline versions of get/put short/long. Pointer is advanced.
|
|
+ */
|
|
+#define NS_GET16(s, cp) do { \
|
|
+ const u_char *t_cp = (const u_char *)(cp); \
|
|
+ (s) = ((uint16_t)t_cp[0] << 8) \
|
|
+ | ((uint16_t)t_cp[1]) \
|
|
+ ; \
|
|
+ (cp) += NS_INT16SZ; \
|
|
+} while (/*CONSTCOND*/0)
|
|
+
|
|
+#define NS_GET32(l, cp) do { \
|
|
+ const u_char *t_cp = (const u_char *)(cp); \
|
|
+ (l) = ((uint32_t)t_cp[0] << 24) \
|
|
+ | ((uint32_t)t_cp[1] << 16) \
|
|
+ | ((uint32_t)t_cp[2] << 8) \
|
|
+ | ((uint32_t)t_cp[3]) \
|
|
+ ; \
|
|
+ (cp) += NS_INT32SZ; \
|
|
+} while (/*CONSTCOND*/0)
|
|
+
|
|
+#define NS_PUT16(s, cp) do { \
|
|
+ uint32_t t_s = (uint32_t)(s); \
|
|
+ u_char *t_cp = (u_char *)(cp); \
|
|
+ *t_cp++ = t_s >> 8; \
|
|
+ *t_cp = t_s; \
|
|
+ (cp) += NS_INT16SZ; \
|
|
+} while (/*CONSTCOND*/0)
|
|
+
|
|
+#define NS_PUT32(l, cp) do { \
|
|
+ uint32_t t_l = (uint32_t)(l); \
|
|
+ u_char *t_cp = (u_char *)(cp); \
|
|
+ *t_cp++ = t_l >> 24; \
|
|
+ *t_cp++ = t_l >> 16; \
|
|
+ *t_cp++ = t_l >> 8; \
|
|
+ *t_cp = t_l; \
|
|
+ (cp) += NS_INT32SZ; \
|
|
+} while (/*CONSTCOND*/0)
|
|
+
|
|
+/*
|
|
+ * ANSI C identifier hiding for bind's lib/nameser.
|
|
+ */
|
|
+#define ns_msg_getflag __ns_msg_getflag
|
|
+#define ns_get16 __ns_get16
|
|
+#define ns_get32 __ns_get32
|
|
+#define ns_put16 __ns_put16
|
|
+#define ns_put32 __ns_put32
|
|
+#define ns_initparse __ns_initparse
|
|
+#define ns_skiprr __ns_skiprr
|
|
+#define ns_parserr __ns_parserr
|
|
+#define ns_sprintrr __ns_sprintrr
|
|
+#define ns_sprintrrf __ns_sprintrrf
|
|
+#define ns_format_ttl __ns_format_ttl
|
|
+#define ns_parse_ttl __ns_parse_ttl
|
|
+#define ns_datetosecs __ns_datetosecs
|
|
+#define ns_name_ntol __ns_name_ntol
|
|
+#define ns_name_ntop __ns_name_ntop
|
|
+#define ns_name_pton __ns_name_pton
|
|
+#define ns_name_unpack __ns_name_unpack
|
|
+#define ns_name_pack __ns_name_pack
|
|
+#define ns_name_compress __ns_name_compress
|
|
+#define ns_name_uncompress __ns_name_uncompress
|
|
+#define ns_name_skip __ns_name_skip
|
|
+#define ns_name_rollback __ns_name_rollback
|
|
+#define ns_sign __ns_sign
|
|
+#define ns_sign2 __ns_sign2
|
|
+#define ns_sign_tcp __ns_sign_tcp
|
|
+#define ns_sign_tcp2 __ns_sign_tcp2
|
|
+#define ns_sign_tcp_init __ns_sign_tcp_init
|
|
+#define ns_find_tsig __ns_find_tsig
|
|
+#define ns_verify __ns_verify
|
|
+#define ns_verify_tcp __ns_verify_tcp
|
|
+#define ns_verify_tcp_init __ns_verify_tcp_init
|
|
+#define ns_samedomain __ns_samedomain
|
|
+#define ns_subdomain __ns_subdomain
|
|
+#define ns_makecanon __ns_makecanon
|
|
+#define ns_samename __ns_samename
|
|
+
|
|
+__BEGIN_DECLS
|
|
+int ns_msg_getflag(ns_msg, int);
|
|
+uint16_t ns_get16(const u_char *);
|
|
+uint32_t ns_get32(const u_char *);
|
|
+void ns_put16(uint16_t, u_char *);
|
|
+void ns_put32(uint32_t, u_char *);
|
|
+int ns_initparse(const u_char *, int, ns_msg *);
|
|
+int ns_skiprr(const u_char *, const u_char *, ns_sect, int);
|
|
+int ns_parserr(ns_msg *, ns_sect, int, ns_rr *);
|
|
+int ns_sprintrr(const ns_msg *, const ns_rr *,
|
|
+ const char *, const char *, char *, size_t);
|
|
+int ns_sprintrrf(const u_char *, size_t, const char *,
|
|
+ ns_class, ns_type, u_long, const u_char *,
|
|
+ size_t, const char *, const char *,
|
|
+ char *, size_t);
|
|
+int ns_format_ttl(u_long, char *, size_t);
|
|
+int ns_parse_ttl(const char *, u_long *);
|
|
+uint32_t ns_datetosecs(const char *cp, int *errp);
|
|
+int ns_name_ntol(const u_char *, u_char *, size_t);
|
|
+int ns_name_ntop(const u_char *, char *, size_t);
|
|
+int ns_name_pton(const char *, u_char *, size_t);
|
|
+int ns_name_unpack(const u_char *, const u_char *,
|
|
+ const u_char *, u_char *, size_t);
|
|
+int ns_name_pack(const u_char *, u_char *, int,
|
|
+ const u_char **, const u_char **);
|
|
+int ns_name_uncompress(const u_char *, const u_char *,
|
|
+ const u_char *, char *, size_t);
|
|
+int ns_name_compress(const char *, u_char *, size_t,
|
|
+ const u_char **, const u_char **);
|
|
+int ns_name_skip(const u_char **, const u_char *);
|
|
+void ns_name_rollback(const u_char *, const u_char **,
|
|
+ const u_char **);
|
|
+int ns_sign(u_char *, int *, int, int, void *,
|
|
+ const u_char *, int, u_char *, int *, time_t);
|
|
+int ns_sign2(u_char *, int *, int, int, void *,
|
|
+ const u_char *, int, u_char *, int *, time_t,
|
|
+ u_char **, u_char **);
|
|
+int ns_sign_tcp(u_char *, int *, int, int,
|
|
+ ns_tcp_tsig_state *, int);
|
|
+int ns_sign_tcp2(u_char *, int *, int, int,
|
|
+ ns_tcp_tsig_state *, int,
|
|
+ u_char **, u_char **);
|
|
+int ns_sign_tcp_init(void *, const u_char *, int,
|
|
+ ns_tcp_tsig_state *);
|
|
+u_char *ns_find_tsig(u_char *, u_char *);
|
|
+int ns_verify(u_char *, int *, void *,
|
|
+ const u_char *, int, u_char *, int *,
|
|
+ time_t *, int);
|
|
+int ns_verify_tcp(u_char *, int *, ns_tcp_tsig_state *, int);
|
|
+int ns_verify_tcp_init(void *, const u_char *, int,
|
|
+ ns_tcp_tsig_state *);
|
|
+int ns_samedomain(const char *, const char *);
|
|
+int ns_subdomain(const char *, const char *);
|
|
+int ns_makecanon(const char *, char *, size_t);
|
|
+int ns_samename(const char *, const char *);
|
|
+__END_DECLS
|
|
+
|
|
+#ifdef BIND_4_COMPAT
|
|
+#include "arpa_nameser_compat.h"
|
|
+#endif
|
|
+
|
|
+#if 0
|
|
+# include <logd.h>
|
|
+# define XLOG(...) \
|
|
+ __libc_android_log_print(ANDROID_LOG_DEBUG,"libc",__VA_ARGS__)
|
|
+#else
|
|
+#define XLOG(...) do {} while (0)
|
|
+#endif
|
|
+
|
|
+#endif /* !_ARPA_NAMESER_H_ */
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/arpa_nameser_compat.h
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/arpa_nameser_compat.h 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,236 @@
|
|
+/* $NetBSD: nameser_compat.h,v 1.1.1.2 2004/11/07 01:28:27 christos Exp $ */
|
|
+
|
|
+/* Copyright (c) 1983, 1989
|
|
+ * The Regents of the University of California. All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. All advertising materials mentioning features or use of this software
|
|
+ * must display the following acknowledgement:
|
|
+ * This product includes software developed by the University of
|
|
+ * California, Berkeley and its contributors.
|
|
+ * 4. Neither the name of the University nor the names of its contributors
|
|
+ * may be used to endorse or promote products derived from this software
|
|
+ * without specific prior written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
+ * SUCH DAMAGE.
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * from nameser.h 8.1 (Berkeley) 6/2/93
|
|
+ * Id: nameser_compat.h,v 1.1.2.3.4.2 2004/07/01 04:43:41 marka Exp
|
|
+ */
|
|
+
|
|
+#ifndef _ARPA_NAMESER_COMPAT_
|
|
+#define _ARPA_NAMESER_COMPAT_
|
|
+
|
|
+#define __BIND 19950621 /* (DEAD) interface version stamp. */
|
|
+
|
|
+#include <endian.h>
|
|
+
|
|
+#ifndef BYTE_ORDER
|
|
+#if (BSD >= 199103)
|
|
+# include <machine/endian.h>
|
|
+#else
|
|
+#ifdef __linux
|
|
+# include <endian.h>
|
|
+#else
|
|
+#define LITTLE_ENDIAN 1234 /* least-significant byte first (vax, pc) */
|
|
+#define BIG_ENDIAN 4321 /* most-significant byte first (IBM, net) */
|
|
+#define PDP_ENDIAN 3412 /* LSB first in word, MSW first in long (pdp)*/
|
|
+
|
|
+#if defined(vax) || defined(ns32000) || defined(sun386) || defined(i386) || \
|
|
+ defined(MIPSEL) || defined(_MIPSEL) || defined(BIT_ZERO_ON_RIGHT) || \
|
|
+ defined(__alpha__) || defined(__alpha) || \
|
|
+ (defined(__Lynx__) && defined(__x86__))
|
|
+#define BYTE_ORDER LITTLE_ENDIAN
|
|
+#endif
|
|
+
|
|
+#if defined(sel) || defined(pyr) || defined(mc68000) || defined(sparc) || \
|
|
+ defined(is68k) || defined(tahoe) || defined(ibm032) || defined(ibm370) || \
|
|
+ defined(MIPSEB) || defined(_MIPSEB) || defined(_IBMR2) || defined(DGUX) ||\
|
|
+ defined(apollo) || defined(__convex__) || defined(_CRAY) || \
|
|
+ defined(__hppa) || defined(__hp9000) || \
|
|
+ defined(__hp9000s300) || defined(__hp9000s700) || \
|
|
+ defined(__hp3000s900) || defined(__hpux) || defined(MPE) || \
|
|
+ defined (BIT_ZERO_ON_LEFT) || defined(m68k) || defined(__sparc) || \
|
|
+ (defined(__Lynx__) && \
|
|
+ (defined(__68k__) || defined(__sparc__) || defined(__powerpc__)))
|
|
+#define BYTE_ORDER BIG_ENDIAN
|
|
+#endif
|
|
+#endif /* __linux */
|
|
+#endif /* BSD */
|
|
+#endif /* BYTE_ORDER */
|
|
+
|
|
+#if !defined(BYTE_ORDER) || \
|
|
+ (BYTE_ORDER != BIG_ENDIAN && BYTE_ORDER != LITTLE_ENDIAN && \
|
|
+ BYTE_ORDER != PDP_ENDIAN)
|
|
+ /* you must determine what the correct bit order is for
|
|
+ * your compiler - the next line is an intentional error
|
|
+ * which will force your compiles to bomb until you fix
|
|
+ * the above macros.
|
|
+ */
|
|
+ #error "Undefined or invalid BYTE_ORDER";
|
|
+#endif
|
|
+
|
|
+/*
|
|
+ * Structure for query header. The order of the fields is machine- and
|
|
+ * compiler-dependent, depending on the byte/bit order and the layout
|
|
+ * of bit fields. We use bit fields only in int variables, as this
|
|
+ * is all ANSI requires. This requires a somewhat confusing rearrangement.
|
|
+ */
|
|
+
|
|
+typedef struct {
|
|
+ unsigned id :16; /* query identification number */
|
|
+#if BYTE_ORDER == BIG_ENDIAN
|
|
+ /* fields in third byte */
|
|
+ unsigned qr: 1; /* response flag */
|
|
+ unsigned opcode: 4; /* purpose of message */
|
|
+ unsigned aa: 1; /* authoritive answer */
|
|
+ unsigned tc: 1; /* truncated message */
|
|
+ unsigned rd: 1; /* recursion desired */
|
|
+ /* fields in fourth byte */
|
|
+ unsigned ra: 1; /* recursion available */
|
|
+ unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */
|
|
+ unsigned ad: 1; /* authentic data from named */
|
|
+ unsigned cd: 1; /* checking disabled by resolver */
|
|
+ unsigned rcode :4; /* response code */
|
|
+#endif
|
|
+#if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN
|
|
+ /* fields in third byte */
|
|
+ unsigned rd :1; /* recursion desired */
|
|
+ unsigned tc :1; /* truncated message */
|
|
+ unsigned aa :1; /* authoritive answer */
|
|
+ unsigned opcode :4; /* purpose of message */
|
|
+ unsigned qr :1; /* response flag */
|
|
+ /* fields in fourth byte */
|
|
+ unsigned rcode :4; /* response code */
|
|
+ unsigned cd: 1; /* checking disabled by resolver */
|
|
+ unsigned ad: 1; /* authentic data from named */
|
|
+ unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */
|
|
+ unsigned ra :1; /* recursion available */
|
|
+#endif
|
|
+ /* remaining bytes */
|
|
+ unsigned qdcount :16; /* number of question entries */
|
|
+ unsigned ancount :16; /* number of answer entries */
|
|
+ unsigned nscount :16; /* number of authority entries */
|
|
+ unsigned arcount :16; /* number of resource entries */
|
|
+} HEADER;
|
|
+
|
|
+#define PACKETSZ NS_PACKETSZ
|
|
+#define MAXDNAME NS_MAXDNAME
|
|
+#define MAXCDNAME NS_MAXCDNAME
|
|
+#define MAXLABEL NS_MAXLABEL
|
|
+#define HFIXEDSZ NS_HFIXEDSZ
|
|
+#define QFIXEDSZ NS_QFIXEDSZ
|
|
+#define RRFIXEDSZ NS_RRFIXEDSZ
|
|
+#define INT32SZ NS_INT32SZ
|
|
+#define INT16SZ NS_INT16SZ
|
|
+#define INT8SZ NS_INT8SZ
|
|
+#define INADDRSZ NS_INADDRSZ
|
|
+#define IN6ADDRSZ NS_IN6ADDRSZ
|
|
+#define INDIR_MASK NS_CMPRSFLGS
|
|
+#define NAMESERVER_PORT NS_DEFAULTPORT
|
|
+
|
|
+#define S_ZONE ns_s_zn
|
|
+#define S_PREREQ ns_s_pr
|
|
+#define S_UPDATE ns_s_ud
|
|
+#define S_ADDT ns_s_ar
|
|
+
|
|
+#define QUERY ns_o_query
|
|
+#define IQUERY ns_o_iquery
|
|
+#define STATUS ns_o_status
|
|
+#define NS_NOTIFY_OP ns_o_notify
|
|
+#define NS_UPDATE_OP ns_o_update
|
|
+
|
|
+#define NOERROR ns_r_noerror
|
|
+#define FORMERR ns_r_formerr
|
|
+#define SERVFAIL ns_r_servfail
|
|
+#define NXDOMAIN ns_r_nxdomain
|
|
+#define NOTIMP ns_r_notimpl
|
|
+#define REFUSED ns_r_refused
|
|
+#define YXDOMAIN ns_r_yxdomain
|
|
+#define YXRRSET ns_r_yxrrset
|
|
+#define NXRRSET ns_r_nxrrset
|
|
+#define NOTAUTH ns_r_notauth
|
|
+#define NOTZONE ns_r_notzone
|
|
+/*#define BADSIG ns_r_badsig*/
|
|
+/*#define BADKEY ns_r_badkey*/
|
|
+/*#define BADTIME ns_r_badtime*/
|
|
+
|
|
+
|
|
+#define DELETE ns_uop_delete
|
|
+#define ADD ns_uop_add
|
|
+
|
|
+#define T_A ns_t_a
|
|
+#define T_NS ns_t_ns
|
|
+#define T_MD ns_t_md
|
|
+#define T_MF ns_t_mf
|
|
+#define T_CNAME ns_t_cname
|
|
+#define T_SOA ns_t_soa
|
|
+#define T_MB ns_t_mb
|
|
+#define T_MG ns_t_mg
|
|
+#define T_MR ns_t_mr
|
|
+#define T_NULL ns_t_null
|
|
+#define T_WKS ns_t_wks
|
|
+#define T_PTR ns_t_ptr
|
|
+#define T_HINFO ns_t_hinfo
|
|
+#define T_MINFO ns_t_minfo
|
|
+#define T_MX ns_t_mx
|
|
+#define T_TXT ns_t_txt
|
|
+#define T_RP ns_t_rp
|
|
+#define T_AFSDB ns_t_afsdb
|
|
+#define T_X25 ns_t_x25
|
|
+#define T_ISDN ns_t_isdn
|
|
+#define T_RT ns_t_rt
|
|
+#define T_NSAP ns_t_nsap
|
|
+#define T_NSAP_PTR ns_t_nsap_ptr
|
|
+#define T_SIG ns_t_sig
|
|
+#define T_KEY ns_t_key
|
|
+#define T_PX ns_t_px
|
|
+#define T_GPOS ns_t_gpos
|
|
+#define T_AAAA ns_t_aaaa
|
|
+#define T_LOC ns_t_loc
|
|
+#define T_NXT ns_t_nxt
|
|
+#define T_EID ns_t_eid
|
|
+#define T_NIMLOC ns_t_nimloc
|
|
+#define T_SRV ns_t_srv
|
|
+#define T_ATMA ns_t_atma
|
|
+#define T_NAPTR ns_t_naptr
|
|
+#define T_A6 ns_t_a6
|
|
+#define T_TSIG ns_t_tsig
|
|
+#define T_IXFR ns_t_ixfr
|
|
+#define T_AXFR ns_t_axfr
|
|
+#define T_MAILB ns_t_mailb
|
|
+#define T_MAILA ns_t_maila
|
|
+#define T_ANY ns_t_any
|
|
+
|
|
+#define C_IN ns_c_in
|
|
+#define C_CHAOS ns_c_chaos
|
|
+#define C_HS ns_c_hs
|
|
+/* BIND_UPDATE */
|
|
+#define C_NONE ns_c_none
|
|
+#define C_ANY ns_c_any
|
|
+
|
|
+#define GETSHORT NS_GET16
|
|
+#define GETLONG NS_GET32
|
|
+#define PUTSHORT NS_PUT16
|
|
+#define PUTLONG NS_PUT32
|
|
+
|
|
+#endif /* _ARPA_NAMESER_COMPAT_ */
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/backup_service.c
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/backup_service.c 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,155 @@
|
|
+/*
|
|
+ * Copyright (C) 2011 The Android Open Source Project
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
+ * you may not use this file except in compliance with the License.
|
|
+ * You may obtain a copy of the License at
|
|
+ *
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
+ *
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+ * See the License for the specific language governing permissions and
|
|
+ * limitations under the License.
|
|
+ */
|
|
+
|
|
+#include <unistd.h>
|
|
+#include <stdio.h>
|
|
+
|
|
+#include "sysdeps.h"
|
|
+
|
|
+#define TRACE_TAG TRACE_ADB
|
|
+#include "adb.h"
|
|
+
|
|
+typedef struct {
|
|
+ pid_t pid;
|
|
+ int fd;
|
|
+} backup_harvest_params;
|
|
+
|
|
+// socketpair but do *not* mark as close_on_exec
|
|
+static int backup_socketpair(int sv[2]) {
|
|
+ int rc = unix_socketpair( AF_UNIX, SOCK_STREAM, 0, sv );
|
|
+ if (rc < 0)
|
|
+ return -1;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+// harvest the child process then close the read end of the socketpair
|
|
+static void* backup_child_waiter(void* args) {
|
|
+ int status;
|
|
+ backup_harvest_params* params = (backup_harvest_params*) args;
|
|
+
|
|
+ waitpid(params->pid, &status, 0);
|
|
+ adb_close(params->fd);
|
|
+ free(params);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+/* returns the data socket passing the backup data here for forwarding */
|
|
+int backup_service(BackupOperation op, char* args) {
|
|
+ pid_t pid;
|
|
+ int s[2];
|
|
+ char* operation;
|
|
+ int socketnum;
|
|
+
|
|
+ // Command string and choice of stdin/stdout for the pipe depend on our invocation
|
|
+ if (op == BACKUP) {
|
|
+ operation = "backup";
|
|
+ socketnum = STDOUT_FILENO;
|
|
+ } else {
|
|
+ operation = "restore";
|
|
+ socketnum = STDIN_FILENO;
|
|
+ }
|
|
+
|
|
+ D("backup_service(%s, %s)\n", operation, args);
|
|
+
|
|
+ // set up the pipe from the subprocess to here
|
|
+ // parent will read s[0]; child will write s[1]
|
|
+ if (backup_socketpair(s)) {
|
|
+ D("can't create backup/restore socketpair\n");
|
|
+ fprintf(stderr, "unable to create backup/restore socketpair\n");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ D("Backup/restore socket pair: (send=%d, receive=%d)\n", s[1], s[0]);
|
|
+ close_on_exec(s[0]); // only the side we hold on to
|
|
+
|
|
+ // spin off the child process to run the backup command
|
|
+ pid = fork();
|
|
+ if (pid < 0) {
|
|
+ // failure
|
|
+ D("can't fork for %s\n", operation);
|
|
+ fprintf(stderr, "unable to fork for %s\n", operation);
|
|
+ adb_close(s[0]);
|
|
+ adb_close(s[1]);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ // Great, we're off and running.
|
|
+ if (pid == 0) {
|
|
+ // child -- actually run the backup here
|
|
+ char* p;
|
|
+ int argc;
|
|
+ char portnum[16];
|
|
+ char** bu_args;
|
|
+
|
|
+ // fixed args: [0] is 'bu', [1] is the port number, [2] is the 'operation' string
|
|
+ argc = 3;
|
|
+ for (p = (char*)args; p && *p; ) {
|
|
+ argc++;
|
|
+ while (*p && *p != ':') p++;
|
|
+ if (*p == ':') p++;
|
|
+ }
|
|
+
|
|
+ bu_args = (char**) alloca(argc*sizeof(char*) + 1);
|
|
+
|
|
+ // run through again to build the argv array
|
|
+ argc = 0;
|
|
+ bu_args[argc++] = "bu";
|
|
+ snprintf(portnum, sizeof(portnum), "%d", s[1]);
|
|
+ bu_args[argc++] = portnum;
|
|
+ bu_args[argc++] = operation;
|
|
+ for (p = (char*)args; p && *p; ) {
|
|
+ bu_args[argc++] = p;
|
|
+ while (*p && *p != ':') p++;
|
|
+ if (*p == ':') {
|
|
+ *p = 0;
|
|
+ p++;
|
|
+ }
|
|
+ }
|
|
+ bu_args[argc] = NULL;
|
|
+
|
|
+ // Close the half of the socket that we don't care about, route 'bu's console
|
|
+ // to the output socket, and off we go
|
|
+ adb_close(s[0]);
|
|
+
|
|
+ // off we go
|
|
+ execvp("/system/bin/bu", (char * const *)bu_args);
|
|
+ // oops error - close up shop and go home
|
|
+ fprintf(stderr, "Unable to exec 'bu', bailing\n");
|
|
+ exit(-1);
|
|
+ } else {
|
|
+ adb_thread_t t;
|
|
+ backup_harvest_params* params;
|
|
+
|
|
+ // parent, i.e. adbd -- close the sending half of the socket
|
|
+ D("fork() returned pid %d\n", pid);
|
|
+ adb_close(s[1]);
|
|
+
|
|
+ // spin a thread to harvest the child process
|
|
+ params = (backup_harvest_params*) malloc(sizeof(backup_harvest_params));
|
|
+ params->pid = pid;
|
|
+ params->fd = s[0];
|
|
+ if (adb_thread_create(&t, backup_child_waiter, params)) {
|
|
+ adb_close(s[0]);
|
|
+ free(params);
|
|
+ D("Unable to create child harvester\n");
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // we'll be reading from s[0] as the data is sent by the child process
|
|
+ return s[0];
|
|
+}
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/base64.c
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/base64.c 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,340 @@
|
|
+/* $NetBSD: base64.c,v 1.8 2002/11/11 01:15:17 thorpej Exp $ */
|
|
+
|
|
+/*
|
|
+ * Copyright (c) 1996 by Internet Software Consortium.
|
|
+ *
|
|
+ * Permission to use, copy, modify, and distribute this software for any
|
|
+ * purpose with or without fee is hereby granted, provided that the above
|
|
+ * copyright notice and this permission notice appear in all copies.
|
|
+ *
|
|
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
|
|
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
|
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
|
|
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
|
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
|
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
|
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
|
+ * SOFTWARE.
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * Portions Copyright (c) 1995 by International Business Machines, Inc.
|
|
+ *
|
|
+ * International Business Machines, Inc. (hereinafter called IBM) grants
|
|
+ * permission under its copyrights to use, copy, modify, and distribute this
|
|
+ * Software with or without fee, provided that the above copyright notice and
|
|
+ * all paragraphs of this notice appear in all copies, and that the name of IBM
|
|
+ * not be used in connection with the marketing of any product incorporating
|
|
+ * the Software or modifications thereof, without specific, written prior
|
|
+ * permission.
|
|
+ *
|
|
+ * To the extent it has a right to do so, IBM grants an immunity from suit
|
|
+ * under its patents, if any, for the use, sale or manufacture of products to
|
|
+ * the extent that such products are used for performing Domain Name System
|
|
+ * dynamic updates in TCP/IP networks by means of the Software. No immunity is
|
|
+ * granted for any product per se or for any other function of any product.
|
|
+ *
|
|
+ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
|
|
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
|
+ * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
|
|
+ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
|
|
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
|
|
+ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
|
+ */
|
|
+
|
|
+#include <sys/cdefs.h>
|
|
+#if defined(LIBC_SCCS) && !defined(lint)
|
|
+__RCSID("$NetBSD: base64.c,v 1.8 2002/11/11 01:15:17 thorpej Exp $");
|
|
+#endif /* LIBC_SCCS and not lint */
|
|
+
|
|
+#include <sys/types.h>
|
|
+#include <sys/param.h>
|
|
+#include <sys/socket.h>
|
|
+#include <netinet/in.h>
|
|
+#include <arpa/inet.h>
|
|
+#include "arpa_nameser.h"
|
|
+
|
|
+#include <assert.h>
|
|
+#include <ctype.h>
|
|
+#ifdef ANDROID_CHANGES
|
|
+#include "resolv_private.h"
|
|
+#else
|
|
+#include <resolv.h>
|
|
+#endif
|
|
+#include <stdio.h>
|
|
+
|
|
+#include <stdlib.h>
|
|
+#include <string.h>
|
|
+
|
|
+static const char Base64[] =
|
|
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
+static const char Pad64 = '=';
|
|
+
|
|
+/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
|
|
+ The following encoding technique is taken from RFC 1521 by Borenstein
|
|
+ and Freed. It is reproduced here in a slightly edited form for
|
|
+ convenience.
|
|
+
|
|
+ A 65-character subset of US-ASCII is used, enabling 6 bits to be
|
|
+ represented per printable character. (The extra 65th character, "=",
|
|
+ is used to signify a special processing function.)
|
|
+
|
|
+ The encoding process represents 24-bit groups of input bits as output
|
|
+ strings of 4 encoded characters. Proceeding from left to right, a
|
|
+ 24-bit input group is formed by concatenating 3 8-bit input groups.
|
|
+ These 24 bits are then treated as 4 concatenated 6-bit groups, each
|
|
+ of which is translated into a single digit in the base64 alphabet.
|
|
+
|
|
+ Each 6-bit group is used as an index into an array of 64 printable
|
|
+ characters. The character referenced by the index is placed in the
|
|
+ output string.
|
|
+
|
|
+ Table 1: The Base64 Alphabet
|
|
+
|
|
+ Value Encoding Value Encoding Value Encoding Value Encoding
|
|
+ 0 A 17 R 34 i 51 z
|
|
+ 1 B 18 S 35 j 52 0
|
|
+ 2 C 19 T 36 k 53 1
|
|
+ 3 D 20 U 37 l 54 2
|
|
+ 4 E 21 V 38 m 55 3
|
|
+ 5 F 22 W 39 n 56 4
|
|
+ 6 G 23 X 40 o 57 5
|
|
+ 7 H 24 Y 41 p 58 6
|
|
+ 8 I 25 Z 42 q 59 7
|
|
+ 9 J 26 a 43 r 60 8
|
|
+ 10 K 27 b 44 s 61 9
|
|
+ 11 L 28 c 45 t 62 +
|
|
+ 12 M 29 d 46 u 63 /
|
|
+ 13 N 30 e 47 v
|
|
+ 14 O 31 f 48 w (pad) =
|
|
+ 15 P 32 g 49 x
|
|
+ 16 Q 33 h 50 y
|
|
+
|
|
+ Special processing is performed if fewer than 24 bits are available
|
|
+ at the end of the data being encoded. A full encoding quantum is
|
|
+ always completed at the end of a quantity. When fewer than 24 input
|
|
+ bits are available in an input group, zero bits are added (on the
|
|
+ right) to form an integral number of 6-bit groups. Padding at the
|
|
+ end of the data is performed using the '=' character.
|
|
+
|
|
+ Since all base64 input is an integral number of octets, only the
|
|
+ -------------------------------------------------
|
|
+ following cases can arise:
|
|
+
|
|
+ (1) the final quantum of encoding input is an integral
|
|
+ multiple of 24 bits; here, the final unit of encoded
|
|
+ output will be an integral multiple of 4 characters
|
|
+ with no "=" padding,
|
|
+ (2) the final quantum of encoding input is exactly 8 bits;
|
|
+ here, the final unit of encoded output will be two
|
|
+ characters followed by two "=" padding characters, or
|
|
+ (3) the final quantum of encoding input is exactly 16 bits;
|
|
+ here, the final unit of encoded output will be three
|
|
+ characters followed by one "=" padding character.
|
|
+ */
|
|
+
|
|
+int
|
|
+b64_ntop(src, srclength, target, targsize)
|
|
+ u_char const *src;
|
|
+ size_t srclength;
|
|
+ char *target;
|
|
+ size_t targsize;
|
|
+{
|
|
+ size_t datalength = 0;
|
|
+ u_char input[3] = { 0, 0, 0 }; /* make compiler happy */
|
|
+ u_char output[4];
|
|
+ size_t i;
|
|
+
|
|
+ assert(src != NULL);
|
|
+ assert(target != NULL);
|
|
+
|
|
+ while (2 < srclength) {
|
|
+ input[0] = *src++;
|
|
+ input[1] = *src++;
|
|
+ input[2] = *src++;
|
|
+ srclength -= 3;
|
|
+
|
|
+ output[0] = (u_int32_t)input[0] >> 2;
|
|
+ output[1] = ((u_int32_t)(input[0] & 0x03) << 4) +
|
|
+ ((u_int32_t)input[1] >> 4);
|
|
+ output[2] = ((u_int32_t)(input[1] & 0x0f) << 2) +
|
|
+ ((u_int32_t)input[2] >> 6);
|
|
+ output[3] = input[2] & 0x3f;
|
|
+ assert(output[0] < 64);
|
|
+ assert(output[1] < 64);
|
|
+ assert(output[2] < 64);
|
|
+ assert(output[3] < 64);
|
|
+
|
|
+ if (datalength + 4 > targsize)
|
|
+ return (-1);
|
|
+ target[datalength++] = Base64[output[0]];
|
|
+ target[datalength++] = Base64[output[1]];
|
|
+ target[datalength++] = Base64[output[2]];
|
|
+ target[datalength++] = Base64[output[3]];
|
|
+ }
|
|
+
|
|
+ /* Now we worry about padding. */
|
|
+ if (0 != srclength) {
|
|
+ /* Get what's left. */
|
|
+ input[0] = input[1] = input[2] = '\0';
|
|
+ for (i = 0; i < srclength; i++)
|
|
+ input[i] = *src++;
|
|
+
|
|
+ output[0] = (u_int32_t)input[0] >> 2;
|
|
+ output[1] = ((u_int32_t)(input[0] & 0x03) << 4) +
|
|
+ ((u_int32_t)input[1] >> 4);
|
|
+ output[2] = ((u_int32_t)(input[1] & 0x0f) << 2) +
|
|
+ ((u_int32_t)input[2] >> 6);
|
|
+ assert(output[0] < 64);
|
|
+ assert(output[1] < 64);
|
|
+ assert(output[2] < 64);
|
|
+
|
|
+ if (datalength + 4 > targsize)
|
|
+ return (-1);
|
|
+ target[datalength++] = Base64[output[0]];
|
|
+ target[datalength++] = Base64[output[1]];
|
|
+ if (srclength == 1)
|
|
+ target[datalength++] = Pad64;
|
|
+ else
|
|
+ target[datalength++] = Base64[output[2]];
|
|
+ target[datalength++] = Pad64;
|
|
+ }
|
|
+ if (datalength >= targsize)
|
|
+ return (-1);
|
|
+ target[datalength] = '\0'; /* Returned value doesn't count \0. */
|
|
+ return (datalength);
|
|
+}
|
|
+
|
|
+/* skips all whitespace anywhere.
|
|
+ converts characters, four at a time, starting at (or after)
|
|
+ src from base - 64 numbers into three 8 bit bytes in the target area.
|
|
+ it returns the number of data bytes stored at the target, or -1 on error.
|
|
+ */
|
|
+
|
|
+int
|
|
+b64_pton(src, target, targsize)
|
|
+ char const *src;
|
|
+ u_char *target;
|
|
+ size_t targsize;
|
|
+{
|
|
+ size_t tarindex;
|
|
+ int state, ch;
|
|
+ char *pos;
|
|
+
|
|
+ assert(src != NULL);
|
|
+ assert(target != NULL);
|
|
+
|
|
+ state = 0;
|
|
+ tarindex = 0;
|
|
+
|
|
+ while ((ch = (u_char) *src++) != '\0') {
|
|
+ if (isspace(ch)) /* Skip whitespace anywhere. */
|
|
+ continue;
|
|
+
|
|
+ if (ch == Pad64)
|
|
+ break;
|
|
+
|
|
+ pos = strchr(Base64, ch);
|
|
+ if (pos == 0) /* A non-base64 character. */
|
|
+ return (-1);
|
|
+
|
|
+ switch (state) {
|
|
+ case 0:
|
|
+ if (target) {
|
|
+ if (tarindex >= targsize)
|
|
+ return (-1);
|
|
+ target[tarindex] = (pos - Base64) << 2;
|
|
+ }
|
|
+ state = 1;
|
|
+ break;
|
|
+ case 1:
|
|
+ if (target) {
|
|
+ if (tarindex + 1 >= targsize)
|
|
+ return (-1);
|
|
+ target[tarindex] |=
|
|
+ (u_int32_t)(pos - Base64) >> 4;
|
|
+ target[tarindex+1] = ((pos - Base64) & 0x0f)
|
|
+ << 4 ;
|
|
+ }
|
|
+ tarindex++;
|
|
+ state = 2;
|
|
+ break;
|
|
+ case 2:
|
|
+ if (target) {
|
|
+ if (tarindex + 1 >= targsize)
|
|
+ return (-1);
|
|
+ target[tarindex] |=
|
|
+ (u_int32_t)(pos - Base64) >> 2;
|
|
+ target[tarindex+1] = ((pos - Base64) & 0x03)
|
|
+ << 6;
|
|
+ }
|
|
+ tarindex++;
|
|
+ state = 3;
|
|
+ break;
|
|
+ case 3:
|
|
+ if (target) {
|
|
+ if (tarindex >= targsize)
|
|
+ return (-1);
|
|
+ target[tarindex] |= (pos - Base64);
|
|
+ }
|
|
+ tarindex++;
|
|
+ state = 0;
|
|
+ break;
|
|
+ default:
|
|
+ abort();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * We are done decoding Base-64 chars. Let's see if we ended
|
|
+ * on a byte boundary, and/or with erroneous trailing characters.
|
|
+ */
|
|
+
|
|
+ if (ch == Pad64) { /* We got a pad char. */
|
|
+ ch = *src++; /* Skip it, get next. */
|
|
+ switch (state) {
|
|
+ case 0: /* Invalid = in first position */
|
|
+ case 1: /* Invalid = in second position */
|
|
+ return (-1);
|
|
+
|
|
+ case 2: /* Valid, means one byte of info */
|
|
+ /* Skip any number of spaces. */
|
|
+ for (; ch != '\0'; ch = (u_char) *src++)
|
|
+ if (!isspace(ch))
|
|
+ break;
|
|
+ /* Make sure there is another trailing = sign. */
|
|
+ if (ch != Pad64)
|
|
+ return (-1);
|
|
+ ch = *src++; /* Skip the = */
|
|
+ /* Fall through to "single trailing =" case. */
|
|
+ /* FALLTHROUGH */
|
|
+
|
|
+ case 3: /* Valid, means two bytes of info */
|
|
+ /*
|
|
+ * We know this char is an =. Is there anything but
|
|
+ * whitespace after it?
|
|
+ */
|
|
+ for (; ch != '\0'; ch = (u_char) *src++)
|
|
+ if (!isspace(ch))
|
|
+ return (-1);
|
|
+
|
|
+ /*
|
|
+ * Now make sure for cases 2 and 3 that the "extra"
|
|
+ * bits that slopped past the last full byte were
|
|
+ * zeros. If we don't check them, they become a
|
|
+ * subliminal channel.
|
|
+ */
|
|
+ if (target && target[tarindex] != 0)
|
|
+ return (-1);
|
|
+ }
|
|
+ } else {
|
|
+ /*
|
|
+ * We ended by seeing the end of the string. Make sure we
|
|
+ * have no partial bytes lying around.
|
|
+ */
|
|
+ if (state != 0)
|
|
+ return (-1);
|
|
+ }
|
|
+
|
|
+ return (tarindex);
|
|
+}
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/commandline.c
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/commandline.c 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,1743 @@
|
|
+/*
|
|
+ * Copyright (C) 2007 The Android Open Source Project
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
+ * you may not use this file except in compliance with the License.
|
|
+ * You may obtain a copy of the License at
|
|
+ *
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
+ *
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+ * See the License for the specific language governing permissions and
|
|
+ * limitations under the License.
|
|
+ */
|
|
+
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+#include <string.h>
|
|
+#include <errno.h>
|
|
+#include <unistd.h>
|
|
+#include <limits.h>
|
|
+#include <stdarg.h>
|
|
+#include <sys/types.h>
|
|
+#include <sys/stat.h>
|
|
+#include <ctype.h>
|
|
+#include <assert.h>
|
|
+
|
|
+#include "sysdeps.h"
|
|
+
|
|
+#ifdef HAVE_TERMIO_H
|
|
+#include <termios.h>
|
|
+#endif
|
|
+
|
|
+#define TRACE_TAG TRACE_ADB
|
|
+#include "adb.h"
|
|
+#include "adb_client.h"
|
|
+#include "file_sync_service.h"
|
|
+
|
|
+static int do_cmd(transport_type ttype, char* serial, char *cmd, ...);
|
|
+
|
|
+void get_my_path(char *s, size_t maxLen);
|
|
+int find_sync_dirs(const char *srcarg,
|
|
+ char **android_srcdir_out, char **data_srcdir_out);
|
|
+int install_app(transport_type transport, char* serial, int argc, char** argv);
|
|
+int uninstall_app(transport_type transport, char* serial, int argc, char** argv);
|
|
+
|
|
+static const char *gProductOutPath = NULL;
|
|
+extern int gListenAll;
|
|
+
|
|
+static char *product_file(const char *extra)
|
|
+{
|
|
+ int n;
|
|
+ char *x;
|
|
+
|
|
+ if (gProductOutPath == NULL) {
|
|
+ fprintf(stderr, "adb: Product directory not specified; "
|
|
+ "use -p or define ANDROID_PRODUCT_OUT\n");
|
|
+ exit(1);
|
|
+ }
|
|
+
|
|
+ n = strlen(gProductOutPath) + strlen(extra) + 2;
|
|
+ x = malloc(n);
|
|
+ if (x == 0) {
|
|
+ fprintf(stderr, "adb: Out of memory (product_file())\n");
|
|
+ exit(1);
|
|
+ }
|
|
+
|
|
+ snprintf(x, (size_t)n, "%s" OS_PATH_SEPARATOR_STR "%s", gProductOutPath, extra);
|
|
+ return x;
|
|
+}
|
|
+
|
|
+void version(FILE * out) {
|
|
+ fprintf(out, "Android Debug Bridge version %d.%d.%d\n",
|
|
+ ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION);
|
|
+}
|
|
+
|
|
+void help()
|
|
+{
|
|
+ version(stderr);
|
|
+
|
|
+ fprintf(stderr,
|
|
+ "\n"
|
|
+ " -a - directs adb to listen on all interfaces for a connection\n"
|
|
+ " -d - directs command to the only connected USB device\n"
|
|
+ " returns an error if more than one USB device is present.\n"
|
|
+ " -e - directs command to the only running emulator.\n"
|
|
+ " returns an error if more than one emulator is running.\n"
|
|
+ " -s <specific device> - directs command to the device or emulator with the given\n"
|
|
+ " serial number or qualifier. Overrides ANDROID_SERIAL\n"
|
|
+ " environment variable.\n"
|
|
+ " -p <product name or path> - simple product name like 'sooner', or\n"
|
|
+ " a relative/absolute path to a product\n"
|
|
+ " out directory like 'out/target/product/sooner'.\n"
|
|
+ " If -p is not specified, the ANDROID_PRODUCT_OUT\n"
|
|
+ " environment variable is used, which must\n"
|
|
+ " be an absolute path.\n"
|
|
+ " -H - Name of adb server host (default: localhost)\n"
|
|
+ " -P - Port of adb server (default: 5037)\n"
|
|
+ " devices [-l] - list all connected devices\n"
|
|
+ " ('-l' will also list device qualifiers)\n"
|
|
+ " connect <host>[:<port>] - connect to a device via TCP/IP\n"
|
|
+ " Port 5555 is used by default if no port number is specified.\n"
|
|
+ " disconnect [<host>[:<port>]] - disconnect from a TCP/IP device.\n"
|
|
+ " Port 5555 is used by default if no port number is specified.\n"
|
|
+ " Using this command with no additional arguments\n"
|
|
+ " will disconnect from all connected TCP/IP devices.\n"
|
|
+ "\n"
|
|
+ "device commands:\n"
|
|
+ " adb push <local> <remote> - copy file/dir to device\n"
|
|
+ " adb pull <remote> [<local>] - copy file/dir from device\n"
|
|
+ " adb sync [ <directory> ] - copy host->device only if changed\n"
|
|
+ " (-l means list but don't copy)\n"
|
|
+ " (see 'adb help all')\n"
|
|
+ " adb shell - run remote shell interactively\n"
|
|
+ " adb shell <command> - run remote shell command\n"
|
|
+ " adb emu <command> - run emulator console command\n"
|
|
+ " adb logcat [ <filter-spec> ] - View device log\n"
|
|
+ " adb forward --list - list all forward socket connections.\n"
|
|
+ " the format is a list of lines with the following format:\n"
|
|
+ " <serial> \" \" <local> \" \" <remote> \"\\n\"\n"
|
|
+ " adb forward <local> <remote> - forward socket connections\n"
|
|
+ " forward specs are one of: \n"
|
|
+ " tcp:<port>\n"
|
|
+ " localabstract:<unix domain socket name>\n"
|
|
+ " localreserved:<unix domain socket name>\n"
|
|
+ " localfilesystem:<unix domain socket name>\n"
|
|
+ " dev:<character device name>\n"
|
|
+ " jdwp:<process pid> (remote only)\n"
|
|
+ " adb forward --no-rebind <local> <remote>\n"
|
|
+ " - same as 'adb forward <local> <remote>' but fails\n"
|
|
+ " if <local> is already forwarded\n"
|
|
+ " adb forward --remove <local> - remove a specific forward socket connection\n"
|
|
+ " adb forward --remove-all - remove all forward socket connections\n"
|
|
+ " adb jdwp - list PIDs of processes hosting a JDWP transport\n"
|
|
+ " adb install [-l] [-r] [-s] [--algo <algorithm name> --key <hex-encoded key> --iv <hex-encoded iv>] <file>\n"
|
|
+ " - push this package file to the device and install it\n"
|
|
+ " ('-l' means forward-lock the app)\n"
|
|
+ " ('-r' means reinstall the app, keeping its data)\n"
|
|
+ " ('-s' means install on SD card instead of internal storage)\n"
|
|
+ " ('--algo', '--key', and '--iv' mean the file is encrypted already)\n"
|
|
+ " adb uninstall [-k] <package> - remove this app package from the device\n"
|
|
+ " ('-k' means keep the data and cache directories)\n"
|
|
+ " adb bugreport - return all information from the device\n"
|
|
+ " that should be included in a bug report.\n"
|
|
+ "\n"
|
|
+ " adb backup [-f <file>] [-apk|-noapk] [-shared|-noshared] [-all] [-system|-nosystem] [<packages...>]\n"
|
|
+ " - write an archive of the device's data to <file>.\n"
|
|
+ " If no -f option is supplied then the data is written\n"
|
|
+ " to \"backup.ab\" in the current directory.\n"
|
|
+ " (-apk|-noapk enable/disable backup of the .apks themselves\n"
|
|
+ " in the archive; the default is noapk.)\n"
|
|
+ " (-shared|-noshared enable/disable backup of the device's\n"
|
|
+ " shared storage / SD card contents; the default is noshared.)\n"
|
|
+ " (-all means to back up all installed applications)\n"
|
|
+ " (-system|-nosystem toggles whether -all automatically includes\n"
|
|
+ " system applications; the default is to include system apps)\n"
|
|
+ " (<packages...> is the list of applications to be backed up. If\n"
|
|
+ " the -all or -shared flags are passed, then the package\n"
|
|
+ " list is optional. Applications explicitly given on the\n"
|
|
+ " command line will be included even if -nosystem would\n"
|
|
+ " ordinarily cause them to be omitted.)\n"
|
|
+ "\n"
|
|
+ " adb restore <file> - restore device contents from the <file> backup archive\n"
|
|
+ "\n"
|
|
+ " adb help - show this help message\n"
|
|
+ " adb version - show version num\n"
|
|
+ "\n"
|
|
+ "scripting:\n"
|
|
+ " adb wait-for-device - block until device is online\n"
|
|
+ " adb start-server - ensure that there is a server running\n"
|
|
+ " adb kill-server - kill the server if it is running\n"
|
|
+ " adb get-state - prints: offline | bootloader | device\n"
|
|
+ " adb get-serialno - prints: <serial-number>\n"
|
|
+ " adb get-devpath - prints: <device-path>\n"
|
|
+ " adb status-window - continuously print device status for a specified device\n"
|
|
+ " adb remount - remounts the /system partition on the device read-write\n"
|
|
+ " adb reboot [bootloader|recovery] - reboots the device, optionally into the bootloader or recovery program\n"
|
|
+ " adb reboot-bootloader - reboots the device into the bootloader\n"
|
|
+ " adb root - restarts the adbd daemon with root permissions\n"
|
|
+ " adb usb - restarts the adbd daemon listening on USB\n"
|
|
+ " adb tcpip <port> - restarts the adbd daemon listening on TCP on the specified port"
|
|
+ "\n"
|
|
+ "networking:\n"
|
|
+ " adb ppp <tty> [parameters] - Run PPP over USB.\n"
|
|
+ " Note: you should not automatically start a PPP connection.\n"
|
|
+ " <tty> refers to the tty for PPP stream. Eg. dev:/dev/omap_csmi_tty1\n"
|
|
+ " [parameters] - Eg. defaultroute debug dump local notty usepeerdns\n"
|
|
+ "\n"
|
|
+ "adb sync notes: adb sync [ <directory> ]\n"
|
|
+ " <localdir> can be interpreted in several ways:\n"
|
|
+ "\n"
|
|
+ " - If <directory> is not specified, both /system and /data partitions will be updated.\n"
|
|
+ "\n"
|
|
+ " - If it is \"system\" or \"data\", only the corresponding partition\n"
|
|
+ " is updated.\n"
|
|
+ "\n"
|
|
+ "environmental variables:\n"
|
|
+ " ADB_TRACE - Print debug information. A comma separated list of the following values\n"
|
|
+ " 1 or all, adb, sockets, packets, rwx, usb, sync, sysdeps, transport, jdwp\n"
|
|
+ " ANDROID_SERIAL - The serial number to connect to. -s takes priority over this if given.\n"
|
|
+ " ANDROID_LOG_TAGS - When used with the logcat option, only these debug tags are printed.\n"
|
|
+ );
|
|
+}
|
|
+
|
|
+int usage()
|
|
+{
|
|
+ help();
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+#ifdef HAVE_TERMIO_H
|
|
+static struct termios tio_save;
|
|
+
|
|
+static void stdin_raw_init(int fd)
|
|
+{
|
|
+ struct termios tio;
|
|
+
|
|
+ if(tcgetattr(fd, &tio)) return;
|
|
+ if(tcgetattr(fd, &tio_save)) return;
|
|
+
|
|
+ tio.c_lflag = 0; /* disable CANON, ECHO*, etc */
|
|
+
|
|
+ /* no timeout but request at least one character per read */
|
|
+ tio.c_cc[VTIME] = 0;
|
|
+ tio.c_cc[VMIN] = 1;
|
|
+
|
|
+ tcsetattr(fd, TCSANOW, &tio);
|
|
+ tcflush(fd, TCIFLUSH);
|
|
+}
|
|
+
|
|
+static void stdin_raw_restore(int fd)
|
|
+{
|
|
+ tcsetattr(fd, TCSANOW, &tio_save);
|
|
+ tcflush(fd, TCIFLUSH);
|
|
+}
|
|
+#endif
|
|
+
|
|
+static void read_and_dump(int fd)
|
|
+{
|
|
+ char buf[4096];
|
|
+ int len;
|
|
+
|
|
+ while(fd >= 0) {
|
|
+ D("read_and_dump(): pre adb_read(fd=%d)\n", fd);
|
|
+ len = adb_read(fd, buf, 4096);
|
|
+ D("read_and_dump(): post adb_read(fd=%d): len=%d\n", fd, len);
|
|
+ if(len == 0) {
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if(len < 0) {
|
|
+ if(errno == EINTR) continue;
|
|
+ break;
|
|
+ }
|
|
+ fwrite(buf, 1, len, stdout);
|
|
+ fflush(stdout);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void copy_to_file(int inFd, int outFd) {
|
|
+ const size_t BUFSIZE = 32 * 1024;
|
|
+ char* buf = (char*) malloc(BUFSIZE);
|
|
+ int len;
|
|
+ long total = 0;
|
|
+
|
|
+ D("copy_to_file(%d -> %d)\n", inFd, outFd);
|
|
+ for (;;) {
|
|
+ len = adb_read(inFd, buf, BUFSIZE);
|
|
+ if (len == 0) {
|
|
+ D("copy_to_file() : read 0 bytes; exiting\n");
|
|
+ break;
|
|
+ }
|
|
+ if (len < 0) {
|
|
+ if (errno == EINTR) {
|
|
+ D("copy_to_file() : EINTR, retrying\n");
|
|
+ continue;
|
|
+ }
|
|
+ D("copy_to_file() : error %d\n", errno);
|
|
+ break;
|
|
+ }
|
|
+ adb_write(outFd, buf, len);
|
|
+ total += len;
|
|
+ }
|
|
+ D("copy_to_file() finished after %lu bytes\n", total);
|
|
+ free(buf);
|
|
+}
|
|
+
|
|
+static void *stdin_read_thread(void *x)
|
|
+{
|
|
+ int fd, fdi;
|
|
+ unsigned char buf[1024];
|
|
+ int r, n;
|
|
+ int state = 0;
|
|
+
|
|
+ int *fds = (int*) x;
|
|
+ fd = fds[0];
|
|
+ fdi = fds[1];
|
|
+ free(fds);
|
|
+
|
|
+ for(;;) {
|
|
+ /* fdi is really the client's stdin, so use read, not adb_read here */
|
|
+ D("stdin_read_thread(): pre unix_read(fdi=%d,...)\n", fdi);
|
|
+ r = unix_read(fdi, buf, 1024);
|
|
+ D("stdin_read_thread(): post unix_read(fdi=%d,...)\n", fdi);
|
|
+ if(r == 0) break;
|
|
+ if(r < 0) {
|
|
+ if(errno == EINTR) continue;
|
|
+ break;
|
|
+ }
|
|
+ for(n = 0; n < r; n++){
|
|
+ switch(buf[n]) {
|
|
+ case '\n':
|
|
+ state = 1;
|
|
+ break;
|
|
+ case '\r':
|
|
+ state = 1;
|
|
+ break;
|
|
+ case '~':
|
|
+ if(state == 1) state++;
|
|
+ break;
|
|
+ case '.':
|
|
+ if(state == 2) {
|
|
+ fprintf(stderr,"\n* disconnect *\n");
|
|
+#ifdef HAVE_TERMIO_H
|
|
+ stdin_raw_restore(fdi);
|
|
+#endif
|
|
+ exit(0);
|
|
+ }
|
|
+ default:
|
|
+ state = 0;
|
|
+ }
|
|
+ }
|
|
+ r = adb_write(fd, buf, r);
|
|
+ if(r <= 0) {
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int interactive_shell(void)
|
|
+{
|
|
+ adb_thread_t thr;
|
|
+ int fdi, fd;
|
|
+ int *fds;
|
|
+
|
|
+ fd = adb_connect("shell:");
|
|
+ if(fd < 0) {
|
|
+ fprintf(stderr,"error: %s\n", adb_error());
|
|
+ return 1;
|
|
+ }
|
|
+ fdi = 0; //dup(0);
|
|
+
|
|
+ fds = malloc(sizeof(int) * 2);
|
|
+ fds[0] = fd;
|
|
+ fds[1] = fdi;
|
|
+
|
|
+#ifdef HAVE_TERMIO_H
|
|
+ stdin_raw_init(fdi);
|
|
+#endif
|
|
+ adb_thread_create(&thr, stdin_read_thread, fds);
|
|
+ read_and_dump(fd);
|
|
+#ifdef HAVE_TERMIO_H
|
|
+ stdin_raw_restore(fdi);
|
|
+#endif
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
+static void format_host_command(char* buffer, size_t buflen, const char* command, transport_type ttype, const char* serial)
|
|
+{
|
|
+ if (serial) {
|
|
+ snprintf(buffer, buflen, "host-serial:%s:%s", serial, command);
|
|
+ } else {
|
|
+ const char* prefix = "host";
|
|
+ if (ttype == kTransportUsb)
|
|
+ prefix = "host-usb";
|
|
+ else if (ttype == kTransportLocal)
|
|
+ prefix = "host-local";
|
|
+
|
|
+ snprintf(buffer, buflen, "%s:%s", prefix, command);
|
|
+ }
|
|
+}
|
|
+
|
|
+int adb_download_buffer(const char *service, const void* data, int sz,
|
|
+ unsigned progress)
|
|
+{
|
|
+ char buf[4096];
|
|
+ unsigned total;
|
|
+ int fd;
|
|
+ const unsigned char *ptr;
|
|
+
|
|
+ sprintf(buf,"%s:%d", service, sz);
|
|
+ fd = adb_connect(buf);
|
|
+ if(fd < 0) {
|
|
+ fprintf(stderr,"error: %s\n", adb_error());
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ int opt = CHUNK_SIZE;
|
|
+ opt = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt));
|
|
+
|
|
+ total = sz;
|
|
+ ptr = data;
|
|
+
|
|
+ if(progress) {
|
|
+ char *x = strrchr(service, ':');
|
|
+ if(x) service = x + 1;
|
|
+ }
|
|
+
|
|
+ while(sz > 0) {
|
|
+ unsigned xfer = (sz > CHUNK_SIZE) ? CHUNK_SIZE : sz;
|
|
+ if(writex(fd, ptr, xfer)) {
|
|
+ adb_status(fd);
|
|
+ fprintf(stderr,"* failed to write data '%s' *\n", adb_error());
|
|
+ return -1;
|
|
+ }
|
|
+ sz -= xfer;
|
|
+ ptr += xfer;
|
|
+ if(progress) {
|
|
+ printf("sending: '%s' %4d%% \r", service, (int)(100LL - ((100LL * sz) / (total))));
|
|
+ fflush(stdout);
|
|
+ }
|
|
+ }
|
|
+ if(progress) {
|
|
+ printf("\n");
|
|
+ }
|
|
+
|
|
+ if(readx(fd, buf, 4)){
|
|
+ fprintf(stderr,"* error reading response *\n");
|
|
+ adb_close(fd);
|
|
+ return -1;
|
|
+ }
|
|
+ if(memcmp(buf, "OKAY", 4)) {
|
|
+ buf[4] = 0;
|
|
+ fprintf(stderr,"* error response '%s' *\n", buf);
|
|
+ adb_close(fd);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ adb_close(fd);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
+int adb_download(const char *service, const char *fn, unsigned progress)
|
|
+{
|
|
+ void *data;
|
|
+ unsigned sz;
|
|
+
|
|
+ data = load_file(fn, &sz);
|
|
+ if(data == 0) {
|
|
+ fprintf(stderr,"* cannot read '%s' *\n", service);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ int status = adb_download_buffer(service, data, sz, progress);
|
|
+ free(data);
|
|
+ return status;
|
|
+}
|
|
+
|
|
+static void status_window(transport_type ttype, const char* serial)
|
|
+{
|
|
+ char command[4096];
|
|
+ char *state = 0;
|
|
+ char *laststate = 0;
|
|
+
|
|
+ /* silence stderr */
|
|
+#ifdef _WIN32
|
|
+ /* XXX: TODO */
|
|
+#else
|
|
+ int fd;
|
|
+ fd = unix_open("/dev/null", O_WRONLY);
|
|
+ dup2(fd, 2);
|
|
+ adb_close(fd);
|
|
+#endif
|
|
+
|
|
+ format_host_command(command, sizeof command, "get-state", ttype, serial);
|
|
+
|
|
+ for(;;) {
|
|
+ adb_sleep_ms(250);
|
|
+
|
|
+ if(state) {
|
|
+ free(state);
|
|
+ state = 0;
|
|
+ }
|
|
+
|
|
+ state = adb_query(command);
|
|
+
|
|
+ if(state) {
|
|
+ if(laststate && !strcmp(state,laststate)){
|
|
+ continue;
|
|
+ } else {
|
|
+ if(laststate) free(laststate);
|
|
+ laststate = strdup(state);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ printf("%c[2J%c[2H", 27, 27);
|
|
+ printf("Android Debug Bridge\n");
|
|
+ printf("State: %s\n", state ? state : "offline");
|
|
+ fflush(stdout);
|
|
+ }
|
|
+}
|
|
+
|
|
+/** duplicate string and quote all \ " ( ) chars + space character. */
|
|
+static char *
|
|
+dupAndQuote(const char *s)
|
|
+{
|
|
+ const char *ts;
|
|
+ size_t alloc_len;
|
|
+ char *ret;
|
|
+ char *dest;
|
|
+
|
|
+ ts = s;
|
|
+
|
|
+ alloc_len = 0;
|
|
+
|
|
+ for( ;*ts != '\0'; ts++) {
|
|
+ alloc_len++;
|
|
+ if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
|
|
+ alloc_len++;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ ret = (char *)malloc(alloc_len + 1);
|
|
+
|
|
+ ts = s;
|
|
+ dest = ret;
|
|
+
|
|
+ for ( ;*ts != '\0'; ts++) {
|
|
+ if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
|
|
+ *dest++ = '\\';
|
|
+ }
|
|
+
|
|
+ *dest++ = *ts;
|
|
+ }
|
|
+
|
|
+ *dest++ = '\0';
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Run ppp in "notty" mode against a resource listed as the first parameter
|
|
+ * eg:
|
|
+ *
|
|
+ * ppp dev:/dev/omap_csmi_tty0 <ppp options>
|
|
+ *
|
|
+ */
|
|
+int ppp(int argc, char **argv)
|
|
+{
|
|
+#ifdef HAVE_WIN32_PROC
|
|
+ fprintf(stderr, "error: adb %s not implemented on Win32\n", argv[0]);
|
|
+ return -1;
|
|
+#else
|
|
+ char *adb_service_name;
|
|
+ pid_t pid;
|
|
+ int fd;
|
|
+
|
|
+ if (argc < 2) {
|
|
+ fprintf(stderr, "usage: adb %s <adb service name> [ppp opts]\n",
|
|
+ argv[0]);
|
|
+
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ adb_service_name = argv[1];
|
|
+
|
|
+ fd = adb_connect(adb_service_name);
|
|
+
|
|
+ if(fd < 0) {
|
|
+ fprintf(stderr,"Error: Could not open adb service: %s. Error: %s\n",
|
|
+ adb_service_name, adb_error());
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ pid = fork();
|
|
+
|
|
+ if (pid < 0) {
|
|
+ perror("from fork()");
|
|
+ return 1;
|
|
+ } else if (pid == 0) {
|
|
+ int err;
|
|
+ int i;
|
|
+ const char **ppp_args;
|
|
+
|
|
+ // copy args
|
|
+ ppp_args = (const char **) alloca(sizeof(char *) * argc + 1);
|
|
+ ppp_args[0] = "pppd";
|
|
+ for (i = 2 ; i < argc ; i++) {
|
|
+ //argv[2] and beyond become ppp_args[1] and beyond
|
|
+ ppp_args[i - 1] = argv[i];
|
|
+ }
|
|
+ ppp_args[i-1] = NULL;
|
|
+
|
|
+ // child side
|
|
+
|
|
+ dup2(fd, STDIN_FILENO);
|
|
+ dup2(fd, STDOUT_FILENO);
|
|
+ adb_close(STDERR_FILENO);
|
|
+ adb_close(fd);
|
|
+
|
|
+ err = execvp("pppd", (char * const *)ppp_args);
|
|
+
|
|
+ if (err < 0) {
|
|
+ perror("execing pppd");
|
|
+ }
|
|
+ exit(-1);
|
|
+ } else {
|
|
+ // parent side
|
|
+
|
|
+ adb_close(fd);
|
|
+ return 0;
|
|
+ }
|
|
+#endif /* !HAVE_WIN32_PROC */
|
|
+}
|
|
+
|
|
+static int send_shellcommand(transport_type transport, char* serial, char* buf)
|
|
+{
|
|
+ int fd, ret;
|
|
+
|
|
+ for(;;) {
|
|
+ fd = adb_connect(buf);
|
|
+ if(fd >= 0)
|
|
+ break;
|
|
+ fprintf(stderr,"- waiting for device -\n");
|
|
+ adb_sleep_ms(1000);
|
|
+ do_cmd(transport, serial, "wait-for-device", 0);
|
|
+ }
|
|
+
|
|
+ read_and_dump(fd);
|
|
+ ret = adb_close(fd);
|
|
+ if (ret)
|
|
+ perror("close");
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int logcat(transport_type transport, char* serial, int argc, char **argv)
|
|
+{
|
|
+ char buf[4096];
|
|
+
|
|
+ char *log_tags;
|
|
+ char *quoted_log_tags;
|
|
+
|
|
+ log_tags = getenv("ANDROID_LOG_TAGS");
|
|
+ quoted_log_tags = dupAndQuote(log_tags == NULL ? "" : log_tags);
|
|
+
|
|
+ snprintf(buf, sizeof(buf),
|
|
+ "shell:export ANDROID_LOG_TAGS=\"\%s\" ; exec logcat",
|
|
+ quoted_log_tags);
|
|
+
|
|
+ free(quoted_log_tags);
|
|
+
|
|
+ if (!strcmp(argv[0],"longcat")) {
|
|
+ strncat(buf, " -v long", sizeof(buf)-1);
|
|
+ }
|
|
+
|
|
+ argc -= 1;
|
|
+ argv += 1;
|
|
+ while(argc-- > 0) {
|
|
+ char *quoted;
|
|
+
|
|
+ quoted = dupAndQuote (*argv++);
|
|
+
|
|
+ strncat(buf, " ", sizeof(buf)-1);
|
|
+ strncat(buf, quoted, sizeof(buf)-1);
|
|
+ free(quoted);
|
|
+ }
|
|
+
|
|
+ send_shellcommand(transport, serial, buf);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int mkdirs(char *path)
|
|
+{
|
|
+ int ret;
|
|
+ char *x = path + 1;
|
|
+
|
|
+ for(;;) {
|
|
+ x = adb_dirstart(x);
|
|
+ if(x == 0) return 0;
|
|
+ *x = 0;
|
|
+ ret = adb_mkdir(path, 0775);
|
|
+ *x = OS_PATH_SEPARATOR;
|
|
+ if((ret < 0) && (errno != EEXIST)) {
|
|
+ return ret;
|
|
+ }
|
|
+ x++;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int backup(int argc, char** argv) {
|
|
+ char buf[4096];
|
|
+ char default_name[32];
|
|
+ const char* filename = strcpy(default_name, "./backup.ab");
|
|
+ int fd, outFd;
|
|
+ int i, j;
|
|
+
|
|
+ /* find, extract, and use any -f argument */
|
|
+ for (i = 1; i < argc; i++) {
|
|
+ if (!strcmp("-f", argv[i])) {
|
|
+ if (i == argc-1) {
|
|
+ fprintf(stderr, "adb: -f passed with no filename\n");
|
|
+ return usage();
|
|
+ }
|
|
+ filename = argv[i+1];
|
|
+ for (j = i+2; j <= argc; ) {
|
|
+ argv[i++] = argv[j++];
|
|
+ }
|
|
+ argc -= 2;
|
|
+ argv[argc] = NULL;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* bare "adb backup" or "adb backup -f filename" are not valid invocations */
|
|
+ if (argc < 2) return usage();
|
|
+
|
|
+ adb_unlink(filename);
|
|
+ mkdirs((char *)filename);
|
|
+ outFd = adb_creat(filename, 0640);
|
|
+ if (outFd < 0) {
|
|
+ fprintf(stderr, "adb: unable to open file %s\n", filename);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ snprintf(buf, sizeof(buf), "backup");
|
|
+ for (argc--, argv++; argc; argc--, argv++) {
|
|
+ strncat(buf, ":", sizeof(buf) - strlen(buf) - 1);
|
|
+ strncat(buf, argv[0], sizeof(buf) - strlen(buf) - 1);
|
|
+ }
|
|
+
|
|
+ D("backup. filename=%s buf=%s\n", filename, buf);
|
|
+ fd = adb_connect(buf);
|
|
+ if (fd < 0) {
|
|
+ fprintf(stderr, "adb: unable to connect for backup\n");
|
|
+ adb_close(outFd);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ printf("Now unlock your device and confirm the backup operation.\n");
|
|
+ copy_to_file(fd, outFd);
|
|
+
|
|
+ adb_close(fd);
|
|
+ adb_close(outFd);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int restore(int argc, char** argv) {
|
|
+ const char* filename;
|
|
+ int fd, tarFd;
|
|
+
|
|
+ if (argc != 2) return usage();
|
|
+
|
|
+ filename = argv[1];
|
|
+ tarFd = adb_open(filename, O_RDONLY);
|
|
+ if (tarFd < 0) {
|
|
+ fprintf(stderr, "adb: unable to open file %s\n", filename);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ fd = adb_connect("restore:");
|
|
+ if (fd < 0) {
|
|
+ fprintf(stderr, "adb: unable to connect for backup\n");
|
|
+ adb_close(tarFd);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ printf("Now unlock your device and confirm the restore operation.\n");
|
|
+ copy_to_file(tarFd, fd);
|
|
+
|
|
+ adb_close(fd);
|
|
+ adb_close(tarFd);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+#define SENTINEL_FILE "config" OS_PATH_SEPARATOR_STR "envsetup.make"
|
|
+static int top_works(const char *top)
|
|
+{
|
|
+ if (top != NULL && adb_is_absolute_host_path(top)) {
|
|
+ char path_buf[PATH_MAX];
|
|
+ snprintf(path_buf, sizeof(path_buf),
|
|
+ "%s" OS_PATH_SEPARATOR_STR SENTINEL_FILE, top);
|
|
+ return access(path_buf, F_OK) == 0;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static char *find_top_from(const char *indir, char path_buf[PATH_MAX])
|
|
+{
|
|
+ strcpy(path_buf, indir);
|
|
+ while (1) {
|
|
+ if (top_works(path_buf)) {
|
|
+ return path_buf;
|
|
+ }
|
|
+ char *s = adb_dirstop(path_buf);
|
|
+ if (s != NULL) {
|
|
+ *s = '\0';
|
|
+ } else {
|
|
+ path_buf[0] = '\0';
|
|
+ return NULL;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+static char *find_top(char path_buf[PATH_MAX])
|
|
+{
|
|
+ char *top = getenv("ANDROID_BUILD_TOP");
|
|
+ if (top != NULL && top[0] != '\0') {
|
|
+ if (!top_works(top)) {
|
|
+ fprintf(stderr, "adb: bad ANDROID_BUILD_TOP value \"%s\"\n", top);
|
|
+ return NULL;
|
|
+ }
|
|
+ } else {
|
|
+ top = getenv("TOP");
|
|
+ if (top != NULL && top[0] != '\0') {
|
|
+ if (!top_works(top)) {
|
|
+ fprintf(stderr, "adb: bad TOP value \"%s\"\n", top);
|
|
+ return NULL;
|
|
+ }
|
|
+ } else {
|
|
+ top = NULL;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (top != NULL) {
|
|
+ /* The environment pointed to a top directory that works.
|
|
+ */
|
|
+ strcpy(path_buf, top);
|
|
+ return path_buf;
|
|
+ }
|
|
+
|
|
+ /* The environment didn't help. Walk up the tree from the CWD
|
|
+ * to see if we can find the top.
|
|
+ */
|
|
+ char dir[PATH_MAX];
|
|
+ top = find_top_from(getcwd(dir, sizeof(dir)), path_buf);
|
|
+ if (top == NULL) {
|
|
+ /* If the CWD isn't under a good-looking top, see if the
|
|
+ * executable is.
|
|
+ */
|
|
+ get_my_path(dir, PATH_MAX);
|
|
+ top = find_top_from(dir, path_buf);
|
|
+ }
|
|
+ return top;
|
|
+}
|
|
+
|
|
+/* <hint> may be:
|
|
+ * - A simple product name
|
|
+ * e.g., "sooner"
|
|
+TODO: debug? sooner-debug, sooner:debug?
|
|
+ * - A relative path from the CWD to the ANDROID_PRODUCT_OUT dir
|
|
+ * e.g., "out/target/product/sooner"
|
|
+ * - An absolute path to the PRODUCT_OUT dir
|
|
+ * e.g., "/src/device/out/target/product/sooner"
|
|
+ *
|
|
+ * Given <hint>, try to construct an absolute path to the
|
|
+ * ANDROID_PRODUCT_OUT dir.
|
|
+ */
|
|
+static const char *find_product_out_path(const char *hint)
|
|
+{
|
|
+ static char path_buf[PATH_MAX];
|
|
+
|
|
+ if (hint == NULL || hint[0] == '\0') {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ /* If it's already absolute, don't bother doing any work.
|
|
+ */
|
|
+ if (adb_is_absolute_host_path(hint)) {
|
|
+ strcpy(path_buf, hint);
|
|
+ return path_buf;
|
|
+ }
|
|
+
|
|
+ /* If there are any slashes in it, assume it's a relative path;
|
|
+ * make it absolute.
|
|
+ */
|
|
+ if (adb_dirstart(hint) != NULL) {
|
|
+ if (getcwd(path_buf, sizeof(path_buf)) == NULL) {
|
|
+ fprintf(stderr, "adb: Couldn't get CWD: %s\n", strerror(errno));
|
|
+ return NULL;
|
|
+ }
|
|
+ if (strlen(path_buf) + 1 + strlen(hint) >= sizeof(path_buf)) {
|
|
+ fprintf(stderr, "adb: Couldn't assemble path\n");
|
|
+ return NULL;
|
|
+ }
|
|
+ strcat(path_buf, OS_PATH_SEPARATOR_STR);
|
|
+ strcat(path_buf, hint);
|
|
+ return path_buf;
|
|
+ }
|
|
+
|
|
+ /* It's a string without any slashes. Try to do something with it.
|
|
+ *
|
|
+ * Try to find the root of the build tree, and build a PRODUCT_OUT
|
|
+ * path from there.
|
|
+ */
|
|
+ char top_buf[PATH_MAX];
|
|
+ const char *top = find_top(top_buf);
|
|
+ if (top == NULL) {
|
|
+ fprintf(stderr, "adb: Couldn't find top of build tree\n");
|
|
+ return NULL;
|
|
+ }
|
|
+//TODO: if we have a way to indicate debug, look in out/debug/target/...
|
|
+ snprintf(path_buf, sizeof(path_buf),
|
|
+ "%s" OS_PATH_SEPARATOR_STR
|
|
+ "out" OS_PATH_SEPARATOR_STR
|
|
+ "target" OS_PATH_SEPARATOR_STR
|
|
+ "product" OS_PATH_SEPARATOR_STR
|
|
+ "%s", top_buf, hint);
|
|
+ if (access(path_buf, F_OK) < 0) {
|
|
+ fprintf(stderr, "adb: Couldn't find a product dir "
|
|
+ "based on \"-p %s\"; \"%s\" doesn't exist\n", hint, path_buf);
|
|
+ return NULL;
|
|
+ }
|
|
+ return path_buf;
|
|
+}
|
|
+
|
|
+int adb_commandline(int argc, char **argv)
|
|
+{
|
|
+ char buf[4096];
|
|
+ int no_daemon = 0;
|
|
+ int is_daemon = 0;
|
|
+ int is_server = 0;
|
|
+ int persist = 0;
|
|
+ int r;
|
|
+ int quote;
|
|
+ transport_type ttype = kTransportAny;
|
|
+ char* serial = NULL;
|
|
+ char* server_port_str = NULL;
|
|
+
|
|
+ /* If defined, this should be an absolute path to
|
|
+ * the directory containing all of the various system images
|
|
+ * for a particular product. If not defined, and the adb
|
|
+ * command requires this information, then the user must
|
|
+ * specify the path using "-p".
|
|
+ */
|
|
+ gProductOutPath = getenv("ANDROID_PRODUCT_OUT");
|
|
+ if (gProductOutPath == NULL || gProductOutPath[0] == '\0') {
|
|
+ gProductOutPath = NULL;
|
|
+ }
|
|
+ // TODO: also try TARGET_PRODUCT/TARGET_DEVICE as a hint
|
|
+
|
|
+ serial = getenv("ANDROID_SERIAL");
|
|
+
|
|
+ /* Validate and assign the server port */
|
|
+ server_port_str = getenv("ANDROID_ADB_SERVER_PORT");
|
|
+ int server_port = DEFAULT_ADB_PORT;
|
|
+ if (server_port_str && strlen(server_port_str) > 0) {
|
|
+ server_port = (int) strtol(server_port_str, NULL, 0);
|
|
+ if (server_port <= 0 || server_port > 65535) {
|
|
+ fprintf(stderr,
|
|
+ "adb: Env var ANDROID_ADB_SERVER_PORT must be a positive number less than 65535. Got \"%s\"\n",
|
|
+ server_port_str);
|
|
+ return usage();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* modifiers and flags */
|
|
+ while(argc > 0) {
|
|
+ if(!strcmp(argv[0],"server")) {
|
|
+ is_server = 1;
|
|
+ } else if(!strcmp(argv[0],"nodaemon")) {
|
|
+ no_daemon = 1;
|
|
+ } else if (!strcmp(argv[0], "fork-server")) {
|
|
+ /* this is a special flag used only when the ADB client launches the ADB Server */
|
|
+ is_daemon = 1;
|
|
+ } else if(!strcmp(argv[0],"persist")) {
|
|
+ persist = 1;
|
|
+ } else if(!strncmp(argv[0], "-p", 2)) {
|
|
+ const char *product = NULL;
|
|
+ if (argv[0][2] == '\0') {
|
|
+ if (argc < 2) return usage();
|
|
+ product = argv[1];
|
|
+ argc--;
|
|
+ argv++;
|
|
+ } else {
|
|
+ product = argv[0] + 2;
|
|
+ }
|
|
+ gProductOutPath = find_product_out_path(product);
|
|
+ if (gProductOutPath == NULL) {
|
|
+ fprintf(stderr, "adb: could not resolve \"-p %s\"\n",
|
|
+ product);
|
|
+ return usage();
|
|
+ }
|
|
+ } else if (argv[0][0]=='-' && argv[0][1]=='s') {
|
|
+ if (isdigit(argv[0][2])) {
|
|
+ serial = argv[0] + 2;
|
|
+ } else {
|
|
+ if(argc < 2 || argv[0][2] != '\0') return usage();
|
|
+ serial = argv[1];
|
|
+ argc--;
|
|
+ argv++;
|
|
+ }
|
|
+ } else if (!strcmp(argv[0],"-d")) {
|
|
+ ttype = kTransportUsb;
|
|
+ } else if (!strcmp(argv[0],"-e")) {
|
|
+ ttype = kTransportLocal;
|
|
+ } else if (!strcmp(argv[0],"-a")) {
|
|
+ gListenAll = 1;
|
|
+ } else if(!strncmp(argv[0], "-H", 2)) {
|
|
+ const char *hostname = NULL;
|
|
+ if (argv[0][2] == '\0') {
|
|
+ if (argc < 2) return usage();
|
|
+ hostname = argv[1];
|
|
+ argc--;
|
|
+ argv++;
|
|
+ } else {
|
|
+ hostname = argv[0] + 2;
|
|
+ }
|
|
+ adb_set_tcp_name(hostname);
|
|
+
|
|
+ } else if(!strncmp(argv[0], "-P", 2)) {
|
|
+ if (argv[0][2] == '\0') {
|
|
+ if (argc < 2) return usage();
|
|
+ server_port_str = argv[1];
|
|
+ argc--;
|
|
+ argv++;
|
|
+ } else {
|
|
+ server_port_str = argv[0] + 2;
|
|
+ }
|
|
+ if (strlen(server_port_str) > 0) {
|
|
+ server_port = (int) strtol(server_port_str, NULL, 0);
|
|
+ if (server_port <= 0 || server_port > 65535) {
|
|
+ fprintf(stderr,
|
|
+ "adb: port number must be a positive number less than 65536. Got \"%s\"\n",
|
|
+ server_port_str);
|
|
+ return usage();
|
|
+ }
|
|
+ } else {
|
|
+ fprintf(stderr,
|
|
+ "adb: port number must be a positive number less than 65536. Got empty string.\n");
|
|
+ return usage();
|
|
+ }
|
|
+ } else {
|
|
+ /* out of recognized modifiers and flags */
|
|
+ break;
|
|
+ }
|
|
+ argc--;
|
|
+ argv++;
|
|
+ }
|
|
+
|
|
+ adb_set_transport(ttype, serial);
|
|
+ adb_set_tcp_specifics(server_port);
|
|
+
|
|
+ if (is_server) {
|
|
+ if (no_daemon || is_daemon) {
|
|
+ r = adb_main(is_daemon, server_port);
|
|
+ } else {
|
|
+ r = launch_server(server_port);
|
|
+ }
|
|
+ if(r) {
|
|
+ fprintf(stderr,"* could not start server *\n");
|
|
+ }
|
|
+ return r;
|
|
+ }
|
|
+
|
|
+top:
|
|
+ if(argc == 0) {
|
|
+ return usage();
|
|
+ }
|
|
+
|
|
+ /* adb_connect() commands */
|
|
+
|
|
+ if(!strcmp(argv[0], "devices")) {
|
|
+ char *tmp;
|
|
+ char *listopt;
|
|
+ if (argc < 2)
|
|
+ listopt = "";
|
|
+ else if (argc == 2 && !strcmp(argv[1], "-l"))
|
|
+ listopt = argv[1];
|
|
+ else {
|
|
+ fprintf(stderr, "Usage: adb devices [-l]\n");
|
|
+ return 1;
|
|
+ }
|
|
+ snprintf(buf, sizeof buf, "host:%s%s", argv[0], listopt);
|
|
+ tmp = adb_query(buf);
|
|
+ if(tmp) {
|
|
+ printf("List of devices attached \n");
|
|
+ printf("%s\n", tmp);
|
|
+ return 0;
|
|
+ } else {
|
|
+ return 1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if(!strcmp(argv[0], "connect")) {
|
|
+ char *tmp;
|
|
+ if (argc != 2) {
|
|
+ fprintf(stderr, "Usage: adb connect <host>[:<port>]\n");
|
|
+ return 1;
|
|
+ }
|
|
+ snprintf(buf, sizeof buf, "host:connect:%s", argv[1]);
|
|
+ tmp = adb_query(buf);
|
|
+ if(tmp) {
|
|
+ printf("%s\n", tmp);
|
|
+ return 0;
|
|
+ } else {
|
|
+ return 1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if(!strcmp(argv[0], "disconnect")) {
|
|
+ char *tmp;
|
|
+ if (argc > 2) {
|
|
+ fprintf(stderr, "Usage: adb disconnect [<host>[:<port>]]\n");
|
|
+ return 1;
|
|
+ }
|
|
+ if (argc == 2) {
|
|
+ snprintf(buf, sizeof buf, "host:disconnect:%s", argv[1]);
|
|
+ } else {
|
|
+ snprintf(buf, sizeof buf, "host:disconnect:");
|
|
+ }
|
|
+ tmp = adb_query(buf);
|
|
+ if(tmp) {
|
|
+ printf("%s\n", tmp);
|
|
+ return 0;
|
|
+ } else {
|
|
+ return 1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!strcmp(argv[0], "emu")) {
|
|
+ return adb_send_emulator_command(argc, argv);
|
|
+ }
|
|
+
|
|
+ if(!strcmp(argv[0], "shell") || !strcmp(argv[0], "hell")) {
|
|
+ int r;
|
|
+ int fd;
|
|
+
|
|
+ char h = (argv[0][0] == 'h');
|
|
+
|
|
+ if (h) {
|
|
+ printf("\x1b[41;33m");
|
|
+ fflush(stdout);
|
|
+ }
|
|
+
|
|
+ if(argc < 2) {
|
|
+ D("starting interactive shell\n");
|
|
+ r = interactive_shell();
|
|
+ if (h) {
|
|
+ printf("\x1b[0m");
|
|
+ fflush(stdout);
|
|
+ }
|
|
+ return r;
|
|
+ }
|
|
+
|
|
+ snprintf(buf, sizeof buf, "shell:%s", argv[1]);
|
|
+ argc -= 2;
|
|
+ argv += 2;
|
|
+ while(argc-- > 0) {
|
|
+ strcat(buf, " ");
|
|
+
|
|
+ /* quote empty strings and strings with spaces */
|
|
+ quote = (**argv == 0 || strchr(*argv, ' '));
|
|
+ if (quote)
|
|
+ strcat(buf, "\"");
|
|
+ strcat(buf, *argv++);
|
|
+ if (quote)
|
|
+ strcat(buf, "\"");
|
|
+ }
|
|
+
|
|
+ for(;;) {
|
|
+ D("interactive shell loop. buff=%s\n", buf);
|
|
+ fd = adb_connect(buf);
|
|
+ if(fd >= 0) {
|
|
+ D("about to read_and_dump(fd=%d)\n", fd);
|
|
+ read_and_dump(fd);
|
|
+ D("read_and_dump() done.\n");
|
|
+ adb_close(fd);
|
|
+ r = 0;
|
|
+ } else {
|
|
+ fprintf(stderr,"error: %s\n", adb_error());
|
|
+ r = -1;
|
|
+ }
|
|
+
|
|
+ if(persist) {
|
|
+ fprintf(stderr,"\n- waiting for device -\n");
|
|
+ adb_sleep_ms(1000);
|
|
+ do_cmd(ttype, serial, "wait-for-device", 0);
|
|
+ } else {
|
|
+ if (h) {
|
|
+ printf("\x1b[0m");
|
|
+ fflush(stdout);
|
|
+ }
|
|
+ D("interactive shell loop. return r=%d\n", r);
|
|
+ return r;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if(!strcmp(argv[0], "kill-server")) {
|
|
+ int fd;
|
|
+ fd = _adb_connect("host:kill");
|
|
+ if(fd == -1) {
|
|
+ fprintf(stderr,"* server not running *\n");
|
|
+ return 1;
|
|
+ }
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if(!strcmp(argv[0], "sideload")) {
|
|
+ if(argc != 2) return usage();
|
|
+ if(adb_download("sideload", argv[1], 1)) {
|
|
+ return 1;
|
|
+ } else {
|
|
+ return 0;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if(!strcmp(argv[0], "remount") || !strcmp(argv[0], "reboot")
|
|
+ || !strcmp(argv[0], "reboot-bootloader")
|
|
+ || !strcmp(argv[0], "tcpip") || !strcmp(argv[0], "usb")
|
|
+ || !strcmp(argv[0], "root")) {
|
|
+ char command[100];
|
|
+ if (!strcmp(argv[0], "reboot-bootloader"))
|
|
+ snprintf(command, sizeof(command), "reboot:bootloader");
|
|
+ else if (argc > 1)
|
|
+ snprintf(command, sizeof(command), "%s:%s", argv[0], argv[1]);
|
|
+ else
|
|
+ snprintf(command, sizeof(command), "%s:", argv[0]);
|
|
+ int fd = adb_connect(command);
|
|
+ if(fd >= 0) {
|
|
+ read_and_dump(fd);
|
|
+ adb_close(fd);
|
|
+ return 0;
|
|
+ }
|
|
+ fprintf(stderr,"error: %s\n", adb_error());
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ if(!strcmp(argv[0], "bugreport")) {
|
|
+ if (argc != 1) return usage();
|
|
+ do_cmd(ttype, serial, "shell", "bugreport", 0);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ /* adb_command() wrapper commands */
|
|
+
|
|
+ if(!strncmp(argv[0], "wait-for-", strlen("wait-for-"))) {
|
|
+ char* service = argv[0];
|
|
+ if (!strncmp(service, "wait-for-device", strlen("wait-for-device"))) {
|
|
+ if (ttype == kTransportUsb) {
|
|
+ service = "wait-for-usb";
|
|
+ } else if (ttype == kTransportLocal) {
|
|
+ service = "wait-for-local";
|
|
+ } else {
|
|
+ service = "wait-for-any";
|
|
+ }
|
|
+ }
|
|
+
|
|
+ format_host_command(buf, sizeof buf, service, ttype, serial);
|
|
+
|
|
+ if (adb_command(buf)) {
|
|
+ D("failure: %s *\n",adb_error());
|
|
+ fprintf(stderr,"error: %s\n", adb_error());
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ /* Allow a command to be run after wait-for-device,
|
|
+ * e.g. 'adb wait-for-device shell'.
|
|
+ */
|
|
+ if(argc > 1) {
|
|
+ argc--;
|
|
+ argv++;
|
|
+ goto top;
|
|
+ }
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if(!strcmp(argv[0], "forward")) {
|
|
+ char host_prefix[64];
|
|
+ char remove = 0;
|
|
+ char remove_all = 0;
|
|
+ char list = 0;
|
|
+ char no_rebind = 0;
|
|
+
|
|
+ // Parse options here.
|
|
+ while (argc > 1 && argv[1][0] == '-') {
|
|
+ if (!strcmp(argv[1], "--list"))
|
|
+ list = 1;
|
|
+ else if (!strcmp(argv[1], "--remove"))
|
|
+ remove = 1;
|
|
+ else if (!strcmp(argv[1], "--remove-all"))
|
|
+ remove_all = 1;
|
|
+ else if (!strcmp(argv[1], "--no-rebind"))
|
|
+ no_rebind = 1;
|
|
+ else {
|
|
+ return usage();
|
|
+ }
|
|
+ argc--;
|
|
+ argv++;
|
|
+ }
|
|
+
|
|
+ // Ensure we can only use one option at a time.
|
|
+ if (list + remove + remove_all + no_rebind > 1) {
|
|
+ return usage();
|
|
+ }
|
|
+
|
|
+ // Determine the <host-prefix> for this command.
|
|
+ if (serial) {
|
|
+ snprintf(host_prefix, sizeof host_prefix, "host-serial:%s",
|
|
+ serial);
|
|
+ } else if (ttype == kTransportUsb) {
|
|
+ snprintf(host_prefix, sizeof host_prefix, "host-usb");
|
|
+ } else if (ttype == kTransportLocal) {
|
|
+ snprintf(host_prefix, sizeof host_prefix, "host-local");
|
|
+ } else {
|
|
+ snprintf(host_prefix, sizeof host_prefix, "host");
|
|
+ }
|
|
+
|
|
+ // Implement forward --list
|
|
+ if (list) {
|
|
+ if (argc != 1)
|
|
+ return usage();
|
|
+ snprintf(buf, sizeof buf, "%s:list-forward", host_prefix);
|
|
+ char* forwards = adb_query(buf);
|
|
+ if (forwards == NULL) {
|
|
+ fprintf(stderr, "error: %s\n", adb_error());
|
|
+ return 1;
|
|
+ }
|
|
+ printf("%s", forwards);
|
|
+ free(forwards);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ // Implement forward --remove-all
|
|
+ else if (remove_all) {
|
|
+ if (argc != 1)
|
|
+ return usage();
|
|
+ snprintf(buf, sizeof buf, "%s:killforward-all", host_prefix);
|
|
+ }
|
|
+
|
|
+ // Implement forward --remove <local>
|
|
+ else if (remove) {
|
|
+ if (argc != 2)
|
|
+ return usage();
|
|
+ snprintf(buf, sizeof buf, "%s:killforward:%s", host_prefix, argv[1]);
|
|
+ }
|
|
+ // Or implement one of:
|
|
+ // forward <local> <remote>
|
|
+ // forward --no-rebind <local> <remote>
|
|
+ else
|
|
+ {
|
|
+ if (argc != 3)
|
|
+ return usage();
|
|
+ const char* command = no_rebind ? "forward:norebind:" : "forward";
|
|
+ snprintf(buf, sizeof buf, "%s:%s:%s;%s", host_prefix, command, argv[1], argv[2]);
|
|
+ }
|
|
+
|
|
+ if(adb_command(buf)) {
|
|
+ fprintf(stderr,"error: %s\n", adb_error());
|
|
+ return 1;
|
|
+ }
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ /* do_sync_*() commands */
|
|
+
|
|
+ if(!strcmp(argv[0], "ls")) {
|
|
+ if(argc != 2) return usage();
|
|
+ return do_sync_ls(argv[1]);
|
|
+ }
|
|
+
|
|
+ if(!strcmp(argv[0], "push")) {
|
|
+ if(argc != 3) return usage();
|
|
+ return do_sync_push(argv[1], argv[2], 0 /* no verify APK */);
|
|
+ }
|
|
+
|
|
+ if(!strcmp(argv[0], "pull")) {
|
|
+ if (argc == 2) {
|
|
+ return do_sync_pull(argv[1], ".");
|
|
+ } else if (argc == 3) {
|
|
+ return do_sync_pull(argv[1], argv[2]);
|
|
+ } else {
|
|
+ return usage();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if(!strcmp(argv[0], "install")) {
|
|
+ if (argc < 2) return usage();
|
|
+ return install_app(ttype, serial, argc, argv);
|
|
+ }
|
|
+
|
|
+ if(!strcmp(argv[0], "uninstall")) {
|
|
+ if (argc < 2) return usage();
|
|
+ return uninstall_app(ttype, serial, argc, argv);
|
|
+ }
|
|
+
|
|
+ if(!strcmp(argv[0], "sync")) {
|
|
+ char *srcarg, *android_srcpath, *data_srcpath;
|
|
+ int listonly = 0;
|
|
+
|
|
+ int ret;
|
|
+ if(argc < 2) {
|
|
+ /* No local path was specified. */
|
|
+ srcarg = NULL;
|
|
+ } else if (argc >= 2 && strcmp(argv[1], "-l") == 0) {
|
|
+ listonly = 1;
|
|
+ if (argc == 3) {
|
|
+ srcarg = argv[2];
|
|
+ } else {
|
|
+ srcarg = NULL;
|
|
+ }
|
|
+ } else if(argc == 2) {
|
|
+ /* A local path or "android"/"data" arg was specified. */
|
|
+ srcarg = argv[1];
|
|
+ } else {
|
|
+ return usage();
|
|
+ }
|
|
+ ret = find_sync_dirs(srcarg, &android_srcpath, &data_srcpath);
|
|
+ if(ret != 0) return usage();
|
|
+
|
|
+ if(android_srcpath != NULL)
|
|
+ ret = do_sync_sync(android_srcpath, "/system", listonly);
|
|
+ if(ret == 0 && data_srcpath != NULL)
|
|
+ ret = do_sync_sync(data_srcpath, "/data", listonly);
|
|
+
|
|
+ free(android_srcpath);
|
|
+ free(data_srcpath);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ /* passthrough commands */
|
|
+
|
|
+ if(!strcmp(argv[0],"get-state") ||
|
|
+ !strcmp(argv[0],"get-serialno") ||
|
|
+ !strcmp(argv[0],"get-devpath"))
|
|
+ {
|
|
+ char *tmp;
|
|
+
|
|
+ format_host_command(buf, sizeof buf, argv[0], ttype, serial);
|
|
+ tmp = adb_query(buf);
|
|
+ if(tmp) {
|
|
+ printf("%s\n", tmp);
|
|
+ return 0;
|
|
+ } else {
|
|
+ return 1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* other commands */
|
|
+
|
|
+ if(!strcmp(argv[0],"status-window")) {
|
|
+ status_window(ttype, serial);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if(!strcmp(argv[0],"logcat") || !strcmp(argv[0],"lolcat") || !strcmp(argv[0],"longcat")) {
|
|
+ return logcat(ttype, serial, argc, argv);
|
|
+ }
|
|
+
|
|
+ if(!strcmp(argv[0],"ppp")) {
|
|
+ return ppp(argc, argv);
|
|
+ }
|
|
+
|
|
+ if (!strcmp(argv[0], "start-server")) {
|
|
+ return adb_connect("host:start-server");
|
|
+ }
|
|
+
|
|
+ if (!strcmp(argv[0], "backup")) {
|
|
+ return backup(argc, argv);
|
|
+ }
|
|
+
|
|
+ if (!strcmp(argv[0], "restore")) {
|
|
+ return restore(argc, argv);
|
|
+ }
|
|
+
|
|
+ if (!strcmp(argv[0], "jdwp")) {
|
|
+ int fd = adb_connect("jdwp");
|
|
+ if (fd >= 0) {
|
|
+ read_and_dump(fd);
|
|
+ adb_close(fd);
|
|
+ return 0;
|
|
+ } else {
|
|
+ fprintf(stderr, "error: %s\n", adb_error());
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* "adb /?" is a common idiom under Windows */
|
|
+ if(!strcmp(argv[0], "help") || !strcmp(argv[0], "/?")) {
|
|
+ help();
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if(!strcmp(argv[0], "version")) {
|
|
+ version(stdout);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ usage();
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+static int do_cmd(transport_type ttype, char* serial, char *cmd, ...)
|
|
+{
|
|
+ char *argv[16];
|
|
+ int argc;
|
|
+ va_list ap;
|
|
+
|
|
+ va_start(ap, cmd);
|
|
+ argc = 0;
|
|
+
|
|
+ if (serial) {
|
|
+ argv[argc++] = "-s";
|
|
+ argv[argc++] = serial;
|
|
+ } else if (ttype == kTransportUsb) {
|
|
+ argv[argc++] = "-d";
|
|
+ } else if (ttype == kTransportLocal) {
|
|
+ argv[argc++] = "-e";
|
|
+ }
|
|
+
|
|
+ argv[argc++] = cmd;
|
|
+ while((argv[argc] = va_arg(ap, char*)) != 0) argc++;
|
|
+ va_end(ap);
|
|
+
|
|
+#if 0
|
|
+ int n;
|
|
+ fprintf(stderr,"argc = %d\n",argc);
|
|
+ for(n = 0; n < argc; n++) {
|
|
+ fprintf(stderr,"argv[%d] = \"%s\"\n", n, argv[n]);
|
|
+ }
|
|
+#endif
|
|
+
|
|
+ return adb_commandline(argc, argv);
|
|
+}
|
|
+
|
|
+int find_sync_dirs(const char *srcarg,
|
|
+ char **android_srcdir_out, char **data_srcdir_out)
|
|
+{
|
|
+ char *android_srcdir, *data_srcdir;
|
|
+
|
|
+ if(srcarg == NULL) {
|
|
+ android_srcdir = product_file("system");
|
|
+ data_srcdir = product_file("data");
|
|
+ } else {
|
|
+ /* srcarg may be "data", "system" or NULL.
|
|
+ * if srcarg is NULL, then both data and system are synced
|
|
+ */
|
|
+ if(strcmp(srcarg, "system") == 0) {
|
|
+ android_srcdir = product_file("system");
|
|
+ data_srcdir = NULL;
|
|
+ } else if(strcmp(srcarg, "data") == 0) {
|
|
+ android_srcdir = NULL;
|
|
+ data_srcdir = product_file("data");
|
|
+ } else {
|
|
+ /* It's not "system" or "data".
|
|
+ */
|
|
+ return 1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if(android_srcdir_out != NULL)
|
|
+ *android_srcdir_out = android_srcdir;
|
|
+ else
|
|
+ free(android_srcdir);
|
|
+
|
|
+ if(data_srcdir_out != NULL)
|
|
+ *data_srcdir_out = data_srcdir;
|
|
+ else
|
|
+ free(data_srcdir);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int pm_command(transport_type transport, char* serial,
|
|
+ int argc, char** argv)
|
|
+{
|
|
+ char buf[4096];
|
|
+
|
|
+ snprintf(buf, sizeof(buf), "shell:pm");
|
|
+
|
|
+ while(argc-- > 0) {
|
|
+ char *quoted;
|
|
+
|
|
+ quoted = dupAndQuote(*argv++);
|
|
+
|
|
+ strncat(buf, " ", sizeof(buf)-1);
|
|
+ strncat(buf, quoted, sizeof(buf)-1);
|
|
+ free(quoted);
|
|
+ }
|
|
+
|
|
+ send_shellcommand(transport, serial, buf);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int uninstall_app(transport_type transport, char* serial, int argc, char** argv)
|
|
+{
|
|
+ /* if the user choose the -k option, we refuse to do it until devices are
|
|
+ out with the option to uninstall the remaining data somehow (adb/ui) */
|
|
+ if (argc == 3 && strcmp(argv[1], "-k") == 0)
|
|
+ {
|
|
+ printf(
|
|
+ "The -k option uninstalls the application while retaining the data/cache.\n"
|
|
+ "At the moment, there is no way to remove the remaining data.\n"
|
|
+ "You will have to reinstall the application with the same signature, and fully uninstall it.\n"
|
|
+ "If you truly wish to continue, execute 'adb shell pm uninstall -k %s'\n", argv[2]);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ /* 'adb uninstall' takes the same arguments as 'pm uninstall' on device */
|
|
+ return pm_command(transport, serial, argc, argv);
|
|
+}
|
|
+
|
|
+static int delete_file(transport_type transport, char* serial, char* filename)
|
|
+{
|
|
+ char buf[4096];
|
|
+ char* quoted;
|
|
+
|
|
+ snprintf(buf, sizeof(buf), "shell:rm ");
|
|
+ quoted = dupAndQuote(filename);
|
|
+ strncat(buf, quoted, sizeof(buf)-1);
|
|
+ free(quoted);
|
|
+
|
|
+ send_shellcommand(transport, serial, buf);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const char* get_basename(const char* filename)
|
|
+{
|
|
+ const char* basename = adb_dirstop(filename);
|
|
+ if (basename) {
|
|
+ basename++;
|
|
+ return basename;
|
|
+ } else {
|
|
+ return filename;
|
|
+ }
|
|
+}
|
|
+
|
|
+static int check_file(const char* filename)
|
|
+{
|
|
+ struct stat st;
|
|
+
|
|
+ if (filename == NULL) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (stat(filename, &st) != 0) {
|
|
+ fprintf(stderr, "can't find '%s' to install\n", filename);
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ if (!S_ISREG(st.st_mode)) {
|
|
+ fprintf(stderr, "can't install '%s' because it's not a file\n", filename);
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int install_app(transport_type transport, char* serial, int argc, char** argv)
|
|
+{
|
|
+ static const char *const DATA_DEST = "/data/local/tmp/%s";
|
|
+ static const char *const SD_DEST = "/sdcard/tmp/%s";
|
|
+ const char* where = DATA_DEST;
|
|
+ char apk_dest[PATH_MAX];
|
|
+ char verification_dest[PATH_MAX];
|
|
+ char* apk_file;
|
|
+ char* verification_file = NULL;
|
|
+ int file_arg = -1;
|
|
+ int err;
|
|
+ int i;
|
|
+ int verify_apk = 1;
|
|
+
|
|
+ for (i = 1; i < argc; i++) {
|
|
+ if (*argv[i] != '-') {
|
|
+ file_arg = i;
|
|
+ break;
|
|
+ } else if (!strcmp(argv[i], "-i")) {
|
|
+ // Skip the installer package name.
|
|
+ i++;
|
|
+ } else if (!strcmp(argv[i], "-s")) {
|
|
+ where = SD_DEST;
|
|
+ } else if (!strcmp(argv[i], "--algo")) {
|
|
+ verify_apk = 0;
|
|
+ i++;
|
|
+ } else if (!strcmp(argv[i], "--iv")) {
|
|
+ verify_apk = 0;
|
|
+ i++;
|
|
+ } else if (!strcmp(argv[i], "--key")) {
|
|
+ verify_apk = 0;
|
|
+ i++;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (file_arg < 0) {
|
|
+ fprintf(stderr, "can't find filename in arguments\n");
|
|
+ return 1;
|
|
+ } else if (file_arg + 2 < argc) {
|
|
+ fprintf(stderr, "too many files specified; only takes APK file and verifier file\n");
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ apk_file = argv[file_arg];
|
|
+
|
|
+ if (file_arg != argc - 1) {
|
|
+ verification_file = argv[file_arg + 1];
|
|
+ }
|
|
+
|
|
+ if (check_file(apk_file) || check_file(verification_file)) {
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ snprintf(apk_dest, sizeof apk_dest, where, get_basename(apk_file));
|
|
+ if (verification_file != NULL) {
|
|
+ snprintf(verification_dest, sizeof(verification_dest), where, get_basename(verification_file));
|
|
+
|
|
+ if (!strcmp(apk_dest, verification_dest)) {
|
|
+ fprintf(stderr, "APK and verification file can't have the same name\n");
|
|
+ return 1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ err = do_sync_push(apk_file, apk_dest, verify_apk);
|
|
+ if (err) {
|
|
+ goto cleanup_apk;
|
|
+ } else {
|
|
+ argv[file_arg] = apk_dest; /* destination name, not source location */
|
|
+ }
|
|
+
|
|
+ if (verification_file != NULL) {
|
|
+ err = do_sync_push(verification_file, verification_dest, 0 /* no verify APK */);
|
|
+ if (err) {
|
|
+ goto cleanup_apk;
|
|
+ } else {
|
|
+ argv[file_arg + 1] = verification_dest; /* destination name, not source location */
|
|
+ }
|
|
+ }
|
|
+
|
|
+ pm_command(transport, serial, argc, argv);
|
|
+
|
|
+cleanup_apk:
|
|
+ if (verification_file != NULL) {
|
|
+ delete_file(transport, serial, verification_dest);
|
|
+ }
|
|
+
|
|
+ delete_file(transport, serial, apk_dest);
|
|
+
|
|
+ return err;
|
|
+}
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/console.c
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/console.c 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,45 @@
|
|
+#include "sysdeps.h"
|
|
+#include "adb.h"
|
|
+#include "adb_client.h"
|
|
+#include <stdio.h>
|
|
+
|
|
+static int connect_to_console(void)
|
|
+{
|
|
+ int fd, port;
|
|
+
|
|
+ port = adb_get_emulator_console_port();
|
|
+ if (port < 0) {
|
|
+ if (port == -2)
|
|
+ fprintf(stderr, "error: more than one emulator detected. use -s option\n");
|
|
+ else
|
|
+ fprintf(stderr, "error: no emulator detected\n");
|
|
+ return -1;
|
|
+ }
|
|
+ fd = socket_loopback_client( port, SOCK_STREAM );
|
|
+ if (fd < 0) {
|
|
+ fprintf(stderr, "error: could not connect to TCP port %d\n", port);
|
|
+ return -1;
|
|
+ }
|
|
+ return fd;
|
|
+}
|
|
+
|
|
+
|
|
+int adb_send_emulator_command(int argc, char** argv)
|
|
+{
|
|
+ int fd, nn;
|
|
+
|
|
+ fd = connect_to_console();
|
|
+ if (fd < 0)
|
|
+ return 1;
|
|
+
|
|
+#define QUIT "quit\n"
|
|
+
|
|
+ for (nn = 1; nn < argc; nn++) {
|
|
+ adb_write( fd, argv[nn], strlen(argv[nn]) );
|
|
+ adb_write( fd, (nn == argc-1) ? "\n" : " ", 1 );
|
|
+ }
|
|
+ adb_write( fd, QUIT, sizeof(QUIT)-1 );
|
|
+ adb_close(fd);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/fdevent.c
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/fdevent.c 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,695 @@
|
|
+/* http://frotznet.googlecode.com/svn/trunk/utils/fdevent.c
|
|
+**
|
|
+** Copyright 2006, Brian Swetland <swetland@frotz.net>
|
|
+**
|
|
+** Licensed under the Apache License, Version 2.0 (the "License");
|
|
+** you may not use this file except in compliance with the License.
|
|
+** You may obtain a copy of the License at
|
|
+**
|
|
+** http://www.apache.org/licenses/LICENSE-2.0
|
|
+**
|
|
+** Unless required by applicable law or agreed to in writing, software
|
|
+** distributed under the License is distributed on an "AS IS" BASIS,
|
|
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+** See the License for the specific language governing permissions and
|
|
+** limitations under the License.
|
|
+*/
|
|
+
|
|
+#include <sys/ioctl.h>
|
|
+
|
|
+#include <stdlib.h>
|
|
+#include <stdio.h>
|
|
+#include <string.h>
|
|
+#include <unistd.h>
|
|
+#include <errno.h>
|
|
+
|
|
+#include <fcntl.h>
|
|
+
|
|
+#include <stdarg.h>
|
|
+#include <stddef.h>
|
|
+
|
|
+#include "fdevent.h"
|
|
+#include "transport.h"
|
|
+#include "sysdeps.h"
|
|
+
|
|
+
|
|
+/* !!! Do not enable DEBUG for the adb that will run as the server:
|
|
+** both stdout and stderr are used to communicate between the client
|
|
+** and server. Any extra output will cause failures.
|
|
+*/
|
|
+#define DEBUG 0 /* non-0 will break adb server */
|
|
+
|
|
+// This socket is used when a subproc shell service exists.
|
|
+// It wakes up the fdevent_loop() and cause the correct handling
|
|
+// of the shell's pseudo-tty master. I.e. force close it.
|
|
+int SHELL_EXIT_NOTIFY_FD = -1;
|
|
+
|
|
+static void fatal(const char *fn, const char *fmt, ...)
|
|
+{
|
|
+ va_list ap;
|
|
+ va_start(ap, fmt);
|
|
+ fprintf(stderr, "%s:", fn);
|
|
+ vfprintf(stderr, fmt, ap);
|
|
+ va_end(ap);
|
|
+ abort();
|
|
+}
|
|
+
|
|
+#define FATAL(x...) fatal(__FUNCTION__, x)
|
|
+
|
|
+#if DEBUG
|
|
+#define D(...) \
|
|
+ do { \
|
|
+ adb_mutex_lock(&D_lock); \
|
|
+ int save_errno = errno; \
|
|
+ fprintf(stderr, "%s::%s():", __FILE__, __FUNCTION__); \
|
|
+ errno = save_errno; \
|
|
+ fprintf(stderr, __VA_ARGS__); \
|
|
+ adb_mutex_unlock(&D_lock); \
|
|
+ errno = save_errno; \
|
|
+ } while(0)
|
|
+static void dump_fde(fdevent *fde, const char *info)
|
|
+{
|
|
+ adb_mutex_lock(&D_lock);
|
|
+ fprintf(stderr,"FDE #%03d %c%c%c %s\n", fde->fd,
|
|
+ fde->state & FDE_READ ? 'R' : ' ',
|
|
+ fde->state & FDE_WRITE ? 'W' : ' ',
|
|
+ fde->state & FDE_ERROR ? 'E' : ' ',
|
|
+ info);
|
|
+ adb_mutex_unlock(&D_lock);
|
|
+}
|
|
+#else
|
|
+#define D(...) ((void)0)
|
|
+#define dump_fde(fde, info) do { } while(0)
|
|
+#endif
|
|
+
|
|
+#define FDE_EVENTMASK 0x00ff
|
|
+#define FDE_STATEMASK 0xff00
|
|
+
|
|
+#define FDE_ACTIVE 0x0100
|
|
+#define FDE_PENDING 0x0200
|
|
+#define FDE_CREATED 0x0400
|
|
+
|
|
+static void fdevent_plist_enqueue(fdevent *node);
|
|
+static void fdevent_plist_remove(fdevent *node);
|
|
+static fdevent *fdevent_plist_dequeue(void);
|
|
+static void fdevent_subproc_event_func(int fd, unsigned events, void *userdata);
|
|
+
|
|
+static fdevent list_pending = {
|
|
+ .next = &list_pending,
|
|
+ .prev = &list_pending,
|
|
+};
|
|
+
|
|
+static fdevent **fd_table = 0;
|
|
+static int fd_table_max = 0;
|
|
+
|
|
+#ifdef CRAPTASTIC
|
|
+//HAVE_EPOLL
|
|
+
|
|
+#include <sys/epoll.h>
|
|
+
|
|
+static int epoll_fd = -1;
|
|
+
|
|
+static void fdevent_init()
|
|
+{
|
|
+ /* XXX: what's a good size for the passed in hint? */
|
|
+ epoll_fd = epoll_create(256);
|
|
+
|
|
+ if(epoll_fd < 0) {
|
|
+ perror("epoll_create() failed");
|
|
+ exit(1);
|
|
+ }
|
|
+
|
|
+ /* mark for close-on-exec */
|
|
+ fcntl(epoll_fd, F_SETFD, FD_CLOEXEC);
|
|
+}
|
|
+
|
|
+static void fdevent_connect(fdevent *fde)
|
|
+{
|
|
+ struct epoll_event ev;
|
|
+
|
|
+ memset(&ev, 0, sizeof(ev));
|
|
+ ev.events = 0;
|
|
+ ev.data.ptr = fde;
|
|
+
|
|
+#if 0
|
|
+ if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fde->fd, &ev)) {
|
|
+ perror("epoll_ctl() failed\n");
|
|
+ exit(1);
|
|
+ }
|
|
+#endif
|
|
+}
|
|
+
|
|
+static void fdevent_disconnect(fdevent *fde)
|
|
+{
|
|
+ struct epoll_event ev;
|
|
+
|
|
+ memset(&ev, 0, sizeof(ev));
|
|
+ ev.events = 0;
|
|
+ ev.data.ptr = fde;
|
|
+
|
|
+ /* technically we only need to delete if we
|
|
+ ** were actively monitoring events, but let's
|
|
+ ** be aggressive and do it anyway, just in case
|
|
+ ** something's out of sync
|
|
+ */
|
|
+ epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fde->fd, &ev);
|
|
+}
|
|
+
|
|
+static void fdevent_update(fdevent *fde, unsigned events)
|
|
+{
|
|
+ struct epoll_event ev;
|
|
+ int active;
|
|
+
|
|
+ active = (fde->state & FDE_EVENTMASK) != 0;
|
|
+
|
|
+ memset(&ev, 0, sizeof(ev));
|
|
+ ev.events = 0;
|
|
+ ev.data.ptr = fde;
|
|
+
|
|
+ if(events & FDE_READ) ev.events |= EPOLLIN;
|
|
+ if(events & FDE_WRITE) ev.events |= EPOLLOUT;
|
|
+ if(events & FDE_ERROR) ev.events |= (EPOLLERR | EPOLLHUP);
|
|
+
|
|
+ fde->state = (fde->state & FDE_STATEMASK) | events;
|
|
+
|
|
+ if(active) {
|
|
+ /* we're already active. if we're changing to *no*
|
|
+ ** events being monitored, we need to delete, otherwise
|
|
+ ** we need to just modify
|
|
+ */
|
|
+ if(ev.events) {
|
|
+ if(epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fde->fd, &ev)) {
|
|
+ perror("epoll_ctl() failed\n");
|
|
+ exit(1);
|
|
+ }
|
|
+ } else {
|
|
+ if(epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fde->fd, &ev)) {
|
|
+ perror("epoll_ctl() failed\n");
|
|
+ exit(1);
|
|
+ }
|
|
+ }
|
|
+ } else {
|
|
+ /* we're not active. if we're watching events, we need
|
|
+ ** to add, otherwise we can just do nothing
|
|
+ */
|
|
+ if(ev.events) {
|
|
+ if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fde->fd, &ev)) {
|
|
+ perror("epoll_ctl() failed\n");
|
|
+ exit(1);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+static void fdevent_process()
|
|
+{
|
|
+ struct epoll_event events[256];
|
|
+ fdevent *fde;
|
|
+ int i, n;
|
|
+
|
|
+ n = epoll_wait(epoll_fd, events, 256, -1);
|
|
+
|
|
+ if(n < 0) {
|
|
+ if(errno == EINTR) return;
|
|
+ perror("epoll_wait");
|
|
+ exit(1);
|
|
+ }
|
|
+
|
|
+ for(i = 0; i < n; i++) {
|
|
+ struct epoll_event *ev = events + i;
|
|
+ fde = ev->data.ptr;
|
|
+
|
|
+ if(ev->events & EPOLLIN) {
|
|
+ fde->events |= FDE_READ;
|
|
+ }
|
|
+ if(ev->events & EPOLLOUT) {
|
|
+ fde->events |= FDE_WRITE;
|
|
+ }
|
|
+ if(ev->events & (EPOLLERR | EPOLLHUP)) {
|
|
+ fde->events |= FDE_ERROR;
|
|
+ }
|
|
+ if(fde->events) {
|
|
+ if(fde->state & FDE_PENDING) continue;
|
|
+ fde->state |= FDE_PENDING;
|
|
+ fdevent_plist_enqueue(fde);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+#else /* USE_SELECT */
|
|
+
|
|
+#ifdef HAVE_WINSOCK
|
|
+#include <winsock2.h>
|
|
+#else
|
|
+#include <sys/select.h>
|
|
+#endif
|
|
+
|
|
+static fd_set read_fds;
|
|
+static fd_set write_fds;
|
|
+static fd_set error_fds;
|
|
+
|
|
+static int select_n = 0;
|
|
+
|
|
+static void fdevent_init(void)
|
|
+{
|
|
+ FD_ZERO(&read_fds);
|
|
+ FD_ZERO(&write_fds);
|
|
+ FD_ZERO(&error_fds);
|
|
+}
|
|
+
|
|
+static void fdevent_connect(fdevent *fde)
|
|
+{
|
|
+ if(fde->fd >= select_n) {
|
|
+ select_n = fde->fd + 1;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void fdevent_disconnect(fdevent *fde)
|
|
+{
|
|
+ int i, n;
|
|
+
|
|
+ FD_CLR(fde->fd, &read_fds);
|
|
+ FD_CLR(fde->fd, &write_fds);
|
|
+ FD_CLR(fde->fd, &error_fds);
|
|
+
|
|
+ for(n = 0, i = 0; i < select_n; i++) {
|
|
+ if(fd_table[i] != 0) n = i;
|
|
+ }
|
|
+ select_n = n + 1;
|
|
+}
|
|
+
|
|
+static void fdevent_update(fdevent *fde, unsigned events)
|
|
+{
|
|
+ if(events & FDE_READ) {
|
|
+ FD_SET(fde->fd, &read_fds);
|
|
+ } else {
|
|
+ FD_CLR(fde->fd, &read_fds);
|
|
+ }
|
|
+ if(events & FDE_WRITE) {
|
|
+ FD_SET(fde->fd, &write_fds);
|
|
+ } else {
|
|
+ FD_CLR(fde->fd, &write_fds);
|
|
+ }
|
|
+ if(events & FDE_ERROR) {
|
|
+ FD_SET(fde->fd, &error_fds);
|
|
+ } else {
|
|
+ FD_CLR(fde->fd, &error_fds);
|
|
+ }
|
|
+
|
|
+ fde->state = (fde->state & FDE_STATEMASK) | events;
|
|
+}
|
|
+
|
|
+/* Looks at fd_table[] for bad FDs and sets bit in fds.
|
|
+** Returns the number of bad FDs.
|
|
+*/
|
|
+static int fdevent_fd_check(fd_set *fds)
|
|
+{
|
|
+ int i, n = 0;
|
|
+ fdevent *fde;
|
|
+
|
|
+ for(i = 0; i < select_n; i++) {
|
|
+ fde = fd_table[i];
|
|
+ if(fde == 0) continue;
|
|
+ if(fcntl(i, F_GETFL, NULL) < 0) {
|
|
+ FD_SET(i, fds);
|
|
+ n++;
|
|
+ // fde->state |= FDE_DONT_CLOSE;
|
|
+
|
|
+ }
|
|
+ }
|
|
+ return n;
|
|
+}
|
|
+
|
|
+#if !DEBUG
|
|
+static inline void dump_all_fds(const char *extra_msg) {}
|
|
+#else
|
|
+static void dump_all_fds(const char *extra_msg)
|
|
+{
|
|
+int i;
|
|
+ fdevent *fde;
|
|
+ // per fd: 4 digits (but really: log10(FD_SETSIZE)), 1 staus, 1 blank
|
|
+ char msg_buff[FD_SETSIZE*6 + 1], *pb=msg_buff;
|
|
+ size_t max_chars = FD_SETSIZE * 6 + 1;
|
|
+ int printed_out;
|
|
+#define SAFE_SPRINTF(...) \
|
|
+ do { \
|
|
+ printed_out = snprintf(pb, max_chars, __VA_ARGS__); \
|
|
+ if (printed_out <= 0) { \
|
|
+ D("... snprintf failed.\n"); \
|
|
+ return; \
|
|
+ } \
|
|
+ if (max_chars < (unsigned int)printed_out) { \
|
|
+ D("... snprintf out of space.\n"); \
|
|
+ return; \
|
|
+ } \
|
|
+ pb += printed_out; \
|
|
+ max_chars -= printed_out; \
|
|
+ } while(0)
|
|
+
|
|
+ for(i = 0; i < select_n; i++) {
|
|
+ fde = fd_table[i];
|
|
+ SAFE_SPRINTF("%d", i);
|
|
+ if(fde == 0) {
|
|
+ SAFE_SPRINTF("? ");
|
|
+ continue;
|
|
+ }
|
|
+ if(fcntl(i, F_GETFL, NULL) < 0) {
|
|
+ SAFE_SPRINTF("b");
|
|
+ }
|
|
+ SAFE_SPRINTF(" ");
|
|
+ }
|
|
+ D("%s fd_table[]->fd = {%s}\n", extra_msg, msg_buff);
|
|
+}
|
|
+#endif
|
|
+
|
|
+static void fdevent_process()
|
|
+{
|
|
+ int i, n;
|
|
+ fdevent *fde;
|
|
+ unsigned events;
|
|
+ fd_set rfd, wfd, efd;
|
|
+
|
|
+ memcpy(&rfd, &read_fds, sizeof(fd_set));
|
|
+ memcpy(&wfd, &write_fds, sizeof(fd_set));
|
|
+ memcpy(&efd, &error_fds, sizeof(fd_set));
|
|
+
|
|
+ dump_all_fds("pre select()");
|
|
+
|
|
+ n = select(select_n, &rfd, &wfd, &efd, NULL);
|
|
+ int saved_errno = errno;
|
|
+ D("select() returned n=%d, errno=%d\n", n, n<0?saved_errno:0);
|
|
+
|
|
+ dump_all_fds("post select()");
|
|
+
|
|
+ if(n < 0) {
|
|
+ switch(saved_errno) {
|
|
+ case EINTR: return;
|
|
+ case EBADF:
|
|
+ // Can't trust the FD sets after an error.
|
|
+ FD_ZERO(&wfd);
|
|
+ FD_ZERO(&efd);
|
|
+ FD_ZERO(&rfd);
|
|
+ break;
|
|
+ default:
|
|
+ D("Unexpected select() error=%d\n", saved_errno);
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+ if(n <= 0) {
|
|
+ // We fake a read, as the rest of the code assumes
|
|
+ // that errors will be detected at that point.
|
|
+ n = fdevent_fd_check(&rfd);
|
|
+ }
|
|
+
|
|
+ for(i = 0; (i < select_n) && (n > 0); i++) {
|
|
+ events = 0;
|
|
+ if(FD_ISSET(i, &rfd)) { events |= FDE_READ; n--; }
|
|
+ if(FD_ISSET(i, &wfd)) { events |= FDE_WRITE; n--; }
|
|
+ if(FD_ISSET(i, &efd)) { events |= FDE_ERROR; n--; }
|
|
+
|
|
+ if(events) {
|
|
+ fde = fd_table[i];
|
|
+ if(fde == 0)
|
|
+ FATAL("missing fde for fd %d\n", i);
|
|
+
|
|
+ fde->events |= events;
|
|
+
|
|
+ D("got events fde->fd=%d events=%04x, state=%04x\n",
|
|
+ fde->fd, fde->events, fde->state);
|
|
+ if(fde->state & FDE_PENDING) continue;
|
|
+ fde->state |= FDE_PENDING;
|
|
+ fdevent_plist_enqueue(fde);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+#endif
|
|
+
|
|
+static void fdevent_register(fdevent *fde)
|
|
+{
|
|
+ if(fde->fd < 0) {
|
|
+ FATAL("bogus negative fd (%d)\n", fde->fd);
|
|
+ }
|
|
+
|
|
+ if(fde->fd >= fd_table_max) {
|
|
+ int oldmax = fd_table_max;
|
|
+ if(fde->fd > 32000) {
|
|
+ FATAL("bogus huuuuge fd (%d)\n", fde->fd);
|
|
+ }
|
|
+ if(fd_table_max == 0) {
|
|
+ fdevent_init();
|
|
+ fd_table_max = 256;
|
|
+ }
|
|
+ while(fd_table_max <= fde->fd) {
|
|
+ fd_table_max *= 2;
|
|
+ }
|
|
+ fd_table = realloc(fd_table, sizeof(fdevent*) * fd_table_max);
|
|
+ if(fd_table == 0) {
|
|
+ FATAL("could not expand fd_table to %d entries\n", fd_table_max);
|
|
+ }
|
|
+ memset(fd_table + oldmax, 0, sizeof(int) * (fd_table_max - oldmax));
|
|
+ }
|
|
+
|
|
+ fd_table[fde->fd] = fde;
|
|
+}
|
|
+
|
|
+static void fdevent_unregister(fdevent *fde)
|
|
+{
|
|
+ if((fde->fd < 0) || (fde->fd >= fd_table_max)) {
|
|
+ FATAL("fd out of range (%d)\n", fde->fd);
|
|
+ }
|
|
+
|
|
+ if(fd_table[fde->fd] != fde) {
|
|
+ FATAL("fd_table out of sync [%d]\n", fde->fd);
|
|
+ }
|
|
+
|
|
+ fd_table[fde->fd] = 0;
|
|
+
|
|
+ if(!(fde->state & FDE_DONT_CLOSE)) {
|
|
+ dump_fde(fde, "close");
|
|
+ adb_close(fde->fd);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void fdevent_plist_enqueue(fdevent *node)
|
|
+{
|
|
+ fdevent *list = &list_pending;
|
|
+
|
|
+ node->next = list;
|
|
+ node->prev = list->prev;
|
|
+ node->prev->next = node;
|
|
+ list->prev = node;
|
|
+}
|
|
+
|
|
+static void fdevent_plist_remove(fdevent *node)
|
|
+{
|
|
+ node->prev->next = node->next;
|
|
+ node->next->prev = node->prev;
|
|
+ node->next = 0;
|
|
+ node->prev = 0;
|
|
+}
|
|
+
|
|
+static fdevent *fdevent_plist_dequeue(void)
|
|
+{
|
|
+ fdevent *list = &list_pending;
|
|
+ fdevent *node = list->next;
|
|
+
|
|
+ if(node == list) return 0;
|
|
+
|
|
+ list->next = node->next;
|
|
+ list->next->prev = list;
|
|
+ node->next = 0;
|
|
+ node->prev = 0;
|
|
+
|
|
+ return node;
|
|
+}
|
|
+
|
|
+static void fdevent_call_fdfunc(fdevent* fde)
|
|
+{
|
|
+ unsigned events = fde->events;
|
|
+ fde->events = 0;
|
|
+ if(!(fde->state & FDE_PENDING)) return;
|
|
+ fde->state &= (~FDE_PENDING);
|
|
+ dump_fde(fde, "callback");
|
|
+ fde->func(fde->fd, events, fde->arg);
|
|
+}
|
|
+
|
|
+static void fdevent_subproc_event_func(int fd, unsigned ev, void *userdata)
|
|
+{
|
|
+
|
|
+ D("subproc handling on fd=%d ev=%04x\n", fd, ev);
|
|
+
|
|
+ // Hook oneself back into the fde's suitable for select() on read.
|
|
+ if((fd < 0) || (fd >= fd_table_max)) {
|
|
+ FATAL("fd %d out of range for fd_table \n", fd);
|
|
+ }
|
|
+ fdevent *fde = fd_table[fd];
|
|
+ fdevent_add(fde, FDE_READ);
|
|
+
|
|
+ if(ev & FDE_READ){
|
|
+ int subproc_fd;
|
|
+
|
|
+ if(readx(fd, &subproc_fd, sizeof(subproc_fd))) {
|
|
+ FATAL("Failed to read the subproc's fd from fd=%d\n", fd);
|
|
+ }
|
|
+ if((subproc_fd < 0) || (subproc_fd >= fd_table_max)) {
|
|
+ D("subproc_fd %d out of range 0, fd_table_max=%d\n",
|
|
+ subproc_fd, fd_table_max);
|
|
+ return;
|
|
+ }
|
|
+ fdevent *subproc_fde = fd_table[subproc_fd];
|
|
+ if(!subproc_fde) {
|
|
+ D("subproc_fd %d cleared from fd_table\n", subproc_fd);
|
|
+ return;
|
|
+ }
|
|
+ if(subproc_fde->fd != subproc_fd) {
|
|
+ // Already reallocated?
|
|
+ D("subproc_fd %d != fd_table[].fd %d\n", subproc_fd, subproc_fde->fd);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ subproc_fde->force_eof = 1;
|
|
+
|
|
+ int rcount = 0;
|
|
+ ioctl(subproc_fd, FIONREAD, &rcount);
|
|
+ D("subproc with fd=%d has rcount=%d err=%d\n",
|
|
+ subproc_fd, rcount, errno);
|
|
+
|
|
+ if(rcount) {
|
|
+ // If there is data left, it will show up in the select().
|
|
+ // This works because there is no other thread reading that
|
|
+ // data when in this fd_func().
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ D("subproc_fde.state=%04x\n", subproc_fde->state);
|
|
+ subproc_fde->events |= FDE_READ;
|
|
+ if(subproc_fde->state & FDE_PENDING) {
|
|
+ return;
|
|
+ }
|
|
+ subproc_fde->state |= FDE_PENDING;
|
|
+ fdevent_call_fdfunc(subproc_fde);
|
|
+ }
|
|
+}
|
|
+
|
|
+fdevent *fdevent_create(int fd, fd_func func, void *arg)
|
|
+{
|
|
+ fdevent *fde = (fdevent*) malloc(sizeof(fdevent));
|
|
+ if(fde == 0) return 0;
|
|
+ fdevent_install(fde, fd, func, arg);
|
|
+ fde->state |= FDE_CREATED;
|
|
+ return fde;
|
|
+}
|
|
+
|
|
+void fdevent_destroy(fdevent *fde)
|
|
+{
|
|
+ if(fde == 0) return;
|
|
+ if(!(fde->state & FDE_CREATED)) {
|
|
+ FATAL("fde %p not created by fdevent_create()\n", fde);
|
|
+ }
|
|
+ fdevent_remove(fde);
|
|
+}
|
|
+
|
|
+void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg)
|
|
+{
|
|
+ memset(fde, 0, sizeof(fdevent));
|
|
+ fde->state = FDE_ACTIVE;
|
|
+ fde->fd = fd;
|
|
+ fde->force_eof = 0;
|
|
+ fde->func = func;
|
|
+ fde->arg = arg;
|
|
+
|
|
+#ifndef HAVE_WINSOCK
|
|
+ fcntl(fd, F_SETFL, O_NONBLOCK);
|
|
+#endif
|
|
+ fdevent_register(fde);
|
|
+ dump_fde(fde, "connect");
|
|
+ fdevent_connect(fde);
|
|
+ fde->state |= FDE_ACTIVE;
|
|
+}
|
|
+
|
|
+void fdevent_remove(fdevent *fde)
|
|
+{
|
|
+ if(fde->state & FDE_PENDING) {
|
|
+ fdevent_plist_remove(fde);
|
|
+ }
|
|
+
|
|
+ if(fde->state & FDE_ACTIVE) {
|
|
+ fdevent_disconnect(fde);
|
|
+ dump_fde(fde, "disconnect");
|
|
+ fdevent_unregister(fde);
|
|
+ }
|
|
+
|
|
+ fde->state = 0;
|
|
+ fde->events = 0;
|
|
+}
|
|
+
|
|
+
|
|
+void fdevent_set(fdevent *fde, unsigned events)
|
|
+{
|
|
+ events &= FDE_EVENTMASK;
|
|
+
|
|
+ if((fde->state & FDE_EVENTMASK) == events) return;
|
|
+
|
|
+ if(fde->state & FDE_ACTIVE) {
|
|
+ fdevent_update(fde, events);
|
|
+ dump_fde(fde, "update");
|
|
+ }
|
|
+
|
|
+ fde->state = (fde->state & FDE_STATEMASK) | events;
|
|
+
|
|
+ if(fde->state & FDE_PENDING) {
|
|
+ /* if we're pending, make sure
|
|
+ ** we don't signal an event that
|
|
+ ** is no longer wanted.
|
|
+ */
|
|
+ fde->events &= (~events);
|
|
+ if(fde->events == 0) {
|
|
+ fdevent_plist_remove(fde);
|
|
+ fde->state &= (~FDE_PENDING);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+void fdevent_add(fdevent *fde, unsigned events)
|
|
+{
|
|
+ fdevent_set(
|
|
+ fde, (fde->state & FDE_EVENTMASK) | (events & FDE_EVENTMASK));
|
|
+}
|
|
+
|
|
+void fdevent_del(fdevent *fde, unsigned events)
|
|
+{
|
|
+ fdevent_set(
|
|
+ fde, (fde->state & FDE_EVENTMASK) & (~(events & FDE_EVENTMASK)));
|
|
+}
|
|
+
|
|
+void fdevent_subproc_setup()
|
|
+{
|
|
+ int s[2];
|
|
+
|
|
+ if(adb_socketpair(s)) {
|
|
+ FATAL("cannot create shell-exit socket-pair\n");
|
|
+ }
|
|
+ SHELL_EXIT_NOTIFY_FD = s[0];
|
|
+ fdevent *fde;
|
|
+ fde = fdevent_create(s[1], fdevent_subproc_event_func, NULL);
|
|
+ if(!fde)
|
|
+ FATAL("cannot create fdevent for shell-exit handler\n");
|
|
+ fdevent_add(fde, FDE_READ);
|
|
+}
|
|
+
|
|
+void fdevent_loop()
|
|
+{
|
|
+ fdevent *fde;
|
|
+ fdevent_subproc_setup();
|
|
+
|
|
+ for(;;) {
|
|
+ D("--- ---- waiting for events\n");
|
|
+
|
|
+ fdevent_process();
|
|
+
|
|
+ while((fde = fdevent_plist_dequeue())) {
|
|
+ fdevent_call_fdfunc(fde);
|
|
+ }
|
|
+ }
|
|
+}
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/fdevent.h
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/fdevent.h 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,83 @@
|
|
+/*
|
|
+ * Copyright (C) 2006 The Android Open Source Project
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
+ * you may not use this file except in compliance with the License.
|
|
+ * You may obtain a copy of the License at
|
|
+ *
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
+ *
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+ * See the License for the specific language governing permissions and
|
|
+ * limitations under the License.
|
|
+ */
|
|
+
|
|
+#ifndef __FDEVENT_H
|
|
+#define __FDEVENT_H
|
|
+
|
|
+#include <stdint.h> /* for int64_t */
|
|
+
|
|
+/* events that may be observed */
|
|
+#define FDE_READ 0x0001
|
|
+#define FDE_WRITE 0x0002
|
|
+#define FDE_ERROR 0x0004
|
|
+#define FDE_TIMEOUT 0x0008
|
|
+
|
|
+/* features that may be set (via the events set/add/del interface) */
|
|
+#define FDE_DONT_CLOSE 0x0080
|
|
+
|
|
+typedef struct fdevent fdevent;
|
|
+
|
|
+typedef void (*fd_func)(int fd, unsigned events, void *userdata);
|
|
+
|
|
+/* Allocate and initialize a new fdevent object
|
|
+ * Note: use FD_TIMER as 'fd' to create a fd-less object
|
|
+ * (used to implement timers).
|
|
+*/
|
|
+fdevent *fdevent_create(int fd, fd_func func, void *arg);
|
|
+
|
|
+/* Uninitialize and deallocate an fdevent object that was
|
|
+** created by fdevent_create()
|
|
+*/
|
|
+void fdevent_destroy(fdevent *fde);
|
|
+
|
|
+/* Initialize an fdevent object that was externally allocated
|
|
+*/
|
|
+void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg);
|
|
+
|
|
+/* Uninitialize an fdevent object that was initialized by
|
|
+** fdevent_install()
|
|
+*/
|
|
+void fdevent_remove(fdevent *item);
|
|
+
|
|
+/* Change which events should cause notifications
|
|
+*/
|
|
+void fdevent_set(fdevent *fde, unsigned events);
|
|
+void fdevent_add(fdevent *fde, unsigned events);
|
|
+void fdevent_del(fdevent *fde, unsigned events);
|
|
+
|
|
+void fdevent_set_timeout(fdevent *fde, int64_t timeout_ms);
|
|
+
|
|
+/* loop forever, handling events.
|
|
+*/
|
|
+void fdevent_loop();
|
|
+
|
|
+struct fdevent
|
|
+{
|
|
+ fdevent *next;
|
|
+ fdevent *prev;
|
|
+
|
|
+ int fd;
|
|
+ int force_eof;
|
|
+
|
|
+ unsigned short state;
|
|
+ unsigned short events;
|
|
+
|
|
+ fd_func func;
|
|
+ void *arg;
|
|
+};
|
|
+
|
|
+
|
|
+#endif
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/file_sync_client.c
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/file_sync_client.c 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,1024 @@
|
|
+/*
|
|
+ * Copyright (C) 2007 The Android Open Source Project
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
+ * you may not use this file except in compliance with the License.
|
|
+ * You may obtain a copy of the License at
|
|
+ *
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
+ *
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+ * See the License for the specific language governing permissions and
|
|
+ * limitations under the License.
|
|
+ */
|
|
+
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+#include <string.h>
|
|
+#include <errno.h>
|
|
+#include <sys/stat.h>
|
|
+#include <sys/time.h>
|
|
+#include <time.h>
|
|
+#include <dirent.h>
|
|
+#include <limits.h>
|
|
+#include <sys/types.h>
|
|
+#include <zipfile/zipfile.h>
|
|
+
|
|
+#include "sysdeps.h"
|
|
+#include "adb.h"
|
|
+#include "adb_client.h"
|
|
+#include "file_sync_service.h"
|
|
+
|
|
+
|
|
+static unsigned total_bytes;
|
|
+static long long start_time;
|
|
+
|
|
+static long long NOW()
|
|
+{
|
|
+ struct timeval tv;
|
|
+ gettimeofday(&tv, 0);
|
|
+ return ((long long) tv.tv_usec) +
|
|
+ 1000000LL * ((long long) tv.tv_sec);
|
|
+}
|
|
+
|
|
+static void BEGIN()
|
|
+{
|
|
+ total_bytes = 0;
|
|
+ start_time = NOW();
|
|
+}
|
|
+
|
|
+static void END()
|
|
+{
|
|
+ long long t = NOW() - start_time;
|
|
+ if(total_bytes == 0) return;
|
|
+
|
|
+ if (t == 0) /* prevent division by 0 :-) */
|
|
+ t = 1000000;
|
|
+
|
|
+ fprintf(stderr,"%lld KB/s (%lld bytes in %lld.%03llds)\n",
|
|
+ ((((long long) total_bytes) * 1000000LL) / t) / 1024LL,
|
|
+ (long long) total_bytes, (t / 1000000LL), (t % 1000000LL) / 1000LL);
|
|
+}
|
|
+
|
|
+void sync_quit(int fd)
|
|
+{
|
|
+ syncmsg msg;
|
|
+
|
|
+ msg.req.id = ID_QUIT;
|
|
+ msg.req.namelen = 0;
|
|
+
|
|
+ writex(fd, &msg.req, sizeof(msg.req));
|
|
+}
|
|
+
|
|
+typedef void (*sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char *name, void *cookie);
|
|
+
|
|
+int sync_ls(int fd, const char *path, sync_ls_cb func, void *cookie)
|
|
+{
|
|
+ syncmsg msg;
|
|
+ char buf[257];
|
|
+ int len;
|
|
+
|
|
+ len = strlen(path);
|
|
+ if(len > 1024) goto fail;
|
|
+
|
|
+ msg.req.id = ID_LIST;
|
|
+ msg.req.namelen = htoll(len);
|
|
+
|
|
+ if(writex(fd, &msg.req, sizeof(msg.req)) ||
|
|
+ writex(fd, path, len)) {
|
|
+ goto fail;
|
|
+ }
|
|
+
|
|
+ for(;;) {
|
|
+ if(readx(fd, &msg.dent, sizeof(msg.dent))) break;
|
|
+ if(msg.dent.id == ID_DONE) return 0;
|
|
+ if(msg.dent.id != ID_DENT) break;
|
|
+
|
|
+ len = ltohl(msg.dent.namelen);
|
|
+ if(len > 256) break;
|
|
+
|
|
+ if(readx(fd, buf, len)) break;
|
|
+ buf[len] = 0;
|
|
+
|
|
+ func(ltohl(msg.dent.mode),
|
|
+ ltohl(msg.dent.size),
|
|
+ ltohl(msg.dent.time),
|
|
+ buf, cookie);
|
|
+ }
|
|
+
|
|
+fail:
|
|
+ adb_close(fd);
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+typedef struct syncsendbuf syncsendbuf;
|
|
+
|
|
+struct syncsendbuf {
|
|
+ unsigned id;
|
|
+ unsigned size;
|
|
+ char data[SYNC_DATA_MAX];
|
|
+};
|
|
+
|
|
+static syncsendbuf send_buffer;
|
|
+
|
|
+int sync_readtime(int fd, const char *path, unsigned *timestamp)
|
|
+{
|
|
+ syncmsg msg;
|
|
+ int len = strlen(path);
|
|
+
|
|
+ msg.req.id = ID_STAT;
|
|
+ msg.req.namelen = htoll(len);
|
|
+
|
|
+ if(writex(fd, &msg.req, sizeof(msg.req)) ||
|
|
+ writex(fd, path, len)) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if(readx(fd, &msg.stat, sizeof(msg.stat))) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if(msg.stat.id != ID_STAT) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ *timestamp = ltohl(msg.stat.time);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int sync_start_readtime(int fd, const char *path)
|
|
+{
|
|
+ syncmsg msg;
|
|
+ int len = strlen(path);
|
|
+
|
|
+ msg.req.id = ID_STAT;
|
|
+ msg.req.namelen = htoll(len);
|
|
+
|
|
+ if(writex(fd, &msg.req, sizeof(msg.req)) ||
|
|
+ writex(fd, path, len)) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int sync_finish_readtime(int fd, unsigned int *timestamp,
|
|
+ unsigned int *mode, unsigned int *size)
|
|
+{
|
|
+ syncmsg msg;
|
|
+
|
|
+ if(readx(fd, &msg.stat, sizeof(msg.stat)))
|
|
+ return -1;
|
|
+
|
|
+ if(msg.stat.id != ID_STAT)
|
|
+ return -1;
|
|
+
|
|
+ *timestamp = ltohl(msg.stat.time);
|
|
+ *mode = ltohl(msg.stat.mode);
|
|
+ *size = ltohl(msg.stat.size);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int sync_readmode(int fd, const char *path, unsigned *mode)
|
|
+{
|
|
+ syncmsg msg;
|
|
+ int len = strlen(path);
|
|
+
|
|
+ msg.req.id = ID_STAT;
|
|
+ msg.req.namelen = htoll(len);
|
|
+
|
|
+ if(writex(fd, &msg.req, sizeof(msg.req)) ||
|
|
+ writex(fd, path, len)) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if(readx(fd, &msg.stat, sizeof(msg.stat))) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if(msg.stat.id != ID_STAT) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ *mode = ltohl(msg.stat.mode);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int write_data_file(int fd, const char *path, syncsendbuf *sbuf)
|
|
+{
|
|
+ int lfd, err = 0;
|
|
+
|
|
+ lfd = adb_open(path, O_RDONLY);
|
|
+ if(lfd < 0) {
|
|
+ fprintf(stderr,"cannot open '%s': %s\n", path, strerror(errno));
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ sbuf->id = ID_DATA;
|
|
+ for(;;) {
|
|
+ int ret;
|
|
+
|
|
+ ret = adb_read(lfd, sbuf->data, SYNC_DATA_MAX);
|
|
+ if(!ret)
|
|
+ break;
|
|
+
|
|
+ if(ret < 0) {
|
|
+ if(errno == EINTR)
|
|
+ continue;
|
|
+ fprintf(stderr,"cannot read '%s': %s\n", path, strerror(errno));
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ sbuf->size = htoll(ret);
|
|
+ if(writex(fd, sbuf, sizeof(unsigned) * 2 + ret)){
|
|
+ err = -1;
|
|
+ break;
|
|
+ }
|
|
+ total_bytes += ret;
|
|
+ }
|
|
+
|
|
+ adb_close(lfd);
|
|
+ return err;
|
|
+}
|
|
+
|
|
+static int write_data_buffer(int fd, char* file_buffer, int size, syncsendbuf *sbuf)
|
|
+{
|
|
+ int err = 0;
|
|
+ int total = 0;
|
|
+
|
|
+ sbuf->id = ID_DATA;
|
|
+ while (total < size) {
|
|
+ int count = size - total;
|
|
+ if (count > SYNC_DATA_MAX) {
|
|
+ count = SYNC_DATA_MAX;
|
|
+ }
|
|
+
|
|
+ memcpy(sbuf->data, &file_buffer[total], count);
|
|
+ sbuf->size = htoll(count);
|
|
+ if(writex(fd, sbuf, sizeof(unsigned) * 2 + count)){
|
|
+ err = -1;
|
|
+ break;
|
|
+ }
|
|
+ total += count;
|
|
+ total_bytes += count;
|
|
+ }
|
|
+
|
|
+ return err;
|
|
+}
|
|
+
|
|
+#ifdef HAVE_SYMLINKS
|
|
+static int write_data_link(int fd, const char *path, syncsendbuf *sbuf)
|
|
+{
|
|
+ int len, ret;
|
|
+
|
|
+ len = readlink(path, sbuf->data, SYNC_DATA_MAX-1);
|
|
+ if(len < 0) {
|
|
+ fprintf(stderr, "error reading link '%s': %s\n", path, strerror(errno));
|
|
+ return -1;
|
|
+ }
|
|
+ sbuf->data[len] = '\0';
|
|
+
|
|
+ sbuf->size = htoll(len + 1);
|
|
+ sbuf->id = ID_DATA;
|
|
+
|
|
+ ret = writex(fd, sbuf, sizeof(unsigned) * 2 + len + 1);
|
|
+ if(ret)
|
|
+ return -1;
|
|
+
|
|
+ total_bytes += len + 1;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+#endif
|
|
+
|
|
+static int sync_send(int fd, const char *lpath, const char *rpath,
|
|
+ unsigned mtime, mode_t mode, int verifyApk)
|
|
+{
|
|
+ syncmsg msg;
|
|
+ int len, r;
|
|
+ syncsendbuf *sbuf = &send_buffer;
|
|
+ char* file_buffer = NULL;
|
|
+ int size = 0;
|
|
+ char tmp[64];
|
|
+
|
|
+ len = strlen(rpath);
|
|
+ if(len > 1024) goto fail;
|
|
+
|
|
+ snprintf(tmp, sizeof(tmp), ",%d", mode);
|
|
+ r = strlen(tmp);
|
|
+
|
|
+ if (verifyApk) {
|
|
+ int lfd;
|
|
+ zipfile_t zip;
|
|
+ zipentry_t entry;
|
|
+ int amt;
|
|
+
|
|
+ // if we are transferring an APK file, then sanity check to make sure
|
|
+ // we have a real zip file that contains an AndroidManifest.xml
|
|
+ // this requires that we read the entire file into memory.
|
|
+ lfd = adb_open(lpath, O_RDONLY);
|
|
+ if(lfd < 0) {
|
|
+ fprintf(stderr,"cannot open '%s': %s\n", lpath, strerror(errno));
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ size = adb_lseek(lfd, 0, SEEK_END);
|
|
+ if (size == -1 || -1 == adb_lseek(lfd, 0, SEEK_SET)) {
|
|
+ fprintf(stderr, "error seeking in file '%s'\n", lpath);
|
|
+ adb_close(lfd);
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ file_buffer = (char *)malloc(size);
|
|
+ if (file_buffer == NULL) {
|
|
+ fprintf(stderr, "could not allocate buffer for '%s'\n",
|
|
+ lpath);
|
|
+ adb_close(lfd);
|
|
+ return 1;
|
|
+ }
|
|
+ amt = adb_read(lfd, file_buffer, size);
|
|
+ if (amt != size) {
|
|
+ fprintf(stderr, "error reading from file: '%s'\n", lpath);
|
|
+ adb_close(lfd);
|
|
+ free(file_buffer);
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ adb_close(lfd);
|
|
+
|
|
+ zip = init_zipfile(file_buffer, size);
|
|
+ if (zip == NULL) {
|
|
+ fprintf(stderr, "file '%s' is not a valid zip file\n",
|
|
+ lpath);
|
|
+ free(file_buffer);
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ entry = lookup_zipentry(zip, "AndroidManifest.xml");
|
|
+ release_zipfile(zip);
|
|
+ if (entry == NULL) {
|
|
+ fprintf(stderr, "file '%s' does not contain AndroidManifest.xml\n",
|
|
+ lpath);
|
|
+ free(file_buffer);
|
|
+ return 1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ msg.req.id = ID_SEND;
|
|
+ msg.req.namelen = htoll(len + r);
|
|
+
|
|
+ if(writex(fd, &msg.req, sizeof(msg.req)) ||
|
|
+ writex(fd, rpath, len) || writex(fd, tmp, r)) {
|
|
+ free(file_buffer);
|
|
+ goto fail;
|
|
+ }
|
|
+
|
|
+ if (file_buffer) {
|
|
+ write_data_buffer(fd, file_buffer, size, sbuf);
|
|
+ free(file_buffer);
|
|
+ } else if (S_ISREG(mode))
|
|
+ write_data_file(fd, lpath, sbuf);
|
|
+#ifdef HAVE_SYMLINKS
|
|
+ else if (S_ISLNK(mode))
|
|
+ write_data_link(fd, lpath, sbuf);
|
|
+#endif
|
|
+ else
|
|
+ goto fail;
|
|
+
|
|
+ msg.data.id = ID_DONE;
|
|
+ msg.data.size = htoll(mtime);
|
|
+ if(writex(fd, &msg.data, sizeof(msg.data)))
|
|
+ goto fail;
|
|
+
|
|
+ if(readx(fd, &msg.status, sizeof(msg.status)))
|
|
+ return -1;
|
|
+
|
|
+ if(msg.status.id != ID_OKAY) {
|
|
+ if(msg.status.id == ID_FAIL) {
|
|
+ len = ltohl(msg.status.msglen);
|
|
+ if(len > 256) len = 256;
|
|
+ if(readx(fd, sbuf->data, len)) {
|
|
+ return -1;
|
|
+ }
|
|
+ sbuf->data[len] = 0;
|
|
+ } else
|
|
+ strcpy(sbuf->data, "unknown reason");
|
|
+
|
|
+ fprintf(stderr,"failed to copy '%s' to '%s': %s\n", lpath, rpath, sbuf->data);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+
|
|
+fail:
|
|
+ fprintf(stderr,"protocol failure\n");
|
|
+ adb_close(fd);
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+static int mkdirs(char *name)
|
|
+{
|
|
+ int ret;
|
|
+ char *x = name + 1;
|
|
+
|
|
+ for(;;) {
|
|
+ x = adb_dirstart(x);
|
|
+ if(x == 0) return 0;
|
|
+ *x = 0;
|
|
+ ret = adb_mkdir(name, 0775);
|
|
+ *x = OS_PATH_SEPARATOR;
|
|
+ if((ret < 0) && (errno != EEXIST)) {
|
|
+ return ret;
|
|
+ }
|
|
+ x++;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int sync_recv(int fd, const char *rpath, const char *lpath)
|
|
+{
|
|
+ syncmsg msg;
|
|
+ int len;
|
|
+ int lfd = -1;
|
|
+ char *buffer = send_buffer.data;
|
|
+ unsigned id;
|
|
+
|
|
+ len = strlen(rpath);
|
|
+ if(len > 1024) return -1;
|
|
+
|
|
+ msg.req.id = ID_RECV;
|
|
+ msg.req.namelen = htoll(len);
|
|
+ if(writex(fd, &msg.req, sizeof(msg.req)) ||
|
|
+ writex(fd, rpath, len)) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if(readx(fd, &msg.data, sizeof(msg.data))) {
|
|
+ return -1;
|
|
+ }
|
|
+ id = msg.data.id;
|
|
+
|
|
+ if((id == ID_DATA) || (id == ID_DONE)) {
|
|
+ adb_unlink(lpath);
|
|
+ mkdirs((char *)lpath);
|
|
+ lfd = adb_creat(lpath, 0644);
|
|
+ if(lfd < 0) {
|
|
+ fprintf(stderr,"cannot create '%s': %s\n", lpath, strerror(errno));
|
|
+ return -1;
|
|
+ }
|
|
+ goto handle_data;
|
|
+ } else {
|
|
+ goto remote_error;
|
|
+ }
|
|
+
|
|
+ for(;;) {
|
|
+ if(readx(fd, &msg.data, sizeof(msg.data))) {
|
|
+ return -1;
|
|
+ }
|
|
+ id = msg.data.id;
|
|
+
|
|
+ handle_data:
|
|
+ len = ltohl(msg.data.size);
|
|
+ if(id == ID_DONE) break;
|
|
+ if(id != ID_DATA) goto remote_error;
|
|
+ if(len > SYNC_DATA_MAX) {
|
|
+ fprintf(stderr,"data overrun\n");
|
|
+ adb_close(lfd);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if(readx(fd, buffer, len)) {
|
|
+ adb_close(lfd);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if(writex(lfd, buffer, len)) {
|
|
+ fprintf(stderr,"cannot write '%s': %s\n", rpath, strerror(errno));
|
|
+ adb_close(lfd);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ total_bytes += len;
|
|
+ }
|
|
+
|
|
+ adb_close(lfd);
|
|
+ return 0;
|
|
+
|
|
+remote_error:
|
|
+ adb_close(lfd);
|
|
+ adb_unlink(lpath);
|
|
+
|
|
+ if(id == ID_FAIL) {
|
|
+ len = ltohl(msg.data.size);
|
|
+ if(len > 256) len = 256;
|
|
+ if(readx(fd, buffer, len)) {
|
|
+ return -1;
|
|
+ }
|
|
+ buffer[len] = 0;
|
|
+ } else {
|
|
+ memcpy(buffer, &id, 4);
|
|
+ buffer[4] = 0;
|
|
+// strcpy(buffer,"unknown reason");
|
|
+ }
|
|
+ fprintf(stderr,"failed to copy '%s' to '%s': %s\n", rpath, lpath, buffer);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
+
|
|
+/* --- */
|
|
+
|
|
+
|
|
+static void do_sync_ls_cb(unsigned mode, unsigned size, unsigned time,
|
|
+ const char *name, void *cookie)
|
|
+{
|
|
+ printf("%08x %08x %08x %s\n", mode, size, time, name);
|
|
+}
|
|
+
|
|
+int do_sync_ls(const char *path)
|
|
+{
|
|
+ int fd = adb_connect("sync:");
|
|
+ if(fd < 0) {
|
|
+ fprintf(stderr,"error: %s\n", adb_error());
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ if(sync_ls(fd, path, do_sync_ls_cb, 0)) {
|
|
+ return 1;
|
|
+ } else {
|
|
+ sync_quit(fd);
|
|
+ return 0;
|
|
+ }
|
|
+}
|
|
+
|
|
+typedef struct copyinfo copyinfo;
|
|
+
|
|
+struct copyinfo
|
|
+{
|
|
+ copyinfo *next;
|
|
+ const char *src;
|
|
+ const char *dst;
|
|
+ unsigned int time;
|
|
+ unsigned int mode;
|
|
+ unsigned int size;
|
|
+ int flag;
|
|
+ //char data[0];
|
|
+};
|
|
+
|
|
+copyinfo *mkcopyinfo(const char *spath, const char *dpath,
|
|
+ const char *name, int isdir)
|
|
+{
|
|
+ int slen = strlen(spath);
|
|
+ int dlen = strlen(dpath);
|
|
+ int nlen = strlen(name);
|
|
+ int ssize = slen + nlen + 2;
|
|
+ int dsize = dlen + nlen + 2;
|
|
+
|
|
+ copyinfo *ci = malloc(sizeof(copyinfo) + ssize + dsize);
|
|
+ if(ci == 0) {
|
|
+ fprintf(stderr,"out of memory\n");
|
|
+ abort();
|
|
+ }
|
|
+
|
|
+ ci->next = 0;
|
|
+ ci->time = 0;
|
|
+ ci->mode = 0;
|
|
+ ci->size = 0;
|
|
+ ci->flag = 0;
|
|
+ ci->src = (const char*)(ci + 1);
|
|
+ ci->dst = ci->src + ssize;
|
|
+ snprintf((char*) ci->src, ssize, isdir ? "%s%s/" : "%s%s", spath, name);
|
|
+ snprintf((char*) ci->dst, dsize, isdir ? "%s%s/" : "%s%s", dpath, name);
|
|
+
|
|
+// fprintf(stderr,"mkcopyinfo('%s','%s')\n", ci->src, ci->dst);
|
|
+ return ci;
|
|
+}
|
|
+
|
|
+
|
|
+static int local_build_list(copyinfo **filelist,
|
|
+ const char *lpath, const char *rpath)
|
|
+{
|
|
+ DIR *d;
|
|
+ struct dirent *de;
|
|
+ struct stat st;
|
|
+ copyinfo *dirlist = 0;
|
|
+ copyinfo *ci, *next;
|
|
+
|
|
+// fprintf(stderr,"local_build_list('%s','%s')\n", lpath, rpath);
|
|
+
|
|
+ d = opendir(lpath);
|
|
+ if(d == 0) {
|
|
+ fprintf(stderr,"cannot open '%s': %s\n", lpath, strerror(errno));
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ while((de = readdir(d))) {
|
|
+ char stat_path[PATH_MAX];
|
|
+ char *name = de->d_name;
|
|
+
|
|
+ if(name[0] == '.') {
|
|
+ if(name[1] == 0) continue;
|
|
+ if((name[1] == '.') && (name[2] == 0)) continue;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * We could use d_type if HAVE_DIRENT_D_TYPE is defined, but reiserfs
|
|
+ * always returns DT_UNKNOWN, so we just use stat() for all cases.
|
|
+ */
|
|
+ if (strlen(lpath) + strlen(de->d_name) + 1 > sizeof(stat_path))
|
|
+ continue;
|
|
+ strcpy(stat_path, lpath);
|
|
+ strcat(stat_path, de->d_name);
|
|
+ stat(stat_path, &st);
|
|
+
|
|
+ if (S_ISDIR(st.st_mode)) {
|
|
+ ci = mkcopyinfo(lpath, rpath, name, 1);
|
|
+ ci->next = dirlist;
|
|
+ dirlist = ci;
|
|
+ } else {
|
|
+ ci = mkcopyinfo(lpath, rpath, name, 0);
|
|
+ if(lstat(ci->src, &st)) {
|
|
+ fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno));
|
|
+ closedir(d);
|
|
+
|
|
+ return -1;
|
|
+ }
|
|
+ if(!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
|
|
+ fprintf(stderr, "skipping special file '%s'\n", ci->src);
|
|
+ free(ci);
|
|
+ } else {
|
|
+ ci->time = st.st_mtime;
|
|
+ ci->mode = st.st_mode;
|
|
+ ci->size = st.st_size;
|
|
+ ci->next = *filelist;
|
|
+ *filelist = ci;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ closedir(d);
|
|
+
|
|
+ for(ci = dirlist; ci != 0; ci = next) {
|
|
+ next = ci->next;
|
|
+ local_build_list(filelist, ci->src, ci->dst);
|
|
+ free(ci);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
+static int copy_local_dir_remote(int fd, const char *lpath, const char *rpath, int checktimestamps, int listonly)
|
|
+{
|
|
+ copyinfo *filelist = 0;
|
|
+ copyinfo *ci, *next;
|
|
+ int pushed = 0;
|
|
+ int skipped = 0;
|
|
+
|
|
+ if((lpath[0] == 0) || (rpath[0] == 0)) return -1;
|
|
+ if(lpath[strlen(lpath) - 1] != '/') {
|
|
+ int tmplen = strlen(lpath)+2;
|
|
+ char *tmp = malloc(tmplen);
|
|
+ if(tmp == 0) return -1;
|
|
+ snprintf(tmp, tmplen, "%s/",lpath);
|
|
+ lpath = tmp;
|
|
+ }
|
|
+ if(rpath[strlen(rpath) - 1] != '/') {
|
|
+ int tmplen = strlen(rpath)+2;
|
|
+ char *tmp = malloc(tmplen);
|
|
+ if(tmp == 0) return -1;
|
|
+ snprintf(tmp, tmplen, "%s/",rpath);
|
|
+ rpath = tmp;
|
|
+ }
|
|
+
|
|
+ if(local_build_list(&filelist, lpath, rpath)) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if(checktimestamps){
|
|
+ for(ci = filelist; ci != 0; ci = ci->next) {
|
|
+ if(sync_start_readtime(fd, ci->dst)) {
|
|
+ return 1;
|
|
+ }
|
|
+ }
|
|
+ for(ci = filelist; ci != 0; ci = ci->next) {
|
|
+ unsigned int timestamp, mode, size;
|
|
+ if(sync_finish_readtime(fd, ×tamp, &mode, &size))
|
|
+ return 1;
|
|
+ if(size == ci->size) {
|
|
+ /* for links, we cannot update the atime/mtime */
|
|
+ if((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
|
|
+ (S_ISLNK(ci->mode & mode) && timestamp >= ci->time))
|
|
+ ci->flag = 1;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ for(ci = filelist; ci != 0; ci = next) {
|
|
+ next = ci->next;
|
|
+ if(ci->flag == 0) {
|
|
+ fprintf(stderr,"%spush: %s -> %s\n", listonly ? "would " : "", ci->src, ci->dst);
|
|
+ if(!listonly &&
|
|
+ sync_send(fd, ci->src, ci->dst, ci->time, ci->mode, 0 /* no verify APK */)){
|
|
+ return 1;
|
|
+ }
|
|
+ pushed++;
|
|
+ } else {
|
|
+ skipped++;
|
|
+ }
|
|
+ free(ci);
|
|
+ }
|
|
+
|
|
+ fprintf(stderr,"%d file%s pushed. %d file%s skipped.\n",
|
|
+ pushed, (pushed == 1) ? "" : "s",
|
|
+ skipped, (skipped == 1) ? "" : "s");
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
+int do_sync_push(const char *lpath, const char *rpath, int verifyApk)
|
|
+{
|
|
+ struct stat st;
|
|
+ unsigned mode;
|
|
+ int fd;
|
|
+
|
|
+ fd = adb_connect("sync:");
|
|
+ if(fd < 0) {
|
|
+ fprintf(stderr,"error: %s\n", adb_error());
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ if(stat(lpath, &st)) {
|
|
+ fprintf(stderr,"cannot stat '%s': %s\n", lpath, strerror(errno));
|
|
+ sync_quit(fd);
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ if(S_ISDIR(st.st_mode)) {
|
|
+ BEGIN();
|
|
+ if(copy_local_dir_remote(fd, lpath, rpath, 0, 0)) {
|
|
+ return 1;
|
|
+ } else {
|
|
+ END();
|
|
+ sync_quit(fd);
|
|
+ }
|
|
+ } else {
|
|
+ if(sync_readmode(fd, rpath, &mode)) {
|
|
+ return 1;
|
|
+ }
|
|
+ if((mode != 0) && S_ISDIR(mode)) {
|
|
+ /* if we're copying a local file to a remote directory,
|
|
+ ** we *really* want to copy to remotedir + "/" + localfilename
|
|
+ */
|
|
+ const char *name = adb_dirstop(lpath);
|
|
+ if(name == 0) {
|
|
+ name = lpath;
|
|
+ } else {
|
|
+ name++;
|
|
+ }
|
|
+ int tmplen = strlen(name) + strlen(rpath) + 2;
|
|
+ char *tmp = malloc(strlen(name) + strlen(rpath) + 2);
|
|
+ if(tmp == 0) return 1;
|
|
+ snprintf(tmp, tmplen, "%s/%s", rpath, name);
|
|
+ rpath = tmp;
|
|
+ }
|
|
+ BEGIN();
|
|
+ if(sync_send(fd, lpath, rpath, st.st_mtime, st.st_mode, verifyApk)) {
|
|
+ return 1;
|
|
+ } else {
|
|
+ END();
|
|
+ sync_quit(fd);
|
|
+ return 0;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
+typedef struct {
|
|
+ copyinfo **filelist;
|
|
+ copyinfo **dirlist;
|
|
+ const char *rpath;
|
|
+ const char *lpath;
|
|
+} sync_ls_build_list_cb_args;
|
|
+
|
|
+void
|
|
+sync_ls_build_list_cb(unsigned mode, unsigned size, unsigned time,
|
|
+ const char *name, void *cookie)
|
|
+{
|
|
+ sync_ls_build_list_cb_args *args = (sync_ls_build_list_cb_args *)cookie;
|
|
+ copyinfo *ci;
|
|
+
|
|
+ if (S_ISDIR(mode)) {
|
|
+ copyinfo **dirlist = args->dirlist;
|
|
+
|
|
+ /* Don't try recursing down "." or ".." */
|
|
+ if (name[0] == '.') {
|
|
+ if (name[1] == '\0') return;
|
|
+ if ((name[1] == '.') && (name[2] == '\0')) return;
|
|
+ }
|
|
+
|
|
+ ci = mkcopyinfo(args->rpath, args->lpath, name, 1);
|
|
+ ci->next = *dirlist;
|
|
+ *dirlist = ci;
|
|
+ } else if (S_ISREG(mode) || S_ISLNK(mode)) {
|
|
+ copyinfo **filelist = args->filelist;
|
|
+
|
|
+ ci = mkcopyinfo(args->rpath, args->lpath, name, 0);
|
|
+ ci->time = time;
|
|
+ ci->mode = mode;
|
|
+ ci->size = size;
|
|
+ ci->next = *filelist;
|
|
+ *filelist = ci;
|
|
+ } else {
|
|
+ fprintf(stderr, "skipping special file '%s'\n", name);
|
|
+ }
|
|
+}
|
|
+
|
|
+static int remote_build_list(int syncfd, copyinfo **filelist,
|
|
+ const char *rpath, const char *lpath)
|
|
+{
|
|
+ copyinfo *dirlist = NULL;
|
|
+ sync_ls_build_list_cb_args args;
|
|
+
|
|
+ args.filelist = filelist;
|
|
+ args.dirlist = &dirlist;
|
|
+ args.rpath = rpath;
|
|
+ args.lpath = lpath;
|
|
+
|
|
+ /* Put the files/dirs in rpath on the lists. */
|
|
+ if (sync_ls(syncfd, rpath, sync_ls_build_list_cb, (void *)&args)) {
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ /* Recurse into each directory we found. */
|
|
+ while (dirlist != NULL) {
|
|
+ copyinfo *next = dirlist->next;
|
|
+ if (remote_build_list(syncfd, filelist, dirlist->src, dirlist->dst)) {
|
|
+ return 1;
|
|
+ }
|
|
+ free(dirlist);
|
|
+ dirlist = next;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath,
|
|
+ int checktimestamps)
|
|
+{
|
|
+ copyinfo *filelist = 0;
|
|
+ copyinfo *ci, *next;
|
|
+ int pulled = 0;
|
|
+ int skipped = 0;
|
|
+
|
|
+ /* Make sure that both directory paths end in a slash. */
|
|
+ if (rpath[0] == 0 || lpath[0] == 0) return -1;
|
|
+ if (rpath[strlen(rpath) - 1] != '/') {
|
|
+ int tmplen = strlen(rpath) + 2;
|
|
+ char *tmp = malloc(tmplen);
|
|
+ if (tmp == 0) return -1;
|
|
+ snprintf(tmp, tmplen, "%s/", rpath);
|
|
+ rpath = tmp;
|
|
+ }
|
|
+ if (lpath[strlen(lpath) - 1] != '/') {
|
|
+ int tmplen = strlen(lpath) + 2;
|
|
+ char *tmp = malloc(tmplen);
|
|
+ if (tmp == 0) return -1;
|
|
+ snprintf(tmp, tmplen, "%s/", lpath);
|
|
+ lpath = tmp;
|
|
+ }
|
|
+
|
|
+ fprintf(stderr, "pull: building file list...\n");
|
|
+ /* Recursively build the list of files to copy. */
|
|
+ if (remote_build_list(fd, &filelist, rpath, lpath)) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+#if 0
|
|
+ if (checktimestamps) {
|
|
+ for (ci = filelist; ci != 0; ci = ci->next) {
|
|
+ if (sync_start_readtime(fd, ci->dst)) {
|
|
+ return 1;
|
|
+ }
|
|
+ }
|
|
+ for (ci = filelist; ci != 0; ci = ci->next) {
|
|
+ unsigned int timestamp, mode, size;
|
|
+ if (sync_finish_readtime(fd, ×tamp, &mode, &size))
|
|
+ return 1;
|
|
+ if (size == ci->size) {
|
|
+ /* for links, we cannot update the atime/mtime */
|
|
+ if ((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
|
|
+ (S_ISLNK(ci->mode & mode) && timestamp >= ci->time))
|
|
+ ci->flag = 1;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+ for (ci = filelist; ci != 0; ci = next) {
|
|
+ next = ci->next;
|
|
+ if (ci->flag == 0) {
|
|
+ fprintf(stderr, "pull: %s -> %s\n", ci->src, ci->dst);
|
|
+ if (sync_recv(fd, ci->src, ci->dst)) {
|
|
+ return 1;
|
|
+ }
|
|
+ pulled++;
|
|
+ } else {
|
|
+ skipped++;
|
|
+ }
|
|
+ free(ci);
|
|
+ }
|
|
+
|
|
+ fprintf(stderr, "%d file%s pulled. %d file%s skipped.\n",
|
|
+ pulled, (pulled == 1) ? "" : "s",
|
|
+ skipped, (skipped == 1) ? "" : "s");
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int do_sync_pull(const char *rpath, const char *lpath)
|
|
+{
|
|
+ unsigned mode;
|
|
+ struct stat st;
|
|
+
|
|
+ int fd;
|
|
+
|
|
+ fd = adb_connect("sync:");
|
|
+ if(fd < 0) {
|
|
+ fprintf(stderr,"error: %s\n", adb_error());
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ if(sync_readmode(fd, rpath, &mode)) {
|
|
+ return 1;
|
|
+ }
|
|
+ if(mode == 0) {
|
|
+ fprintf(stderr,"remote object '%s' does not exist\n", rpath);
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ if(S_ISREG(mode) || S_ISLNK(mode) || S_ISCHR(mode) || S_ISBLK(mode)) {
|
|
+ if(stat(lpath, &st) == 0) {
|
|
+ if(S_ISDIR(st.st_mode)) {
|
|
+ /* if we're copying a remote file to a local directory,
|
|
+ ** we *really* want to copy to localdir + "/" + remotefilename
|
|
+ */
|
|
+ const char *name = adb_dirstop(rpath);
|
|
+ if(name == 0) {
|
|
+ name = rpath;
|
|
+ } else {
|
|
+ name++;
|
|
+ }
|
|
+ int tmplen = strlen(name) + strlen(lpath) + 2;
|
|
+ char *tmp = malloc(tmplen);
|
|
+ if(tmp == 0) return 1;
|
|
+ snprintf(tmp, tmplen, "%s/%s", lpath, name);
|
|
+ lpath = tmp;
|
|
+ }
|
|
+ }
|
|
+ BEGIN();
|
|
+ if(sync_recv(fd, rpath, lpath)) {
|
|
+ return 1;
|
|
+ } else {
|
|
+ END();
|
|
+ sync_quit(fd);
|
|
+ return 0;
|
|
+ }
|
|
+ } else if(S_ISDIR(mode)) {
|
|
+ BEGIN();
|
|
+ if (copy_remote_dir_local(fd, rpath, lpath, 0)) {
|
|
+ return 1;
|
|
+ } else {
|
|
+ END();
|
|
+ sync_quit(fd);
|
|
+ return 0;
|
|
+ }
|
|
+ } else {
|
|
+ fprintf(stderr,"remote object '%s' not a file or directory\n", rpath);
|
|
+ return 1;
|
|
+ }
|
|
+}
|
|
+
|
|
+int do_sync_sync(const char *lpath, const char *rpath, int listonly)
|
|
+{
|
|
+ fprintf(stderr,"syncing %s...\n",rpath);
|
|
+
|
|
+ int fd = adb_connect("sync:");
|
|
+ if(fd < 0) {
|
|
+ fprintf(stderr,"error: %s\n", adb_error());
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ BEGIN();
|
|
+ if(copy_local_dir_remote(fd, lpath, rpath, 1, listonly)){
|
|
+ return 1;
|
|
+ } else {
|
|
+ END();
|
|
+ sync_quit(fd);
|
|
+ return 0;
|
|
+ }
|
|
+}
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/file_sync_service.c
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/file_sync_service.c 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,414 @@
|
|
+/*
|
|
+ * Copyright (C) 2007 The Android Open Source Project
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
+ * you may not use this file except in compliance with the License.
|
|
+ * You may obtain a copy of the License at
|
|
+ *
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
+ *
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+ * See the License for the specific language governing permissions and
|
|
+ * limitations under the License.
|
|
+ */
|
|
+
|
|
+#include <stdlib.h>
|
|
+#include <stdio.h>
|
|
+#include <string.h>
|
|
+
|
|
+#include <sys/stat.h>
|
|
+#include <sys/types.h>
|
|
+#include <dirent.h>
|
|
+#include <utime.h>
|
|
+
|
|
+#include <errno.h>
|
|
+
|
|
+#include "sysdeps.h"
|
|
+
|
|
+#define TRACE_TAG TRACE_SYNC
|
|
+#include "adb.h"
|
|
+#include "file_sync_service.h"
|
|
+
|
|
+static int mkdirs(char *name)
|
|
+{
|
|
+ int ret;
|
|
+ char *x = name + 1;
|
|
+
|
|
+ if(name[0] != '/') return -1;
|
|
+
|
|
+ for(;;) {
|
|
+ x = adb_dirstart(x);
|
|
+ if(x == 0) return 0;
|
|
+ *x = 0;
|
|
+ ret = adb_mkdir(name, 0775);
|
|
+ if((ret < 0) && (errno != EEXIST)) {
|
|
+ D("mkdir(\"%s\") -> %s\n", name, strerror(errno));
|
|
+ *x = '/';
|
|
+ return ret;
|
|
+ }
|
|
+ *x++ = '/';
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int do_stat(int s, const char *path)
|
|
+{
|
|
+ syncmsg msg;
|
|
+ struct stat st;
|
|
+
|
|
+ msg.stat.id = ID_STAT;
|
|
+
|
|
+ if(lstat(path, &st)) {
|
|
+ msg.stat.mode = 0;
|
|
+ msg.stat.size = 0;
|
|
+ msg.stat.time = 0;
|
|
+ } else {
|
|
+ msg.stat.mode = htoll(st.st_mode);
|
|
+ msg.stat.size = htoll(st.st_size);
|
|
+ msg.stat.time = htoll(st.st_mtime);
|
|
+ }
|
|
+
|
|
+ return writex(s, &msg.stat, sizeof(msg.stat));
|
|
+}
|
|
+
|
|
+static int do_list(int s, const char *path)
|
|
+{
|
|
+ DIR *d;
|
|
+ struct dirent *de;
|
|
+ struct stat st;
|
|
+ syncmsg msg;
|
|
+ int len;
|
|
+
|
|
+ char tmp[1024 + 256 + 1];
|
|
+ char *fname;
|
|
+
|
|
+ len = strlen(path);
|
|
+ memcpy(tmp, path, len);
|
|
+ tmp[len] = '/';
|
|
+ fname = tmp + len + 1;
|
|
+
|
|
+ msg.dent.id = ID_DENT;
|
|
+
|
|
+ d = opendir(path);
|
|
+ if(d == 0) goto done;
|
|
+
|
|
+ while((de = readdir(d))) {
|
|
+ int len = strlen(de->d_name);
|
|
+
|
|
+ /* not supposed to be possible, but
|
|
+ if it does happen, let's not buffer overrun */
|
|
+ if(len > 256) continue;
|
|
+
|
|
+ strcpy(fname, de->d_name);
|
|
+ if(lstat(tmp, &st) == 0) {
|
|
+ msg.dent.mode = htoll(st.st_mode);
|
|
+ msg.dent.size = htoll(st.st_size);
|
|
+ msg.dent.time = htoll(st.st_mtime);
|
|
+ msg.dent.namelen = htoll(len);
|
|
+
|
|
+ if(writex(s, &msg.dent, sizeof(msg.dent)) ||
|
|
+ writex(s, de->d_name, len)) {
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ closedir(d);
|
|
+
|
|
+done:
|
|
+ msg.dent.id = ID_DONE;
|
|
+ msg.dent.mode = 0;
|
|
+ msg.dent.size = 0;
|
|
+ msg.dent.time = 0;
|
|
+ msg.dent.namelen = 0;
|
|
+ return writex(s, &msg.dent, sizeof(msg.dent));
|
|
+}
|
|
+
|
|
+static int fail_message(int s, const char *reason)
|
|
+{
|
|
+ syncmsg msg;
|
|
+ int len = strlen(reason);
|
|
+
|
|
+ D("sync: failure: %s\n", reason);
|
|
+
|
|
+ msg.data.id = ID_FAIL;
|
|
+ msg.data.size = htoll(len);
|
|
+ if(writex(s, &msg.data, sizeof(msg.data)) ||
|
|
+ writex(s, reason, len)) {
|
|
+ return -1;
|
|
+ } else {
|
|
+ return 0;
|
|
+ }
|
|
+}
|
|
+
|
|
+static int fail_errno(int s)
|
|
+{
|
|
+ return fail_message(s, strerror(errno));
|
|
+}
|
|
+
|
|
+static int handle_send_file(int s, char *path, mode_t mode, char *buffer)
|
|
+{
|
|
+ syncmsg msg;
|
|
+ unsigned int timestamp = 0;
|
|
+ int fd;
|
|
+
|
|
+ fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode);
|
|
+ if(fd < 0 && errno == ENOENT) {
|
|
+ mkdirs(path);
|
|
+ fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode);
|
|
+ }
|
|
+ if(fd < 0 && errno == EEXIST) {
|
|
+ fd = adb_open_mode(path, O_WRONLY, mode);
|
|
+ }
|
|
+ if(fd < 0) {
|
|
+ if(fail_errno(s))
|
|
+ return -1;
|
|
+ fd = -1;
|
|
+ }
|
|
+
|
|
+ for(;;) {
|
|
+ unsigned int len;
|
|
+
|
|
+ if(readx(s, &msg.data, sizeof(msg.data)))
|
|
+ goto fail;
|
|
+
|
|
+ if(msg.data.id != ID_DATA) {
|
|
+ if(msg.data.id == ID_DONE) {
|
|
+ timestamp = ltohl(msg.data.size);
|
|
+ break;
|
|
+ }
|
|
+ fail_message(s, "invalid data message");
|
|
+ goto fail;
|
|
+ }
|
|
+ len = ltohl(msg.data.size);
|
|
+ if(len > SYNC_DATA_MAX) {
|
|
+ fail_message(s, "oversize data message");
|
|
+ goto fail;
|
|
+ }
|
|
+ if(readx(s, buffer, len))
|
|
+ goto fail;
|
|
+
|
|
+ if(fd < 0)
|
|
+ continue;
|
|
+ if(writex(fd, buffer, len)) {
|
|
+ int saved_errno = errno;
|
|
+ adb_close(fd);
|
|
+ adb_unlink(path);
|
|
+ fd = -1;
|
|
+ errno = saved_errno;
|
|
+ if(fail_errno(s)) return -1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if(fd >= 0) {
|
|
+ struct utimbuf u;
|
|
+ adb_close(fd);
|
|
+ u.actime = timestamp;
|
|
+ u.modtime = timestamp;
|
|
+ utime(path, &u);
|
|
+
|
|
+ msg.status.id = ID_OKAY;
|
|
+ msg.status.msglen = 0;
|
|
+ if(writex(s, &msg.status, sizeof(msg.status)))
|
|
+ return -1;
|
|
+ }
|
|
+ return 0;
|
|
+
|
|
+fail:
|
|
+ if(fd >= 0)
|
|
+ adb_close(fd);
|
|
+ adb_unlink(path);
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+#ifdef HAVE_SYMLINKS
|
|
+static int handle_send_link(int s, char *path, char *buffer)
|
|
+{
|
|
+ syncmsg msg;
|
|
+ unsigned int len;
|
|
+ int ret;
|
|
+
|
|
+ if(readx(s, &msg.data, sizeof(msg.data)))
|
|
+ return -1;
|
|
+
|
|
+ if(msg.data.id != ID_DATA) {
|
|
+ fail_message(s, "invalid data message: expected ID_DATA");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ len = ltohl(msg.data.size);
|
|
+ if(len > SYNC_DATA_MAX) {
|
|
+ fail_message(s, "oversize data message");
|
|
+ return -1;
|
|
+ }
|
|
+ if(readx(s, buffer, len))
|
|
+ return -1;
|
|
+
|
|
+ ret = symlink(buffer, path);
|
|
+ if(ret && errno == ENOENT) {
|
|
+ mkdirs(path);
|
|
+ ret = symlink(buffer, path);
|
|
+ }
|
|
+ if(ret) {
|
|
+ fail_errno(s);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if(readx(s, &msg.data, sizeof(msg.data)))
|
|
+ return -1;
|
|
+
|
|
+ if(msg.data.id == ID_DONE) {
|
|
+ msg.status.id = ID_OKAY;
|
|
+ msg.status.msglen = 0;
|
|
+ if(writex(s, &msg.status, sizeof(msg.status)))
|
|
+ return -1;
|
|
+ } else {
|
|
+ fail_message(s, "invalid data message: expected ID_DONE");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+#endif /* HAVE_SYMLINKS */
|
|
+
|
|
+static int do_send(int s, char *path, char *buffer)
|
|
+{
|
|
+ char *tmp;
|
|
+ mode_t mode;
|
|
+ int is_link, ret;
|
|
+
|
|
+ tmp = strrchr(path,',');
|
|
+ if(tmp) {
|
|
+ *tmp = 0;
|
|
+ errno = 0;
|
|
+ mode = strtoul(tmp + 1, NULL, 0);
|
|
+#ifndef HAVE_SYMLINKS
|
|
+ is_link = 0;
|
|
+#else
|
|
+ is_link = S_ISLNK(mode);
|
|
+#endif
|
|
+ mode &= 0777;
|
|
+ }
|
|
+ if(!tmp || errno) {
|
|
+ mode = 0644;
|
|
+ is_link = 0;
|
|
+ }
|
|
+
|
|
+ adb_unlink(path);
|
|
+
|
|
+
|
|
+#ifdef HAVE_SYMLINKS
|
|
+ if(is_link)
|
|
+ ret = handle_send_link(s, path, buffer);
|
|
+ else {
|
|
+#else
|
|
+ {
|
|
+#endif
|
|
+ /* copy user permission bits to "group" and "other" permissions */
|
|
+ mode |= ((mode >> 3) & 0070);
|
|
+ mode |= ((mode >> 3) & 0007);
|
|
+
|
|
+ ret = handle_send_file(s, path, mode, buffer);
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int do_recv(int s, const char *path, char *buffer)
|
|
+{
|
|
+ syncmsg msg;
|
|
+ int fd, r;
|
|
+
|
|
+ fd = adb_open(path, O_RDONLY);
|
|
+ if(fd < 0) {
|
|
+ if(fail_errno(s)) return -1;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ msg.data.id = ID_DATA;
|
|
+ for(;;) {
|
|
+ r = adb_read(fd, buffer, SYNC_DATA_MAX);
|
|
+ if(r <= 0) {
|
|
+ if(r == 0) break;
|
|
+ if(errno == EINTR) continue;
|
|
+ r = fail_errno(s);
|
|
+ adb_close(fd);
|
|
+ return r;
|
|
+ }
|
|
+ msg.data.size = htoll(r);
|
|
+ if(writex(s, &msg.data, sizeof(msg.data)) ||
|
|
+ writex(s, buffer, r)) {
|
|
+ adb_close(fd);
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ adb_close(fd);
|
|
+
|
|
+ msg.data.id = ID_DONE;
|
|
+ msg.data.size = 0;
|
|
+ if(writex(s, &msg.data, sizeof(msg.data))) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void file_sync_service(int fd, void *cookie)
|
|
+{
|
|
+ syncmsg msg;
|
|
+ char name[1025];
|
|
+ unsigned namelen;
|
|
+
|
|
+ char *buffer = malloc(SYNC_DATA_MAX);
|
|
+ if(buffer == 0) goto fail;
|
|
+
|
|
+ for(;;) {
|
|
+ D("sync: waiting for command\n");
|
|
+
|
|
+ if(readx(fd, &msg.req, sizeof(msg.req))) {
|
|
+ fail_message(fd, "command read failure");
|
|
+ break;
|
|
+ }
|
|
+ namelen = ltohl(msg.req.namelen);
|
|
+ if(namelen > 1024) {
|
|
+ fail_message(fd, "invalid namelen");
|
|
+ break;
|
|
+ }
|
|
+ if(readx(fd, name, namelen)) {
|
|
+ fail_message(fd, "filename read failure");
|
|
+ break;
|
|
+ }
|
|
+ name[namelen] = 0;
|
|
+
|
|
+ msg.req.namelen = 0;
|
|
+ D("sync: '%s' '%s'\n", (char*) &msg.req, name);
|
|
+
|
|
+ switch(msg.req.id) {
|
|
+ case ID_STAT:
|
|
+ if(do_stat(fd, name)) goto fail;
|
|
+ break;
|
|
+ case ID_LIST:
|
|
+ if(do_list(fd, name)) goto fail;
|
|
+ break;
|
|
+ case ID_SEND:
|
|
+ if(do_send(fd, name, buffer)) goto fail;
|
|
+ break;
|
|
+ case ID_RECV:
|
|
+ if(do_recv(fd, name, buffer)) goto fail;
|
|
+ break;
|
|
+ case ID_QUIT:
|
|
+ goto fail;
|
|
+ default:
|
|
+ fail_message(fd, "unknown command");
|
|
+ goto fail;
|
|
+ }
|
|
+ }
|
|
+
|
|
+fail:
|
|
+ if(buffer != 0) free(buffer);
|
|
+ D("sync: done\n");
|
|
+ adb_close(fd);
|
|
+}
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/file_sync_service.h
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/file_sync_service.h 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,87 @@
|
|
+/*
|
|
+ * Copyright (C) 2007 The Android Open Source Project
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
+ * you may not use this file except in compliance with the License.
|
|
+ * You may obtain a copy of the License at
|
|
+ *
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
+ *
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+ * See the License for the specific language governing permissions and
|
|
+ * limitations under the License.
|
|
+ */
|
|
+
|
|
+#ifndef _FILE_SYNC_SERVICE_H_
|
|
+#define _FILE_SYNC_SERVICE_H_
|
|
+
|
|
+#ifdef HAVE_BIG_ENDIAN
|
|
+static inline unsigned __swap_uint32(unsigned x)
|
|
+{
|
|
+ return (((x) & 0xFF000000) >> 24)
|
|
+ | (((x) & 0x00FF0000) >> 8)
|
|
+ | (((x) & 0x0000FF00) << 8)
|
|
+ | (((x) & 0x000000FF) << 24);
|
|
+}
|
|
+#define htoll(x) __swap_uint32(x)
|
|
+#define ltohl(x) __swap_uint32(x)
|
|
+#define MKID(a,b,c,d) ((d) | ((c) << 8) | ((b) << 16) | ((a) << 24))
|
|
+#else
|
|
+#define htoll(x) (x)
|
|
+#define ltohl(x) (x)
|
|
+#define MKID(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24))
|
|
+#endif
|
|
+
|
|
+#define ID_STAT MKID('S','T','A','T')
|
|
+#define ID_LIST MKID('L','I','S','T')
|
|
+#define ID_ULNK MKID('U','L','N','K')
|
|
+#define ID_SEND MKID('S','E','N','D')
|
|
+#define ID_RECV MKID('R','E','C','V')
|
|
+#define ID_DENT MKID('D','E','N','T')
|
|
+#define ID_DONE MKID('D','O','N','E')
|
|
+#define ID_DATA MKID('D','A','T','A')
|
|
+#define ID_OKAY MKID('O','K','A','Y')
|
|
+#define ID_FAIL MKID('F','A','I','L')
|
|
+#define ID_QUIT MKID('Q','U','I','T')
|
|
+
|
|
+typedef union {
|
|
+ unsigned id;
|
|
+ struct {
|
|
+ unsigned id;
|
|
+ unsigned namelen;
|
|
+ } req;
|
|
+ struct {
|
|
+ unsigned id;
|
|
+ unsigned mode;
|
|
+ unsigned size;
|
|
+ unsigned time;
|
|
+ } stat;
|
|
+ struct {
|
|
+ unsigned id;
|
|
+ unsigned mode;
|
|
+ unsigned size;
|
|
+ unsigned time;
|
|
+ unsigned namelen;
|
|
+ } dent;
|
|
+ struct {
|
|
+ unsigned id;
|
|
+ unsigned size;
|
|
+ } data;
|
|
+ struct {
|
|
+ unsigned id;
|
|
+ unsigned msglen;
|
|
+ } status;
|
|
+} syncmsg;
|
|
+
|
|
+
|
|
+void file_sync_service(int fd, void *cookie);
|
|
+int do_sync_ls(const char *path);
|
|
+int do_sync_push(const char *lpath, const char *rpath, int verifyApk);
|
|
+int do_sync_sync(const char *lpath, const char *rpath, int listonly);
|
|
+int do_sync_pull(const char *rpath, const char *lpath);
|
|
+
|
|
+#define SYNC_DATA_MAX (64*1024)
|
|
+
|
|
+#endif
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/framebuffer_service.c
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/framebuffer_service.c 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,180 @@
|
|
+/*
|
|
+ * Copyright (C) 2007 The Android Open Source Project
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
+ * you may not use this file except in compliance with the License.
|
|
+ * You may obtain a copy of the License at
|
|
+ *
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
+ *
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+ * See the License for the specific language governing permissions and
|
|
+ * limitations under the License.
|
|
+ */
|
|
+
|
|
+#include <stdlib.h>
|
|
+#include <stdio.h>
|
|
+#include <unistd.h>
|
|
+#include <string.h>
|
|
+#include <fcntl.h>
|
|
+#include <errno.h>
|
|
+#include <sys/types.h>
|
|
+#include <sys/wait.h>
|
|
+
|
|
+#include "fdevent.h"
|
|
+#include "adb.h"
|
|
+
|
|
+#include <linux/fb.h>
|
|
+#include <sys/ioctl.h>
|
|
+#include <sys/mman.h>
|
|
+
|
|
+/* TODO:
|
|
+** - sync with vsync to avoid tearing
|
|
+*/
|
|
+/* This version number defines the format of the fbinfo struct.
|
|
+ It must match versioning in ddms where this data is consumed. */
|
|
+#define DDMS_RAWIMAGE_VERSION 1
|
|
+struct fbinfo {
|
|
+ unsigned int version;
|
|
+ unsigned int bpp;
|
|
+ unsigned int size;
|
|
+ unsigned int width;
|
|
+ unsigned int height;
|
|
+ unsigned int red_offset;
|
|
+ unsigned int red_length;
|
|
+ unsigned int blue_offset;
|
|
+ unsigned int blue_length;
|
|
+ unsigned int green_offset;
|
|
+ unsigned int green_length;
|
|
+ unsigned int alpha_offset;
|
|
+ unsigned int alpha_length;
|
|
+} __attribute__((packed));
|
|
+
|
|
+void framebuffer_service(int fd, void *cookie)
|
|
+{
|
|
+ struct fbinfo fbinfo;
|
|
+ unsigned int i;
|
|
+ char buf[640];
|
|
+ int fd_screencap;
|
|
+ int w, h, f;
|
|
+ int fds[2];
|
|
+
|
|
+ if (pipe(fds) < 0) goto done;
|
|
+
|
|
+ pid_t pid = fork();
|
|
+ if (pid < 0) goto done;
|
|
+
|
|
+ if (pid == 0) {
|
|
+ dup2(fds[1], STDOUT_FILENO);
|
|
+ close(fds[0]);
|
|
+ close(fds[1]);
|
|
+ const char* command = "screencap";
|
|
+ const char *args[2] = {command, NULL};
|
|
+ execvp(command, (char**)args);
|
|
+ exit(1);
|
|
+ }
|
|
+
|
|
+ fd_screencap = fds[0];
|
|
+
|
|
+ /* read w, h & format */
|
|
+ if(readx(fd_screencap, &w, 4)) goto done;
|
|
+ if(readx(fd_screencap, &h, 4)) goto done;
|
|
+ if(readx(fd_screencap, &f, 4)) goto done;
|
|
+
|
|
+ fbinfo.version = DDMS_RAWIMAGE_VERSION;
|
|
+ /* see hardware/hardware.h */
|
|
+ switch (f) {
|
|
+ case 1: /* RGBA_8888 */
|
|
+ fbinfo.bpp = 32;
|
|
+ fbinfo.size = w * h * 4;
|
|
+ fbinfo.width = w;
|
|
+ fbinfo.height = h;
|
|
+ fbinfo.red_offset = 0;
|
|
+ fbinfo.red_length = 8;
|
|
+ fbinfo.green_offset = 8;
|
|
+ fbinfo.green_length = 8;
|
|
+ fbinfo.blue_offset = 16;
|
|
+ fbinfo.blue_length = 8;
|
|
+ fbinfo.alpha_offset = 24;
|
|
+ fbinfo.alpha_length = 8;
|
|
+ break;
|
|
+ case 2: /* RGBX_8888 */
|
|
+ fbinfo.bpp = 32;
|
|
+ fbinfo.size = w * h * 4;
|
|
+ fbinfo.width = w;
|
|
+ fbinfo.height = h;
|
|
+ fbinfo.red_offset = 0;
|
|
+ fbinfo.red_length = 8;
|
|
+ fbinfo.green_offset = 8;
|
|
+ fbinfo.green_length = 8;
|
|
+ fbinfo.blue_offset = 16;
|
|
+ fbinfo.blue_length = 8;
|
|
+ fbinfo.alpha_offset = 24;
|
|
+ fbinfo.alpha_length = 0;
|
|
+ break;
|
|
+ case 3: /* RGB_888 */
|
|
+ fbinfo.bpp = 24;
|
|
+ fbinfo.size = w * h * 3;
|
|
+ fbinfo.width = w;
|
|
+ fbinfo.height = h;
|
|
+ fbinfo.red_offset = 0;
|
|
+ fbinfo.red_length = 8;
|
|
+ fbinfo.green_offset = 8;
|
|
+ fbinfo.green_length = 8;
|
|
+ fbinfo.blue_offset = 16;
|
|
+ fbinfo.blue_length = 8;
|
|
+ fbinfo.alpha_offset = 24;
|
|
+ fbinfo.alpha_length = 0;
|
|
+ break;
|
|
+ case 4: /* RGB_565 */
|
|
+ fbinfo.bpp = 16;
|
|
+ fbinfo.size = w * h * 2;
|
|
+ fbinfo.width = w;
|
|
+ fbinfo.height = h;
|
|
+ fbinfo.red_offset = 11;
|
|
+ fbinfo.red_length = 5;
|
|
+ fbinfo.green_offset = 5;
|
|
+ fbinfo.green_length = 6;
|
|
+ fbinfo.blue_offset = 0;
|
|
+ fbinfo.blue_length = 5;
|
|
+ fbinfo.alpha_offset = 0;
|
|
+ fbinfo.alpha_length = 0;
|
|
+ break;
|
|
+ case 5: /* BGRA_8888 */
|
|
+ fbinfo.bpp = 32;
|
|
+ fbinfo.size = w * h * 4;
|
|
+ fbinfo.width = w;
|
|
+ fbinfo.height = h;
|
|
+ fbinfo.red_offset = 16;
|
|
+ fbinfo.red_length = 8;
|
|
+ fbinfo.green_offset = 8;
|
|
+ fbinfo.green_length = 8;
|
|
+ fbinfo.blue_offset = 0;
|
|
+ fbinfo.blue_length = 8;
|
|
+ fbinfo.alpha_offset = 24;
|
|
+ fbinfo.alpha_length = 8;
|
|
+ break;
|
|
+ default:
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ /* write header */
|
|
+ if(writex(fd, &fbinfo, sizeof(fbinfo))) goto done;
|
|
+
|
|
+ /* write data */
|
|
+ for(i = 0; i < fbinfo.size; i += sizeof(buf)) {
|
|
+ if(readx(fd_screencap, buf, sizeof(buf))) goto done;
|
|
+ if(writex(fd, buf, sizeof(buf))) goto done;
|
|
+ }
|
|
+ if(readx(fd_screencap, buf, fbinfo.size % sizeof(buf))) goto done;
|
|
+ if(writex(fd, buf, fbinfo.size % sizeof(buf))) goto done;
|
|
+
|
|
+done:
|
|
+ TEMP_FAILURE_RETRY(waitpid(pid, NULL, 0));
|
|
+
|
|
+ close(fds[0]);
|
|
+ close(fds[1]);
|
|
+ close(fd);
|
|
+}
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/get_my_path_darwin.c
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/get_my_path_darwin.c 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,30 @@
|
|
+/*
|
|
+ * Copyright (C) 2007 The Android Open Source Project
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
+ * you may not use this file except in compliance with the License.
|
|
+ * You may obtain a copy of the License at
|
|
+ *
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
+ *
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+ * See the License for the specific language governing permissions and
|
|
+ * limitations under the License.
|
|
+ */
|
|
+
|
|
+#import <Carbon/Carbon.h>
|
|
+#include <unistd.h>
|
|
+
|
|
+void get_my_path(char *s, size_t maxLen)
|
|
+{
|
|
+ ProcessSerialNumber psn;
|
|
+ GetCurrentProcess(&psn);
|
|
+ CFDictionaryRef dict;
|
|
+ dict = ProcessInformationCopyDictionary(&psn, 0xffffffff);
|
|
+ CFStringRef value = (CFStringRef)CFDictionaryGetValue(dict,
|
|
+ CFSTR("CFBundleExecutable"));
|
|
+ CFStringGetCString(value, s, maxLen, kCFStringEncodingUTF8);
|
|
+}
|
|
+
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/get_my_path_freebsd.c
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/get_my_path_freebsd.c 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,36 @@
|
|
+/*
|
|
+ * Copyright (C) 2009 bsdroid project
|
|
+ * Alexey Tarasov <tarasov@dodologics.com>
|
|
+ *
|
|
+ * Copyright (C) 2007 The Android Open Source Project
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
+ * you may not use this file except in compliance with the License.
|
|
+ * You may obtain a copy of the License at
|
|
+ *
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
+ *
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+ * See the License for the specific language governing permissions and
|
|
+ * limitations under the License.
|
|
+ */
|
|
+
|
|
+#include <sys/types.h>
|
|
+#include <unistd.h>
|
|
+#include <limits.h>
|
|
+#include <stdio.h>
|
|
+
|
|
+void
|
|
+get_my_path(char *exe, size_t maxLen)
|
|
+{
|
|
+ char proc[64];
|
|
+
|
|
+ snprintf(proc, sizeof(proc), "/proc/%d/file", getpid());
|
|
+
|
|
+ int err = readlink(proc, exe, maxLen - 1);
|
|
+
|
|
+ exe[err > 0 ? err : 0] = '\0';
|
|
+}
|
|
+
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/get_my_path_linux.c
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/get_my_path_linux.c 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,33 @@
|
|
+/*
|
|
+ * Copyright (C) 2007 The Android Open Source Project
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
+ * you may not use this file except in compliance with the License.
|
|
+ * You may obtain a copy of the License at
|
|
+ *
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
+ *
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+ * See the License for the specific language governing permissions and
|
|
+ * limitations under the License.
|
|
+ */
|
|
+
|
|
+#include <sys/types.h>
|
|
+#include <unistd.h>
|
|
+#include <limits.h>
|
|
+#include <stdio.h>
|
|
+
|
|
+void get_my_path(char *exe, size_t maxLen)
|
|
+{
|
|
+ char proc[64];
|
|
+ snprintf(proc, sizeof proc, "/proc/%d/exe", getpid());
|
|
+ int err = readlink(proc, exe, maxLen - 1);
|
|
+ if(err > 0) {
|
|
+ exe[err] = '\0';
|
|
+ } else {
|
|
+ exe[0] = '\0';
|
|
+ }
|
|
+}
|
|
+
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/get_my_path_windows.c
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/get_my_path_windows.c 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,34 @@
|
|
+/*
|
|
+ * Copyright (C) 2007 The Android Open Source Project
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
+ * you may not use this file except in compliance with the License.
|
|
+ * You may obtain a copy of the License at
|
|
+ *
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
+ *
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+ * See the License for the specific language governing permissions and
|
|
+ * limitations under the License.
|
|
+ */
|
|
+
|
|
+#include <limits.h>
|
|
+#include <assert.h>
|
|
+#include <windows.h>
|
|
+
|
|
+void get_my_path(char *exe, size_t maxLen)
|
|
+{
|
|
+ char *r;
|
|
+
|
|
+ /* XXX: should be GetModuleFileNameA */
|
|
+ if (GetModuleFileName(NULL, exe, maxLen) > 0) {
|
|
+ r = strrchr(exe, '\\');
|
|
+ if (r != NULL)
|
|
+ *r = '\0';
|
|
+ } else {
|
|
+ exe[0] = '\0';
|
|
+ }
|
|
+}
|
|
+
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/jdwp_service.c
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/jdwp_service.c 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,735 @@
|
|
+/* implement the "debug-ports" and "track-debug-ports" device services */
|
|
+#include "sysdeps.h"
|
|
+#define TRACE_TAG TRACE_JDWP
|
|
+#include "adb.h"
|
|
+#include <errno.h>
|
|
+#include <stdio.h>
|
|
+#include <string.h>
|
|
+#include <unistd.h>
|
|
+
|
|
+/* here's how these things work.
|
|
+
|
|
+ when adbd starts, it creates a unix server socket
|
|
+ named @vm-debug-control (@ is a shortcut for "first byte is zero"
|
|
+ to use the private namespace instead of the file system)
|
|
+
|
|
+ when a new JDWP daemon thread starts in a new VM process, it creates
|
|
+ a connection to @vm-debug-control to announce its availability.
|
|
+
|
|
+
|
|
+ JDWP thread @vm-debug-control
|
|
+ | |
|
|
+ |-------------------------------> |
|
|
+ | hello I'm in process <pid> |
|
|
+ | |
|
|
+ | |
|
|
+
|
|
+ the connection is kept alive. it will be closed automatically if
|
|
+ the JDWP process terminates (this allows adbd to detect dead
|
|
+ processes).
|
|
+
|
|
+ adbd thus maintains a list of "active" JDWP processes. it can send
|
|
+ its content to clients through the "device:debug-ports" service,
|
|
+ or even updates through the "device:track-debug-ports" service.
|
|
+
|
|
+ when a debugger wants to connect, it simply runs the command
|
|
+ equivalent to "adb forward tcp:<hostport> jdwp:<pid>"
|
|
+
|
|
+ "jdwp:<pid>" is a new forward destination format used to target
|
|
+ a given JDWP process on the device. when sutch a request arrives,
|
|
+ adbd does the following:
|
|
+
|
|
+ - first, it calls socketpair() to create a pair of equivalent
|
|
+ sockets.
|
|
+
|
|
+ - it attaches the first socket in the pair to a local socket
|
|
+ which is itself attached to the transport's remote socket:
|
|
+
|
|
+
|
|
+ - it sends the file descriptor of the second socket directly
|
|
+ to the JDWP process with the help of sendmsg()
|
|
+
|
|
+
|
|
+ JDWP thread @vm-debug-control
|
|
+ | |
|
|
+ | <----------------------|
|
|
+ | OK, try this file descriptor |
|
|
+ | |
|
|
+ | |
|
|
+
|
|
+ then, the JDWP thread uses this new socket descriptor as its
|
|
+ pass-through connection to the debugger (and receives the
|
|
+ JDWP-Handshake message, answers to it, etc...)
|
|
+
|
|
+ this gives the following graphics:
|
|
+ ____________________________________
|
|
+ | |
|
|
+ | ADB Server (host) |
|
|
+ | |
|
|
+ Debugger <---> LocalSocket <----> RemoteSocket |
|
|
+ | ^^ |
|
|
+ |___________________________||_______|
|
|
+ ||
|
|
+ Transport ||
|
|
+ (TCP for emulator - USB for device) ||
|
|
+ ||
|
|
+ ___________________________||_______
|
|
+ | || |
|
|
+ | ADBD (device) || |
|
|
+ | VV |
|
|
+ JDWP <======> LocalSocket <----> RemoteSocket |
|
|
+ | |
|
|
+ |____________________________________|
|
|
+
|
|
+ due to the way adb works, this doesn't need a special socket
|
|
+ type or fancy handling of socket termination if either the debugger
|
|
+ or the JDWP process closes the connection.
|
|
+
|
|
+ THIS IS THE SIMPLEST IMPLEMENTATION I COULD FIND, IF YOU HAPPEN
|
|
+ TO HAVE A BETTER IDEA, LET ME KNOW - Digit
|
|
+
|
|
+**********************************************************************/
|
|
+
|
|
+/** JDWP PID List Support Code
|
|
+ ** for each JDWP process, we record its pid and its connected socket
|
|
+ **/
|
|
+
|
|
+#define MAX_OUT_FDS 4
|
|
+
|
|
+#if !ADB_HOST
|
|
+
|
|
+#include <sys/socket.h>
|
|
+#include <sys/un.h>
|
|
+
|
|
+typedef struct JdwpProcess JdwpProcess;
|
|
+struct JdwpProcess {
|
|
+ JdwpProcess* next;
|
|
+ JdwpProcess* prev;
|
|
+ int pid;
|
|
+ int socket;
|
|
+ fdevent* fde;
|
|
+
|
|
+ char in_buff[4]; /* input character to read PID */
|
|
+ int in_len; /* number from JDWP process */
|
|
+
|
|
+ int out_fds[MAX_OUT_FDS]; /* output array of file descriptors */
|
|
+ int out_count; /* to send to the JDWP process */
|
|
+};
|
|
+
|
|
+static JdwpProcess _jdwp_list;
|
|
+
|
|
+static int
|
|
+jdwp_process_list( char* buffer, int bufferlen )
|
|
+{
|
|
+ char* end = buffer + bufferlen;
|
|
+ char* p = buffer;
|
|
+ JdwpProcess* proc = _jdwp_list.next;
|
|
+
|
|
+ for ( ; proc != &_jdwp_list; proc = proc->next ) {
|
|
+ int len;
|
|
+
|
|
+ /* skip transient connections */
|
|
+ if (proc->pid < 0)
|
|
+ continue;
|
|
+
|
|
+ len = snprintf(p, end-p, "%d\n", proc->pid);
|
|
+ if (p + len >= end)
|
|
+ break;
|
|
+ p += len;
|
|
+ }
|
|
+ p[0] = 0;
|
|
+ return (p - buffer);
|
|
+}
|
|
+
|
|
+
|
|
+static int
|
|
+jdwp_process_list_msg( char* buffer, int bufferlen )
|
|
+{
|
|
+ char head[5];
|
|
+ int len = jdwp_process_list( buffer+4, bufferlen-4 );
|
|
+ snprintf(head, sizeof head, "%04x", len);
|
|
+ memcpy(buffer, head, 4);
|
|
+ return len + 4;
|
|
+}
|
|
+
|
|
+
|
|
+static void jdwp_process_list_updated(void);
|
|
+
|
|
+static void
|
|
+jdwp_process_free( JdwpProcess* proc )
|
|
+{
|
|
+ if (proc) {
|
|
+ int n;
|
|
+
|
|
+ proc->prev->next = proc->next;
|
|
+ proc->next->prev = proc->prev;
|
|
+
|
|
+ if (proc->socket >= 0) {
|
|
+ adb_shutdown(proc->socket);
|
|
+ adb_close(proc->socket);
|
|
+ proc->socket = -1;
|
|
+ }
|
|
+
|
|
+ if (proc->fde != NULL) {
|
|
+ fdevent_destroy(proc->fde);
|
|
+ proc->fde = NULL;
|
|
+ }
|
|
+ proc->pid = -1;
|
|
+
|
|
+ for (n = 0; n < proc->out_count; n++) {
|
|
+ adb_close(proc->out_fds[n]);
|
|
+ }
|
|
+ proc->out_count = 0;
|
|
+
|
|
+ free(proc);
|
|
+
|
|
+ jdwp_process_list_updated();
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+static void jdwp_process_event(int, unsigned, void*); /* forward */
|
|
+
|
|
+
|
|
+static JdwpProcess*
|
|
+jdwp_process_alloc( int socket )
|
|
+{
|
|
+ JdwpProcess* proc = calloc(1,sizeof(*proc));
|
|
+
|
|
+ if (proc == NULL) {
|
|
+ D("not enough memory to create new JDWP process\n");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ proc->socket = socket;
|
|
+ proc->pid = -1;
|
|
+ proc->next = proc;
|
|
+ proc->prev = proc;
|
|
+
|
|
+ proc->fde = fdevent_create( socket, jdwp_process_event, proc );
|
|
+ if (proc->fde == NULL) {
|
|
+ D("could not create fdevent for new JDWP process\n" );
|
|
+ free(proc);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ proc->fde->state |= FDE_DONT_CLOSE;
|
|
+ proc->in_len = 0;
|
|
+ proc->out_count = 0;
|
|
+
|
|
+ /* append to list */
|
|
+ proc->next = &_jdwp_list;
|
|
+ proc->prev = proc->next->prev;
|
|
+
|
|
+ proc->prev->next = proc;
|
|
+ proc->next->prev = proc;
|
|
+
|
|
+ /* start by waiting for the PID */
|
|
+ fdevent_add(proc->fde, FDE_READ);
|
|
+
|
|
+ return proc;
|
|
+}
|
|
+
|
|
+
|
|
+static void
|
|
+jdwp_process_event( int socket, unsigned events, void* _proc )
|
|
+{
|
|
+ JdwpProcess* proc = _proc;
|
|
+
|
|
+ if (events & FDE_READ) {
|
|
+ if (proc->pid < 0) {
|
|
+ /* read the PID as a 4-hexchar string */
|
|
+ char* p = proc->in_buff + proc->in_len;
|
|
+ int size = 4 - proc->in_len;
|
|
+ char temp[5];
|
|
+ while (size > 0) {
|
|
+ int len = recv( socket, p, size, 0 );
|
|
+ if (len < 0) {
|
|
+ if (errno == EINTR)
|
|
+ continue;
|
|
+ if (errno == EAGAIN)
|
|
+ return;
|
|
+ /* this can fail here if the JDWP process crashes very fast */
|
|
+ D("weird unknown JDWP process failure: %s\n",
|
|
+ strerror(errno));
|
|
+
|
|
+ goto CloseProcess;
|
|
+ }
|
|
+ if (len == 0) { /* end of stream ? */
|
|
+ D("weird end-of-stream from unknown JDWP process\n");
|
|
+ goto CloseProcess;
|
|
+ }
|
|
+ p += len;
|
|
+ proc->in_len += len;
|
|
+ size -= len;
|
|
+ }
|
|
+ /* we have read 4 characters, now decode the pid */
|
|
+ memcpy(temp, proc->in_buff, 4);
|
|
+ temp[4] = 0;
|
|
+
|
|
+ if (sscanf( temp, "%04x", &proc->pid ) != 1) {
|
|
+ D("could not decode JDWP %p PID number: '%s'\n", proc, temp);
|
|
+ goto CloseProcess;
|
|
+ }
|
|
+
|
|
+ /* all is well, keep reading to detect connection closure */
|
|
+ D("Adding pid %d to jdwp process list\n", proc->pid);
|
|
+ jdwp_process_list_updated();
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ /* the pid was read, if we get there it's probably because the connection
|
|
+ * was closed (e.g. the JDWP process exited or crashed) */
|
|
+ char buf[32];
|
|
+
|
|
+ for (;;) {
|
|
+ int len = recv(socket, buf, sizeof(buf), 0);
|
|
+
|
|
+ if (len <= 0) {
|
|
+ if (len < 0 && errno == EINTR)
|
|
+ continue;
|
|
+ if (len < 0 && errno == EAGAIN)
|
|
+ return;
|
|
+ else {
|
|
+ D("terminating JDWP %d connection: %s\n", proc->pid,
|
|
+ strerror(errno));
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ else {
|
|
+ D( "ignoring unexpected JDWP %d control socket activity (%d bytes)\n",
|
|
+ proc->pid, len );
|
|
+ }
|
|
+ }
|
|
+
|
|
+ CloseProcess:
|
|
+ if (proc->pid >= 0)
|
|
+ D( "remove pid %d to jdwp process list\n", proc->pid );
|
|
+ jdwp_process_free(proc);
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (events & FDE_WRITE) {
|
|
+ D("trying to write to JDWP pid controli (count=%d first=%d) %d\n",
|
|
+ proc->pid, proc->out_count, proc->out_fds[0]);
|
|
+ if (proc->out_count > 0) {
|
|
+ int fd = proc->out_fds[0];
|
|
+ int n, ret;
|
|
+ struct cmsghdr* cmsg;
|
|
+ struct msghdr msg;
|
|
+ struct iovec iov;
|
|
+ char dummy = '!';
|
|
+ char buffer[sizeof(struct cmsghdr) + sizeof(int)];
|
|
+ int flags;
|
|
+
|
|
+ iov.iov_base = &dummy;
|
|
+ iov.iov_len = 1;
|
|
+ msg.msg_name = NULL;
|
|
+ msg.msg_namelen = 0;
|
|
+ msg.msg_iov = &iov;
|
|
+ msg.msg_iovlen = 1;
|
|
+ msg.msg_flags = 0;
|
|
+ msg.msg_control = buffer;
|
|
+ msg.msg_controllen = sizeof(buffer);
|
|
+
|
|
+ cmsg = CMSG_FIRSTHDR(&msg);
|
|
+ cmsg->cmsg_len = msg.msg_controllen;
|
|
+ cmsg->cmsg_level = SOL_SOCKET;
|
|
+ cmsg->cmsg_type = SCM_RIGHTS;
|
|
+ ((int*)CMSG_DATA(cmsg))[0] = fd;
|
|
+
|
|
+ flags = fcntl(proc->socket,F_GETFL,0);
|
|
+
|
|
+ if (flags == -1) {
|
|
+ D("failed to get cntl flags for socket %d: %s\n",
|
|
+ proc->pid, strerror(errno));
|
|
+ goto CloseProcess;
|
|
+
|
|
+ }
|
|
+
|
|
+ if (fcntl(proc->socket, F_SETFL, flags & ~O_NONBLOCK) == -1) {
|
|
+ D("failed to remove O_NONBLOCK flag for socket %d: %s\n",
|
|
+ proc->pid, strerror(errno));
|
|
+ goto CloseProcess;
|
|
+ }
|
|
+
|
|
+ for (;;) {
|
|
+ ret = sendmsg(proc->socket, &msg, 0);
|
|
+ if (ret >= 0) {
|
|
+ adb_close(fd);
|
|
+ break;
|
|
+ }
|
|
+ if (errno == EINTR)
|
|
+ continue;
|
|
+ D("sending new file descriptor to JDWP %d failed: %s\n",
|
|
+ proc->pid, strerror(errno));
|
|
+ goto CloseProcess;
|
|
+ }
|
|
+
|
|
+ D("sent file descriptor %d to JDWP process %d\n",
|
|
+ fd, proc->pid);
|
|
+
|
|
+ for (n = 1; n < proc->out_count; n++)
|
|
+ proc->out_fds[n-1] = proc->out_fds[n];
|
|
+
|
|
+ if (fcntl(proc->socket, F_SETFL, flags) == -1) {
|
|
+ D("failed to set O_NONBLOCK flag for socket %d: %s\n",
|
|
+ proc->pid, strerror(errno));
|
|
+ goto CloseProcess;
|
|
+ }
|
|
+
|
|
+ if (--proc->out_count == 0)
|
|
+ fdevent_del( proc->fde, FDE_WRITE );
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+int
|
|
+create_jdwp_connection_fd(int pid)
|
|
+{
|
|
+ JdwpProcess* proc = _jdwp_list.next;
|
|
+
|
|
+ D("looking for pid %d in JDWP process list\n", pid);
|
|
+ for ( ; proc != &_jdwp_list; proc = proc->next ) {
|
|
+ if (proc->pid == pid) {
|
|
+ goto FoundIt;
|
|
+ }
|
|
+ }
|
|
+ D("search failed !!\n");
|
|
+ return -1;
|
|
+
|
|
+FoundIt:
|
|
+ {
|
|
+ int fds[2];
|
|
+
|
|
+ if (proc->out_count >= MAX_OUT_FDS) {
|
|
+ D("%s: too many pending JDWP connection for pid %d\n",
|
|
+ __FUNCTION__, pid);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if (adb_socketpair(fds) < 0) {
|
|
+ D("%s: socket pair creation failed: %s\n",
|
|
+ __FUNCTION__, strerror(errno));
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ proc->out_fds[ proc->out_count ] = fds[1];
|
|
+ if (++proc->out_count == 1)
|
|
+ fdevent_add( proc->fde, FDE_WRITE );
|
|
+
|
|
+ return fds[0];
|
|
+ }
|
|
+}
|
|
+
|
|
+/** VM DEBUG CONTROL SOCKET
|
|
+ **
|
|
+ ** we do implement a custom asocket to receive the data
|
|
+ **/
|
|
+
|
|
+/* name of the debug control Unix socket */
|
|
+#define JDWP_CONTROL_NAME "\0jdwp-control"
|
|
+#define JDWP_CONTROL_NAME_LEN (sizeof(JDWP_CONTROL_NAME)-1)
|
|
+
|
|
+typedef struct {
|
|
+ int listen_socket;
|
|
+ fdevent* fde;
|
|
+
|
|
+} JdwpControl;
|
|
+
|
|
+
|
|
+static void
|
|
+jdwp_control_event(int s, unsigned events, void* user);
|
|
+
|
|
+
|
|
+static int
|
|
+jdwp_control_init( JdwpControl* control,
|
|
+ const char* sockname,
|
|
+ int socknamelen )
|
|
+{
|
|
+ struct sockaddr_un addr;
|
|
+ socklen_t addrlen;
|
|
+ int s;
|
|
+ int maxpath = sizeof(addr.sun_path);
|
|
+ int pathlen = socknamelen;
|
|
+
|
|
+ if (pathlen >= maxpath) {
|
|
+ D( "vm debug control socket name too long (%d extra chars)\n",
|
|
+ pathlen+1-maxpath );
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ memset(&addr, 0, sizeof(addr));
|
|
+ addr.sun_family = AF_UNIX;
|
|
+ memcpy(addr.sun_path, sockname, socknamelen);
|
|
+
|
|
+ s = socket( AF_UNIX, SOCK_STREAM, 0 );
|
|
+ if (s < 0) {
|
|
+ D( "could not create vm debug control socket. %d: %s\n",
|
|
+ errno, strerror(errno));
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ addrlen = (pathlen + sizeof(addr.sun_family));
|
|
+
|
|
+ if (bind(s, (struct sockaddr*)&addr, addrlen) < 0) {
|
|
+ D( "could not bind vm debug control socket: %d: %s\n",
|
|
+ errno, strerror(errno) );
|
|
+ adb_close(s);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if ( listen(s, 4) < 0 ) {
|
|
+ D("listen failed in jdwp control socket: %d: %s\n",
|
|
+ errno, strerror(errno));
|
|
+ adb_close(s);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ control->listen_socket = s;
|
|
+
|
|
+ control->fde = fdevent_create(s, jdwp_control_event, control);
|
|
+ if (control->fde == NULL) {
|
|
+ D( "could not create fdevent for jdwp control socket\n" );
|
|
+ adb_close(s);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ /* only wait for incoming connections */
|
|
+ fdevent_add(control->fde, FDE_READ);
|
|
+ close_on_exec(s);
|
|
+
|
|
+ D("jdwp control socket started (%d)\n", control->listen_socket);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
+static void
|
|
+jdwp_control_event( int s, unsigned events, void* _control )
|
|
+{
|
|
+ JdwpControl* control = (JdwpControl*) _control;
|
|
+
|
|
+ if (events & FDE_READ) {
|
|
+ struct sockaddr addr;
|
|
+ socklen_t addrlen = sizeof(addr);
|
|
+ int s = -1;
|
|
+ JdwpProcess* proc;
|
|
+
|
|
+ do {
|
|
+ s = adb_socket_accept( control->listen_socket, &addr, &addrlen );
|
|
+ if (s < 0) {
|
|
+ if (errno == EINTR)
|
|
+ continue;
|
|
+ if (errno == ECONNABORTED) {
|
|
+ /* oops, the JDWP process died really quick */
|
|
+ D("oops, the JDWP process died really quick\n");
|
|
+ return;
|
|
+ }
|
|
+ /* the socket is probably closed ? */
|
|
+ D( "weird accept() failed on jdwp control socket: %s\n",
|
|
+ strerror(errno) );
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+ while (s < 0);
|
|
+
|
|
+ proc = jdwp_process_alloc( s );
|
|
+ if (proc == NULL)
|
|
+ return;
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+static JdwpControl _jdwp_control;
|
|
+
|
|
+/** "jdwp" local service implementation
|
|
+ ** this simply returns the list of known JDWP process pids
|
|
+ **/
|
|
+
|
|
+typedef struct {
|
|
+ asocket socket;
|
|
+ int pass;
|
|
+} JdwpSocket;
|
|
+
|
|
+static void
|
|
+jdwp_socket_close( asocket* s )
|
|
+{
|
|
+ asocket* peer = s->peer;
|
|
+
|
|
+ remove_socket(s);
|
|
+
|
|
+ if (peer) {
|
|
+ peer->peer = NULL;
|
|
+ peer->close(peer);
|
|
+ }
|
|
+ free(s);
|
|
+}
|
|
+
|
|
+static int
|
|
+jdwp_socket_enqueue( asocket* s, apacket* p )
|
|
+{
|
|
+ /* you can't write to this asocket */
|
|
+ put_apacket(p);
|
|
+ s->peer->close(s->peer);
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+
|
|
+static void
|
|
+jdwp_socket_ready( asocket* s )
|
|
+{
|
|
+ JdwpSocket* jdwp = (JdwpSocket*)s;
|
|
+ asocket* peer = jdwp->socket.peer;
|
|
+
|
|
+ /* on the first call, send the list of pids,
|
|
+ * on the second one, close the connection
|
|
+ */
|
|
+ if (jdwp->pass == 0) {
|
|
+ apacket* p = get_apacket();
|
|
+ p->len = jdwp_process_list((char*)p->data, MAX_PAYLOAD);
|
|
+ peer->enqueue(peer, p);
|
|
+ jdwp->pass = 1;
|
|
+ }
|
|
+ else {
|
|
+ peer->close(peer);
|
|
+ }
|
|
+}
|
|
+
|
|
+asocket*
|
|
+create_jdwp_service_socket( void )
|
|
+{
|
|
+ JdwpSocket* s = calloc(sizeof(*s),1);
|
|
+
|
|
+ if (s == NULL)
|
|
+ return NULL;
|
|
+
|
|
+ install_local_socket(&s->socket);
|
|
+
|
|
+ s->socket.ready = jdwp_socket_ready;
|
|
+ s->socket.enqueue = jdwp_socket_enqueue;
|
|
+ s->socket.close = jdwp_socket_close;
|
|
+ s->pass = 0;
|
|
+
|
|
+ return &s->socket;
|
|
+}
|
|
+
|
|
+/** "track-jdwp" local service implementation
|
|
+ ** this periodically sends the list of known JDWP process pids
|
|
+ ** to the client...
|
|
+ **/
|
|
+
|
|
+typedef struct JdwpTracker JdwpTracker;
|
|
+
|
|
+struct JdwpTracker {
|
|
+ asocket socket;
|
|
+ JdwpTracker* next;
|
|
+ JdwpTracker* prev;
|
|
+ int need_update;
|
|
+};
|
|
+
|
|
+static JdwpTracker _jdwp_trackers_list;
|
|
+
|
|
+
|
|
+static void
|
|
+jdwp_process_list_updated(void)
|
|
+{
|
|
+ char buffer[1024];
|
|
+ int len;
|
|
+ JdwpTracker* t = _jdwp_trackers_list.next;
|
|
+
|
|
+ len = jdwp_process_list_msg(buffer, sizeof(buffer));
|
|
+
|
|
+ for ( ; t != &_jdwp_trackers_list; t = t->next ) {
|
|
+ apacket* p = get_apacket();
|
|
+ asocket* peer = t->socket.peer;
|
|
+ memcpy(p->data, buffer, len);
|
|
+ p->len = len;
|
|
+ peer->enqueue( peer, p );
|
|
+ }
|
|
+}
|
|
+
|
|
+static void
|
|
+jdwp_tracker_close( asocket* s )
|
|
+{
|
|
+ JdwpTracker* tracker = (JdwpTracker*) s;
|
|
+ asocket* peer = s->peer;
|
|
+
|
|
+ if (peer) {
|
|
+ peer->peer = NULL;
|
|
+ peer->close(peer);
|
|
+ }
|
|
+
|
|
+ remove_socket(s);
|
|
+
|
|
+ tracker->prev->next = tracker->next;
|
|
+ tracker->next->prev = tracker->prev;
|
|
+
|
|
+ free(s);
|
|
+}
|
|
+
|
|
+static void
|
|
+jdwp_tracker_ready( asocket* s )
|
|
+{
|
|
+ JdwpTracker* t = (JdwpTracker*) s;
|
|
+
|
|
+ if (t->need_update) {
|
|
+ apacket* p = get_apacket();
|
|
+ t->need_update = 0;
|
|
+ p->len = jdwp_process_list_msg((char*)p->data, sizeof(p->data));
|
|
+ s->peer->enqueue(s->peer, p);
|
|
+ }
|
|
+}
|
|
+
|
|
+static int
|
|
+jdwp_tracker_enqueue( asocket* s, apacket* p )
|
|
+{
|
|
+ /* you can't write to this socket */
|
|
+ put_apacket(p);
|
|
+ s->peer->close(s->peer);
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+
|
|
+asocket*
|
|
+create_jdwp_tracker_service_socket( void )
|
|
+{
|
|
+ JdwpTracker* t = calloc(sizeof(*t),1);
|
|
+
|
|
+ if (t == NULL)
|
|
+ return NULL;
|
|
+
|
|
+ t->next = &_jdwp_trackers_list;
|
|
+ t->prev = t->next->prev;
|
|
+
|
|
+ t->next->prev = t;
|
|
+ t->prev->next = t;
|
|
+
|
|
+ install_local_socket(&t->socket);
|
|
+
|
|
+ t->socket.ready = jdwp_tracker_ready;
|
|
+ t->socket.enqueue = jdwp_tracker_enqueue;
|
|
+ t->socket.close = jdwp_tracker_close;
|
|
+ t->need_update = 1;
|
|
+
|
|
+ return &t->socket;
|
|
+}
|
|
+
|
|
+
|
|
+int
|
|
+init_jdwp(void)
|
|
+{
|
|
+ _jdwp_list.next = &_jdwp_list;
|
|
+ _jdwp_list.prev = &_jdwp_list;
|
|
+
|
|
+ _jdwp_trackers_list.next = &_jdwp_trackers_list;
|
|
+ _jdwp_trackers_list.prev = &_jdwp_trackers_list;
|
|
+
|
|
+ return jdwp_control_init( &_jdwp_control,
|
|
+ JDWP_CONTROL_NAME,
|
|
+ JDWP_CONTROL_NAME_LEN );
|
|
+}
|
|
+
|
|
+#endif /* !ADB_HOST */
|
|
+
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/log_service.c
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/log_service.c 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,92 @@
|
|
+/*
|
|
+ * Copyright (C) 2007 The Android Open Source Project
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
+ * you may not use this file except in compliance with the License.
|
|
+ * You may obtain a copy of the License at
|
|
+ *
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
+ *
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+ * See the License for the specific language governing permissions and
|
|
+ * limitations under the License.
|
|
+ */
|
|
+
|
|
+
|
|
+#include <stdlib.h>
|
|
+#include <stdio.h>
|
|
+#include <unistd.h>
|
|
+#include <string.h>
|
|
+#include <fcntl.h>
|
|
+#include <errno.h>
|
|
+#include <sys/socket.h>
|
|
+#include <cutils/logger.h>
|
|
+#include "sysdeps.h"
|
|
+#include "adb.h"
|
|
+
|
|
+#define LOG_FILE_DIR "/dev/log/"
|
|
+
|
|
+void write_log_entry(int fd, struct logger_entry *buf);
|
|
+
|
|
+void log_service(int fd, void *cookie)
|
|
+{
|
|
+ /* get the name of the log filepath to read */
|
|
+ char * log_filepath = cookie;
|
|
+
|
|
+ /* open the log file. */
|
|
+ int logfd = unix_open(log_filepath, O_RDONLY);
|
|
+ if (logfd < 0) {
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ // temp buffer to read the entries
|
|
+ unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1] __attribute__((aligned(4)));
|
|
+ struct logger_entry *entry = (struct logger_entry *) buf;
|
|
+
|
|
+ while (1) {
|
|
+ int ret;
|
|
+
|
|
+ ret = unix_read(logfd, entry, LOGGER_ENTRY_MAX_LEN);
|
|
+ if (ret < 0) {
|
|
+ if (errno == EINTR || errno == EAGAIN)
|
|
+ continue;
|
|
+ // perror("logcat read");
|
|
+ goto done;
|
|
+ }
|
|
+ else if (!ret) {
|
|
+ // fprintf(stderr, "read: Unexpected EOF!\n");
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ /* NOTE: driver guarantees we read exactly one full entry */
|
|
+
|
|
+ entry->msg[entry->len] = '\0';
|
|
+
|
|
+ write_log_entry(fd, entry);
|
|
+ }
|
|
+
|
|
+done:
|
|
+ unix_close(fd);
|
|
+ free(log_filepath);
|
|
+}
|
|
+
|
|
+/* returns the full path to the log file in a newly allocated string */
|
|
+char * get_log_file_path(const char * log_name) {
|
|
+ char *log_device = malloc(strlen(LOG_FILE_DIR) + strlen(log_name) + 1);
|
|
+
|
|
+ strcpy(log_device, LOG_FILE_DIR);
|
|
+ strcat(log_device, log_name);
|
|
+
|
|
+ return log_device;
|
|
+}
|
|
+
|
|
+
|
|
+/* prints one log entry into the file descriptor fd */
|
|
+void write_log_entry(int fd, struct logger_entry *buf)
|
|
+{
|
|
+ size_t size = sizeof(struct logger_entry) + buf->len;
|
|
+
|
|
+ writex(fd, buf, size);
|
|
+}
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/mutex_list.h
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/mutex_list.h 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,26 @@
|
|
+/* the list of mutexes used by adb */
|
|
+/* #ifndef __MUTEX_LIST_H
|
|
+ * Do not use an include-guard. This file is included once to declare the locks
|
|
+ * and once in win32 to actually do the runtime initialization.
|
|
+ */
|
|
+#ifndef ADB_MUTEX
|
|
+#error ADB_MUTEX not defined when including this file
|
|
+#endif
|
|
+ADB_MUTEX(dns_lock)
|
|
+ADB_MUTEX(socket_list_lock)
|
|
+ADB_MUTEX(transport_lock)
|
|
+#if ADB_HOST
|
|
+ADB_MUTEX(local_transports_lock)
|
|
+#endif
|
|
+ADB_MUTEX(usb_lock)
|
|
+
|
|
+// Sadly logging to /data/adb/adb-... is not thread safe.
|
|
+// After modifying adb.h::D() to count invocations:
|
|
+// DEBUG(jpa):0:Handling main()
|
|
+// DEBUG(jpa):1:[ usb_init - starting thread ]
|
|
+// (Oopsies, no :2:, and matching message is also gone.)
|
|
+// DEBUG(jpa):3:[ usb_thread - opening device ]
|
|
+// DEBUG(jpa):4:jdwp control socket started (10)
|
|
+ADB_MUTEX(D_lock)
|
|
+
|
|
+#undef ADB_MUTEX
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/qemu_pipe.h
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/qemu_pipe.h 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,91 @@
|
|
+/*
|
|
+ * Copyright (C) 2011 The Android Open Source Project
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
+ * you may not use this file except in compliance with the License.
|
|
+ * You may obtain a copy of the License at
|
|
+ *
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
+ *
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+ * See the License for the specific language governing permissions and
|
|
+ * limitations under the License.
|
|
+ */
|
|
+#ifndef ANDROID_INCLUDE_HARDWARE_QEMU_PIPE_H
|
|
+#define ANDROID_INCLUDE_HARDWARE_QEMU_PIPE_H
|
|
+
|
|
+#include <sys/cdefs.h>
|
|
+#include <unistd.h>
|
|
+#include <fcntl.h>
|
|
+#include <sys/mman.h>
|
|
+#include <pthread.h> /* for pthread_once() */
|
|
+#include <stdlib.h>
|
|
+#include <stdio.h>
|
|
+#include <errno.h>
|
|
+
|
|
+#ifndef D
|
|
+# define D(...) do{}while(0)
|
|
+#endif
|
|
+
|
|
+/* Try to open a new Qemu fast-pipe. This function returns a file descriptor
|
|
+ * that can be used to communicate with a named service managed by the
|
|
+ * emulator.
|
|
+ *
|
|
+ * This file descriptor can be used as a standard pipe/socket descriptor.
|
|
+ *
|
|
+ * 'pipeName' is the name of the emulator service you want to connect to.
|
|
+ * E.g. 'opengles' or 'camera'.
|
|
+ *
|
|
+ * On success, return a valid file descriptor
|
|
+ * Returns -1 on error, and errno gives the error code, e.g.:
|
|
+ *
|
|
+ * EINVAL -> unknown/unsupported pipeName
|
|
+ * ENOSYS -> fast pipes not available in this system.
|
|
+ *
|
|
+ * ENOSYS should never happen, except if you're trying to run within a
|
|
+ * misconfigured emulator.
|
|
+ *
|
|
+ * You should be able to open several pipes to the same pipe service,
|
|
+ * except for a few special cases (e.g. GSM modem), where EBUSY will be
|
|
+ * returned if more than one client tries to connect to it.
|
|
+ */
|
|
+static __inline__ int
|
|
+qemu_pipe_open(const char* pipeName)
|
|
+{
|
|
+ char buff[256];
|
|
+ int buffLen;
|
|
+ int fd, ret;
|
|
+
|
|
+ if (pipeName == NULL || pipeName[0] == '\0') {
|
|
+ errno = EINVAL;
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ snprintf(buff, sizeof buff, "pipe:%s", pipeName);
|
|
+
|
|
+ fd = open("/dev/qemu_pipe", O_RDWR);
|
|
+ if (fd < 0) {
|
|
+ D("%s: Could not open /dev/qemu_pipe: %s", __FUNCTION__, strerror(errno));
|
|
+ //errno = ENOSYS;
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ buffLen = strlen(buff);
|
|
+
|
|
+ ret = TEMP_FAILURE_RETRY(write(fd, buff, buffLen+1));
|
|
+ if (ret != buffLen+1) {
|
|
+ D("%s: Could not connect to %s pipe service: %s", __FUNCTION__, pipeName, strerror(errno));
|
|
+ if (ret == 0) {
|
|
+ errno = ECONNRESET;
|
|
+ } else if (ret > 0) {
|
|
+ errno = EINVAL;
|
|
+ }
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return fd;
|
|
+}
|
|
+
|
|
+#endif /* ANDROID_INCLUDE_HARDWARE_QEMUD_PIPE_H */
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/remount_service.c
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/remount_service.c 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,111 @@
|
|
+/*
|
|
+ * Copyright (C) 2008 The Android Open Source Project
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
+ * you may not use this file except in compliance with the License.
|
|
+ * You may obtain a copy of the License at
|
|
+ *
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
+ *
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+ * See the License for the specific language governing permissions and
|
|
+ * limitations under the License.
|
|
+ */
|
|
+
|
|
+#include <stdlib.h>
|
|
+#include <stdio.h>
|
|
+#include <unistd.h>
|
|
+#include <string.h>
|
|
+#include <fcntl.h>
|
|
+#include <sys/mount.h>
|
|
+#include <errno.h>
|
|
+
|
|
+#include "sysdeps.h"
|
|
+
|
|
+#define TRACE_TAG TRACE_ADB
|
|
+#include "adb.h"
|
|
+
|
|
+
|
|
+static int system_ro = 1;
|
|
+
|
|
+/* Returns the device used to mount a directory in /proc/mounts */
|
|
+static char *find_mount(const char *dir)
|
|
+{
|
|
+ int fd;
|
|
+ int res;
|
|
+ int size;
|
|
+ char *token = NULL;
|
|
+ const char delims[] = "\n";
|
|
+ char buf[4096];
|
|
+
|
|
+ fd = unix_open("/proc/mounts", O_RDONLY);
|
|
+ if (fd < 0)
|
|
+ return NULL;
|
|
+
|
|
+ buf[sizeof(buf) - 1] = '\0';
|
|
+ size = adb_read(fd, buf, sizeof(buf) - 1);
|
|
+ adb_close(fd);
|
|
+
|
|
+ token = strtok(buf, delims);
|
|
+
|
|
+ while (token) {
|
|
+ char mount_dev[256];
|
|
+ char mount_dir[256];
|
|
+ int mount_freq;
|
|
+ int mount_passno;
|
|
+
|
|
+ res = sscanf(token, "%255s %255s %*s %*s %d %d\n",
|
|
+ mount_dev, mount_dir, &mount_freq, &mount_passno);
|
|
+ mount_dev[255] = 0;
|
|
+ mount_dir[255] = 0;
|
|
+ if (res == 4 && (strcmp(dir, mount_dir) == 0))
|
|
+ return strdup(mount_dev);
|
|
+
|
|
+ token = strtok(NULL, delims);
|
|
+ }
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+/* Init mounts /system as read only, remount to enable writes. */
|
|
+static int remount_system()
|
|
+{
|
|
+ char *dev;
|
|
+
|
|
+ if (system_ro == 0) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ dev = find_mount("/system");
|
|
+
|
|
+ if (!dev)
|
|
+ return -1;
|
|
+
|
|
+ system_ro = mount(dev, "/system", "none", MS_REMOUNT, NULL);
|
|
+
|
|
+ free(dev);
|
|
+
|
|
+ return system_ro;
|
|
+}
|
|
+
|
|
+static void write_string(int fd, const char* str)
|
|
+{
|
|
+ writex(fd, str, strlen(str));
|
|
+}
|
|
+
|
|
+void remount_service(int fd, void *cookie)
|
|
+{
|
|
+ int ret = remount_system();
|
|
+
|
|
+ if (!ret)
|
|
+ write_string(fd, "remount succeeded\n");
|
|
+ else {
|
|
+ char buffer[200];
|
|
+ snprintf(buffer, sizeof(buffer), "remount failed: %s\n", strerror(errno));
|
|
+ write_string(fd, buffer);
|
|
+ }
|
|
+
|
|
+ adb_close(fd);
|
|
+}
|
|
+
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/services.c
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/services.c 2013-06-19 02:41:32.583408302 -0300
|
|
@@ -0,0 +1,568 @@
|
|
+/*
|
|
+ * Copyright (C) 2007 The Android Open Source Project
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
+ * you may not use this file except in compliance with the License.
|
|
+ * You may obtain a copy of the License at
|
|
+ *
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
+ *
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+ * See the License for the specific language governing permissions and
|
|
+ * limitations under the License.
|
|
+ */
|
|
+
|
|
+#include <stdlib.h>
|
|
+#include <stdio.h>
|
|
+#include <unistd.h>
|
|
+#include <string.h>
|
|
+#include <errno.h>
|
|
+#include <pwd.h>
|
|
+
|
|
+#include "sysdeps.h"
|
|
+
|
|
+#define TRACE_TAG TRACE_SERVICES
|
|
+#include "adb.h"
|
|
+#include "file_sync_service.h"
|
|
+
|
|
+#if ADB_HOST
|
|
+# ifndef HAVE_WINSOCK
|
|
+# include <netinet/in.h>
|
|
+# include <netdb.h>
|
|
+# include <sys/ioctl.h>
|
|
+# endif
|
|
+#else
|
|
+# include <cutils/android_reboot.h>
|
|
+#endif
|
|
+
|
|
+typedef struct stinfo stinfo;
|
|
+
|
|
+struct stinfo {
|
|
+ void (*func)(int fd, void *cookie);
|
|
+ int fd;
|
|
+ void *cookie;
|
|
+};
|
|
+
|
|
+
|
|
+void *service_bootstrap_func(void *x)
|
|
+{
|
|
+ stinfo *sti = x;
|
|
+ sti->func(sti->fd, sti->cookie);
|
|
+ free(sti);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+#if ADB_HOST
|
|
+ADB_MUTEX_DEFINE( dns_lock );
|
|
+
|
|
+static void dns_service(int fd, void *cookie)
|
|
+{
|
|
+ char *hostname = cookie;
|
|
+ struct hostent *hp;
|
|
+ unsigned zero = 0;
|
|
+
|
|
+ adb_mutex_lock(&dns_lock);
|
|
+ hp = gethostbyname(hostname);
|
|
+ free(cookie);
|
|
+ if(hp == 0) {
|
|
+ writex(fd, &zero, 4);
|
|
+ } else {
|
|
+ writex(fd, hp->h_addr, 4);
|
|
+ }
|
|
+ adb_mutex_unlock(&dns_lock);
|
|
+ adb_close(fd);
|
|
+}
|
|
+#else
|
|
+extern int recovery_mode;
|
|
+
|
|
+static void recover_service(int s, void *cookie)
|
|
+{
|
|
+ unsigned char buf[4096];
|
|
+ unsigned count = (unsigned) cookie;
|
|
+ int fd;
|
|
+
|
|
+ fd = adb_creat("/tmp/update", 0644);
|
|
+ if(fd < 0) {
|
|
+ adb_close(s);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ while(count > 0) {
|
|
+ unsigned xfer = (count > 4096) ? 4096 : count;
|
|
+ if(readx(s, buf, xfer)) break;
|
|
+ if(writex(fd, buf, xfer)) break;
|
|
+ count -= xfer;
|
|
+ }
|
|
+
|
|
+ if(count == 0) {
|
|
+ writex(s, "OKAY", 4);
|
|
+ } else {
|
|
+ writex(s, "FAIL", 4);
|
|
+ }
|
|
+ adb_close(fd);
|
|
+ adb_close(s);
|
|
+
|
|
+ fd = adb_creat("/tmp/update.begin", 0644);
|
|
+ adb_close(fd);
|
|
+}
|
|
+
|
|
+void restart_root_service(int fd, void *cookie)
|
|
+{
|
|
+ char buf[100];
|
|
+ char value[PROPERTY_VALUE_MAX];
|
|
+
|
|
+ if (getuid() == 0) {
|
|
+ snprintf(buf, sizeof(buf), "adbd is already running as root\n");
|
|
+ writex(fd, buf, strlen(buf));
|
|
+ adb_close(fd);
|
|
+ } else {
|
|
+ //property_get("ro.debuggable", value, "");
|
|
+ if (strcmp(value, "1") != 0) {
|
|
+ snprintf(buf, sizeof(buf), "adbd cannot run as root in production builds\n");
|
|
+ writex(fd, buf, strlen(buf));
|
|
+ adb_close(fd);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ //property_set("service.adb.root", "1");
|
|
+ snprintf(buf, sizeof(buf), "restarting adbd as root\n");
|
|
+ writex(fd, buf, strlen(buf));
|
|
+ adb_close(fd);
|
|
+ }
|
|
+}
|
|
+
|
|
+void restart_tcp_service(int fd, void *cookie)
|
|
+{
|
|
+ char buf[100];
|
|
+ char value[PROPERTY_VALUE_MAX];
|
|
+ int port = (int)cookie;
|
|
+
|
|
+ if (port <= 0) {
|
|
+ snprintf(buf, sizeof(buf), "invalid port\n");
|
|
+ writex(fd, buf, strlen(buf));
|
|
+ adb_close(fd);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ snprintf(value, sizeof(value), "%d", port);
|
|
+ //property_set("service.adb.tcp.port", value);
|
|
+ snprintf(buf, sizeof(buf), "restarting in TCP mode port: %d\n", port);
|
|
+ writex(fd, buf, strlen(buf));
|
|
+ adb_close(fd);
|
|
+}
|
|
+
|
|
+void restart_usb_service(int fd, void *cookie)
|
|
+{
|
|
+ char buf[100];
|
|
+
|
|
+ //property_set("service.adb.tcp.port", "0");
|
|
+ snprintf(buf, sizeof(buf), "restarting in USB mode\n");
|
|
+ writex(fd, buf, strlen(buf));
|
|
+ adb_close(fd);
|
|
+}
|
|
+
|
|
+void reboot_service(int fd, void *arg)
|
|
+{
|
|
+ char buf[100];
|
|
+ int pid, ret;
|
|
+
|
|
+ sync();
|
|
+
|
|
+ /* Attempt to unmount the SD card first.
|
|
+ * No need to bother checking for errors.
|
|
+ */
|
|
+ pid = fork();
|
|
+ if (pid == 0) {
|
|
+ /* ask vdc to unmount it */
|
|
+ execl("/system/bin/vdc", "/system/bin/vdc", "volume", "unmount",
|
|
+ getenv("EXTERNAL_STORAGE"), "force", NULL);
|
|
+ } else if (pid > 0) {
|
|
+ /* wait until vdc succeeds or fails */
|
|
+ waitpid(pid, &ret, 0);
|
|
+ }
|
|
+
|
|
+ ret = android_reboot(ANDROID_RB_RESTART2, 0, (char *) arg);
|
|
+ if (ret < 0) {
|
|
+ snprintf(buf, sizeof(buf), "reboot failed: %s\n", strerror(errno));
|
|
+ writex(fd, buf, strlen(buf));
|
|
+ }
|
|
+ free(arg);
|
|
+ adb_close(fd);
|
|
+}
|
|
+
|
|
+#endif
|
|
+
|
|
+#if 0
|
|
+static void echo_service(int fd, void *cookie)
|
|
+{
|
|
+ char buf[4096];
|
|
+ int r;
|
|
+ char *p;
|
|
+ int c;
|
|
+
|
|
+ for(;;) {
|
|
+ r = adb_read(fd, buf, 4096);
|
|
+ if(r == 0) goto done;
|
|
+ if(r < 0) {
|
|
+ if(errno == EINTR) continue;
|
|
+ else goto done;
|
|
+ }
|
|
+
|
|
+ c = r;
|
|
+ p = buf;
|
|
+ while(c > 0) {
|
|
+ r = write(fd, p, c);
|
|
+ if(r > 0) {
|
|
+ c -= r;
|
|
+ p += r;
|
|
+ continue;
|
|
+ }
|
|
+ if((r < 0) && (errno == EINTR)) continue;
|
|
+ goto done;
|
|
+ }
|
|
+ }
|
|
+done:
|
|
+ close(fd);
|
|
+}
|
|
+#endif
|
|
+
|
|
+static int create_service_thread(void (*func)(int, void *), void *cookie)
|
|
+{
|
|
+ stinfo *sti;
|
|
+ adb_thread_t t;
|
|
+ int s[2];
|
|
+
|
|
+ if(adb_socketpair(s)) {
|
|
+ printf("cannot create service socket pair\n");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ sti = malloc(sizeof(stinfo));
|
|
+ if(sti == 0) fatal("cannot allocate stinfo");
|
|
+ sti->func = func;
|
|
+ sti->cookie = cookie;
|
|
+ sti->fd = s[1];
|
|
+
|
|
+ if(adb_thread_create( &t, service_bootstrap_func, sti)){
|
|
+ free(sti);
|
|
+ adb_close(s[0]);
|
|
+ adb_close(s[1]);
|
|
+ printf("cannot create service thread\n");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ D("service thread started, %d:%d\n",s[0], s[1]);
|
|
+ return s[0];
|
|
+}
|
|
+
|
|
+#if !ADB_HOST
|
|
+static int create_subprocess(const char *cmd, const char *arg0, const char *arg1, pid_t *pid)
|
|
+{
|
|
+#ifdef HAVE_WIN32_PROC
|
|
+ D("create_subprocess(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1);
|
|
+ fprintf(stderr, "error: create_subprocess not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1);
|
|
+ return -1;
|
|
+#else /* !HAVE_WIN32_PROC */
|
|
+ char *devname;
|
|
+ int ptm;
|
|
+
|
|
+ ptm = unix_open("/dev/ptmx", O_RDWR); // | O_NOCTTY);
|
|
+ if(ptm < 0){
|
|
+ printf("[ cannot open /dev/ptmx - %s ]\n",strerror(errno));
|
|
+ return -1;
|
|
+ }
|
|
+ fcntl(ptm, F_SETFD, FD_CLOEXEC);
|
|
+
|
|
+ if(grantpt(ptm) || unlockpt(ptm) ||
|
|
+ ((devname = (char*) ptsname(ptm)) == 0)){
|
|
+ printf("[ trouble with /dev/ptmx - %s ]\n", strerror(errno));
|
|
+ adb_close(ptm);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ *pid = fork();
|
|
+ if(*pid < 0) {
|
|
+ printf("- fork failed: %s -\n", strerror(errno));
|
|
+ adb_close(ptm);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if(*pid == 0){
|
|
+ int pts;
|
|
+
|
|
+ setsid();
|
|
+
|
|
+ pts = unix_open(devname, O_RDWR);
|
|
+ if(pts < 0) {
|
|
+ fprintf(stderr, "child failed to open pseudo-term slave: %s\n", devname);
|
|
+ exit(-1);
|
|
+ }
|
|
+
|
|
+ dup2(pts, 0);
|
|
+ dup2(pts, 1);
|
|
+ dup2(pts, 2);
|
|
+
|
|
+ adb_close(pts);
|
|
+ adb_close(ptm);
|
|
+
|
|
+ // set OOM adjustment to zero
|
|
+ char text[64];
|
|
+ snprintf(text, sizeof text, "/proc/%d/oom_adj", getpid());
|
|
+ int fd = adb_open(text, O_WRONLY);
|
|
+ if (fd >= 0) {
|
|
+ adb_write(fd, "0", 1);
|
|
+ adb_close(fd);
|
|
+ } else {
|
|
+ D("adb: unable to open %s\n", text);
|
|
+ }
|
|
+ execl(cmd, cmd, arg0, arg1, NULL);
|
|
+ fprintf(stderr, "- exec '%s' failed: %s (%d) -\n",
|
|
+ cmd, strerror(errno), errno);
|
|
+ exit(-1);
|
|
+ } else {
|
|
+ // Don't set child's OOM adjustment to zero.
|
|
+ // Let the child do it itself, as sometimes the parent starts
|
|
+ // running before the child has a /proc/pid/oom_adj.
|
|
+ // """adb: unable to open /proc/644/oom_adj""" seen in some logs.
|
|
+ return ptm;
|
|
+ }
|
|
+#endif /* !HAVE_WIN32_PROC */
|
|
+}
|
|
+#endif /* !ABD_HOST */
|
|
+
|
|
+#if ADB_HOST
|
|
+#define SHELL_COMMAND "/bin/sh"
|
|
+#else
|
|
+#define SHELL_COMMAND "/system/bin/sh"
|
|
+#endif
|
|
+
|
|
+#if !ADB_HOST
|
|
+static void subproc_waiter_service(int fd, void *cookie)
|
|
+{
|
|
+ pid_t pid = (pid_t)cookie;
|
|
+
|
|
+ D("entered. fd=%d of pid=%d\n", fd, pid);
|
|
+ for (;;) {
|
|
+ int status;
|
|
+ pid_t p = waitpid(pid, &status, 0);
|
|
+ if (p == pid) {
|
|
+ D("fd=%d, post waitpid(pid=%d) status=%04x\n", fd, p, status);
|
|
+ if (WIFSIGNALED(status)) {
|
|
+ D("*** Killed by signal %d\n", WTERMSIG(status));
|
|
+ break;
|
|
+ } else if (!WIFEXITED(status)) {
|
|
+ D("*** Didn't exit!!. status %d\n", status);
|
|
+ break;
|
|
+ } else if (WEXITSTATUS(status) >= 0) {
|
|
+ D("*** Exit code %d\n", WEXITSTATUS(status));
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ D("shell exited fd=%d of pid=%d err=%d\n", fd, pid, errno);
|
|
+ if (SHELL_EXIT_NOTIFY_FD >=0) {
|
|
+ int res;
|
|
+ res = writex(SHELL_EXIT_NOTIFY_FD, &fd, sizeof(fd));
|
|
+ D("notified shell exit via fd=%d for pid=%d res=%d errno=%d\n",
|
|
+ SHELL_EXIT_NOTIFY_FD, pid, res, errno);
|
|
+ }
|
|
+}
|
|
+
|
|
+static int create_subproc_thread(const char *name)
|
|
+{
|
|
+ stinfo *sti;
|
|
+ adb_thread_t t;
|
|
+ int ret_fd;
|
|
+ pid_t pid;
|
|
+
|
|
+ struct passwd *user = getpwuid(getuid());
|
|
+ char *shell;
|
|
+
|
|
+ if (user && user->pw_shell)
|
|
+ shell = user->pw_shell;
|
|
+ else
|
|
+ shell = SHELL_COMMAND;
|
|
+
|
|
+ if(name) {
|
|
+ ret_fd = create_subprocess(shell, "-c", name, &pid);
|
|
+ } else {
|
|
+ ret_fd = create_subprocess(shell, "-", 0, &pid);
|
|
+ }
|
|
+ D("create_subprocess() ret_fd=%d pid=%d\n", ret_fd, pid);
|
|
+
|
|
+ sti = malloc(sizeof(stinfo));
|
|
+ if(sti == 0) fatal("cannot allocate stinfo");
|
|
+ sti->func = subproc_waiter_service;
|
|
+ sti->cookie = (void*)pid;
|
|
+ sti->fd = ret_fd;
|
|
+
|
|
+ if(adb_thread_create( &t, service_bootstrap_func, sti)){
|
|
+ free(sti);
|
|
+ adb_close(ret_fd);
|
|
+ printf("cannot create service thread\n");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ D("service thread started, fd=%d pid=%d\n",ret_fd, pid);
|
|
+ return ret_fd;
|
|
+}
|
|
+#endif
|
|
+
|
|
+int service_to_fd(const char *name)
|
|
+{
|
|
+ int ret = -1;
|
|
+
|
|
+ if(!strncmp(name, "tcp:", 4)) {
|
|
+ int port = atoi(name + 4);
|
|
+ name = strchr(name + 4, ':');
|
|
+ if(name == 0) {
|
|
+ ret = socket_loopback_client(port, SOCK_STREAM);
|
|
+ if (ret >= 0)
|
|
+ disable_tcp_nagle(ret);
|
|
+ } else {
|
|
+#if ADB_HOST
|
|
+ adb_mutex_lock(&dns_lock);
|
|
+ ret = socket_network_client(name + 1, port, SOCK_STREAM);
|
|
+ adb_mutex_unlock(&dns_lock);
|
|
+#else
|
|
+ return -1;
|
|
+#endif
|
|
+ }
|
|
+#ifndef HAVE_WINSOCK /* winsock doesn't implement unix domain sockets */
|
|
+ } else if(!strncmp(name, "local:", 6)) {
|
|
+ ret = socket_local_client(name + 6,
|
|
+ ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
|
|
+ } else if(!strncmp(name, "localreserved:", 14)) {
|
|
+ ret = socket_local_client(name + 14,
|
|
+ ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
|
|
+ } else if(!strncmp(name, "localabstract:", 14)) {
|
|
+ ret = socket_local_client(name + 14,
|
|
+ ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
|
|
+ } else if(!strncmp(name, "localfilesystem:", 16)) {
|
|
+ ret = socket_local_client(name + 16,
|
|
+ ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
|
|
+#endif
|
|
+#if ADB_HOST
|
|
+ } else if(!strncmp("dns:", name, 4)){
|
|
+ char *n = strdup(name + 4);
|
|
+ if(n == 0) return -1;
|
|
+ ret = create_service_thread(dns_service, n);
|
|
+#else /* !ADB_HOST */
|
|
+ } else if(!strncmp("dev:", name, 4)) {
|
|
+ ret = unix_open(name + 4, O_RDWR);
|
|
+ } else if(!strncmp(name, "framebuffer:", 12)) {
|
|
+ ret = create_service_thread(framebuffer_service, 0);
|
|
+ } else if(recovery_mode && !strncmp(name, "recover:", 8)) {
|
|
+ ret = create_service_thread(recover_service, (void*) atoi(name + 8));
|
|
+ } else if (!strncmp(name, "jdwp:", 5)) {
|
|
+ ret = create_jdwp_connection_fd(atoi(name+5));
|
|
+ } else if (!strncmp(name, "log:", 4)) {
|
|
+ ret = create_service_thread(log_service, get_log_file_path(name + 4));
|
|
+ } else if(!HOST && !strncmp(name, "shell:", 6)) {
|
|
+ if(name[6]) {
|
|
+ ret = create_subproc_thread(name + 6);
|
|
+ } else {
|
|
+ ret = create_subproc_thread(0);
|
|
+ }
|
|
+ } else if(!strncmp(name, "sync:", 5)) {
|
|
+ ret = create_service_thread(file_sync_service, NULL);
|
|
+ } else if(!strncmp(name, "remount:", 8)) {
|
|
+ ret = create_service_thread(remount_service, NULL);
|
|
+ } else if(!strncmp(name, "reboot:", 7)) {
|
|
+ void* arg = strdup(name + 7);
|
|
+ if(arg == 0) return -1;
|
|
+ ret = create_service_thread(reboot_service, arg);
|
|
+ } else if(!strncmp(name, "root:", 5)) {
|
|
+ ret = create_service_thread(restart_root_service, NULL);
|
|
+ } else if(!strncmp(name, "backup:", 7)) {
|
|
+ char* arg = strdup(name+7);
|
|
+ if (arg == NULL) return -1;
|
|
+ ret = backup_service(BACKUP, arg);
|
|
+ } else if(!strncmp(name, "restore:", 8)) {
|
|
+ ret = backup_service(RESTORE, NULL);
|
|
+ } else if(!strncmp(name, "tcpip:", 6)) {
|
|
+ int port;
|
|
+ if (sscanf(name + 6, "%d", &port) == 0) {
|
|
+ port = 0;
|
|
+ }
|
|
+ ret = create_service_thread(restart_tcp_service, (void *)port);
|
|
+ } else if(!strncmp(name, "usb:", 4)) {
|
|
+ ret = create_service_thread(restart_usb_service, NULL);
|
|
+#endif
|
|
+#if 0
|
|
+ } else if(!strncmp(name, "echo:", 5)){
|
|
+ ret = create_service_thread(echo_service, 0);
|
|
+#endif
|
|
+ }
|
|
+ if (ret >= 0) {
|
|
+ close_on_exec(ret);
|
|
+ }
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+#if ADB_HOST
|
|
+struct state_info {
|
|
+ transport_type transport;
|
|
+ char* serial;
|
|
+ int state;
|
|
+};
|
|
+
|
|
+static void wait_for_state(int fd, void* cookie)
|
|
+{
|
|
+ struct state_info* sinfo = cookie;
|
|
+ char* err = "unknown error";
|
|
+
|
|
+ D("wait_for_state %d\n", sinfo->state);
|
|
+
|
|
+ atransport *t = acquire_one_transport(sinfo->state, sinfo->transport, sinfo->serial, &err);
|
|
+ if(t != 0) {
|
|
+ writex(fd, "OKAY", 4);
|
|
+ } else {
|
|
+ sendfailmsg(fd, err);
|
|
+ }
|
|
+
|
|
+ if (sinfo->serial)
|
|
+ free(sinfo->serial);
|
|
+ free(sinfo);
|
|
+ adb_close(fd);
|
|
+ D("wait_for_state is done\n");
|
|
+}
|
|
+#endif
|
|
+
|
|
+#if ADB_HOST
|
|
+asocket* host_service_to_socket(const char* name, const char *serial)
|
|
+{
|
|
+ if (!strcmp(name,"track-devices")) {
|
|
+ return create_device_tracker();
|
|
+ } else if (!strncmp(name, "wait-for-", strlen("wait-for-"))) {
|
|
+ struct state_info* sinfo = malloc(sizeof(struct state_info));
|
|
+
|
|
+ if (serial)
|
|
+ sinfo->serial = strdup(serial);
|
|
+ else
|
|
+ sinfo->serial = NULL;
|
|
+
|
|
+ name += strlen("wait-for-");
|
|
+
|
|
+ if (!strncmp(name, "local", strlen("local"))) {
|
|
+ sinfo->transport = kTransportLocal;
|
|
+ sinfo->state = CS_DEVICE;
|
|
+ } else if (!strncmp(name, "usb", strlen("usb"))) {
|
|
+ sinfo->transport = kTransportUsb;
|
|
+ sinfo->state = CS_DEVICE;
|
|
+ } else if (!strncmp(name, "any", strlen("any"))) {
|
|
+ sinfo->transport = kTransportAny;
|
|
+ sinfo->state = CS_DEVICE;
|
|
+ } else {
|
|
+ free(sinfo);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ int fd = create_service_thread(wait_for_state, sinfo);
|
|
+ return create_local_socket(fd);
|
|
+ }
|
|
+ return NULL;
|
|
+}
|
|
+#endif /* ADB_HOST */
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/sockets.c
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/sockets.c 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,873 @@
|
|
+/*
|
|
+ * Copyright (C) 2007 The Android Open Source Project
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
+ * you may not use this file except in compliance with the License.
|
|
+ * You may obtain a copy of the License at
|
|
+ *
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
+ *
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+ * See the License for the specific language governing permissions and
|
|
+ * limitations under the License.
|
|
+ */
|
|
+
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+#include <unistd.h>
|
|
+#include <errno.h>
|
|
+#include <string.h>
|
|
+#include <ctype.h>
|
|
+
|
|
+#include "sysdeps.h"
|
|
+
|
|
+#define TRACE_TAG TRACE_SOCKETS
|
|
+#include "adb.h"
|
|
+
|
|
+ADB_MUTEX_DEFINE( socket_list_lock );
|
|
+
|
|
+static void local_socket_close_locked(asocket *s);
|
|
+
|
|
+int sendfailmsg(int fd, const char *reason)
|
|
+{
|
|
+ char buf[9];
|
|
+ int len;
|
|
+ len = strlen(reason);
|
|
+ if(len > 0xffff) len = 0xffff;
|
|
+ snprintf(buf, sizeof buf, "FAIL%04x", len);
|
|
+ if(writex(fd, buf, 8)) return -1;
|
|
+ return writex(fd, reason, len);
|
|
+}
|
|
+
|
|
+//extern int online;
|
|
+
|
|
+static unsigned local_socket_next_id = 1;
|
|
+
|
|
+static asocket local_socket_list = {
|
|
+ .next = &local_socket_list,
|
|
+ .prev = &local_socket_list,
|
|
+};
|
|
+
|
|
+/* the the list of currently closing local sockets.
|
|
+** these have no peer anymore, but still packets to
|
|
+** write to their fd.
|
|
+*/
|
|
+static asocket local_socket_closing_list = {
|
|
+ .next = &local_socket_closing_list,
|
|
+ .prev = &local_socket_closing_list,
|
|
+};
|
|
+
|
|
+asocket *find_local_socket(unsigned id)
|
|
+{
|
|
+ asocket *s;
|
|
+ asocket *result = NULL;
|
|
+
|
|
+ adb_mutex_lock(&socket_list_lock);
|
|
+ for (s = local_socket_list.next; s != &local_socket_list; s = s->next) {
|
|
+ if (s->id == id) {
|
|
+ result = s;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ adb_mutex_unlock(&socket_list_lock);
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
+static void
|
|
+insert_local_socket(asocket* s, asocket* list)
|
|
+{
|
|
+ s->next = list;
|
|
+ s->prev = s->next->prev;
|
|
+ s->prev->next = s;
|
|
+ s->next->prev = s;
|
|
+}
|
|
+
|
|
+
|
|
+void install_local_socket(asocket *s)
|
|
+{
|
|
+ adb_mutex_lock(&socket_list_lock);
|
|
+
|
|
+ s->id = local_socket_next_id++;
|
|
+ insert_local_socket(s, &local_socket_list);
|
|
+
|
|
+ adb_mutex_unlock(&socket_list_lock);
|
|
+}
|
|
+
|
|
+void remove_socket(asocket *s)
|
|
+{
|
|
+ // socket_list_lock should already be held
|
|
+ if (s->prev && s->next)
|
|
+ {
|
|
+ s->prev->next = s->next;
|
|
+ s->next->prev = s->prev;
|
|
+ s->next = 0;
|
|
+ s->prev = 0;
|
|
+ s->id = 0;
|
|
+ }
|
|
+}
|
|
+
|
|
+void close_all_sockets(atransport *t)
|
|
+{
|
|
+ asocket *s;
|
|
+
|
|
+ /* this is a little gross, but since s->close() *will* modify
|
|
+ ** the list out from under you, your options are limited.
|
|
+ */
|
|
+ adb_mutex_lock(&socket_list_lock);
|
|
+restart:
|
|
+ for(s = local_socket_list.next; s != &local_socket_list; s = s->next){
|
|
+ if(s->transport == t || (s->peer && s->peer->transport == t)) {
|
|
+ local_socket_close_locked(s);
|
|
+ goto restart;
|
|
+ }
|
|
+ }
|
|
+ adb_mutex_unlock(&socket_list_lock);
|
|
+}
|
|
+
|
|
+static int local_socket_enqueue(asocket *s, apacket *p)
|
|
+{
|
|
+ D("LS(%d): enqueue %d\n", s->id, p->len);
|
|
+
|
|
+ p->ptr = p->data;
|
|
+
|
|
+ /* if there is already data queue'd, we will receive
|
|
+ ** events when it's time to write. just add this to
|
|
+ ** the tail
|
|
+ */
|
|
+ if(s->pkt_first) {
|
|
+ goto enqueue;
|
|
+ }
|
|
+
|
|
+ /* write as much as we can, until we
|
|
+ ** would block or there is an error/eof
|
|
+ */
|
|
+ while(p->len > 0) {
|
|
+ int r = adb_write(s->fd, p->ptr, p->len);
|
|
+ if(r > 0) {
|
|
+ p->len -= r;
|
|
+ p->ptr += r;
|
|
+ continue;
|
|
+ }
|
|
+ if((r == 0) || (errno != EAGAIN)) {
|
|
+ D( "LS(%d): not ready, errno=%d: %s\n", s->id, errno, strerror(errno) );
|
|
+ s->close(s);
|
|
+ return 1; /* not ready (error) */
|
|
+ } else {
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if(p->len == 0) {
|
|
+ put_apacket(p);
|
|
+ return 0; /* ready for more data */
|
|
+ }
|
|
+
|
|
+enqueue:
|
|
+ p->next = 0;
|
|
+ if(s->pkt_first) {
|
|
+ s->pkt_last->next = p;
|
|
+ } else {
|
|
+ s->pkt_first = p;
|
|
+ }
|
|
+ s->pkt_last = p;
|
|
+
|
|
+ /* make sure we are notified when we can drain the queue */
|
|
+ fdevent_add(&s->fde, FDE_WRITE);
|
|
+
|
|
+ return 1; /* not ready (backlog) */
|
|
+}
|
|
+
|
|
+static void local_socket_ready(asocket *s)
|
|
+{
|
|
+ /* far side is ready for data, pay attention to
|
|
+ readable events */
|
|
+ fdevent_add(&s->fde, FDE_READ);
|
|
+// D("LS(%d): ready()\n", s->id);
|
|
+}
|
|
+
|
|
+static void local_socket_close(asocket *s)
|
|
+{
|
|
+ adb_mutex_lock(&socket_list_lock);
|
|
+ local_socket_close_locked(s);
|
|
+ adb_mutex_unlock(&socket_list_lock);
|
|
+}
|
|
+
|
|
+// be sure to hold the socket list lock when calling this
|
|
+static void local_socket_destroy(asocket *s)
|
|
+{
|
|
+ apacket *p, *n;
|
|
+ int exit_on_close = s->exit_on_close;
|
|
+
|
|
+ D("LS(%d): destroying fde.fd=%d\n", s->id, s->fde.fd);
|
|
+
|
|
+ /* IMPORTANT: the remove closes the fd
|
|
+ ** that belongs to this socket
|
|
+ */
|
|
+ fdevent_remove(&s->fde);
|
|
+
|
|
+ /* dispose of any unwritten data */
|
|
+ for(p = s->pkt_first; p; p = n) {
|
|
+ D("LS(%d): discarding %d bytes\n", s->id, p->len);
|
|
+ n = p->next;
|
|
+ put_apacket(p);
|
|
+ }
|
|
+ remove_socket(s);
|
|
+ free(s);
|
|
+
|
|
+ if (exit_on_close) {
|
|
+ D("local_socket_destroy: exiting\n");
|
|
+ exit(1);
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+static void local_socket_close_locked(asocket *s)
|
|
+{
|
|
+ D("entered. LS(%d) fd=%d\n", s->id, s->fd);
|
|
+ if(s->peer) {
|
|
+ D("LS(%d): closing peer. peer->id=%d peer->fd=%d\n",
|
|
+ s->id, s->peer->id, s->peer->fd);
|
|
+ s->peer->peer = 0;
|
|
+ // tweak to avoid deadlock
|
|
+ if (s->peer->close == local_socket_close) {
|
|
+ local_socket_close_locked(s->peer);
|
|
+ } else {
|
|
+ s->peer->close(s->peer);
|
|
+ }
|
|
+ s->peer = 0;
|
|
+ }
|
|
+
|
|
+ /* If we are already closing, or if there are no
|
|
+ ** pending packets, destroy immediately
|
|
+ */
|
|
+ if (s->closing || s->pkt_first == NULL) {
|
|
+ int id = s->id;
|
|
+ local_socket_destroy(s);
|
|
+ D("LS(%d): closed\n", id);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ /* otherwise, put on the closing list
|
|
+ */
|
|
+ D("LS(%d): closing\n", s->id);
|
|
+ s->closing = 1;
|
|
+ fdevent_del(&s->fde, FDE_READ);
|
|
+ remove_socket(s);
|
|
+ D("LS(%d): put on socket_closing_list fd=%d\n", s->id, s->fd);
|
|
+ insert_local_socket(s, &local_socket_closing_list);
|
|
+}
|
|
+
|
|
+static void local_socket_event_func(int fd, unsigned ev, void *_s)
|
|
+{
|
|
+ asocket *s = _s;
|
|
+
|
|
+ D("LS(%d): event_func(fd=%d(==%d), ev=%04x)\n", s->id, s->fd, fd, ev);
|
|
+
|
|
+ /* put the FDE_WRITE processing before the FDE_READ
|
|
+ ** in order to simplify the code.
|
|
+ */
|
|
+ if(ev & FDE_WRITE){
|
|
+ apacket *p;
|
|
+
|
|
+ while((p = s->pkt_first) != 0) {
|
|
+ while(p->len > 0) {
|
|
+ int r = adb_write(fd, p->ptr, p->len);
|
|
+ if(r > 0) {
|
|
+ p->ptr += r;
|
|
+ p->len -= r;
|
|
+ continue;
|
|
+ }
|
|
+ if(r < 0) {
|
|
+ /* returning here is ok because FDE_READ will
|
|
+ ** be processed in the next iteration loop
|
|
+ */
|
|
+ if(errno == EAGAIN) return;
|
|
+ if(errno == EINTR) continue;
|
|
+ }
|
|
+ D(" closing after write because r=%d and errno is %d\n", r, errno);
|
|
+ s->close(s);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if(p->len == 0) {
|
|
+ s->pkt_first = p->next;
|
|
+ if(s->pkt_first == 0) s->pkt_last = 0;
|
|
+ put_apacket(p);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* if we sent the last packet of a closing socket,
|
|
+ ** we can now destroy it.
|
|
+ */
|
|
+ if (s->closing) {
|
|
+ D(" closing because 'closing' is set after write\n");
|
|
+ s->close(s);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ /* no more packets queued, so we can ignore
|
|
+ ** writable events again and tell our peer
|
|
+ ** to resume writing
|
|
+ */
|
|
+ fdevent_del(&s->fde, FDE_WRITE);
|
|
+ s->peer->ready(s->peer);
|
|
+ }
|
|
+
|
|
+
|
|
+ if(ev & FDE_READ){
|
|
+ apacket *p = get_apacket();
|
|
+ unsigned char *x = p->data;
|
|
+ size_t avail = MAX_PAYLOAD;
|
|
+ int r;
|
|
+ int is_eof = 0;
|
|
+
|
|
+ while(avail > 0) {
|
|
+ r = adb_read(fd, x, avail);
|
|
+ D("LS(%d): post adb_read(fd=%d,...) r=%d (errno=%d) avail=%d\n", s->id, s->fd, r, r<0?errno:0, avail);
|
|
+ if(r > 0) {
|
|
+ avail -= r;
|
|
+ x += r;
|
|
+ continue;
|
|
+ }
|
|
+ if(r < 0) {
|
|
+ if(errno == EAGAIN) break;
|
|
+ if(errno == EINTR) continue;
|
|
+ }
|
|
+
|
|
+ /* r = 0 or unhandled error */
|
|
+ is_eof = 1;
|
|
+ break;
|
|
+ }
|
|
+ D("LS(%d): fd=%d post avail loop. r=%d is_eof=%d forced_eof=%d\n",
|
|
+ s->id, s->fd, r, is_eof, s->fde.force_eof);
|
|
+ if((avail == MAX_PAYLOAD) || (s->peer == 0)) {
|
|
+ put_apacket(p);
|
|
+ } else {
|
|
+ p->len = MAX_PAYLOAD - avail;
|
|
+
|
|
+ r = s->peer->enqueue(s->peer, p);
|
|
+ D("LS(%d): fd=%d post peer->enqueue(). r=%d\n", s->id, s->fd, r);
|
|
+
|
|
+ if(r < 0) {
|
|
+ /* error return means they closed us as a side-effect
|
|
+ ** and we must return immediately.
|
|
+ **
|
|
+ ** note that if we still have buffered packets, the
|
|
+ ** socket will be placed on the closing socket list.
|
|
+ ** this handler function will be called again
|
|
+ ** to process FDE_WRITE events.
|
|
+ */
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if(r > 0) {
|
|
+ /* if the remote cannot accept further events,
|
|
+ ** we disable notification of READs. They'll
|
|
+ ** be enabled again when we get a call to ready()
|
|
+ */
|
|
+ fdevent_del(&s->fde, FDE_READ);
|
|
+ }
|
|
+ }
|
|
+ /* Don't allow a forced eof if data is still there */
|
|
+ if((s->fde.force_eof && !r) || is_eof) {
|
|
+ D(" closing because is_eof=%d r=%d s->fde.force_eof=%d\n", is_eof, r, s->fde.force_eof);
|
|
+ s->close(s);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if(ev & FDE_ERROR){
|
|
+ /* this should be caught be the next read or write
|
|
+ ** catching it here means we may skip the last few
|
|
+ ** bytes of readable data.
|
|
+ */
|
|
+// s->close(s);
|
|
+ D("LS(%d): FDE_ERROR (fd=%d)\n", s->id, s->fd);
|
|
+
|
|
+ return;
|
|
+ }
|
|
+}
|
|
+
|
|
+asocket *create_local_socket(int fd)
|
|
+{
|
|
+ asocket *s = calloc(1, sizeof(asocket));
|
|
+ if (s == NULL) fatal("cannot allocate socket");
|
|
+ s->fd = fd;
|
|
+ s->enqueue = local_socket_enqueue;
|
|
+ s->ready = local_socket_ready;
|
|
+ s->close = local_socket_close;
|
|
+ install_local_socket(s);
|
|
+
|
|
+ fdevent_install(&s->fde, fd, local_socket_event_func, s);
|
|
+/* fdevent_add(&s->fde, FDE_ERROR); */
|
|
+ //fprintf(stderr, "Created local socket in create_local_socket \n");
|
|
+ D("LS(%d): created (fd=%d)\n", s->id, s->fd);
|
|
+ return s;
|
|
+}
|
|
+
|
|
+asocket *create_local_service_socket(const char *name)
|
|
+{
|
|
+ asocket *s;
|
|
+ int fd;
|
|
+
|
|
+#if !ADB_HOST
|
|
+ if (!strcmp(name,"jdwp")) {
|
|
+ return create_jdwp_service_socket();
|
|
+ }
|
|
+ if (!strcmp(name,"track-jdwp")) {
|
|
+ return create_jdwp_tracker_service_socket();
|
|
+ }
|
|
+#endif
|
|
+ fd = service_to_fd(name);
|
|
+ if(fd < 0) return 0;
|
|
+
|
|
+ s = create_local_socket(fd);
|
|
+ D("LS(%d): bound to '%s' via %d\n", s->id, name, fd);
|
|
+
|
|
+#if !ADB_HOST
|
|
+ if ((!strncmp(name, "root:", 5) && getuid() != 0)
|
|
+ || !strncmp(name, "usb:", 4)
|
|
+ || !strncmp(name, "tcpip:", 6)) {
|
|
+ D("LS(%d): enabling exit_on_close\n", s->id);
|
|
+ s->exit_on_close = 1;
|
|
+ }
|
|
+#endif
|
|
+
|
|
+ return s;
|
|
+}
|
|
+
|
|
+#if ADB_HOST
|
|
+static asocket *create_host_service_socket(const char *name, const char* serial)
|
|
+{
|
|
+ asocket *s;
|
|
+
|
|
+ s = host_service_to_socket(name, serial);
|
|
+
|
|
+ if (s != NULL) {
|
|
+ D("LS(%d) bound to '%s'\n", s->id, name);
|
|
+ return s;
|
|
+ }
|
|
+
|
|
+ return s;
|
|
+}
|
|
+#endif /* ADB_HOST */
|
|
+
|
|
+/* a Remote socket is used to send/receive data to/from a given transport object
|
|
+** it needs to be closed when the transport is forcibly destroyed by the user
|
|
+*/
|
|
+typedef struct aremotesocket {
|
|
+ asocket socket;
|
|
+ adisconnect disconnect;
|
|
+} aremotesocket;
|
|
+
|
|
+static int remote_socket_enqueue(asocket *s, apacket *p)
|
|
+{
|
|
+ D("entered remote_socket_enqueue RS(%d) WRITE fd=%d peer.fd=%d\n",
|
|
+ s->id, s->fd, s->peer->fd);
|
|
+ p->msg.command = A_WRTE;
|
|
+ p->msg.arg0 = s->peer->id;
|
|
+ p->msg.arg1 = s->id;
|
|
+ p->msg.data_length = p->len;
|
|
+ send_packet(p, s->transport);
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+static void remote_socket_ready(asocket *s)
|
|
+{
|
|
+ D("entered remote_socket_ready RS(%d) OKAY fd=%d peer.fd=%d\n",
|
|
+ s->id, s->fd, s->peer->fd);
|
|
+ apacket *p = get_apacket();
|
|
+ p->msg.command = A_OKAY;
|
|
+ p->msg.arg0 = s->peer->id;
|
|
+ p->msg.arg1 = s->id;
|
|
+ send_packet(p, s->transport);
|
|
+}
|
|
+
|
|
+static void remote_socket_close(asocket *s)
|
|
+{
|
|
+ D("entered remote_socket_close RS(%d) CLOSE fd=%d peer->fd=%d\n",
|
|
+ s->id, s->fd, s->peer?s->peer->fd:-1);
|
|
+ apacket *p = get_apacket();
|
|
+ p->msg.command = A_CLSE;
|
|
+ if(s->peer) {
|
|
+ p->msg.arg0 = s->peer->id;
|
|
+ s->peer->peer = 0;
|
|
+ D("RS(%d) peer->close()ing peer->id=%d peer->fd=%d\n",
|
|
+ s->id, s->peer->id, s->peer->fd);
|
|
+ s->peer->close(s->peer);
|
|
+ }
|
|
+ p->msg.arg1 = s->id;
|
|
+ send_packet(p, s->transport);
|
|
+ D("RS(%d): closed\n", s->id);
|
|
+ remove_transport_disconnect( s->transport, &((aremotesocket*)s)->disconnect );
|
|
+ free(s);
|
|
+}
|
|
+
|
|
+static void remote_socket_disconnect(void* _s, atransport* t)
|
|
+{
|
|
+ asocket* s = _s;
|
|
+ asocket* peer = s->peer;
|
|
+
|
|
+ D("remote_socket_disconnect RS(%d)\n", s->id);
|
|
+ if (peer) {
|
|
+ peer->peer = NULL;
|
|
+ peer->close(peer);
|
|
+ }
|
|
+ remove_transport_disconnect( s->transport, &((aremotesocket*)s)->disconnect );
|
|
+ free(s);
|
|
+}
|
|
+
|
|
+asocket *create_remote_socket(unsigned id, atransport *t)
|
|
+{
|
|
+ asocket *s = calloc(1, sizeof(aremotesocket));
|
|
+ adisconnect* dis = &((aremotesocket*)s)->disconnect;
|
|
+
|
|
+ if (s == NULL) fatal("cannot allocate socket");
|
|
+ s->id = id;
|
|
+ s->enqueue = remote_socket_enqueue;
|
|
+ s->ready = remote_socket_ready;
|
|
+ s->close = remote_socket_close;
|
|
+ s->transport = t;
|
|
+
|
|
+ dis->func = remote_socket_disconnect;
|
|
+ dis->opaque = s;
|
|
+ add_transport_disconnect( t, dis );
|
|
+ D("RS(%d): created\n", s->id);
|
|
+ return s;
|
|
+}
|
|
+
|
|
+void connect_to_remote(asocket *s, const char *destination)
|
|
+{
|
|
+ D("Connect_to_remote call RS(%d) fd=%d\n", s->id, s->fd);
|
|
+ apacket *p = get_apacket();
|
|
+ int len = strlen(destination) + 1;
|
|
+
|
|
+ if(len > (MAX_PAYLOAD-1)) {
|
|
+ fatal("destination oversized");
|
|
+ }
|
|
+
|
|
+ D("LS(%d): connect('%s')\n", s->id, destination);
|
|
+ p->msg.command = A_OPEN;
|
|
+ p->msg.arg0 = s->id;
|
|
+ p->msg.data_length = len;
|
|
+ strcpy((char*) p->data, destination);
|
|
+ send_packet(p, s->transport);
|
|
+}
|
|
+
|
|
+
|
|
+/* this is used by magic sockets to rig local sockets to
|
|
+ send the go-ahead message when they connect */
|
|
+static void local_socket_ready_notify(asocket *s)
|
|
+{
|
|
+ s->ready = local_socket_ready;
|
|
+ s->close = local_socket_close;
|
|
+ adb_write(s->fd, "OKAY", 4);
|
|
+ s->ready(s);
|
|
+}
|
|
+
|
|
+/* this is used by magic sockets to rig local sockets to
|
|
+ send the failure message if they are closed before
|
|
+ connected (to avoid closing them without a status message) */
|
|
+static void local_socket_close_notify(asocket *s)
|
|
+{
|
|
+ s->ready = local_socket_ready;
|
|
+ s->close = local_socket_close;
|
|
+ sendfailmsg(s->fd, "closed");
|
|
+ s->close(s);
|
|
+}
|
|
+
|
|
+unsigned unhex(unsigned char *s, int len)
|
|
+{
|
|
+ unsigned n = 0, c;
|
|
+
|
|
+ while(len-- > 0) {
|
|
+ switch((c = *s++)) {
|
|
+ case '0': case '1': case '2':
|
|
+ case '3': case '4': case '5':
|
|
+ case '6': case '7': case '8':
|
|
+ case '9':
|
|
+ c -= '0';
|
|
+ break;
|
|
+ case 'a': case 'b': case 'c':
|
|
+ case 'd': case 'e': case 'f':
|
|
+ c = c - 'a' + 10;
|
|
+ break;
|
|
+ case 'A': case 'B': case 'C':
|
|
+ case 'D': case 'E': case 'F':
|
|
+ c = c - 'A' + 10;
|
|
+ break;
|
|
+ default:
|
|
+ return 0xffffffff;
|
|
+ }
|
|
+
|
|
+ n = (n << 4) | c;
|
|
+ }
|
|
+
|
|
+ return n;
|
|
+}
|
|
+
|
|
+#define PREFIX(str) { str, sizeof(str) - 1 }
|
|
+static const struct prefix_struct {
|
|
+ const char *str;
|
|
+ const size_t len;
|
|
+} prefixes[] = {
|
|
+ PREFIX("usb:"),
|
|
+ PREFIX("product:"),
|
|
+ PREFIX("model:"),
|
|
+ PREFIX("device:"),
|
|
+};
|
|
+static const int num_prefixes = (sizeof(prefixes) / sizeof(prefixes[0]));
|
|
+
|
|
+/* skip_host_serial return the position in a string
|
|
+ skipping over the 'serial' parameter in the ADB protocol,
|
|
+ where parameter string may be a host:port string containing
|
|
+ the protocol delimiter (colon). */
|
|
+char *skip_host_serial(char *service) {
|
|
+ char *first_colon, *serial_end;
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < num_prefixes; i++) {
|
|
+ if (!strncmp(service, prefixes[i].str, prefixes[i].len))
|
|
+ return strchr(service + prefixes[i].len, ':');
|
|
+ }
|
|
+
|
|
+ first_colon = strchr(service, ':');
|
|
+ if (!first_colon) {
|
|
+ /* No colon in service string. */
|
|
+ return NULL;
|
|
+ }
|
|
+ serial_end = first_colon;
|
|
+ if (isdigit(serial_end[1])) {
|
|
+ serial_end++;
|
|
+ while ((*serial_end) && isdigit(*serial_end)) {
|
|
+ serial_end++;
|
|
+ }
|
|
+ if ((*serial_end) != ':') {
|
|
+ // Something other than numbers was found, reset the end.
|
|
+ serial_end = first_colon;
|
|
+ }
|
|
+ }
|
|
+ return serial_end;
|
|
+}
|
|
+
|
|
+static int smart_socket_enqueue(asocket *s, apacket *p)
|
|
+{
|
|
+ unsigned len;
|
|
+#if ADB_HOST
|
|
+ char *service = NULL;
|
|
+ char* serial = NULL;
|
|
+ transport_type ttype = kTransportAny;
|
|
+#endif
|
|
+
|
|
+ D("SS(%d): enqueue %d\n", s->id, p->len);
|
|
+
|
|
+ if(s->pkt_first == 0) {
|
|
+ s->pkt_first = p;
|
|
+ s->pkt_last = p;
|
|
+ } else {
|
|
+ if((s->pkt_first->len + p->len) > MAX_PAYLOAD) {
|
|
+ D("SS(%d): overflow\n", s->id);
|
|
+ put_apacket(p);
|
|
+ goto fail;
|
|
+ }
|
|
+
|
|
+ memcpy(s->pkt_first->data + s->pkt_first->len,
|
|
+ p->data, p->len);
|
|
+ s->pkt_first->len += p->len;
|
|
+ put_apacket(p);
|
|
+
|
|
+ p = s->pkt_first;
|
|
+ }
|
|
+
|
|
+ /* don't bother if we can't decode the length */
|
|
+ if(p->len < 4) return 0;
|
|
+
|
|
+ len = unhex(p->data, 4);
|
|
+ if((len < 1) || (len > 1024)) {
|
|
+ D("SS(%d): bad size (%d)\n", s->id, len);
|
|
+ goto fail;
|
|
+ }
|
|
+
|
|
+ D("SS(%d): len is %d\n", s->id, len );
|
|
+ /* can't do anything until we have the full header */
|
|
+ if((len + 4) > p->len) {
|
|
+ D("SS(%d): waiting for %d more bytes\n", s->id, len+4 - p->len);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ p->data[len + 4] = 0;
|
|
+
|
|
+ D("SS(%d): '%s'\n", s->id, (char*) (p->data + 4));
|
|
+
|
|
+#if ADB_HOST
|
|
+ service = (char *)p->data + 4;
|
|
+ if(!strncmp(service, "host-serial:", strlen("host-serial:"))) {
|
|
+ char* serial_end;
|
|
+ service += strlen("host-serial:");
|
|
+
|
|
+ // serial number should follow "host:" and could be a host:port string.
|
|
+ serial_end = skip_host_serial(service);
|
|
+ if (serial_end) {
|
|
+ *serial_end = 0; // terminate string
|
|
+ serial = service;
|
|
+ service = serial_end + 1;
|
|
+ }
|
|
+ } else if (!strncmp(service, "host-usb:", strlen("host-usb:"))) {
|
|
+ ttype = kTransportUsb;
|
|
+ service += strlen("host-usb:");
|
|
+ } else if (!strncmp(service, "host-local:", strlen("host-local:"))) {
|
|
+ ttype = kTransportLocal;
|
|
+ service += strlen("host-local:");
|
|
+ } else if (!strncmp(service, "host:", strlen("host:"))) {
|
|
+ ttype = kTransportAny;
|
|
+ service += strlen("host:");
|
|
+ } else {
|
|
+ service = NULL;
|
|
+ }
|
|
+
|
|
+ if (service) {
|
|
+ asocket *s2;
|
|
+
|
|
+ /* some requests are handled immediately -- in that
|
|
+ ** case the handle_host_request() routine has sent
|
|
+ ** the OKAY or FAIL message and all we have to do
|
|
+ ** is clean up.
|
|
+ */
|
|
+ if(handle_host_request(service, ttype, serial, s->peer->fd, s) == 0) {
|
|
+ /* XXX fail message? */
|
|
+ D( "SS(%d): handled host service '%s'\n", s->id, service );
|
|
+ goto fail;
|
|
+ }
|
|
+ if (!strncmp(service, "transport", strlen("transport"))) {
|
|
+ D( "SS(%d): okay transport\n", s->id );
|
|
+ p->len = 0;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ /* try to find a local service with this name.
|
|
+ ** if no such service exists, we'll fail out
|
|
+ ** and tear down here.
|
|
+ */
|
|
+ s2 = create_host_service_socket(service, serial);
|
|
+ if(s2 == 0) {
|
|
+ D( "SS(%d): couldn't create host service '%s'\n", s->id, service );
|
|
+ sendfailmsg(s->peer->fd, "unknown host service");
|
|
+ goto fail;
|
|
+ }
|
|
+
|
|
+ /* we've connected to a local host service,
|
|
+ ** so we make our peer back into a regular
|
|
+ ** local socket and bind it to the new local
|
|
+ ** service socket, acknowledge the successful
|
|
+ ** connection, and close this smart socket now
|
|
+ ** that its work is done.
|
|
+ */
|
|
+ adb_write(s->peer->fd, "OKAY", 4);
|
|
+
|
|
+ s->peer->ready = local_socket_ready;
|
|
+ s->peer->close = local_socket_close;
|
|
+ s->peer->peer = s2;
|
|
+ s2->peer = s->peer;
|
|
+ s->peer = 0;
|
|
+ D( "SS(%d): okay\n", s->id );
|
|
+ s->close(s);
|
|
+
|
|
+ /* initial state is "ready" */
|
|
+ s2->ready(s2);
|
|
+ return 0;
|
|
+ }
|
|
+#else /* !ADB_HOST */
|
|
+ if (s->transport == NULL) {
|
|
+ char* error_string = "unknown failure";
|
|
+ s->transport = acquire_one_transport (CS_ANY,
|
|
+ kTransportAny, NULL, &error_string);
|
|
+
|
|
+ if (s->transport == NULL) {
|
|
+ sendfailmsg(s->peer->fd, error_string);
|
|
+ goto fail;
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+
|
|
+ if(!(s->transport) || (s->transport->connection_state == CS_OFFLINE)) {
|
|
+ /* if there's no remote we fail the connection
|
|
+ ** right here and terminate it
|
|
+ */
|
|
+ sendfailmsg(s->peer->fd, "device offline (x)");
|
|
+ goto fail;
|
|
+ }
|
|
+
|
|
+
|
|
+ /* instrument our peer to pass the success or fail
|
|
+ ** message back once it connects or closes, then
|
|
+ ** detach from it, request the connection, and
|
|
+ ** tear down
|
|
+ */
|
|
+ s->peer->ready = local_socket_ready_notify;
|
|
+ s->peer->close = local_socket_close_notify;
|
|
+ s->peer->peer = 0;
|
|
+ /* give him our transport and upref it */
|
|
+ s->peer->transport = s->transport;
|
|
+
|
|
+ connect_to_remote(s->peer, (char*) (p->data + 4));
|
|
+ s->peer = 0;
|
|
+ s->close(s);
|
|
+ return 1;
|
|
+
|
|
+fail:
|
|
+ /* we're going to close our peer as a side-effect, so
|
|
+ ** return -1 to signal that state to the local socket
|
|
+ ** who is enqueueing against us
|
|
+ */
|
|
+ s->close(s);
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+static void smart_socket_ready(asocket *s)
|
|
+{
|
|
+ D("SS(%d): ready\n", s->id);
|
|
+}
|
|
+
|
|
+static void smart_socket_close(asocket *s)
|
|
+{
|
|
+ D("SS(%d): closed\n", s->id);
|
|
+ if(s->pkt_first){
|
|
+ put_apacket(s->pkt_first);
|
|
+ }
|
|
+ if(s->peer) {
|
|
+ s->peer->peer = 0;
|
|
+ s->peer->close(s->peer);
|
|
+ s->peer = 0;
|
|
+ }
|
|
+ free(s);
|
|
+}
|
|
+
|
|
+asocket *create_smart_socket(void (*action_cb)(asocket *s, const char *act))
|
|
+{
|
|
+ D("Creating smart socket \n");
|
|
+ asocket *s = calloc(1, sizeof(asocket));
|
|
+ if (s == NULL) fatal("cannot allocate socket");
|
|
+ s->enqueue = smart_socket_enqueue;
|
|
+ s->ready = smart_socket_ready;
|
|
+ s->close = smart_socket_close;
|
|
+ s->extra = action_cb;
|
|
+
|
|
+ D("SS(%d): created %p\n", s->id, action_cb);
|
|
+ return s;
|
|
+}
|
|
+
|
|
+void smart_socket_action(asocket *s, const char *act)
|
|
+{
|
|
+
|
|
+}
|
|
+
|
|
+void connect_to_smartsocket(asocket *s)
|
|
+{
|
|
+ D("Connecting to smart socket \n");
|
|
+ asocket *ss = create_smart_socket(smart_socket_action);
|
|
+ s->peer = ss;
|
|
+ ss->peer = s;
|
|
+ s->ready(s);
|
|
+}
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/sysdeps.h
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/sysdeps.h 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,522 @@
|
|
+/*
|
|
+ * Copyright (C) 2007 The Android Open Source Project
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
+ * you may not use this file except in compliance with the License.
|
|
+ * You may obtain a copy of the License at
|
|
+ *
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
+ *
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+ * See the License for the specific language governing permissions and
|
|
+ * limitations under the License.
|
|
+ */
|
|
+
|
|
+/* this file contains system-dependent definitions used by ADB
|
|
+ * they're related to threads, sockets and file descriptors
|
|
+ */
|
|
+#ifndef _ADB_SYSDEPS_H
|
|
+#define _ADB_SYSDEPS_H
|
|
+
|
|
+#ifdef __CYGWIN__
|
|
+# undef _WIN32
|
|
+#endif
|
|
+
|
|
+#ifdef _WIN32
|
|
+
|
|
+#include <windows.h>
|
|
+#include <winsock2.h>
|
|
+#include <ws2tcpip.h>
|
|
+#include <process.h>
|
|
+#include <fcntl.h>
|
|
+#include <io.h>
|
|
+#include <sys/stat.h>
|
|
+#include <errno.h>
|
|
+#include <ctype.h>
|
|
+
|
|
+#define OS_PATH_SEPARATOR '\\'
|
|
+#define OS_PATH_SEPARATOR_STR "\\"
|
|
+#define ENV_PATH_SEPARATOR_STR ";"
|
|
+
|
|
+typedef CRITICAL_SECTION adb_mutex_t;
|
|
+
|
|
+#define ADB_MUTEX_DEFINE(x) adb_mutex_t x
|
|
+
|
|
+/* declare all mutexes */
|
|
+/* For win32, adb_sysdeps_init() will do the mutex runtime initialization. */
|
|
+#define ADB_MUTEX(x) extern adb_mutex_t x;
|
|
+#include "mutex_list.h"
|
|
+
|
|
+extern void adb_sysdeps_init(void);
|
|
+
|
|
+static __inline__ void adb_mutex_lock( adb_mutex_t* lock )
|
|
+{
|
|
+ EnterCriticalSection( lock );
|
|
+}
|
|
+
|
|
+static __inline__ void adb_mutex_unlock( adb_mutex_t* lock )
|
|
+{
|
|
+ LeaveCriticalSection( lock );
|
|
+}
|
|
+
|
|
+typedef struct { unsigned tid; } adb_thread_t;
|
|
+
|
|
+typedef void* (*adb_thread_func_t)(void* arg);
|
|
+
|
|
+typedef void (*win_thread_func_t)(void* arg);
|
|
+
|
|
+static __inline__ int adb_thread_create( adb_thread_t *thread, adb_thread_func_t func, void* arg)
|
|
+{
|
|
+ thread->tid = _beginthread( (win_thread_func_t)func, 0, arg );
|
|
+ if (thread->tid == (unsigned)-1L) {
|
|
+ return -1;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static __inline__ void close_on_exec(int fd)
|
|
+{
|
|
+ /* nothing really */
|
|
+}
|
|
+
|
|
+extern void disable_tcp_nagle(int fd);
|
|
+
|
|
+#define lstat stat /* no symlinks on Win32 */
|
|
+
|
|
+#define S_ISLNK(m) 0 /* no symlinks on Win32 */
|
|
+
|
|
+static __inline__ int adb_unlink(const char* path)
|
|
+{
|
|
+ int rc = unlink(path);
|
|
+
|
|
+ if (rc == -1 && errno == EACCES) {
|
|
+ /* unlink returns EACCES when the file is read-only, so we first */
|
|
+ /* try to make it writable, then unlink again... */
|
|
+ rc = chmod(path, _S_IREAD|_S_IWRITE );
|
|
+ if (rc == 0)
|
|
+ rc = unlink(path);
|
|
+ }
|
|
+ return rc;
|
|
+}
|
|
+#undef unlink
|
|
+#define unlink ___xxx_unlink
|
|
+
|
|
+static __inline__ int adb_mkdir(const char* path, int mode)
|
|
+{
|
|
+ return _mkdir(path);
|
|
+}
|
|
+#undef mkdir
|
|
+#define mkdir ___xxx_mkdir
|
|
+
|
|
+extern int adb_open(const char* path, int options);
|
|
+extern int adb_creat(const char* path, int mode);
|
|
+extern int adb_read(int fd, void* buf, int len);
|
|
+extern int adb_write(int fd, const void* buf, int len);
|
|
+extern int adb_lseek(int fd, int pos, int where);
|
|
+extern int adb_shutdown(int fd);
|
|
+extern int adb_close(int fd);
|
|
+
|
|
+static __inline__ int unix_close(int fd)
|
|
+{
|
|
+ return close(fd);
|
|
+}
|
|
+#undef close
|
|
+#define close ____xxx_close
|
|
+
|
|
+static __inline__ int unix_read(int fd, void* buf, size_t len)
|
|
+{
|
|
+ return read(fd, buf, len);
|
|
+}
|
|
+#undef read
|
|
+#define read ___xxx_read
|
|
+
|
|
+static __inline__ int unix_write(int fd, const void* buf, size_t len)
|
|
+{
|
|
+ return write(fd, buf, len);
|
|
+}
|
|
+#undef write
|
|
+#define write ___xxx_write
|
|
+
|
|
+static __inline__ int adb_open_mode(const char* path, int options, int mode)
|
|
+{
|
|
+ return adb_open(path, options);
|
|
+}
|
|
+
|
|
+static __inline__ int unix_open(const char* path, int options,...)
|
|
+{
|
|
+ if ((options & O_CREAT) == 0)
|
|
+ {
|
|
+ return open(path, options);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ int mode;
|
|
+ va_list args;
|
|
+ va_start( args, options );
|
|
+ mode = va_arg( args, int );
|
|
+ va_end( args );
|
|
+ return open(path, options, mode);
|
|
+ }
|
|
+}
|
|
+#define open ___xxx_unix_open
|
|
+
|
|
+
|
|
+/* normally provided by <cutils/misc.h> */
|
|
+extern void* load_file(const char* pathname, unsigned* psize);
|
|
+
|
|
+/* normally provided by <cutils/sockets.h> */
|
|
+extern int socket_loopback_client(int port, int type);
|
|
+extern int socket_network_client(const char *host, int port, int type);
|
|
+extern int socket_loopback_server(int port, int type);
|
|
+extern int socket_inaddr_any_server(int port, int type);
|
|
+
|
|
+/* normally provided by "fdevent.h" */
|
|
+
|
|
+#define FDE_READ 0x0001
|
|
+#define FDE_WRITE 0x0002
|
|
+#define FDE_ERROR 0x0004
|
|
+#define FDE_DONT_CLOSE 0x0080
|
|
+
|
|
+typedef struct fdevent fdevent;
|
|
+
|
|
+typedef void (*fd_func)(int fd, unsigned events, void *userdata);
|
|
+
|
|
+fdevent *fdevent_create(int fd, fd_func func, void *arg);
|
|
+void fdevent_destroy(fdevent *fde);
|
|
+void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg);
|
|
+void fdevent_remove(fdevent *item);
|
|
+void fdevent_set(fdevent *fde, unsigned events);
|
|
+void fdevent_add(fdevent *fde, unsigned events);
|
|
+void fdevent_del(fdevent *fde, unsigned events);
|
|
+void fdevent_loop();
|
|
+
|
|
+struct fdevent {
|
|
+ fdevent *next;
|
|
+ fdevent *prev;
|
|
+
|
|
+ int fd;
|
|
+ int force_eof;
|
|
+
|
|
+ unsigned short state;
|
|
+ unsigned short events;
|
|
+
|
|
+ fd_func func;
|
|
+ void *arg;
|
|
+};
|
|
+
|
|
+static __inline__ void adb_sleep_ms( int mseconds )
|
|
+{
|
|
+ Sleep( mseconds );
|
|
+}
|
|
+
|
|
+extern int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen);
|
|
+
|
|
+#undef accept
|
|
+#define accept ___xxx_accept
|
|
+
|
|
+static __inline__ int adb_socket_setbufsize( int fd, int bufsize )
|
|
+{
|
|
+ int opt = bufsize;
|
|
+ return setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char*)&opt, sizeof(opt));
|
|
+}
|
|
+
|
|
+extern int adb_socketpair( int sv[2] );
|
|
+
|
|
+static __inline__ char* adb_dirstart( const char* path )
|
|
+{
|
|
+ char* p = strchr(path, '/');
|
|
+ char* p2 = strchr(path, '\\');
|
|
+
|
|
+ if ( !p )
|
|
+ p = p2;
|
|
+ else if ( p2 && p2 > p )
|
|
+ p = p2;
|
|
+
|
|
+ return p;
|
|
+}
|
|
+
|
|
+static __inline__ char* adb_dirstop( const char* path )
|
|
+{
|
|
+ char* p = strrchr(path, '/');
|
|
+ char* p2 = strrchr(path, '\\');
|
|
+
|
|
+ if ( !p )
|
|
+ p = p2;
|
|
+ else if ( p2 && p2 > p )
|
|
+ p = p2;
|
|
+
|
|
+ return p;
|
|
+}
|
|
+
|
|
+static __inline__ int adb_is_absolute_host_path( const char* path )
|
|
+{
|
|
+ return isalpha(path[0]) && path[1] == ':' && path[2] == '\\';
|
|
+}
|
|
+
|
|
+extern char* adb_strtok_r(char *str, const char *delim, char **saveptr);
|
|
+
|
|
+#else /* !_WIN32 a.k.a. Unix */
|
|
+
|
|
+#include "fdevent.h"
|
|
+#include <cutils/sockets.h>
|
|
+#include <cutils/properties.h>
|
|
+#include <cutils/misc.h>
|
|
+#include <signal.h>
|
|
+#include <sys/wait.h>
|
|
+#include <sys/stat.h>
|
|
+#include <fcntl.h>
|
|
+
|
|
+#include <pthread.h>
|
|
+#include <unistd.h>
|
|
+#include <fcntl.h>
|
|
+#include <stdarg.h>
|
|
+#include <netinet/in.h>
|
|
+#include <netinet/tcp.h>
|
|
+#include <string.h>
|
|
+#include <unistd.h>
|
|
+
|
|
+/*
|
|
+ * TEMP_FAILURE_RETRY is defined by some, but not all, versions of
|
|
+ * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
|
|
+ * not already defined, then define it here.
|
|
+ */
|
|
+#ifndef TEMP_FAILURE_RETRY
|
|
+/* Used to retry syscalls that can return EINTR. */
|
|
+#define TEMP_FAILURE_RETRY(exp) ({ \
|
|
+ typeof (exp) _rc; \
|
|
+ do { \
|
|
+ _rc = (exp); \
|
|
+ } while (_rc == -1 && errno == EINTR); \
|
|
+ _rc; })
|
|
+#endif
|
|
+
|
|
+#define OS_PATH_SEPARATOR '/'
|
|
+#define OS_PATH_SEPARATOR_STR "/"
|
|
+#define ENV_PATH_SEPARATOR_STR ":"
|
|
+
|
|
+typedef pthread_mutex_t adb_mutex_t;
|
|
+
|
|
+#define ADB_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
|
|
+#define adb_mutex_init pthread_mutex_init
|
|
+#define adb_mutex_lock pthread_mutex_lock
|
|
+#define adb_mutex_unlock pthread_mutex_unlock
|
|
+#define adb_mutex_destroy pthread_mutex_destroy
|
|
+
|
|
+#define ADB_MUTEX_DEFINE(m) adb_mutex_t m = PTHREAD_MUTEX_INITIALIZER
|
|
+
|
|
+#define adb_cond_t pthread_cond_t
|
|
+#define adb_cond_init pthread_cond_init
|
|
+#define adb_cond_wait pthread_cond_wait
|
|
+#define adb_cond_broadcast pthread_cond_broadcast
|
|
+#define adb_cond_signal pthread_cond_signal
|
|
+#define adb_cond_destroy pthread_cond_destroy
|
|
+
|
|
+/* declare all mutexes */
|
|
+#define ADB_MUTEX(x) extern adb_mutex_t x;
|
|
+#include "mutex_list.h"
|
|
+
|
|
+static __inline__ void close_on_exec(int fd)
|
|
+{
|
|
+ fcntl( fd, F_SETFD, FD_CLOEXEC );
|
|
+}
|
|
+
|
|
+static __inline__ int unix_open(const char* path, int options,...)
|
|
+{
|
|
+ if ((options & O_CREAT) == 0)
|
|
+ {
|
|
+ return TEMP_FAILURE_RETRY( open(path, options) );
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ int mode;
|
|
+ va_list args;
|
|
+ va_start( args, options );
|
|
+ mode = va_arg( args, int );
|
|
+ va_end( args );
|
|
+ return TEMP_FAILURE_RETRY( open( path, options, mode ) );
|
|
+ }
|
|
+}
|
|
+
|
|
+static __inline__ int adb_open_mode( const char* pathname, int options, int mode )
|
|
+{
|
|
+ return TEMP_FAILURE_RETRY( open( pathname, options, mode ) );
|
|
+}
|
|
+
|
|
+
|
|
+static __inline__ int adb_open( const char* pathname, int options )
|
|
+{
|
|
+ int fd = TEMP_FAILURE_RETRY( open( pathname, options ) );
|
|
+ if (fd < 0)
|
|
+ return -1;
|
|
+ close_on_exec( fd );
|
|
+ return fd;
|
|
+}
|
|
+#undef open
|
|
+#define open ___xxx_open
|
|
+
|
|
+static __inline__ int adb_shutdown(int fd)
|
|
+{
|
|
+ return shutdown(fd, SHUT_RDWR);
|
|
+}
|
|
+#undef shutdown
|
|
+#define shutdown ____xxx_shutdown
|
|
+
|
|
+static __inline__ int adb_close(int fd)
|
|
+{
|
|
+ return close(fd);
|
|
+}
|
|
+#undef close
|
|
+#define close ____xxx_close
|
|
+
|
|
+
|
|
+static __inline__ int adb_read(int fd, void* buf, size_t len)
|
|
+{
|
|
+ return TEMP_FAILURE_RETRY( read( fd, buf, len ) );
|
|
+}
|
|
+
|
|
+#undef read
|
|
+#define read ___xxx_read
|
|
+
|
|
+static __inline__ int adb_write(int fd, const void* buf, size_t len)
|
|
+{
|
|
+ return TEMP_FAILURE_RETRY( write( fd, buf, len ) );
|
|
+}
|
|
+#undef write
|
|
+#define write ___xxx_write
|
|
+
|
|
+static __inline__ int adb_lseek(int fd, int pos, int where)
|
|
+{
|
|
+ return lseek(fd, pos, where);
|
|
+}
|
|
+#undef lseek
|
|
+#define lseek ___xxx_lseek
|
|
+
|
|
+static __inline__ int adb_unlink(const char* path)
|
|
+{
|
|
+ return unlink(path);
|
|
+}
|
|
+#undef unlink
|
|
+#define unlink ___xxx_unlink
|
|
+
|
|
+static __inline__ int adb_creat(const char* path, int mode)
|
|
+{
|
|
+ int fd = TEMP_FAILURE_RETRY( creat( path, mode ) );
|
|
+
|
|
+ if ( fd < 0 )
|
|
+ return -1;
|
|
+
|
|
+ close_on_exec(fd);
|
|
+ return fd;
|
|
+}
|
|
+#undef creat
|
|
+#define creat ___xxx_creat
|
|
+
|
|
+static __inline__ int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen)
|
|
+{
|
|
+ int fd;
|
|
+
|
|
+ fd = TEMP_FAILURE_RETRY( accept( serverfd, addr, addrlen ) );
|
|
+ if (fd >= 0)
|
|
+ close_on_exec(fd);
|
|
+
|
|
+ return fd;
|
|
+}
|
|
+
|
|
+#undef accept
|
|
+#define accept ___xxx_accept
|
|
+
|
|
+#define unix_read adb_read
|
|
+#define unix_write adb_write
|
|
+#define unix_close adb_close
|
|
+
|
|
+typedef pthread_t adb_thread_t;
|
|
+
|
|
+typedef void* (*adb_thread_func_t)( void* arg );
|
|
+
|
|
+static __inline__ int adb_thread_create( adb_thread_t *pthread, adb_thread_func_t start, void* arg )
|
|
+{
|
|
+ pthread_attr_t attr;
|
|
+
|
|
+ pthread_attr_init (&attr);
|
|
+ pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
|
|
+
|
|
+ return pthread_create( pthread, &attr, start, arg );
|
|
+}
|
|
+
|
|
+static __inline__ int adb_socket_setbufsize( int fd, int bufsize )
|
|
+{
|
|
+ int opt = bufsize;
|
|
+ return setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
|
|
+}
|
|
+
|
|
+static __inline__ void disable_tcp_nagle(int fd)
|
|
+{
|
|
+ int on = 1;
|
|
+ setsockopt( fd, IPPROTO_TCP, TCP_NODELAY, (void*)&on, sizeof(on) );
|
|
+}
|
|
+
|
|
+
|
|
+static __inline__ int unix_socketpair( int d, int type, int protocol, int sv[2] )
|
|
+{
|
|
+ return socketpair( d, type, protocol, sv );
|
|
+}
|
|
+
|
|
+static __inline__ int adb_socketpair( int sv[2] )
|
|
+{
|
|
+ int rc;
|
|
+
|
|
+ rc = unix_socketpair( AF_UNIX, SOCK_STREAM, 0, sv );
|
|
+ if (rc < 0)
|
|
+ return -1;
|
|
+
|
|
+ close_on_exec( sv[0] );
|
|
+ close_on_exec( sv[1] );
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+#undef socketpair
|
|
+#define socketpair ___xxx_socketpair
|
|
+
|
|
+static __inline__ void adb_sleep_ms( int mseconds )
|
|
+{
|
|
+ usleep( mseconds*1000 );
|
|
+}
|
|
+
|
|
+static __inline__ int adb_mkdir(const char* path, int mode)
|
|
+{
|
|
+ return mkdir(path, mode);
|
|
+}
|
|
+#undef mkdir
|
|
+#define mkdir ___xxx_mkdir
|
|
+
|
|
+static __inline__ void adb_sysdeps_init(void)
|
|
+{
|
|
+}
|
|
+
|
|
+static __inline__ char* adb_dirstart(const char* path)
|
|
+{
|
|
+ return strchr(path, '/');
|
|
+}
|
|
+
|
|
+static __inline__ char* adb_dirstop(const char* path)
|
|
+{
|
|
+ return strrchr(path, '/');
|
|
+}
|
|
+
|
|
+static __inline__ int adb_is_absolute_host_path( const char* path )
|
|
+{
|
|
+ return path[0] == '/';
|
|
+}
|
|
+
|
|
+static __inline__ char* adb_strtok_r(char *str, const char *delim, char **saveptr)
|
|
+{
|
|
+ return strtok_r(str, delim, saveptr);
|
|
+}
|
|
+#undef strtok_r
|
|
+#define strtok_r ___xxx_strtok_r
|
|
+
|
|
+#endif /* !_WIN32 */
|
|
+
|
|
+#endif /* _ADB_SYSDEPS_H */
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/sysdeps_win32.c
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/sysdeps_win32.c 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,2220 @@
|
|
+#include "sysdeps.h"
|
|
+#include <windows.h>
|
|
+#include <winsock2.h>
|
|
+#include <stdio.h>
|
|
+#include <errno.h>
|
|
+#define TRACE_TAG TRACE_SYSDEPS
|
|
+#include "adb.h"
|
|
+
|
|
+extern void fatal(const char *fmt, ...);
|
|
+
|
|
+#define assert(cond) do { if (!(cond)) fatal( "assertion failed '%s' on %s:%ld\n", #cond, __FILE__, __LINE__ ); } while (0)
|
|
+
|
|
+/**************************************************************************/
|
|
+/**************************************************************************/
|
|
+/***** *****/
|
|
+/***** replaces libs/cutils/load_file.c *****/
|
|
+/***** *****/
|
|
+/**************************************************************************/
|
|
+/**************************************************************************/
|
|
+
|
|
+void *load_file(const char *fn, unsigned *_sz)
|
|
+{
|
|
+ HANDLE file;
|
|
+ char *data;
|
|
+ DWORD file_size;
|
|
+
|
|
+ file = CreateFile( fn,
|
|
+ GENERIC_READ,
|
|
+ FILE_SHARE_READ,
|
|
+ NULL,
|
|
+ OPEN_EXISTING,
|
|
+ 0,
|
|
+ NULL );
|
|
+
|
|
+ if (file == INVALID_HANDLE_VALUE)
|
|
+ return NULL;
|
|
+
|
|
+ file_size = GetFileSize( file, NULL );
|
|
+ data = NULL;
|
|
+
|
|
+ if (file_size > 0) {
|
|
+ data = (char*) malloc( file_size + 1 );
|
|
+ if (data == NULL) {
|
|
+ D("load_file: could not allocate %ld bytes\n", file_size );
|
|
+ file_size = 0;
|
|
+ } else {
|
|
+ DWORD out_bytes;
|
|
+
|
|
+ if ( !ReadFile( file, data, file_size, &out_bytes, NULL ) ||
|
|
+ out_bytes != file_size )
|
|
+ {
|
|
+ D("load_file: could not read %ld bytes from '%s'\n", file_size, fn);
|
|
+ free(data);
|
|
+ data = NULL;
|
|
+ file_size = 0;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ CloseHandle( file );
|
|
+
|
|
+ *_sz = (unsigned) file_size;
|
|
+ return data;
|
|
+}
|
|
+
|
|
+/**************************************************************************/
|
|
+/**************************************************************************/
|
|
+/***** *****/
|
|
+/***** common file descriptor handling *****/
|
|
+/***** *****/
|
|
+/**************************************************************************/
|
|
+/**************************************************************************/
|
|
+
|
|
+typedef const struct FHClassRec_* FHClass;
|
|
+
|
|
+typedef struct FHRec_* FH;
|
|
+
|
|
+typedef struct EventHookRec_* EventHook;
|
|
+
|
|
+typedef struct FHClassRec_
|
|
+{
|
|
+ void (*_fh_init) ( FH f );
|
|
+ int (*_fh_close)( FH f );
|
|
+ int (*_fh_lseek)( FH f, int pos, int origin );
|
|
+ int (*_fh_read) ( FH f, void* buf, int len );
|
|
+ int (*_fh_write)( FH f, const void* buf, int len );
|
|
+ void (*_fh_hook) ( FH f, int events, EventHook hook );
|
|
+
|
|
+} FHClassRec;
|
|
+
|
|
+/* used to emulate unix-domain socket pairs */
|
|
+typedef struct SocketPairRec_* SocketPair;
|
|
+
|
|
+typedef struct FHRec_
|
|
+{
|
|
+ FHClass clazz;
|
|
+ int used;
|
|
+ int eof;
|
|
+ union {
|
|
+ HANDLE handle;
|
|
+ SOCKET socket;
|
|
+ SocketPair pair;
|
|
+ } u;
|
|
+
|
|
+ HANDLE event;
|
|
+ int mask;
|
|
+
|
|
+ char name[32];
|
|
+
|
|
+} FHRec;
|
|
+
|
|
+#define fh_handle u.handle
|
|
+#define fh_socket u.socket
|
|
+#define fh_pair u.pair
|
|
+
|
|
+#define WIN32_FH_BASE 100
|
|
+
|
|
+#define WIN32_MAX_FHS 128
|
|
+
|
|
+static adb_mutex_t _win32_lock;
|
|
+static FHRec _win32_fhs[ WIN32_MAX_FHS ];
|
|
+static int _win32_fh_count;
|
|
+
|
|
+static FH
|
|
+_fh_from_int( int fd )
|
|
+{
|
|
+ FH f;
|
|
+
|
|
+ fd -= WIN32_FH_BASE;
|
|
+
|
|
+ if (fd < 0 || fd >= _win32_fh_count) {
|
|
+ D( "_fh_from_int: invalid fd %d\n", fd + WIN32_FH_BASE );
|
|
+ errno = EBADF;
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ f = &_win32_fhs[fd];
|
|
+
|
|
+ if (f->used == 0) {
|
|
+ D( "_fh_from_int: invalid fd %d\n", fd + WIN32_FH_BASE );
|
|
+ errno = EBADF;
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ return f;
|
|
+}
|
|
+
|
|
+
|
|
+static int
|
|
+_fh_to_int( FH f )
|
|
+{
|
|
+ if (f && f->used && f >= _win32_fhs && f < _win32_fhs + WIN32_MAX_FHS)
|
|
+ return (int)(f - _win32_fhs) + WIN32_FH_BASE;
|
|
+
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+static FH
|
|
+_fh_alloc( FHClass clazz )
|
|
+{
|
|
+ int nn;
|
|
+ FH f = NULL;
|
|
+
|
|
+ adb_mutex_lock( &_win32_lock );
|
|
+
|
|
+ if (_win32_fh_count < WIN32_MAX_FHS) {
|
|
+ f = &_win32_fhs[ _win32_fh_count++ ];
|
|
+ goto Exit;
|
|
+ }
|
|
+
|
|
+ for (nn = 0; nn < WIN32_MAX_FHS; nn++) {
|
|
+ if ( _win32_fhs[nn].clazz == NULL) {
|
|
+ f = &_win32_fhs[nn];
|
|
+ goto Exit;
|
|
+ }
|
|
+ }
|
|
+ D( "_fh_alloc: no more free file descriptors\n" );
|
|
+Exit:
|
|
+ if (f) {
|
|
+ f->clazz = clazz;
|
|
+ f->used = 1;
|
|
+ f->eof = 0;
|
|
+ clazz->_fh_init(f);
|
|
+ }
|
|
+ adb_mutex_unlock( &_win32_lock );
|
|
+ return f;
|
|
+}
|
|
+
|
|
+
|
|
+static int
|
|
+_fh_close( FH f )
|
|
+{
|
|
+ if ( f->used ) {
|
|
+ f->clazz->_fh_close( f );
|
|
+ f->used = 0;
|
|
+ f->eof = 0;
|
|
+ f->clazz = NULL;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* forward definitions */
|
|
+static const FHClassRec _fh_file_class;
|
|
+static const FHClassRec _fh_socket_class;
|
|
+
|
|
+/**************************************************************************/
|
|
+/**************************************************************************/
|
|
+/***** *****/
|
|
+/***** file-based descriptor handling *****/
|
|
+/***** *****/
|
|
+/**************************************************************************/
|
|
+/**************************************************************************/
|
|
+
|
|
+static void
|
|
+_fh_file_init( FH f )
|
|
+{
|
|
+ f->fh_handle = INVALID_HANDLE_VALUE;
|
|
+}
|
|
+
|
|
+static int
|
|
+_fh_file_close( FH f )
|
|
+{
|
|
+ CloseHandle( f->fh_handle );
|
|
+ f->fh_handle = INVALID_HANDLE_VALUE;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+_fh_file_read( FH f, void* buf, int len )
|
|
+{
|
|
+ DWORD read_bytes;
|
|
+
|
|
+ if ( !ReadFile( f->fh_handle, buf, (DWORD)len, &read_bytes, NULL ) ) {
|
|
+ D( "adb_read: could not read %d bytes from %s\n", len, f->name );
|
|
+ errno = EIO;
|
|
+ return -1;
|
|
+ } else if (read_bytes < (DWORD)len) {
|
|
+ f->eof = 1;
|
|
+ }
|
|
+ return (int)read_bytes;
|
|
+}
|
|
+
|
|
+static int
|
|
+_fh_file_write( FH f, const void* buf, int len )
|
|
+{
|
|
+ DWORD wrote_bytes;
|
|
+
|
|
+ if ( !WriteFile( f->fh_handle, buf, (DWORD)len, &wrote_bytes, NULL ) ) {
|
|
+ D( "adb_file_write: could not write %d bytes from %s\n", len, f->name );
|
|
+ errno = EIO;
|
|
+ return -1;
|
|
+ } else if (wrote_bytes < (DWORD)len) {
|
|
+ f->eof = 1;
|
|
+ }
|
|
+ return (int)wrote_bytes;
|
|
+}
|
|
+
|
|
+static int
|
|
+_fh_file_lseek( FH f, int pos, int origin )
|
|
+{
|
|
+ DWORD method;
|
|
+ DWORD result;
|
|
+
|
|
+ switch (origin)
|
|
+ {
|
|
+ case SEEK_SET: method = FILE_BEGIN; break;
|
|
+ case SEEK_CUR: method = FILE_CURRENT; break;
|
|
+ case SEEK_END: method = FILE_END; break;
|
|
+ default:
|
|
+ errno = EINVAL;
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ result = SetFilePointer( f->fh_handle, pos, NULL, method );
|
|
+ if (result == INVALID_SET_FILE_POINTER) {
|
|
+ errno = EIO;
|
|
+ return -1;
|
|
+ } else {
|
|
+ f->eof = 0;
|
|
+ }
|
|
+ return (int)result;
|
|
+}
|
|
+
|
|
+static void _fh_file_hook( FH f, int event, EventHook eventhook ); /* forward */
|
|
+
|
|
+static const FHClassRec _fh_file_class =
|
|
+{
|
|
+ _fh_file_init,
|
|
+ _fh_file_close,
|
|
+ _fh_file_lseek,
|
|
+ _fh_file_read,
|
|
+ _fh_file_write,
|
|
+ _fh_file_hook
|
|
+};
|
|
+
|
|
+/**************************************************************************/
|
|
+/**************************************************************************/
|
|
+/***** *****/
|
|
+/***** file-based descriptor handling *****/
|
|
+/***** *****/
|
|
+/**************************************************************************/
|
|
+/**************************************************************************/
|
|
+
|
|
+int adb_open(const char* path, int options)
|
|
+{
|
|
+ FH f;
|
|
+
|
|
+ DWORD desiredAccess = 0;
|
|
+ DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
|
|
+
|
|
+ switch (options) {
|
|
+ case O_RDONLY:
|
|
+ desiredAccess = GENERIC_READ;
|
|
+ break;
|
|
+ case O_WRONLY:
|
|
+ desiredAccess = GENERIC_WRITE;
|
|
+ break;
|
|
+ case O_RDWR:
|
|
+ desiredAccess = GENERIC_READ | GENERIC_WRITE;
|
|
+ break;
|
|
+ default:
|
|
+ D("adb_open: invalid options (0x%0x)\n", options);
|
|
+ errno = EINVAL;
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ f = _fh_alloc( &_fh_file_class );
|
|
+ if ( !f ) {
|
|
+ errno = ENOMEM;
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ f->fh_handle = CreateFile( path, desiredAccess, shareMode, NULL, OPEN_EXISTING,
|
|
+ 0, NULL );
|
|
+
|
|
+ if ( f->fh_handle == INVALID_HANDLE_VALUE ) {
|
|
+ _fh_close(f);
|
|
+ D( "adb_open: could not open '%s':", path );
|
|
+ switch (GetLastError()) {
|
|
+ case ERROR_FILE_NOT_FOUND:
|
|
+ D( "file not found\n" );
|
|
+ errno = ENOENT;
|
|
+ return -1;
|
|
+
|
|
+ case ERROR_PATH_NOT_FOUND:
|
|
+ D( "path not found\n" );
|
|
+ errno = ENOTDIR;
|
|
+ return -1;
|
|
+
|
|
+ default:
|
|
+ D( "unknown error\n" );
|
|
+ errno = ENOENT;
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ snprintf( f->name, sizeof(f->name), "%d(%s)", _fh_to_int(f), path );
|
|
+ D( "adb_open: '%s' => fd %d\n", path, _fh_to_int(f) );
|
|
+ return _fh_to_int(f);
|
|
+}
|
|
+
|
|
+/* ignore mode on Win32 */
|
|
+int adb_creat(const char* path, int mode)
|
|
+{
|
|
+ FH f;
|
|
+
|
|
+ f = _fh_alloc( &_fh_file_class );
|
|
+ if ( !f ) {
|
|
+ errno = ENOMEM;
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ f->fh_handle = CreateFile( path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
+ NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
|
|
+ NULL );
|
|
+
|
|
+ if ( f->fh_handle == INVALID_HANDLE_VALUE ) {
|
|
+ _fh_close(f);
|
|
+ D( "adb_creat: could not open '%s':", path );
|
|
+ switch (GetLastError()) {
|
|
+ case ERROR_FILE_NOT_FOUND:
|
|
+ D( "file not found\n" );
|
|
+ errno = ENOENT;
|
|
+ return -1;
|
|
+
|
|
+ case ERROR_PATH_NOT_FOUND:
|
|
+ D( "path not found\n" );
|
|
+ errno = ENOTDIR;
|
|
+ return -1;
|
|
+
|
|
+ default:
|
|
+ D( "unknown error\n" );
|
|
+ errno = ENOENT;
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+ snprintf( f->name, sizeof(f->name), "%d(%s)", _fh_to_int(f), path );
|
|
+ D( "adb_creat: '%s' => fd %d\n", path, _fh_to_int(f) );
|
|
+ return _fh_to_int(f);
|
|
+}
|
|
+
|
|
+
|
|
+int adb_read(int fd, void* buf, int len)
|
|
+{
|
|
+ FH f = _fh_from_int(fd);
|
|
+
|
|
+ if (f == NULL) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return f->clazz->_fh_read( f, buf, len );
|
|
+}
|
|
+
|
|
+
|
|
+int adb_write(int fd, const void* buf, int len)
|
|
+{
|
|
+ FH f = _fh_from_int(fd);
|
|
+
|
|
+ if (f == NULL) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return f->clazz->_fh_write(f, buf, len);
|
|
+}
|
|
+
|
|
+
|
|
+int adb_lseek(int fd, int pos, int where)
|
|
+{
|
|
+ FH f = _fh_from_int(fd);
|
|
+
|
|
+ if (!f) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return f->clazz->_fh_lseek(f, pos, where);
|
|
+}
|
|
+
|
|
+
|
|
+int adb_shutdown(int fd)
|
|
+{
|
|
+ FH f = _fh_from_int(fd);
|
|
+
|
|
+ if (!f) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ D( "adb_shutdown: %s\n", f->name);
|
|
+ shutdown( f->fh_socket, SD_BOTH );
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
+int adb_close(int fd)
|
|
+{
|
|
+ FH f = _fh_from_int(fd);
|
|
+
|
|
+ if (!f) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ D( "adb_close: %s\n", f->name);
|
|
+ _fh_close(f);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/**************************************************************************/
|
|
+/**************************************************************************/
|
|
+/***** *****/
|
|
+/***** socket-based file descriptors *****/
|
|
+/***** *****/
|
|
+/**************************************************************************/
|
|
+/**************************************************************************/
|
|
+
|
|
+static void
|
|
+_socket_set_errno( void )
|
|
+{
|
|
+ switch (WSAGetLastError()) {
|
|
+ case 0: errno = 0; break;
|
|
+ case WSAEWOULDBLOCK: errno = EAGAIN; break;
|
|
+ case WSAEINTR: errno = EINTR; break;
|
|
+ default:
|
|
+ D( "_socket_set_errno: unhandled value %d\n", WSAGetLastError() );
|
|
+ errno = EINVAL;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void
|
|
+_fh_socket_init( FH f )
|
|
+{
|
|
+ f->fh_socket = INVALID_SOCKET;
|
|
+ f->event = WSACreateEvent();
|
|
+ f->mask = 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+_fh_socket_close( FH f )
|
|
+{
|
|
+ /* gently tell any peer that we're closing the socket */
|
|
+ shutdown( f->fh_socket, SD_BOTH );
|
|
+ closesocket( f->fh_socket );
|
|
+ f->fh_socket = INVALID_SOCKET;
|
|
+ CloseHandle( f->event );
|
|
+ f->mask = 0;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+_fh_socket_lseek( FH f, int pos, int origin )
|
|
+{
|
|
+ errno = EPIPE;
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+static int
|
|
+_fh_socket_read( FH f, void* buf, int len )
|
|
+{
|
|
+ int result = recv( f->fh_socket, buf, len, 0 );
|
|
+ if (result == SOCKET_ERROR) {
|
|
+ _socket_set_errno();
|
|
+ result = -1;
|
|
+ }
|
|
+ return result;
|
|
+}
|
|
+
|
|
+static int
|
|
+_fh_socket_write( FH f, const void* buf, int len )
|
|
+{
|
|
+ int result = send( f->fh_socket, buf, len, 0 );
|
|
+ if (result == SOCKET_ERROR) {
|
|
+ _socket_set_errno();
|
|
+ result = -1;
|
|
+ }
|
|
+ return result;
|
|
+}
|
|
+
|
|
+static void _fh_socket_hook( FH f, int event, EventHook hook ); /* forward */
|
|
+
|
|
+static const FHClassRec _fh_socket_class =
|
|
+{
|
|
+ _fh_socket_init,
|
|
+ _fh_socket_close,
|
|
+ _fh_socket_lseek,
|
|
+ _fh_socket_read,
|
|
+ _fh_socket_write,
|
|
+ _fh_socket_hook
|
|
+};
|
|
+
|
|
+/**************************************************************************/
|
|
+/**************************************************************************/
|
|
+/***** *****/
|
|
+/***** replacement for libs/cutils/socket_xxxx.c *****/
|
|
+/***** *****/
|
|
+/**************************************************************************/
|
|
+/**************************************************************************/
|
|
+
|
|
+#include <winsock2.h>
|
|
+
|
|
+static int _winsock_init;
|
|
+
|
|
+static void
|
|
+_cleanup_winsock( void )
|
|
+{
|
|
+ WSACleanup();
|
|
+}
|
|
+
|
|
+static void
|
|
+_init_winsock( void )
|
|
+{
|
|
+ if (!_winsock_init) {
|
|
+ WSADATA wsaData;
|
|
+ int rc = WSAStartup( MAKEWORD(2,2), &wsaData);
|
|
+ if (rc != 0) {
|
|
+ fatal( "adb: could not initialize Winsock\n" );
|
|
+ }
|
|
+ atexit( _cleanup_winsock );
|
|
+ _winsock_init = 1;
|
|
+ }
|
|
+}
|
|
+
|
|
+int socket_loopback_client(int port, int type)
|
|
+{
|
|
+ FH f = _fh_alloc( &_fh_socket_class );
|
|
+ struct sockaddr_in addr;
|
|
+ SOCKET s;
|
|
+
|
|
+ if (!f)
|
|
+ return -1;
|
|
+
|
|
+ if (!_winsock_init)
|
|
+ _init_winsock();
|
|
+
|
|
+ memset(&addr, 0, sizeof(addr));
|
|
+ addr.sin_family = AF_INET;
|
|
+ addr.sin_port = htons(port);
|
|
+ addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
|
+
|
|
+ s = socket(AF_INET, type, 0);
|
|
+ if(s == INVALID_SOCKET) {
|
|
+ D("socket_loopback_client: could not create socket\n" );
|
|
+ _fh_close(f);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ f->fh_socket = s;
|
|
+ if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
|
|
+ D("socket_loopback_client: could not connect to %s:%d\n", type != SOCK_STREAM ? "udp" : "tcp", port );
|
|
+ _fh_close(f);
|
|
+ return -1;
|
|
+ }
|
|
+ snprintf( f->name, sizeof(f->name), "%d(lo-client:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port );
|
|
+ D( "socket_loopback_client: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) );
|
|
+ return _fh_to_int(f);
|
|
+}
|
|
+
|
|
+#define LISTEN_BACKLOG 4
|
|
+
|
|
+int socket_loopback_server(int port, int type)
|
|
+{
|
|
+ FH f = _fh_alloc( &_fh_socket_class );
|
|
+ struct sockaddr_in addr;
|
|
+ SOCKET s;
|
|
+ int n;
|
|
+
|
|
+ if (!f) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if (!_winsock_init)
|
|
+ _init_winsock();
|
|
+
|
|
+ memset(&addr, 0, sizeof(addr));
|
|
+ addr.sin_family = AF_INET;
|
|
+ addr.sin_port = htons(port);
|
|
+ addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
|
+
|
|
+ s = socket(AF_INET, type, 0);
|
|
+ if(s == INVALID_SOCKET) return -1;
|
|
+
|
|
+ f->fh_socket = s;
|
|
+
|
|
+ n = 1;
|
|
+ setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*)&n, sizeof(n));
|
|
+
|
|
+ if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
|
|
+ _fh_close(f);
|
|
+ return -1;
|
|
+ }
|
|
+ if (type == SOCK_STREAM) {
|
|
+ int ret;
|
|
+
|
|
+ ret = listen(s, LISTEN_BACKLOG);
|
|
+ if (ret < 0) {
|
|
+ _fh_close(f);
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+ snprintf( f->name, sizeof(f->name), "%d(lo-server:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port );
|
|
+ D( "socket_loopback_server: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) );
|
|
+ return _fh_to_int(f);
|
|
+}
|
|
+
|
|
+
|
|
+int socket_network_client(const char *host, int port, int type)
|
|
+{
|
|
+ FH f = _fh_alloc( &_fh_socket_class );
|
|
+ struct hostent *hp;
|
|
+ struct sockaddr_in addr;
|
|
+ SOCKET s;
|
|
+
|
|
+ if (!f)
|
|
+ return -1;
|
|
+
|
|
+ if (!_winsock_init)
|
|
+ _init_winsock();
|
|
+
|
|
+ hp = gethostbyname(host);
|
|
+ if(hp == 0) {
|
|
+ _fh_close(f);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ memset(&addr, 0, sizeof(addr));
|
|
+ addr.sin_family = hp->h_addrtype;
|
|
+ addr.sin_port = htons(port);
|
|
+ memcpy(&addr.sin_addr, hp->h_addr, hp->h_length);
|
|
+
|
|
+ s = socket(hp->h_addrtype, type, 0);
|
|
+ if(s == INVALID_SOCKET) {
|
|
+ _fh_close(f);
|
|
+ return -1;
|
|
+ }
|
|
+ f->fh_socket = s;
|
|
+
|
|
+ if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
|
|
+ _fh_close(f);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ snprintf( f->name, sizeof(f->name), "%d(net-client:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port );
|
|
+ D( "socket_network_client: host '%s' port %d type %s => fd %d\n", host, port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) );
|
|
+ return _fh_to_int(f);
|
|
+}
|
|
+
|
|
+
|
|
+int socket_inaddr_any_server(int port, int type)
|
|
+{
|
|
+ FH f = _fh_alloc( &_fh_socket_class );
|
|
+ struct sockaddr_in addr;
|
|
+ SOCKET s;
|
|
+ int n;
|
|
+
|
|
+ if (!f)
|
|
+ return -1;
|
|
+
|
|
+ if (!_winsock_init)
|
|
+ _init_winsock();
|
|
+
|
|
+ memset(&addr, 0, sizeof(addr));
|
|
+ addr.sin_family = AF_INET;
|
|
+ addr.sin_port = htons(port);
|
|
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
+
|
|
+ s = socket(AF_INET, type, 0);
|
|
+ if(s == INVALID_SOCKET) {
|
|
+ _fh_close(f);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ f->fh_socket = s;
|
|
+ n = 1;
|
|
+ setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*)&n, sizeof(n));
|
|
+
|
|
+ if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
|
|
+ _fh_close(f);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if (type == SOCK_STREAM) {
|
|
+ int ret;
|
|
+
|
|
+ ret = listen(s, LISTEN_BACKLOG);
|
|
+ if (ret < 0) {
|
|
+ _fh_close(f);
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+ snprintf( f->name, sizeof(f->name), "%d(any-server:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port );
|
|
+ D( "socket_inaddr_server: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) );
|
|
+ return _fh_to_int(f);
|
|
+}
|
|
+
|
|
+#undef accept
|
|
+int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen)
|
|
+{
|
|
+ FH serverfh = _fh_from_int(serverfd);
|
|
+ FH fh;
|
|
+
|
|
+ if ( !serverfh || serverfh->clazz != &_fh_socket_class ) {
|
|
+ D( "adb_socket_accept: invalid fd %d\n", serverfd );
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ fh = _fh_alloc( &_fh_socket_class );
|
|
+ if (!fh) {
|
|
+ D( "adb_socket_accept: not enough memory to allocate accepted socket descriptor\n" );
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ fh->fh_socket = accept( serverfh->fh_socket, addr, addrlen );
|
|
+ if (fh->fh_socket == INVALID_SOCKET) {
|
|
+ _fh_close( fh );
|
|
+ D( "adb_socket_accept: accept on fd %d return error %ld\n", serverfd, GetLastError() );
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ snprintf( fh->name, sizeof(fh->name), "%d(accept:%s)", _fh_to_int(fh), serverfh->name );
|
|
+ D( "adb_socket_accept on fd %d returns fd %d\n", serverfd, _fh_to_int(fh) );
|
|
+ return _fh_to_int(fh);
|
|
+}
|
|
+
|
|
+
|
|
+void disable_tcp_nagle(int fd)
|
|
+{
|
|
+ FH fh = _fh_from_int(fd);
|
|
+ int on = 1;
|
|
+
|
|
+ if ( !fh || fh->clazz != &_fh_socket_class )
|
|
+ return;
|
|
+
|
|
+ setsockopt( fh->fh_socket, IPPROTO_TCP, TCP_NODELAY, (const char*)&on, sizeof(on) );
|
|
+}
|
|
+
|
|
+/**************************************************************************/
|
|
+/**************************************************************************/
|
|
+/***** *****/
|
|
+/***** emulated socketpairs *****/
|
|
+/***** *****/
|
|
+/**************************************************************************/
|
|
+/**************************************************************************/
|
|
+
|
|
+/* we implement socketpairs directly in use space for the following reasons:
|
|
+ * - it avoids copying data from/to the Nt kernel
|
|
+ * - it allows us to implement fdevent hooks easily and cheaply, something
|
|
+ * that is not possible with standard Win32 pipes !!
|
|
+ *
|
|
+ * basically, we use two circular buffers, each one corresponding to a given
|
|
+ * direction.
|
|
+ *
|
|
+ * each buffer is implemented as two regions:
|
|
+ *
|
|
+ * region A which is (a_start,a_end)
|
|
+ * region B which is (0, b_end) with b_end <= a_start
|
|
+ *
|
|
+ * an empty buffer has: a_start = a_end = b_end = 0
|
|
+ *
|
|
+ * a_start is the pointer where we start reading data
|
|
+ * a_end is the pointer where we start writing data, unless it is BUFFER_SIZE,
|
|
+ * then you start writing at b_end
|
|
+ *
|
|
+ * the buffer is full when b_end == a_start && a_end == BUFFER_SIZE
|
|
+ *
|
|
+ * there is room when b_end < a_start || a_end < BUFER_SIZE
|
|
+ *
|
|
+ * when reading, a_start is incremented, it a_start meets a_end, then
|
|
+ * we do: a_start = 0, a_end = b_end, b_end = 0, and keep going on..
|
|
+ */
|
|
+
|
|
+#define BIP_BUFFER_SIZE 4096
|
|
+
|
|
+#if 0
|
|
+#include <stdio.h>
|
|
+# define BIPD(x) D x
|
|
+# define BIPDUMP bip_dump_hex
|
|
+
|
|
+static void bip_dump_hex( const unsigned char* ptr, size_t len )
|
|
+{
|
|
+ int nn, len2 = len;
|
|
+
|
|
+ if (len2 > 8) len2 = 8;
|
|
+
|
|
+ for (nn = 0; nn < len2; nn++)
|
|
+ printf("%02x", ptr[nn]);
|
|
+ printf(" ");
|
|
+
|
|
+ for (nn = 0; nn < len2; nn++) {
|
|
+ int c = ptr[nn];
|
|
+ if (c < 32 || c > 127)
|
|
+ c = '.';
|
|
+ printf("%c", c);
|
|
+ }
|
|
+ printf("\n");
|
|
+ fflush(stdout);
|
|
+}
|
|
+
|
|
+#else
|
|
+# define BIPD(x) do {} while (0)
|
|
+# define BIPDUMP(p,l) BIPD(p)
|
|
+#endif
|
|
+
|
|
+typedef struct BipBufferRec_
|
|
+{
|
|
+ int a_start;
|
|
+ int a_end;
|
|
+ int b_end;
|
|
+ int fdin;
|
|
+ int fdout;
|
|
+ int closed;
|
|
+ int can_write; /* boolean */
|
|
+ HANDLE evt_write; /* event signaled when one can write to a buffer */
|
|
+ int can_read; /* boolean */
|
|
+ HANDLE evt_read; /* event signaled when one can read from a buffer */
|
|
+ CRITICAL_SECTION lock;
|
|
+ unsigned char buff[ BIP_BUFFER_SIZE ];
|
|
+
|
|
+} BipBufferRec, *BipBuffer;
|
|
+
|
|
+static void
|
|
+bip_buffer_init( BipBuffer buffer )
|
|
+{
|
|
+ D( "bit_buffer_init %p\n", buffer );
|
|
+ buffer->a_start = 0;
|
|
+ buffer->a_end = 0;
|
|
+ buffer->b_end = 0;
|
|
+ buffer->can_write = 1;
|
|
+ buffer->can_read = 0;
|
|
+ buffer->fdin = 0;
|
|
+ buffer->fdout = 0;
|
|
+ buffer->closed = 0;
|
|
+ buffer->evt_write = CreateEvent( NULL, TRUE, TRUE, NULL );
|
|
+ buffer->evt_read = CreateEvent( NULL, TRUE, FALSE, NULL );
|
|
+ InitializeCriticalSection( &buffer->lock );
|
|
+}
|
|
+
|
|
+static void
|
|
+bip_buffer_close( BipBuffer bip )
|
|
+{
|
|
+ bip->closed = 1;
|
|
+
|
|
+ if (!bip->can_read) {
|
|
+ SetEvent( bip->evt_read );
|
|
+ }
|
|
+ if (!bip->can_write) {
|
|
+ SetEvent( bip->evt_write );
|
|
+ }
|
|
+}
|
|
+
|
|
+static void
|
|
+bip_buffer_done( BipBuffer bip )
|
|
+{
|
|
+ BIPD(( "bip_buffer_done: %d->%d\n", bip->fdin, bip->fdout ));
|
|
+ CloseHandle( bip->evt_read );
|
|
+ CloseHandle( bip->evt_write );
|
|
+ DeleteCriticalSection( &bip->lock );
|
|
+}
|
|
+
|
|
+static int
|
|
+bip_buffer_write( BipBuffer bip, const void* src, int len )
|
|
+{
|
|
+ int avail, count = 0;
|
|
+
|
|
+ if (len <= 0)
|
|
+ return 0;
|
|
+
|
|
+ BIPD(( "bip_buffer_write: enter %d->%d len %d\n", bip->fdin, bip->fdout, len ));
|
|
+ BIPDUMP( src, len );
|
|
+
|
|
+ EnterCriticalSection( &bip->lock );
|
|
+
|
|
+ while (!bip->can_write) {
|
|
+ int ret;
|
|
+ LeaveCriticalSection( &bip->lock );
|
|
+
|
|
+ if (bip->closed) {
|
|
+ errno = EPIPE;
|
|
+ return -1;
|
|
+ }
|
|
+ /* spinlocking here is probably unfair, but let's live with it */
|
|
+ ret = WaitForSingleObject( bip->evt_write, INFINITE );
|
|
+ if (ret != WAIT_OBJECT_0) { /* buffer probably closed */
|
|
+ D( "bip_buffer_write: error %d->%d WaitForSingleObject returned %d, error %ld\n", bip->fdin, bip->fdout, ret, GetLastError() );
|
|
+ return 0;
|
|
+ }
|
|
+ if (bip->closed) {
|
|
+ errno = EPIPE;
|
|
+ return -1;
|
|
+ }
|
|
+ EnterCriticalSection( &bip->lock );
|
|
+ }
|
|
+
|
|
+ BIPD(( "bip_buffer_write: exec %d->%d len %d\n", bip->fdin, bip->fdout, len ));
|
|
+
|
|
+ avail = BIP_BUFFER_SIZE - bip->a_end;
|
|
+ if (avail > 0)
|
|
+ {
|
|
+ /* we can append to region A */
|
|
+ if (avail > len)
|
|
+ avail = len;
|
|
+
|
|
+ memcpy( bip->buff + bip->a_end, src, avail );
|
|
+ src += avail;
|
|
+ count += avail;
|
|
+ len -= avail;
|
|
+
|
|
+ bip->a_end += avail;
|
|
+ if (bip->a_end == BIP_BUFFER_SIZE && bip->a_start == 0) {
|
|
+ bip->can_write = 0;
|
|
+ ResetEvent( bip->evt_write );
|
|
+ goto Exit;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (len == 0)
|
|
+ goto Exit;
|
|
+
|
|
+ avail = bip->a_start - bip->b_end;
|
|
+ assert( avail > 0 ); /* since can_write is TRUE */
|
|
+
|
|
+ if (avail > len)
|
|
+ avail = len;
|
|
+
|
|
+ memcpy( bip->buff + bip->b_end, src, avail );
|
|
+ count += avail;
|
|
+ bip->b_end += avail;
|
|
+
|
|
+ if (bip->b_end == bip->a_start) {
|
|
+ bip->can_write = 0;
|
|
+ ResetEvent( bip->evt_write );
|
|
+ }
|
|
+
|
|
+Exit:
|
|
+ assert( count > 0 );
|
|
+
|
|
+ if ( !bip->can_read ) {
|
|
+ bip->can_read = 1;
|
|
+ SetEvent( bip->evt_read );
|
|
+ }
|
|
+
|
|
+ BIPD(( "bip_buffer_write: exit %d->%d count %d (as=%d ae=%d be=%d cw=%d cr=%d\n",
|
|
+ bip->fdin, bip->fdout, count, bip->a_start, bip->a_end, bip->b_end, bip->can_write, bip->can_read ));
|
|
+ LeaveCriticalSection( &bip->lock );
|
|
+
|
|
+ return count;
|
|
+ }
|
|
+
|
|
+static int
|
|
+bip_buffer_read( BipBuffer bip, void* dst, int len )
|
|
+{
|
|
+ int avail, count = 0;
|
|
+
|
|
+ if (len <= 0)
|
|
+ return 0;
|
|
+
|
|
+ BIPD(( "bip_buffer_read: enter %d->%d len %d\n", bip->fdin, bip->fdout, len ));
|
|
+
|
|
+ EnterCriticalSection( &bip->lock );
|
|
+ while ( !bip->can_read )
|
|
+ {
|
|
+#if 0
|
|
+ LeaveCriticalSection( &bip->lock );
|
|
+ errno = EAGAIN;
|
|
+ return -1;
|
|
+#else
|
|
+ int ret;
|
|
+ LeaveCriticalSection( &bip->lock );
|
|
+
|
|
+ if (bip->closed) {
|
|
+ errno = EPIPE;
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ ret = WaitForSingleObject( bip->evt_read, INFINITE );
|
|
+ if (ret != WAIT_OBJECT_0) { /* probably closed buffer */
|
|
+ D( "bip_buffer_read: error %d->%d WaitForSingleObject returned %d, error %ld\n", bip->fdin, bip->fdout, ret, GetLastError());
|
|
+ return 0;
|
|
+ }
|
|
+ if (bip->closed) {
|
|
+ errno = EPIPE;
|
|
+ return -1;
|
|
+ }
|
|
+ EnterCriticalSection( &bip->lock );
|
|
+#endif
|
|
+ }
|
|
+
|
|
+ BIPD(( "bip_buffer_read: exec %d->%d len %d\n", bip->fdin, bip->fdout, len ));
|
|
+
|
|
+ avail = bip->a_end - bip->a_start;
|
|
+ assert( avail > 0 ); /* since can_read is TRUE */
|
|
+
|
|
+ if (avail > len)
|
|
+ avail = len;
|
|
+
|
|
+ memcpy( dst, bip->buff + bip->a_start, avail );
|
|
+ dst += avail;
|
|
+ count += avail;
|
|
+ len -= avail;
|
|
+
|
|
+ bip->a_start += avail;
|
|
+ if (bip->a_start < bip->a_end)
|
|
+ goto Exit;
|
|
+
|
|
+ bip->a_start = 0;
|
|
+ bip->a_end = bip->b_end;
|
|
+ bip->b_end = 0;
|
|
+
|
|
+ avail = bip->a_end;
|
|
+ if (avail > 0) {
|
|
+ if (avail > len)
|
|
+ avail = len;
|
|
+ memcpy( dst, bip->buff, avail );
|
|
+ count += avail;
|
|
+ bip->a_start += avail;
|
|
+
|
|
+ if ( bip->a_start < bip->a_end )
|
|
+ goto Exit;
|
|
+
|
|
+ bip->a_start = bip->a_end = 0;
|
|
+ }
|
|
+
|
|
+ bip->can_read = 0;
|
|
+ ResetEvent( bip->evt_read );
|
|
+
|
|
+Exit:
|
|
+ assert( count > 0 );
|
|
+
|
|
+ if (!bip->can_write ) {
|
|
+ bip->can_write = 1;
|
|
+ SetEvent( bip->evt_write );
|
|
+ }
|
|
+
|
|
+ BIPDUMP( (const unsigned char*)dst - count, count );
|
|
+ BIPD(( "bip_buffer_read: exit %d->%d count %d (as=%d ae=%d be=%d cw=%d cr=%d\n",
|
|
+ bip->fdin, bip->fdout, count, bip->a_start, bip->a_end, bip->b_end, bip->can_write, bip->can_read ));
|
|
+ LeaveCriticalSection( &bip->lock );
|
|
+
|
|
+ return count;
|
|
+}
|
|
+
|
|
+typedef struct SocketPairRec_
|
|
+{
|
|
+ BipBufferRec a2b_bip;
|
|
+ BipBufferRec b2a_bip;
|
|
+ FH a_fd;
|
|
+ int used;
|
|
+
|
|
+} SocketPairRec;
|
|
+
|
|
+void _fh_socketpair_init( FH f )
|
|
+{
|
|
+ f->fh_pair = NULL;
|
|
+}
|
|
+
|
|
+static int
|
|
+_fh_socketpair_close( FH f )
|
|
+{
|
|
+ if ( f->fh_pair ) {
|
|
+ SocketPair pair = f->fh_pair;
|
|
+
|
|
+ if ( f == pair->a_fd ) {
|
|
+ pair->a_fd = NULL;
|
|
+ }
|
|
+
|
|
+ bip_buffer_close( &pair->b2a_bip );
|
|
+ bip_buffer_close( &pair->a2b_bip );
|
|
+
|
|
+ if ( --pair->used == 0 ) {
|
|
+ bip_buffer_done( &pair->b2a_bip );
|
|
+ bip_buffer_done( &pair->a2b_bip );
|
|
+ free( pair );
|
|
+ }
|
|
+ f->fh_pair = NULL;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+_fh_socketpair_lseek( FH f, int pos, int origin )
|
|
+{
|
|
+ errno = ESPIPE;
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+static int
|
|
+_fh_socketpair_read( FH f, void* buf, int len )
|
|
+{
|
|
+ SocketPair pair = f->fh_pair;
|
|
+ BipBuffer bip;
|
|
+
|
|
+ if (!pair)
|
|
+ return -1;
|
|
+
|
|
+ if ( f == pair->a_fd )
|
|
+ bip = &pair->b2a_bip;
|
|
+ else
|
|
+ bip = &pair->a2b_bip;
|
|
+
|
|
+ return bip_buffer_read( bip, buf, len );
|
|
+}
|
|
+
|
|
+static int
|
|
+_fh_socketpair_write( FH f, const void* buf, int len )
|
|
+{
|
|
+ SocketPair pair = f->fh_pair;
|
|
+ BipBuffer bip;
|
|
+
|
|
+ if (!pair)
|
|
+ return -1;
|
|
+
|
|
+ if ( f == pair->a_fd )
|
|
+ bip = &pair->a2b_bip;
|
|
+ else
|
|
+ bip = &pair->b2a_bip;
|
|
+
|
|
+ return bip_buffer_write( bip, buf, len );
|
|
+}
|
|
+
|
|
+
|
|
+static void _fh_socketpair_hook( FH f, int event, EventHook hook ); /* forward */
|
|
+
|
|
+static const FHClassRec _fh_socketpair_class =
|
|
+{
|
|
+ _fh_socketpair_init,
|
|
+ _fh_socketpair_close,
|
|
+ _fh_socketpair_lseek,
|
|
+ _fh_socketpair_read,
|
|
+ _fh_socketpair_write,
|
|
+ _fh_socketpair_hook
|
|
+};
|
|
+
|
|
+
|
|
+int adb_socketpair( int sv[2] )
|
|
+{
|
|
+ FH fa, fb;
|
|
+ SocketPair pair;
|
|
+
|
|
+ fa = _fh_alloc( &_fh_socketpair_class );
|
|
+ fb = _fh_alloc( &_fh_socketpair_class );
|
|
+
|
|
+ if (!fa || !fb)
|
|
+ goto Fail;
|
|
+
|
|
+ pair = malloc( sizeof(*pair) );
|
|
+ if (pair == NULL) {
|
|
+ D("adb_socketpair: not enough memory to allocate pipes\n" );
|
|
+ goto Fail;
|
|
+ }
|
|
+
|
|
+ bip_buffer_init( &pair->a2b_bip );
|
|
+ bip_buffer_init( &pair->b2a_bip );
|
|
+
|
|
+ fa->fh_pair = pair;
|
|
+ fb->fh_pair = pair;
|
|
+ pair->used = 2;
|
|
+ pair->a_fd = fa;
|
|
+
|
|
+ sv[0] = _fh_to_int(fa);
|
|
+ sv[1] = _fh_to_int(fb);
|
|
+
|
|
+ pair->a2b_bip.fdin = sv[0];
|
|
+ pair->a2b_bip.fdout = sv[1];
|
|
+ pair->b2a_bip.fdin = sv[1];
|
|
+ pair->b2a_bip.fdout = sv[0];
|
|
+
|
|
+ snprintf( fa->name, sizeof(fa->name), "%d(pair:%d)", sv[0], sv[1] );
|
|
+ snprintf( fb->name, sizeof(fb->name), "%d(pair:%d)", sv[1], sv[0] );
|
|
+ D( "adb_socketpair: returns (%d, %d)\n", sv[0], sv[1] );
|
|
+ return 0;
|
|
+
|
|
+Fail:
|
|
+ _fh_close(fb);
|
|
+ _fh_close(fa);
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+/**************************************************************************/
|
|
+/**************************************************************************/
|
|
+/***** *****/
|
|
+/***** fdevents emulation *****/
|
|
+/***** *****/
|
|
+/***** this is a very simple implementation, we rely on the fact *****/
|
|
+/***** that ADB doesn't use FDE_ERROR. *****/
|
|
+/***** *****/
|
|
+/**************************************************************************/
|
|
+/**************************************************************************/
|
|
+
|
|
+#define FATAL(x...) fatal(__FUNCTION__, x)
|
|
+
|
|
+#if DEBUG
|
|
+static void dump_fde(fdevent *fde, const char *info)
|
|
+{
|
|
+ fprintf(stderr,"FDE #%03d %c%c%c %s\n", fde->fd,
|
|
+ fde->state & FDE_READ ? 'R' : ' ',
|
|
+ fde->state & FDE_WRITE ? 'W' : ' ',
|
|
+ fde->state & FDE_ERROR ? 'E' : ' ',
|
|
+ info);
|
|
+}
|
|
+#else
|
|
+#define dump_fde(fde, info) do { } while(0)
|
|
+#endif
|
|
+
|
|
+#define FDE_EVENTMASK 0x00ff
|
|
+#define FDE_STATEMASK 0xff00
|
|
+
|
|
+#define FDE_ACTIVE 0x0100
|
|
+#define FDE_PENDING 0x0200
|
|
+#define FDE_CREATED 0x0400
|
|
+
|
|
+static void fdevent_plist_enqueue(fdevent *node);
|
|
+static void fdevent_plist_remove(fdevent *node);
|
|
+static fdevent *fdevent_plist_dequeue(void);
|
|
+
|
|
+static fdevent list_pending = {
|
|
+ .next = &list_pending,
|
|
+ .prev = &list_pending,
|
|
+};
|
|
+
|
|
+static fdevent **fd_table = 0;
|
|
+static int fd_table_max = 0;
|
|
+
|
|
+typedef struct EventLooperRec_* EventLooper;
|
|
+
|
|
+typedef struct EventHookRec_
|
|
+{
|
|
+ EventHook next;
|
|
+ FH fh;
|
|
+ HANDLE h;
|
|
+ int wanted; /* wanted event flags */
|
|
+ int ready; /* ready event flags */
|
|
+ void* aux;
|
|
+ void (*prepare)( EventHook hook );
|
|
+ int (*start) ( EventHook hook );
|
|
+ void (*stop) ( EventHook hook );
|
|
+ int (*check) ( EventHook hook );
|
|
+ int (*peek) ( EventHook hook );
|
|
+} EventHookRec;
|
|
+
|
|
+static EventHook _free_hooks;
|
|
+
|
|
+static EventHook
|
|
+event_hook_alloc( FH fh )
|
|
+{
|
|
+ EventHook hook = _free_hooks;
|
|
+ if (hook != NULL)
|
|
+ _free_hooks = hook->next;
|
|
+ else {
|
|
+ hook = malloc( sizeof(*hook) );
|
|
+ if (hook == NULL)
|
|
+ fatal( "could not allocate event hook\n" );
|
|
+ }
|
|
+ hook->next = NULL;
|
|
+ hook->fh = fh;
|
|
+ hook->wanted = 0;
|
|
+ hook->ready = 0;
|
|
+ hook->h = INVALID_HANDLE_VALUE;
|
|
+ hook->aux = NULL;
|
|
+
|
|
+ hook->prepare = NULL;
|
|
+ hook->start = NULL;
|
|
+ hook->stop = NULL;
|
|
+ hook->check = NULL;
|
|
+ hook->peek = NULL;
|
|
+
|
|
+ return hook;
|
|
+}
|
|
+
|
|
+static void
|
|
+event_hook_free( EventHook hook )
|
|
+{
|
|
+ hook->fh = NULL;
|
|
+ hook->wanted = 0;
|
|
+ hook->ready = 0;
|
|
+ hook->next = _free_hooks;
|
|
+ _free_hooks = hook;
|
|
+}
|
|
+
|
|
+
|
|
+static void
|
|
+event_hook_signal( EventHook hook )
|
|
+{
|
|
+ FH f = hook->fh;
|
|
+ int fd = _fh_to_int(f);
|
|
+ fdevent* fde = fd_table[ fd - WIN32_FH_BASE ];
|
|
+
|
|
+ if (fde != NULL && fde->fd == fd) {
|
|
+ if ((fde->state & FDE_PENDING) == 0) {
|
|
+ fde->state |= FDE_PENDING;
|
|
+ fdevent_plist_enqueue( fde );
|
|
+ }
|
|
+ fde->events |= hook->wanted;
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+#define MAX_LOOPER_HANDLES WIN32_MAX_FHS
|
|
+
|
|
+typedef struct EventLooperRec_
|
|
+{
|
|
+ EventHook hooks;
|
|
+ HANDLE htab[ MAX_LOOPER_HANDLES ];
|
|
+ int htab_count;
|
|
+
|
|
+} EventLooperRec;
|
|
+
|
|
+static EventHook*
|
|
+event_looper_find_p( EventLooper looper, FH fh )
|
|
+{
|
|
+ EventHook *pnode = &looper->hooks;
|
|
+ EventHook node = *pnode;
|
|
+ for (;;) {
|
|
+ if ( node == NULL || node->fh == fh )
|
|
+ break;
|
|
+ pnode = &node->next;
|
|
+ node = *pnode;
|
|
+ }
|
|
+ return pnode;
|
|
+}
|
|
+
|
|
+static void
|
|
+event_looper_hook( EventLooper looper, int fd, int events )
|
|
+{
|
|
+ FH f = _fh_from_int(fd);
|
|
+ EventHook *pnode;
|
|
+ EventHook node;
|
|
+
|
|
+ if (f == NULL) /* invalid arg */ {
|
|
+ D("event_looper_hook: invalid fd=%d\n", fd);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ pnode = event_looper_find_p( looper, f );
|
|
+ node = *pnode;
|
|
+ if ( node == NULL ) {
|
|
+ node = event_hook_alloc( f );
|
|
+ node->next = *pnode;
|
|
+ *pnode = node;
|
|
+ }
|
|
+
|
|
+ if ( (node->wanted & events) != events ) {
|
|
+ /* this should update start/stop/check/peek */
|
|
+ D("event_looper_hook: call hook for %d (new=%x, old=%x)\n",
|
|
+ fd, node->wanted, events);
|
|
+ f->clazz->_fh_hook( f, events & ~node->wanted, node );
|
|
+ node->wanted |= events;
|
|
+ } else {
|
|
+ D("event_looper_hook: ignoring events %x for %d wanted=%x)\n",
|
|
+ events, fd, node->wanted);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void
|
|
+event_looper_unhook( EventLooper looper, int fd, int events )
|
|
+{
|
|
+ FH fh = _fh_from_int(fd);
|
|
+ EventHook *pnode = event_looper_find_p( looper, fh );
|
|
+ EventHook node = *pnode;
|
|
+
|
|
+ if (node != NULL) {
|
|
+ int events2 = events & node->wanted;
|
|
+ if ( events2 == 0 ) {
|
|
+ D( "event_looper_unhook: events %x not registered for fd %d\n", events, fd );
|
|
+ return;
|
|
+ }
|
|
+ node->wanted &= ~events2;
|
|
+ if (!node->wanted) {
|
|
+ *pnode = node->next;
|
|
+ event_hook_free( node );
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * A fixer for WaitForMultipleObjects on condition that there are more than 64
|
|
+ * handles to wait on.
|
|
+ *
|
|
+ * In cetain cases DDMS may establish more than 64 connections with ADB. For
|
|
+ * instance, this may happen if there are more than 64 processes running on a
|
|
+ * device, or there are multiple devices connected (including the emulator) with
|
|
+ * the combined number of running processes greater than 64. In this case using
|
|
+ * WaitForMultipleObjects to wait on connection events simply wouldn't cut,
|
|
+ * because of the API limitations (64 handles max). So, we need to provide a way
|
|
+ * to scale WaitForMultipleObjects to accept an arbitrary number of handles. The
|
|
+ * easiest (and "Microsoft recommended") way to do that would be dividing the
|
|
+ * handle array into chunks with the chunk size less than 64, and fire up as many
|
|
+ * waiting threads as there are chunks. Then each thread would wait on a chunk of
|
|
+ * handles, and will report back to the caller which handle has been set.
|
|
+ * Here is the implementation of that algorithm.
|
|
+ */
|
|
+
|
|
+/* Number of handles to wait on in each wating thread. */
|
|
+#define WAIT_ALL_CHUNK_SIZE 63
|
|
+
|
|
+/* Descriptor for a wating thread */
|
|
+typedef struct WaitForAllParam {
|
|
+ /* A handle to an event to signal when waiting is over. This handle is shared
|
|
+ * accross all the waiting threads, so each waiting thread knows when any
|
|
+ * other thread has exited, so it can exit too. */
|
|
+ HANDLE main_event;
|
|
+ /* Upon exit from a waiting thread contains the index of the handle that has
|
|
+ * been signaled. The index is an absolute index of the signaled handle in
|
|
+ * the original array. This pointer is shared accross all the waiting threads
|
|
+ * and it's not guaranteed (due to a race condition) that when all the
|
|
+ * waiting threads exit, the value contained here would indicate the first
|
|
+ * handle that was signaled. This is fine, because the caller cares only
|
|
+ * about any handle being signaled. It doesn't care about the order, nor
|
|
+ * about the whole list of handles that were signaled. */
|
|
+ LONG volatile *signaled_index;
|
|
+ /* Array of handles to wait on in a waiting thread. */
|
|
+ HANDLE* handles;
|
|
+ /* Number of handles in 'handles' array to wait on. */
|
|
+ int handles_count;
|
|
+ /* Index inside the main array of the first handle in the 'handles' array. */
|
|
+ int first_handle_index;
|
|
+ /* Waiting thread handle. */
|
|
+ HANDLE thread;
|
|
+} WaitForAllParam;
|
|
+
|
|
+/* Waiting thread routine. */
|
|
+static unsigned __stdcall
|
|
+_in_waiter_thread(void* arg)
|
|
+{
|
|
+ HANDLE wait_on[WAIT_ALL_CHUNK_SIZE + 1];
|
|
+ int res;
|
|
+ WaitForAllParam* const param = (WaitForAllParam*)arg;
|
|
+
|
|
+ /* We have to wait on the main_event in order to be notified when any of the
|
|
+ * sibling threads is exiting. */
|
|
+ wait_on[0] = param->main_event;
|
|
+ /* The rest of the handles go behind the main event handle. */
|
|
+ memcpy(wait_on + 1, param->handles, param->handles_count * sizeof(HANDLE));
|
|
+
|
|
+ res = WaitForMultipleObjects(param->handles_count + 1, wait_on, FALSE, INFINITE);
|
|
+ if (res > 0 && res < (param->handles_count + 1)) {
|
|
+ /* One of the original handles got signaled. Save its absolute index into
|
|
+ * the output variable. */
|
|
+ InterlockedCompareExchange(param->signaled_index,
|
|
+ res - 1L + param->first_handle_index, -1L);
|
|
+ }
|
|
+
|
|
+ /* Notify the caller (and the siblings) that the wait is over. */
|
|
+ SetEvent(param->main_event);
|
|
+
|
|
+ _endthreadex(0);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* WaitForMultipeObjects fixer routine.
|
|
+ * Param:
|
|
+ * handles Array of handles to wait on.
|
|
+ * handles_count Number of handles in the array.
|
|
+ * Return:
|
|
+ * (>= 0 && < handles_count) - Index of the signaled handle in the array, or
|
|
+ * WAIT_FAILED on an error.
|
|
+ */
|
|
+static int
|
|
+_wait_for_all(HANDLE* handles, int handles_count)
|
|
+{
|
|
+ WaitForAllParam* threads;
|
|
+ HANDLE main_event;
|
|
+ int chunks, chunk, remains;
|
|
+
|
|
+ /* This variable is going to be accessed by several threads at the same time,
|
|
+ * this is bound to fail randomly when the core is run on multi-core machines.
|
|
+ * To solve this, we need to do the following (1 _and_ 2):
|
|
+ * 1. Use the "volatile" qualifier to ensure the compiler doesn't optimize
|
|
+ * out the reads/writes in this function unexpectedly.
|
|
+ * 2. Ensure correct memory ordering. The "simple" way to do that is to wrap
|
|
+ * all accesses inside a critical section. But we can also use
|
|
+ * InterlockedCompareExchange() which always provide a full memory barrier
|
|
+ * on Win32.
|
|
+ */
|
|
+ volatile LONG sig_index = -1;
|
|
+
|
|
+ /* Calculate number of chunks, and allocate thread param array. */
|
|
+ chunks = handles_count / WAIT_ALL_CHUNK_SIZE;
|
|
+ remains = handles_count % WAIT_ALL_CHUNK_SIZE;
|
|
+ threads = (WaitForAllParam*)malloc((chunks + (remains ? 1 : 0)) *
|
|
+ sizeof(WaitForAllParam));
|
|
+ if (threads == NULL) {
|
|
+ D("Unable to allocate thread array for %d handles.", handles_count);
|
|
+ return (int)WAIT_FAILED;
|
|
+ }
|
|
+
|
|
+ /* Create main event to wait on for all waiting threads. This is a "manualy
|
|
+ * reset" event that will remain set once it was set. */
|
|
+ main_event = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
+ if (main_event == NULL) {
|
|
+ D("Unable to create main event. Error: %d", GetLastError());
|
|
+ free(threads);
|
|
+ return (int)WAIT_FAILED;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Initialize waiting thread parameters.
|
|
+ */
|
|
+
|
|
+ for (chunk = 0; chunk < chunks; chunk++) {
|
|
+ threads[chunk].main_event = main_event;
|
|
+ threads[chunk].signaled_index = &sig_index;
|
|
+ threads[chunk].first_handle_index = WAIT_ALL_CHUNK_SIZE * chunk;
|
|
+ threads[chunk].handles = handles + threads[chunk].first_handle_index;
|
|
+ threads[chunk].handles_count = WAIT_ALL_CHUNK_SIZE;
|
|
+ }
|
|
+ if (remains) {
|
|
+ threads[chunk].main_event = main_event;
|
|
+ threads[chunk].signaled_index = &sig_index;
|
|
+ threads[chunk].first_handle_index = WAIT_ALL_CHUNK_SIZE * chunk;
|
|
+ threads[chunk].handles = handles + threads[chunk].first_handle_index;
|
|
+ threads[chunk].handles_count = remains;
|
|
+ chunks++;
|
|
+ }
|
|
+
|
|
+ /* Start the waiting threads. */
|
|
+ for (chunk = 0; chunk < chunks; chunk++) {
|
|
+ /* Note that using adb_thread_create is not appropriate here, since we
|
|
+ * need a handle to wait on for thread termination. */
|
|
+ threads[chunk].thread = (HANDLE)_beginthreadex(NULL, 0, _in_waiter_thread,
|
|
+ &threads[chunk], 0, NULL);
|
|
+ if (threads[chunk].thread == NULL) {
|
|
+ /* Unable to create a waiter thread. Collapse. */
|
|
+ D("Unable to create a waiting thread %d of %d. errno=%d",
|
|
+ chunk, chunks, errno);
|
|
+ chunks = chunk;
|
|
+ SetEvent(main_event);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Wait on any of the threads to get signaled. */
|
|
+ WaitForSingleObject(main_event, INFINITE);
|
|
+
|
|
+ /* Wait on all the waiting threads to exit. */
|
|
+ for (chunk = 0; chunk < chunks; chunk++) {
|
|
+ WaitForSingleObject(threads[chunk].thread, INFINITE);
|
|
+ CloseHandle(threads[chunk].thread);
|
|
+ }
|
|
+
|
|
+ CloseHandle(main_event);
|
|
+ free(threads);
|
|
+
|
|
+
|
|
+ const int ret = (int)InterlockedCompareExchange(&sig_index, -1, -1);
|
|
+ return (ret >= 0) ? ret : (int)WAIT_FAILED;
|
|
+}
|
|
+
|
|
+static EventLooperRec win32_looper;
|
|
+
|
|
+static void fdevent_init(void)
|
|
+{
|
|
+ win32_looper.htab_count = 0;
|
|
+ win32_looper.hooks = NULL;
|
|
+}
|
|
+
|
|
+static void fdevent_connect(fdevent *fde)
|
|
+{
|
|
+ EventLooper looper = &win32_looper;
|
|
+ int events = fde->state & FDE_EVENTMASK;
|
|
+
|
|
+ if (events != 0)
|
|
+ event_looper_hook( looper, fde->fd, events );
|
|
+}
|
|
+
|
|
+static void fdevent_disconnect(fdevent *fde)
|
|
+{
|
|
+ EventLooper looper = &win32_looper;
|
|
+ int events = fde->state & FDE_EVENTMASK;
|
|
+
|
|
+ if (events != 0)
|
|
+ event_looper_unhook( looper, fde->fd, events );
|
|
+}
|
|
+
|
|
+static void fdevent_update(fdevent *fde, unsigned events)
|
|
+{
|
|
+ EventLooper looper = &win32_looper;
|
|
+ unsigned events0 = fde->state & FDE_EVENTMASK;
|
|
+
|
|
+ if (events != events0) {
|
|
+ int removes = events0 & ~events;
|
|
+ int adds = events & ~events0;
|
|
+ if (removes) {
|
|
+ D("fdevent_update: remove %x from %d\n", removes, fde->fd);
|
|
+ event_looper_unhook( looper, fde->fd, removes );
|
|
+ }
|
|
+ if (adds) {
|
|
+ D("fdevent_update: add %x to %d\n", adds, fde->fd);
|
|
+ event_looper_hook ( looper, fde->fd, adds );
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+static void fdevent_process()
|
|
+{
|
|
+ EventLooper looper = &win32_looper;
|
|
+ EventHook hook;
|
|
+ int gotone = 0;
|
|
+
|
|
+ /* if we have at least one ready hook, execute it/them */
|
|
+ for (hook = looper->hooks; hook; hook = hook->next) {
|
|
+ hook->ready = 0;
|
|
+ if (hook->prepare) {
|
|
+ hook->prepare(hook);
|
|
+ if (hook->ready != 0) {
|
|
+ event_hook_signal( hook );
|
|
+ gotone = 1;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* nothing's ready yet, so wait for something to happen */
|
|
+ if (!gotone)
|
|
+ {
|
|
+ looper->htab_count = 0;
|
|
+
|
|
+ for (hook = looper->hooks; hook; hook = hook->next)
|
|
+ {
|
|
+ if (hook->start && !hook->start(hook)) {
|
|
+ D( "fdevent_process: error when starting a hook\n" );
|
|
+ return;
|
|
+ }
|
|
+ if (hook->h != INVALID_HANDLE_VALUE) {
|
|
+ int nn;
|
|
+
|
|
+ for (nn = 0; nn < looper->htab_count; nn++)
|
|
+ {
|
|
+ if ( looper->htab[nn] == hook->h )
|
|
+ goto DontAdd;
|
|
+ }
|
|
+ looper->htab[ looper->htab_count++ ] = hook->h;
|
|
+ DontAdd:
|
|
+ ;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (looper->htab_count == 0) {
|
|
+ D( "fdevent_process: nothing to wait for !!\n" );
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ do
|
|
+ {
|
|
+ int wait_ret;
|
|
+
|
|
+ D( "adb_win32: waiting for %d events\n", looper->htab_count );
|
|
+ if (looper->htab_count > MAXIMUM_WAIT_OBJECTS) {
|
|
+ D("handle count %d exceeds MAXIMUM_WAIT_OBJECTS.\n", looper->htab_count);
|
|
+ wait_ret = _wait_for_all(looper->htab, looper->htab_count);
|
|
+ } else {
|
|
+ wait_ret = WaitForMultipleObjects( looper->htab_count, looper->htab, FALSE, INFINITE );
|
|
+ }
|
|
+ if (wait_ret == (int)WAIT_FAILED) {
|
|
+ D( "adb_win32: wait failed, error %ld\n", GetLastError() );
|
|
+ } else {
|
|
+ D( "adb_win32: got one (index %d)\n", wait_ret );
|
|
+
|
|
+ /* according to Cygwin, some objects like consoles wake up on "inappropriate" events
|
|
+ * like mouse movements. we need to filter these with the "check" function
|
|
+ */
|
|
+ if ((unsigned)wait_ret < (unsigned)looper->htab_count)
|
|
+ {
|
|
+ for (hook = looper->hooks; hook; hook = hook->next)
|
|
+ {
|
|
+ if ( looper->htab[wait_ret] == hook->h &&
|
|
+ (!hook->check || hook->check(hook)) )
|
|
+ {
|
|
+ D( "adb_win32: signaling %s for %x\n", hook->fh->name, hook->ready );
|
|
+ event_hook_signal( hook );
|
|
+ gotone = 1;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ while (!gotone);
|
|
+
|
|
+ for (hook = looper->hooks; hook; hook = hook->next) {
|
|
+ if (hook->stop)
|
|
+ hook->stop( hook );
|
|
+ }
|
|
+ }
|
|
+
|
|
+ for (hook = looper->hooks; hook; hook = hook->next) {
|
|
+ if (hook->peek && hook->peek(hook))
|
|
+ event_hook_signal( hook );
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+static void fdevent_register(fdevent *fde)
|
|
+{
|
|
+ int fd = fde->fd - WIN32_FH_BASE;
|
|
+
|
|
+ if(fd < 0) {
|
|
+ FATAL("bogus negative fd (%d)\n", fde->fd);
|
|
+ }
|
|
+
|
|
+ if(fd >= fd_table_max) {
|
|
+ int oldmax = fd_table_max;
|
|
+ if(fde->fd > 32000) {
|
|
+ FATAL("bogus huuuuge fd (%d)\n", fde->fd);
|
|
+ }
|
|
+ if(fd_table_max == 0) {
|
|
+ fdevent_init();
|
|
+ fd_table_max = 256;
|
|
+ }
|
|
+ while(fd_table_max <= fd) {
|
|
+ fd_table_max *= 2;
|
|
+ }
|
|
+ fd_table = realloc(fd_table, sizeof(fdevent*) * fd_table_max);
|
|
+ if(fd_table == 0) {
|
|
+ FATAL("could not expand fd_table to %d entries\n", fd_table_max);
|
|
+ }
|
|
+ memset(fd_table + oldmax, 0, sizeof(int) * (fd_table_max - oldmax));
|
|
+ }
|
|
+
|
|
+ fd_table[fd] = fde;
|
|
+}
|
|
+
|
|
+static void fdevent_unregister(fdevent *fde)
|
|
+{
|
|
+ int fd = fde->fd - WIN32_FH_BASE;
|
|
+
|
|
+ if((fd < 0) || (fd >= fd_table_max)) {
|
|
+ FATAL("fd out of range (%d)\n", fde->fd);
|
|
+ }
|
|
+
|
|
+ if(fd_table[fd] != fde) {
|
|
+ FATAL("fd_table out of sync");
|
|
+ }
|
|
+
|
|
+ fd_table[fd] = 0;
|
|
+
|
|
+ if(!(fde->state & FDE_DONT_CLOSE)) {
|
|
+ dump_fde(fde, "close");
|
|
+ adb_close(fde->fd);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void fdevent_plist_enqueue(fdevent *node)
|
|
+{
|
|
+ fdevent *list = &list_pending;
|
|
+
|
|
+ node->next = list;
|
|
+ node->prev = list->prev;
|
|
+ node->prev->next = node;
|
|
+ list->prev = node;
|
|
+}
|
|
+
|
|
+static void fdevent_plist_remove(fdevent *node)
|
|
+{
|
|
+ node->prev->next = node->next;
|
|
+ node->next->prev = node->prev;
|
|
+ node->next = 0;
|
|
+ node->prev = 0;
|
|
+}
|
|
+
|
|
+static fdevent *fdevent_plist_dequeue(void)
|
|
+{
|
|
+ fdevent *list = &list_pending;
|
|
+ fdevent *node = list->next;
|
|
+
|
|
+ if(node == list) return 0;
|
|
+
|
|
+ list->next = node->next;
|
|
+ list->next->prev = list;
|
|
+ node->next = 0;
|
|
+ node->prev = 0;
|
|
+
|
|
+ return node;
|
|
+}
|
|
+
|
|
+fdevent *fdevent_create(int fd, fd_func func, void *arg)
|
|
+{
|
|
+ fdevent *fde = (fdevent*) malloc(sizeof(fdevent));
|
|
+ if(fde == 0) return 0;
|
|
+ fdevent_install(fde, fd, func, arg);
|
|
+ fde->state |= FDE_CREATED;
|
|
+ return fde;
|
|
+}
|
|
+
|
|
+void fdevent_destroy(fdevent *fde)
|
|
+{
|
|
+ if(fde == 0) return;
|
|
+ if(!(fde->state & FDE_CREATED)) {
|
|
+ FATAL("fde %p not created by fdevent_create()\n", fde);
|
|
+ }
|
|
+ fdevent_remove(fde);
|
|
+}
|
|
+
|
|
+void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg)
|
|
+{
|
|
+ memset(fde, 0, sizeof(fdevent));
|
|
+ fde->state = FDE_ACTIVE;
|
|
+ fde->fd = fd;
|
|
+ fde->func = func;
|
|
+ fde->arg = arg;
|
|
+
|
|
+ fdevent_register(fde);
|
|
+ dump_fde(fde, "connect");
|
|
+ fdevent_connect(fde);
|
|
+ fde->state |= FDE_ACTIVE;
|
|
+}
|
|
+
|
|
+void fdevent_remove(fdevent *fde)
|
|
+{
|
|
+ if(fde->state & FDE_PENDING) {
|
|
+ fdevent_plist_remove(fde);
|
|
+ }
|
|
+
|
|
+ if(fde->state & FDE_ACTIVE) {
|
|
+ fdevent_disconnect(fde);
|
|
+ dump_fde(fde, "disconnect");
|
|
+ fdevent_unregister(fde);
|
|
+ }
|
|
+
|
|
+ fde->state = 0;
|
|
+ fde->events = 0;
|
|
+}
|
|
+
|
|
+
|
|
+void fdevent_set(fdevent *fde, unsigned events)
|
|
+{
|
|
+ events &= FDE_EVENTMASK;
|
|
+
|
|
+ if((fde->state & FDE_EVENTMASK) == (int)events) return;
|
|
+
|
|
+ if(fde->state & FDE_ACTIVE) {
|
|
+ fdevent_update(fde, events);
|
|
+ dump_fde(fde, "update");
|
|
+ }
|
|
+
|
|
+ fde->state = (fde->state & FDE_STATEMASK) | events;
|
|
+
|
|
+ if(fde->state & FDE_PENDING) {
|
|
+ /* if we're pending, make sure
|
|
+ ** we don't signal an event that
|
|
+ ** is no longer wanted.
|
|
+ */
|
|
+ fde->events &= (~events);
|
|
+ if(fde->events == 0) {
|
|
+ fdevent_plist_remove(fde);
|
|
+ fde->state &= (~FDE_PENDING);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+void fdevent_add(fdevent *fde, unsigned events)
|
|
+{
|
|
+ fdevent_set(
|
|
+ fde, (fde->state & FDE_EVENTMASK) | (events & FDE_EVENTMASK));
|
|
+}
|
|
+
|
|
+void fdevent_del(fdevent *fde, unsigned events)
|
|
+{
|
|
+ fdevent_set(
|
|
+ fde, (fde->state & FDE_EVENTMASK) & (~(events & FDE_EVENTMASK)));
|
|
+}
|
|
+
|
|
+void fdevent_loop()
|
|
+{
|
|
+ fdevent *fde;
|
|
+
|
|
+ for(;;) {
|
|
+#if DEBUG
|
|
+ fprintf(stderr,"--- ---- waiting for events\n");
|
|
+#endif
|
|
+ fdevent_process();
|
|
+
|
|
+ while((fde = fdevent_plist_dequeue())) {
|
|
+ unsigned events = fde->events;
|
|
+ fde->events = 0;
|
|
+ fde->state &= (~FDE_PENDING);
|
|
+ dump_fde(fde, "callback");
|
|
+ fde->func(fde->fd, events, fde->arg);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+/** FILE EVENT HOOKS
|
|
+ **/
|
|
+
|
|
+static void _event_file_prepare( EventHook hook )
|
|
+{
|
|
+ if (hook->wanted & (FDE_READ|FDE_WRITE)) {
|
|
+ /* we can always read/write */
|
|
+ hook->ready |= hook->wanted & (FDE_READ|FDE_WRITE);
|
|
+ }
|
|
+}
|
|
+
|
|
+static int _event_file_peek( EventHook hook )
|
|
+{
|
|
+ return (hook->wanted & (FDE_READ|FDE_WRITE));
|
|
+}
|
|
+
|
|
+static void _fh_file_hook( FH f, int events, EventHook hook )
|
|
+{
|
|
+ hook->h = f->fh_handle;
|
|
+ hook->prepare = _event_file_prepare;
|
|
+ hook->peek = _event_file_peek;
|
|
+}
|
|
+
|
|
+/** SOCKET EVENT HOOKS
|
|
+ **/
|
|
+
|
|
+static void _event_socket_verify( EventHook hook, WSANETWORKEVENTS* evts )
|
|
+{
|
|
+ if ( evts->lNetworkEvents & (FD_READ|FD_ACCEPT|FD_CLOSE) ) {
|
|
+ if (hook->wanted & FDE_READ)
|
|
+ hook->ready |= FDE_READ;
|
|
+ if ((evts->iErrorCode[FD_READ] != 0) && hook->wanted & FDE_ERROR)
|
|
+ hook->ready |= FDE_ERROR;
|
|
+ }
|
|
+ if ( evts->lNetworkEvents & (FD_WRITE|FD_CONNECT|FD_CLOSE) ) {
|
|
+ if (hook->wanted & FDE_WRITE)
|
|
+ hook->ready |= FDE_WRITE;
|
|
+ if ((evts->iErrorCode[FD_WRITE] != 0) && hook->wanted & FDE_ERROR)
|
|
+ hook->ready |= FDE_ERROR;
|
|
+ }
|
|
+ if ( evts->lNetworkEvents & FD_OOB ) {
|
|
+ if (hook->wanted & FDE_ERROR)
|
|
+ hook->ready |= FDE_ERROR;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void _event_socket_prepare( EventHook hook )
|
|
+{
|
|
+ WSANETWORKEVENTS evts;
|
|
+
|
|
+ /* look if some of the events we want already happened ? */
|
|
+ if (!WSAEnumNetworkEvents( hook->fh->fh_socket, NULL, &evts ))
|
|
+ _event_socket_verify( hook, &evts );
|
|
+}
|
|
+
|
|
+static int _socket_wanted_to_flags( int wanted )
|
|
+{
|
|
+ int flags = 0;
|
|
+ if (wanted & FDE_READ)
|
|
+ flags |= FD_READ | FD_ACCEPT | FD_CLOSE;
|
|
+
|
|
+ if (wanted & FDE_WRITE)
|
|
+ flags |= FD_WRITE | FD_CONNECT | FD_CLOSE;
|
|
+
|
|
+ if (wanted & FDE_ERROR)
|
|
+ flags |= FD_OOB;
|
|
+
|
|
+ return flags;
|
|
+}
|
|
+
|
|
+static int _event_socket_start( EventHook hook )
|
|
+{
|
|
+ /* create an event which we're going to wait for */
|
|
+ FH fh = hook->fh;
|
|
+ long flags = _socket_wanted_to_flags( hook->wanted );
|
|
+
|
|
+ hook->h = fh->event;
|
|
+ if (hook->h == INVALID_HANDLE_VALUE) {
|
|
+ D( "_event_socket_start: no event for %s\n", fh->name );
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if ( flags != fh->mask ) {
|
|
+ D( "_event_socket_start: hooking %s for %x (flags %ld)\n", hook->fh->name, hook->wanted, flags );
|
|
+ if ( WSAEventSelect( fh->fh_socket, hook->h, flags ) ) {
|
|
+ D( "_event_socket_start: WSAEventSelect() for %s failed, error %d\n", hook->fh->name, WSAGetLastError() );
|
|
+ CloseHandle( hook->h );
|
|
+ hook->h = INVALID_HANDLE_VALUE;
|
|
+ exit(1);
|
|
+ return 0;
|
|
+ }
|
|
+ fh->mask = flags;
|
|
+ }
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+static void _event_socket_stop( EventHook hook )
|
|
+{
|
|
+ hook->h = INVALID_HANDLE_VALUE;
|
|
+}
|
|
+
|
|
+static int _event_socket_check( EventHook hook )
|
|
+{
|
|
+ int result = 0;
|
|
+ FH fh = hook->fh;
|
|
+ WSANETWORKEVENTS evts;
|
|
+
|
|
+ if (!WSAEnumNetworkEvents( fh->fh_socket, hook->h, &evts ) ) {
|
|
+ _event_socket_verify( hook, &evts );
|
|
+ result = (hook->ready != 0);
|
|
+ if (result) {
|
|
+ ResetEvent( hook->h );
|
|
+ }
|
|
+ }
|
|
+ D( "_event_socket_check %s returns %d\n", fh->name, result );
|
|
+ return result;
|
|
+}
|
|
+
|
|
+static int _event_socket_peek( EventHook hook )
|
|
+{
|
|
+ WSANETWORKEVENTS evts;
|
|
+ FH fh = hook->fh;
|
|
+
|
|
+ /* look if some of the events we want already happened ? */
|
|
+ if (!WSAEnumNetworkEvents( fh->fh_socket, NULL, &evts )) {
|
|
+ _event_socket_verify( hook, &evts );
|
|
+ if (hook->ready)
|
|
+ ResetEvent( hook->h );
|
|
+ }
|
|
+
|
|
+ return hook->ready != 0;
|
|
+}
|
|
+
|
|
+
|
|
+
|
|
+static void _fh_socket_hook( FH f, int events, EventHook hook )
|
|
+{
|
|
+ hook->prepare = _event_socket_prepare;
|
|
+ hook->start = _event_socket_start;
|
|
+ hook->stop = _event_socket_stop;
|
|
+ hook->check = _event_socket_check;
|
|
+ hook->peek = _event_socket_peek;
|
|
+
|
|
+ _event_socket_start( hook );
|
|
+}
|
|
+
|
|
+/** SOCKETPAIR EVENT HOOKS
|
|
+ **/
|
|
+
|
|
+static void _event_socketpair_prepare( EventHook hook )
|
|
+{
|
|
+ FH fh = hook->fh;
|
|
+ SocketPair pair = fh->fh_pair;
|
|
+ BipBuffer rbip = (pair->a_fd == fh) ? &pair->b2a_bip : &pair->a2b_bip;
|
|
+ BipBuffer wbip = (pair->a_fd == fh) ? &pair->a2b_bip : &pair->b2a_bip;
|
|
+
|
|
+ if (hook->wanted & FDE_READ && rbip->can_read)
|
|
+ hook->ready |= FDE_READ;
|
|
+
|
|
+ if (hook->wanted & FDE_WRITE && wbip->can_write)
|
|
+ hook->ready |= FDE_WRITE;
|
|
+ }
|
|
+
|
|
+ static int _event_socketpair_start( EventHook hook )
|
|
+ {
|
|
+ FH fh = hook->fh;
|
|
+ SocketPair pair = fh->fh_pair;
|
|
+ BipBuffer rbip = (pair->a_fd == fh) ? &pair->b2a_bip : &pair->a2b_bip;
|
|
+ BipBuffer wbip = (pair->a_fd == fh) ? &pair->a2b_bip : &pair->b2a_bip;
|
|
+
|
|
+ if (hook->wanted == FDE_READ)
|
|
+ hook->h = rbip->evt_read;
|
|
+
|
|
+ else if (hook->wanted == FDE_WRITE)
|
|
+ hook->h = wbip->evt_write;
|
|
+
|
|
+ else {
|
|
+ D("_event_socketpair_start: can't handle FDE_READ+FDE_WRITE\n" );
|
|
+ return 0;
|
|
+ }
|
|
+ D( "_event_socketpair_start: hook %s for %x wanted=%x\n",
|
|
+ hook->fh->name, _fh_to_int(fh), hook->wanted);
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+static int _event_socketpair_peek( EventHook hook )
|
|
+{
|
|
+ _event_socketpair_prepare( hook );
|
|
+ return hook->ready != 0;
|
|
+}
|
|
+
|
|
+static void _fh_socketpair_hook( FH fh, int events, EventHook hook )
|
|
+{
|
|
+ hook->prepare = _event_socketpair_prepare;
|
|
+ hook->start = _event_socketpair_start;
|
|
+ hook->peek = _event_socketpair_peek;
|
|
+}
|
|
+
|
|
+
|
|
+void
|
|
+adb_sysdeps_init( void )
|
|
+{
|
|
+#define ADB_MUTEX(x) InitializeCriticalSection( & x );
|
|
+#include "mutex_list.h"
|
|
+ InitializeCriticalSection( &_win32_lock );
|
|
+}
|
|
+
|
|
+/* Windows doesn't have strtok_r. Use the one from bionic. */
|
|
+
|
|
+/*
|
|
+ * Copyright (c) 1988 Regents of the University of California.
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. Neither the name of the University nor the names of its contributors
|
|
+ * may be used to endorse or promote products derived from this software
|
|
+ * without specific prior written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
+ * SUCH DAMAGE.
|
|
+ */
|
|
+
|
|
+char *
|
|
+adb_strtok_r(char *s, const char *delim, char **last)
|
|
+{
|
|
+ char *spanp;
|
|
+ int c, sc;
|
|
+ char *tok;
|
|
+
|
|
+
|
|
+ if (s == NULL && (s = *last) == NULL)
|
|
+ return (NULL);
|
|
+
|
|
+ /*
|
|
+ * Skip (span) leading delimiters (s += strspn(s, delim), sort of).
|
|
+ */
|
|
+cont:
|
|
+ c = *s++;
|
|
+ for (spanp = (char *)delim; (sc = *spanp++) != 0;) {
|
|
+ if (c == sc)
|
|
+ goto cont;
|
|
+ }
|
|
+
|
|
+ if (c == 0) { /* no non-delimiter characters */
|
|
+ *last = NULL;
|
|
+ return (NULL);
|
|
+ }
|
|
+ tok = s - 1;
|
|
+
|
|
+ /*
|
|
+ * Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
|
|
+ * Note that delim must have one NUL; we stop if we see that, too.
|
|
+ */
|
|
+ for (;;) {
|
|
+ c = *s++;
|
|
+ spanp = (char *)delim;
|
|
+ do {
|
|
+ if ((sc = *spanp++) == c) {
|
|
+ if (c == 0)
|
|
+ s = NULL;
|
|
+ else
|
|
+ s[-1] = 0;
|
|
+ *last = s;
|
|
+ return (tok);
|
|
+ }
|
|
+ } while (sc != 0);
|
|
+ }
|
|
+ /* NOTREACHED */
|
|
+}
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/test_track_devices.c
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/test_track_devices.c 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,97 @@
|
|
+/* a simple test program, connects to ADB server, and opens a track-devices session */
|
|
+#include <netdb.h>
|
|
+#include <sys/socket.h>
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+#include <errno.h>
|
|
+#include <memory.h>
|
|
+
|
|
+static void
|
|
+panic( const char* msg )
|
|
+{
|
|
+ fprintf(stderr, "PANIC: %s: %s\n", msg, strerror(errno));
|
|
+ exit(1);
|
|
+}
|
|
+
|
|
+static int
|
|
+unix_write( int fd, const char* buf, int len )
|
|
+{
|
|
+ int result = 0;
|
|
+ while (len > 0) {
|
|
+ int len2 = write(fd, buf, len);
|
|
+ if (len2 < 0) {
|
|
+ if (errno == EINTR || errno == EAGAIN)
|
|
+ continue;
|
|
+ return -1;
|
|
+ }
|
|
+ result += len2;
|
|
+ len -= len2;
|
|
+ buf += len2;
|
|
+ }
|
|
+ return result;
|
|
+}
|
|
+
|
|
+static int
|
|
+unix_read( int fd, char* buf, int len )
|
|
+{
|
|
+ int result = 0;
|
|
+ while (len > 0) {
|
|
+ int len2 = read(fd, buf, len);
|
|
+ if (len2 < 0) {
|
|
+ if (errno == EINTR || errno == EAGAIN)
|
|
+ continue;
|
|
+ return -1;
|
|
+ }
|
|
+ result += len2;
|
|
+ len -= len2;
|
|
+ buf += len2;
|
|
+ }
|
|
+ return result;
|
|
+}
|
|
+
|
|
+
|
|
+int main( void )
|
|
+{
|
|
+ int ret, s;
|
|
+ struct sockaddr_in server;
|
|
+ char buffer[1024];
|
|
+ const char* request = "host:track-devices";
|
|
+ int len;
|
|
+
|
|
+ memset( &server, 0, sizeof(server) );
|
|
+ server.sin_family = AF_INET;
|
|
+ server.sin_port = htons(5037);
|
|
+ server.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
|
+
|
|
+ s = socket( PF_INET, SOCK_STREAM, 0 );
|
|
+ ret = connect( s, (struct sockaddr*) &server, sizeof(server) );
|
|
+ if (ret < 0) panic( "could not connect to server" );
|
|
+
|
|
+ /* send the request */
|
|
+ len = snprintf( buffer, sizeof buffer, "%04x%s", strlen(request), request );
|
|
+ if (unix_write(s, buffer, len) < 0)
|
|
+ panic( "could not send request" );
|
|
+
|
|
+ /* read the OKAY answer */
|
|
+ if (unix_read(s, buffer, 4) != 4)
|
|
+ panic( "could not read request" );
|
|
+
|
|
+ printf( "server answer: %.*s\n", 4, buffer );
|
|
+
|
|
+ /* now loop */
|
|
+ for (;;) {
|
|
+ char head[5] = "0000";
|
|
+
|
|
+ if (unix_read(s, head, 4) < 0)
|
|
+ panic("could not read length");
|
|
+
|
|
+ if ( sscanf( head, "%04x", &len ) != 1 )
|
|
+ panic("could not decode length");
|
|
+
|
|
+ if (unix_read(s, buffer, len) != len)
|
|
+ panic("could not read data");
|
|
+
|
|
+ printf( "received header %.*s (%d bytes):\n%.*s", 4, head, len, len, buffer );
|
|
+ }
|
|
+ close(s);
|
|
+}
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/test_track_jdwp.c
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/test_track_jdwp.c 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,97 @@
|
|
+/* a simple test program, connects to ADB server, and opens a track-devices session */
|
|
+#include <netdb.h>
|
|
+#include <sys/socket.h>
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+#include <errno.h>
|
|
+#include <memory.h>
|
|
+
|
|
+static void
|
|
+panic( const char* msg )
|
|
+{
|
|
+ fprintf(stderr, "PANIC: %s: %s\n", msg, strerror(errno));
|
|
+ exit(1);
|
|
+}
|
|
+
|
|
+static int
|
|
+unix_write( int fd, const char* buf, int len )
|
|
+{
|
|
+ int result = 0;
|
|
+ while (len > 0) {
|
|
+ int len2 = write(fd, buf, len);
|
|
+ if (len2 < 0) {
|
|
+ if (errno == EINTR || errno == EAGAIN)
|
|
+ continue;
|
|
+ return -1;
|
|
+ }
|
|
+ result += len2;
|
|
+ len -= len2;
|
|
+ buf += len2;
|
|
+ }
|
|
+ return result;
|
|
+}
|
|
+
|
|
+static int
|
|
+unix_read( int fd, char* buf, int len )
|
|
+{
|
|
+ int result = 0;
|
|
+ while (len > 0) {
|
|
+ int len2 = read(fd, buf, len);
|
|
+ if (len2 < 0) {
|
|
+ if (errno == EINTR || errno == EAGAIN)
|
|
+ continue;
|
|
+ return -1;
|
|
+ }
|
|
+ result += len2;
|
|
+ len -= len2;
|
|
+ buf += len2;
|
|
+ }
|
|
+ return result;
|
|
+}
|
|
+
|
|
+
|
|
+int main( void )
|
|
+{
|
|
+ int ret, s;
|
|
+ struct sockaddr_in server;
|
|
+ char buffer[1024];
|
|
+ const char* request = "track-jdwp";
|
|
+ int len;
|
|
+
|
|
+ memset( &server, 0, sizeof(server) );
|
|
+ server.sin_family = AF_INET;
|
|
+ server.sin_port = htons(5037);
|
|
+ server.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
|
+
|
|
+ s = socket( PF_INET, SOCK_STREAM, 0 );
|
|
+ ret = connect( s, (struct sockaddr*) &server, sizeof(server) );
|
|
+ if (ret < 0) panic( "could not connect to server" );
|
|
+
|
|
+ /* send the request */
|
|
+ len = snprintf( buffer, sizeof buffer, "%04x%s", strlen(request), request );
|
|
+ if (unix_write(s, buffer, len) < 0)
|
|
+ panic( "could not send request" );
|
|
+
|
|
+ /* read the OKAY answer */
|
|
+ if (unix_read(s, buffer, 4) != 4)
|
|
+ panic( "could not read request" );
|
|
+
|
|
+ printf( "server answer: %.*s\n", 4, buffer );
|
|
+
|
|
+ /* now loop */
|
|
+ for (;;) {
|
|
+ char head[5] = "0000";
|
|
+
|
|
+ if (unix_read(s, head, 4) < 0)
|
|
+ panic("could not read length");
|
|
+
|
|
+ if ( sscanf( head, "%04x", &len ) != 1 )
|
|
+ panic("could not decode length");
|
|
+
|
|
+ if (unix_read(s, buffer, len) != len)
|
|
+ panic("could not read data");
|
|
+
|
|
+ printf( "received header %.*s (%d bytes):\n%.*s", 4, head, len, len, buffer );
|
|
+ }
|
|
+ close(s);
|
|
+}
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/transport.c
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/transport.c 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,1186 @@
|
|
+/*
|
|
+ * Copyright (C) 2007 The Android Open Source Project
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
+ * you may not use this file except in compliance with the License.
|
|
+ * You may obtain a copy of the License at
|
|
+ *
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
+ *
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+ * See the License for the specific language governing permissions and
|
|
+ * limitations under the License.
|
|
+ */
|
|
+
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+#include <unistd.h>
|
|
+#include <string.h>
|
|
+#include <errno.h>
|
|
+
|
|
+#include "sysdeps.h"
|
|
+
|
|
+#define TRACE_TAG TRACE_TRANSPORT
|
|
+#include "adb.h"
|
|
+
|
|
+static void transport_unref(atransport *t);
|
|
+
|
|
+static atransport transport_list = {
|
|
+ .next = &transport_list,
|
|
+ .prev = &transport_list,
|
|
+};
|
|
+
|
|
+ADB_MUTEX_DEFINE( transport_lock );
|
|
+
|
|
+#if ADB_TRACE
|
|
+#define MAX_DUMP_HEX_LEN 16
|
|
+static void dump_hex( const unsigned char* ptr, size_t len )
|
|
+{
|
|
+ int nn, len2 = len;
|
|
+ // Build a string instead of logging each character.
|
|
+ // MAX chars in 2 digit hex, one space, MAX chars, one '\0'.
|
|
+ char buffer[MAX_DUMP_HEX_LEN *2 + 1 + MAX_DUMP_HEX_LEN + 1 ], *pb = buffer;
|
|
+
|
|
+ if (len2 > MAX_DUMP_HEX_LEN) len2 = MAX_DUMP_HEX_LEN;
|
|
+
|
|
+ for (nn = 0; nn < len2; nn++) {
|
|
+ sprintf(pb, "%02x", ptr[nn]);
|
|
+ pb += 2;
|
|
+ }
|
|
+ sprintf(pb++, " ");
|
|
+
|
|
+ for (nn = 0; nn < len2; nn++) {
|
|
+ int c = ptr[nn];
|
|
+ if (c < 32 || c > 127)
|
|
+ c = '.';
|
|
+ *pb++ = c;
|
|
+ }
|
|
+ *pb++ = '\0';
|
|
+ DR("%s\n", buffer);
|
|
+}
|
|
+#endif
|
|
+
|
|
+void
|
|
+kick_transport(atransport* t)
|
|
+{
|
|
+ if (t && !t->kicked)
|
|
+ {
|
|
+ int kicked;
|
|
+
|
|
+ adb_mutex_lock(&transport_lock);
|
|
+ kicked = t->kicked;
|
|
+ if (!kicked)
|
|
+ t->kicked = 1;
|
|
+ adb_mutex_unlock(&transport_lock);
|
|
+
|
|
+ if (!kicked)
|
|
+ t->kick(t);
|
|
+ }
|
|
+}
|
|
+
|
|
+void
|
|
+run_transport_disconnects(atransport* t)
|
|
+{
|
|
+ adisconnect* dis = t->disconnects.next;
|
|
+
|
|
+ D("%s: run_transport_disconnects\n", t->serial);
|
|
+ while (dis != &t->disconnects) {
|
|
+ adisconnect* next = dis->next;
|
|
+ dis->func( dis->opaque, t );
|
|
+ dis = next;
|
|
+ }
|
|
+}
|
|
+
|
|
+#if ADB_TRACE
|
|
+static void
|
|
+dump_packet(const char* name, const char* func, apacket* p)
|
|
+{
|
|
+ unsigned command = p->msg.command;
|
|
+ int len = p->msg.data_length;
|
|
+ char cmd[9];
|
|
+ char arg0[12], arg1[12];
|
|
+ int n;
|
|
+
|
|
+ for (n = 0; n < 4; n++) {
|
|
+ int b = (command >> (n*8)) & 255;
|
|
+ if (b < 32 || b >= 127)
|
|
+ break;
|
|
+ cmd[n] = (char)b;
|
|
+ }
|
|
+ if (n == 4) {
|
|
+ cmd[4] = 0;
|
|
+ } else {
|
|
+ /* There is some non-ASCII name in the command, so dump
|
|
+ * the hexadecimal value instead */
|
|
+ snprintf(cmd, sizeof cmd, "%08x", command);
|
|
+ }
|
|
+
|
|
+ if (p->msg.arg0 < 256U)
|
|
+ snprintf(arg0, sizeof arg0, "%d", p->msg.arg0);
|
|
+ else
|
|
+ snprintf(arg0, sizeof arg0, "0x%x", p->msg.arg0);
|
|
+
|
|
+ if (p->msg.arg1 < 256U)
|
|
+ snprintf(arg1, sizeof arg1, "%d", p->msg.arg1);
|
|
+ else
|
|
+ snprintf(arg1, sizeof arg1, "0x%x", p->msg.arg1);
|
|
+
|
|
+ D("%s: %s: [%s] arg0=%s arg1=%s (len=%d) ",
|
|
+ name, func, cmd, arg0, arg1, len);
|
|
+ dump_hex(p->data, len);
|
|
+}
|
|
+#endif /* ADB_TRACE */
|
|
+
|
|
+static int
|
|
+read_packet(int fd, const char* name, apacket** ppacket)
|
|
+{
|
|
+ char *p = (char*)ppacket; /* really read a packet address */
|
|
+ int r;
|
|
+ int len = sizeof(*ppacket);
|
|
+ char buff[8];
|
|
+ if (!name) {
|
|
+ snprintf(buff, sizeof buff, "fd=%d", fd);
|
|
+ name = buff;
|
|
+ }
|
|
+ while(len > 0) {
|
|
+ r = adb_read(fd, p, len);
|
|
+ if(r > 0) {
|
|
+ len -= r;
|
|
+ p += r;
|
|
+ } else {
|
|
+ D("%s: read_packet (fd=%d), error ret=%d errno=%d: %s\n", name, fd, r, errno, strerror(errno));
|
|
+ if((r < 0) && (errno == EINTR)) continue;
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+#if ADB_TRACE
|
|
+ if (ADB_TRACING) {
|
|
+ dump_packet(name, "from remote", *ppacket);
|
|
+ }
|
|
+#endif
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+write_packet(int fd, const char* name, apacket** ppacket)
|
|
+{
|
|
+ char *p = (char*) ppacket; /* we really write the packet address */
|
|
+ int r, len = sizeof(ppacket);
|
|
+ char buff[8];
|
|
+ if (!name) {
|
|
+ snprintf(buff, sizeof buff, "fd=%d", fd);
|
|
+ name = buff;
|
|
+ }
|
|
+
|
|
+#if ADB_TRACE
|
|
+ if (ADB_TRACING) {
|
|
+ dump_packet(name, "to remote", *ppacket);
|
|
+ }
|
|
+#endif
|
|
+ len = sizeof(ppacket);
|
|
+ while(len > 0) {
|
|
+ r = adb_write(fd, p, len);
|
|
+ if(r > 0) {
|
|
+ len -= r;
|
|
+ p += r;
|
|
+ } else {
|
|
+ D("%s: write_packet (fd=%d) error ret=%d errno=%d: %s\n", name, fd, r, errno, strerror(errno));
|
|
+ if((r < 0) && (errno == EINTR)) continue;
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void transport_socket_events(int fd, unsigned events, void *_t)
|
|
+{
|
|
+ atransport *t = _t;
|
|
+ D("transport_socket_events(fd=%d, events=%04x,...)\n", fd, events);
|
|
+ if(events & FDE_READ){
|
|
+ apacket *p = 0;
|
|
+ if(read_packet(fd, t->serial, &p)){
|
|
+ D("%s: failed to read packet from transport socket on fd %d\n", t->serial, fd);
|
|
+ } else {
|
|
+ handle_packet(p, (atransport *) _t);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+void send_packet(apacket *p, atransport *t)
|
|
+{
|
|
+ unsigned char *x;
|
|
+ unsigned sum;
|
|
+ unsigned count;
|
|
+
|
|
+ p->msg.magic = p->msg.command ^ 0xffffffff;
|
|
+
|
|
+ count = p->msg.data_length;
|
|
+ x = (unsigned char *) p->data;
|
|
+ sum = 0;
|
|
+ while(count-- > 0){
|
|
+ sum += *x++;
|
|
+ }
|
|
+ p->msg.data_check = sum;
|
|
+
|
|
+ print_packet("send", p);
|
|
+
|
|
+ if (t == NULL) {
|
|
+ D("Transport is null \n");
|
|
+ // Zap errno because print_packet() and other stuff have errno effect.
|
|
+ errno = 0;
|
|
+ fatal_errno("Transport is null");
|
|
+ }
|
|
+
|
|
+ if(write_packet(t->transport_socket, t->serial, &p)){
|
|
+ fatal_errno("cannot enqueue packet on transport socket");
|
|
+ }
|
|
+}
|
|
+
|
|
+/* The transport is opened by transport_register_func before
|
|
+** the input and output threads are started.
|
|
+**
|
|
+** The output thread issues a SYNC(1, token) message to let
|
|
+** the input thread know to start things up. In the event
|
|
+** of transport IO failure, the output thread will post a
|
|
+** SYNC(0,0) message to ensure shutdown.
|
|
+**
|
|
+** The transport will not actually be closed until both
|
|
+** threads exit, but the input thread will kick the transport
|
|
+** on its way out to disconnect the underlying device.
|
|
+*/
|
|
+
|
|
+static void *output_thread(void *_t)
|
|
+{
|
|
+ atransport *t = _t;
|
|
+ apacket *p;
|
|
+
|
|
+ D("%s: starting transport output thread on fd %d, SYNC online (%d)\n",
|
|
+ t->serial, t->fd, t->sync_token + 1);
|
|
+ p = get_apacket();
|
|
+ p->msg.command = A_SYNC;
|
|
+ p->msg.arg0 = 1;
|
|
+ p->msg.arg1 = ++(t->sync_token);
|
|
+ p->msg.magic = A_SYNC ^ 0xffffffff;
|
|
+ if(write_packet(t->fd, t->serial, &p)) {
|
|
+ put_apacket(p);
|
|
+ D("%s: failed to write SYNC packet\n", t->serial);
|
|
+ goto oops;
|
|
+ }
|
|
+
|
|
+ D("%s: data pump started\n", t->serial);
|
|
+ for(;;) {
|
|
+ p = get_apacket();
|
|
+
|
|
+ if(t->read_from_remote(p, t) == 0){
|
|
+ D("%s: received remote packet, sending to transport\n",
|
|
+ t->serial);
|
|
+ if(write_packet(t->fd, t->serial, &p)){
|
|
+ put_apacket(p);
|
|
+ D("%s: failed to write apacket to transport\n", t->serial);
|
|
+ goto oops;
|
|
+ }
|
|
+ } else {
|
|
+ D("%s: remote read failed for transport\n", t->serial);
|
|
+ put_apacket(p);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ D("%s: SYNC offline for transport\n", t->serial);
|
|
+ p = get_apacket();
|
|
+ p->msg.command = A_SYNC;
|
|
+ p->msg.arg0 = 0;
|
|
+ p->msg.arg1 = 0;
|
|
+ p->msg.magic = A_SYNC ^ 0xffffffff;
|
|
+ if(write_packet(t->fd, t->serial, &p)) {
|
|
+ put_apacket(p);
|
|
+ D("%s: failed to write SYNC apacket to transport", t->serial);
|
|
+ }
|
|
+
|
|
+oops:
|
|
+ D("%s: transport output thread is exiting\n", t->serial);
|
|
+ kick_transport(t);
|
|
+ transport_unref(t);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void *input_thread(void *_t)
|
|
+{
|
|
+ atransport *t = _t;
|
|
+ apacket *p;
|
|
+ int active = 0;
|
|
+
|
|
+ D("%s: starting transport input thread, reading from fd %d\n",
|
|
+ t->serial, t->fd);
|
|
+
|
|
+ for(;;){
|
|
+ if(read_packet(t->fd, t->serial, &p)) {
|
|
+ D("%s: failed to read apacket from transport on fd %d\n",
|
|
+ t->serial, t->fd );
|
|
+ break;
|
|
+ }
|
|
+ if(p->msg.command == A_SYNC){
|
|
+ if(p->msg.arg0 == 0) {
|
|
+ D("%s: transport SYNC offline\n", t->serial);
|
|
+ put_apacket(p);
|
|
+ break;
|
|
+ } else {
|
|
+ if(p->msg.arg1 == t->sync_token) {
|
|
+ D("%s: transport SYNC online\n", t->serial);
|
|
+ active = 1;
|
|
+ } else {
|
|
+ D("%s: transport ignoring SYNC %d != %d\n",
|
|
+ t->serial, p->msg.arg1, t->sync_token);
|
|
+ }
|
|
+ }
|
|
+ } else {
|
|
+ if(active) {
|
|
+ D("%s: transport got packet, sending to remote\n", t->serial);
|
|
+ t->write_to_remote(p, t);
|
|
+ } else {
|
|
+ D("%s: transport ignoring packet while offline\n", t->serial);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ put_apacket(p);
|
|
+ }
|
|
+
|
|
+ // this is necessary to avoid a race condition that occured when a transport closes
|
|
+ // while a client socket is still active.
|
|
+ close_all_sockets(t);
|
|
+
|
|
+ D("%s: transport input thread is exiting, fd %d\n", t->serial, t->fd);
|
|
+ kick_transport(t);
|
|
+ transport_unref(t);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
+static int transport_registration_send = -1;
|
|
+static int transport_registration_recv = -1;
|
|
+static fdevent transport_registration_fde;
|
|
+
|
|
+
|
|
+#if ADB_HOST
|
|
+static int list_transports_msg(char* buffer, size_t bufferlen)
|
|
+{
|
|
+ char head[5];
|
|
+ int len;
|
|
+
|
|
+ len = list_transports(buffer+4, bufferlen-4, 0);
|
|
+ snprintf(head, sizeof(head), "%04x", len);
|
|
+ memcpy(buffer, head, 4);
|
|
+ len += 4;
|
|
+ return len;
|
|
+}
|
|
+
|
|
+/* this adds support required by the 'track-devices' service.
|
|
+ * this is used to send the content of "list_transport" to any
|
|
+ * number of client connections that want it through a single
|
|
+ * live TCP connection
|
|
+ */
|
|
+typedef struct device_tracker device_tracker;
|
|
+struct device_tracker {
|
|
+ asocket socket;
|
|
+ int update_needed;
|
|
+ device_tracker* next;
|
|
+};
|
|
+
|
|
+/* linked list of all device trackers */
|
|
+static device_tracker* device_tracker_list;
|
|
+
|
|
+static void
|
|
+device_tracker_remove( device_tracker* tracker )
|
|
+{
|
|
+ device_tracker** pnode = &device_tracker_list;
|
|
+ device_tracker* node = *pnode;
|
|
+
|
|
+ adb_mutex_lock( &transport_lock );
|
|
+ while (node) {
|
|
+ if (node == tracker) {
|
|
+ *pnode = node->next;
|
|
+ break;
|
|
+ }
|
|
+ pnode = &node->next;
|
|
+ node = *pnode;
|
|
+ }
|
|
+ adb_mutex_unlock( &transport_lock );
|
|
+}
|
|
+
|
|
+static void
|
|
+device_tracker_close( asocket* socket )
|
|
+{
|
|
+ device_tracker* tracker = (device_tracker*) socket;
|
|
+ asocket* peer = socket->peer;
|
|
+
|
|
+ D( "device tracker %p removed\n", tracker);
|
|
+ if (peer) {
|
|
+ peer->peer = NULL;
|
|
+ peer->close(peer);
|
|
+ }
|
|
+ device_tracker_remove(tracker);
|
|
+ free(tracker);
|
|
+}
|
|
+
|
|
+static int
|
|
+device_tracker_enqueue( asocket* socket, apacket* p )
|
|
+{
|
|
+ /* you can't read from a device tracker, close immediately */
|
|
+ put_apacket(p);
|
|
+ device_tracker_close(socket);
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+static int
|
|
+device_tracker_send( device_tracker* tracker,
|
|
+ const char* buffer,
|
|
+ int len )
|
|
+{
|
|
+ apacket* p = get_apacket();
|
|
+ asocket* peer = tracker->socket.peer;
|
|
+
|
|
+ memcpy(p->data, buffer, len);
|
|
+ p->len = len;
|
|
+ return peer->enqueue( peer, p );
|
|
+}
|
|
+
|
|
+
|
|
+static void
|
|
+device_tracker_ready( asocket* socket )
|
|
+{
|
|
+ device_tracker* tracker = (device_tracker*) socket;
|
|
+
|
|
+ /* we want to send the device list when the tracker connects
|
|
+ * for the first time, even if no update occured */
|
|
+ if (tracker->update_needed > 0) {
|
|
+ char buffer[1024];
|
|
+ int len;
|
|
+
|
|
+ tracker->update_needed = 0;
|
|
+
|
|
+ len = list_transports_msg(buffer, sizeof(buffer));
|
|
+ device_tracker_send(tracker, buffer, len);
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+asocket*
|
|
+create_device_tracker(void)
|
|
+{
|
|
+ device_tracker* tracker = calloc(1,sizeof(*tracker));
|
|
+
|
|
+ if(tracker == 0) fatal("cannot allocate device tracker");
|
|
+
|
|
+ D( "device tracker %p created\n", tracker);
|
|
+
|
|
+ tracker->socket.enqueue = device_tracker_enqueue;
|
|
+ tracker->socket.ready = device_tracker_ready;
|
|
+ tracker->socket.close = device_tracker_close;
|
|
+ tracker->update_needed = 1;
|
|
+
|
|
+ tracker->next = device_tracker_list;
|
|
+ device_tracker_list = tracker;
|
|
+
|
|
+ return &tracker->socket;
|
|
+}
|
|
+
|
|
+
|
|
+/* call this function each time the transport list has changed */
|
|
+void update_transports(void)
|
|
+{
|
|
+ char buffer[1024];
|
|
+ int len;
|
|
+ device_tracker* tracker;
|
|
+
|
|
+ len = list_transports_msg(buffer, sizeof(buffer));
|
|
+
|
|
+ tracker = device_tracker_list;
|
|
+ while (tracker != NULL) {
|
|
+ device_tracker* next = tracker->next;
|
|
+ /* note: this may destroy the tracker if the connection is closed */
|
|
+ device_tracker_send(tracker, buffer, len);
|
|
+ tracker = next;
|
|
+ }
|
|
+}
|
|
+#else
|
|
+void update_transports(void)
|
|
+{
|
|
+ // nothing to do on the device side
|
|
+}
|
|
+#endif // ADB_HOST
|
|
+
|
|
+typedef struct tmsg tmsg;
|
|
+struct tmsg
|
|
+{
|
|
+ atransport *transport;
|
|
+ int action;
|
|
+};
|
|
+
|
|
+static int
|
|
+transport_read_action(int fd, struct tmsg* m)
|
|
+{
|
|
+ char *p = (char*)m;
|
|
+ int len = sizeof(*m);
|
|
+ int r;
|
|
+
|
|
+ while(len > 0) {
|
|
+ r = adb_read(fd, p, len);
|
|
+ if(r > 0) {
|
|
+ len -= r;
|
|
+ p += r;
|
|
+ } else {
|
|
+ if((r < 0) && (errno == EINTR)) continue;
|
|
+ D("transport_read_action: on fd %d, error %d: %s\n",
|
|
+ fd, errno, strerror(errno));
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+transport_write_action(int fd, struct tmsg* m)
|
|
+{
|
|
+ char *p = (char*)m;
|
|
+ int len = sizeof(*m);
|
|
+ int r;
|
|
+
|
|
+ while(len > 0) {
|
|
+ r = adb_write(fd, p, len);
|
|
+ if(r > 0) {
|
|
+ len -= r;
|
|
+ p += r;
|
|
+ } else {
|
|
+ if((r < 0) && (errno == EINTR)) continue;
|
|
+ D("transport_write_action: on fd %d, error %d: %s\n",
|
|
+ fd, errno, strerror(errno));
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void transport_registration_func(int _fd, unsigned ev, void *data)
|
|
+{
|
|
+ tmsg m;
|
|
+ adb_thread_t output_thread_ptr;
|
|
+ adb_thread_t input_thread_ptr;
|
|
+ int s[2];
|
|
+ atransport *t;
|
|
+
|
|
+ if(!(ev & FDE_READ)) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if(transport_read_action(_fd, &m)) {
|
|
+ fatal_errno("cannot read transport registration socket");
|
|
+ }
|
|
+
|
|
+ t = m.transport;
|
|
+
|
|
+ if(m.action == 0){
|
|
+ D("transport: %s removing and free'ing %d\n", t->serial, t->transport_socket);
|
|
+
|
|
+ /* IMPORTANT: the remove closes one half of the
|
|
+ ** socket pair. The close closes the other half.
|
|
+ */
|
|
+ fdevent_remove(&(t->transport_fde));
|
|
+ adb_close(t->fd);
|
|
+
|
|
+ adb_mutex_lock(&transport_lock);
|
|
+ t->next->prev = t->prev;
|
|
+ t->prev->next = t->next;
|
|
+ adb_mutex_unlock(&transport_lock);
|
|
+
|
|
+ run_transport_disconnects(t);
|
|
+
|
|
+ if (t->product)
|
|
+ free(t->product);
|
|
+ if (t->serial)
|
|
+ free(t->serial);
|
|
+ if (t->model)
|
|
+ free(t->model);
|
|
+ if (t->device)
|
|
+ free(t->device);
|
|
+ if (t->devpath)
|
|
+ free(t->devpath);
|
|
+
|
|
+ memset(t,0xee,sizeof(atransport));
|
|
+ free(t);
|
|
+
|
|
+ update_transports();
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ /* don't create transport threads for inaccessible devices */
|
|
+ if (t->connection_state != CS_NOPERM) {
|
|
+ /* initial references are the two threads */
|
|
+ t->ref_count = 2;
|
|
+
|
|
+ if(adb_socketpair(s)) {
|
|
+ fatal_errno("cannot open transport socketpair");
|
|
+ }
|
|
+
|
|
+ D("transport: %s (%d,%d) starting\n", t->serial, s[0], s[1]);
|
|
+
|
|
+ t->transport_socket = s[0];
|
|
+ t->fd = s[1];
|
|
+
|
|
+ fdevent_install(&(t->transport_fde),
|
|
+ t->transport_socket,
|
|
+ transport_socket_events,
|
|
+ t);
|
|
+
|
|
+ fdevent_set(&(t->transport_fde), FDE_READ);
|
|
+
|
|
+ if(adb_thread_create(&input_thread_ptr, input_thread, t)){
|
|
+ fatal_errno("cannot create input thread");
|
|
+ }
|
|
+
|
|
+ if(adb_thread_create(&output_thread_ptr, output_thread, t)){
|
|
+ fatal_errno("cannot create output thread");
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* put us on the master device list */
|
|
+ adb_mutex_lock(&transport_lock);
|
|
+ t->next = &transport_list;
|
|
+ t->prev = transport_list.prev;
|
|
+ t->next->prev = t;
|
|
+ t->prev->next = t;
|
|
+ adb_mutex_unlock(&transport_lock);
|
|
+
|
|
+ t->disconnects.next = t->disconnects.prev = &t->disconnects;
|
|
+
|
|
+ update_transports();
|
|
+}
|
|
+
|
|
+void init_transport_registration(void)
|
|
+{
|
|
+ int s[2];
|
|
+
|
|
+ if(adb_socketpair(s)){
|
|
+ fatal_errno("cannot open transport registration socketpair");
|
|
+ }
|
|
+
|
|
+ transport_registration_send = s[0];
|
|
+ transport_registration_recv = s[1];
|
|
+
|
|
+ fdevent_install(&transport_registration_fde,
|
|
+ transport_registration_recv,
|
|
+ transport_registration_func,
|
|
+ 0);
|
|
+
|
|
+ fdevent_set(&transport_registration_fde, FDE_READ);
|
|
+}
|
|
+
|
|
+/* the fdevent select pump is single threaded */
|
|
+static void register_transport(atransport *transport)
|
|
+{
|
|
+ tmsg m;
|
|
+ m.transport = transport;
|
|
+ m.action = 1;
|
|
+ D("transport: %s registered\n", transport->serial);
|
|
+ if(transport_write_action(transport_registration_send, &m)) {
|
|
+ fatal_errno("cannot write transport registration socket\n");
|
|
+ }
|
|
+}
|
|
+
|
|
+static void remove_transport(atransport *transport)
|
|
+{
|
|
+ tmsg m;
|
|
+ m.transport = transport;
|
|
+ m.action = 0;
|
|
+ D("transport: %s removed\n", transport->serial);
|
|
+ if(transport_write_action(transport_registration_send, &m)) {
|
|
+ fatal_errno("cannot write transport registration socket\n");
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+static void transport_unref_locked(atransport *t)
|
|
+{
|
|
+ t->ref_count--;
|
|
+ if (t->ref_count == 0) {
|
|
+ D("transport: %s unref (kicking and closing)\n", t->serial);
|
|
+ if (!t->kicked) {
|
|
+ t->kicked = 1;
|
|
+ t->kick(t);
|
|
+ }
|
|
+ t->close(t);
|
|
+ remove_transport(t);
|
|
+ } else {
|
|
+ D("transport: %s unref (count=%d)\n", t->serial, t->ref_count);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void transport_unref(atransport *t)
|
|
+{
|
|
+ if (t) {
|
|
+ adb_mutex_lock(&transport_lock);
|
|
+ transport_unref_locked(t);
|
|
+ adb_mutex_unlock(&transport_lock);
|
|
+ }
|
|
+}
|
|
+
|
|
+void add_transport_disconnect(atransport* t, adisconnect* dis)
|
|
+{
|
|
+ adb_mutex_lock(&transport_lock);
|
|
+ dis->next = &t->disconnects;
|
|
+ dis->prev = dis->next->prev;
|
|
+ dis->prev->next = dis;
|
|
+ dis->next->prev = dis;
|
|
+ adb_mutex_unlock(&transport_lock);
|
|
+}
|
|
+
|
|
+void remove_transport_disconnect(atransport* t, adisconnect* dis)
|
|
+{
|
|
+ dis->prev->next = dis->next;
|
|
+ dis->next->prev = dis->prev;
|
|
+ dis->next = dis->prev = dis;
|
|
+}
|
|
+
|
|
+static int qual_char_is_invalid(char ch)
|
|
+{
|
|
+ if ('A' <= ch && ch <= 'Z')
|
|
+ return 0;
|
|
+ if ('a' <= ch && ch <= 'z')
|
|
+ return 0;
|
|
+ if ('0' <= ch && ch <= '9')
|
|
+ return 0;
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+static int qual_match(const char *to_test,
|
|
+ const char *prefix, const char *qual, int sanitize_qual)
|
|
+{
|
|
+ if (!to_test || !*to_test)
|
|
+ /* Return true if both the qual and to_test are null strings. */
|
|
+ return !qual || !*qual;
|
|
+
|
|
+ if (!qual)
|
|
+ return 0;
|
|
+
|
|
+ if (prefix) {
|
|
+ while (*prefix) {
|
|
+ if (*prefix++ != *to_test++)
|
|
+ return 0;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ while (*qual) {
|
|
+ char ch = *qual++;
|
|
+ if (sanitize_qual && qual_char_is_invalid(ch))
|
|
+ ch = '_';
|
|
+ if (ch != *to_test++)
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ /* Everything matched so far. Return true if *to_test is a NUL. */
|
|
+ return !*to_test;
|
|
+}
|
|
+
|
|
+atransport *acquire_one_transport(int state, transport_type ttype, const char* serial, char** error_out)
|
|
+{
|
|
+ atransport *t;
|
|
+ atransport *result = NULL;
|
|
+ int ambiguous = 0;
|
|
+
|
|
+retry:
|
|
+ if (error_out)
|
|
+ *error_out = "device not found";
|
|
+
|
|
+ adb_mutex_lock(&transport_lock);
|
|
+ for (t = transport_list.next; t != &transport_list; t = t->next) {
|
|
+ if (t->connection_state == CS_NOPERM) {
|
|
+ if (error_out)
|
|
+ *error_out = "insufficient permissions for device";
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ /* check for matching serial number */
|
|
+ if (serial) {
|
|
+ if ((t->serial && !strcmp(serial, t->serial)) ||
|
|
+ (t->devpath && !strcmp(serial, t->devpath)) ||
|
|
+ qual_match(serial, "product:", t->product, 0) ||
|
|
+ qual_match(serial, "model:", t->model, 1) ||
|
|
+ qual_match(serial, "device:", t->device, 0)) {
|
|
+ if (result) {
|
|
+ if (error_out)
|
|
+ *error_out = "more than one device";
|
|
+ ambiguous = 1;
|
|
+ result = NULL;
|
|
+ break;
|
|
+ }
|
|
+ result = t;
|
|
+ }
|
|
+ } else {
|
|
+ if (ttype == kTransportUsb && t->type == kTransportUsb) {
|
|
+ if (result) {
|
|
+ if (error_out)
|
|
+ *error_out = "more than one device";
|
|
+ ambiguous = 1;
|
|
+ result = NULL;
|
|
+ break;
|
|
+ }
|
|
+ result = t;
|
|
+ } else if (ttype == kTransportLocal && t->type == kTransportLocal) {
|
|
+ if (result) {
|
|
+ if (error_out)
|
|
+ *error_out = "more than one emulator";
|
|
+ ambiguous = 1;
|
|
+ result = NULL;
|
|
+ break;
|
|
+ }
|
|
+ result = t;
|
|
+ } else if (ttype == kTransportAny) {
|
|
+ if (result) {
|
|
+ if (error_out)
|
|
+ *error_out = "more than one device and emulator";
|
|
+ ambiguous = 1;
|
|
+ result = NULL;
|
|
+ break;
|
|
+ }
|
|
+ result = t;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ adb_mutex_unlock(&transport_lock);
|
|
+
|
|
+ if (result) {
|
|
+ /* offline devices are ignored -- they are either being born or dying */
|
|
+ if (result && result->connection_state == CS_OFFLINE) {
|
|
+ if (error_out)
|
|
+ *error_out = "device offline";
|
|
+ result = NULL;
|
|
+ }
|
|
+ /* check for required connection state */
|
|
+ if (result && state != CS_ANY && result->connection_state != state) {
|
|
+ if (error_out)
|
|
+ *error_out = "invalid device state";
|
|
+ result = NULL;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (result) {
|
|
+ /* found one that we can take */
|
|
+ if (error_out)
|
|
+ *error_out = NULL;
|
|
+ } else if (state != CS_ANY && (serial || !ambiguous)) {
|
|
+ adb_sleep_ms(1000);
|
|
+ goto retry;
|
|
+ }
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
+#if ADB_HOST
|
|
+static const char *statename(atransport *t)
|
|
+{
|
|
+ switch(t->connection_state){
|
|
+ case CS_OFFLINE: return "offline";
|
|
+ case CS_BOOTLOADER: return "bootloader";
|
|
+ case CS_DEVICE: return "device";
|
|
+ case CS_HOST: return "host";
|
|
+ case CS_RECOVERY: return "recovery";
|
|
+ case CS_SIDELOAD: return "sideload";
|
|
+ case CS_NOPERM: return "no permissions";
|
|
+ default: return "unknown";
|
|
+ }
|
|
+}
|
|
+
|
|
+static void add_qual(char **buf, size_t *buf_size,
|
|
+ const char *prefix, const char *qual, int sanitize_qual)
|
|
+{
|
|
+ size_t len;
|
|
+ int prefix_len;
|
|
+
|
|
+ if (!buf || !*buf || !buf_size || !*buf_size || !qual || !*qual)
|
|
+ return;
|
|
+
|
|
+ len = snprintf(*buf, *buf_size, "%s%n%s", prefix, &prefix_len, qual);
|
|
+
|
|
+ if (sanitize_qual) {
|
|
+ char *cp;
|
|
+ for (cp = *buf + prefix_len; cp < *buf + len; cp++) {
|
|
+ if (qual_char_is_invalid(*cp))
|
|
+ *cp = '_';
|
|
+ }
|
|
+ }
|
|
+
|
|
+ *buf_size -= len;
|
|
+ *buf += len;
|
|
+}
|
|
+
|
|
+static size_t format_transport(atransport *t, char *buf, size_t bufsize,
|
|
+ int long_listing)
|
|
+{
|
|
+ const char* serial = t->serial;
|
|
+ if (!serial || !serial[0])
|
|
+ serial = "????????????";
|
|
+
|
|
+ if (!long_listing) {
|
|
+ return snprintf(buf, bufsize, "%s\t%s\n", serial, statename(t));
|
|
+ } else {
|
|
+ size_t len, remaining = bufsize;
|
|
+
|
|
+ len = snprintf(buf, remaining, "%-22s %s", serial, statename(t));
|
|
+ remaining -= len;
|
|
+ buf += len;
|
|
+
|
|
+ add_qual(&buf, &remaining, " ", t->devpath, 0);
|
|
+ add_qual(&buf, &remaining, " product:", t->product, 0);
|
|
+ add_qual(&buf, &remaining, " model:", t->model, 1);
|
|
+ add_qual(&buf, &remaining, " device:", t->device, 0);
|
|
+
|
|
+ len = snprintf(buf, remaining, "\n");
|
|
+ remaining -= len;
|
|
+
|
|
+ return bufsize - remaining;
|
|
+ }
|
|
+}
|
|
+
|
|
+int list_transports(char *buf, size_t bufsize, int long_listing)
|
|
+{
|
|
+ char* p = buf;
|
|
+ char* end = buf + bufsize;
|
|
+ int len;
|
|
+ atransport *t;
|
|
+
|
|
+ /* XXX OVERRUN PROBLEMS XXX */
|
|
+ adb_mutex_lock(&transport_lock);
|
|
+ for(t = transport_list.next; t != &transport_list; t = t->next) {
|
|
+ len = format_transport(t, p, end - p, long_listing);
|
|
+ if (p + len >= end) {
|
|
+ /* discard last line if buffer is too short */
|
|
+ break;
|
|
+ }
|
|
+ p += len;
|
|
+ }
|
|
+ p[0] = 0;
|
|
+ adb_mutex_unlock(&transport_lock);
|
|
+ return p - buf;
|
|
+}
|
|
+
|
|
+
|
|
+/* hack for osx */
|
|
+void close_usb_devices()
|
|
+{
|
|
+ atransport *t;
|
|
+
|
|
+ adb_mutex_lock(&transport_lock);
|
|
+ for(t = transport_list.next; t != &transport_list; t = t->next) {
|
|
+ if ( !t->kicked ) {
|
|
+ t->kicked = 1;
|
|
+ t->kick(t);
|
|
+ }
|
|
+ }
|
|
+ adb_mutex_unlock(&transport_lock);
|
|
+}
|
|
+#endif // ADB_HOST
|
|
+
|
|
+void register_socket_transport(int s, const char *serial, int port, int local)
|
|
+{
|
|
+ atransport *t = calloc(1, sizeof(atransport));
|
|
+ char buff[32];
|
|
+
|
|
+ if (!serial) {
|
|
+ snprintf(buff, sizeof buff, "T-%p", t);
|
|
+ serial = buff;
|
|
+ }
|
|
+ D("transport: %s init'ing for socket %d, on port %d\n", serial, s, port);
|
|
+ if ( init_socket_transport(t, s, port, local) < 0 ) {
|
|
+ adb_close(s);
|
|
+ free(t);
|
|
+ return;
|
|
+ }
|
|
+ if(serial) {
|
|
+ t->serial = strdup(serial);
|
|
+ }
|
|
+ register_transport(t);
|
|
+}
|
|
+
|
|
+#if ADB_HOST
|
|
+atransport *find_transport(const char *serial)
|
|
+{
|
|
+ atransport *t;
|
|
+
|
|
+ adb_mutex_lock(&transport_lock);
|
|
+ for(t = transport_list.next; t != &transport_list; t = t->next) {
|
|
+ if (t->serial && !strcmp(serial, t->serial)) {
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ adb_mutex_unlock(&transport_lock);
|
|
+
|
|
+ if (t != &transport_list)
|
|
+ return t;
|
|
+ else
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void unregister_transport(atransport *t)
|
|
+{
|
|
+ adb_mutex_lock(&transport_lock);
|
|
+ t->next->prev = t->prev;
|
|
+ t->prev->next = t->next;
|
|
+ adb_mutex_unlock(&transport_lock);
|
|
+
|
|
+ kick_transport(t);
|
|
+ transport_unref(t);
|
|
+}
|
|
+
|
|
+// unregisters all non-emulator TCP transports
|
|
+void unregister_all_tcp_transports()
|
|
+{
|
|
+ atransport *t, *next;
|
|
+ adb_mutex_lock(&transport_lock);
|
|
+ for (t = transport_list.next; t != &transport_list; t = next) {
|
|
+ next = t->next;
|
|
+ if (t->type == kTransportLocal && t->adb_port == 0) {
|
|
+ t->next->prev = t->prev;
|
|
+ t->prev->next = next;
|
|
+ // we cannot call kick_transport when holding transport_lock
|
|
+ if (!t->kicked)
|
|
+ {
|
|
+ t->kicked = 1;
|
|
+ t->kick(t);
|
|
+ }
|
|
+ transport_unref_locked(t);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ adb_mutex_unlock(&transport_lock);
|
|
+}
|
|
+
|
|
+#endif
|
|
+
|
|
+void register_usb_transport(usb_handle *usb, const char *serial, const char *devpath, unsigned writeable)
|
|
+{
|
|
+ atransport *t = calloc(1, sizeof(atransport));
|
|
+ D("transport: %p init'ing for usb_handle %p (sn='%s')\n", t, usb,
|
|
+ serial ? serial : "");
|
|
+ init_usb_transport(t, usb, (writeable ? CS_OFFLINE : CS_NOPERM));
|
|
+ if(serial) {
|
|
+ t->serial = strdup(serial);
|
|
+ }
|
|
+ if(devpath) {
|
|
+ t->devpath = strdup(devpath);
|
|
+ }
|
|
+ register_transport(t);
|
|
+}
|
|
+
|
|
+/* this should only be used for transports with connection_state == CS_NOPERM */
|
|
+void unregister_usb_transport(usb_handle *usb)
|
|
+{
|
|
+ atransport *t;
|
|
+ adb_mutex_lock(&transport_lock);
|
|
+ for(t = transport_list.next; t != &transport_list; t = t->next) {
|
|
+ if (t->usb == usb && t->connection_state == CS_NOPERM) {
|
|
+ t->next->prev = t->prev;
|
|
+ t->prev->next = t->next;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ adb_mutex_unlock(&transport_lock);
|
|
+}
|
|
+
|
|
+#undef TRACE_TAG
|
|
+#define TRACE_TAG TRACE_RWX
|
|
+
|
|
+int readx(int fd, void *ptr, size_t len)
|
|
+{
|
|
+ char *p = ptr;
|
|
+ int r;
|
|
+#if ADB_TRACE
|
|
+ int len0 = len;
|
|
+#endif
|
|
+ D("readx: fd=%d wanted=%d\n", fd, (int)len);
|
|
+ while(len > 0) {
|
|
+ r = adb_read(fd, p, len);
|
|
+ if(r > 0) {
|
|
+ len -= r;
|
|
+ p += r;
|
|
+ } else {
|
|
+ if (r < 0) {
|
|
+ D("readx: fd=%d error %d: %s\n", fd, errno, strerror(errno));
|
|
+ if (errno == EINTR)
|
|
+ continue;
|
|
+ } else {
|
|
+ D("readx: fd=%d disconnected\n", fd);
|
|
+ }
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+#if ADB_TRACE
|
|
+ D("readx: fd=%d wanted=%d got=%d\n", fd, len0, len0 - len);
|
|
+ dump_hex( ptr, len0 );
|
|
+#endif
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int writex(int fd, const void *ptr, size_t len)
|
|
+{
|
|
+ char *p = (char*) ptr;
|
|
+ int r;
|
|
+
|
|
+#if ADB_TRACE
|
|
+ D("writex: fd=%d len=%d: ", fd, (int)len);
|
|
+ dump_hex( ptr, len );
|
|
+#endif
|
|
+ while(len > 0) {
|
|
+ r = adb_write(fd, p, len);
|
|
+ if(r > 0) {
|
|
+ len -= r;
|
|
+ p += r;
|
|
+ } else {
|
|
+ if (r < 0) {
|
|
+ D("writex: fd=%d error %d: %s\n", fd, errno, strerror(errno));
|
|
+ if (errno == EINTR)
|
|
+ continue;
|
|
+ } else {
|
|
+ D("writex: fd=%d disconnected\n", fd);
|
|
+ }
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int check_header(apacket *p)
|
|
+{
|
|
+ if(p->msg.magic != (p->msg.command ^ 0xffffffff)) {
|
|
+ D("check_header(): invalid magic\n");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if(p->msg.data_length > MAX_PAYLOAD) {
|
|
+ D("check_header(): %d > MAX_PAYLOAD\n", p->msg.data_length);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int check_data(apacket *p)
|
|
+{
|
|
+ unsigned count, sum;
|
|
+ unsigned char *x;
|
|
+
|
|
+ count = p->msg.data_length;
|
|
+ x = p->data;
|
|
+ sum = 0;
|
|
+ while(count-- > 0) {
|
|
+ sum += *x++;
|
|
+ }
|
|
+
|
|
+ if(sum != p->msg.data_check) {
|
|
+ return -1;
|
|
+ } else {
|
|
+ return 0;
|
|
+ }
|
|
+}
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/transport.h
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/transport.h 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,26 @@
|
|
+/*
|
|
+ * Copyright (C) 2011 The Android Open Source Project
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
+ * you may not use this file except in compliance with the License.
|
|
+ * You may obtain a copy of the License at
|
|
+ *
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
+ *
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+ * See the License for the specific language governing permissions and
|
|
+ * limitations under the License.
|
|
+ */
|
|
+
|
|
+#ifndef __TRANSPORT_H
|
|
+#define __TRANSPORT_H
|
|
+
|
|
+/* convenience wrappers around read/write that will retry on
|
|
+** EINTR and/or short read/write. Returns 0 on success, -1
|
|
+** on error or EOF.
|
|
+*/
|
|
+int readx(int fd, void *ptr, size_t len);
|
|
+int writex(int fd, const void *ptr, size_t len);
|
|
+#endif /* __TRANSPORT_H */
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/transport_local.c
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/transport_local.c 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,441 @@
|
|
+/*
|
|
+ * Copyright (C) 2007 The Android Open Source Project
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
+ * you may not use this file except in compliance with the License.
|
|
+ * You may obtain a copy of the License at
|
|
+ *
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
+ *
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+ * See the License for the specific language governing permissions and
|
|
+ * limitations under the License.
|
|
+ */
|
|
+
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+#include <string.h>
|
|
+#include <errno.h>
|
|
+
|
|
+#include "sysdeps.h"
|
|
+#include <sys/types.h>
|
|
+
|
|
+#define TRACE_TAG TRACE_TRANSPORT
|
|
+#include "adb.h"
|
|
+
|
|
+#ifdef HAVE_BIG_ENDIAN
|
|
+#define H4(x) (((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24)
|
|
+static inline void fix_endians(apacket *p)
|
|
+{
|
|
+ p->msg.command = H4(p->msg.command);
|
|
+ p->msg.arg0 = H4(p->msg.arg0);
|
|
+ p->msg.arg1 = H4(p->msg.arg1);
|
|
+ p->msg.data_length = H4(p->msg.data_length);
|
|
+ p->msg.data_check = H4(p->msg.data_check);
|
|
+ p->msg.magic = H4(p->msg.magic);
|
|
+}
|
|
+#else
|
|
+#define fix_endians(p) do {} while (0)
|
|
+#endif
|
|
+
|
|
+#if ADB_HOST
|
|
+/* we keep a list of opened transports. The atransport struct knows to which
|
|
+ * local transport it is connected. The list is used to detect when we're
|
|
+ * trying to connect twice to a given local transport.
|
|
+ */
|
|
+#define ADB_LOCAL_TRANSPORT_MAX 16
|
|
+
|
|
+ADB_MUTEX_DEFINE( local_transports_lock );
|
|
+
|
|
+static atransport* local_transports[ ADB_LOCAL_TRANSPORT_MAX ];
|
|
+#endif /* ADB_HOST */
|
|
+
|
|
+static int remote_read(apacket *p, atransport *t)
|
|
+{
|
|
+ if(readx(t->sfd, &p->msg, sizeof(amessage))){
|
|
+ D("remote local: read terminated (message)\n");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ fix_endians(p);
|
|
+
|
|
+#if 0 && defined HAVE_BIG_ENDIAN
|
|
+ D("read remote packet: %04x arg0=%0x arg1=%0x data_length=%0x data_check=%0x magic=%0x\n",
|
|
+ p->msg.command, p->msg.arg0, p->msg.arg1, p->msg.data_length, p->msg.data_check, p->msg.magic);
|
|
+#endif
|
|
+ if(check_header(p)) {
|
|
+ D("bad header: terminated (data)\n");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if(readx(t->sfd, p->data, p->msg.data_length)){
|
|
+ D("remote local: terminated (data)\n");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if(check_data(p)) {
|
|
+ D("bad data: terminated (data)\n");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int remote_write(apacket *p, atransport *t)
|
|
+{
|
|
+ int length = p->msg.data_length;
|
|
+
|
|
+ fix_endians(p);
|
|
+
|
|
+#if 0 && defined HAVE_BIG_ENDIAN
|
|
+ D("write remote packet: %04x arg0=%0x arg1=%0x data_length=%0x data_check=%0x magic=%0x\n",
|
|
+ p->msg.command, p->msg.arg0, p->msg.arg1, p->msg.data_length, p->msg.data_check, p->msg.magic);
|
|
+#endif
|
|
+ if(writex(t->sfd, &p->msg, sizeof(amessage) + length)) {
|
|
+ D("remote local: write terminated\n");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
+int local_connect(int port) {
|
|
+ return local_connect_arbitrary_ports(port-1, port);
|
|
+}
|
|
+
|
|
+int local_connect_arbitrary_ports(int console_port, int adb_port)
|
|
+{
|
|
+ char buf[64];
|
|
+ int fd = -1;
|
|
+
|
|
+#if ADB_HOST
|
|
+ const char *host = getenv("ADBHOST");
|
|
+ if (host) {
|
|
+ fd = socket_network_client(host, adb_port, SOCK_STREAM);
|
|
+ }
|
|
+#endif
|
|
+ if (fd < 0) {
|
|
+ fd = socket_loopback_client(adb_port, SOCK_STREAM);
|
|
+ }
|
|
+
|
|
+ if (fd >= 0) {
|
|
+ D("client: connected on remote on fd %d\n", fd);
|
|
+ close_on_exec(fd);
|
|
+ disable_tcp_nagle(fd);
|
|
+ snprintf(buf, sizeof buf, "%s%d", LOCAL_CLIENT_PREFIX, console_port);
|
|
+ register_socket_transport(fd, buf, adb_port, 1);
|
|
+ return 0;
|
|
+ }
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+
|
|
+static void *client_socket_thread(void *x)
|
|
+{
|
|
+#if ADB_HOST
|
|
+ int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
|
|
+ int count = ADB_LOCAL_TRANSPORT_MAX;
|
|
+
|
|
+ D("transport: client_socket_thread() starting\n");
|
|
+
|
|
+ /* try to connect to any number of running emulator instances */
|
|
+ /* this is only done when ADB starts up. later, each new emulator */
|
|
+ /* will send a message to ADB to indicate that is is starting up */
|
|
+ for ( ; count > 0; count--, port += 2 ) {
|
|
+ (void) local_connect(port);
|
|
+ }
|
|
+#endif
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void *server_socket_thread(void * arg)
|
|
+{
|
|
+ int serverfd, fd;
|
|
+ struct sockaddr addr;
|
|
+ socklen_t alen;
|
|
+ int port = (int)arg;
|
|
+
|
|
+ D("transport: server_socket_thread() starting\n");
|
|
+ serverfd = -1;
|
|
+ for(;;) {
|
|
+ if(serverfd == -1) {
|
|
+ serverfd = socket_inaddr_any_server(port, SOCK_STREAM);
|
|
+ if(serverfd < 0) {
|
|
+ D("server: cannot bind socket yet\n");
|
|
+ adb_sleep_ms(1000);
|
|
+ continue;
|
|
+ }
|
|
+ close_on_exec(serverfd);
|
|
+ }
|
|
+
|
|
+ alen = sizeof(addr);
|
|
+ D("server: trying to get new connection from %d\n", port);
|
|
+ fd = adb_socket_accept(serverfd, &addr, &alen);
|
|
+ if(fd >= 0) {
|
|
+ D("server: new connection on fd %d\n", fd);
|
|
+ close_on_exec(fd);
|
|
+ disable_tcp_nagle(fd);
|
|
+ register_socket_transport(fd, "host", port, 1);
|
|
+ }
|
|
+ }
|
|
+ D("transport: server_socket_thread() exiting\n");
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* This is relevant only for ADB daemon running inside the emulator. */
|
|
+#if !ADB_HOST
|
|
+/*
|
|
+ * Redefine open and write for qemu_pipe.h that contains inlined references
|
|
+ * to those routines. We will redifine them back after qemu_pipe.h inclusion.
|
|
+ */
|
|
+#undef open
|
|
+#undef write
|
|
+#define open adb_open
|
|
+#define write adb_write
|
|
+#include "qemu_pipe.h"
|
|
+#undef open
|
|
+#undef write
|
|
+#define open ___xxx_open
|
|
+#define write ___xxx_write
|
|
+
|
|
+/* A worker thread that monitors host connections, and registers a transport for
|
|
+ * every new host connection. This thread replaces server_socket_thread on
|
|
+ * condition that adbd daemon runs inside the emulator, and emulator uses QEMUD
|
|
+ * pipe to communicate with adbd daemon inside the guest. This is done in order
|
|
+ * to provide more robust communication channel between ADB host and guest. The
|
|
+ * main issue with server_socket_thread approach is that it runs on top of TCP,
|
|
+ * and thus is sensitive to network disruptions. For instance, the
|
|
+ * ConnectionManager may decide to reset all network connections, in which case
|
|
+ * the connection between ADB host and guest will be lost. To make ADB traffic
|
|
+ * independent from the network, we use here 'adb' QEMUD service to transfer data
|
|
+ * between the host, and the guest. See external/qemu/android/adb-*.* that
|
|
+ * implements the emulator's side of the protocol. Another advantage of using
|
|
+ * QEMUD approach is that ADB will be up much sooner, since it doesn't depend
|
|
+ * anymore on network being set up.
|
|
+ * The guest side of the protocol contains the following phases:
|
|
+ * - Connect with adb QEMUD service. In this phase a handle to 'adb' QEMUD service
|
|
+ * is opened, and it becomes clear whether or not emulator supports that
|
|
+ * protocol.
|
|
+ * - Wait for the ADB host to create connection with the guest. This is done by
|
|
+ * sending an 'accept' request to the adb QEMUD service, and waiting on
|
|
+ * response.
|
|
+ * - When new ADB host connection is accepted, the connection with adb QEMUD
|
|
+ * service is registered as the transport, and a 'start' request is sent to the
|
|
+ * adb QEMUD service, indicating that the guest is ready to receive messages.
|
|
+ * Note that the guest will ignore messages sent down from the emulator before
|
|
+ * the transport registration is completed. That's why we need to send the
|
|
+ * 'start' request after the transport is registered.
|
|
+ */
|
|
+static void *qemu_socket_thread(void * arg)
|
|
+{
|
|
+/* 'accept' request to the adb QEMUD service. */
|
|
+static const char _accept_req[] = "accept";
|
|
+/* 'start' request to the adb QEMUD service. */
|
|
+static const char _start_req[] = "start";
|
|
+/* 'ok' reply from the adb QEMUD service. */
|
|
+static const char _ok_resp[] = "ok";
|
|
+
|
|
+ const int port = (int)arg;
|
|
+ int res, fd;
|
|
+ char tmp[256];
|
|
+ char con_name[32];
|
|
+
|
|
+ D("transport: qemu_socket_thread() starting\n");
|
|
+
|
|
+ /* adb QEMUD service connection request. */
|
|
+ snprintf(con_name, sizeof(con_name), "qemud:adb:%d", port);
|
|
+
|
|
+ /* Connect to the adb QEMUD service. */
|
|
+ fd = qemu_pipe_open(con_name);
|
|
+ if (fd < 0) {
|
|
+ /* This could be an older version of the emulator, that doesn't
|
|
+ * implement adb QEMUD service. Fall back to the old TCP way. */
|
|
+ adb_thread_t thr;
|
|
+ D("adb service is not available. Falling back to TCP socket.\n");
|
|
+ adb_thread_create(&thr, server_socket_thread, arg);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ for(;;) {
|
|
+ /*
|
|
+ * Wait till the host creates a new connection.
|
|
+ */
|
|
+
|
|
+ /* Send the 'accept' request. */
|
|
+ res = adb_write(fd, _accept_req, strlen(_accept_req));
|
|
+ if ((size_t)res == strlen(_accept_req)) {
|
|
+ /* Wait for the response. In the response we expect 'ok' on success,
|
|
+ * or 'ko' on failure. */
|
|
+ res = adb_read(fd, tmp, sizeof(tmp));
|
|
+ if (res != 2 || memcmp(tmp, _ok_resp, 2)) {
|
|
+ D("Accepting ADB host connection has failed.\n");
|
|
+ adb_close(fd);
|
|
+ } else {
|
|
+ /* Host is connected. Register the transport, and start the
|
|
+ * exchange. */
|
|
+ register_socket_transport(fd, "host", port, 1);
|
|
+ adb_write(fd, _start_req, strlen(_start_req));
|
|
+ }
|
|
+
|
|
+ /* Prepare for accepting of the next ADB host connection. */
|
|
+ fd = qemu_pipe_open(con_name);
|
|
+ if (fd < 0) {
|
|
+ D("adb service become unavailable.\n");
|
|
+ return 0;
|
|
+ }
|
|
+ } else {
|
|
+ D("Unable to send the '%s' request to ADB service.\n", _accept_req);
|
|
+ return 0;
|
|
+ }
|
|
+ }
|
|
+ D("transport: qemu_socket_thread() exiting\n");
|
|
+ return 0;
|
|
+}
|
|
+#endif // !ADB_HOST
|
|
+
|
|
+void local_init(int port)
|
|
+{
|
|
+ adb_thread_t thr;
|
|
+ void* (*func)(void *);
|
|
+
|
|
+ if(HOST) {
|
|
+ func = client_socket_thread;
|
|
+ } else {
|
|
+#if ADB_HOST
|
|
+ func = server_socket_thread;
|
|
+#else
|
|
+ /* For the adbd daemon in the system image we need to distinguish
|
|
+ * between the device, and the emulator. */
|
|
+ char is_qemu[PROPERTY_VALUE_MAX];
|
|
+ //property_get("ro.kernel.qemu", is_qemu, "");
|
|
+ //if (!strcmp(is_qemu, "1")) {
|
|
+ /* Running inside the emulator: use QEMUD pipe as the transport. */
|
|
+ // func = qemu_socket_thread;
|
|
+ //} else {
|
|
+ /* Running inside the device: use TCP socket as the transport. */
|
|
+ func = server_socket_thread;
|
|
+ //}
|
|
+#endif // !ADB_HOST
|
|
+ }
|
|
+
|
|
+ D("transport: local %s init\n", HOST ? "client" : "server");
|
|
+
|
|
+ if(adb_thread_create(&thr, func, (void *)port)) {
|
|
+ fatal_errno("cannot create local socket %s thread",
|
|
+ HOST ? "client" : "server");
|
|
+ }
|
|
+}
|
|
+
|
|
+static void remote_kick(atransport *t)
|
|
+{
|
|
+ int fd = t->sfd;
|
|
+ t->sfd = -1;
|
|
+ adb_shutdown(fd);
|
|
+ adb_close(fd);
|
|
+
|
|
+#if ADB_HOST
|
|
+ if(HOST) {
|
|
+ int nn;
|
|
+ adb_mutex_lock( &local_transports_lock );
|
|
+ for (nn = 0; nn < ADB_LOCAL_TRANSPORT_MAX; nn++) {
|
|
+ if (local_transports[nn] == t) {
|
|
+ local_transports[nn] = NULL;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ adb_mutex_unlock( &local_transports_lock );
|
|
+ }
|
|
+#endif
|
|
+}
|
|
+
|
|
+static void remote_close(atransport *t)
|
|
+{
|
|
+ adb_close(t->fd);
|
|
+}
|
|
+
|
|
+
|
|
+#if ADB_HOST
|
|
+/* Only call this function if you already hold local_transports_lock. */
|
|
+atransport* find_emulator_transport_by_adb_port_locked(int adb_port)
|
|
+{
|
|
+ int i;
|
|
+ for (i = 0; i < ADB_LOCAL_TRANSPORT_MAX; i++) {
|
|
+ if (local_transports[i] && local_transports[i]->adb_port == adb_port) {
|
|
+ return local_transports[i];
|
|
+ }
|
|
+ }
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+atransport* find_emulator_transport_by_adb_port(int adb_port)
|
|
+{
|
|
+ adb_mutex_lock( &local_transports_lock );
|
|
+ atransport* result = find_emulator_transport_by_adb_port_locked(adb_port);
|
|
+ adb_mutex_unlock( &local_transports_lock );
|
|
+ return result;
|
|
+}
|
|
+
|
|
+/* Only call this function if you already hold local_transports_lock. */
|
|
+int get_available_local_transport_index_locked()
|
|
+{
|
|
+ int i;
|
|
+ for (i = 0; i < ADB_LOCAL_TRANSPORT_MAX; i++) {
|
|
+ if (local_transports[i] == NULL) {
|
|
+ return i;
|
|
+ }
|
|
+ }
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+int get_available_local_transport_index()
|
|
+{
|
|
+ adb_mutex_lock( &local_transports_lock );
|
|
+ int result = get_available_local_transport_index_locked();
|
|
+ adb_mutex_unlock( &local_transports_lock );
|
|
+ return result;
|
|
+}
|
|
+#endif
|
|
+
|
|
+int init_socket_transport(atransport *t, int s, int adb_port, int local)
|
|
+{
|
|
+ int fail = 0;
|
|
+
|
|
+ t->kick = remote_kick;
|
|
+ t->close = remote_close;
|
|
+ t->read_from_remote = remote_read;
|
|
+ t->write_to_remote = remote_write;
|
|
+ t->sfd = s;
|
|
+ t->sync_token = 1;
|
|
+ t->connection_state = CS_OFFLINE;
|
|
+ t->type = kTransportLocal;
|
|
+ t->adb_port = 0;
|
|
+
|
|
+#if ADB_HOST
|
|
+ if (HOST && local) {
|
|
+ adb_mutex_lock( &local_transports_lock );
|
|
+ {
|
|
+ t->adb_port = adb_port;
|
|
+ atransport* existing_transport =
|
|
+ find_emulator_transport_by_adb_port_locked(adb_port);
|
|
+ int index = get_available_local_transport_index_locked();
|
|
+ if (existing_transport != NULL) {
|
|
+ D("local transport for port %d already registered (%p)?\n",
|
|
+ adb_port, existing_transport);
|
|
+ fail = -1;
|
|
+ } else if (index < 0) {
|
|
+ // Too many emulators.
|
|
+ D("cannot register more emulators. Maximum is %d\n",
|
|
+ ADB_LOCAL_TRANSPORT_MAX);
|
|
+ fail = -1;
|
|
+ } else {
|
|
+ local_transports[index] = t;
|
|
+ }
|
|
+ }
|
|
+ adb_mutex_unlock( &local_transports_lock );
|
|
+ }
|
|
+#endif
|
|
+ return fail;
|
|
+}
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/transport_usb.c
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/transport_usb.c 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,148 @@
|
|
+/*
|
|
+ * Copyright (C) 2007 The Android Open Source Project
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
+ * you may not use this file except in compliance with the License.
|
|
+ * You may obtain a copy of the License at
|
|
+ *
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
+ *
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+ * See the License for the specific language governing permissions and
|
|
+ * limitations under the License.
|
|
+ */
|
|
+
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+#include <string.h>
|
|
+
|
|
+#include <sysdeps.h>
|
|
+
|
|
+#define TRACE_TAG TRACE_TRANSPORT
|
|
+#include "adb.h"
|
|
+
|
|
+#if ADB_HOST
|
|
+#include "usb_vendors.h"
|
|
+#endif
|
|
+
|
|
+#ifdef HAVE_BIG_ENDIAN
|
|
+#define H4(x) (((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24)
|
|
+static inline void fix_endians(apacket *p)
|
|
+{
|
|
+ p->msg.command = H4(p->msg.command);
|
|
+ p->msg.arg0 = H4(p->msg.arg0);
|
|
+ p->msg.arg1 = H4(p->msg.arg1);
|
|
+ p->msg.data_length = H4(p->msg.data_length);
|
|
+ p->msg.data_check = H4(p->msg.data_check);
|
|
+ p->msg.magic = H4(p->msg.magic);
|
|
+}
|
|
+unsigned host_to_le32(unsigned n)
|
|
+{
|
|
+ return H4(n);
|
|
+}
|
|
+#else
|
|
+#define fix_endians(p) do {} while (0)
|
|
+unsigned host_to_le32(unsigned n)
|
|
+{
|
|
+ return n;
|
|
+}
|
|
+#endif
|
|
+
|
|
+static int remote_read(apacket *p, atransport *t)
|
|
+{
|
|
+ if(usb_read(t->usb, &p->msg, sizeof(amessage))){
|
|
+ D("remote usb: read terminated (message)\n");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ fix_endians(p);
|
|
+
|
|
+ if(check_header(p)) {
|
|
+ D("remote usb: check_header failed\n");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if(p->msg.data_length) {
|
|
+ if(usb_read(t->usb, p->data, p->msg.data_length)){
|
|
+ D("remote usb: terminated (data)\n");
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if(check_data(p)) {
|
|
+ D("remote usb: check_data failed\n");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int remote_write(apacket *p, atransport *t)
|
|
+{
|
|
+ unsigned size = p->msg.data_length;
|
|
+
|
|
+ fix_endians(p);
|
|
+
|
|
+ if(usb_write(t->usb, &p->msg, sizeof(amessage))) {
|
|
+ D("remote usb: 1 - write terminated\n");
|
|
+ return -1;
|
|
+ }
|
|
+ if(p->msg.data_length == 0) return 0;
|
|
+ if(usb_write(t->usb, &p->data, size)) {
|
|
+ D("remote usb: 2 - write terminated\n");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void remote_close(atransport *t)
|
|
+{
|
|
+ usb_close(t->usb);
|
|
+ t->usb = 0;
|
|
+}
|
|
+
|
|
+static void remote_kick(atransport *t)
|
|
+{
|
|
+ usb_kick(t->usb);
|
|
+}
|
|
+
|
|
+void init_usb_transport(atransport *t, usb_handle *h, int state)
|
|
+{
|
|
+ D("transport: usb\n");
|
|
+ t->close = remote_close;
|
|
+ t->kick = remote_kick;
|
|
+ t->read_from_remote = remote_read;
|
|
+ t->write_to_remote = remote_write;
|
|
+ t->sync_token = 1;
|
|
+ t->connection_state = state;
|
|
+ t->type = kTransportUsb;
|
|
+ t->usb = h;
|
|
+
|
|
+#if ADB_HOST
|
|
+ HOST = 1;
|
|
+#else
|
|
+ HOST = 0;
|
|
+#endif
|
|
+}
|
|
+
|
|
+#if ADB_HOST
|
|
+int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol)
|
|
+{
|
|
+ unsigned i;
|
|
+ for (i = 0; i < vendorIdCount; i++) {
|
|
+ if (vid == vendorIds[i]) {
|
|
+ if (usb_class == ADB_CLASS && usb_subclass == ADB_SUBCLASS &&
|
|
+ usb_protocol == ADB_PROTOCOL) {
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+#endif
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/usb_libusb.c
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/usb_libusb.c 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,657 @@
|
|
+/*
|
|
+ * Copyright (C) 2009 bsdroid project
|
|
+ * Alexey Tarasov <tarasov@dodologics.com>
|
|
+ *
|
|
+ * Copyright (C) 2007 The Android Open Source Project
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
+ * you may not use this file except in compliance with the License.
|
|
+ * You may obtain a copy of the License at
|
|
+ *
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
+ *
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+ * See the License for the specific language governing permissions and
|
|
+ * limitations under the License.
|
|
+ */
|
|
+
|
|
+#include <sys/endian.h>
|
|
+#include <sys/ioctl.h>
|
|
+#include <sys/types.h>
|
|
+#include <sys/uio.h>
|
|
+
|
|
+#include <err.h>
|
|
+#include <errno.h>
|
|
+#include <poll.h>
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+#include <strings.h>
|
|
+#include <string.h>
|
|
+#include <sysexits.h>
|
|
+#include <unistd.h>
|
|
+#include <libusb.h>
|
|
+#include "sysdeps.h"
|
|
+
|
|
+#define TRACE_TAG TRACE_USB
|
|
+#include "adb.h"
|
|
+
|
|
+static adb_mutex_t usb_lock = ADB_MUTEX_INITIALIZER;
|
|
+static libusb_context *ctx = NULL;
|
|
+
|
|
+struct usb_handle
|
|
+{
|
|
+ usb_handle *prev;
|
|
+ usb_handle *next;
|
|
+
|
|
+ libusb_device *dev;
|
|
+ libusb_device_handle *devh;
|
|
+ int interface;
|
|
+ uint8_t dev_bus;
|
|
+ uint8_t dev_addr;
|
|
+
|
|
+ int zero_mask;
|
|
+ unsigned char end_point_address[2];
|
|
+ char serial[128];
|
|
+
|
|
+ adb_cond_t notify;
|
|
+ adb_mutex_t lock;
|
|
+};
|
|
+
|
|
+static struct usb_handle handle_list = {
|
|
+ .prev = &handle_list,
|
|
+ .next = &handle_list,
|
|
+};
|
|
+
|
|
+void
|
|
+usb_cleanup()
|
|
+{
|
|
+ libusb_exit(ctx);
|
|
+}
|
|
+
|
|
+void
|
|
+report_bulk_libusb_error(int r)
|
|
+{
|
|
+ switch (r) {
|
|
+ case LIBUSB_ERROR_TIMEOUT:
|
|
+ D("Transfer timeout\n");
|
|
+ break;
|
|
+
|
|
+ case LIBUSB_ERROR_PIPE:
|
|
+ D("Control request is not supported\n");
|
|
+ break;
|
|
+
|
|
+ case LIBUSB_ERROR_OVERFLOW:
|
|
+ D("Device offered more data\n");
|
|
+ break;
|
|
+
|
|
+ case LIBUSB_ERROR_NO_DEVICE :
|
|
+ D("Device was disconnected\n");
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ D("Error %d during transfer\n", r);
|
|
+ break;
|
|
+ };
|
|
+}
|
|
+
|
|
+static int
|
|
+usb_bulk_write(usb_handle *uh, const void *data, int len)
|
|
+{
|
|
+ int r = 0;
|
|
+ int transferred = 0;
|
|
+
|
|
+ r = libusb_bulk_transfer(uh->devh, uh->end_point_address[1], (void *)data, len,
|
|
+ &transferred, 0);
|
|
+
|
|
+ if (r != 0) {
|
|
+ D("usb_bulk_write(): ");
|
|
+ report_bulk_libusb_error(r);
|
|
+ return r;
|
|
+ }
|
|
+
|
|
+ return (transferred);
|
|
+}
|
|
+
|
|
+static int
|
|
+usb_bulk_read(usb_handle *uh, void *data, int len)
|
|
+{
|
|
+ int r = 0;
|
|
+ int transferred = 0;
|
|
+
|
|
+ r = libusb_bulk_transfer(uh->devh, uh->end_point_address[0], data, len,
|
|
+ &transferred, 0);
|
|
+
|
|
+ if (r != 0) {
|
|
+ D("usb_bulk_read(): ");
|
|
+ report_bulk_libusb_error(r);
|
|
+ return r;
|
|
+ }
|
|
+
|
|
+ return (transferred);
|
|
+}
|
|
+
|
|
+int
|
|
+usb_write(struct usb_handle *uh, const void *_data, int len)
|
|
+{
|
|
+ unsigned char *data = (unsigned char*) _data;
|
|
+ int n;
|
|
+ int need_zero = 0;
|
|
+
|
|
+ if (uh->zero_mask == 1) {
|
|
+ if (!(len & uh->zero_mask)) {
|
|
+ need_zero = 1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ D("usb_write(): %p:%d -> transport %p\n", _data, len, uh);
|
|
+
|
|
+ while (len > 0) {
|
|
+ int xfer = (len > 4096) ? 4096 : len;
|
|
+
|
|
+ n = usb_bulk_write(uh, data, xfer);
|
|
+
|
|
+ if (n != xfer) {
|
|
+ D("usb_write(): failed for transport %p (%d bytes left)\n", uh, len);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ len -= xfer;
|
|
+ data += xfer;
|
|
+ }
|
|
+
|
|
+ if (need_zero){
|
|
+ n = usb_bulk_write(uh, _data, 0);
|
|
+
|
|
+ if (n < 0) {
|
|
+ D("usb_write(): failed to finish operation for transport %p\n", uh);
|
|
+ }
|
|
+ return n;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int
|
|
+usb_read(struct usb_handle *uh, void *_data, int len)
|
|
+{
|
|
+ unsigned char *data = (unsigned char*) _data;
|
|
+ int n;
|
|
+
|
|
+ D("usb_read(): %p:%d <- transport %p\n", _data, len, uh);
|
|
+
|
|
+ while (len > 0) {
|
|
+ int xfer = (len > 4096) ? 4096 : len;
|
|
+
|
|
+ n = usb_bulk_read(uh, data, xfer);
|
|
+
|
|
+ if (n != xfer) {
|
|
+ if (n > 0) {
|
|
+ data += n;
|
|
+ len -= n;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ D("usb_read(): failed for transport %p (%d bytes left)\n", uh, len);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ len -= xfer;
|
|
+ data += xfer;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+int
|
|
+usb_close(struct usb_handle *h)
|
|
+{
|
|
+ D("usb_close(): closing transport %p\n", h);
|
|
+ adb_mutex_lock(&usb_lock);
|
|
+
|
|
+ h->next->prev = h->prev;
|
|
+ h->prev->next = h->next;
|
|
+ h->prev = NULL;
|
|
+ h->next = NULL;
|
|
+
|
|
+ libusb_release_interface(h->devh, h->interface);
|
|
+ libusb_close(h->devh);
|
|
+ libusb_unref_device(h->dev);
|
|
+
|
|
+ adb_mutex_unlock(&usb_lock);
|
|
+
|
|
+ free(h);
|
|
+
|
|
+ return (0);
|
|
+}
|
|
+
|
|
+void usb_kick(struct usb_handle *h)
|
|
+{
|
|
+ D("usb_cick(): kicking transport %p\n", h);
|
|
+
|
|
+ adb_mutex_lock(&h->lock);
|
|
+ unregister_usb_transport(h);
|
|
+ adb_mutex_unlock(&h->lock);
|
|
+
|
|
+ h->next->prev = h->prev;
|
|
+ h->prev->next = h->next;
|
|
+ h->prev = NULL;
|
|
+ h->next = NULL;
|
|
+
|
|
+ libusb_release_interface(h->devh, h->interface);
|
|
+ libusb_close(h->devh);
|
|
+ libusb_unref_device(h->dev);
|
|
+ free(h);
|
|
+}
|
|
+
|
|
+int
|
|
+check_usb_interface(libusb_interface *interface,
|
|
+ libusb_device_descriptor *desc,
|
|
+ struct usb_handle *uh)
|
|
+{
|
|
+ int e;
|
|
+
|
|
+ if (interface->num_altsetting == 0) {
|
|
+ D("check_usb_interface(): No interface settings\n");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ libusb_interface_descriptor *idesc = &interface->altsetting[0];
|
|
+
|
|
+ if (idesc->bNumEndpoints != 2) {
|
|
+ D("check_usb_interface(): Interface have not 2 endpoints, ignoring\n");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ for (e = 0; e < idesc->bNumEndpoints; e++) {
|
|
+ libusb_endpoint_descriptor *edesc = &idesc->endpoint[e];
|
|
+
|
|
+ if (edesc->bmAttributes != LIBUSB_TRANSFER_TYPE_BULK) {
|
|
+ D("check_usb_interface(): Endpoint (%u) is not bulk (%u), ignoring\n",
|
|
+ edesc->bmAttributes, LIBUSB_TRANSFER_TYPE_BULK);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if (edesc->bEndpointAddress & LIBUSB_ENDPOINT_IN)
|
|
+ uh->end_point_address[0] = edesc->bEndpointAddress;
|
|
+ else
|
|
+ uh->end_point_address[1] = edesc->bEndpointAddress;
|
|
+
|
|
+ /* aproto 01 needs 0 termination */
|
|
+ if (idesc->bInterfaceProtocol == 0x01) {
|
|
+ uh->zero_mask = edesc->wMaxPacketSize - 1;
|
|
+ D("check_usb_interface(): Forced Android interface protocol v.1\n");
|
|
+ }
|
|
+ }
|
|
+
|
|
+ D("check_usb_interface(): Device: %04x:%04x "
|
|
+ "iclass: %x, isclass: %x, iproto: %x ep: %x/%x-> ",
|
|
+ desc->idVendor, desc->idProduct, idesc->bInterfaceClass,
|
|
+ idesc->bInterfaceSubClass, idesc->bInterfaceProtocol,
|
|
+ uh->end_point_address[0], uh->end_point_address[1]);
|
|
+
|
|
+ if (!is_adb_interface(desc->idVendor, desc->idProduct,
|
|
+ idesc->bInterfaceClass, idesc->bInterfaceSubClass,
|
|
+ idesc->bInterfaceProtocol))
|
|
+ {
|
|
+ D("not matches\n");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ D("matches\n");
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+int
|
|
+check_usb_interfaces(libusb_config_descriptor *config,
|
|
+ libusb_device_descriptor *desc, struct usb_handle *uh)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < config->bNumInterfaces; ++i) {
|
|
+ if (check_usb_interface(&config->interface[i], desc, uh) != -1) {
|
|
+ /* found some interface and saved information about it */
|
|
+ D("check_usb_interfaces(): Interface %d of %04x:%04x "
|
|
+ "matches Android device\n", i, desc->idVendor,
|
|
+ desc->idProduct);
|
|
+
|
|
+ return i;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+int
|
|
+register_device(struct usb_handle *uh, const char *serial)
|
|
+{
|
|
+ D("register_device(): Registering %p [%s] as USB transport\n",
|
|
+ uh, serial);
|
|
+
|
|
+ struct usb_handle *usb= NULL;
|
|
+
|
|
+ usb = calloc(1, sizeof(struct usb_handle));
|
|
+ memcpy(usb, uh, sizeof(struct usb_handle));
|
|
+ strcpy(usb->serial, uh->serial);
|
|
+
|
|
+ adb_cond_init(&usb->notify, 0);
|
|
+ adb_mutex_init(&usb->lock, 0);
|
|
+
|
|
+ adb_mutex_lock(&usb_lock);
|
|
+
|
|
+ usb->next = &handle_list;
|
|
+ usb->prev = handle_list.prev;
|
|
+ usb->prev->next = usb;
|
|
+ usb->next->prev = usb;
|
|
+
|
|
+ adb_mutex_unlock(&usb_lock);
|
|
+
|
|
+ register_usb_transport(usb, serial, NULL, 1);
|
|
+
|
|
+ return (1);
|
|
+}
|
|
+
|
|
+int
|
|
+already_registered(usb_handle *uh)
|
|
+{
|
|
+ struct usb_handle *usb= NULL;
|
|
+ int exists = 0;
|
|
+
|
|
+ adb_mutex_lock(&usb_lock);
|
|
+
|
|
+ for (usb = handle_list.next; usb != &handle_list; usb = usb->next) {
|
|
+ if ((usb->dev_bus == uh->dev_bus) &&
|
|
+ (usb->dev_addr == uh->dev_addr))
|
|
+ {
|
|
+ exists = 1;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ adb_mutex_unlock(&usb_lock);
|
|
+
|
|
+ return exists;
|
|
+}
|
|
+
|
|
+void
|
|
+check_device(libusb_device *dev)
|
|
+{
|
|
+ struct usb_handle uh;
|
|
+ int i = 0;
|
|
+ int found = -1;
|
|
+ char serial[256] = {0};
|
|
+
|
|
+ libusb_device_descriptor desc;
|
|
+ libusb_config_descriptor *config = NULL;
|
|
+
|
|
+ int r = libusb_get_device_descriptor(dev, &desc);
|
|
+
|
|
+ if (r != LIBUSB_SUCCESS) {
|
|
+ D("check_device(): Failed to get device descriptor\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if ((desc.idVendor == 0) && (desc.idProduct == 0))
|
|
+ return;
|
|
+
|
|
+ D("check_device(): Probing usb device %04x:%04x\n",
|
|
+ desc.idVendor, desc.idProduct);
|
|
+
|
|
+ if (!is_adb_interface (desc.idVendor, desc.idProduct,
|
|
+ ADB_CLASS, ADB_SUBCLASS, ADB_PROTOCOL))
|
|
+ {
|
|
+ D("check_device(): Ignored due unknown vendor id\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ uh.dev_bus = libusb_get_bus_number(dev);
|
|
+ uh.dev_addr = libusb_get_device_address(dev);
|
|
+
|
|
+ if (already_registered(&uh)) {
|
|
+ D("check_device(): Device (bus: %d, address: %d) "
|
|
+ "is already registered\n", uh.dev_bus, uh.dev_addr);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ D("check_device(): Device bus: %d, address: %d\n",
|
|
+ uh.dev_bus, uh.dev_addr);
|
|
+
|
|
+ r = libusb_get_active_config_descriptor(dev, &config);
|
|
+
|
|
+ if (r != 0) {
|
|
+ if (r == LIBUSB_ERROR_NOT_FOUND) {
|
|
+ D("check_device(): Device %4x:%4x is unconfigured\n",
|
|
+ desc.idVendor, desc.idProduct);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ D("check_device(): Failed to get configuration for %4x:%4x\n",
|
|
+ desc.idVendor, desc.idProduct);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (config == NULL) {
|
|
+ D("check_device(): Sanity check failed after "
|
|
+ "getting active config\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (config->interface != NULL) {
|
|
+ found = check_usb_interfaces(config, &desc, &uh);
|
|
+ }
|
|
+
|
|
+ /* not needed anymore */
|
|
+ libusb_free_config_descriptor(config);
|
|
+
|
|
+ r = libusb_open(dev, &uh.devh);
|
|
+ uh.dev = dev;
|
|
+
|
|
+ if (r != 0) {
|
|
+ switch (r) {
|
|
+ case LIBUSB_ERROR_NO_MEM:
|
|
+ D("check_device(): Memory allocation problem\n");
|
|
+ break;
|
|
+
|
|
+ case LIBUSB_ERROR_ACCESS:
|
|
+ D("check_device(): Permissions problem, "
|
|
+ "current user priveleges are messed up?\n");
|
|
+ break;
|
|
+
|
|
+ case LIBUSB_ERROR_NO_DEVICE:
|
|
+ D("check_device(): Device disconected, bad cable?\n");
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ D("check_device(): libusb triggered error %d\n", r);
|
|
+ }
|
|
+ // skip rest
|
|
+ found = -1;
|
|
+ }
|
|
+
|
|
+ if (found >= 0) {
|
|
+ D("check_device(): Device matches Android interface\n");
|
|
+ // read the device's serial number
|
|
+ memset(serial, 0, sizeof(serial));
|
|
+ uh.interface = found;
|
|
+
|
|
+ r = libusb_claim_interface(uh.devh, uh.interface);
|
|
+
|
|
+ if (r < 0) {
|
|
+ D("check_device(): Failed to claim interface %d\n",
|
|
+ uh.interface);
|
|
+
|
|
+ goto fail;
|
|
+ }
|
|
+
|
|
+ if (desc.iSerialNumber) {
|
|
+ // reading serial
|
|
+ uint16_t buffer[128] = {0};
|
|
+ uint16_t languages[128] = {0};
|
|
+ int languageCount = 0;
|
|
+
|
|
+ memset(languages, 0, sizeof(languages));
|
|
+ r = libusb_control_transfer(uh.devh,
|
|
+ LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE,
|
|
+ LIBUSB_REQUEST_GET_DESCRIPTOR, LIBUSB_DT_STRING << 8,
|
|
+ 0, (uint8_t *)languages, sizeof(languages), 0);
|
|
+
|
|
+ if (r <= 0) {
|
|
+ D("check_device(): Failed to get languages count\n");
|
|
+ goto fail;
|
|
+ }
|
|
+
|
|
+ languageCount = (r - 2) / 2;
|
|
+
|
|
+ for (i = 1; i <= languageCount; ++i) {
|
|
+ memset(buffer, 0, sizeof(buffer));
|
|
+
|
|
+ r = libusb_control_transfer(uh.devh,
|
|
+ LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE,
|
|
+ LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_STRING << 8) | desc.iSerialNumber,
|
|
+ languages[i], (uint8_t *)buffer, sizeof(buffer), 0);
|
|
+
|
|
+ if (r > 0) { /* converting serial */
|
|
+ int j = 0;
|
|
+ r /= 2;
|
|
+
|
|
+ for (j = 1; j < r; ++j)
|
|
+ serial[j - 1] = buffer[j];
|
|
+
|
|
+ serial[j - 1] = '\0';
|
|
+ break; /* languagesCount cycle */
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (register_device(&uh, serial) == 0) {
|
|
+ D("check_device(): Failed to register device\n");
|
|
+ goto fail_interface;
|
|
+ }
|
|
+
|
|
+ libusb_ref_device(dev);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return;
|
|
+
|
|
+fail_interface:
|
|
+ libusb_release_interface(uh.devh, uh.interface);
|
|
+
|
|
+fail:
|
|
+ libusb_close(uh.devh);
|
|
+ uh.devh = NULL;
|
|
+}
|
|
+
|
|
+int
|
|
+check_device_connected(struct usb_handle *uh)
|
|
+{
|
|
+ int r = libusb_kernel_driver_active(uh->devh, uh->interface);
|
|
+
|
|
+ if (r == LIBUSB_ERROR_NO_DEVICE)
|
|
+ return 0;
|
|
+
|
|
+ if (r < 0)
|
|
+ return -1;
|
|
+
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+void
|
|
+kick_disconnected()
|
|
+{
|
|
+ struct usb_handle *usb= NULL;
|
|
+
|
|
+ adb_mutex_lock(&usb_lock);
|
|
+
|
|
+ for (usb = handle_list.next; usb != &handle_list; usb = usb->next) {
|
|
+
|
|
+ if (check_device_connected(usb) == 0) {
|
|
+ D("kick_disconnected(): Transport %p is not online anymore\n",
|
|
+ usb);
|
|
+
|
|
+ usb_kick(usb);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ adb_mutex_unlock(&usb_lock);
|
|
+}
|
|
+
|
|
+void
|
|
+scan_usb_devices()
|
|
+{
|
|
+ D("scan_usb_devices(): started\n");
|
|
+
|
|
+ libusb_device **devs= NULL;
|
|
+ libusb_device *dev= NULL;
|
|
+ ssize_t cnt = libusb_get_device_list(ctx, &devs);
|
|
+
|
|
+ if (cnt < 0) {
|
|
+ D("scan_usb_devices(): Failed to get device list (error: %d)\n",
|
|
+ cnt);
|
|
+
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ int i = 0;
|
|
+
|
|
+ while ((dev = devs[i++]) != NULL) {
|
|
+ check_device(dev);
|
|
+ }
|
|
+
|
|
+ libusb_free_device_list(devs, 1);
|
|
+}
|
|
+
|
|
+void *
|
|
+device_poll_thread(void* unused)
|
|
+{
|
|
+ D("device_poll_thread(): Created USB scan thread\n");
|
|
+
|
|
+ for (;;) {
|
|
+ sleep(5);
|
|
+ kick_disconnected();
|
|
+ scan_usb_devices();
|
|
+ }
|
|
+
|
|
+ /* never reaching this point */
|
|
+ return (NULL);
|
|
+}
|
|
+
|
|
+static void
|
|
+sigalrm_handler(int signo)
|
|
+{
|
|
+ /* nothing */
|
|
+}
|
|
+
|
|
+void
|
|
+usb_init()
|
|
+{
|
|
+ D("usb_init(): started\n");
|
|
+ adb_thread_t tid;
|
|
+ struct sigaction actions;
|
|
+
|
|
+ int r = libusb_init(&ctx);
|
|
+
|
|
+ if (r != LIBUSB_SUCCESS) {
|
|
+ err(EX_IOERR, "Failed to init libusb\n");
|
|
+ }
|
|
+
|
|
+ memset(&actions, 0, sizeof(actions));
|
|
+
|
|
+ sigemptyset(&actions.sa_mask);
|
|
+
|
|
+ actions.sa_flags = 0;
|
|
+ actions.sa_handler = sigalrm_handler;
|
|
+
|
|
+ sigaction(SIGALRM, &actions, NULL);
|
|
+
|
|
+ /* initial device scan */
|
|
+ scan_usb_devices();
|
|
+
|
|
+ /* starting USB event polling thread */
|
|
+ if (adb_thread_create(&tid, device_poll_thread, NULL)) {
|
|
+ err(EX_IOERR, "cannot create USB scan thread\n");
|
|
+ }
|
|
+
|
|
+ D("usb_init(): finished\n");
|
|
+}
|
|
+
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/usb_linux.c
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/usb_linux.c 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,715 @@
|
|
+/*
|
|
+ * Copyright (C) 2007 The Android Open Source Project
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
+ * you may not use this file except in compliance with the License.
|
|
+ * You may obtain a copy of the License at
|
|
+ *
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
+ *
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+ * See the License for the specific language governing permissions and
|
|
+ * limitations under the License.
|
|
+ */
|
|
+
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+#include <unistd.h>
|
|
+#include <string.h>
|
|
+
|
|
+#include <sys/ioctl.h>
|
|
+#include <sys/types.h>
|
|
+#include <sys/time.h>
|
|
+#include <dirent.h>
|
|
+#include <fcntl.h>
|
|
+#include <errno.h>
|
|
+#include <ctype.h>
|
|
+
|
|
+#include <linux/usbdevice_fs.h>
|
|
+#include <linux/version.h>
|
|
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20)
|
|
+#include <linux/usb/ch9.h>
|
|
+#else
|
|
+#include <linux/usb_ch9.h>
|
|
+#endif
|
|
+#include <asm/byteorder.h>
|
|
+
|
|
+#include "sysdeps.h"
|
|
+
|
|
+#define TRACE_TAG TRACE_USB
|
|
+#include "adb.h"
|
|
+
|
|
+
|
|
+/* usb scan debugging is waaaay too verbose */
|
|
+#define DBGX(x...)
|
|
+
|
|
+ADB_MUTEX_DEFINE( usb_lock );
|
|
+
|
|
+struct usb_handle
|
|
+{
|
|
+ usb_handle *prev;
|
|
+ usb_handle *next;
|
|
+
|
|
+ char fname[64];
|
|
+ int desc;
|
|
+ unsigned char ep_in;
|
|
+ unsigned char ep_out;
|
|
+
|
|
+ unsigned zero_mask;
|
|
+ unsigned writeable;
|
|
+
|
|
+ struct usbdevfs_urb urb_in;
|
|
+ struct usbdevfs_urb urb_out;
|
|
+
|
|
+ int urb_in_busy;
|
|
+ int urb_out_busy;
|
|
+ int dead;
|
|
+
|
|
+ adb_cond_t notify;
|
|
+ adb_mutex_t lock;
|
|
+
|
|
+ // for garbage collecting disconnected devices
|
|
+ int mark;
|
|
+
|
|
+ // ID of thread currently in REAPURB
|
|
+ pthread_t reaper_thread;
|
|
+};
|
|
+
|
|
+static usb_handle handle_list = {
|
|
+ .prev = &handle_list,
|
|
+ .next = &handle_list,
|
|
+};
|
|
+
|
|
+static int known_device(const char *dev_name)
|
|
+{
|
|
+ usb_handle *usb;
|
|
+
|
|
+ adb_mutex_lock(&usb_lock);
|
|
+ for(usb = handle_list.next; usb != &handle_list; usb = usb->next){
|
|
+ if(!strcmp(usb->fname, dev_name)) {
|
|
+ // set mark flag to indicate this device is still alive
|
|
+ usb->mark = 1;
|
|
+ adb_mutex_unlock(&usb_lock);
|
|
+ return 1;
|
|
+ }
|
|
+ }
|
|
+ adb_mutex_unlock(&usb_lock);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void kick_disconnected_devices()
|
|
+{
|
|
+ usb_handle *usb;
|
|
+
|
|
+ adb_mutex_lock(&usb_lock);
|
|
+ // kick any devices in the device list that were not found in the device scan
|
|
+ for(usb = handle_list.next; usb != &handle_list; usb = usb->next){
|
|
+ if (usb->mark == 0) {
|
|
+ usb_kick(usb);
|
|
+ } else {
|
|
+ usb->mark = 0;
|
|
+ }
|
|
+ }
|
|
+ adb_mutex_unlock(&usb_lock);
|
|
+
|
|
+}
|
|
+
|
|
+static void register_device(const char *dev_name, const char *devpath,
|
|
+ unsigned char ep_in, unsigned char ep_out,
|
|
+ int ifc, int serial_index, unsigned zero_mask);
|
|
+
|
|
+static inline int badname(const char *name)
|
|
+{
|
|
+ while(*name) {
|
|
+ if(!isdigit(*name++)) return 1;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void find_usb_device(const char *base,
|
|
+ void (*register_device_callback)
|
|
+ (const char *, const char *, unsigned char, unsigned char, int, int, unsigned))
|
|
+{
|
|
+ char busname[32], devname[32];
|
|
+ unsigned char local_ep_in, local_ep_out;
|
|
+ DIR *busdir , *devdir ;
|
|
+ struct dirent *de;
|
|
+ int fd ;
|
|
+
|
|
+ busdir = opendir(base);
|
|
+ if(busdir == 0) return;
|
|
+
|
|
+ while((de = readdir(busdir)) != 0) {
|
|
+ if(badname(de->d_name)) continue;
|
|
+
|
|
+ snprintf(busname, sizeof busname, "%s/%s", base, de->d_name);
|
|
+ devdir = opendir(busname);
|
|
+ if(devdir == 0) continue;
|
|
+
|
|
+// DBGX("[ scanning %s ]\n", busname);
|
|
+ while((de = readdir(devdir))) {
|
|
+ unsigned char devdesc[4096];
|
|
+ unsigned char* bufptr = devdesc;
|
|
+ unsigned char* bufend;
|
|
+ struct usb_device_descriptor* device;
|
|
+ struct usb_config_descriptor* config;
|
|
+ struct usb_interface_descriptor* interface;
|
|
+ struct usb_endpoint_descriptor *ep1, *ep2;
|
|
+ unsigned zero_mask = 0;
|
|
+ unsigned vid, pid;
|
|
+ size_t desclength;
|
|
+
|
|
+ if(badname(de->d_name)) continue;
|
|
+ snprintf(devname, sizeof devname, "%s/%s", busname, de->d_name);
|
|
+
|
|
+ if(known_device(devname)) {
|
|
+ DBGX("skipping %s\n", devname);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+// DBGX("[ scanning %s ]\n", devname);
|
|
+ if((fd = unix_open(devname, O_RDONLY)) < 0) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ desclength = adb_read(fd, devdesc, sizeof(devdesc));
|
|
+ bufend = bufptr + desclength;
|
|
+
|
|
+ // should have device and configuration descriptors, and atleast two endpoints
|
|
+ if (desclength < USB_DT_DEVICE_SIZE + USB_DT_CONFIG_SIZE) {
|
|
+ D("desclength %d is too small\n", desclength);
|
|
+ adb_close(fd);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ device = (struct usb_device_descriptor*)bufptr;
|
|
+ bufptr += USB_DT_DEVICE_SIZE;
|
|
+
|
|
+ if((device->bLength != USB_DT_DEVICE_SIZE) || (device->bDescriptorType != USB_DT_DEVICE)) {
|
|
+ adb_close(fd);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ vid = device->idVendor;
|
|
+ pid = device->idProduct;
|
|
+ DBGX("[ %s is V:%04x P:%04x ]\n", devname, vid, pid);
|
|
+
|
|
+ // should have config descriptor next
|
|
+ config = (struct usb_config_descriptor *)bufptr;
|
|
+ bufptr += USB_DT_CONFIG_SIZE;
|
|
+ if (config->bLength != USB_DT_CONFIG_SIZE || config->bDescriptorType != USB_DT_CONFIG) {
|
|
+ D("usb_config_descriptor not found\n");
|
|
+ adb_close(fd);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ // loop through all the descriptors and look for the ADB interface
|
|
+ while (bufptr < bufend) {
|
|
+ unsigned char length = bufptr[0];
|
|
+ unsigned char type = bufptr[1];
|
|
+
|
|
+ if (type == USB_DT_INTERFACE) {
|
|
+ interface = (struct usb_interface_descriptor *)bufptr;
|
|
+ bufptr += length;
|
|
+
|
|
+ if (length != USB_DT_INTERFACE_SIZE) {
|
|
+ D("interface descriptor has wrong size\n");
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ DBGX("bInterfaceClass: %d, bInterfaceSubClass: %d,"
|
|
+ "bInterfaceProtocol: %d, bNumEndpoints: %d\n",
|
|
+ interface->bInterfaceClass, interface->bInterfaceSubClass,
|
|
+ interface->bInterfaceProtocol, interface->bNumEndpoints);
|
|
+
|
|
+ if (interface->bNumEndpoints == 2 &&
|
|
+ is_adb_interface(vid, pid, interface->bInterfaceClass,
|
|
+ interface->bInterfaceSubClass, interface->bInterfaceProtocol)) {
|
|
+
|
|
+ struct stat st;
|
|
+ char pathbuf[128];
|
|
+ char link[256];
|
|
+ char *devpath = NULL;
|
|
+
|
|
+ DBGX("looking for bulk endpoints\n");
|
|
+ // looks like ADB...
|
|
+ ep1 = (struct usb_endpoint_descriptor *)bufptr;
|
|
+ bufptr += USB_DT_ENDPOINT_SIZE;
|
|
+ ep2 = (struct usb_endpoint_descriptor *)bufptr;
|
|
+ bufptr += USB_DT_ENDPOINT_SIZE;
|
|
+
|
|
+ if (bufptr > devdesc + desclength ||
|
|
+ ep1->bLength != USB_DT_ENDPOINT_SIZE ||
|
|
+ ep1->bDescriptorType != USB_DT_ENDPOINT ||
|
|
+ ep2->bLength != USB_DT_ENDPOINT_SIZE ||
|
|
+ ep2->bDescriptorType != USB_DT_ENDPOINT) {
|
|
+ D("endpoints not found\n");
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ // both endpoints should be bulk
|
|
+ if (ep1->bmAttributes != USB_ENDPOINT_XFER_BULK ||
|
|
+ ep2->bmAttributes != USB_ENDPOINT_XFER_BULK) {
|
|
+ D("bulk endpoints not found\n");
|
|
+ continue;
|
|
+ }
|
|
+ /* aproto 01 needs 0 termination */
|
|
+ if(interface->bInterfaceProtocol == 0x01) {
|
|
+ zero_mask = ep1->wMaxPacketSize - 1;
|
|
+ }
|
|
+
|
|
+ // we have a match. now we just need to figure out which is in and which is out.
|
|
+ if (ep1->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
|
|
+ local_ep_in = ep1->bEndpointAddress;
|
|
+ local_ep_out = ep2->bEndpointAddress;
|
|
+ } else {
|
|
+ local_ep_in = ep2->bEndpointAddress;
|
|
+ local_ep_out = ep1->bEndpointAddress;
|
|
+ }
|
|
+
|
|
+ // Determine the device path
|
|
+ if (!fstat(fd, &st) && S_ISCHR(st.st_mode)) {
|
|
+ char *slash;
|
|
+ ssize_t link_len;
|
|
+ snprintf(pathbuf, sizeof(pathbuf), "/sys/dev/char/%d:%d",
|
|
+ major(st.st_rdev), minor(st.st_rdev));
|
|
+ link_len = readlink(pathbuf, link, sizeof(link) - 1);
|
|
+ if (link_len > 0) {
|
|
+ link[link_len] = '\0';
|
|
+ slash = strrchr(link, '/');
|
|
+ if (slash) {
|
|
+ snprintf(pathbuf, sizeof(pathbuf),
|
|
+ "usb:%s", slash + 1);
|
|
+ devpath = pathbuf;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ register_device_callback(devname, devpath,
|
|
+ local_ep_in, local_ep_out,
|
|
+ interface->bInterfaceNumber, device->iSerialNumber, zero_mask);
|
|
+ break;
|
|
+ }
|
|
+ } else {
|
|
+ bufptr += length;
|
|
+ }
|
|
+ } // end of while
|
|
+
|
|
+ adb_close(fd);
|
|
+ } // end of devdir while
|
|
+ closedir(devdir);
|
|
+ } //end of busdir while
|
|
+ closedir(busdir);
|
|
+}
|
|
+
|
|
+void usb_cleanup()
|
|
+{
|
|
+}
|
|
+
|
|
+static int usb_bulk_write(usb_handle *h, const void *data, int len)
|
|
+{
|
|
+ struct usbdevfs_urb *urb = &h->urb_out;
|
|
+ int res;
|
|
+ struct timeval tv;
|
|
+ struct timespec ts;
|
|
+
|
|
+ memset(urb, 0, sizeof(*urb));
|
|
+ urb->type = USBDEVFS_URB_TYPE_BULK;
|
|
+ urb->endpoint = h->ep_out;
|
|
+ urb->status = -1;
|
|
+ urb->buffer = (void*) data;
|
|
+ urb->buffer_length = len;
|
|
+
|
|
+ D("++ write ++\n");
|
|
+
|
|
+ adb_mutex_lock(&h->lock);
|
|
+ if(h->dead) {
|
|
+ res = -1;
|
|
+ goto fail;
|
|
+ }
|
|
+ do {
|
|
+ res = ioctl(h->desc, USBDEVFS_SUBMITURB, urb);
|
|
+ } while((res < 0) && (errno == EINTR));
|
|
+
|
|
+ if(res < 0) {
|
|
+ goto fail;
|
|
+ }
|
|
+
|
|
+ res = -1;
|
|
+ h->urb_out_busy = 1;
|
|
+ for(;;) {
|
|
+ /* time out after five seconds */
|
|
+ gettimeofday(&tv, NULL);
|
|
+ ts.tv_sec = tv.tv_sec + 5;
|
|
+ ts.tv_nsec = tv.tv_usec * 1000L;
|
|
+ res = pthread_cond_timedwait(&h->notify, &h->lock, &ts);
|
|
+ if(res < 0 || h->dead) {
|
|
+ break;
|
|
+ }
|
|
+ if(h->urb_out_busy == 0) {
|
|
+ if(urb->status == 0) {
|
|
+ res = urb->actual_length;
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+fail:
|
|
+ adb_mutex_unlock(&h->lock);
|
|
+ D("-- write --\n");
|
|
+ return res;
|
|
+}
|
|
+
|
|
+static int usb_bulk_read(usb_handle *h, void *data, int len)
|
|
+{
|
|
+ struct usbdevfs_urb *urb = &h->urb_in;
|
|
+ struct usbdevfs_urb *out = NULL;
|
|
+ int res;
|
|
+
|
|
+ memset(urb, 0, sizeof(*urb));
|
|
+ urb->type = USBDEVFS_URB_TYPE_BULK;
|
|
+ urb->endpoint = h->ep_in;
|
|
+ urb->status = -1;
|
|
+ urb->buffer = data;
|
|
+ urb->buffer_length = len;
|
|
+
|
|
+
|
|
+ adb_mutex_lock(&h->lock);
|
|
+ if(h->dead) {
|
|
+ res = -1;
|
|
+ goto fail;
|
|
+ }
|
|
+ do {
|
|
+ res = ioctl(h->desc, USBDEVFS_SUBMITURB, urb);
|
|
+ } while((res < 0) && (errno == EINTR));
|
|
+
|
|
+ if(res < 0) {
|
|
+ goto fail;
|
|
+ }
|
|
+
|
|
+ h->urb_in_busy = 1;
|
|
+ for(;;) {
|
|
+ D("[ reap urb - wait ]\n");
|
|
+ h->reaper_thread = pthread_self();
|
|
+ adb_mutex_unlock(&h->lock);
|
|
+ res = ioctl(h->desc, USBDEVFS_REAPURB, &out);
|
|
+ int saved_errno = errno;
|
|
+ adb_mutex_lock(&h->lock);
|
|
+ h->reaper_thread = 0;
|
|
+ if(h->dead) {
|
|
+ res = -1;
|
|
+ break;
|
|
+ }
|
|
+ if(res < 0) {
|
|
+ if(saved_errno == EINTR) {
|
|
+ continue;
|
|
+ }
|
|
+ D("[ reap urb - error ]\n");
|
|
+ break;
|
|
+ }
|
|
+ D("[ urb @%p status = %d, actual = %d ]\n",
|
|
+ out, out->status, out->actual_length);
|
|
+
|
|
+ if(out == &h->urb_in) {
|
|
+ D("[ reap urb - IN complete ]\n");
|
|
+ h->urb_in_busy = 0;
|
|
+ if(urb->status == 0) {
|
|
+ res = urb->actual_length;
|
|
+ } else {
|
|
+ res = -1;
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ if(out == &h->urb_out) {
|
|
+ D("[ reap urb - OUT compelete ]\n");
|
|
+ h->urb_out_busy = 0;
|
|
+ adb_cond_broadcast(&h->notify);
|
|
+ }
|
|
+ }
|
|
+fail:
|
|
+ adb_mutex_unlock(&h->lock);
|
|
+ return res;
|
|
+}
|
|
+
|
|
+
|
|
+int usb_write(usb_handle *h, const void *_data, int len)
|
|
+{
|
|
+ unsigned char *data = (unsigned char*) _data;
|
|
+ int n;
|
|
+ int need_zero = 0;
|
|
+
|
|
+ if(h->zero_mask) {
|
|
+ /* if we need 0-markers and our transfer
|
|
+ ** is an even multiple of the packet size,
|
|
+ ** we make note of it
|
|
+ */
|
|
+ if(!(len & h->zero_mask)) {
|
|
+ need_zero = 1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ while(len > 0) {
|
|
+ int xfer = (len > 4096) ? 4096 : len;
|
|
+
|
|
+ n = usb_bulk_write(h, data, xfer);
|
|
+ if(n != xfer) {
|
|
+ D("ERROR: n = %d, errno = %d (%s)\n",
|
|
+ n, errno, strerror(errno));
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ len -= xfer;
|
|
+ data += xfer;
|
|
+ }
|
|
+
|
|
+ if(need_zero){
|
|
+ n = usb_bulk_write(h, _data, 0);
|
|
+ return n;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int usb_read(usb_handle *h, void *_data, int len)
|
|
+{
|
|
+ unsigned char *data = (unsigned char*) _data;
|
|
+ int n;
|
|
+
|
|
+ D("++ usb_read ++\n");
|
|
+ while(len > 0) {
|
|
+ int xfer = (len > 4096) ? 4096 : len;
|
|
+
|
|
+ D("[ usb read %d fd = %d], fname=%s\n", xfer, h->desc, h->fname);
|
|
+ n = usb_bulk_read(h, data, xfer);
|
|
+ D("[ usb read %d ] = %d, fname=%s\n", xfer, n, h->fname);
|
|
+ if(n != xfer) {
|
|
+ if((errno == ETIMEDOUT) && (h->desc != -1)) {
|
|
+ D("[ timeout ]\n");
|
|
+ if(n > 0){
|
|
+ data += n;
|
|
+ len -= n;
|
|
+ }
|
|
+ continue;
|
|
+ }
|
|
+ D("ERROR: n = %d, errno = %d (%s)\n",
|
|
+ n, errno, strerror(errno));
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ len -= xfer;
|
|
+ data += xfer;
|
|
+ }
|
|
+
|
|
+ D("-- usb_read --\n");
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void usb_kick(usb_handle *h)
|
|
+{
|
|
+ D("[ kicking %p (fd = %d) ]\n", h, h->desc);
|
|
+ adb_mutex_lock(&h->lock);
|
|
+ if(h->dead == 0) {
|
|
+ h->dead = 1;
|
|
+
|
|
+ if (h->writeable) {
|
|
+ /* HACK ALERT!
|
|
+ ** Sometimes we get stuck in ioctl(USBDEVFS_REAPURB).
|
|
+ ** This is a workaround for that problem.
|
|
+ */
|
|
+ if (h->reaper_thread) {
|
|
+ pthread_kill(h->reaper_thread, SIGALRM);
|
|
+ }
|
|
+
|
|
+ /* cancel any pending transactions
|
|
+ ** these will quietly fail if the txns are not active,
|
|
+ ** but this ensures that a reader blocked on REAPURB
|
|
+ ** will get unblocked
|
|
+ */
|
|
+ ioctl(h->desc, USBDEVFS_DISCARDURB, &h->urb_in);
|
|
+ ioctl(h->desc, USBDEVFS_DISCARDURB, &h->urb_out);
|
|
+ h->urb_in.status = -ENODEV;
|
|
+ h->urb_out.status = -ENODEV;
|
|
+ h->urb_in_busy = 0;
|
|
+ h->urb_out_busy = 0;
|
|
+ adb_cond_broadcast(&h->notify);
|
|
+ } else {
|
|
+ unregister_usb_transport(h);
|
|
+ }
|
|
+ }
|
|
+ adb_mutex_unlock(&h->lock);
|
|
+}
|
|
+
|
|
+int usb_close(usb_handle *h)
|
|
+{
|
|
+ D("[ usb close ... ]\n");
|
|
+ adb_mutex_lock(&usb_lock);
|
|
+ h->next->prev = h->prev;
|
|
+ h->prev->next = h->next;
|
|
+ h->prev = 0;
|
|
+ h->next = 0;
|
|
+
|
|
+ adb_close(h->desc);
|
|
+ D("[ usb closed %p (fd = %d) ]\n", h, h->desc);
|
|
+ adb_mutex_unlock(&usb_lock);
|
|
+
|
|
+ free(h);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void register_device(const char *dev_name, const char *devpath,
|
|
+ unsigned char ep_in, unsigned char ep_out,
|
|
+ int interface, int serial_index, unsigned zero_mask)
|
|
+{
|
|
+ usb_handle* usb = 0;
|
|
+ int n = 0;
|
|
+ char serial[256];
|
|
+
|
|
+ /* Since Linux will not reassign the device ID (and dev_name)
|
|
+ ** as long as the device is open, we can add to the list here
|
|
+ ** once we open it and remove from the list when we're finally
|
|
+ ** closed and everything will work out fine.
|
|
+ **
|
|
+ ** If we have a usb_handle on the list 'o handles with a matching
|
|
+ ** name, we have no further work to do.
|
|
+ */
|
|
+ adb_mutex_lock(&usb_lock);
|
|
+ for(usb = handle_list.next; usb != &handle_list; usb = usb->next){
|
|
+ if(!strcmp(usb->fname, dev_name)) {
|
|
+ adb_mutex_unlock(&usb_lock);
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+ adb_mutex_unlock(&usb_lock);
|
|
+
|
|
+ D("[ usb located new device %s (%d/%d/%d) ]\n",
|
|
+ dev_name, ep_in, ep_out, interface);
|
|
+ usb = calloc(1, sizeof(usb_handle));
|
|
+ strcpy(usb->fname, dev_name);
|
|
+ usb->ep_in = ep_in;
|
|
+ usb->ep_out = ep_out;
|
|
+ usb->zero_mask = zero_mask;
|
|
+ usb->writeable = 1;
|
|
+
|
|
+ adb_cond_init(&usb->notify, 0);
|
|
+ adb_mutex_init(&usb->lock, 0);
|
|
+ /* initialize mark to 1 so we don't get garbage collected after the device scan */
|
|
+ usb->mark = 1;
|
|
+ usb->reaper_thread = 0;
|
|
+
|
|
+ usb->desc = unix_open(usb->fname, O_RDWR);
|
|
+ if(usb->desc < 0) {
|
|
+ /* if we fail, see if have read-only access */
|
|
+ usb->desc = unix_open(usb->fname, O_RDONLY);
|
|
+ if(usb->desc < 0) goto fail;
|
|
+ usb->writeable = 0;
|
|
+ D("[ usb open read-only %s fd = %d]\n", usb->fname, usb->desc);
|
|
+ } else {
|
|
+ D("[ usb open %s fd = %d]\n", usb->fname, usb->desc);
|
|
+ n = ioctl(usb->desc, USBDEVFS_CLAIMINTERFACE, &interface);
|
|
+ if(n != 0) goto fail;
|
|
+ }
|
|
+
|
|
+ /* read the device's serial number */
|
|
+ serial[0] = 0;
|
|
+ memset(serial, 0, sizeof(serial));
|
|
+ if (serial_index) {
|
|
+ struct usbdevfs_ctrltransfer ctrl;
|
|
+ __u16 buffer[128];
|
|
+ __u16 languages[128];
|
|
+ int i, result;
|
|
+ int languageCount = 0;
|
|
+
|
|
+ memset(languages, 0, sizeof(languages));
|
|
+ memset(&ctrl, 0, sizeof(ctrl));
|
|
+
|
|
+ // read list of supported languages
|
|
+ ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
|
|
+ ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
|
|
+ ctrl.wValue = (USB_DT_STRING << 8) | 0;
|
|
+ ctrl.wIndex = 0;
|
|
+ ctrl.wLength = sizeof(languages);
|
|
+ ctrl.data = languages;
|
|
+ ctrl.timeout = 1000;
|
|
+
|
|
+ result = ioctl(usb->desc, USBDEVFS_CONTROL, &ctrl);
|
|
+ if (result > 0)
|
|
+ languageCount = (result - 2) / 2;
|
|
+
|
|
+ for (i = 1; i <= languageCount; i++) {
|
|
+ memset(buffer, 0, sizeof(buffer));
|
|
+ memset(&ctrl, 0, sizeof(ctrl));
|
|
+
|
|
+ ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
|
|
+ ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
|
|
+ ctrl.wValue = (USB_DT_STRING << 8) | serial_index;
|
|
+ ctrl.wIndex = __le16_to_cpu(languages[i]);
|
|
+ ctrl.wLength = sizeof(buffer);
|
|
+ ctrl.data = buffer;
|
|
+ ctrl.timeout = 1000;
|
|
+
|
|
+ result = ioctl(usb->desc, USBDEVFS_CONTROL, &ctrl);
|
|
+ if (result > 0) {
|
|
+ int i;
|
|
+ // skip first word, and copy the rest to the serial string, changing shorts to bytes.
|
|
+ result /= 2;
|
|
+ for (i = 1; i < result; i++)
|
|
+ serial[i - 1] = __le16_to_cpu(buffer[i]);
|
|
+ serial[i - 1] = 0;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* add to the end of the active handles */
|
|
+ adb_mutex_lock(&usb_lock);
|
|
+ usb->next = &handle_list;
|
|
+ usb->prev = handle_list.prev;
|
|
+ usb->prev->next = usb;
|
|
+ usb->next->prev = usb;
|
|
+ adb_mutex_unlock(&usb_lock);
|
|
+
|
|
+ register_usb_transport(usb, serial, devpath, usb->writeable);
|
|
+ return;
|
|
+
|
|
+fail:
|
|
+ D("[ usb open %s error=%d, err_str = %s]\n",
|
|
+ usb->fname, errno, strerror(errno));
|
|
+ if(usb->desc >= 0) {
|
|
+ adb_close(usb->desc);
|
|
+ }
|
|
+ free(usb);
|
|
+}
|
|
+
|
|
+void* device_poll_thread(void* unused)
|
|
+{
|
|
+ D("Created device thread\n");
|
|
+ for(;;) {
|
|
+ /* XXX use inotify */
|
|
+ find_usb_device("/dev/bus/usb", register_device);
|
|
+ kick_disconnected_devices();
|
|
+ sleep(1);
|
|
+ }
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static void sigalrm_handler(int signo)
|
|
+{
|
|
+ // don't need to do anything here
|
|
+}
|
|
+
|
|
+void usb_init()
|
|
+{
|
|
+ adb_thread_t tid;
|
|
+ struct sigaction actions;
|
|
+
|
|
+ memset(&actions, 0, sizeof(actions));
|
|
+ sigemptyset(&actions.sa_mask);
|
|
+ actions.sa_flags = 0;
|
|
+ actions.sa_handler = sigalrm_handler;
|
|
+ sigaction(SIGALRM,& actions, NULL);
|
|
+
|
|
+ if(adb_thread_create(&tid, device_poll_thread, NULL)){
|
|
+ fatal_errno("cannot create input thread");
|
|
+ }
|
|
+}
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/usb_linux_client.c
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/usb_linux_client.c 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,492 @@
|
|
+/*
|
|
+ * Copyright (C) 2007 The Android Open Source Project
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
+ * you may not use this file except in compliance with the License.
|
|
+ * You may obtain a copy of the License at
|
|
+ *
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
+ *
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+ * See the License for the specific language governing permissions and
|
|
+ * limitations under the License.
|
|
+ */
|
|
+
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+#include <unistd.h>
|
|
+#include <string.h>
|
|
+
|
|
+#include <linux/usb/ch9.h>
|
|
+#include <linux/usb/functionfs.h>
|
|
+#include <sys/ioctl.h>
|
|
+#include <sys/types.h>
|
|
+#include <dirent.h>
|
|
+#include <errno.h>
|
|
+
|
|
+#include "sysdeps.h"
|
|
+
|
|
+#define TRACE_TAG TRACE_USB
|
|
+#include "adb.h"
|
|
+
|
|
+#define MAX_PACKET_SIZE_FS 64
|
|
+#define MAX_PACKET_SIZE_HS 512
|
|
+
|
|
+#define cpu_to_le16(x) htole16(x)
|
|
+#define cpu_to_le32(x) htole32(x)
|
|
+
|
|
+struct usb_handle
|
|
+{
|
|
+ adb_cond_t notify;
|
|
+ adb_mutex_t lock;
|
|
+
|
|
+ int (*write)(usb_handle *h, const void *data, int len);
|
|
+ int (*read)(usb_handle *h, void *data, int len);
|
|
+ void (*kick)(usb_handle *h);
|
|
+
|
|
+ // Legacy f_adb
|
|
+ int fd;
|
|
+
|
|
+ // FunctionFS
|
|
+ int control;
|
|
+ int bulk_out; /* "out" from the host's perspective => source for adbd */
|
|
+ int bulk_in; /* "in" from the host's perspective => sink for adbd */
|
|
+};
|
|
+
|
|
+static const struct {
|
|
+ struct usb_functionfs_descs_head header;
|
|
+ struct {
|
|
+ struct usb_interface_descriptor intf;
|
|
+ struct usb_endpoint_descriptor_no_audio source;
|
|
+ struct usb_endpoint_descriptor_no_audio sink;
|
|
+ } __attribute__((packed)) fs_descs, hs_descs;
|
|
+} __attribute__((packed)) descriptors = {
|
|
+ .header = {
|
|
+ .magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC),
|
|
+ .length = cpu_to_le32(sizeof(descriptors)),
|
|
+ .fs_count = 3,
|
|
+ .hs_count = 3,
|
|
+ },
|
|
+ .fs_descs = {
|
|
+ .intf = {
|
|
+ .bLength = sizeof(descriptors.fs_descs.intf),
|
|
+ .bDescriptorType = USB_DT_INTERFACE,
|
|
+ .bInterfaceNumber = 0,
|
|
+ .bNumEndpoints = 2,
|
|
+ .bInterfaceClass = ADB_CLASS,
|
|
+ .bInterfaceSubClass = ADB_SUBCLASS,
|
|
+ .bInterfaceProtocol = ADB_PROTOCOL,
|
|
+ .iInterface = 1, /* first string from the provided table */
|
|
+ },
|
|
+ .source = {
|
|
+ .bLength = sizeof(descriptors.fs_descs.source),
|
|
+ .bDescriptorType = USB_DT_ENDPOINT,
|
|
+ .bEndpointAddress = 1 | USB_DIR_OUT,
|
|
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
|
|
+ .wMaxPacketSize = MAX_PACKET_SIZE_FS,
|
|
+ },
|
|
+ .sink = {
|
|
+ .bLength = sizeof(descriptors.fs_descs.sink),
|
|
+ .bDescriptorType = USB_DT_ENDPOINT,
|
|
+ .bEndpointAddress = 2 | USB_DIR_IN,
|
|
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
|
|
+ .wMaxPacketSize = MAX_PACKET_SIZE_FS,
|
|
+ },
|
|
+ },
|
|
+ .hs_descs = {
|
|
+ .intf = {
|
|
+ .bLength = sizeof(descriptors.hs_descs.intf),
|
|
+ .bDescriptorType = USB_DT_INTERFACE,
|
|
+ .bInterfaceNumber = 0,
|
|
+ .bNumEndpoints = 2,
|
|
+ .bInterfaceClass = ADB_CLASS,
|
|
+ .bInterfaceSubClass = ADB_SUBCLASS,
|
|
+ .bInterfaceProtocol = ADB_PROTOCOL,
|
|
+ .iInterface = 1, /* first string from the provided table */
|
|
+ },
|
|
+ .source = {
|
|
+ .bLength = sizeof(descriptors.hs_descs.source),
|
|
+ .bDescriptorType = USB_DT_ENDPOINT,
|
|
+ .bEndpointAddress = 1 | USB_DIR_OUT,
|
|
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
|
|
+ .wMaxPacketSize = MAX_PACKET_SIZE_HS,
|
|
+ },
|
|
+ .sink = {
|
|
+ .bLength = sizeof(descriptors.hs_descs.sink),
|
|
+ .bDescriptorType = USB_DT_ENDPOINT,
|
|
+ .bEndpointAddress = 2 | USB_DIR_IN,
|
|
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
|
|
+ .wMaxPacketSize = MAX_PACKET_SIZE_HS,
|
|
+ },
|
|
+ },
|
|
+};
|
|
+
|
|
+#define STR_INTERFACE_ "ADB Interface"
|
|
+
|
|
+static const struct {
|
|
+ struct usb_functionfs_strings_head header;
|
|
+ struct {
|
|
+ __le16 code;
|
|
+ const char str1[sizeof(STR_INTERFACE_)];
|
|
+ } __attribute__((packed)) lang0;
|
|
+} __attribute__((packed)) strings = {
|
|
+ .header = {
|
|
+ .magic = cpu_to_le32(FUNCTIONFS_STRINGS_MAGIC),
|
|
+ .length = cpu_to_le32(sizeof(strings)),
|
|
+ .str_count = cpu_to_le32(1),
|
|
+ .lang_count = cpu_to_le32(1),
|
|
+ },
|
|
+ .lang0 = {
|
|
+ cpu_to_le16(0x0409), /* en-us */
|
|
+ STR_INTERFACE_,
|
|
+ },
|
|
+};
|
|
+
|
|
+
|
|
+
|
|
+static void *usb_adb_open_thread(void *x)
|
|
+{
|
|
+ struct usb_handle *usb = (struct usb_handle *)x;
|
|
+ int fd;
|
|
+
|
|
+ while (1) {
|
|
+ // wait until the USB device needs opening
|
|
+ adb_mutex_lock(&usb->lock);
|
|
+ while (usb->fd != -1)
|
|
+ adb_cond_wait(&usb->notify, &usb->lock);
|
|
+ adb_mutex_unlock(&usb->lock);
|
|
+
|
|
+ D("[ usb_thread - opening device ]\n");
|
|
+ do {
|
|
+ /* XXX use inotify? */
|
|
+ fd = unix_open("/dev/android_adb", O_RDWR);
|
|
+ if (fd < 0) {
|
|
+ // to support older kernels
|
|
+ fd = unix_open("/dev/android", O_RDWR);
|
|
+ }
|
|
+ if (fd < 0) {
|
|
+ adb_sleep_ms(1000);
|
|
+ }
|
|
+ } while (fd < 0);
|
|
+ D("[ opening device succeeded ]\n");
|
|
+
|
|
+ close_on_exec(fd);
|
|
+ usb->fd = fd;
|
|
+
|
|
+ D("[ usb_thread - registering device ]\n");
|
|
+ register_usb_transport(usb, 0, 0, 1);
|
|
+ }
|
|
+
|
|
+ // never gets here
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int usb_adb_write(usb_handle *h, const void *data, int len)
|
|
+{
|
|
+ int n;
|
|
+
|
|
+ D("about to write (fd=%d, len=%d)\n", h->fd, len);
|
|
+ n = adb_write(h->fd, data, len);
|
|
+ if(n != len) {
|
|
+ D("ERROR: fd = %d, n = %d, errno = %d (%s)\n",
|
|
+ h->fd, n, errno, strerror(errno));
|
|
+ return -1;
|
|
+ }
|
|
+ D("[ done fd=%d ]\n", h->fd);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int usb_adb_read(usb_handle *h, void *data, int len)
|
|
+{
|
|
+ int n;
|
|
+
|
|
+ D("about to read (fd=%d, len=%d)\n", h->fd, len);
|
|
+ n = adb_read(h->fd, data, len);
|
|
+ if(n != len) {
|
|
+ D("ERROR: fd = %d, n = %d, errno = %d (%s)\n",
|
|
+ h->fd, n, errno, strerror(errno));
|
|
+ return -1;
|
|
+ }
|
|
+ D("[ done fd=%d ]\n", h->fd);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void usb_adb_kick(usb_handle *h)
|
|
+{
|
|
+ D("usb_kick\n");
|
|
+ adb_mutex_lock(&h->lock);
|
|
+ adb_close(h->fd);
|
|
+ h->fd = -1;
|
|
+
|
|
+ // notify usb_adb_open_thread that we are disconnected
|
|
+ adb_cond_signal(&h->notify);
|
|
+ adb_mutex_unlock(&h->lock);
|
|
+}
|
|
+
|
|
+static void usb_adb_init()
|
|
+{
|
|
+ usb_handle *h;
|
|
+ adb_thread_t tid;
|
|
+ int fd;
|
|
+
|
|
+ h = calloc(1, sizeof(usb_handle));
|
|
+
|
|
+ h->write = usb_adb_write;
|
|
+ h->read = usb_adb_read;
|
|
+ h->kick = usb_adb_kick;
|
|
+ h->fd = -1;
|
|
+
|
|
+ adb_cond_init(&h->notify, 0);
|
|
+ adb_mutex_init(&h->lock, 0);
|
|
+
|
|
+ // Open the file /dev/android_adb_enable to trigger
|
|
+ // the enabling of the adb USB function in the kernel.
|
|
+ // We never touch this file again - just leave it open
|
|
+ // indefinitely so the kernel will know when we are running
|
|
+ // and when we are not.
|
|
+ fd = unix_open("/dev/android_adb_enable", O_RDWR);
|
|
+ if (fd < 0) {
|
|
+ D("failed to open /dev/android_adb_enable\n");
|
|
+ } else {
|
|
+ close_on_exec(fd);
|
|
+ }
|
|
+
|
|
+ D("[ usb_init - starting thread ]\n");
|
|
+ if(adb_thread_create(&tid, usb_adb_open_thread, h)){
|
|
+ fatal_errno("cannot create usb thread");
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+static void init_functionfs(struct usb_handle *h)
|
|
+{
|
|
+ ssize_t ret;
|
|
+
|
|
+ D("OPENING %s\n", USB_FFS_ADB_EP0);
|
|
+ h->control = adb_open(USB_FFS_ADB_EP0, O_RDWR);
|
|
+ if (h->control < 0) {
|
|
+ D("[ %s: cannot open control endpoint: errno=%d]\n", USB_FFS_ADB_EP0, errno);
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+ ret = adb_write(h->control, &descriptors, sizeof(descriptors));
|
|
+ if (ret < 0) {
|
|
+ D("[ %s: write descriptors failed: errno=%d ]\n", USB_FFS_ADB_EP0, errno);
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+ ret = adb_write(h->control, &strings, sizeof(strings));
|
|
+ if (ret < 0) {
|
|
+ D("[ %s: writing strings failed: errno=%d]\n", USB_FFS_ADB_EP0, errno);
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+ h->bulk_out = adb_open(USB_FFS_ADB_OUT, O_RDWR);
|
|
+ if (h->bulk_out < 0) {
|
|
+ D("[ %s: cannot open bulk-out ep: errno=%d ]\n", USB_FFS_ADB_OUT, errno);
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+ h->bulk_in = adb_open(USB_FFS_ADB_IN, O_RDWR);
|
|
+ if (h->bulk_in < 0) {
|
|
+ D("[ %s: cannot open bulk-in ep: errno=%d ]\n", USB_FFS_ADB_IN, errno);
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+ return;
|
|
+
|
|
+err:
|
|
+ if (h->bulk_in > 0) {
|
|
+ adb_close(h->bulk_in);
|
|
+ h->bulk_in = -1;
|
|
+ }
|
|
+ if (h->bulk_out > 0) {
|
|
+ adb_close(h->bulk_out);
|
|
+ h->bulk_out = -1;
|
|
+ }
|
|
+ if (h->control > 0) {
|
|
+ adb_close(h->control);
|
|
+ h->control = -1;
|
|
+ }
|
|
+ return;
|
|
+}
|
|
+
|
|
+static void *usb_ffs_open_thread(void *x)
|
|
+{
|
|
+ struct usb_handle *usb = (struct usb_handle *)x;
|
|
+
|
|
+ while (1) {
|
|
+ // wait until the USB device needs opening
|
|
+ adb_mutex_lock(&usb->lock);
|
|
+ while (usb->control != -1)
|
|
+ adb_cond_wait(&usb->notify, &usb->lock);
|
|
+ adb_mutex_unlock(&usb->lock);
|
|
+
|
|
+ while (1) {
|
|
+ init_functionfs(usb);
|
|
+
|
|
+ if (usb->control >= 0)
|
|
+ break;
|
|
+
|
|
+ adb_sleep_ms(1000);
|
|
+ }
|
|
+
|
|
+ D("[ usb_thread - registering device ]\n");
|
|
+ register_usb_transport(usb, 0, 0, 1);
|
|
+ }
|
|
+
|
|
+ // never gets here
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int bulk_write(int bulk_in, const char *buf, size_t length)
|
|
+{
|
|
+ size_t count = 0;
|
|
+ int ret;
|
|
+
|
|
+ do {
|
|
+ ret = adb_write(bulk_in, buf + count, length - count);
|
|
+ if (ret < 0) {
|
|
+ if (errno != EINTR)
|
|
+ return ret;
|
|
+ } else {
|
|
+ count += ret;
|
|
+ }
|
|
+ } while (count < length);
|
|
+
|
|
+ D("[ bulk_write done fd=%d ]\n", bulk_in);
|
|
+ return count;
|
|
+}
|
|
+
|
|
+static int usb_ffs_write(usb_handle *h, const void *data, int len)
|
|
+{
|
|
+ int n;
|
|
+
|
|
+ D("about to write (fd=%d, len=%d)\n", h->bulk_in, len);
|
|
+ n = bulk_write(h->bulk_in, data, len);
|
|
+ if (n != len) {
|
|
+ D("ERROR: fd = %d, n = %d, errno = %d (%s)\n",
|
|
+ h->bulk_in, n, errno, strerror(errno));
|
|
+ return -1;
|
|
+ }
|
|
+ D("[ done fd=%d ]\n", h->bulk_in);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int bulk_read(int bulk_out, char *buf, size_t length)
|
|
+{
|
|
+ size_t count = 0;
|
|
+ int ret;
|
|
+
|
|
+ do {
|
|
+ ret = adb_read(bulk_out, buf + count, length - count);
|
|
+ if (ret < 0) {
|
|
+ if (errno != EINTR) {
|
|
+ D("[ bulk_read failed fd=%d length=%d count=%d ]\n",
|
|
+ bulk_out, length, count);
|
|
+ return ret;
|
|
+ }
|
|
+ } else {
|
|
+ count += ret;
|
|
+ }
|
|
+ } while (count < length);
|
|
+
|
|
+ return count;
|
|
+}
|
|
+
|
|
+static int usb_ffs_read(usb_handle *h, void *data, int len)
|
|
+{
|
|
+ int n;
|
|
+
|
|
+ D("about to read (fd=%d, len=%d)\n", h->bulk_out, len);
|
|
+ n = bulk_read(h->bulk_out, data, len);
|
|
+ if (n != len) {
|
|
+ D("ERROR: fd = %d, n = %d, errno = %d (%s)\n",
|
|
+ h->bulk_out, n, errno, strerror(errno));
|
|
+ return -1;
|
|
+ }
|
|
+ D("[ done fd=%d ]\n", h->bulk_out);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void usb_ffs_kick(usb_handle *h)
|
|
+{
|
|
+ int err;
|
|
+
|
|
+ err = ioctl(h->bulk_in, FUNCTIONFS_CLEAR_HALT);
|
|
+ if (err < 0)
|
|
+ D("[ kick: source (fd=%d) clear halt failed (%d) ]", h->bulk_in, errno);
|
|
+
|
|
+ err = ioctl(h->bulk_out, FUNCTIONFS_CLEAR_HALT);
|
|
+ if (err < 0)
|
|
+ D("[ kick: sink (fd=%d) clear halt failed (%d) ]", h->bulk_out, errno);
|
|
+
|
|
+ adb_mutex_lock(&h->lock);
|
|
+ adb_close(h->control);
|
|
+ adb_close(h->bulk_out);
|
|
+ adb_close(h->bulk_in);
|
|
+ h->control = h->bulk_out = h->bulk_in = -1;
|
|
+
|
|
+ // notify usb_ffs_open_thread that we are disconnected
|
|
+ adb_cond_signal(&h->notify);
|
|
+ adb_mutex_unlock(&h->lock);
|
|
+}
|
|
+
|
|
+static void usb_ffs_init()
|
|
+{
|
|
+ usb_handle *h;
|
|
+ adb_thread_t tid;
|
|
+
|
|
+ D("[ usb_init - using FunctionFS ]\n");
|
|
+
|
|
+ h = calloc(1, sizeof(usb_handle));
|
|
+
|
|
+ h->write = usb_ffs_write;
|
|
+ h->read = usb_ffs_read;
|
|
+ h->kick = usb_ffs_kick;
|
|
+
|
|
+ h->control = -1;
|
|
+ h->bulk_out = -1;
|
|
+ h->bulk_out = -1;
|
|
+
|
|
+ adb_cond_init(&h->notify, 0);
|
|
+ adb_mutex_init(&h->lock, 0);
|
|
+
|
|
+ D("[ usb_init - starting thread ]\n");
|
|
+ if (adb_thread_create(&tid, usb_ffs_open_thread, h)){
|
|
+ fatal_errno("[ cannot create usb thread ]\n");
|
|
+ }
|
|
+}
|
|
+
|
|
+void usb_init()
|
|
+{
|
|
+ if (access(USB_FFS_ADB_EP0, F_OK) == 0)
|
|
+ usb_ffs_init();
|
|
+ else
|
|
+ usb_adb_init();
|
|
+}
|
|
+
|
|
+void usb_cleanup()
|
|
+{
|
|
+}
|
|
+
|
|
+int usb_write(usb_handle *h, const void *data, int len)
|
|
+{
|
|
+ return h->write(h, data, len);
|
|
+}
|
|
+
|
|
+int usb_read(usb_handle *h, void *data, int len)
|
|
+{
|
|
+ return h->read(h, data, len);
|
|
+}
|
|
+int usb_close(usb_handle *h)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void usb_kick(usb_handle *h)
|
|
+{
|
|
+ h->kick(h);
|
|
+}
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/usb_osx.c
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/usb_osx.c 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,545 @@
|
|
+/*
|
|
+ * Copyright (C) 2007 The Android Open Source Project
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
+ * you may not use this file except in compliance with the License.
|
|
+ * You may obtain a copy of the License at
|
|
+ *
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
+ *
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+ * See the License for the specific language governing permissions and
|
|
+ * limitations under the License.
|
|
+ */
|
|
+
|
|
+#include <CoreFoundation/CoreFoundation.h>
|
|
+
|
|
+#include <IOKit/IOKitLib.h>
|
|
+#include <IOKit/IOCFPlugIn.h>
|
|
+#include <IOKit/usb/IOUSBLib.h>
|
|
+#include <IOKit/IOMessage.h>
|
|
+#include <mach/mach_port.h>
|
|
+
|
|
+#include "sysdeps.h"
|
|
+
|
|
+#include <stdio.h>
|
|
+
|
|
+#define TRACE_TAG TRACE_USB
|
|
+#include "adb.h"
|
|
+#include "usb_vendors.h"
|
|
+
|
|
+#define DBG D
|
|
+
|
|
+static IONotificationPortRef notificationPort = 0;
|
|
+static io_iterator_t* notificationIterators;
|
|
+
|
|
+struct usb_handle
|
|
+{
|
|
+ UInt8 bulkIn;
|
|
+ UInt8 bulkOut;
|
|
+ IOUSBInterfaceInterface **interface;
|
|
+ io_object_t usbNotification;
|
|
+ unsigned int zero_mask;
|
|
+};
|
|
+
|
|
+static CFRunLoopRef currentRunLoop = 0;
|
|
+static pthread_mutex_t start_lock;
|
|
+static pthread_cond_t start_cond;
|
|
+
|
|
+
|
|
+static void AndroidInterfaceAdded(void *refCon, io_iterator_t iterator);
|
|
+static void AndroidInterfaceNotify(void *refCon, io_iterator_t iterator,
|
|
+ natural_t messageType,
|
|
+ void *messageArgument);
|
|
+static usb_handle* CheckInterface(IOUSBInterfaceInterface **iface,
|
|
+ UInt16 vendor, UInt16 product);
|
|
+
|
|
+static int
|
|
+InitUSB()
|
|
+{
|
|
+ CFMutableDictionaryRef matchingDict;
|
|
+ CFRunLoopSourceRef runLoopSource;
|
|
+ SInt32 vendor, if_subclass, if_protocol;
|
|
+ unsigned i;
|
|
+
|
|
+ //* To set up asynchronous notifications, create a notification port and
|
|
+ //* add its run loop event source to the program's run loop
|
|
+ notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
|
|
+ runLoopSource = IONotificationPortGetRunLoopSource(notificationPort);
|
|
+ CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode);
|
|
+
|
|
+ memset(notificationIterators, 0, sizeof(notificationIterators));
|
|
+
|
|
+ //* loop through all supported vendors
|
|
+ for (i = 0; i < vendorIdCount; i++) {
|
|
+ //* Create our matching dictionary to find the Android device's
|
|
+ //* adb interface
|
|
+ //* IOServiceAddMatchingNotification consumes the reference, so we do
|
|
+ //* not need to release this
|
|
+ matchingDict = IOServiceMatching(kIOUSBInterfaceClassName);
|
|
+
|
|
+ if (!matchingDict) {
|
|
+ DBG("ERR: Couldn't create USB matching dictionary.\n");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ //* Match based on vendor id, interface subclass and protocol
|
|
+ vendor = vendorIds[i];
|
|
+ if_subclass = ADB_SUBCLASS;
|
|
+ if_protocol = ADB_PROTOCOL;
|
|
+ CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorID),
|
|
+ CFNumberCreate(kCFAllocatorDefault,
|
|
+ kCFNumberSInt32Type, &vendor));
|
|
+ CFDictionarySetValue(matchingDict, CFSTR(kUSBInterfaceSubClass),
|
|
+ CFNumberCreate(kCFAllocatorDefault,
|
|
+ kCFNumberSInt32Type, &if_subclass));
|
|
+ CFDictionarySetValue(matchingDict, CFSTR(kUSBInterfaceProtocol),
|
|
+ CFNumberCreate(kCFAllocatorDefault,
|
|
+ kCFNumberSInt32Type, &if_protocol));
|
|
+ IOServiceAddMatchingNotification(
|
|
+ notificationPort,
|
|
+ kIOFirstMatchNotification,
|
|
+ matchingDict,
|
|
+ AndroidInterfaceAdded,
|
|
+ NULL,
|
|
+ ¬ificationIterators[i]);
|
|
+
|
|
+ //* Iterate over set of matching interfaces to access already-present
|
|
+ //* devices and to arm the notification
|
|
+ AndroidInterfaceAdded(NULL, notificationIterators[i]);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void
|
|
+AndroidInterfaceAdded(void *refCon, io_iterator_t iterator)
|
|
+{
|
|
+ kern_return_t kr;
|
|
+ io_service_t usbDevice;
|
|
+ io_service_t usbInterface;
|
|
+ IOCFPlugInInterface **plugInInterface = NULL;
|
|
+ IOUSBInterfaceInterface220 **iface = NULL;
|
|
+ IOUSBDeviceInterface197 **dev = NULL;
|
|
+ HRESULT result;
|
|
+ SInt32 score;
|
|
+ UInt32 locationId;
|
|
+ UInt16 vendor;
|
|
+ UInt16 product;
|
|
+ UInt8 serialIndex;
|
|
+ char serial[256];
|
|
+ char devpathBuf[64];
|
|
+ char *devpath = NULL;
|
|
+
|
|
+ while ((usbInterface = IOIteratorNext(iterator))) {
|
|
+ //* Create an intermediate interface plugin
|
|
+ kr = IOCreatePlugInInterfaceForService(usbInterface,
|
|
+ kIOUSBInterfaceUserClientTypeID,
|
|
+ kIOCFPlugInInterfaceID,
|
|
+ &plugInInterface, &score);
|
|
+ IOObjectRelease(usbInterface);
|
|
+ if ((kIOReturnSuccess != kr) || (!plugInInterface)) {
|
|
+ DBG("ERR: Unable to create an interface plug-in (%08x)\n", kr);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ //* This gets us the interface object
|
|
+ result = (*plugInInterface)->QueryInterface(plugInInterface,
|
|
+ CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID)
|
|
+ &iface);
|
|
+ //* We only needed the plugin to get the interface, so discard it
|
|
+ (*plugInInterface)->Release(plugInInterface);
|
|
+ if (result || !iface) {
|
|
+ DBG("ERR: Couldn't query the interface (%08x)\n", (int) result);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ //* this gets us an ioservice, with which we will find the actual
|
|
+ //* device; after getting a plugin, and querying the interface, of
|
|
+ //* course.
|
|
+ //* Gotta love OS X
|
|
+ kr = (*iface)->GetDevice(iface, &usbDevice);
|
|
+ if (kIOReturnSuccess != kr || !usbDevice) {
|
|
+ DBG("ERR: Couldn't grab device from interface (%08x)\n", kr);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ plugInInterface = NULL;
|
|
+ score = 0;
|
|
+ //* create an intermediate device plugin
|
|
+ kr = IOCreatePlugInInterfaceForService(usbDevice,
|
|
+ kIOUSBDeviceUserClientTypeID,
|
|
+ kIOCFPlugInInterfaceID,
|
|
+ &plugInInterface, &score);
|
|
+ //* only needed this to find the plugin
|
|
+ (void)IOObjectRelease(usbDevice);
|
|
+ if ((kIOReturnSuccess != kr) || (!plugInInterface)) {
|
|
+ DBG("ERR: Unable to create a device plug-in (%08x)\n", kr);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ result = (*plugInInterface)->QueryInterface(plugInInterface,
|
|
+ CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID) &dev);
|
|
+ //* only needed this to query the plugin
|
|
+ (*plugInInterface)->Release(plugInInterface);
|
|
+ if (result || !dev) {
|
|
+ DBG("ERR: Couldn't create a device interface (%08x)\n",
|
|
+ (int) result);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ //* Now after all that, we actually have a ref to the device and
|
|
+ //* the interface that matched our criteria
|
|
+
|
|
+ kr = (*dev)->GetDeviceVendor(dev, &vendor);
|
|
+ kr = (*dev)->GetDeviceProduct(dev, &product);
|
|
+ kr = (*dev)->GetLocationID(dev, &locationId);
|
|
+ if (kr == 0) {
|
|
+ snprintf(devpathBuf, sizeof(devpathBuf), "usb:%lX", locationId);
|
|
+ devpath = devpathBuf;
|
|
+ }
|
|
+ kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex);
|
|
+
|
|
+ if (serialIndex > 0) {
|
|
+ IOUSBDevRequest req;
|
|
+ UInt16 buffer[256];
|
|
+ UInt16 languages[128];
|
|
+
|
|
+ memset(languages, 0, sizeof(languages));
|
|
+
|
|
+ req.bmRequestType =
|
|
+ USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
|
|
+ req.bRequest = kUSBRqGetDescriptor;
|
|
+ req.wValue = (kUSBStringDesc << 8) | 0;
|
|
+ req.wIndex = 0;
|
|
+ req.pData = languages;
|
|
+ req.wLength = sizeof(languages);
|
|
+ kr = (*dev)->DeviceRequest(dev, &req);
|
|
+
|
|
+ if (kr == kIOReturnSuccess && req.wLenDone > 0) {
|
|
+
|
|
+ int langCount = (req.wLenDone - 2) / 2, lang;
|
|
+
|
|
+ for (lang = 1; lang <= langCount; lang++) {
|
|
+
|
|
+ memset(buffer, 0, sizeof(buffer));
|
|
+ memset(&req, 0, sizeof(req));
|
|
+
|
|
+ req.bmRequestType =
|
|
+ USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
|
|
+ req.bRequest = kUSBRqGetDescriptor;
|
|
+ req.wValue = (kUSBStringDesc << 8) | serialIndex;
|
|
+ req.wIndex = languages[lang];
|
|
+ req.pData = buffer;
|
|
+ req.wLength = sizeof(buffer);
|
|
+ kr = (*dev)->DeviceRequest(dev, &req);
|
|
+
|
|
+ if (kr == kIOReturnSuccess && req.wLenDone > 0) {
|
|
+ int i, count;
|
|
+
|
|
+ // skip first word, and copy the rest to the serial string,
|
|
+ // changing shorts to bytes.
|
|
+ count = (req.wLenDone - 1) / 2;
|
|
+ for (i = 0; i < count; i++)
|
|
+ serial[i] = buffer[i + 1];
|
|
+ serial[i] = 0;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ (*dev)->Release(dev);
|
|
+
|
|
+ DBG("INFO: Found vid=%04x pid=%04x serial=%s\n", vendor, product,
|
|
+ serial);
|
|
+
|
|
+ usb_handle* handle = CheckInterface((IOUSBInterfaceInterface**)iface,
|
|
+ vendor, product);
|
|
+ if (handle == NULL) {
|
|
+ DBG("ERR: Could not find device interface: %08x\n", kr);
|
|
+ (*iface)->Release(iface);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ DBG("AndroidDeviceAdded calling register_usb_transport\n");
|
|
+ register_usb_transport(handle, (serial[0] ? serial : NULL), devpath, 1);
|
|
+
|
|
+ // Register for an interest notification of this device being removed.
|
|
+ // Pass the reference to our private data as the refCon for the
|
|
+ // notification.
|
|
+ kr = IOServiceAddInterestNotification(notificationPort,
|
|
+ usbInterface,
|
|
+ kIOGeneralInterest,
|
|
+ AndroidInterfaceNotify,
|
|
+ handle,
|
|
+ &handle->usbNotification);
|
|
+
|
|
+ if (kIOReturnSuccess != kr) {
|
|
+ DBG("ERR: Unable to create interest notification (%08x)\n", kr);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+static void
|
|
+AndroidInterfaceNotify(void *refCon, io_service_t service, natural_t messageType, void *messageArgument)
|
|
+{
|
|
+ usb_handle *handle = (usb_handle *)refCon;
|
|
+
|
|
+ if (messageType == kIOMessageServiceIsTerminated) {
|
|
+ if (!handle) {
|
|
+ DBG("ERR: NULL handle\n");
|
|
+ return;
|
|
+ }
|
|
+ DBG("AndroidInterfaceNotify\n");
|
|
+ IOObjectRelease(handle->usbNotification);
|
|
+ usb_kick(handle);
|
|
+ }
|
|
+}
|
|
+
|
|
+//* TODO: simplify this further since we only register to get ADB interface
|
|
+//* subclass+protocol events
|
|
+static usb_handle*
|
|
+CheckInterface(IOUSBInterfaceInterface **interface, UInt16 vendor, UInt16 product)
|
|
+{
|
|
+ usb_handle* handle = NULL;
|
|
+ IOReturn kr;
|
|
+ UInt8 interfaceNumEndpoints, interfaceClass, interfaceSubClass, interfaceProtocol;
|
|
+ UInt8 endpoint;
|
|
+
|
|
+
|
|
+ //* Now open the interface. This will cause the pipes associated with
|
|
+ //* the endpoints in the interface descriptor to be instantiated
|
|
+ kr = (*interface)->USBInterfaceOpen(interface);
|
|
+ if (kr != kIOReturnSuccess) {
|
|
+ DBG("ERR: Could not open interface: (%08x)\n", kr);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ //* Get the number of endpoints associated with this interface
|
|
+ kr = (*interface)->GetNumEndpoints(interface, &interfaceNumEndpoints);
|
|
+ if (kr != kIOReturnSuccess) {
|
|
+ DBG("ERR: Unable to get number of endpoints: (%08x)\n", kr);
|
|
+ goto err_get_num_ep;
|
|
+ }
|
|
+
|
|
+ //* Get interface class, subclass and protocol
|
|
+ if ((*interface)->GetInterfaceClass(interface, &interfaceClass) != kIOReturnSuccess ||
|
|
+ (*interface)->GetInterfaceSubClass(interface, &interfaceSubClass) != kIOReturnSuccess ||
|
|
+ (*interface)->GetInterfaceProtocol(interface, &interfaceProtocol) != kIOReturnSuccess) {
|
|
+ DBG("ERR: Unable to get interface class, subclass and protocol\n");
|
|
+ goto err_get_interface_class;
|
|
+ }
|
|
+
|
|
+ //* check to make sure interface class, subclass and protocol match ADB
|
|
+ //* avoid opening mass storage endpoints
|
|
+ if (!is_adb_interface(vendor, product, interfaceClass,
|
|
+ interfaceSubClass, interfaceProtocol))
|
|
+ goto err_bad_adb_interface;
|
|
+
|
|
+ handle = calloc(1, sizeof(usb_handle));
|
|
+
|
|
+ //* Iterate over the endpoints for this interface and find the first
|
|
+ //* bulk in/out pipes available. These will be our read/write pipes.
|
|
+ for (endpoint = 0; endpoint <= interfaceNumEndpoints; endpoint++) {
|
|
+ UInt8 transferType;
|
|
+ UInt16 maxPacketSize;
|
|
+ UInt8 interval;
|
|
+ UInt8 number;
|
|
+ UInt8 direction;
|
|
+
|
|
+ kr = (*interface)->GetPipeProperties(interface, endpoint, &direction,
|
|
+ &number, &transferType, &maxPacketSize, &interval);
|
|
+
|
|
+ if (kIOReturnSuccess == kr) {
|
|
+ if (kUSBBulk != transferType)
|
|
+ continue;
|
|
+
|
|
+ if (kUSBIn == direction)
|
|
+ handle->bulkIn = endpoint;
|
|
+
|
|
+ if (kUSBOut == direction)
|
|
+ handle->bulkOut = endpoint;
|
|
+
|
|
+ handle->zero_mask = maxPacketSize - 1;
|
|
+ } else {
|
|
+ DBG("ERR: FindDeviceInterface - could not get pipe properties\n");
|
|
+ goto err_get_pipe_props;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ handle->interface = interface;
|
|
+ return handle;
|
|
+
|
|
+err_get_pipe_props:
|
|
+ free(handle);
|
|
+err_bad_adb_interface:
|
|
+err_get_interface_class:
|
|
+err_get_num_ep:
|
|
+ (*interface)->USBInterfaceClose(interface);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+
|
|
+void* RunLoopThread(void* unused)
|
|
+{
|
|
+ unsigned i;
|
|
+
|
|
+ InitUSB();
|
|
+
|
|
+ currentRunLoop = CFRunLoopGetCurrent();
|
|
+
|
|
+ // Signal the parent that we are running
|
|
+ adb_mutex_lock(&start_lock);
|
|
+ adb_cond_signal(&start_cond);
|
|
+ adb_mutex_unlock(&start_lock);
|
|
+
|
|
+ CFRunLoopRun();
|
|
+ currentRunLoop = 0;
|
|
+
|
|
+ for (i = 0; i < vendorIdCount; i++) {
|
|
+ IOObjectRelease(notificationIterators[i]);
|
|
+ }
|
|
+ IONotificationPortDestroy(notificationPort);
|
|
+
|
|
+ DBG("RunLoopThread done\n");
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+
|
|
+static int initialized = 0;
|
|
+void usb_init()
|
|
+{
|
|
+ if (!initialized)
|
|
+ {
|
|
+ adb_thread_t tid;
|
|
+
|
|
+ notificationIterators = (io_iterator_t*)malloc(
|
|
+ vendorIdCount * sizeof(io_iterator_t));
|
|
+
|
|
+ adb_mutex_init(&start_lock, NULL);
|
|
+ adb_cond_init(&start_cond, NULL);
|
|
+
|
|
+ if(adb_thread_create(&tid, RunLoopThread, NULL))
|
|
+ fatal_errno("cannot create input thread");
|
|
+
|
|
+ // Wait for initialization to finish
|
|
+ adb_mutex_lock(&start_lock);
|
|
+ adb_cond_wait(&start_cond, &start_lock);
|
|
+ adb_mutex_unlock(&start_lock);
|
|
+
|
|
+ adb_mutex_destroy(&start_lock);
|
|
+ adb_cond_destroy(&start_cond);
|
|
+
|
|
+ initialized = 1;
|
|
+ }
|
|
+}
|
|
+
|
|
+void usb_cleanup()
|
|
+{
|
|
+ DBG("usb_cleanup\n");
|
|
+ close_usb_devices();
|
|
+ if (currentRunLoop)
|
|
+ CFRunLoopStop(currentRunLoop);
|
|
+
|
|
+ if (notificationIterators != NULL) {
|
|
+ free(notificationIterators);
|
|
+ notificationIterators = NULL;
|
|
+ }
|
|
+}
|
|
+
|
|
+int usb_write(usb_handle *handle, const void *buf, int len)
|
|
+{
|
|
+ IOReturn result;
|
|
+
|
|
+ if (!len)
|
|
+ return 0;
|
|
+
|
|
+ if (!handle)
|
|
+ return -1;
|
|
+
|
|
+ if (NULL == handle->interface) {
|
|
+ DBG("ERR: usb_write interface was null\n");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if (0 == handle->bulkOut) {
|
|
+ DBG("ERR: bulkOut endpoint not assigned\n");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ result =
|
|
+ (*handle->interface)->WritePipe(
|
|
+ handle->interface, handle->bulkOut, (void *)buf, len);
|
|
+
|
|
+ if ((result == 0) && (handle->zero_mask)) {
|
|
+ /* we need 0-markers and our transfer */
|
|
+ if(!(len & handle->zero_mask)) {
|
|
+ result =
|
|
+ (*handle->interface)->WritePipe(
|
|
+ handle->interface, handle->bulkOut, (void *)buf, 0);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (0 == result)
|
|
+ return 0;
|
|
+
|
|
+ DBG("ERR: usb_write failed with status %d\n", result);
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+int usb_read(usb_handle *handle, void *buf, int len)
|
|
+{
|
|
+ IOReturn result;
|
|
+ UInt32 numBytes = len;
|
|
+
|
|
+ if (!len) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (!handle) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if (NULL == handle->interface) {
|
|
+ DBG("ERR: usb_read interface was null\n");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if (0 == handle->bulkIn) {
|
|
+ DBG("ERR: bulkIn endpoint not assigned\n");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ result =
|
|
+ (*handle->interface)->ReadPipe(handle->interface,
|
|
+ handle->bulkIn, buf, &numBytes);
|
|
+
|
|
+ if (0 == result)
|
|
+ return 0;
|
|
+ else {
|
|
+ DBG("ERR: usb_read failed with status %d\n", result);
|
|
+ }
|
|
+
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+int usb_close(usb_handle *handle)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void usb_kick(usb_handle *handle)
|
|
+{
|
|
+ /* release the interface */
|
|
+ if (!handle)
|
|
+ return;
|
|
+
|
|
+ if (handle->interface)
|
|
+ {
|
|
+ (*handle->interface)->USBInterfaceClose(handle->interface);
|
|
+ (*handle->interface)->Release(handle->interface);
|
|
+ handle->interface = 0;
|
|
+ }
|
|
+}
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/usb_vendors.c
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/usb_vendors.c 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,273 @@
|
|
+/*
|
|
+ * Copyright (C) 2009 The Android Open Source Project
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
+ * you may not use this file except in compliance with the License.
|
|
+ * You may obtain a copy of the License at
|
|
+ *
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
+ *
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+ * See the License for the specific language governing permissions and
|
|
+ * limitations under the License.
|
|
+ */
|
|
+
|
|
+#include "usb_vendors.h"
|
|
+
|
|
+#include <stdio.h>
|
|
+
|
|
+#ifdef _WIN32
|
|
+# define WIN32_LEAN_AND_MEAN
|
|
+# include "windows.h"
|
|
+# include "shlobj.h"
|
|
+#else
|
|
+# include <unistd.h>
|
|
+# include <sys/stat.h>
|
|
+#endif
|
|
+
|
|
+#include "sysdeps.h"
|
|
+#include "adb.h"
|
|
+
|
|
+#define ANDROID_PATH ".android"
|
|
+#define ANDROID_ADB_INI "adb_usb.ini"
|
|
+
|
|
+#define TRACE_TAG TRACE_USB
|
|
+
|
|
+// Google's USB Vendor ID
|
|
+#define VENDOR_ID_GOOGLE 0x18d1
|
|
+// Intel's USB Vendor ID
|
|
+#define VENDOR_ID_INTEL 0x8087
|
|
+// HTC's USB Vendor ID
|
|
+#define VENDOR_ID_HTC 0x0bb4
|
|
+// Samsung's USB Vendor ID
|
|
+#define VENDOR_ID_SAMSUNG 0x04e8
|
|
+// Motorola's USB Vendor ID
|
|
+#define VENDOR_ID_MOTOROLA 0x22b8
|
|
+// LG's USB Vendor ID
|
|
+#define VENDOR_ID_LGE 0x1004
|
|
+// Huawei's USB Vendor ID
|
|
+#define VENDOR_ID_HUAWEI 0x12D1
|
|
+// Acer's USB Vendor ID
|
|
+#define VENDOR_ID_ACER 0x0502
|
|
+// Sony Ericsson's USB Vendor ID
|
|
+#define VENDOR_ID_SONY_ERICSSON 0x0FCE
|
|
+// Foxconn's USB Vendor ID
|
|
+#define VENDOR_ID_FOXCONN 0x0489
|
|
+// Dell's USB Vendor ID
|
|
+#define VENDOR_ID_DELL 0x413c
|
|
+// Nvidia's USB Vendor ID
|
|
+#define VENDOR_ID_NVIDIA 0x0955
|
|
+// Garmin-Asus's USB Vendor ID
|
|
+#define VENDOR_ID_GARMIN_ASUS 0x091E
|
|
+// Sharp's USB Vendor ID
|
|
+#define VENDOR_ID_SHARP 0x04dd
|
|
+// ZTE's USB Vendor ID
|
|
+#define VENDOR_ID_ZTE 0x19D2
|
|
+// Kyocera's USB Vendor ID
|
|
+#define VENDOR_ID_KYOCERA 0x0482
|
|
+// Pantech's USB Vendor ID
|
|
+#define VENDOR_ID_PANTECH 0x10A9
|
|
+// Qualcomm's USB Vendor ID
|
|
+#define VENDOR_ID_QUALCOMM 0x05c6
|
|
+// On-The-Go-Video's USB Vendor ID
|
|
+#define VENDOR_ID_OTGV 0x2257
|
|
+// NEC's USB Vendor ID
|
|
+#define VENDOR_ID_NEC 0x0409
|
|
+// Panasonic Mobile Communication's USB Vendor ID
|
|
+#define VENDOR_ID_PMC 0x04DA
|
|
+// Toshiba's USB Vendor ID
|
|
+#define VENDOR_ID_TOSHIBA 0x0930
|
|
+// SK Telesys's USB Vendor ID
|
|
+#define VENDOR_ID_SK_TELESYS 0x1F53
|
|
+// KT Tech's USB Vendor ID
|
|
+#define VENDOR_ID_KT_TECH 0x2116
|
|
+// Asus's USB Vendor ID
|
|
+#define VENDOR_ID_ASUS 0x0b05
|
|
+// Philips's USB Vendor ID
|
|
+#define VENDOR_ID_PHILIPS 0x0471
|
|
+// Texas Instruments's USB Vendor ID
|
|
+#define VENDOR_ID_TI 0x0451
|
|
+// Funai's USB Vendor ID
|
|
+#define VENDOR_ID_FUNAI 0x0F1C
|
|
+// Gigabyte's USB Vendor ID
|
|
+#define VENDOR_ID_GIGABYTE 0x0414
|
|
+// IRiver's USB Vendor ID
|
|
+#define VENDOR_ID_IRIVER 0x2420
|
|
+// Compal's USB Vendor ID
|
|
+#define VENDOR_ID_COMPAL 0x1219
|
|
+// T & A Mobile Phones' USB Vendor ID
|
|
+#define VENDOR_ID_T_AND_A 0x1BBB
|
|
+// LenovoMobile's USB Vendor ID
|
|
+#define VENDOR_ID_LENOVOMOBILE 0x2006
|
|
+// Lenovo's USB Vendor ID
|
|
+#define VENDOR_ID_LENOVO 0x17EF
|
|
+// Vizio's USB Vendor ID
|
|
+#define VENDOR_ID_VIZIO 0xE040
|
|
+// K-Touch's USB Vendor ID
|
|
+#define VENDOR_ID_K_TOUCH 0x24E3
|
|
+// Pegatron's USB Vendor ID
|
|
+#define VENDOR_ID_PEGATRON 0x1D4D
|
|
+// Archos's USB Vendor ID
|
|
+#define VENDOR_ID_ARCHOS 0x0E79
|
|
+// Positivo's USB Vendor ID
|
|
+#define VENDOR_ID_POSITIVO 0x1662
|
|
+// Fujitsu's USB Vendor ID
|
|
+#define VENDOR_ID_FUJITSU 0x04C5
|
|
+// Lumigon's USB Vendor ID
|
|
+#define VENDOR_ID_LUMIGON 0x25E3
|
|
+// Quanta's USB Vendor ID
|
|
+#define VENDOR_ID_QUANTA 0x0408
|
|
+// INQ Mobile's USB Vendor ID
|
|
+#define VENDOR_ID_INQ_MOBILE 0x2314
|
|
+// Sony's USB Vendor ID
|
|
+#define VENDOR_ID_SONY 0x054C
|
|
+// Lab126's USB Vendor ID
|
|
+#define VENDOR_ID_LAB126 0x1949
|
|
+// Yulong Coolpad's USB Vendor ID
|
|
+#define VENDOR_ID_YULONG_COOLPAD 0x1EBF
|
|
+// Kobo's USB Vendor ID
|
|
+#define VENDOR_ID_KOBO 0x2237
|
|
+// Teleepoch's USB Vendor ID
|
|
+#define VENDOR_ID_TELEEPOCH 0x2340
|
|
+
|
|
+
|
|
+/** built-in vendor list */
|
|
+int builtInVendorIds[] = {
|
|
+ VENDOR_ID_GOOGLE,
|
|
+ VENDOR_ID_INTEL,
|
|
+ VENDOR_ID_HTC,
|
|
+ VENDOR_ID_SAMSUNG,
|
|
+ VENDOR_ID_MOTOROLA,
|
|
+ VENDOR_ID_LGE,
|
|
+ VENDOR_ID_HUAWEI,
|
|
+ VENDOR_ID_ACER,
|
|
+ VENDOR_ID_SONY_ERICSSON,
|
|
+ VENDOR_ID_FOXCONN,
|
|
+ VENDOR_ID_DELL,
|
|
+ VENDOR_ID_NVIDIA,
|
|
+ VENDOR_ID_GARMIN_ASUS,
|
|
+ VENDOR_ID_SHARP,
|
|
+ VENDOR_ID_ZTE,
|
|
+ VENDOR_ID_KYOCERA,
|
|
+ VENDOR_ID_PANTECH,
|
|
+ VENDOR_ID_QUALCOMM,
|
|
+ VENDOR_ID_OTGV,
|
|
+ VENDOR_ID_NEC,
|
|
+ VENDOR_ID_PMC,
|
|
+ VENDOR_ID_TOSHIBA,
|
|
+ VENDOR_ID_SK_TELESYS,
|
|
+ VENDOR_ID_KT_TECH,
|
|
+ VENDOR_ID_ASUS,
|
|
+ VENDOR_ID_PHILIPS,
|
|
+ VENDOR_ID_TI,
|
|
+ VENDOR_ID_FUNAI,
|
|
+ VENDOR_ID_GIGABYTE,
|
|
+ VENDOR_ID_IRIVER,
|
|
+ VENDOR_ID_COMPAL,
|
|
+ VENDOR_ID_T_AND_A,
|
|
+ VENDOR_ID_LENOVOMOBILE,
|
|
+ VENDOR_ID_LENOVO,
|
|
+ VENDOR_ID_VIZIO,
|
|
+ VENDOR_ID_K_TOUCH,
|
|
+ VENDOR_ID_PEGATRON,
|
|
+ VENDOR_ID_ARCHOS,
|
|
+ VENDOR_ID_POSITIVO,
|
|
+ VENDOR_ID_FUJITSU,
|
|
+ VENDOR_ID_LUMIGON,
|
|
+ VENDOR_ID_QUANTA,
|
|
+ VENDOR_ID_INQ_MOBILE,
|
|
+ VENDOR_ID_SONY,
|
|
+ VENDOR_ID_LAB126,
|
|
+ VENDOR_ID_YULONG_COOLPAD,
|
|
+ VENDOR_ID_KOBO,
|
|
+ VENDOR_ID_TELEEPOCH,
|
|
+};
|
|
+
|
|
+#define BUILT_IN_VENDOR_COUNT (sizeof(builtInVendorIds)/sizeof(builtInVendorIds[0]))
|
|
+
|
|
+/* max number of supported vendor ids (built-in + 3rd party). increase as needed */
|
|
+#define VENDOR_COUNT_MAX 128
|
|
+
|
|
+int vendorIds[VENDOR_COUNT_MAX];
|
|
+unsigned vendorIdCount = 0;
|
|
+
|
|
+int get_adb_usb_ini(char* buff, size_t len);
|
|
+
|
|
+void usb_vendors_init(void)
|
|
+{
|
|
+ if (VENDOR_COUNT_MAX < BUILT_IN_VENDOR_COUNT) {
|
|
+ fprintf(stderr, "VENDOR_COUNT_MAX not big enough for built-in vendor list.\n");
|
|
+ exit(2);
|
|
+ }
|
|
+
|
|
+ /* add the built-in vendors at the beginning of the array */
|
|
+ memcpy(vendorIds, builtInVendorIds, sizeof(builtInVendorIds));
|
|
+
|
|
+ /* default array size is the number of built-in vendors */
|
|
+ vendorIdCount = BUILT_IN_VENDOR_COUNT;
|
|
+
|
|
+ if (VENDOR_COUNT_MAX == BUILT_IN_VENDOR_COUNT)
|
|
+ return;
|
|
+
|
|
+ char temp[PATH_MAX];
|
|
+ if (get_adb_usb_ini(temp, sizeof(temp)) == 0) {
|
|
+ FILE * f = fopen(temp, "rt");
|
|
+
|
|
+ if (f != NULL) {
|
|
+ /* The vendor id file is pretty basic. 1 vendor id per line.
|
|
+ Lines starting with # are comments */
|
|
+ while (fgets(temp, sizeof(temp), f) != NULL) {
|
|
+ if (temp[0] == '#')
|
|
+ continue;
|
|
+
|
|
+ long value = strtol(temp, NULL, 0);
|
|
+ if (errno == EINVAL || errno == ERANGE || value > INT_MAX || value < 0) {
|
|
+ fprintf(stderr, "Invalid content in %s. Quitting.\n", ANDROID_ADB_INI);
|
|
+ exit(2);
|
|
+ }
|
|
+
|
|
+ vendorIds[vendorIdCount++] = (int)value;
|
|
+
|
|
+ /* make sure we don't go beyond the array */
|
|
+ if (vendorIdCount == VENDOR_COUNT_MAX) {
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+/* Utils methods */
|
|
+
|
|
+/* builds the path to the adb vendor id file. returns 0 if success */
|
|
+int build_path(char* buff, size_t len, const char* format, const char* home)
|
|
+{
|
|
+ if (snprintf(buff, len, format, home, ANDROID_PATH, ANDROID_ADB_INI) >= (signed)len) {
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* fills buff with the path to the adb vendor id file. returns 0 if success */
|
|
+int get_adb_usb_ini(char* buff, size_t len)
|
|
+{
|
|
+#ifdef _WIN32
|
|
+ const char* home = getenv("ANDROID_SDK_HOME");
|
|
+ if (home != NULL) {
|
|
+ return build_path(buff, len, "%s\\%s\\%s", home);
|
|
+ } else {
|
|
+ char path[MAX_PATH];
|
|
+ SHGetFolderPath( NULL, CSIDL_PROFILE, NULL, 0, path);
|
|
+ return build_path(buff, len, "%s\\%s\\%s", path);
|
|
+ }
|
|
+#else
|
|
+ const char* home = getenv("HOME");
|
|
+ if (home == NULL)
|
|
+ home = "/tmp";
|
|
+
|
|
+ return build_path(buff, len, "%s/%s/%s", home);
|
|
+#endif
|
|
+}
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/usb_vendors.h
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/usb_vendors.h 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,25 @@
|
|
+/*
|
|
+ * Copyright (C) 2009 The Android Open Source Project
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
+ * you may not use this file except in compliance with the License.
|
|
+ * You may obtain a copy of the License at
|
|
+ *
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
+ *
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+ * See the License for the specific language governing permissions and
|
|
+ * limitations under the License.
|
|
+ */
|
|
+
|
|
+#ifndef __USB_VENDORS_H
|
|
+#define __USB_VENDORS_H
|
|
+
|
|
+extern int vendorIds[];
|
|
+extern unsigned vendorIdCount;
|
|
+
|
|
+void usb_vendors_init(void);
|
|
+
|
|
+#endif
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/usb_windows.c
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/usb_windows.c 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,515 @@
|
|
+/*
|
|
+ * Copyright (C) 2007 The Android Open Source Project
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
+ * you may not use this file except in compliance with the License.
|
|
+ * You may obtain a copy of the License at
|
|
+ *
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
+ *
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+ * See the License for the specific language governing permissions and
|
|
+ * limitations under the License.
|
|
+ */
|
|
+
|
|
+#include <windows.h>
|
|
+#include <winerror.h>
|
|
+#include <errno.h>
|
|
+#include <usb100.h>
|
|
+#include <adb_api.h>
|
|
+#include <stdio.h>
|
|
+
|
|
+#include "sysdeps.h"
|
|
+
|
|
+#define TRACE_TAG TRACE_USB
|
|
+#include "adb.h"
|
|
+
|
|
+/** Structure usb_handle describes our connection to the usb device via
|
|
+ AdbWinApi.dll. This structure is returned from usb_open() routine and
|
|
+ is expected in each subsequent call that is accessing the device.
|
|
+*/
|
|
+struct usb_handle {
|
|
+ /// Previous entry in the list of opened usb handles
|
|
+ usb_handle *prev;
|
|
+
|
|
+ /// Next entry in the list of opened usb handles
|
|
+ usb_handle *next;
|
|
+
|
|
+ /// Handle to USB interface
|
|
+ ADBAPIHANDLE adb_interface;
|
|
+
|
|
+ /// Handle to USB read pipe (endpoint)
|
|
+ ADBAPIHANDLE adb_read_pipe;
|
|
+
|
|
+ /// Handle to USB write pipe (endpoint)
|
|
+ ADBAPIHANDLE adb_write_pipe;
|
|
+
|
|
+ /// Interface name
|
|
+ char* interface_name;
|
|
+
|
|
+ /// Mask for determining when to use zero length packets
|
|
+ unsigned zero_mask;
|
|
+};
|
|
+
|
|
+/// Class ID assigned to the device by androidusb.sys
|
|
+static const GUID usb_class_id = ANDROID_USB_CLASS_ID;
|
|
+
|
|
+/// List of opened usb handles
|
|
+static usb_handle handle_list = {
|
|
+ .prev = &handle_list,
|
|
+ .next = &handle_list,
|
|
+};
|
|
+
|
|
+/// Locker for the list of opened usb handles
|
|
+ADB_MUTEX_DEFINE( usb_lock );
|
|
+
|
|
+/// Checks if there is opened usb handle in handle_list for this device.
|
|
+int known_device(const char* dev_name);
|
|
+
|
|
+/// Checks if there is opened usb handle in handle_list for this device.
|
|
+/// usb_lock mutex must be held before calling this routine.
|
|
+int known_device_locked(const char* dev_name);
|
|
+
|
|
+/// Registers opened usb handle (adds it to handle_list).
|
|
+int register_new_device(usb_handle* handle);
|
|
+
|
|
+/// Checks if interface (device) matches certain criteria
|
|
+int recognized_device(usb_handle* handle);
|
|
+
|
|
+/// Enumerates present and available interfaces (devices), opens new ones and
|
|
+/// registers usb transport for them.
|
|
+void find_devices();
|
|
+
|
|
+/// Entry point for thread that polls (every second) for new usb interfaces.
|
|
+/// This routine calls find_devices in infinite loop.
|
|
+void* device_poll_thread(void* unused);
|
|
+
|
|
+/// Initializes this module
|
|
+void usb_init();
|
|
+
|
|
+/// Cleans up this module
|
|
+void usb_cleanup();
|
|
+
|
|
+/// Opens usb interface (device) by interface (device) name.
|
|
+usb_handle* do_usb_open(const wchar_t* interface_name);
|
|
+
|
|
+/// Writes data to the opened usb handle
|
|
+int usb_write(usb_handle* handle, const void* data, int len);
|
|
+
|
|
+/// Reads data using the opened usb handle
|
|
+int usb_read(usb_handle *handle, void* data, int len);
|
|
+
|
|
+/// Cleans up opened usb handle
|
|
+void usb_cleanup_handle(usb_handle* handle);
|
|
+
|
|
+/// Cleans up (but don't close) opened usb handle
|
|
+void usb_kick(usb_handle* handle);
|
|
+
|
|
+/// Closes opened usb handle
|
|
+int usb_close(usb_handle* handle);
|
|
+
|
|
+/// Gets interface (device) name for an opened usb handle
|
|
+const char *usb_name(usb_handle* handle);
|
|
+
|
|
+int known_device_locked(const char* dev_name) {
|
|
+ usb_handle* usb;
|
|
+
|
|
+ if (NULL != dev_name) {
|
|
+ // Iterate through the list looking for the name match.
|
|
+ for(usb = handle_list.next; usb != &handle_list; usb = usb->next) {
|
|
+ // In Windows names are not case sensetive!
|
|
+ if((NULL != usb->interface_name) &&
|
|
+ (0 == stricmp(usb->interface_name, dev_name))) {
|
|
+ return 1;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int known_device(const char* dev_name) {
|
|
+ int ret = 0;
|
|
+
|
|
+ if (NULL != dev_name) {
|
|
+ adb_mutex_lock(&usb_lock);
|
|
+ ret = known_device_locked(dev_name);
|
|
+ adb_mutex_unlock(&usb_lock);
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+int register_new_device(usb_handle* handle) {
|
|
+ if (NULL == handle)
|
|
+ return 0;
|
|
+
|
|
+ adb_mutex_lock(&usb_lock);
|
|
+
|
|
+ // Check if device is already in the list
|
|
+ if (known_device_locked(handle->interface_name)) {
|
|
+ adb_mutex_unlock(&usb_lock);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ // Not in the list. Add this handle to the list.
|
|
+ handle->next = &handle_list;
|
|
+ handle->prev = handle_list.prev;
|
|
+ handle->prev->next = handle;
|
|
+ handle->next->prev = handle;
|
|
+
|
|
+ adb_mutex_unlock(&usb_lock);
|
|
+
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+void* device_poll_thread(void* unused) {
|
|
+ D("Created device thread\n");
|
|
+
|
|
+ while(1) {
|
|
+ find_devices();
|
|
+ adb_sleep_ms(1000);
|
|
+ }
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+void usb_init() {
|
|
+ adb_thread_t tid;
|
|
+
|
|
+ if(adb_thread_create(&tid, device_poll_thread, NULL)) {
|
|
+ fatal_errno("cannot create input thread");
|
|
+ }
|
|
+}
|
|
+
|
|
+void usb_cleanup() {
|
|
+}
|
|
+
|
|
+usb_handle* do_usb_open(const wchar_t* interface_name) {
|
|
+ // Allocate our handle
|
|
+ usb_handle* ret = (usb_handle*)malloc(sizeof(usb_handle));
|
|
+ if (NULL == ret)
|
|
+ return NULL;
|
|
+
|
|
+ // Set linkers back to the handle
|
|
+ ret->next = ret;
|
|
+ ret->prev = ret;
|
|
+
|
|
+ // Create interface.
|
|
+ ret->adb_interface = AdbCreateInterfaceByName(interface_name);
|
|
+
|
|
+ if (NULL == ret->adb_interface) {
|
|
+ free(ret);
|
|
+ errno = GetLastError();
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ // Open read pipe (endpoint)
|
|
+ ret->adb_read_pipe =
|
|
+ AdbOpenDefaultBulkReadEndpoint(ret->adb_interface,
|
|
+ AdbOpenAccessTypeReadWrite,
|
|
+ AdbOpenSharingModeReadWrite);
|
|
+ if (NULL != ret->adb_read_pipe) {
|
|
+ // Open write pipe (endpoint)
|
|
+ ret->adb_write_pipe =
|
|
+ AdbOpenDefaultBulkWriteEndpoint(ret->adb_interface,
|
|
+ AdbOpenAccessTypeReadWrite,
|
|
+ AdbOpenSharingModeReadWrite);
|
|
+ if (NULL != ret->adb_write_pipe) {
|
|
+ // Save interface name
|
|
+ unsigned long name_len = 0;
|
|
+
|
|
+ // First get expected name length
|
|
+ AdbGetInterfaceName(ret->adb_interface,
|
|
+ NULL,
|
|
+ &name_len,
|
|
+ true);
|
|
+ if (0 != name_len) {
|
|
+ ret->interface_name = (char*)malloc(name_len);
|
|
+
|
|
+ if (NULL != ret->interface_name) {
|
|
+ // Now save the name
|
|
+ if (AdbGetInterfaceName(ret->adb_interface,
|
|
+ ret->interface_name,
|
|
+ &name_len,
|
|
+ true)) {
|
|
+ // We're done at this point
|
|
+ return ret;
|
|
+ }
|
|
+ } else {
|
|
+ SetLastError(ERROR_OUTOFMEMORY);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // Something went wrong.
|
|
+ int saved_errno = GetLastError();
|
|
+ usb_cleanup_handle(ret);
|
|
+ free(ret);
|
|
+ SetLastError(saved_errno);
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+int usb_write(usb_handle* handle, const void* data, int len) {
|
|
+ unsigned long time_out = 5000;
|
|
+ unsigned long written = 0;
|
|
+ int ret;
|
|
+
|
|
+ D("usb_write %d\n", len);
|
|
+ if (NULL != handle) {
|
|
+ // Perform write
|
|
+ ret = AdbWriteEndpointSync(handle->adb_write_pipe,
|
|
+ (void*)data,
|
|
+ (unsigned long)len,
|
|
+ &written,
|
|
+ time_out);
|
|
+ int saved_errno = GetLastError();
|
|
+
|
|
+ if (ret) {
|
|
+ // Make sure that we've written what we were asked to write
|
|
+ D("usb_write got: %ld, expected: %d\n", written, len);
|
|
+ if (written == (unsigned long)len) {
|
|
+ if(handle->zero_mask && (len & handle->zero_mask) == 0) {
|
|
+ // Send a zero length packet
|
|
+ AdbWriteEndpointSync(handle->adb_write_pipe,
|
|
+ (void*)data,
|
|
+ 0,
|
|
+ &written,
|
|
+ time_out);
|
|
+ }
|
|
+ return 0;
|
|
+ }
|
|
+ } else {
|
|
+ // assume ERROR_INVALID_HANDLE indicates we are disconnected
|
|
+ if (saved_errno == ERROR_INVALID_HANDLE)
|
|
+ usb_kick(handle);
|
|
+ }
|
|
+ errno = saved_errno;
|
|
+ } else {
|
|
+ D("usb_write NULL handle\n");
|
|
+ SetLastError(ERROR_INVALID_HANDLE);
|
|
+ }
|
|
+
|
|
+ D("usb_write failed: %d\n", errno);
|
|
+
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+int usb_read(usb_handle *handle, void* data, int len) {
|
|
+ unsigned long time_out = 0;
|
|
+ unsigned long read = 0;
|
|
+ int ret;
|
|
+
|
|
+ D("usb_read %d\n", len);
|
|
+ if (NULL != handle) {
|
|
+ while (len > 0) {
|
|
+ int xfer = (len > 4096) ? 4096 : len;
|
|
+
|
|
+ ret = AdbReadEndpointSync(handle->adb_read_pipe,
|
|
+ (void*)data,
|
|
+ (unsigned long)xfer,
|
|
+ &read,
|
|
+ time_out);
|
|
+ int saved_errno = GetLastError();
|
|
+ D("usb_write got: %ld, expected: %d, errno: %d\n", read, xfer, saved_errno);
|
|
+ if (ret) {
|
|
+ data += read;
|
|
+ len -= read;
|
|
+
|
|
+ if (len == 0)
|
|
+ return 0;
|
|
+ } else {
|
|
+ // assume ERROR_INVALID_HANDLE indicates we are disconnected
|
|
+ if (saved_errno == ERROR_INVALID_HANDLE)
|
|
+ usb_kick(handle);
|
|
+ break;
|
|
+ }
|
|
+ errno = saved_errno;
|
|
+ }
|
|
+ } else {
|
|
+ D("usb_read NULL handle\n");
|
|
+ SetLastError(ERROR_INVALID_HANDLE);
|
|
+ }
|
|
+
|
|
+ D("usb_read failed: %d\n", errno);
|
|
+
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+void usb_cleanup_handle(usb_handle* handle) {
|
|
+ if (NULL != handle) {
|
|
+ if (NULL != handle->interface_name)
|
|
+ free(handle->interface_name);
|
|
+ if (NULL != handle->adb_write_pipe)
|
|
+ AdbCloseHandle(handle->adb_write_pipe);
|
|
+ if (NULL != handle->adb_read_pipe)
|
|
+ AdbCloseHandle(handle->adb_read_pipe);
|
|
+ if (NULL != handle->adb_interface)
|
|
+ AdbCloseHandle(handle->adb_interface);
|
|
+
|
|
+ handle->interface_name = NULL;
|
|
+ handle->adb_write_pipe = NULL;
|
|
+ handle->adb_read_pipe = NULL;
|
|
+ handle->adb_interface = NULL;
|
|
+ }
|
|
+}
|
|
+
|
|
+void usb_kick(usb_handle* handle) {
|
|
+ if (NULL != handle) {
|
|
+ adb_mutex_lock(&usb_lock);
|
|
+
|
|
+ usb_cleanup_handle(handle);
|
|
+
|
|
+ adb_mutex_unlock(&usb_lock);
|
|
+ } else {
|
|
+ SetLastError(ERROR_INVALID_HANDLE);
|
|
+ errno = ERROR_INVALID_HANDLE;
|
|
+ }
|
|
+}
|
|
+
|
|
+int usb_close(usb_handle* handle) {
|
|
+ D("usb_close\n");
|
|
+
|
|
+ if (NULL != handle) {
|
|
+ // Remove handle from the list
|
|
+ adb_mutex_lock(&usb_lock);
|
|
+
|
|
+ if ((handle->next != handle) && (handle->prev != handle)) {
|
|
+ handle->next->prev = handle->prev;
|
|
+ handle->prev->next = handle->next;
|
|
+ handle->prev = handle;
|
|
+ handle->next = handle;
|
|
+ }
|
|
+
|
|
+ adb_mutex_unlock(&usb_lock);
|
|
+
|
|
+ // Cleanup handle
|
|
+ usb_cleanup_handle(handle);
|
|
+ free(handle);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+const char *usb_name(usb_handle* handle) {
|
|
+ if (NULL == handle) {
|
|
+ SetLastError(ERROR_INVALID_HANDLE);
|
|
+ errno = ERROR_INVALID_HANDLE;
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ return (const char*)handle->interface_name;
|
|
+}
|
|
+
|
|
+int recognized_device(usb_handle* handle) {
|
|
+ if (NULL == handle)
|
|
+ return 0;
|
|
+
|
|
+ // Check vendor and product id first
|
|
+ USB_DEVICE_DESCRIPTOR device_desc;
|
|
+
|
|
+ if (!AdbGetUsbDeviceDescriptor(handle->adb_interface,
|
|
+ &device_desc)) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ // Then check interface properties
|
|
+ USB_INTERFACE_DESCRIPTOR interf_desc;
|
|
+
|
|
+ if (!AdbGetUsbInterfaceDescriptor(handle->adb_interface,
|
|
+ &interf_desc)) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ // Must have two endpoints
|
|
+ if (2 != interf_desc.bNumEndpoints) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (is_adb_interface(device_desc.idVendor, device_desc.idProduct,
|
|
+ interf_desc.bInterfaceClass, interf_desc.bInterfaceSubClass, interf_desc.bInterfaceProtocol)) {
|
|
+
|
|
+ if(interf_desc.bInterfaceProtocol == 0x01) {
|
|
+ AdbEndpointInformation endpoint_info;
|
|
+ // assuming zero is a valid bulk endpoint ID
|
|
+ if (AdbGetEndpointInformation(handle->adb_interface, 0, &endpoint_info)) {
|
|
+ handle->zero_mask = endpoint_info.max_packet_size - 1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void find_devices() {
|
|
+ usb_handle* handle = NULL;
|
|
+ char entry_buffer[2048];
|
|
+ char interf_name[2048];
|
|
+ AdbInterfaceInfo* next_interface = (AdbInterfaceInfo*)(&entry_buffer[0]);
|
|
+ unsigned long entry_buffer_size = sizeof(entry_buffer);
|
|
+ char* copy_name;
|
|
+
|
|
+ // Enumerate all present and active interfaces.
|
|
+ ADBAPIHANDLE enum_handle =
|
|
+ AdbEnumInterfaces(usb_class_id, true, true, true);
|
|
+
|
|
+ if (NULL == enum_handle)
|
|
+ return;
|
|
+
|
|
+ while (AdbNextInterface(enum_handle, next_interface, &entry_buffer_size)) {
|
|
+ // TODO: FIXME - temp hack converting wchar_t into char.
|
|
+ // It would be better to change AdbNextInterface so it will return
|
|
+ // interface name as single char string.
|
|
+ const wchar_t* wchar_name = next_interface->device_name;
|
|
+ for(copy_name = interf_name;
|
|
+ L'\0' != *wchar_name;
|
|
+ wchar_name++, copy_name++) {
|
|
+ *copy_name = (char)(*wchar_name);
|
|
+ }
|
|
+ *copy_name = '\0';
|
|
+
|
|
+ // Lets see if we already have this device in the list
|
|
+ if (!known_device(interf_name)) {
|
|
+ // This seems to be a new device. Open it!
|
|
+ handle = do_usb_open(next_interface->device_name);
|
|
+ if (NULL != handle) {
|
|
+ // Lets see if this interface (device) belongs to us
|
|
+ if (recognized_device(handle)) {
|
|
+ D("adding a new device %s\n", interf_name);
|
|
+ char serial_number[512];
|
|
+ unsigned long serial_number_len = sizeof(serial_number);
|
|
+ if (AdbGetSerialNumber(handle->adb_interface,
|
|
+ serial_number,
|
|
+ &serial_number_len,
|
|
+ true)) {
|
|
+ // Lets make sure that we don't duplicate this device
|
|
+ if (register_new_device(handle)) {
|
|
+ register_usb_transport(handle, serial_number, NULL, 1);
|
|
+ } else {
|
|
+ D("register_new_device failed for %s\n", interf_name);
|
|
+ usb_cleanup_handle(handle);
|
|
+ free(handle);
|
|
+ }
|
|
+ } else {
|
|
+ D("cannot get serial number\n");
|
|
+ usb_cleanup_handle(handle);
|
|
+ free(handle);
|
|
+ }
|
|
+ } else {
|
|
+ usb_cleanup_handle(handle);
|
|
+ free(handle);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ entry_buffer_size = sizeof(entry_buffer);
|
|
+ }
|
|
+
|
|
+ AdbCloseHandle(enum_handle);
|
|
+}
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/utils.c
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/utils.c 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,106 @@
|
|
+/*
|
|
+ * Copyright (C) 2008 The Android Open Source Project
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
+ * you may not use this file except in compliance with the License.
|
|
+ * You may obtain a copy of the License at
|
|
+ *
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
+ *
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+ * See the License for the specific language governing permissions and
|
|
+ * limitations under the License.
|
|
+ */
|
|
+#include "utils.h"
|
|
+#include <stdarg.h>
|
|
+#include <stdio.h>
|
|
+#include <string.h>
|
|
+
|
|
+char*
|
|
+buff_addc (char* buff, char* buffEnd, int c)
|
|
+{
|
|
+ int avail = buffEnd - buff;
|
|
+
|
|
+ if (avail <= 0) /* already in overflow mode */
|
|
+ return buff;
|
|
+
|
|
+ if (avail == 1) { /* overflowing, the last byte is reserved for zero */
|
|
+ buff[0] = 0;
|
|
+ return buff + 1;
|
|
+ }
|
|
+
|
|
+ buff[0] = (char) c; /* add char and terminating zero */
|
|
+ buff[1] = 0;
|
|
+ return buff + 1;
|
|
+}
|
|
+
|
|
+char*
|
|
+buff_adds (char* buff, char* buffEnd, const char* s)
|
|
+{
|
|
+ int slen = strlen(s);
|
|
+
|
|
+ return buff_addb(buff, buffEnd, s, slen);
|
|
+}
|
|
+
|
|
+char*
|
|
+buff_addb (char* buff, char* buffEnd, const void* data, int len)
|
|
+{
|
|
+ int avail = (buffEnd - buff);
|
|
+
|
|
+ if (avail <= 0 || len <= 0) /* already overflowing */
|
|
+ return buff;
|
|
+
|
|
+ if (len > avail)
|
|
+ len = avail;
|
|
+
|
|
+ memcpy(buff, data, len);
|
|
+
|
|
+ buff += len;
|
|
+
|
|
+ /* ensure there is a terminating zero */
|
|
+ if (buff >= buffEnd) { /* overflow */
|
|
+ buff[-1] = 0;
|
|
+ } else
|
|
+ buff[0] = 0;
|
|
+
|
|
+ return buff;
|
|
+}
|
|
+
|
|
+char*
|
|
+buff_add (char* buff, char* buffEnd, const char* format, ... )
|
|
+{
|
|
+ int avail;
|
|
+
|
|
+ avail = (buffEnd - buff);
|
|
+
|
|
+ if (avail > 0) {
|
|
+ va_list args;
|
|
+ int nn;
|
|
+
|
|
+ va_start(args, format);
|
|
+ nn = vsnprintf( buff, avail, format, args);
|
|
+ va_end(args);
|
|
+
|
|
+ if (nn < 0) {
|
|
+ /* some C libraries return -1 in case of overflow,
|
|
+ * but they will also do that if the format spec is
|
|
+ * invalid. We assume ADB is not buggy enough to
|
|
+ * trigger that last case. */
|
|
+ nn = avail;
|
|
+ }
|
|
+ else if (nn > avail) {
|
|
+ nn = avail;
|
|
+ }
|
|
+
|
|
+ buff += nn;
|
|
+
|
|
+ /* ensure that there is a terminating zero */
|
|
+ if (buff >= buffEnd)
|
|
+ buff[-1] = 0;
|
|
+ else
|
|
+ buff[0] = 0;
|
|
+ }
|
|
+ return buff;
|
|
+}
|
|
Index: android-tools-4.2.2+git20130218/core/adbd/utils.h
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ android-tools-4.2.2+git20130218/core/adbd/utils.h 2013-06-18 17:12:17.000000000 -0300
|
|
@@ -0,0 +1,68 @@
|
|
+/*
|
|
+ * Copyright (C) 2008 The Android Open Source Project
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
+ * you may not use this file except in compliance with the License.
|
|
+ * You may obtain a copy of the License at
|
|
+ *
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
+ *
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+ * See the License for the specific language governing permissions and
|
|
+ * limitations under the License.
|
|
+ */
|
|
+#ifndef _ADB_UTILS_H
|
|
+#define _ADB_UTILS_H
|
|
+
|
|
+/* bounded buffer functions */
|
|
+
|
|
+/* all these functions are used to append data to a bounded buffer.
|
|
+ *
|
|
+ * after each operation, the buffer is guaranteed to be zero-terminated,
|
|
+ * even in the case of an overflow. they all return the new buffer position
|
|
+ * which allows one to use them in succession, only checking for overflows
|
|
+ * at the end. For example:
|
|
+ *
|
|
+ * BUFF_DECL(temp,p,end,1024);
|
|
+ * char* p;
|
|
+ *
|
|
+ * p = buff_addc(temp, end, '"');
|
|
+ * p = buff_adds(temp, end, string);
|
|
+ * p = buff_addc(temp, end, '"');
|
|
+ *
|
|
+ * if (p >= end) {
|
|
+ * overflow detected. note that 'temp' is
|
|
+ * zero-terminated for safety.
|
|
+ * }
|
|
+ * return strdup(temp);
|
|
+ */
|
|
+
|
|
+/* tries to add a character to the buffer, in case of overflow
|
|
+ * this will only write a terminating zero and return buffEnd.
|
|
+ */
|
|
+char* buff_addc (char* buff, char* buffEnd, int c);
|
|
+
|
|
+/* tries to add a string to the buffer */
|
|
+char* buff_adds (char* buff, char* buffEnd, const char* s);
|
|
+
|
|
+/* tries to add a bytes to the buffer. the input can contain zero bytes,
|
|
+ * but a terminating zero will always be appended at the end anyway
|
|
+ */
|
|
+char* buff_addb (char* buff, char* buffEnd, const void* data, int len);
|
|
+
|
|
+/* tries to add a formatted string to a bounded buffer */
|
|
+char* buff_add (char* buff, char* buffEnd, const char* format, ... );
|
|
+
|
|
+/* convenience macro used to define a bounded buffer, as well as
|
|
+ * a 'cursor' and 'end' variables all in one go.
|
|
+ *
|
|
+ * note: this doesn't place an initial terminating zero in the buffer,
|
|
+ * you need to use one of the buff_ functions for this. or simply
|
|
+ * do _cursor[0] = 0 manually.
|
|
+ */
|
|
+#define BUFF_DECL(_buff,_cursor,_end,_size) \
|
|
+ char _buff[_size], *_cursor=_buff, *_end = _cursor + (_size)
|
|
+
|
|
+#endif /* _ADB_UTILS_H */
|