Revert "[Feature][T8TSK-250][ADBD]add adb debug patch"

This reverts commit 0300fcc023c83b5b569b0c0799aff58cfd65dd39.

Reason for revert: <INSERT REASONING HERE>

Change-Id: I82e92daf5003f885c4732744291c57425ef27642
diff --git a/src/devtools/adb/Makefile b/src/devtools/adb/Makefile
index 9386b84..cf6beac 100644
--- a/src/devtools/adb/Makefile
+++ b/src/devtools/adb/Makefile
@@ -25,6 +25,9 @@
 
 ADBD_SRC_FILES := \
 	file_sync_service.c \
+	adb_auth_client.c \
+	jdwp_service.c \
+	framebuffer_service.c \
 	remount_service.c
 ifneq ($(ADB_OVER_PCIE),1)
 	ADBD_SRC_FILES+= usb_linux_client.c
@@ -40,6 +43,7 @@
 	socket_loopback_server.c \
 	socket_network_client.c \
 	sha.c \
+	rsa.c \
 	sha256.c \
 	logd_write.c \
 	thread_utils.c \
@@ -58,13 +62,6 @@
 
 ifeq ($(ADB_OVER_PCIE),1)
 	LOCAL_CFLAGS+= -DADB_OVER_PCIE=1
-else ifeq ($(UCI_PROPERTY_SUPPORT),1)
-	LOCAL_CFLAGS+= -DUCI_PROPERTY_SUPPORT=1
-	LIBS+= -luci
-endif
-
-ifeq ($(ADB_SERVICE_ENABLE),1)
-    LOCAL_CFLAGS += -DADB_SERVICE_ENABLE
 endif
 
 CPPFLAGS+= -DDZONE -DHAVE_FORKEXEC=1 -DHAVE_SYMLINKS -DHAVE_TERMIO_H
@@ -72,7 +69,7 @@
 CPPFLAGS+= -I. -I./include
 CPPFLAGS+= $(LOCAL_CFLAGS)
 
-LIBS+= -lpthread -lrt
+LIBS += -lpthread -luci
 
 LOCAL_MODULE := adbd
 LOCAL_SRC_FILES+= $(COMMON_SRC_FILES) $(ADBD_SRC_FILES)
diff --git a/src/devtools/adb/adb.c b/src/devtools/adb/adb.c
index 2eb667a..82efb12 100644
--- a/src/devtools/adb/adb.c
+++ b/src/devtools/adb/adb.c
@@ -59,8 +59,6 @@
 static const char *root_seclabel = NULL;
 #endif
 
-int   adb_service_enable = 1;
-
 void fatal(const char *fmt, ...)
 {
     va_list ap;
@@ -120,7 +118,7 @@
 
     /* use a comma/column/semi-colum/space separated list */
     while (*p) {
-        unsigned int  len, tagn;
+        int  len, tagn;
 
         q = strpbrk(p, " ,:;");
         if (q == NULL) {
@@ -238,8 +236,6 @@
     char *tag;
     char *x;
     unsigned count;
-    char data[DUMPMAX+4];
-    int i = 0;
 
     switch(p->msg.command){
     case A_SYNC: tag = "SYNC"; break;
@@ -252,26 +248,25 @@
     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(i < count){
+    while(count-- > 0){
         if((*x >= ' ') && (*x < 127)) {
-            data[i] = *x;
+            fputc(*x, stderr);
         } else {
-            data[i] = '.';
+            fputc('.', stderr);
         }
         x++;
-        i++;
     }
-    data[i++] = '\"';
-    data[i++] = '\n';
-    data[i] = '\0';
-
-    D("%s: %s %08x %08x %04x %s\"",
-            label, tag, p->msg.arg0, p->msg.arg1, p->msg.data_length, data);
+    fputs(tag, stderr);
 }
 #endif
 
@@ -395,6 +390,69 @@
     send_packet(cp, t);
 }
 
+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);
+}
 
 #if ADB_HOST
 static char *connection_state_name(atransport *t)
@@ -562,11 +620,35 @@
 
         parse_banner((char*) p->data, t);
 
-        if (!adb_service_enable) {
-            D("Ignore ADB client CNXN request, ADB keeps disabled");
-        } else if (HOST || !auth_enabled) {
+        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->connection_state = CS_UNAUTHORIZED;
+            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;
 
@@ -944,6 +1026,48 @@
 #endif
 }
 
+void start_logging(void)
+{
+#if defined(_WIN32)
+    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)
 {
@@ -951,19 +1075,34 @@
     char    path[PATH_MAX];
     struct tm now;
     time_t t;
-    char value[PROPERTY_VALUE_MAX] = "";
+    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 || adb_trace_mask == 0)
-    {
-        DD("ADB daemon log DISABLED, adb_trace_mask=0x%x\n", adb_trace_mask);
+    if (sscanf(value, "%x", &adb_trace_mask) != 1)
         return;
-    } else {
-        adb_trace_mask %= (1 <<TRACE_LAST);
-        DD("ADB daemon log to AP log file ENABLED, adb_trace_mask=0x%x\n", adb_trace_mask);
-    }
+
+    adb_mkdir("/tmp/adb", 0775);
+    tzset();
+    time(&t);
+    localtime_r(&t, &now);
+    strftime(path, sizeof(path),
+                "/tmp/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
 
@@ -1194,9 +1333,6 @@
     return 1;
 #else /* ALLOW_ADBD_ROOT */
 #ifdef ADB_NON_ANDROID
-    if (!adb_service_enable) {
-        return 1;
-    }
     return 0;
 #endif /* ADB_NON_ANDROID */
     int secure = 0;
@@ -1261,6 +1397,7 @@
     usb_init();
 #endif
     local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
+    adb_auth_init();
 
     char local_name[30];
     build_local_name(local_name, sizeof(local_name), server_port);
@@ -1268,6 +1405,10 @@
         exit(1);
     }
 #else
+    property_get("ro.adb.secure", value, "0");
+    auth_enabled = !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.
@@ -1357,6 +1498,9 @@
         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)
@@ -1368,6 +1512,7 @@
 #else
         fprintf(stderr, "OK\n");
 #endif
+        start_logging();
     }
     D("Event loop starting\n");
 
@@ -1628,24 +1773,6 @@
     return -1;
 }
 
-void update_enabled_flag() {
-#ifndef ADB_OVER_PCIE
-#ifdef ADB_SERVICE_ENABLE
-    adb_service_enable = 1;
-#else
-    char value[PROPERTY_VALUE_MAX] = "";
-
-    property_get("service.adb.enable", value, "");
-    if (sscanf(value, "%x", &adb_service_enable) != 1) {
-        adb_service_enable = 0;
-    } else if (adb_service_enable != 0) {
-        adb_service_enable = 1;
-    }
-#endif
-#endif
-    printf("ADB service enabled status=%d\n", adb_service_enable);
-}
-
 int main(int argc, char **argv)
 {
 #if ADB_HOST
@@ -1657,7 +1784,7 @@
     /* If adbd runs inside the emulator this will enable adb tracing via
      * adb-debug qemud service in the emulator. */
     //adb_qemu_trace_init();
-    DD("adb main()\n");
+    D("main()\n");
     while(1) {
         int c;
         int option_index = 0;
@@ -1681,8 +1808,7 @@
     }
 
     start_device_log();
-    update_enabled_flag();
-    DD("Handling main()\n");
+    D("Handling main()\n");
     return adb_main(0, DEFAULT_ADB_PORT);
 #endif
 }
diff --git a/src/devtools/adb/adb.h b/src/devtools/adb/adb.h
index f5b4aa0..84d55d8 100644
--- a/src/devtools/adb/adb.h
+++ b/src/devtools/adb/adb.h
@@ -324,9 +324,17 @@
 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
+
 int handle_forward_request(const char* service, transport_type ttype, char* serial, int reply_fd);
 
 #if !ADB_HOST
+void framebuffer_service(int fd, void *cookie);
 void remount_service(int fd, void *cookie);
 #endif
 
diff --git a/src/devtools/adb/adb_auth_client.c b/src/devtools/adb/adb_auth_client.c
new file mode 100644
index 0000000..4ce5d1e
--- /dev/null
+++ b/src/devtools/adb/adb_auth_client.c
@@ -0,0 +1,276 @@
+/*
+ * 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"
+#include "mincrypt/sha.h"
+
+#define TRACE_TAG TRACE_AUTH
+
+#ifdef __GLIBC__
+#ifdef b64_pton
+#undef b64_pton
+#endif
+#endif
+
+struct adb_public_key {
+    struct listnode node;
+    RSAPublicKey key;
+};
+
+static char *key_paths[] = {
+    "/adb_keys",
+    "/data/misc/adb/adb_keys",
+    NULL
+};
+
+static fdevent listener_fde;
+static int framework_fd = -1;
+
+static void usb_disconnected(void* unused, atransport* t);
+static struct adisconnect usb_disconnect = { usb_disconnected, 0, 0, 0 };
+static atransport* usb_transport;
+static bool needs_retry = false;
+
+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, "re");
+    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));
+    }
+}
+
+static void load_keys(struct listnode *list)
+{
+    char *path;
+    char **paths = key_paths;
+    struct stat buf;
+
+    list_init(list);
+
+    while ((path = *paths++)) {
+        if (!stat(path, &buf)) {
+            D("Loading keys from '%s'\n", path);
+            read_keys(path, list);
+        }
+    }
+}
+
+int adb_auth_generate_token(void *token, size_t token_size)
+{
+    FILE *f;
+    int ret;
+
+    f = fopen("/dev/urandom", "re");
+    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;
+    struct listnode key_list;
+    int ret = 0;
+
+    if (siglen != RSANUMBYTES)
+        return 0;
+
+    load_keys(&key_list);
+
+    list_for_each(item, &key_list) {
+        key = node_to_item(item, struct adb_public_key, node);
+        ret = RSA_verify(&key->key, sig, siglen, token, SHA_DIGEST_SIZE);
+        if (ret)
+            break;
+    }
+
+    free_keys(&key_list);
+
+    return ret;
+}
+
+static void usb_disconnected(void* unused, atransport* t)
+{
+    D("USB disconnect\n");
+    remove_transport_disconnect(usb_transport, &usb_disconnect);
+    usb_transport = NULL;
+    needs_retry = false;
+}
+
+static void adb_auth_event(int fd, unsigned events, void *data)
+{
+    char response[2];
+    int ret;
+
+    if (events & FDE_READ) {
+        ret = unix_read(fd, response, sizeof(response));
+        if (ret <= 0) {
+            D("Framework disconnect\n");
+            if (usb_transport)
+                fdevent_remove(&usb_transport->auth_fde);
+            framework_fd = -1;
+        }
+        else if (ret == 2 && response[0] == 'O' && response[1] == 'K') {
+            if (usb_transport)
+                adb_auth_verified(usb_transport);
+        }
+    }
+}
+
+void adb_auth_confirm_key(unsigned char *key, size_t len, atransport *t)
+{
+    char msg[MAX_PAYLOAD];
+    int ret;
+
+    if (!usb_transport) {
+        usb_transport = t;
+        add_transport_disconnect(t, &usb_disconnect);
+    }
+
+    if (framework_fd < 0) {
+        D("Client not connected\n");
+        needs_retry = true;
+        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;
+
+    if (needs_retry) {
+        needs_retry = false;
+        send_auth_request(usb_transport);
+    }
+}
+
+void adb_auth_init(void)
+{
+    int fd, ret;
+
+    fd = android_get_control_socket("adbd");
+    if (fd < 0) {
+        D("Failed to get adbd socket\n");
+        printf("Failed to get adbd socket\n");
+        return;
+    }
+    fcntl(fd, F_SETFD, FD_CLOEXEC);
+
+    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);
+}
diff --git a/src/devtools/adb/adb_trace.h b/src/devtools/adb/adb_trace.h
index 2039dbe..32c3cc6 100644
--- a/src/devtools/adb/adb_trace.h
+++ b/src/devtools/adb/adb_trace.h
@@ -22,7 +22,7 @@
 #endif
 
 /* define ADB_TRACE to 1 to enable tracing support, or 0 to disable it */
-#define  ADB_TRACE    1
+#define  ADB_TRACE    0
 
 /* IMPORTANT: if you change the following list, don't
  * forget to update the corresponding 'tags' table in
@@ -41,7 +41,6 @@
     TRACE_SERVICES,
     TRACE_AUTH,
     TRACE_FDEVENT,
-    TRACE_LAST,      /* 0x1000 */
 } AdbTrace;
 
 #if ADB_TRACE
diff --git a/src/devtools/adb/adb_trace.h.bak b/src/devtools/adb/adb_trace.h.bak
deleted file mode 100644
index d21a041..0000000
--- a/src/devtools/adb/adb_trace.h.bak
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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_TRACE_H
-#define __ADB_TRACE_H
-
-#if !ADB_HOST
-#include <android/log.h>
-#endif
-
-#include <syslog.h>
-
-#define LOG_ERR     1
-#define LOG_WARNING 2
-#define LOG_INFO    3
-#define LOG_DEBUG   4
-
-/* 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,
-    TRACE_FDEVENT,
-    TRACE_LAST,      /* 0x1000 */
-} 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 */
-#if ADB_HOST
-#  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)
-#  define  DD(...)                                     \
-        do {                                           \
-          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)
-#else
-#  define  D(...)                                      \
-        do {                                           \
-            if (ADB_TRACING) {                         \
-                __android_log_print(                   \
-                    ANDROID_LOG_INFO,                  \
-                    __FUNCTION__,                      \
-                    __VA_ARGS__ );                     \
-            }                                          \
-        } while (0)
-#  define  DR(...)                                     \
-        do {                                           \
-            if (ADB_TRACING) {                         \
-                __android_log_print(                   \
-                    ANDROID_LOG_INFO,                  \
-                    __FUNCTION__,                      \
-                    __VA_ARGS__ );                     \
-            }                                          \
-        } while (0)
-#  define  DD(...)                                     \
-        do {                                           \
-          __android_log_print(                         \
-              ANDROID_LOG_INFO,                        \
-              __FUNCTION__,                            \
-              __VA_ARGS__ );                           \
-        } while (0)
-#endif /* ADB_HOST */
-#else
-#  define  D(...)          ((void)0)
-#  define  DR(...)         ((void)0)
-#  define  DD(...)         ((void)0)
-#  define  ADB_TRACING     0
-#endif /* ADB_TRACE */
-
-#endif /* __ADB_TRACE_H */
diff --git a/src/devtools/adb/adbd_pcie.init b/src/devtools/adb/adbd_pcie.init
index 078bd10..d8bf1af 100644
--- a/src/devtools/adb/adbd_pcie.init
+++ b/src/devtools/adb/adbd_pcie.init
@@ -7,10 +7,9 @@
 
 start_service() {
     echo "start adbd_pcie"
-    procd_open_instance adbd_pcie
     procd_set_param stdout 1
     procd_set_param stderr 1
-    procd_set_param env ADBD_TRACE=0
+    procd_open_instance adbd_pcie
     procd_set_param command /sbin/adbd_pcie
     procd_set_param respawn
     procd_close_instance
diff --git a/src/devtools/adb/b64_pton.c b/src/devtools/adb/b64_pton.c
index 351309b..e5c3153 100644
--- a/src/devtools/adb/b64_pton.c
+++ b/src/devtools/adb/b64_pton.c
@@ -170,8 +170,7 @@
 static int
 b64_pton_do(char const *src, uint8_t *target, size_t targsize)
 {
-	int state;
-	unsigned int tarindex, ch;
+	int tarindex, state, ch;
 	uint8_t ofs;
 
 	state = 0;
@@ -288,8 +287,7 @@
 static int
 b64_pton_len(char const *src)
 {
-	int tarindex, state;
-	unsigned int  ch;
+	int tarindex, state, ch;
 	uint8_t ofs;
 
 	state = 0;
diff --git a/src/devtools/adb/commandline.c b/src/devtools/adb/commandline.c
index 7a48c4c..1a85de2 100644
--- a/src/devtools/adb/commandline.c
+++ b/src/devtools/adb/commandline.c
@@ -41,6 +41,8 @@
 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, char **vendor_srcdir_out);
 int install_app(transport_type transport, char* serial, int argc, char** argv);
 int install_multiple_app(transport_type transport, char* serial, int argc, char** argv);
 int uninstall_app(transport_type transport, char* serial, int argc, char** argv);
@@ -1642,6 +1644,42 @@
         return uninstall_app(ttype, serial, argc, argv);
     }
 
+    if(!strcmp(argv[0], "sync")) {
+        char *srcarg, *android_srcpath, *data_srcpath, *vendor_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, &vendor_srcpath);
+        if(ret != 0) return usage();
+
+        if(android_srcpath != NULL)
+            ret = do_sync_sync(android_srcpath, "/system", listonly);
+        if(ret == 0 && vendor_srcpath != NULL)
+            ret = do_sync_sync(vendor_srcpath, "/vendor", listonly);
+        if(ret == 0 && data_srcpath != NULL)
+            ret = do_sync_sync(data_srcpath, "/data", listonly);
+
+        free(android_srcpath);
+        free(vendor_srcpath);
+        free(data_srcpath);
+        return ret;
+    }
 
     /* passthrough commands */
 
@@ -1689,6 +1727,18 @@
         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();
@@ -1740,6 +1790,53 @@
     return adb_commandline(argc, argv);
 }
 
+int find_sync_dirs(const char *srcarg,
+        char **android_srcdir_out, char **data_srcdir_out, char **vendor_srcdir_out)
+{
+    char *android_srcdir = NULL, *data_srcdir = NULL, *vendor_srcdir = NULL;
+    struct stat st;
+
+    if(srcarg == NULL) {
+        android_srcdir = product_file("system");
+        data_srcdir = product_file("data");
+        vendor_srcdir = product_file("vendor");
+        /* Check if vendor partition exists */
+        if (lstat(vendor_srcdir, &st) || !S_ISDIR(st.st_mode))
+            vendor_srcdir = NULL;
+    } 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");
+        } else if(strcmp(srcarg, "data") == 0) {
+            data_srcdir = product_file("data");
+        } else if(strcmp(srcarg, "vendor") == 0) {
+            vendor_srcdir = product_file("vendor");
+        } else {
+            /* It's not "system", "vendor", or "data".
+             */
+            return 1;
+        }
+    }
+
+    if(android_srcdir_out != NULL)
+        *android_srcdir_out = android_srcdir;
+    else
+        free(android_srcdir);
+
+    if(vendor_srcdir_out != NULL)
+        *vendor_srcdir_out = vendor_srcdir;
+    else
+        free(vendor_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)
 {
diff --git a/src/devtools/adb/console.c b/src/devtools/adb/console.c
new file mode 100644
index 0000000..b813d33
--- /dev/null
+++ b/src/devtools/adb/console.c
@@ -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;
+}
diff --git a/src/devtools/adb/file_sync_client.c b/src/devtools/adb/file_sync_client.c
index c37e321..ad59e81 100644
--- a/src/devtools/adb/file_sync_client.c
+++ b/src/devtools/adb/file_sync_client.c
@@ -1014,3 +1014,22 @@
     }
 }
 
+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;
+    }
+}
diff --git a/src/devtools/adb/file_sync_service.c b/src/devtools/adb/file_sync_service.c
index ba87c2c..b2a8bc6 100644
--- a/src/devtools/adb/file_sync_service.c
+++ b/src/devtools/adb/file_sync_service.c
@@ -111,7 +111,7 @@
     struct dirent *de;
     struct stat st;
     syncmsg msg;
-    unsigned int len;
+    int len;
 
     char tmp[1024 + 256 + 1];
     char *fname;
diff --git a/src/devtools/adb/framebuffer_service.c b/src/devtools/adb/framebuffer_service.c
new file mode 100644
index 0000000..1c5cd2f
--- /dev/null
+++ b/src/devtools/adb/framebuffer_service.c
@@ -0,0 +1,184 @@
+/*
+ * 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>
+
+#include <cutils/fs.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, bsize;
+    char buf[640];
+    int fd_screencap;
+    int w, h, f;
+    int fds[2];
+
+    if (pipe2(fds, O_CLOEXEC) < 0) goto pipefail;
+
+    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 += bsize) {
+      bsize = sizeof(buf);
+      if (i + bsize > fbinfo.size)
+        bsize = fbinfo.size - i;
+      if(readx(fd_screencap, buf, bsize)) goto done;
+      if(writex(fd, buf, bsize)) goto done;
+    }
+
+done:
+    TEMP_FAILURE_RETRY(waitpid(pid, NULL, 0));
+
+    close(fds[0]);
+    close(fds[1]);
+pipefail:
+    close(fd);
+}
diff --git a/src/devtools/adb/jdwp_service.c b/src/devtools/adb/jdwp_service.c
new file mode 100644
index 0000000..cd62b55
--- /dev/null
+++ b/src/devtools/adb/jdwp_service.c
@@ -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 */
+
diff --git a/src/devtools/adb/logd_write.c b/src/devtools/adb/logd_write.c
index 384f62e..b2668ce 100644
--- a/src/devtools/adb/logd_write.c
+++ b/src/devtools/adb/logd_write.c
@@ -403,8 +403,7 @@
     vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
     va_end(ap);
 
-    printf("%s(): %s", tag, buf);
-    return fflush(stdout);
+    return __android_log_write(prio, tag, buf);
 }
 
 int __android_log_buf_print(int bufID, int prio, const char *tag, const char *fmt, ...)
diff --git a/src/devtools/adb/properties.c b/src/devtools/adb/properties.c
index 520688b..20069b0 100644
--- a/src/devtools/adb/properties.c
+++ b/src/devtools/adb/properties.c
@@ -354,17 +354,12 @@
     char ename[PROPERTY_KEY_MAX + 6];
     char *p;
     int len;
-
+    
     len = strlen(key);
     if(len >= PROPERTY_KEY_MAX) return -1;
-
-    if (strcmp(key, "persist.adb.trace_mask")) {
-        memcpy(ename, "PROP_", 5);
-        memcpy(ename + 5, key, len + 1);
-    } else {
-        memcpy(ename, "ADBD_TRACE", 11);
-    }
-
+    memcpy(ename, "PROP_", 5);
+    memcpy(ename + 5, key, len + 1);
+    
     mutex_lock(&env_lock);
 
     p = getenv(ename);
@@ -373,7 +368,7 @@
     if(len >= PROPERTY_VALUE_MAX) {
         len = PROPERTY_VALUE_MAX - 1;
     }
-
+    
     if((len == 0) && default_value) {
         len = strlen(default_value);
         memcpy(value, default_value, len + 1);
@@ -424,7 +419,7 @@
     return 0;
 }
 
-#elif defined(UCI_PROPERTY_SUPPORT)
+#else
 
 /* UCI configuration system implementation for OpenWrt */
 #include <uci.h>
@@ -455,8 +450,7 @@
 
     if (UCI_OK != uci_load(uciCtx, UCI_CONFIG_FILE, &pkg)) {
         if (default_value) {
-            unsigned int len = strlen(default_value);
-            len = len < PROPERTY_VALUE_MAX ? len : PROPERTY_VALUE_MAX-1;
+            int len = strlen(default_value);
             memcpy(value, default_value, len);
             value[len] = '\0';
             retValue = 1;
@@ -471,10 +465,7 @@
             if (!strncmp(pValueData, ":empty", strlen(":empty"))) {
                 value[0] = '\0';
             } else {
-                unsigned int len = strlen(pValueData);
-                len = len < PROPERTY_VALUE_MAX ? len : PROPERTY_VALUE_MAX-1;
-                strncpy(value, pValueData, len);
-                value[len] = '\0';
+                strncpy(value, pValueData, strlen(pValueData));
             }
             retValue = 1;
             D("property_get, %s: %s\n", key, value);
@@ -482,8 +473,7 @@
     }
     if (!retValue) {
         if (default_value) {
-            unsigned int len = strlen(default_value);
-            len = len < PROPERTY_VALUE_MAX ? len : PROPERTY_VALUE_MAX-1;
+            int len = strlen(default_value);
             memcpy(value, default_value, len);
             value[len] = '\0';
             retValue = 1;
@@ -553,29 +543,4 @@
     return 0;
 }
 
-#else
-
-int property_get(const char *key, char *value, const char *default_value) {
-    if (NULL == key || NULL == value) {
-        return 0;
-    }
-    int retValue = 0;
-
-    if (default_value) {
-        int len = strlen(default_value);
-        memcpy(value, default_value, len);
-        value[len] = '\0';
-        retValue = 1;
-    }
-    return retValue;
-}
-
-int property_set(const char *key, const char *new_value) {
-    return 0;
-}
-
-int property_list(void (*propfn)(const char *key, const char *value, void *cookie),
-                  void *cookie) {
-    return 0;
-}
 #endif
diff --git a/src/devtools/adb/rsa.c b/src/devtools/adb/rsa.c
new file mode 100644
index 0000000..171c437
--- /dev/null
+++ b/src/devtools/adb/rsa.c
@@ -0,0 +1,310 @@
+/* rsa.c
+**
+** Copyright 2012, The Android Open Source Project
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are met:
+**     * Redistributions of source code must retain the above copyright
+**       notice, this list of conditions and the following disclaimer.
+**     * Redistributions in binary form must reproduce the above copyright
+**       notice, this list of conditions and the following disclaimer in the
+**       documentation and/or other materials provided with the distribution.
+**     * Neither the name of Google Inc. nor the names of its contributors may
+**       be used to endorse or promote products derived from this software
+**       without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mincrypt/rsa.h"
+#include "mincrypt/sha.h"
+#include "mincrypt/sha256.h"
+
+// a[] -= mod
+static void subM(const RSAPublicKey* key,
+                 uint32_t* a) {
+    int64_t A = 0;
+    int i;
+    for (i = 0; i < key->len; ++i) {
+        A += (uint64_t)a[i] - key->n[i];
+        a[i] = (uint32_t)A;
+        A >>= 32;
+    }
+}
+
+// return a[] >= mod
+static int geM(const RSAPublicKey* key,
+               const uint32_t* a) {
+    int i;
+    for (i = key->len; i;) {
+        --i;
+        if (a[i] < key->n[i]) return 0;
+        if (a[i] > key->n[i]) return 1;
+    }
+    return 1;  // equal
+}
+
+// montgomery c[] += a * b[] / R % mod
+static void montMulAdd(const RSAPublicKey* key,
+                       uint32_t* c,
+                       const uint32_t a,
+                       const uint32_t* b) {
+    uint64_t A = (uint64_t)a * b[0] + c[0];
+    uint32_t d0 = (uint32_t)A * key->n0inv;
+    uint64_t B = (uint64_t)d0 * key->n[0] + (uint32_t)A;
+    int i;
+
+    for (i = 1; i < key->len; ++i) {
+        A = (A >> 32) + (uint64_t)a * b[i] + c[i];
+        B = (B >> 32) + (uint64_t)d0 * key->n[i] + (uint32_t)A;
+        c[i - 1] = (uint32_t)B;
+    }
+
+    A = (A >> 32) + (B >> 32);
+
+    c[i - 1] = (uint32_t)A;
+
+    if (A >> 32) {
+        subM(key, c);
+    }
+}
+
+// montgomery c[] = a[] * b[] / R % mod
+static void montMul(const RSAPublicKey* key,
+                    uint32_t* c,
+                    const uint32_t* a,
+                    const uint32_t* b) {
+    int i;
+    for (i = 0; i < key->len; ++i) {
+        c[i] = 0;
+    }
+    for (i = 0; i < key->len; ++i) {
+        montMulAdd(key, c, a[i], b);
+    }
+}
+
+// In-place public exponentiation.
+// Input and output big-endian byte array in inout.
+static void modpow(const RSAPublicKey* key,
+                   uint8_t* inout) {
+    uint32_t a[RSANUMWORDS];
+    uint32_t aR[RSANUMWORDS];
+    uint32_t aaR[RSANUMWORDS];
+    uint32_t* aaa = 0;
+    int i;
+
+    // Convert from big endian byte array to little endian word array.
+    for (i = 0; i < key->len; ++i) {
+        uint32_t tmp =
+            (inout[((key->len - 1 - i) * 4) + 0] << 24) |
+            (inout[((key->len - 1 - i) * 4) + 1] << 16) |
+            (inout[((key->len - 1 - i) * 4) + 2] << 8) |
+            (inout[((key->len - 1 - i) * 4) + 3] << 0);
+        a[i] = tmp;
+    }
+
+    if (key->exponent == 65537) {
+        aaa = aaR;  // Re-use location.
+        montMul(key, aR, a, key->rr);  // aR = a * RR / R mod M
+        for (i = 0; i < 16; i += 2) {
+            montMul(key, aaR, aR, aR);  // aaR = aR * aR / R mod M
+            montMul(key, aR, aaR, aaR);  // aR = aaR * aaR / R mod M
+        }
+        montMul(key, aaa, aR, a);  // aaa = aR * a / R mod M
+    } else if (key->exponent == 3) {
+        aaa = aR;  // Re-use location.
+        montMul(key, aR, a, key->rr);  /* aR = a * RR / R mod M   */
+        montMul(key, aaR, aR, aR);     /* aaR = aR * aR / R mod M */
+        montMul(key, aaa, aaR, a);     /* aaa = aaR * a / R mod M */
+    } else {
+        return; // avoid NULL aaa caused exceptions
+    }
+
+    // Make sure aaa < mod; aaa is at most 1x mod too large.
+    if (geM(key, aaa)) {
+        subM(key, aaa);
+    }
+
+    // Convert to bigendian byte array
+    for (i = key->len - 1; i >= 0; --i) {
+        uint32_t tmp = aaa[i];
+        *inout++ = tmp >> 24;
+        *inout++ = tmp >> 16;
+        *inout++ = tmp >> 8;
+        *inout++ = tmp >> 0;
+    }
+}
+
+// Expected PKCS1.5 signature padding bytes, for a keytool RSA signature.
+// Has the 0-length optional parameter encoded in the ASN1 (as opposed to the
+// other flavor which omits the optional parameter entirely). This code does not
+// accept signatures without the optional parameter.
+
+/*
+static const uint8_t sha_padding[RSANUMBYTES] = {
+    0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0x00, 0x30, 0x21, 0x30,
+    0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a,
+    0x05, 0x00, 0x04, 0x14,
+
+    // 20 bytes of hash go here.
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+};
+*/
+
+// SHA-1 of PKCS1.5 signature sha_padding for 2048 bit, as above.
+// At the location of the bytes of the hash all 00 are hashed.
+static const uint8_t kExpectedPadShaRsa2048[SHA_DIGEST_SIZE] = {
+    0xdc, 0xbd, 0xbe, 0x42, 0xd5, 0xf5, 0xa7, 0x2e,
+    0x6e, 0xfc, 0xf5, 0x5d, 0xaf, 0x9d, 0xea, 0x68,
+    0x7c, 0xfb, 0xf1, 0x67
+};
+
+/*
+static const uint8_t sha256_padding[RSANUMBYTES] = {
+    0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0x00, 0x30, 0x31, 0x30,
+    0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65,
+    0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20,
+
+    // 32 bytes of hash go here.
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+};
+*/
+
+// SHA-256 of PKCS1.5 signature sha256_padding for 2048 bit, as above.
+// At the location of the bytes of the hash all 00 are hashed.
+static const uint8_t kExpectedPadSha256Rsa2048[SHA256_DIGEST_SIZE] = {
+    0xab, 0x28, 0x8d, 0x8a, 0xd7, 0xd9, 0x59, 0x92,
+    0xba, 0xcc, 0xf8, 0x67, 0x20, 0xe1, 0x15, 0x2e,
+    0x39, 0x8d, 0x80, 0x36, 0xd6, 0x6f, 0xf0, 0xfd,
+    0x90, 0xe8, 0x7d, 0x8b, 0xe1, 0x7c, 0x87, 0x59,
+};
+
+// Verify a 2048-bit RSA PKCS1.5 signature against an expected hash.
+// Both e=3 and e=65537 are supported.  hash_len may be
+// SHA_DIGEST_SIZE (== 20) to indicate a SHA-1 hash, or
+// SHA256_DIGEST_SIZE (== 32) to indicate a SHA-256 hash.  No other
+// values are supported.
+//
+// Returns 1 on successful verification, 0 on failure.
+int RSA_verify(const RSAPublicKey *key,
+               const uint8_t *signature,
+               const int len,
+               const uint8_t *hash,
+               const int hash_len) {
+    uint8_t buf[RSANUMBYTES];
+    int i;
+    const uint8_t* padding_hash;
+
+    if (key->len != RSANUMWORDS) {
+        return 0;  // Wrong key passed in.
+    }
+
+    if (len != sizeof(buf)) {
+        return 0;  // Wrong input length.
+    }
+
+    if (hash_len != SHA_DIGEST_SIZE &&
+        hash_len != SHA256_DIGEST_SIZE) {
+        return 0;  // Unsupported hash.
+    }
+
+    if (key->exponent != 3 && key->exponent != 65537) {
+        return 0;  // Unsupported exponent.
+    }
+
+    for (i = 0; i < len; ++i) {  // Copy input to local workspace.
+        buf[i] = signature[i];
+    }
+
+    modpow(key, buf);  // In-place exponentiation.
+
+    // Xor sha portion, so it all becomes 00 iff equal.
+    for (i = len - hash_len; i < len; ++i) {
+        buf[i] ^= *hash++;
+    }
+
+    // Hash resulting buf, in-place.
+    switch (hash_len) {
+        case SHA_DIGEST_SIZE:
+            padding_hash = kExpectedPadShaRsa2048;
+            SHA_hash(buf, len, buf);
+            break;
+        case SHA256_DIGEST_SIZE:
+            padding_hash = kExpectedPadSha256Rsa2048;
+            SHA256_hash(buf, len, buf);
+            break;
+        default:
+            return 0;
+    }
+
+    // Compare against expected hash value.
+    for (i = 0; i < hash_len; ++i) {
+        if (buf[i] != padding_hash[i]) {
+            return 0;
+        }
+    }
+
+    return 1;  // All checked out OK.
+}
diff --git a/src/devtools/adb/services.c b/src/devtools/adb/services.c
index 1527ef8..1360782 100644
--- a/src/devtools/adb/services.c
+++ b/src/devtools/adb/services.c
@@ -440,6 +440,10 @@
 #if !ADB_HOST
     } else if(!strncmp("dev:", name, 4)) {
         ret = unix_open(name + 4, O_RDWR | O_CLOEXEC);
+    } else if(!strncmp(name, "framebuffer:", 12)) {
+        ret = create_service_thread(framebuffer_service, 0);
+    } else if (!strncmp(name, "jdwp:", 5)) {
+        ret = create_jdwp_connection_fd(atoi(name+5));
     } else if(!HOST && !strncmp(name, "shell:", 6)) {
         ret = create_subproc_thread(name + 6, SUBPROC_PTY);
     } else if(!HOST && !strncmp(name, "exec:", 5)) {
diff --git a/src/devtools/adb/sha.c b/src/devtools/adb/sha.c
index a637f24..5bef32e 100644
--- a/src/devtools/adb/sha.c
+++ b/src/devtools/adb/sha.c
@@ -105,7 +105,7 @@
 
 
 void SHA_update(SHA_CTX* ctx, const void* data, int len) {
-    unsigned int i = (unsigned int) (ctx->count & 63);
+    int i = (int) (ctx->count & 63);
     const uint8_t* p = (const uint8_t*)data;
 
     ctx->count += len;
diff --git a/src/devtools/adb/sha256.c b/src/devtools/adb/sha256.c
index 6086b08..eb6e308 100644
--- a/src/devtools/adb/sha256.c
+++ b/src/devtools/adb/sha256.c
@@ -134,7 +134,7 @@
 
 
 void SHA256_update(SHA256_CTX* ctx, const void* data, int len) {
-    unsigned int i = (unsigned int) (ctx->count & 63);
+    int i = (int) (ctx->count & 63);
     const uint8_t* p = (const uint8_t*)data;
 
     ctx->count += len;
diff --git a/src/devtools/adb/sockets.c b/src/devtools/adb/sockets.c
index e4e0df3..3c2773c 100644
--- a/src/devtools/adb/sockets.c
+++ b/src/devtools/adb/sockets.c
@@ -436,6 +436,14 @@
     char debug[PROPERTY_VALUE_MAX];
 #endif
 
+#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;
 
diff --git a/src/devtools/adb/test_track_jdwp.c b/src/devtools/adb/test_track_jdwp.c
new file mode 100644
index 0000000..8ecc6b8
--- /dev/null
+++ b/src/devtools/adb/test_track_jdwp.c
@@ -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);
+}
diff --git a/src/devtools/adb/transport_pcie.c b/src/devtools/adb/transport_pcie.c
index e06ff2b..d677587 100644
--- a/src/devtools/adb/transport_pcie.c
+++ b/src/devtools/adb/transport_pcie.c
@@ -103,17 +103,18 @@
 
 static void remote_close(atransport *t)
 {
-    D("remote_close\n");
+    struct pcie_handle *pcie = t->pcie;
+
+    unix_close(pcie->fd);
+    pcie->fd = -1;
 }
 
 static void remote_kick(atransport *t)
 {
 	struct pcie_handle *pcie = t->pcie;
 
-	if (pcie->kick) {
-		D("Enter pcie->kick\n");
+	if (pcie->kick)
 		pcie->kick(pcie);
-	}
 }
 
 void init_pcie_transport(atransport *t, struct pcie_handle *h, const char *devpath, int state)
@@ -163,6 +164,7 @@
 {
 	struct pcie_handle *pcie = (struct pcie_handle *)x;
 	int fd = -1;
+	char *banner = "Start PCIe port\n";
 
 	while (1) {
 		adb_mutex_lock(&pcie->lock);
@@ -170,16 +172,15 @@
 			adb_cond_wait(&pcie->notify, &pcie->lock);
 		adb_mutex_unlock(&pcie->lock);
 
-		D("Try open pcie adbd port~\n");
 		do {
 			fd = unix_open(PCIE_ADB_PATH, O_RDWR);
 			if (fd < 0) {
 				adb_sleep_ms(1000);
 			}
 		} while (fd < 0);
-		D("Open pcie adbd port success~\n");
 
 		pcie->fd = fd;
+		adb_write(fd, banner, strlen(banner));
 
 		/* Get PCIe config information */
 		fd = unix_open(PCIE_INFO_ADB_PATH, O_RDONLY);
diff --git a/src/devtools/adb/transport_usb.c b/src/devtools/adb/transport_usb.c
index edc7620..3d19803 100644
--- a/src/devtools/adb/transport_usb.c
+++ b/src/devtools/adb/transport_usb.c
@@ -48,40 +48,28 @@
 
 static int remote_read(apacket *p, atransport *t)
 {
-    int ret = 0;
-    while (true) {
-        ret = usb_read(t->usb, &p->msg, sizeof(amessage));
-        if(ret < -1){
-            D("remote usb: terminated (message) due to suspended, ret=%d, retry read\n", ret);
-            continue;
-        } else if (ret) { // not zero
-            D("remote usb: read terminated (message)\n");
+    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;
         }
+    }
 
-        fix_endians(p);
-
-        if(check_header(p)) {
-            D("remote usb: check_header failed\n");
-            return -1;
-        }
-
-        if(p->msg.data_length) {
-            ret = usb_read(t->usb, p->data, p->msg.data_length);
-            if(ret < -1){
-                D("remote usb: terminated (data) due to suspended, ret=%d, retry read\n", ret);
-                continue;
-            } else if (ret) { // not zero
-                D("remote usb: terminated (data)\n");
-                return -1;
-            }
-        }
-
-        if(check_data(p)) {
-            D("remote usb: check_data failed\n");
-            return -1;
-        }
-        break;
+    if(check_data(p)) {
+        D("remote usb: check_data failed\n");
+        return -1;
     }
 
     return 0;
diff --git a/src/devtools/adb/usb_linux_client.c b/src/devtools/adb/usb_linux_client.c
index da39951..2466275 100644
--- a/src/devtools/adb/usb_linux_client.c
+++ b/src/devtools/adb/usb_linux_client.c
@@ -58,15 +58,6 @@
 #define FFS_CONTOL_MAX_EPOLL_EVENT 50
 #define DEBUG   0
 
-#define USB_FFS_WAKE_LOCK_ID           "usb_adbd_wakelock"
-#define USB_FFS_WAKE_LOCK_TIMEOUT      (2 * 1000)
-
-static const char* sTag = "adbd_usb";
-adb_mutex_t g_wake_lock;
-timer_t g_wake_unlock_timer;
-bool g_wake_lock_acquired;
-typedef void (*timer_routine) (int id);
-
 struct usb_handle
 {
     adb_cond_t notify;
@@ -84,7 +75,6 @@
     int bulk_out; /* "out" from the host's perspective => source for adbd */
     int bulk_in;  /* "in" from the host's perspective => sink for adbd */
     bool ffs_control_thread_created;
-    bool ffs_control_suspend_mode;
 };
 
 static const struct {
@@ -322,12 +312,10 @@
     h->bulk_out = -1;
     h->control = -1;
     h->ffs_control_thread_created = false;
-    h->ffs_control_suspend_mode = false;
     h->fd = -1;
 
     adb_cond_init(&h->notify, 0);
     adb_mutex_init(&h->lock, 0);
-    adb_mutex_init(&g_wake_lock, 0);
 
     // Open the file /dev/android_adb_enable to trigger
     // the enabling of the adb USB function in the kernel.
@@ -347,94 +335,6 @@
     }
 }
 
-////////////////////// wake lock ///////////////////////////////
-timer_t timer_init(timer_routine cb, int id) {
-    struct sigevent sevp;
-    timer_t timerid;
-
-    memset(&sevp, 0, sizeof(sevp));
-    sevp.sigev_value.sival_int = id;
-    sevp.sigev_notify = SIGEV_THREAD;
-    sevp.sigev_notify_function = (void*)cb;
-
-    if(timer_create(CLOCK_BOOTTIME, &sevp, &timerid) == -1) {
-       D("timer_init() timer_create() failed, reason=[%s]%d",
-            strerror(errno), errno);
-        return NULL;
-    }
-    return timerid;
-}
-
-bool timer_start(timer_t timerid, int milliseconds) {
-    struct itimerspec expire;
-    expire.it_interval.tv_sec = 0;
-    expire.it_interval.tv_nsec = 0;
-    expire.it_value.tv_sec = milliseconds/1000;
-    expire.it_value.tv_nsec = (milliseconds%1000)*1000000;
-    if(timer_settime(timerid, 0, &expire, NULL) == -1) {
-        D("timer_start() timer_settime() failed, reason=[%s]%d", strerror(errno), errno);
-        return false;
-    }
-    return true;
-}
-
-bool timer_stop(timer_t timerid) {
-    return timer_start(timerid, 0);
-}
-
-bool usb_ffs_wake_lock() {
-#if !defined(__LBS_OS_LINUX__)    //no permission to open wake_lock on Linux
-    int fd = adb_open("/sys/power/wake_lock", O_RDWR | O_NONBLOCK);
-    if(fd == -1) {
-        D("[%s] open() failed, reason=[%s]%d", sTag, strerror(errno), errno);
-        return false;
-    }
-
-    int ret = adb_write(fd, USB_FFS_WAKE_LOCK_ID, strlen(USB_FFS_WAKE_LOCK_ID));
-    if(ret == -1) {
-        D("[%s] write() failed id=[%s], reason=[%s]%d", sTag, USB_FFS_WAKE_LOCK_ID, strerror(errno), errno);
-        adb_close(fd);
-        return false;
-    }
-
-    adb_close(fd);
-#endif
-    return true;
-}
-
-bool usb_ffs_wake_unlock() {
-#if !defined(__LBS_OS_LINUX__)    //no permission to open wake_lock on Linux
-    int fd = adb_open("/sys/power/wake_unlock", O_RDWR | O_NONBLOCK);
-    if(fd == -1) {
-        D("[%s] open() failed, reason=[%s]%d", sTag, strerror(errno), errno);
-        return false;
-    }
-
-    int ret = adb_write(fd, USB_FFS_WAKE_LOCK_ID, strlen(USB_FFS_WAKE_LOCK_ID));
-    if(ret == -1) {
-        D("[%s] write() failed id=[%s], reason=[%s]%d", sTag,
-                USB_FFS_WAKE_LOCK_ID, strerror(errno), errno);
-        adb_close(fd);
-        return false;
-    }
-
-    adb_close(fd);
-#endif
-    return true;
-}
-
-static void usb_ffs_timer_wake_unlock_routine(int id) {
-    //do not use the internal msg or it will cause infinite loop in epoll_wait
-    adb_mutex_lock(&g_wake_lock);
-    if(g_wake_lock_acquired) {
-        if(usb_ffs_wake_unlock()) {
-            g_wake_lock_acquired = false;
-        }
-    }
-    if (DEBUG) D("[%s] unlock wake_lock_acquired=[%d]", sTag, g_wake_lock_acquired);
-    adb_mutex_unlock(&g_wake_lock);
-}
-
 static void *ffs_control_read_msg_thread(void *_h)
 {
     usb_handle *h = _h;
@@ -504,13 +404,6 @@
     D("event.type: %s\n", ffs_get_event_type_code(event.type));
 
     switch (event.type) {
-        case FUNCTIONFS_SUSPEND:
-            D("received FUNCTIONFS_SUSPEND set suspend mode 1");
-            h->ffs_control_suspend_mode = true;
-            break;
-        case FUNCTIONFS_RESUME:
-            D("received FUNCTIONFS_RESUME");
-            break;
         case FUNCTIONFS_SETUP: {
             D("received FUNCTIONFS_SETUP");
             D("bRequestType = %d",(int)(event.u.setup.bRequestType));
@@ -567,7 +460,6 @@
     int control_fd = h->control;
     struct epoll_event events[FFS_CONTOL_MAX_EPOLL_EVENT];
 
-    g_wake_unlock_timer = timer_init(usb_ffs_timer_wake_unlock_routine, 0);
     int epfd = epoll_create(FFS_CONTOL_MAX_EPOLL_EVENT);
     if(epfd == -1) {
         D("ERR: epoll_create() fail reason=[%s]", strerror(errno));
@@ -583,14 +475,6 @@
         D("Before ffs control thread epoll_wait");
         n = epoll_wait(epfd, events, FFS_CONTOL_MAX_EPOLL_EVENT , -1);
 
-        adb_mutex_lock(&g_wake_lock);
-        timer_stop(g_wake_unlock_timer);
-        if (!g_wake_lock_acquired) {
-            g_wake_lock_acquired = usb_ffs_wake_lock();
-            if (DEBUG) D("[%s] wake_lock_acquired=[%d]", sTag, g_wake_lock_acquired);
-        }
-        adb_mutex_unlock(&g_wake_lock);
-
         for(i = 0; i < n; i++) {
             if(events[i].data.fd == control_fd) {
                 if(events[i].events & EPOLLIN) {
@@ -599,8 +483,6 @@
                 }
             }
         }
-
-        timer_start(g_wake_unlock_timer, USB_FFS_WAKE_LOCK_TIMEOUT);
     }
 }
 
@@ -764,22 +646,11 @@
 
     D("about to read (fd=%d, len=%d)\n", h->bulk_out, len);
     n = bulk_read(h->bulk_out, data, len);
-    if (h->ffs_control_suspend_mode) {
-        if (n < 0) {
-            int ret_err  = -1 * errno;
-            D("Suspended bulk_read() ERROR: fd = %d, n = %d, errno = %d (%s) ret_err=%d\n",
-                h->bulk_out, n, errno, strerror(errno), ret_err);
-            return ret_err;
-        } else {
-            D("Suspended bulk_read: fd = %d, n = %d, errno = %d (%s) len:%d data:%s\n",
-                h->bulk_out, n, errno, strerror(errno), len, data);
-        }
-    } else if (n != len) {
+    if (n != len) {
         D("ERROR: fd = %d, n = %d, errno = %d (%s)\n",
             h->bulk_out, n, errno, strerror(errno));
         return -1;
     }
-    h->ffs_control_suspend_mode = false;
     D("[ done fd=%d ]\n", h->bulk_out);
     return 0;
 }
@@ -834,7 +705,6 @@
 
     adb_cond_init(&h->notify, 0);
     adb_mutex_init(&h->lock, 0);
-    adb_mutex_init(&g_wake_lock, 0);
 
     D("[ usb_init - starting thread ]\n");
     if (adb_thread_create(&tid, usb_ffs_open_thread, h)){