[Feauture] support adbd listening on tcp port with uci config

Change-Id: Ic885b955900cf3cf20322ba5f54ff47d1eedf0ef
diff --git a/src/devtools/adb_tcp/MODULE_LICENSE_APACHE2 b/src/devtools/adb_tcp/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/devtools/adb_tcp/MODULE_LICENSE_APACHE2
diff --git a/src/devtools/adb_tcp/Makefile b/src/devtools/adb_tcp/Makefile
new file mode 100644
index 0000000..1eb5f3d
--- /dev/null
+++ b/src/devtools/adb_tcp/Makefile
@@ -0,0 +1,86 @@
+ifeq ($(OPENWRT_BUILD_ADBD),)
+export STAGING_DIR=../../openwrt/staging_dir
+else
+export STAGING_DIR=$(TOPDIR)/staging_dir
+endif
+ifeq ($(ADB_OVER_PCIE),)
+ADB_OVER_PCIE=0
+endif
+
+COMMON_SRC_FILES := \
+	adb.c \
+	fdevent.c \
+	transport.c \
+	transport_local.c \
+	sockets.c \
+	services.c
+ifeq ($(ADB_OVER_PCIE),1)
+	COMMON_SRC_FILES+= transport_pcie.c
+else
+	COMMON_SRC_FILES+= transport_usb.c
+endif
+
+# adbd device daemon
+# =========================================================
+
+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
+endif
+
+LOCAL_SRC_FILES += \
+	properties.c \
+	load_file.c \
+	socket_inaddr_any_server.c \
+	socket_local_client.c \
+	socket_local_server.c \
+	socket_loopback_client.c \
+	socket_loopback_server.c \
+	socket_network_client.c \
+	sha.c \
+	rsa.c \
+	sha256.c \
+	logd_write.c \
+	thread_utils.c \
+	b64_pton.c
+
+LOCAL_CFLAGS := \
+	-O2 \
+	-g \
+	-D_XOPEN_SOURCE \
+	-D_GNU_SOURCE \
+	-Wall -Wno-unused-parameter -Wno-deprecated-declarations \
+	-DADB_NON_ANDROID=1 \
+	-DALLOW_ADBD_ROOT=1 \
+	-DHAVE_PTHREADS \
+	-DDEBUG_PACKETS=1
+
+ifeq ($(ADB_OVER_PCIE),1)
+	LOCAL_CFLAGS+= -DADB_OVER_PCIE=1
+endif
+
+CPPFLAGS+= -DDZONE -DHAVE_FORKEXEC=1 -DHAVE_SYMLINKS -DHAVE_TERMIO_H
+CPPFLAGS+= -D_GNU_SOURCE -D_XOPEN_SOURCE
+CPPFLAGS+= -I. -I./include
+CPPFLAGS+= $(LOCAL_CFLAGS)
+
+LIBS += -lpthread -luci  -llynq-log  -llynq-uci 
+
+LOCAL_MODULE := adbd
+LOCAL_SRC_FILES+= $(COMMON_SRC_FILES) $(ADBD_SRC_FILES)
+CPPFLAGS+= -DADB_HOST=0
+
+OBJS=$(LOCAL_SRC_FILES:.c=.o)
+
+all: $(LOCAL_MODULE)
+
+$(LOCAL_MODULE): $(OBJS)
+	$(CC) -o $@ $(LDFLAGS) $(OBJS) $(LIBS)
+
+clean:
+	rm -rf $(OBJS) $(LOCAL_MODULE)
diff --git a/src/devtools/adb_tcp/NOTICE b/src/devtools/adb_tcp/NOTICE
new file mode 100644
index 0000000..f46a084
--- /dev/null
+++ b/src/devtools/adb_tcp/NOTICE
@@ -0,0 +1,202 @@
+Copyright (C) 2005-2014 The Android Open Source Project
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+
+All rights reserved.
+
+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 the <ORGANIZATION> 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
+
+
diff --git a/src/devtools/adb_tcp/OVERVIEW.TXT b/src/devtools/adb_tcp/OVERVIEW.TXT
new file mode 100644
index 0000000..c40695a
--- /dev/null
+++ b/src/devtools/adb_tcp/OVERVIEW.TXT
@@ -0,0 +1,139 @@
+Implementation notes regarding ADB.
+
+I. General Overview:
+
+The Android Debug Bridge (ADB) is used to:
+
+- keep track of all Android devices and emulators instances
+  connected to or running on a given host developer machine
+
+- implement various control commands (e.g. "adb shell", "adb pull", etc..)
+  for the benefit of clients (command-line users, or helper programs like
+  DDMS). These commands are what is called a 'service' in ADB.
+
+As a whole, everything works through the following components:
+
+  1. The ADB server
+
+    This is a background process that runs on the host machine. Its purpose
+    if to sense the USB ports to know when devices are attached/removed,
+    as well as when emulator instances start/stop.
+
+    It thus maintains a list of "connected devices" and assigns a 'state'
+    to each one of them: OFFLINE, BOOTLOADER, RECOVERY or ONLINE (more on
+    this below).
+
+    The ADB server is really one giant multiplexing loop whose purpose is
+    to orchestrate the exchange of data (packets, really) between clients,
+    services and devices.
+
+
+  2. The ADB daemon (adbd)
+
+    The 'adbd' program runs as a background process within an Android device
+    or emulated system. Its purpose is to connect to the ADB server
+    (through USB for devices, through TCP for emulators) and provide a
+    few services for clients that run on the host.
+
+    The ADB server considers that a device is ONLINE when it has successfully
+    connected to the adbd program within it. Otherwise, the device is OFFLINE,
+    meaning that the ADB server detected a new device/emulator, but could not
+    connect to the adbd daemon.
+
+    the BOOTLOADER and RECOVERY states correspond to alternate states of
+    devices when they are in the bootloader or recovery mode.
+
+  3. The ADB command-line client
+
+    The 'adb' command-line program is used to run adb commands from a shell
+    or a script. It first tries to locate the ADB server on the host machine,
+    and will start one automatically if none is found.
+
+    then, the client sends its service requests to the ADB server. It doesn't
+    need to know.
+
+    Currently, a single 'adb' binary is used for both the server and client.
+    this makes distribution and starting the server easier.
+
+
+  4. Services
+
+    There are essentially two kinds of services that a client can talk to.
+
+    Host Services:
+      these services run within the ADB Server and thus do not need to
+      communicate with a device at all. A typical example is "adb devices"
+      which is used to return the list of currently known devices and their
+      state. They are a few couple other services though.
+
+    Local Services:
+      these services either run within the adbd daemon, or are started by
+      it on the device. The ADB server is used to multiplex streams
+      between the client and the service running in adbd. In this case
+      its role is to initiate the connection, then of being a pass-through
+      for the data.
+
+
+II. Protocol details:
+
+  1. Client <-> Server protocol:
+
+    This details the protocol used between ADB clients and the ADB
+    server itself. The ADB server listens on TCP:localhost:5037.
+
+    A client sends a request using the following format:
+
+        1. A 4-byte hexadecimal string giving the length of the payload
+        2. Followed by the payload itself.
+
+    For example, to query the ADB server for its internal version number,
+    the client will do the following:
+
+        1. Connect to tcp:localhost:5037
+        2. Send the string "000Chost:version" to the corresponding socket
+
+    The 'host:' prefix is used to indicate that the request is addressed
+    to the server itself (we will talk about other kinds of requests later).
+    The content length is encoded in ASCII for easier debugging.
+
+    The server should answer a request with one of the following:
+
+        1. For success, the 4-byte "OKAY" string
+
+        2. For failure, the 4-byte "FAIL" string, followed by a
+           4-byte hex length, followed by a string giving the reason
+           for failure.
+
+        3. As a special exception, for 'host:version', a 4-byte
+           hex string corresponding to the server's internal version number
+
+    Note that the connection is still alive after an OKAY, which allows the
+    client to make other requests. But in certain cases, an OKAY will even
+    change the state of the connection. 
+
+    For example, the case of the 'host:transport:<serialnumber>' request,
+    where '<serialnumber>' is used to identify a given device/emulator; after
+    the "OKAY" answer, all further requests made by the client will go
+    directly to the corresponding adbd daemon.
+
+    The file SERVICES.TXT lists all services currently implemented by ADB.
+
+
+  2. Transports:
+
+    An ADB transport models a connection between the ADB server and one device
+    or emulator. There are currently two kinds of transports:
+
+       - USB transports, for physical devices through USB
+
+       - Local transports, for emulators running on the host, connected to
+         the server through TCP
+
+    In theory, it should be possible to write a local transport that proxies
+    a connection between an ADB server and a device/emulator connected to/
+    running on another machine. This hasn't been done yet though.
+
+    Each transport can carry one or more multiplexed streams between clients
+    and the device/emulator they point to. The ADB server must handle
+    unexpected transport disconnections (e.g. when a device is physically
+    unplugged) properly.
diff --git a/src/devtools/adb_tcp/SERVICES.TXT b/src/devtools/adb_tcp/SERVICES.TXT
new file mode 100644
index 0000000..63000f2
--- /dev/null
+++ b/src/devtools/adb_tcp/SERVICES.TXT
@@ -0,0 +1,259 @@
+This file tries to document all requests a client can make
+to the ADB server of an adbd daemon. See the OVERVIEW.TXT document
+to understand what's going on here.
+
+HOST SERVICES:
+
+host:version
+    Ask the ADB server for its internal version number.
+
+    As a special exception, the server will respond with a 4-byte
+    hex string corresponding to its internal version number, without
+    any OKAY or FAIL.
+
+host:kill
+    Ask the ADB server to quit immediately. This is used when the
+    ADB client detects that an obsolete server is running after an
+    upgrade.
+
+host:devices
+host:devices-l
+    Ask to return the list of available Android devices and their
+    state. devices-l includes the device paths in the state.
+    After the OKAY, this is followed by a 4-byte hex len,
+    and a string that will be dumped as-is by the client, then
+    the connection is closed
+
+host:track-devices
+    This is a variant of host:devices which doesn't close the
+    connection. Instead, a new device list description is sent
+    each time a device is added/removed or the state of a given
+    device changes (hex4 + content). This allows tools like DDMS
+    to track the state of connected devices in real-time without
+    polling the server repeatedly.
+
+host:emulator:<port>
+    This is a special query that is sent to the ADB server when a
+    new emulator starts up. <port> is a decimal number corresponding
+    to the emulator's ADB control port, i.e. the TCP port that the
+    emulator will forward automatically to the adbd daemon running
+    in the emulator system.
+
+    This mechanism allows the ADB server to know when new emulator
+    instances start.
+
+host:transport:<serial-number>
+    Ask to switch the connection to the device/emulator identified by
+    <serial-number>. After the OKAY response, every client request will
+    be sent directly to the adbd daemon running on the device.
+    (Used to implement the -s option)
+
+host:transport-usb
+    Ask to switch the connection to one device connected through USB
+    to the host machine. This will fail if there are more than one such
+    devices. (Used to implement the -d convenience option)
+
+host:transport-local
+    Ask to switch the connection to one emulator connected through TCP.
+    This will fail if there is more than one such emulator instance
+    running. (Used to implement the -e convenience option)
+
+host:transport-any
+    Another host:transport variant. Ask to switch the connection to
+    either the device or emulator connect to/running on the host.
+    Will fail if there is more than one such device/emulator available.
+    (Used when neither -s, -d or -e are provided)
+
+host-serial:<serial-number>:<request>
+    This is a special form of query, where the 'host-serial:<serial-number>:'
+    prefix can be used to indicate that the client is asking the ADB server
+    for information related to a specific device. <request> can be in one
+    of the format described below.
+
+host-usb:<request>
+    A variant of host-serial used to target the single USB device connected
+    to the host. This will fail if there is none or more than one.
+
+host-local:<request>
+    A variant of host-serial used to target the single emulator instance
+    running on the host. This will fail if there is none or more than one.
+
+host:<request>
+    When asking for information related to a device, 'host:' can also be
+    interpreted as 'any single device or emulator connected to/running on
+    the host'.
+
+<host-prefix>:get-product
+    XXX
+
+<host-prefix>:get-serialno
+    Returns the serial number of the corresponding device/emulator.
+    Note that emulator serial numbers are of the form "emulator-5554"
+
+<host-prefix>:get-devpath
+    Returns the device path of the corresponding device/emulator.
+
+<host-prefix>:get-state
+    Returns the state of a given device as a string.
+
+<host-prefix>:forward:<local>;<remote>
+    Asks the ADB server to forward local connections from <local>
+    to the <remote> address on a given device.
+
+    There, <host-prefix> can be one of the
+    host-serial/host-usb/host-local/host prefixes as described previously
+    and indicates which device/emulator to target.
+
+    the format of <local> is one of:
+
+        tcp:<port>      -> TCP connection on localhost:<port>
+        local:<path>    -> Unix local domain socket on <path>
+
+    the format of <remote> is one of:
+
+        tcp:<port>      -> TCP localhost:<port> on device
+        local:<path>    -> Unix local domain socket on device
+        jdwp:<pid>      -> JDWP thread on VM process <pid>
+
+    or even any one of the local services described below.
+
+<host-prefix>:forward:norebind:<local>;<remote>
+    Same as <host-prefix>:forward:<local>;<remote> except that it will
+    fail it there is already a forward connection from <local>.
+
+    Used to implement 'adb forward --no-rebind <local> <remote>'
+
+<host-prefix>:killforward:<local>
+    Remove any existing forward local connection from <local>.
+    This is used to implement 'adb forward --remove <local>'
+
+<host-prefix>:killforward-all
+    Remove all forward network connections.
+    This is used to implement 'adb forward --remove-all'.
+
+<host-prefix>:list-forward
+    List all existing forward connections from this server.
+    This returns something that looks like the following:
+
+       <hex4>: The length of the payload, as 4 hexadecimal chars.
+       <payload>: A series of lines of the following format:
+
+         <serial> " " <local> " " <remote> "\n"
+
+    Where <serial> is a device serial number.
+          <local>  is the host-specific endpoint (e.g. tcp:9000).
+          <remote> is the device-specific endpoint.
+
+    Used to implement 'adb forward --list'.
+
+LOCAL SERVICES:
+
+All the queries below assumed that you already switched the transport
+to a real device, or that you have used a query prefix as described
+above.
+
+shell:command arg1 arg2 ...
+    Run 'command arg1 arg2 ...' in a shell on the device, and return
+    its output and error streams. Note that arguments must be separated
+    by spaces. If an argument contains a space, it must be quoted with
+    double-quotes. Arguments cannot contain double quotes or things
+    will go very wrong.
+
+    Note that this is the non-interactive version of "adb shell"
+
+shell:
+    Start an interactive shell session on the device. Redirect
+    stdin/stdout/stderr as appropriate. Note that the ADB server uses
+    this to implement "adb shell", but will also cook the input before
+    sending it to the device (see interactive_shell() in commandline.c)
+
+remount:
+    Ask adbd to remount the device's filesystem in read-write mode,
+    instead of read-only. This is usually necessary before performing
+    an "adb sync" or "adb push" request.
+
+    This request may not succeed on certain builds which do not allow
+    that.
+
+dev:<path>
+    Opens a device file and connects the client directly to it for
+    read/write purposes. Useful for debugging, but may require special
+    privileges and thus may not run on all devices. <path> is a full
+    path from the root of the filesystem.
+
+tcp:<port>
+    Tries to connect to tcp port <port> on localhost.
+
+tcp:<port>:<server-name>
+    Tries to connect to tcp port <port> on machine <server-name> from
+    the device. This can be useful to debug some networking/proxy
+    issues that can only be revealed on the device itself.
+
+local:<path>
+    Tries to connect to a Unix domain socket <path> on the device
+
+localreserved:<path>
+localabstract:<path>
+localfilesystem:<path>
+    Variants of local:<path> that are used to access other Android
+    socket namespaces.
+
+framebuffer:
+    This service is used to send snapshots of the framebuffer to a client.
+    It requires sufficient privileges but works as follow:
+
+      After the OKAY, the service sends 16-byte binary structure
+      containing the following fields (little-endian format):
+
+            depth:   uint32_t:    framebuffer depth
+            size:    uint32_t:    framebuffer size in bytes
+            width:   uint32_t:    framebuffer width in pixels
+            height:  uint32_t:    framebuffer height in pixels
+
+      With the current implementation, depth is always 16, and
+      size is always width*height*2
+
+      Then, each time the client wants a snapshot, it should send
+      one byte through the channel, which will trigger the service
+      to send it 'size' bytes of framebuffer data.
+
+      If the adbd daemon doesn't have sufficient privileges to open
+      the framebuffer device, the connection is simply closed immediately.
+
+jdwp:<pid>
+    Connects to the JDWP thread running in the VM of process <pid>.
+
+track-jdwp
+    This is used to send the list of JDWP pids periodically to the client.
+    The format of the returned data is the following:
+
+        <hex4>:    the length of all content as a 4-char hexadecimal string
+        <content>: a series of ASCII lines of the following format:
+                        <pid> "\n"
+
+    This service is used by DDMS to know which debuggable processes are running
+    on the device/emulator.
+
+    Note that there is no single-shot service to retrieve the list only once.
+
+sync:
+    This starts the file synchronisation service, used to implement "adb push"
+    and "adb pull". Since this service is pretty complex, it will be detailed
+    in a companion document named SYNC.TXT
+
+reverse:<forward-command>
+    This implements the 'adb reverse' feature, i.e. the ability to reverse
+    socket connections from a device to the host. <forward-command> is one
+    of the forwarding commands that are described above, as in:
+
+      list-forward
+      forward:<local>;<remote>
+      forward:norebind:<local>;<remote>
+      killforward-all
+      killforward:<local>
+
+    Note that in this case, <local> corresponds to the socket on the device
+    and <remote> corresponds to the socket on the host.
+
+    The output of reverse:list-forward is the same as host:list-forward
+    except that <serial> will be just 'host'.
diff --git a/src/devtools/adb_tcp/SYNC.TXT b/src/devtools/adb_tcp/SYNC.TXT
new file mode 100644
index 0000000..e74d217
--- /dev/null
+++ b/src/devtools/adb_tcp/SYNC.TXT
@@ -0,0 +1,84 @@
+This file tries to document file related requests a client can make
+to the ADB server of an adbd daemon. See the OVERVIEW.TXT document
+to understand what's going on here. See the SERVICES.TXT to learn more
+about the other requests that are possible.
+
+SYNC SERVICES:
+
+
+Requesting the sync service ("sync:") using the protocol as described in
+SERVICES.TXT sets the connection in sync mode. This mode is a binary mode that
+differ from the regular adb protocol. The connection stays in sync mode until
+explicitly terminated (see below).
+
+After the initial "sync:" command is sent the server must respond with either
+"OKAY" or "FAIL" as per usual. 
+
+In sync mode both the server and the client will frequently use eight-byte
+packets to communicate in this document called sync request and sync
+responses. The first four bytes is an id and specifies sync request is
+represented by four utf-8 characters. The last four bytes is a Little-Endian
+integer, with various uses. This number will be called "length" below. In fact
+all binary integers are Little-Endian in the sync mode. Sync mode is
+implicitly exited after each sync request, and normal adb communication
+follows as described in SERVICES.TXT.
+
+The following sync requests are accepted:
+LIST - List the files in a folder
+SEND - Send a file to device
+RECV - Retreive a file from device
+
+Not yet documented:
+STAT - Stat a file
+ULNK - Unlink (remove) a file. (Not currently supported)
+
+For all of the sync request above the must be followed by length number of
+bytes containing an utf-8 string with a remote filename.
+
+LIST:
+Lists files in the directory specified by the remote filename. The server will
+respond with zero or more directory entries or "dents".
+
+The directory entries will be returned in the following form
+1. A four-byte sync response id beeing "DENT"
+2. A four-byte integer representing file mode.
+3. A four-byte integer representing file size.
+4. A four-byte integer representing last modified time.
+5. A four-byte integer representing file name length.
+6. length number of bytes containing an utf-8 string representing the file
+   name.
+
+When an sync response "DONE" is received the listing is done.
+
+SEND:
+The remote file name is split into two parts separated by the last
+comma (","). The first part is the actual path, while the second is a decimal
+encoded file mode containing the permissions of the file on device.
+
+Note that some file types will be deleted before the copying starts, and if
+the transfer fails. Some file types will not be deleted, which allows
+  adb push disk_image /some_block_device
+to work.
+
+After this the actual file is sent in chunks. Each chucks has the following
+format.
+A sync request with id "DATA" and length equal to the chunk size. After
+follows chunk size number of bytes. This is repeated until the file is
+transfered. Each chunk must not be larger than 64k.
+
+When the file is tranfered a sync request "DONE" is sent, where length is set
+to the last modified time for the file. The server responds to this last
+request (but not to chuck requests) with an "OKAY" sync response (length can
+be ignored).
+
+
+RECV:
+Retrieves a file from device to a local file. The remote path is the path to
+the file that will be returned. Just as for the SEND sync request the file
+received is split up into chunks. The sync response id is "DATA" and length is
+the chuck size. After follows chunk size number of bytes. This is repeated
+until the file is transfered. Each chuck will not be larger than 64k.
+
+When the file is transfered a sync resopnse "DONE" is retrieved where the
+length can be ignored.
+
diff --git a/src/devtools/adb_tcp/adb.c b/src/devtools/adb_tcp/adb.c
new file mode 100644
index 0000000..f418db1
--- /dev/null
+++ b/src/devtools/adb_tcp/adb.c
@@ -0,0 +1,1824 @@
+/*
+ * 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 <grp.h> //For setgroups
+
+#include "sysdeps.h"
+#include "adb.h"
+#include "adb_auth.h"
+#include "transport_pcie.h"
+#include <log/log.h>
+#include <include/lynq_uci.h>
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+#if !ADB_HOST
+#include <cutils/properties.h>
+#include <private/android_filesystem_config.h>
+//#include <sys/capability.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <getopt.h>
+//#include <selinux/selinux.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";
+static const char *root_seclabel = NULL;
+#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 && !ADB_NON_ANDROID
+/*
+ * 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 <hardware/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;
+#if ADB_HOST && ADB_OVER_PCIE
+#endif
+}
+
+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);
+}
+
+#if (!ADB_HOST && ADB_OVER_PCIE)
+static size_t fill_connect_data(atransport *t, char *buf, size_t bufsize)
+{
+    struct pcie_info *info;
+    size_t remaining = bufsize;
+    size_t len;
+
+    len = snprintf(buf, remaining, "%s::", adb_device_banner);
+    remaining -= len;
+    buf += len;
+
+    if (t->pcie && t->pcie->info) {
+	info = t->pcie->info;
+	D("device: 0x%x\n", info->device);
+	D("vendor: 0x%x\n", info->vendor);
+	D("class: 0x%x\n", info->class);
+
+	len = snprintf(buf, remaining, "device=%x;vendor=%x;class=%x;",
+		       info->device, info->vendor, info->class);
+	remaining -= len;
+	buf += len;
+    }
+
+    return bufsize - remaining + 1;
+}
+#else
+
+#if !ADB_HOST
+static const char *cnxn_props[] = {
+    "ro.product.name",
+    "ro.product.model",
+    "ro.product.device",
+};
+#endif
+
+static size_t fill_connect_data(char *buf, size_t bufsize)
+{
+#if ADB_HOST
+    return snprintf(buf, bufsize, "host::") + 1;
+#else
+    static const int num_cnxn_props = ARRAY_SIZE(cnxn_props);
+    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], value);
+        remaining -= len;
+        buf += len;
+    }
+
+    return bufsize - remaining + 1;
+#endif
+}
+#endif /* ADB_OVER_PCIE */
+
+#if !ADB_HOST
+static void send_msg_with_header(int fd, const char* msg, size_t msglen) {
+    char header[5];
+    if (msglen > 0xffff)
+        msglen = 0xffff;
+    snprintf(header, sizeof(header), "%04x", (unsigned)msglen);
+    writex(fd, header, 4);
+    writex(fd, msg, msglen);
+}
+#endif
+
+#if ADB_HOST
+static void send_msg_with_okay(int fd, const char* msg, size_t msglen) {
+    char header[9];
+    if (msglen > 0xffff)
+        msglen = 0xffff;
+    snprintf(header, sizeof(header), "OKAY%04x", (unsigned)msglen);
+    writex(fd, header, 8);
+    writex(fd, msg, msglen);
+}
+#endif // ADB_HOST
+
+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;
+#if (!ADB_HOST && ADB_OVER_PCIE)
+    cp->msg.data_length = fill_connect_data(t, (char *)cp->data,
+                                            sizeof(cp->data));
+#else
+    cp->msg.data_length = fill_connect_data((char *)cp->data,
+                                            sizeof(cp->data));
+#endif
+    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)
+{
+    if (t == NULL) {
+        return "unknown";
+    }
+
+    switch(t->connection_state) {
+    case CS_BOOTLOADER:
+        return "bootloader";
+    case CS_DEVICE:
+        return "device";
+    case CS_RECOVERY:
+        return "recovery";
+    case CS_SIDELOAD:
+        return "sideload";
+    case CS_OFFLINE:
+        return "offline";
+    case CS_UNAUTHORIZED:
+        return "unauthorized";
+    default:
+        return "unknown";
+    }
+}
+#endif // ADB_HOST
+
+/* 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) {
+#if ADB_OVER_PCIE
+	    static const char *dev_info[] = {
+	    	"device",
+		"vendor",
+		"class",
+	    };
+
+            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, dev_info[0]))
+			t->device = cp;
+                    else if (!strcmp(key, dev_info[1]))
+			t->product = cp;
+                    else if (!strcmp(key, dev_info[2]))
+			t->serial = cp;
+                }
+                key = adb_strtok_r(NULL, prop_seps, &save);
+            }
+#else
+	    static const char **dev_info = cnxn_props;
+            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, dev_info[0]))
+                        qual_overwrite(&t->product, cp);
+                    else if (!strcmp(key, dev_info[1]))
+                        qual_overwrite(&t->model, cp);
+                    else if (!strcmp(key, dev_info[2]))
+                        qual_overwrite(&t->device, cp);
+                }
+                key = adb_strtok_r(NULL, prop_seps, &save);
+            }
+#endif
+        }
+    }
+
+    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->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;
+
+    case A_OPEN: /* OPEN(local-id, 0, "destination") */
+        if (t->online && p->msg.arg0 != 0 && p->msg.arg1 == 0) {
+            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 && p->msg.arg0 != 0 && p->msg.arg1 != 0) {
+            if((s = find_local_socket(p->msg.arg1, 0))) {
+                if(s->peer == 0) {
+                    /* On first READY message, create the connection. */
+                    s->peer = create_remote_socket(p->msg.arg0, t);
+                    s->peer->peer = s;
+                    s->ready(s);
+                } else if (s->peer->id == p->msg.arg0) {
+                    /* Other READY messages must use the same local-id */
+                    s->ready(s);
+                } else {
+                    D("Invalid A_OKAY(%d,%d), expected A_OKAY(%d,%d) on transport %s\n",
+                      p->msg.arg0, p->msg.arg1, s->peer->id, p->msg.arg1, t->serial);
+                }
+            }
+        }
+        break;
+
+    case A_CLSE: /* CLOSE(local-id, remote-id, "") or CLOSE(0, remote-id, "") */
+        if (t->online && p->msg.arg1 != 0) {
+            if((s = find_local_socket(p->msg.arg1, p->msg.arg0))) {
+                /* According to protocol.txt, p->msg.arg0 might be 0 to indicate
+                 * a failed OPEN only. However, due to a bug in previous ADB
+                 * versions, CLOSE(0, remote-id, "") was also used for normal
+                 * CLOSE() operations.
+                 *
+                 * This is bad because it means a compromised adbd could
+                 * send packets to close connections between the host and
+                 * other devices. To avoid this, only allow this if the local
+                 * socket has a peer on the same transport.
+                 */
+                if (p->msg.arg0 == 0 && s->peer && s->peer->transport != t) {
+                    D("Invalid A_CLSE(0, %u) from transport %s, expected transport %s\n",
+                      p->msg.arg1, t->serial, s->peer->transport->serial);
+                } else {
+                    s->close(s);
+                }
+            }
+        }
+        break;
+
+    case A_WRTE: /* WRITE(local-id, remote-id, <data>) */
+        if (t->online && p->msg.arg0 != 0 && p->msg.arg1 != 0) {
+            if((s = find_local_socket(p->msg.arg1, p->msg.arg0))) {
+                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;
+}
+
+#if defined(_WIN32)
+static BOOL WINAPI ctrlc_handler(DWORD type)
+{
+    exit(STATUS_CONTROL_C_EXIT);
+    return TRUE;
+}
+#endif
+
+static void adb_cleanup(void)
+{
+#ifndef ADB_OVER_PCIE
+    usb_cleanup();
+#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)
+{
+    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("/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
+
+#if ADB_HOST
+
+#ifdef WORKAROUND_BUG6558362
+#include <sched.h>
+#define AFFINITY_ENVVAR "ADB_CPU_AFFINITY_BUG6558362"
+void adb_set_affinity(void)
+{
+   cpu_set_t cpu_set;
+   const char* cpunum_str = getenv(AFFINITY_ENVVAR);
+   char* strtol_res;
+   int cpu_num;
+
+   if (!cpunum_str || !*cpunum_str)
+       return;
+   cpu_num = strtol(cpunum_str, &strtol_res, 0);
+   if (*strtol_res != '\0')
+     fatal("bad number (%s) in env var %s. Expecting 0..n.\n", cpunum_str, AFFINITY_ENVVAR);
+
+   sched_getaffinity(0, sizeof(cpu_set), &cpu_set);
+   D("orig cpu_set[0]=0x%08lx\n", cpu_set.__bits[0]);
+   CPU_ZERO(&cpu_set);
+   CPU_SET(cpu_num, &cpu_set);
+   sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
+   sched_getaffinity(0, sizeof(cpu_set), &cpu_set);
+   D("new cpu_set[0]=0x%08lx\n", cpu_set.__bits[0]);
+}
+#endif
+
+int launch_server(int server_port)
+{
+#if defined(_WIN32)
+    /* 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;
+        }
+    }
+#else /* !defined(_WIN32) */
+    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();
+    }
+#endif /* !defined(_WIN32) */
+    return 0;
+}
+#endif /* ADB_HOST */
+
+/* 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 void drop_capabilities_bounding_set_if_needed() {
+#ifdef ALLOW_ADBD_ROOT
+    char value[PROPERTY_VALUE_MAX];
+    property_get("ro.debuggable", value, "");
+    if (strcmp(value, "1") == 0) {
+        return;
+    }
+#endif
+    int i;
+    for (i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0; i++) {
+        if (i == CAP_SETUID || i == CAP_SETGID) {
+            // CAP_SETUID CAP_SETGID needed by /system/bin/run-as
+            continue;
+        }
+        int err = prctl(PR_CAPBSET_DROP, i, 0, 0, 0);
+
+        // Some kernels don't have file capabilities compiled in, and
+        // prctl(PR_CAPBSET_DROP) returns EINVAL. Don't automatically
+        // die when we see such misconfigured kernels.
+        if ((err < 0) && (errno != EINVAL)) {
+            exit(1);
+        }
+    }
+}
+
+static int should_drop_privileges() {
+#ifndef ALLOW_ADBD_ROOT
+    return 1;
+#else /* ALLOW_ADBD_ROOT */
+#ifdef ADB_NON_ANDROID
+    return 0;
+#endif /* ADB_NON_ANDROID */
+    int secure = 0;
+    char value[PROPERTY_VALUE_MAX];
+
+   /* 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)
+{
+    char tmp[20];
+#if !ADB_HOST
+    int port;
+    char value[PROPERTY_VALUE_MAX];
+
+    umask(000);
+#endif
+
+    atexit(adb_cleanup);
+#if defined(_WIN32)
+    SetConsoleCtrlHandler( ctrlc_handler, TRUE );
+#else
+    // No SIGCHLD. Let the service subproc handle its children.
+    signal(SIGPIPE, SIG_IGN);
+#endif
+
+    init_transport_registration();
+
+#if ADB_HOST
+    HOST = 1;
+
+#ifdef WORKAROUND_BUG6558362
+    if(is_daemon) adb_set_affinity();
+#endif
+
+#if ADB_OVER_PCIE
+    fprintf(stderr, "adb path: %s\n", PCIE_ADB_PATH);
+    pcie_host_init();
+#else
+    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);
+    if(install_listener(local_name, "*smartsocket*", NULL, 0)) {
+        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.
+    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");
+    }
+
+    /* 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_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_NET_BW_STATS to read out qtaguid statistics
+    */
+    gid_t groups[] = { AID_ADB, AID_LOG, AID_INPUT, AID_INET, AID_NET_BT,
+                       AID_NET_BT_ADMIN, AID_SDCARD_R, AID_SDCARD_RW,
+                       AID_NET_BW_STATS };
+    if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
+        exit(1);
+    }
+
+    /* 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()) {
+        drop_capabilities_bounding_set_if_needed();
+
+        /* then switch user and group to "shell" */
+        if (setgid(AID_SHELL) != 0) {
+            exit(1);
+        }
+        if (setuid(AID_SHELL) != 0) {
+            exit(1);
+        }
+
+        D("Local port disabled\n");
+    } else {
+#ifndef ADB_NON_ANDROID
+        char local_name[30];
+        if ((root_seclabel != NULL) && (is_selinux_enabled() > 0)) {
+            // b/12587913: fix setcon to allow const pointers
+            if (setcon((char *)root_seclabel) < 0) {
+                exit(1);
+            }
+        }
+        build_local_name(local_name, sizeof(local_name), server_port);
+        if(install_listener(local_name, "*smartsocket*", NULL, 0)) {
+            exit(1);
+        }
+#endif
+    }
+
+    int usb = 0;
+#ifdef ADB_OVER_PCIE
+    fprintf(stderr, "adbd path: %s\n", PCIE_ADB_PATH);
+    if (access(PCIE_ADB_PATH, F_OK) == 0) {
+	pcie_init();
+	usb = 1;
+    }
+#else
+  /*  if (access(USB_ADB_PATH, F_OK) == 0 || access(USB_FFS_ADB_EP0, F_OK) == 0) {
+        // listen on USB
+        usb_init();
+        usb = 1;
+    }
+  */
+#endif
+
+    // 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.
+    //FILE *f=fopen("/data/adbd.log","rb");
+#define LOG_UCI_MODULE "tcp"
+#define LOG_UCI_FILE "lynq_uci"
+
+    lynq_get_value(LOG_UCI_FILE, LOG_UCI_MODULE, "port", value); // 即获取系统层面的环境变量
+   
+    printf("ADB Daemon. port %s\n",value);
+    //fprintf(f,"usb.tcp.port=%d\n", 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) {
+        // listen on default port
+        local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
+    }
+    //fprintf(f,"usb.tcp.port=5555\n");
+    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.
+#if defined(_WIN32)
+        DWORD  count;
+        WriteFile( GetStdHandle( STD_OUTPUT_HANDLE ), "OK\n", 3, &count, NULL );
+#else
+        fprintf(stderr, "OK\n");
+#endif
+        start_logging();
+    }
+    D("Event loop starting\n");
+
+    fdevent_loop();
+
+#ifndef ADB_OVER_PCIE
+    usb_cleanup();
+#endif
+
+    return 0;
+}
+
+// Try to handle a network forwarding request.
+// This returns 1 on success, 0 on failure, and -1 to indicate this is not
+// a forwarding-related request.
+int handle_forward_request(const char* service, transport_type ttype, char* serial, int reply_fd)
+{
+    if (!strcmp(service, "list-forward")) {
+        // Create the list of forward redirections.
+        int buffer_size = format_listeners(NULL, 0);
+        // Add one byte for the trailing zero.
+        char* buffer = malloc(buffer_size + 1);
+        if (buffer == NULL) {
+            sendfailmsg(reply_fd, "not enough memory");
+            return 1;
+        }
+        (void) format_listeners(buffer, buffer_size + 1);
+#if ADB_HOST
+        send_msg_with_okay(reply_fd, buffer, buffer_size);
+#else
+        send_msg_with_header(reply_fd, buffer, buffer_size);
+#endif
+        free(buffer);
+        return 1;
+    }
+
+    if (!strcmp(service, "killforward-all")) {
+        remove_all_listeners();
+#if ADB_HOST
+        /* On the host: 1st OKAY is connect, 2nd OKAY is status */
+        adb_write(reply_fd, "OKAY", 4);
+#endif
+        adb_write(reply_fd, "OKAY", 4);
+        return 1;
+    }
+
+    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 1;
+            }
+
+            *remote++ = 0;
+            if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')) {
+                sendfailmsg(reply_fd, "malformed forward spec");
+                return 1;
+            }
+        } else {
+            // Check killforward: parameter format: '<local>'
+            if (local[0] == 0) {
+                sendfailmsg(reply_fd, "malformed forward spec");
+                return 1;
+            }
+        }
+
+        transport = acquire_one_transport(CS_ANY, ttype, serial, &err);
+        if (!transport) {
+            sendfailmsg(reply_fd, err);
+            return 1;
+        }
+
+        if (createForward) {
+            r = install_listener(local, remote, transport, no_rebind);
+        } else {
+            r = remove_listener(local, transport);
+        }
+        if(r == 0) {
+#if ADB_HOST
+            /* On the host: 1st OKAY is connect, 2nd OKAY is status */
+            writex(reply_fd, "OKAY", 4);
+#endif
+            writex(reply_fd, "OKAY", 4);
+            return 1;
+        }
+
+        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 1;
+    }
+    return 0;
+}
+
+int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s)
+{
+    if(!strcmp(service, "kill")) {
+        fprintf(stderr,"adb server killed by remote request\n");
+        fflush(stdout);
+        adb_write(reply_fd, "OKAY", 4);
+#ifndef ADB_OVER_PCIE
+        usb_cleanup();
+#endif
+        exit(0);
+    }
+
+#if ADB_HOST
+    atransport *transport = NULL;
+    // "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(buffer, 0, sizeof(buffer));
+            D("Getting device list \n");
+            list_transports(buffer, sizeof(buffer), use_long);
+            D("Wrote device list \n");
+            send_msg_with_okay(reply_fd, buffer, strlen(buffer));
+            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);
+            }
+        }
+
+        send_msg_with_okay(reply_fd, buffer, strlen(buffer));
+        return 0;
+    }
+
+    // returns our value for ADB_SERVER_VERSION
+    if (!strcmp(service, "version")) {
+        char version[12];
+        snprintf(version, sizeof version, "%04x", ADB_SERVER_VERSION);
+        send_msg_with_okay(reply_fd, version, strlen(version));
+        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;
+        }
+        send_msg_with_okay(reply_fd, out, strlen(out));
+        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;
+        }
+        send_msg_with_okay(reply_fd, out, strlen(out));
+        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;
+    }
+
+    if(!strncmp(service,"get-state",strlen("get-state"))) {
+        transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
+        char *state = connection_state_name(transport);
+        send_msg_with_okay(reply_fd, state, strlen(state));
+        return 0;
+    }
+#endif // ADB_HOST
+
+    int ret = handle_forward_request(service, ttype, serial, reply_fd);
+    if (ret >= 0)
+      return ret - 1;
+    return -1;
+}
+
+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();
+    D("main()\n");
+    while(1) {
+        int c;
+        int option_index = 0;
+        static struct option opts[] = {
+            {"root_seclabel", required_argument, 0, 's' },
+            {"device_banner", required_argument, 0, 'b' }
+        };
+        c = getopt_long(argc, argv, "", opts, &option_index);
+        if (c == -1)
+            break;
+        switch (c) {
+        case 's':
+            root_seclabel = optarg;
+            break;
+        case 'b':
+            adb_device_banner = optarg;
+            break;
+        default:
+            break;
+        }
+    }
+
+    start_device_log();
+    D("Handling main()\n");
+    return adb_main(0, DEFAULT_ADB_PORT);
+#endif
+}
diff --git a/src/devtools/adb_tcp/adb.h b/src/devtools/adb_tcp/adb.h
new file mode 100644
index 0000000..84d55d8
--- /dev/null
+++ b/src/devtools/adb_tcp/adb.h
@@ -0,0 +1,437 @@
+/*
+ * 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 "adb_trace.h"
+#include "transport.h"  /* readx(), writex() */
+
+#if ADB_OVER_PCIE
+#define MAX_PAYLOAD 3456
+#else
+#define MAX_PAYLOAD 4096
+#endif
+
+#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    32    // 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);
+
+        /* shutdown is called by the peer before it goes away.
+        ** the socket should not do any further calls on its peer.
+        ** Always followed by a call to close. Optional, i.e. can be NULL.
+        */
+    void (*shutdown)(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);
+
+        /* 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 */
+    struct usb_handle *usb;
+    struct pcie_handle *pcie;
+    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 local_id, unsigned remote_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 */
+int 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);
+void init_pcie_transport(atransport *t, struct pcie_handle *h, const char *devpath, int state);
+void register_pcie_transport(struct pcie_handle *h, 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
+
+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
+
+/* packet allocator */
+apacket *get_apacket(void);
+void put_apacket(apacket *p);
+
+int check_header(apacket *p);
+int check_data(apacket *p);
+
+#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
+#define CS_UNAUTHORIZED 7
+
+extern int HOST;
+extern int SHELL_EXIT_NOTIFY_FD;
+
+typedef enum {
+    SUBPROC_PTY = 0,
+    SUBPROC_RAW = 1,
+} subproc_mode;
+
+#define CHUNK_SIZE (64*1024)
+
+#if !ADB_HOST
+#define USB_ADB_PATH     "/dev/android_adb"
+
+#define USB_FFS_ADB_PATH  "/dev/usb-ffs/adb/"
+#define USB_FFS_ADB_EP(x) USB_FFS_ADB_PATH#x
+
+#define USB_FFS_ADB_EP0   USB_FFS_ADB_EP(ep0)
+#define USB_FFS_ADB_OUT   USB_FFS_ADB_EP(ep1)
+#define USB_FFS_ADB_IN    USB_FFS_ADB_EP(ep2)
+#endif
+
+/* PCIe interface */
+#if ADB_OVER_PCIE
+#if ADB_HOST
+#define PCIE_ADB_PATH     "/dev/ccci_sap_adb"
+#else
+#define PCIE_ADB_PATH     "/dev/ccci_hsapif_adb"
+#define PCIE_INFO_ADB_PATH     "/dev/pcie_dipc1"
+#endif /* ADB_HOST */
+#endif /* ADB_OVER_PCIE */
+
+int sendfailmsg(int fd, const char *reason);
+int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s);
+
+void pcie_init(void);
+void pcie_host_init(void);
+
+#endif
diff --git a/src/devtools/adb_tcp/adb_auth.h b/src/devtools/adb_tcp/adb_auth.h
new file mode 100644
index 0000000..b24c674
--- /dev/null
+++ b/src/devtools/adb_tcp/adb_auth.h
@@ -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);
+
+void send_auth_request(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) { }
+
+#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);
+
+#endif // ADB_HOST
+
+#endif // __ADB_AUTH_H
diff --git a/src/devtools/adb_tcp/adb_auth_client.c b/src/devtools/adb_tcp/adb_auth_client.c
new file mode 100644
index 0000000..4ce5d1e
--- /dev/null
+++ b/src/devtools/adb_tcp/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_tcp/adb_auth_host.c b/src/devtools/adb_tcp/adb_auth_host.c
new file mode 100644
index 0000000..c72fe42
--- /dev/null
+++ b/src/devtools/adb_tcp/adb_auth_host.c
@@ -0,0 +1,454 @@
+/*
+ * 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>
+
+#if defined(OPENSSL_IS_BORINGSSL)
+#include <openssl/base64.h>
+#endif
+
+#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;
+    FILE *outfile = NULL;
+    char path[PATH_MAX], info[MAX_PAYLOAD];
+    uint8_t *encoded = NULL;
+    size_t encoded_length;
+    int ret = 0;
+
+    if (snprintf(path, sizeof(path), "%s.pub", private_key_path) >=
+        (int)sizeof(path)) {
+        D("Path too long while writing public key\n");
+        return 0;
+    }
+
+    if (!RSA_to_RSAPublicKey(private_key, &pkey)) {
+        D("Failed to convert to publickey\n");
+        return 0;
+    }
+
+    outfile = fopen(path, "w");
+    if (!outfile) {
+        D("Failed to open '%s'\n", path);
+        return 0;
+    }
+
+    D("Writing public key to '%s'\n", path);
+
+#if defined(OPENSSL_IS_BORINGSSL)
+    if (!EVP_EncodedLength(&encoded_length, sizeof(pkey))) {
+        D("Public key too large to base64 encode");
+        goto out;
+    }
+#else
+    /* While we switch from OpenSSL to BoringSSL we have to implement
+     * |EVP_EncodedLength| here. */
+    encoded_length = 1 + ((sizeof(pkey) + 2) / 3 * 4);
+#endif
+
+    encoded = malloc(encoded_length);
+    if (encoded == NULL) {
+        D("Allocation failure");
+        goto out;
+    }
+
+    encoded_length = EVP_EncodeBlock(encoded, (uint8_t*) &pkey, sizeof(pkey));
+    get_user_info(info, sizeof(info));
+
+    if (fwrite(encoded, encoded_length, 1, outfile) != 1 ||
+        fwrite(info, strlen(info), 1, outfile) != 1) {
+        D("Write error while writing public key");
+        goto out;
+    }
+
+    ret = 1;
+
+ out:
+    if (outfile != NULL) {
+        fclose(outfile);
+    }
+    if (encoded != NULL) {
+        free(encoded);
+    }
+    return ret;
+}
+
+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);
+}
diff --git a/src/devtools/adb_tcp/adb_client.c b/src/devtools/adb_tcp/adb_client.c
new file mode 100644
index 0000000..b511c4b
--- /dev/null
+++ b/src/devtools/adb_tcp/adb_client.c
@@ -0,0 +1,347 @@
+#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];
+        size_t 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 > 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 == -1) {
+        D("_adb_connect error: %s\n", __adb_error);
+    } else 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) {
+        fprintf(stderr, "error: %s\n", adb_error());
+        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 >= 0xffff) {
+        strcpy(__adb_error, "reply is too long (>= 64kB)");
+        goto oops;
+    }
+    D("buf = %s\n", buf);
+
+    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;
+}
diff --git a/src/devtools/adb_tcp/adb_client.h b/src/devtools/adb_tcp/adb_client.h
new file mode 100644
index 0000000..0ec47ca
--- /dev/null
+++ b/src/devtools/adb_tcp/adb_client.h
@@ -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
diff --git a/src/devtools/adb_tcp/adb_trace.h b/src/devtools/adb_tcp/adb_trace.h
new file mode 100644
index 0000000..32c3cc6
--- /dev/null
+++ b/src/devtools/adb_tcp/adb_trace.h
@@ -0,0 +1,144 @@
+/*
+ * 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
+
+/* define ADB_TRACE to 1 to enable tracing support, or 0 to disable it */
+#define  ADB_TRACE    0
+
+/* 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,
+} 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_tcp/adbd_pcie.init b/src/devtools/adb_tcp/adbd_pcie.init
new file mode 100644
index 0000000..d8bf1af
--- /dev/null
+++ b/src/devtools/adb_tcp/adbd_pcie.init
@@ -0,0 +1,16 @@
+#!/bin/sh /etc/rc.common
+
+USE_PROCD=1
+
+START=99
+STOP=99
+
+start_service() {
+    echo "start adbd_pcie"
+    procd_set_param stdout 1
+    procd_set_param stderr 1
+    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_tcp/b64_pton.c b/src/devtools/adb_tcp/b64_pton.c
new file mode 100644
index 0000000..e5c3153
--- /dev/null
+++ b/src/devtools/adb_tcp/b64_pton.c
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 1996, 1998 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/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define Assert(Cond) if (!(Cond)) abort()
+
+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.
+   */
+
+/* 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.
+ */
+
+static int b64rmap_initialized = 0;
+static uint8_t b64rmap[256];
+
+static const uint8_t b64rmap_special = 0xf0;
+static const uint8_t b64rmap_end = 0xfd;
+static const uint8_t b64rmap_space = 0xfe;
+static const uint8_t b64rmap_invalid = 0xff;
+
+/**
+ * Initializing the reverse map is not thread safe.
+ * Which is fine for NSD. For now...
+ **/
+static void
+b64_initialize_rmap ()
+{
+	int i;
+	char ch;
+
+	/* Null: end of string, stop parsing */
+	b64rmap[0] = b64rmap_end;
+
+	for (i = 1; i < 256; ++i) {
+		ch = (char)i;
+		/* Whitespaces */
+		if (isspace(ch))
+			b64rmap[i] = b64rmap_space;
+		/* Padding: stop parsing */
+		else if (ch == Pad64)
+			b64rmap[i] = b64rmap_end;
+		/* Non-base64 char */
+		else
+			b64rmap[i] = b64rmap_invalid;
+	}
+
+	/* Fill reverse mapping for base64 chars */
+	for (i = 0; Base64[i] != '\0'; ++i)
+		b64rmap[(uint8_t)Base64[i]] = i;
+
+	b64rmap_initialized = 1;
+}
+
+static int
+b64_pton_do(char const *src, uint8_t *target, size_t targsize)
+{
+	int tarindex, state, ch;
+	uint8_t ofs;
+
+	state = 0;
+	tarindex = 0;
+
+	while (1)
+	{
+		ch = *src++;
+		ofs = b64rmap[ch];
+
+		if (ofs >= b64rmap_special) {
+			/* Ignore whitespaces */
+			if (ofs == b64rmap_space)
+				continue;
+			/* End of base64 characters */
+			if (ofs == b64rmap_end)
+				break;
+			/* A non-base64 character. */
+			return (-1);
+		}
+
+		switch (state) {
+		case 0:
+			if ((size_t)tarindex >= targsize)
+				return (-1);
+			target[tarindex] = ofs << 2;
+			state = 1;
+			break;
+		case 1:
+			if ((size_t)tarindex + 1 >= targsize)
+				return (-1);
+			target[tarindex]   |=  ofs >> 4;
+			target[tarindex+1]  = (ofs & 0x0f)
+						<< 4 ;
+			tarindex++;
+			state = 2;
+			break;
+		case 2:
+			if ((size_t)tarindex + 1 >= targsize)
+				return (-1);
+			target[tarindex]   |=  ofs >> 2;
+			target[tarindex+1]  = (ofs & 0x03)
+						<< 6;
+			tarindex++;
+			state = 3;
+			break;
+		case 3:
+			if ((size_t)tarindex >= targsize)
+				return (-1);
+			target[tarindex] |= ofs;
+			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 ((void)NULL; ch != '\0'; ch = *src++)
+				if (b64rmap[ch] != b64rmap_space)
+					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 ((void)NULL; ch != '\0'; ch = *src++)
+				if (b64rmap[ch] != b64rmap_space)
+					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[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);
+}
+
+
+static int
+b64_pton_len(char const *src)
+{
+	int tarindex, state, ch;
+	uint8_t ofs;
+
+	state = 0;
+	tarindex = 0;
+
+	while (1)
+	{
+		ch = *src++;
+		ofs = b64rmap[ch];
+
+		if (ofs >= b64rmap_special) {
+			/* Ignore whitespaces */
+			if (ofs == b64rmap_space)
+				continue;
+			/* End of base64 characters */
+			if (ofs == b64rmap_end)
+				break;
+			/* A non-base64 character. */
+			return (-1);
+		}
+
+		switch (state) {
+		case 0:
+			state = 1;
+			break;
+		case 1:
+			tarindex++;
+			state = 2;
+			break;
+		case 2:
+			tarindex++;
+			state = 3;
+			break;
+		case 3:
+			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 ((void)NULL; ch != '\0'; ch = *src++)
+				if (b64rmap[ch] != b64rmap_space)
+					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 ((void)NULL; ch != '\0'; ch = *src++)
+				if (b64rmap[ch] != b64rmap_space)
+					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);
+}
+
+
+int
+b64_pton(char const *src, uint8_t *target, size_t targsize)
+{
+	if (!b64rmap_initialized)
+		b64_initialize_rmap ();
+
+	if (target)
+		return b64_pton_do (src, target, targsize);
+	else
+		return b64_pton_len (src);
+}
diff --git a/src/devtools/adb_tcp/commandline.c b/src/devtools/adb_tcp/commandline.c
new file mode 100644
index 0000000..1a85de2
--- /dev/null
+++ b/src/devtools/adb_tcp/commandline.c
@@ -0,0 +1,2083 @@
+/*
+ * 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 <stdint.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"
+
+#if !defined(_WIN32)
+#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, 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);
+
+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 [-p] <local> <remote>\n"
+        "                               - copy file/dir to device\n"
+        "                                 ('-p' to display the transfer progress)\n"
+        "  adb pull [-p] [-a] <remote> [<local>]\n"
+        "                               - copy file/dir from device\n"
+        "                                 ('-p' to display the transfer progress)\n"
+        "                                 ('-a' means copy timestamp and mode)\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 logread [ <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 reverse --list           - list all reverse socket connections from device\n"
+        "  adb reverse <remote> <local> - reverse socket connections\n"
+        "                                 reverse 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"
+        "  adb reverse --norebind <remote> <local>\n"
+        "                               - same as 'adb reverse <remote> <local>' but fails\n"
+        "                                 if <remote> is already reversed.\n"
+        "  adb reverse --remove <remote>\n"
+        "                               - remove a specific reversed socket connection\n"
+        "  adb reverse --remove-all     - remove all reversed socket connections from device\n"
+        "  adb jdwp                     - list PIDs of processes hosting a JDWP transport\n"
+        "  adb install [-lrtsd] <file>\n"
+        "  adb install-multiple [-lrtsdp] <file...>\n"
+        "                               - push this package file to the device and install it\n"
+        "                                 (-l: forward lock application)\n"
+        "                                 (-r: replace existing application)\n"
+        "                                 (-t: allow test packages)\n"
+        "                                 (-s: install application on sdcard)\n"
+        "                                 (-d: allow version code downgrade)\n"
+        "                                 (-p: partial application install)\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] [-obb|-noobb] [-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"
+        "                                 (-obb|-noobb enable/disable backup of any installed apk expansion\n"
+        "                                    (aka .obb) files associated with each application; the default\n"
+        "                                    is noobb.)\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 and /vendor (if present) partitions 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 reconnect                - restarts the adbd daemon\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, /system, /vendor (if present), and /data partitions will be updated.\n"
+        "\n"
+        "  - If it is \"system\", \"vendor\" 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;
+}
+
+#if defined(_WIN32)
+
+// Windows does not have <termio.h>.
+static void stdin_raw_init(int fd) {
+
+}
+
+static void stdin_raw_restore(int fd) {
+
+}
+
+#else
+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 read_status_line(int fd, char* buf, size_t count)
+{
+    count--;
+    while (count > 0) {
+        int len = adb_read(fd, buf, count);
+        if (len == 0) {
+            break;
+        } else if (len < 0) {
+            if (errno == EINTR) continue;
+            break;
+        }
+
+        buf += len;
+        count -= len;
+    }
+    *buf = '\0';
+}
+
+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);
+
+    if (inFd == STDIN_FILENO) {
+        stdin_raw_init(STDIN_FILENO);
+    }
+
+    for (;;) {
+        if (inFd == STDIN_FILENO) {
+            len = unix_read(inFd, buf, BUFSIZE);
+        } else {
+            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;
+        }
+        if (outFd == STDOUT_FILENO) {
+            fwrite(buf, 1, len, stdout);
+            fflush(stdout);
+        } else {
+            adb_write(outFd, buf, len);
+        }
+        total += len;
+    }
+
+    if (inFd == STDIN_FILENO) {
+        stdin_raw_restore(STDIN_FILENO);
+    }
+
+    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");
+                    stdin_raw_restore(fdi);
+                    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;
+
+    stdin_raw_init(fdi);
+    adb_thread_create(&thr, stdin_read_thread, fds);
+    read_and_dump(fd);
+    stdin_raw_restore(fdi);
+    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 char *fn, 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, (const void *) &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", fn, (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", fn);
+        return -1;
+    }
+
+    int status = adb_download_buffer(service, fn, data, sz, progress);
+    free(data);
+    return status;
+}
+
+#define SIDELOAD_HOST_BLOCK_SIZE (CHUNK_SIZE)
+
+/*
+ * The sideload-host protocol serves the data in a file (given on the
+ * command line) to the client, using a simple protocol:
+ *
+ * - The connect message includes the total number of bytes in the
+ *   file and a block size chosen by us.
+ *
+ * - The other side sends the desired block number as eight decimal
+ *   digits (eg "00000023" for block 23).  Blocks are numbered from
+ *   zero.
+ *
+ * - We send back the data of the requested block.  The last block is
+ *   likely to be partial; when the last block is requested we only
+ *   send the part of the block that exists, it's not padded up to the
+ *   block size.
+ *
+ * - When the other side sends "DONEDONE" instead of a block number,
+ *   we hang up.
+ */
+int adb_sideload_host(const char* fn) {
+    uint8_t* data;
+    unsigned sz;
+    size_t xfer = 0;
+    int status;
+
+    printf("loading: '%s'", fn);
+    fflush(stdout);
+    data = load_file(fn, &sz);
+    if (data == 0) {
+        printf("\n");
+        fprintf(stderr, "* cannot read '%s' *\n", fn);
+        return -1;
+    }
+
+    char buf[100];
+    sprintf(buf, "sideload-host:%d:%d", sz, SIDELOAD_HOST_BLOCK_SIZE);
+    int fd = adb_connect(buf);
+    if (fd < 0) {
+        // Try falling back to the older sideload method.  Maybe this
+        // is an older device that doesn't support sideload-host.
+        printf("\n");
+        status = adb_download_buffer("sideload", fn, data, sz, 1);
+        goto done;
+    }
+
+    int opt = SIDELOAD_HOST_BLOCK_SIZE;
+    opt = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &opt, sizeof(opt));
+
+    int last_percent = -1;
+    for (;;) {
+        if (readx(fd, buf, 8)) {
+            fprintf(stderr, "* failed to read command: %s\n", adb_error());
+            status = -1;
+            goto done;
+        }
+
+        if (strncmp("DONEDONE", buf, 8) == 0) {
+            status = 0;
+            break;
+        }
+
+        buf[8] = '\0';
+        int block = strtol(buf, NULL, 10);
+
+        size_t offset = block * SIDELOAD_HOST_BLOCK_SIZE;
+        if (offset >= sz) {
+            fprintf(stderr, "* attempt to read past end: %s\n", adb_error());
+            status = -1;
+            goto done;
+        }
+        uint8_t* start = data + offset;
+        size_t offset_end = offset + SIDELOAD_HOST_BLOCK_SIZE;
+        size_t to_write = SIDELOAD_HOST_BLOCK_SIZE;
+        if (offset_end > sz) {
+            to_write = sz - offset;
+        }
+
+        if(writex(fd, start, to_write)) {
+            adb_status(fd);
+            fprintf(stderr,"* failed to write data '%s' *\n", adb_error());
+            status = -1;
+            goto done;
+        }
+        xfer += to_write;
+
+        // For normal OTA packages, we expect to transfer every byte
+        // twice, plus a bit of overhead (one read during
+        // verification, one read of each byte for installation, plus
+        // extra access to things like the zip central directory).
+        // This estimate of the completion becomes 100% when we've
+        // transferred ~2.13 (=100/47) times the package size.
+        int percent = (int)(xfer * 47LL / (sz ? sz : 1));
+        if (percent != last_percent) {
+            printf("\rserving: '%s'  (~%d%%)    ", fn, percent);
+            fflush(stdout);
+            last_percent = percent;
+        }
+    }
+
+    printf("\rTotal xfer: %.2fx%*s\n", (double)xfer / (sz ? sz : 1), (int)strlen(fn)+10, "");
+
+  done:
+    if (fd >= 0) adb_close(fd);
+    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);
+    }
+}
+
+static int should_escape(const char c)
+{
+    return (c == ' ' || c == '\'' || c == '"' || c == '\\' || c == '(' || c == ')');
+}
+
+/* Duplicate and escape given argument. */
+static char *escape_arg(const char *s)
+{
+    const char *ts;
+    size_t alloc_len;
+    char *ret;
+    char *dest;
+
+    alloc_len = 0;
+    for (ts = s; *ts != '\0'; ts++) {
+        alloc_len++;
+        if (should_escape(*ts)) {
+            alloc_len++;
+        }
+    }
+
+    if (alloc_len == 0) {
+        // Preserve empty arguments
+        ret = (char *) malloc(3);
+        ret[0] = '\"';
+        ret[1] = '\"';
+        ret[2] = '\0';
+        return ret;
+    }
+
+    ret = (char *) malloc(alloc_len + 1);
+    dest = ret;
+
+    for (ts = s; *ts != '\0'; ts++) {
+        if (should_escape(*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)
+{
+#if defined(_WIN32)
+    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 /* !defined(_WIN32) */
+}
+
+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 = getenv("ANDROID_LOG_TAGS");
+    quoted = escape_arg(log_tags == NULL ? "" : log_tags);
+    snprintf(buf, sizeof(buf),
+            "shell:export ANDROID_LOG_TAGS=\"%s\"; exec logcat", quoted);
+    free(quoted);
+
+    if (!strcmp(argv[0], "longcat")) {
+        strncat(buf, " -v long", sizeof(buf) - 1);
+    }
+
+    argc -= 1;
+    argv += 1;
+    while(argc-- > 0) {
+        quoted = escape_arg(*argv++);
+        strncat(buf, " ", sizeof(buf) - 1);
+        strncat(buf, quoted, sizeof(buf) - 1);
+        free(quoted);
+    }
+
+    send_shellcommand(transport, serial, buf);
+    return 0;
+}
+
+static int mkdirs(const char *path)
+{
+    int ret;
+    char *x = (char *)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(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 restore\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;
+}
+
+static void parse_push_pull_args(char **arg, int narg, char const **path1, char const **path2,
+                                 int *show_progress, int *copy_attrs) {
+    *show_progress = 0;
+    *copy_attrs = 0;
+
+    while (narg > 0) {
+        if (!strcmp(*arg, "-p")) {
+            *show_progress = 1;
+        } else if (!strcmp(*arg, "-a")) {
+            *copy_attrs = 1;
+        } else {
+            break;
+        }
+        ++arg;
+        --narg;
+    }
+
+    if (narg > 0) {
+        *path1 = *arg;
+        ++arg;
+        --narg;
+    }
+
+    if (narg > 0) {
+        *path2 = *arg;
+    }
+}
+
+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;
+    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) {
+            char *quoted = escape_arg(*argv++);
+            strncat(buf, " ", sizeof(buf) - 1);
+            strncat(buf, quoted, sizeof(buf) - 1);
+            free(quoted);
+        }
+
+        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], "exec-in") || !strcmp(argv[0], "exec-out")) {
+        int exec_in = !strcmp(argv[0], "exec-in");
+        int fd;
+
+        snprintf(buf, sizeof buf, "exec:%s", argv[1]);
+        argc -= 2;
+        argv += 2;
+        while (argc-- > 0) {
+            char *quoted = escape_arg(*argv++);
+            strncat(buf, " ", sizeof(buf) - 1);
+            strncat(buf, quoted, sizeof(buf) - 1);
+            free(quoted);
+        }
+
+        fd = adb_connect(buf);
+        if (fd < 0) {
+            fprintf(stderr, "error: %s\n", adb_error());
+            return -1;
+        }
+
+        if (exec_in) {
+            copy_to_file(STDIN_FILENO, fd);
+        } else {
+            copy_to_file(fd, STDOUT_FILENO);
+        }
+
+        adb_close(fd);
+        return 0;
+    }
+
+    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_sideload_host(argv[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") || !strcmp(argv[0], "reconnect")) {
+        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") ||
+       !strcmp(argv[0], "reverse"))
+    {
+        char host_prefix[64];
+        char reverse = (char) !strcmp(argv[0], "reverse");
+        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 (reverse) {
+            snprintf(host_prefix, sizeof host_prefix, "reverse");
+        } else {
+            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")) {
+        int show_progress = 0;
+        int copy_attrs = 0; // unused
+        const char* lpath = NULL, *rpath = NULL;
+
+        parse_push_pull_args(&argv[1], argc - 1, &lpath, &rpath, &show_progress, &copy_attrs);
+
+        if ((lpath != NULL) && (rpath != NULL)) {
+            return do_sync_push(lpath, rpath, show_progress);
+        }
+
+        return usage();
+    }
+
+    if(!strcmp(argv[0], "pull")) {
+        int show_progress = 0;
+        int copy_attrs = 0;
+        const char* rpath = NULL, *lpath = ".";
+
+        parse_push_pull_args(&argv[1], argc - 1, &rpath, &lpath, &show_progress, &copy_attrs);
+
+        if (rpath != NULL) {
+            return do_sync_pull(rpath, lpath, show_progress, copy_attrs);
+        }
+
+        return usage();
+    }
+
+    if (!strcmp(argv[0], "install")) {
+        if (argc < 2) return usage();
+        return install_app(ttype, serial, argc, argv);
+    }
+
+    if (!strcmp(argv[0], "install-multiple")) {
+        if (argc < 2) return usage();
+        return install_multiple_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, *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 */
+
+    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") || !strcmp(argv[0], "logread")) {
+        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;
+}
+
+#define MAX_ARGV_LENGTH 16
+static int do_cmd(transport_type ttype, char* serial, char *cmd, ...)
+{
+    char *argv[MAX_ARGV_LENGTH];
+    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(argc < MAX_ARGV_LENGTH &&
+        (argv[argc] = va_arg(ap, char*)) != 0) argc++;
+    assert(argc < MAX_ARGV_LENGTH);
+    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 **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)
+{
+    char buf[4096];
+
+    snprintf(buf, sizeof(buf), "shell:pm");
+
+    while(argc-- > 0) {
+        char *quoted = escape_arg(*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 -f ");
+    quoted = escape_arg(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;
+    }
+}
+
+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;
+    int i;
+    struct stat sb;
+
+    for (i = 1; i < argc; i++) {
+        if (!strcmp(argv[i], "-s")) {
+            where = SD_DEST;
+        }
+    }
+
+    // Find last APK argument.
+    // All other arguments passed through verbatim.
+    int last_apk = -1;
+    for (i = argc - 1; i >= 0; i--) {
+        char* file = argv[i];
+        char* dot = strrchr(file, '.');
+        if (dot && !strcasecmp(dot, ".apk")) {
+            if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) {
+                fprintf(stderr, "Invalid APK file: %s\n", file);
+                return -1;
+            }
+
+            last_apk = i;
+            break;
+        }
+    }
+
+    if (last_apk == -1) {
+        fprintf(stderr, "Missing APK file\n");
+        return -1;
+    }
+
+    char* apk_file = argv[last_apk];
+    char apk_dest[PATH_MAX];
+    snprintf(apk_dest, sizeof apk_dest, where, get_basename(apk_file));
+    int err = do_sync_push(apk_file, apk_dest, 0 /* no show progress */);
+    if (err) {
+        goto cleanup_apk;
+    } else {
+        argv[last_apk] = apk_dest; /* destination name, not source location */
+    }
+
+    pm_command(transport, serial, argc, argv);
+
+cleanup_apk:
+    delete_file(transport, serial, apk_dest);
+    return err;
+}
+
+int install_multiple_app(transport_type transport, char* serial, int argc, char** argv)
+{
+    char buf[1024];
+    int i;
+    struct stat sb;
+    unsigned long long total_size = 0;
+
+    // Find all APK arguments starting at end.
+    // All other arguments passed through verbatim.
+    int first_apk = -1;
+    for (i = argc - 1; i >= 0; i--) {
+        char* file = argv[i];
+        char* dot = strrchr(file, '.');
+        if (dot && !strcasecmp(dot, ".apk")) {
+            if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) {
+                fprintf(stderr, "Invalid APK file: %s\n", file);
+                return -1;
+            }
+
+            total_size += sb.st_size;
+            first_apk = i;
+        } else {
+            break;
+        }
+    }
+
+    if (first_apk == -1) {
+        fprintf(stderr, "Missing APK file\n");
+        return 1;
+    }
+
+    snprintf(buf, sizeof(buf), "exec:pm install-create -S %lld", total_size);
+    for (i = 1; i < first_apk; i++) {
+        char *quoted = escape_arg(argv[i]);
+        strncat(buf, " ", sizeof(buf) - 1);
+        strncat(buf, quoted, sizeof(buf) - 1);
+        free(quoted);
+    }
+
+    // Create install session
+    int fd = adb_connect(buf);
+    if (fd < 0) {
+        fprintf(stderr, "Connect error for create: %s\n", adb_error());
+        return -1;
+    }
+    read_status_line(fd, buf, sizeof(buf));
+    adb_close(fd);
+
+    int session_id = -1;
+    if (!strncmp("Success", buf, 7)) {
+        char* start = strrchr(buf, '[');
+        char* end = strrchr(buf, ']');
+        if (start && end) {
+            *end = '\0';
+            session_id = strtol(start + 1, NULL, 10);
+        }
+    }
+    if (session_id < 0) {
+        fprintf(stderr, "Failed to create session\n");
+        fputs(buf, stderr);
+        return -1;
+    }
+
+    // Valid session, now stream the APKs
+    int success = 1;
+    for (i = first_apk; i < argc; i++) {
+        char* file = argv[i];
+        if (stat(file, &sb) == -1) {
+            fprintf(stderr, "Failed to stat %s\n", file);
+            success = 0;
+            goto finalize_session;
+        }
+
+        snprintf(buf, sizeof(buf), "exec:pm install-write -S %lld %d %d_%s -",
+                (long long int) sb.st_size, session_id, i, get_basename(file));
+
+        int localFd = adb_open(file, O_RDONLY);
+        if (localFd < 0) {
+            fprintf(stderr, "Failed to open %s: %s\n", file, adb_error());
+            success = 0;
+            goto finalize_session;
+        }
+
+        int remoteFd = adb_connect(buf);
+        if (remoteFd < 0) {
+            fprintf(stderr, "Connect error for write: %s\n", adb_error());
+            adb_close(localFd);
+            success = 0;
+            goto finalize_session;
+        }
+
+        copy_to_file(localFd, remoteFd);
+        read_status_line(remoteFd, buf, sizeof(buf));
+
+        adb_close(localFd);
+        adb_close(remoteFd);
+
+        if (strncmp("Success", buf, 7)) {
+            fprintf(stderr, "Failed to write %s\n", file);
+            fputs(buf, stderr);
+            success = 0;
+            goto finalize_session;
+        }
+    }
+
+finalize_session:
+    // Commit session if we streamed everything okay; otherwise abandon
+    if (success) {
+        snprintf(buf, sizeof(buf), "exec:pm install-commit %d", session_id);
+    } else {
+        snprintf(buf, sizeof(buf), "exec:pm install-abandon %d", session_id);
+    }
+
+    fd = adb_connect(buf);
+    if (fd < 0) {
+        fprintf(stderr, "Connect error for finalize: %s\n", adb_error());
+        return -1;
+    }
+    read_status_line(fd, buf, sizeof(buf));
+    adb_close(fd);
+
+    if (!strncmp("Success", buf, 7)) {
+        fputs(buf, stderr);
+        return 0;
+    } else {
+        fprintf(stderr, "Failed to finalize session\n");
+        fputs(buf, stderr);
+        return -1;
+    }
+}
diff --git a/src/devtools/adb_tcp/console.c b/src/devtools/adb_tcp/console.c
new file mode 100644
index 0000000..b813d33
--- /dev/null
+++ b/src/devtools/adb_tcp/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_tcp/fdevent.c b/src/devtools/adb_tcp/fdevent.c
new file mode 100644
index 0000000..43e600c
--- /dev/null
+++ b/src/devtools/adb_tcp/fdevent.c
@@ -0,0 +1,686 @@
+/* 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 "adb_trace.h"
+#include "fdevent.h"
+#include "transport.h"
+#include "sysdeps.h"
+
+#define TRACE_TAG  TRACE_FDEVENT
+
+/* !!! 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
+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 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);
+        }
+    }
+}
diff --git a/src/devtools/adb_tcp/fdevent.h b/src/devtools/adb_tcp/fdevent.h
new file mode 100644
index 0000000..a0ebe2a
--- /dev/null
+++ b/src/devtools/adb_tcp/fdevent.h
@@ -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
diff --git a/src/devtools/adb_tcp/file_sync_client.c b/src/devtools/adb_tcp/file_sync_client.c
new file mode 100644
index 0000000..ad59e81
--- /dev/null
+++ b/src/devtools/adb_tcp/file_sync_client.c
@@ -0,0 +1,1035 @@
+/*
+ * 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 <utime.h>
+
+#include "sysdeps.h"
+#include "adb.h"
+#include "adb_client.h"
+#include "file_sync_service.h"
+
+
+static unsigned long long 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",
+            ((total_bytes * 1000000LL) / t) / 1024LL,
+            total_bytes, (t / 1000000LL), (t % 1000000LL) / 1000LL);
+}
+
+static const char* transfer_progress_format = "\rTransferring: %llu/%llu (%d%%)";
+
+static void print_transfer_progress(unsigned long long bytes_current,
+                                    unsigned long long bytes_total) {
+    if (bytes_total == 0) return;
+
+    fprintf(stderr, transfer_progress_format, bytes_current, bytes_total,
+            (int) (bytes_current * 100 / bytes_total));
+
+    if (bytes_current == bytes_total) {
+        fputc('\n', stderr);
+    }
+
+    fflush(stderr);
+}
+
+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 int *timestamp,
+                  unsigned int *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;
+    }
+
+    *timestamp = ltohl(msg.stat.time);
+    *mode = ltohl(msg.stat.mode);
+    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 show_progress)
+{
+    int lfd, err = 0;
+    unsigned long long size = 0;
+
+    lfd = adb_open(path, O_RDONLY);
+    if(lfd < 0) {
+        fprintf(stderr,"cannot open '%s': %s\n", path, strerror(errno));
+        return -1;
+    }
+
+    if (show_progress) {
+        // Determine local file size.
+        struct stat st;
+        if (fstat(lfd, &st)) {
+            fprintf(stderr,"cannot stat '%s': %s\n", path, strerror(errno));
+            return -1;
+        }
+
+        size = st.st_size;
+    }
+
+    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;
+
+        if (show_progress) {
+            print_transfer_progress(total_bytes, size);
+        }
+    }
+
+    adb_close(lfd);
+    return err;
+}
+
+static int write_data_buffer(int fd, char* file_buffer, int size, syncsendbuf *sbuf,
+                             int show_progress)
+{
+    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;
+
+        if (show_progress) {
+            print_transfer_progress(total, size);
+        }
+    }
+
+    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 show_progress)
+{
+    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);
+
+    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, show_progress);
+        free(file_buffer);
+    } else if (S_ISREG(mode))
+        write_data_file(fd, lpath, sbuf, show_progress);
+#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(const char *name)
+{
+    int ret;
+    char *x = (char *)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, int show_progress)
+{
+    syncmsg msg;
+    int len;
+    int lfd = -1;
+    char *buffer = send_buffer.data;
+    unsigned id;
+    unsigned long long size = 0;
+
+    len = strlen(rpath);
+    if(len > 1024) return -1;
+
+    if (show_progress) {
+        // Determine remote file size.
+        syncmsg stat_msg;
+        stat_msg.req.id = ID_STAT;
+        stat_msg.req.namelen = htoll(len);
+
+        if (writex(fd, &stat_msg.req, sizeof(stat_msg.req)) ||
+            writex(fd, rpath, len)) {
+            return -1;
+        }
+
+        if (readx(fd, &stat_msg.stat, sizeof(stat_msg.stat))) {
+            return -1;
+        }
+
+        if (stat_msg.stat.id != ID_STAT) return -1;
+
+        size = ltohl(stat_msg.stat.size);
+    }
+
+    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(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;
+
+        if (show_progress) {
+            print_transfer_progress(total_bytes, size);
+        }
+    }
+
+    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);
+
+        if(!lstat(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));
+                    free(ci);
+                    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;
+                }
+            }
+        } else {
+            fprintf(stderr, "cannot lstat '%s': %s\n",stat_path , strerror(errno));
+        }
+    }
+
+    closedir(d);
+
+    for(ci = dirlist; ci != 0; ci = next) {
+        next = ci->next;
+        local_build_list(filelist, ci->src, ci->dst);
+        free(ci);
+    }
+
+    return 0;
+}
+
+
+static int copy_local_dir_remote(int fd, const char *lpath, const char *rpath, int checktimestamps, int listonly)
+{
+    copyinfo *filelist = 0;
+    copyinfo *ci, *next;
+    int pushed = 0;
+    int skipped = 0;
+
+    if((lpath[0] == 0) || (rpath[0] == 0)) return -1;
+    if(lpath[strlen(lpath) - 1] != '/') {
+        int  tmplen = strlen(lpath)+2;
+        char *tmp = malloc(tmplen);
+        if(tmp == 0) return -1;
+        snprintf(tmp, tmplen, "%s/",lpath);
+        lpath = tmp;
+    }
+    if(rpath[strlen(rpath) - 1] != '/') {
+        int tmplen = strlen(rpath)+2;
+        char *tmp = malloc(tmplen);
+        if(tmp == 0) return -1;
+        snprintf(tmp, tmplen, "%s/",rpath);
+        rpath = tmp;
+    }
+
+    if(local_build_list(&filelist, lpath, rpath)) {
+        return -1;
+    }
+
+    if(checktimestamps){
+        for(ci = filelist; ci != 0; ci = ci->next) {
+            if(sync_start_readtime(fd, ci->dst)) {
+                return 1;
+            }
+        }
+        for(ci = filelist; ci != 0; ci = ci->next) {
+            unsigned int timestamp, mode, size;
+            if(sync_finish_readtime(fd, &timestamp, &mode, &size))
+                return 1;
+            if(size == ci->size) {
+                /* for links, we cannot update the atime/mtime */
+                if((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
+                    (S_ISLNK(ci->mode & mode) && timestamp >= ci->time))
+                    ci->flag = 1;
+            }
+        }
+    }
+    for(ci = filelist; ci != 0; ci = next) {
+        next = ci->next;
+        if(ci->flag == 0) {
+            fprintf(stderr,"%spush: %s -> %s\n", listonly ? "would " : "", ci->src, ci->dst);
+            if(!listonly &&
+               sync_send(fd, ci->src, ci->dst, ci->time, ci->mode,
+                         0 /* no show progress */)) {
+                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 show_progress)
+{
+    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, show_progress)) {
+            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 set_time_and_mode(const char *lpath, unsigned int time, unsigned int mode)
+{
+    struct utimbuf times = { time, time };
+    int r1 = utime(lpath, &times);
+
+    /* use umask for permissions */
+    mode_t mask=umask(0000);
+    umask(mask);
+    int r2 = chmod(lpath, mode & ~mask);
+
+    return r1 ? : r2;
+}
+
+static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath,
+                                 int copy_attrs)
+{
+    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;
+    }
+
+    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, 0 /* no show progress */)) {
+                return 1;
+            }
+
+            if (copy_attrs && set_time_and_mode(ci->dst, ci->time, ci->mode)) {
+               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, int show_progress, int copy_attrs)
+{
+    unsigned mode, time;
+    struct stat st;
+
+    int fd;
+
+    fd = adb_connect("sync:");
+    if(fd < 0) {
+        fprintf(stderr,"error: %s\n", adb_error());
+        return 1;
+    }
+
+    if(sync_readtime(fd, rpath, &time, &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, show_progress)) {
+            return 1;
+        } else {
+            if (copy_attrs && set_time_and_mode(lpath, time, mode))
+                return 1;
+            END();
+            sync_quit(fd);
+            return 0;
+        }
+    } else if(S_ISDIR(mode)) {
+        BEGIN();
+        if (copy_remote_dir_local(fd, rpath, lpath, copy_attrs)) {
+            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;
+    }
+}
diff --git a/src/devtools/adb_tcp/file_sync_service.c b/src/devtools/adb_tcp/file_sync_service.c
new file mode 100644
index 0000000..b2a8bc6
--- /dev/null
+++ b/src/devtools/adb_tcp/file_sync_service.c
@@ -0,0 +1,488 @@
+/*
+ * 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 <unistd.h>
+
+#include <errno.h>
+#include <private/android_filesystem_config.h>
+
+#ifndef ADB_NON_ANDROID
+#include <selinux/android.h>
+#endif
+#include "sysdeps.h"
+
+#define TRACE_TAG  TRACE_SYNC
+#include "adb.h"
+#include "file_sync_service.h"
+
+/* TODO: use fs_config to configure permissions on /data */
+static bool is_on_system(const char *name) {
+    const char *SYSTEM = "/system/";
+    return (strncmp(SYSTEM, name, strlen(SYSTEM)) == 0);
+}
+
+static bool is_on_vendor(const char *name) {
+    const char *VENDOR = "/vendor/";
+    return (strncmp(VENDOR, name, strlen(VENDOR)) == 0);
+}
+
+static int mkdirs(char *name)
+{
+    int ret;
+    char *x = name + 1;
+    uid_t uid = -1;
+    gid_t gid = -1;
+    unsigned int mode = 0775;
+    uint64_t cap = 0;
+
+    if(name[0] != '/') return -1;
+
+    for(;;) {
+        x = adb_dirstart(x);
+        if(x == 0) return 0;
+        *x = 0;
+        if (is_on_system(name) || is_on_vendor(name)) {
+            fs_config(name, 1, &uid, &gid, &mode, &cap);
+        }
+        ret = adb_mkdir(name, mode);
+        if((ret < 0) && (errno != EEXIST)) {
+            D("mkdir(\"%s\") -> %s\n", name, strerror(errno));
+            *x = '/';
+            return ret;
+        } else if(ret == 0) {
+            ret = chown(name, uid, gid);
+            if (ret < 0) {
+                *x = '/';
+                return ret;
+            }
+#ifndef ADB_NON_ANDROID
+            selinux_android_restorecon(name, 0);
+#endif
+        }
+        *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)) {
+                closedir(d);
+                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, uid_t uid,
+        gid_t gid, mode_t mode, char *buffer, bool do_unlink)
+{
+    syncmsg msg;
+    unsigned int timestamp = 0;
+    int fd;
+
+    fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
+    if(fd < 0 && errno == ENOENT) {
+        if(mkdirs(path) != 0) {
+            if(fail_errno(s))
+                return -1;
+            fd = -1;
+        } else {
+            fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
+        }
+    }
+    if(fd < 0 && errno == EEXIST) {
+        fd = adb_open_mode(path, O_WRONLY | O_CLOEXEC, mode);
+    }
+    if(fd < 0) {
+        if(fail_errno(s))
+            return -1;
+        fd = -1;
+    } else {
+        if(fchown(fd, uid, gid) != 0) {
+            fail_errno(s);
+            errno = 0;
+        }
+
+        /*
+         * fchown clears the setuid bit - restore it if present.
+         * Ignore the result of calling fchmod. It's not supported
+         * by all filesystems. b/12441485
+         */
+        fchmod(fd, mode);
+    }
+
+    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);
+            if (do_unlink) adb_unlink(path);
+            fd = -1;
+            errno = saved_errno;
+            if(fail_errno(s)) return -1;
+        }
+    }
+
+    if(fd >= 0) {
+        struct utimbuf u;
+        adb_close(fd);
+#ifndef ADB_NON_ANDROID
+        selinux_android_restorecon(path, 0);
+#endif
+        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);
+    if (do_unlink) 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) {
+        if(mkdirs(path) != 0) {
+            fail_errno(s);
+            return -1;
+        }
+        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;
+    unsigned int mode;
+    int is_link, ret;
+    bool do_unlink;
+
+    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_t) mode);
+#endif
+        mode &= 0777;
+    }
+    if(!tmp || errno) {
+        mode = 0644;
+        is_link = 0;
+        do_unlink = true;
+    } else {
+        struct stat st;
+        /* Don't delete files before copying if they are not "regular" */
+        do_unlink = lstat(path, &st) || S_ISREG(st.st_mode) || S_ISLNK(st.st_mode);
+        if (do_unlink) {
+            adb_unlink(path);
+        }
+    }
+
+#ifdef HAVE_SYMLINKS
+    if(is_link)
+        ret = handle_send_link(s, path, buffer);
+    else {
+#else
+    {
+#endif
+        uid_t uid = -1;
+        gid_t gid = -1;
+        uint64_t cap = 0;
+
+        /* copy user permission bits to "group" and "other" permissions */
+        mode |= ((mode >> 3) & 0070);
+        mode |= ((mode >> 3) & 0007);
+
+        tmp = path;
+        if(*tmp == '/') {
+            tmp++;
+        }
+        if (is_on_system(path) || is_on_vendor(path)) {
+            fs_config(tmp, 0, &uid, &gid, &mode, &cap);
+        }
+        ret = handle_send_file(s, path, uid, gid, mode, buffer, do_unlink);
+    }
+
+    return ret;
+}
+
+static int do_recv(int s, const char *path, char *buffer)
+{
+    syncmsg msg;
+    int fd, r;
+
+    fd = adb_open(path, O_RDONLY | O_CLOEXEC);
+    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);
+}
diff --git a/src/devtools/adb_tcp/file_sync_service.h b/src/devtools/adb_tcp/file_sync_service.h
new file mode 100644
index 0000000..5dd2e80
--- /dev/null
+++ b/src/devtools/adb_tcp/file_sync_service.h
@@ -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 show_progress);
+int do_sync_sync(const char *lpath, const char *rpath, int listonly);
+int do_sync_pull(const char *rpath, const char *lpath, int show_progress, int pullTime);
+
+#define SYNC_DATA_MAX (64*1024)
+
+#endif
diff --git a/src/devtools/adb_tcp/framebuffer_service.c b/src/devtools/adb_tcp/framebuffer_service.c
new file mode 100644
index 0000000..1c5cd2f
--- /dev/null
+++ b/src/devtools/adb_tcp/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_tcp/get_my_path_darwin.c b/src/devtools/adb_tcp/get_my_path_darwin.c
new file mode 100644
index 0000000..ff1396c
--- /dev/null
+++ b/src/devtools/adb_tcp/get_my_path_darwin.c
@@ -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)
+{
+    CFBundleRef mainBundle = CFBundleGetMainBundle();
+    CFURLRef executableURL = CFBundleCopyExecutableURL(mainBundle);
+    CFStringRef executablePathString = CFURLCopyFileSystemPath(executableURL, kCFURLPOSIXPathStyle);
+    CFRelease(executableURL);
+
+    CFStringGetFileSystemRepresentation(executablePathString, s, maxLen);
+    CFRelease(executablePathString);
+}
+
diff --git a/src/devtools/adb_tcp/get_my_path_freebsd.c b/src/devtools/adb_tcp/get_my_path_freebsd.c
new file mode 100644
index 0000000..b06ec66
--- /dev/null
+++ b/src/devtools/adb_tcp/get_my_path_freebsd.c
@@ -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';
+}
+
diff --git a/src/devtools/adb_tcp/get_my_path_linux.c b/src/devtools/adb_tcp/get_my_path_linux.c
new file mode 100644
index 0000000..179c3dd
--- /dev/null
+++ b/src/devtools/adb_tcp/get_my_path_linux.c
@@ -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';
+    }
+}
+
diff --git a/src/devtools/adb_tcp/get_my_path_windows.c b/src/devtools/adb_tcp/get_my_path_windows.c
new file mode 100644
index 0000000..ddf2816
--- /dev/null
+++ b/src/devtools/adb_tcp/get_my_path_windows.c
@@ -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';
+    }
+}
+
diff --git a/src/devtools/adb_tcp/include/android/log.h b/src/devtools/adb_tcp/include/android/log.h
new file mode 100644
index 0000000..1c171b7
--- /dev/null
+++ b/src/devtools/adb_tcp/include/android/log.h
@@ -0,0 +1,144 @@
+/*
+ * 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 _ANDROID_LOG_H
+#define _ANDROID_LOG_H
+
+/******************************************************************
+ *
+ * IMPORTANT NOTICE:
+ *
+ *   This file is part of Android's set of stable system headers
+ *   exposed by the Android NDK (Native Development Kit) since
+ *   platform release 1.5
+ *
+ *   Third-party source AND binary code relies on the definitions
+ *   here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES.
+ *
+ *   - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES)
+ *   - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS
+ *   - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY
+ *   - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
+ */
+
+/*
+ * Support routines to send messages to the Android in-kernel log buffer,
+ * which can later be accessed through the 'logcat' utility.
+ *
+ * Each log message must have
+ *   - a priority
+ *   - a log tag
+ *   - some text
+ *
+ * The tag normally corresponds to the component that emits the log message,
+ * and should be reasonably small.
+ *
+ * Log message text may be truncated to less than an implementation-specific
+ * limit (e.g. 1023 characters max).
+ *
+ * Note that a newline character ("\n") will be appended automatically to your
+ * log message, if not already there. It is not possible to send several messages
+ * and have them appear on a single line in logcat.
+ *
+ * PLEASE USE LOGS WITH MODERATION:
+ *
+ *  - Sending log messages eats CPU and slow down your application and the
+ *    system.
+ *
+ *  - The circular log buffer is pretty small (<64KB), sending many messages
+ *    might push off other important log messages from the rest of the system.
+ *
+ *  - In release builds, only send log messages to account for exceptional
+ *    conditions.
+ *
+ * NOTE: These functions MUST be implemented by /system/lib/liblog.so
+ */
+
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Android log priority values, in ascending priority order.
+ */
+typedef enum android_LogPriority {
+    ANDROID_LOG_UNKNOWN = 0,
+    ANDROID_LOG_DEFAULT,    /* only for SetMinPriority() */
+    ANDROID_LOG_VERBOSE,
+    ANDROID_LOG_DEBUG,
+    ANDROID_LOG_INFO,
+    ANDROID_LOG_WARN,
+    ANDROID_LOG_ERROR,
+    ANDROID_LOG_FATAL,
+    ANDROID_LOG_SILENT,     /* only for SetMinPriority(); must be last */
+} android_LogPriority;
+
+/*
+ * Send a simple string to the log.
+ */
+int __android_log_write(int prio, const char *tag, const char *text);
+
+/*
+ * Send a formatted string to the log, used like printf(fmt,...)
+ */
+int __android_log_print(int prio, const char *tag,  const char *fmt, ...)
+#if defined(__GNUC__)
+#ifdef __USE_MINGW_ANSI_STDIO
+#if __USE_MINGW_ANSI_STDIO
+    __attribute__ ((format(gnu_printf, 3, 4)))
+#else
+    __attribute__ ((format(printf, 3, 4)))
+#endif
+#else
+    __attribute__ ((format(printf, 3, 4)))
+#endif
+#endif
+    ;
+
+/*
+ * A variant of __android_log_print() that takes a va_list to list
+ * additional parameters.
+ */
+int __android_log_vprint(int prio, const char *tag,
+                         const char *fmt, va_list ap);
+
+/*
+ * Log an assertion failure and abort the process to have a chance
+ * to inspect it if a debugger is attached. This uses the FATAL priority.
+ */
+void __android_log_assert(const char *cond, const char *tag,
+                          const char *fmt, ...)
+#if defined(__GNUC__)
+    __attribute__ ((noreturn))
+#ifdef __USE_MINGW_ANSI_STDIO
+#if __USE_MINGW_ANSI_STDIO
+    __attribute__ ((format(gnu_printf, 3, 4)))
+#else
+    __attribute__ ((format(printf, 3, 4)))
+#endif
+#else
+    __attribute__ ((format(printf, 3, 4)))
+#endif
+#endif
+    ;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ANDROID_LOG_H */
diff --git a/src/devtools/adb_tcp/include/cutils/android_reboot.h b/src/devtools/adb_tcp/include/cutils/android_reboot.h
new file mode 100644
index 0000000..8c30e8e
--- /dev/null
+++ b/src/devtools/adb_tcp/include/cutils/android_reboot.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 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 __CUTILS_ANDROID_REBOOT_H__
+#define __CUTILS_ANDROID_REBOOT_H__
+
+__BEGIN_DECLS
+
+/* Commands */
+#define ANDROID_RB_RESTART  0xDEAD0001
+#define ANDROID_RB_POWEROFF 0xDEAD0002
+#define ANDROID_RB_RESTART2 0xDEAD0003
+
+/* Properties */
+#define ANDROID_RB_PROPERTY "sys.powerctl"
+
+int android_reboot(int cmd, int flags, char *arg);
+
+__END_DECLS
+
+#endif /* __CUTILS_ANDROID_REBOOT_H__ */
diff --git a/src/devtools/adb_tcp/include/cutils/fs.h b/src/devtools/adb_tcp/include/cutils/fs.h
new file mode 100644
index 0000000..70f0b92
--- /dev/null
+++ b/src/devtools/adb_tcp/include/cutils/fs.h
@@ -0,0 +1,71 @@
+/*
+ * 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 __CUTILS_FS_H
+#define __CUTILS_FS_H
+
+#include <sys/types.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
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Ensure that directory exists with given mode and owners.
+ */
+extern int fs_prepare_dir(const char* path, mode_t mode, uid_t uid, gid_t gid);
+
+/*
+ * Read single plaintext integer from given file, correctly handling files
+ * partially written with fs_write_atomic_int().
+ */
+extern int fs_read_atomic_int(const char* path, int* value);
+
+/*
+ * Write single plaintext integer to given file, creating backup while
+ * in progress.
+ */
+extern int fs_write_atomic_int(const char* path, int value);
+
+/*
+ * Ensure that all directories along given path exist, creating parent
+ * directories as needed.  Validates that given path is absolute and that
+ * it contains no relative "." or ".." paths or symlinks.  Last path segment
+ * is treated as filename and ignored, unless the path ends with "/".
+ */
+extern int fs_mkdirs(const char* path, mode_t mode);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CUTILS_FS_H */
diff --git a/src/devtools/adb_tcp/include/cutils/list.h b/src/devtools/adb_tcp/include/cutils/list.h
new file mode 100644
index 0000000..4ba2cfd
--- /dev/null
+++ b/src/devtools/adb_tcp/include/cutils/list.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2008-2013 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 _CUTILS_LIST_H_
+#define _CUTILS_LIST_H_
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+struct listnode
+{
+    struct listnode *next;
+    struct listnode *prev;
+};
+
+#define node_to_item(node, container, member) \
+    (container *) (((char*) (node)) - offsetof(container, member))
+
+#define list_declare(name) \
+    struct listnode name = { \
+        .next = &name, \
+        .prev = &name, \
+    }
+
+#define list_for_each(node, list) \
+    for (node = (list)->next; node != (list); node = node->next)
+
+#define list_for_each_reverse(node, list) \
+    for (node = (list)->prev; node != (list); node = node->prev)
+
+#define list_for_each_safe(node, n, list) \
+    for (node = (list)->next, n = node->next; \
+         node != (list); \
+         node = n, n = node->next)
+
+static inline void list_init(struct listnode *node)
+{
+    node->next = node;
+    node->prev = node;
+}
+
+static inline void list_add_tail(struct listnode *head, struct listnode *item)
+{
+    item->next = head;
+    item->prev = head->prev;
+    head->prev->next = item;
+    head->prev = item;
+}
+
+static inline void list_add_head(struct listnode *head, struct listnode *item)
+{
+    item->next = head->next;
+    item->prev = head;
+    head->next->prev = item;
+    head->next = item;
+}
+
+static inline void list_remove(struct listnode *item)
+{
+    item->next->prev = item->prev;
+    item->prev->next = item->next;
+}
+
+#define list_empty(list) ((list) == (list)->next)
+#define list_head(list) ((list)->next)
+#define list_tail(list) ((list)->prev)
+
+#ifdef __cplusplus
+};
+#endif /* __cplusplus */
+
+#endif
diff --git a/src/devtools/adb_tcp/include/cutils/misc.h b/src/devtools/adb_tcp/include/cutils/misc.h
new file mode 100644
index 0000000..0de505f
--- /dev/null
+++ b/src/devtools/adb_tcp/include/cutils/misc.h
@@ -0,0 +1,41 @@
+/*
+ * 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 __CUTILS_MISC_H
+#define __CUTILS_MISC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+        /* Load an entire file into a malloc'd chunk of memory
+         * that is length_of_file + 1 (null terminator).  If
+         * sz is non-zero, return the size of the file via sz.
+         * Returns 0 on failure.
+         */
+extern void *load_file(const char *fn, unsigned *sz);
+
+        /* This is the range of UIDs (and GIDs) that are reserved
+         * for assigning to applications.
+         */
+#define FIRST_APPLICATION_UID 10000
+#define LAST_APPLICATION_UID 99999
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CUTILS_MISC_H */ 
diff --git a/src/devtools/adb_tcp/include/cutils/properties.h b/src/devtools/adb_tcp/include/cutils/properties.h
new file mode 100644
index 0000000..20f7f85
--- /dev/null
+++ b/src/devtools/adb_tcp/include/cutils/properties.h
@@ -0,0 +1,156 @@
+/*
+ * 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 __CUTILS_PROPERTIES_H
+#define __CUTILS_PROPERTIES_H
+
+#include <sys/cdefs.h>
+#include <stddef.h>
+//#include <sys/system_properties.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef PROP_NAME_MAX
+#define PROP_NAME_MAX 32
+#endif
+#ifndef PROP_VALUE_MAX
+#define PROP_VALUE_MAX 92
+#endif
+
+/* System properties are *small* name value pairs managed by the
+** property service.  If your data doesn't fit in the provided
+** space it is not appropriate for a system property.
+**
+** WARNING: system/bionic/include/sys/system_properties.h also defines
+**          these, but with different names.  (TODO: fix that)
+*/
+#define PROPERTY_KEY_MAX   PROP_NAME_MAX
+#define PROPERTY_VALUE_MAX  PROP_VALUE_MAX
+
+/* property_get: returns the length of the value which will never be
+** greater than PROPERTY_VALUE_MAX - 1 and will always be zero terminated.
+** (the length does not include the terminating zero).
+**
+** If the property read fails or returns an empty value, the default
+** value is used (if nonnull).
+*/
+int property_get(const char *key, char *value, const char *default_value);
+
+/* property_get_bool: returns the value of key coerced into a
+** boolean. If the property is not set, then the default value is returned.
+**
+* The following is considered to be true (1):
+**   "1", "true", "y", "yes", "on"
+**
+** The following is considered to be false (0):
+**   "0", "false", "n", "no", "off"
+**
+** The conversion is whitespace-sensitive (e.g. " off" will not be false).
+**
+** If no property with this key is set (or the key is NULL) or the boolean
+** conversion fails, the default value is returned.
+**/
+int8_t property_get_bool(const char *key, int8_t default_value);
+
+/* property_get_int64: returns the value of key truncated and coerced into a
+** int64_t. If the property is not set, then the default value is used.
+**
+** The numeric conversion is identical to strtoimax with the base inferred:
+** - All digits up to the first non-digit characters are read
+** - The longest consecutive prefix of digits is converted to a long
+**
+** Valid strings of digits are:
+** - An optional sign character + or -
+** - An optional prefix indicating the base (otherwise base 10 is assumed)
+**   -- 0 prefix is octal
+**   -- 0x / 0X prefix is hex
+**
+** Leading/trailing whitespace is ignored. Overflow/underflow will cause
+** numeric conversion to fail.
+**
+** If no property with this key is set (or the key is NULL) or the numeric
+** conversion fails, the default value is returned.
+**/
+int64_t property_get_int64(const char *key, int64_t default_value);
+
+/* property_get_int32: returns the value of key truncated and coerced into an
+** int32_t. If the property is not set, then the default value is used.
+**
+** The numeric conversion is identical to strtoimax with the base inferred:
+** - All digits up to the first non-digit characters are read
+** - The longest consecutive prefix of digits is converted to a long
+**
+** Valid strings of digits are:
+** - An optional sign character + or -
+** - An optional prefix indicating the base (otherwise base 10 is assumed)
+**   -- 0 prefix is octal
+**   -- 0x / 0X prefix is hex
+**
+** Leading/trailing whitespace is ignored. Overflow/underflow will cause
+** numeric conversion to fail.
+**
+** If no property with this key is set (or the key is NULL) or the numeric
+** conversion fails, the default value is returned.
+**/
+int32_t property_get_int32(const char *key, int32_t default_value);
+
+/* property_set: returns 0 on success, < 0 on failure
+*/
+int property_set(const char *key, const char *value);
+    
+int property_list(void (*propfn)(const char *key, const char *value, void *cookie), void *cookie);    
+
+#if defined(__BIONIC_FORTIFY)
+
+extern int __property_get_real(const char *, char *, const char *)
+    __asm__(__USER_LABEL_PREFIX__ "property_get");
+__errordecl(__property_get_too_small_error, "property_get() called with too small of a buffer");
+
+__BIONIC_FORTIFY_INLINE
+int property_get(const char *key, char *value, const char *default_value) {
+    size_t bos = __bos(value);
+    if (bos < PROPERTY_VALUE_MAX) {
+        __property_get_too_small_error();
+    }
+    return __property_get_real(key, value, default_value);
+}
+
+#endif
+
+#ifdef HAVE_SYSTEM_PROPERTY_SERVER
+/*
+ * We have an external property server instead of built-in libc support.
+ * Used by the simulator.
+ */
+#define SYSTEM_PROPERTY_PIPE_NAME       "/tmp/android-sysprop"
+
+enum {
+    kSystemPropertyUnknown = 0,
+    kSystemPropertyGet,
+    kSystemPropertySet,
+    kSystemPropertyList
+};
+#endif /*HAVE_SYSTEM_PROPERTY_SERVER*/
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/devtools/adb_tcp/include/cutils/sockets.h b/src/devtools/adb_tcp/include/cutils/sockets.h
new file mode 100644
index 0000000..daf43ec
--- /dev/null
+++ b/src/devtools/adb_tcp/include/cutils/sockets.h
@@ -0,0 +1,114 @@
+/*
+ * 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 __CUTILS_SOCKETS_H
+#define __CUTILS_SOCKETS_H
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#ifdef HAVE_WINSOCK
+#include <winsock2.h>
+typedef int  socklen_t;
+#elif HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#define ANDROID_SOCKET_ENV_PREFIX	"ANDROID_SOCKET_"
+#define ANDROID_SOCKET_DIR		"/dev/socket"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * android_get_control_socket - simple helper function to get the file
+ * descriptor of our init-managed Unix domain socket. `name' is the name of the
+ * socket, as given in init.rc. Returns -1 on error.
+ *
+ * This is inline and not in libcutils proper because we want to use this in
+ * third-party daemons with minimal modification.
+ */
+static inline int android_get_control_socket(const char *name)
+{
+	char key[64] = ANDROID_SOCKET_ENV_PREFIX;
+	const char *val;
+	int fd;
+
+	/* build our environment variable, counting cycles like a wolf ... */
+#if HAVE_STRLCPY
+	strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,
+		name,
+		sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));
+#else	/* for the host, which may lack the almightly strncpy ... */
+	strncpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,
+		name,
+		sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));
+	key[sizeof(key)-1] = '\0';
+#endif
+
+	val = getenv(key);
+	if (!val)
+		return -1;
+
+	errno = 0;
+	fd = strtol(val, NULL, 10);
+	if (errno)
+		return -1;
+
+	return fd;
+}
+
+/*
+ * See also android.os.LocalSocketAddress.Namespace
+ */
+// Linux "abstract" (non-filesystem) namespace
+#define ANDROID_SOCKET_NAMESPACE_ABSTRACT 0
+// Android "reserved" (/dev/socket) namespace
+#define ANDROID_SOCKET_NAMESPACE_RESERVED 1
+// Normal filesystem namespace
+#define ANDROID_SOCKET_NAMESPACE_FILESYSTEM 2
+
+extern int socket_loopback_client(int port, int type);
+extern int socket_network_client(const char *host, int port, int type);
+extern int socket_network_client_timeout(const char *host, int port, int type,
+                                         int timeout);
+extern int socket_loopback_server(int port, int type);
+extern int socket_local_server(const char *name, int namespaceId, int type);
+extern int socket_local_server_bind(int s, const char *name, int namespaceId);
+extern int socket_local_client_connect(int fd, 
+        const char *name, int namespaceId, int type);
+extern int socket_local_client(const char *name, int namespaceId, int type);
+extern int socket_inaddr_any_server(int port, int type);
+
+/*
+ * socket_peer_is_trusted - Takes a socket which is presumed to be a
+ * connected local socket (e.g. AF_LOCAL) and returns whether the peer
+ * (the userid that owns the process on the other end of that socket)
+ * is one of the two trusted userids, root or shell.
+ *
+ * Note: This only works as advertised on the Android OS and always
+ * just returns true when called on other operating systems.
+ */
+extern bool socket_peer_is_trusted(int fd);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CUTILS_SOCKETS_H */ 
diff --git a/src/devtools/adb_tcp/include/cutils/threads.h b/src/devtools/adb_tcp/include/cutils/threads.h
new file mode 100644
index 0000000..acf8f48
--- /dev/null
+++ b/src/devtools/adb_tcp/include/cutils/threads.h
@@ -0,0 +1,146 @@
+/*
+ * 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 _LIBS_CUTILS_THREADS_H
+#define _LIBS_CUTILS_THREADS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/***********************************************************************/
+/***********************************************************************/
+/*****                                                             *****/
+/*****         local thread storage                                *****/
+/*****                                                             *****/
+/***********************************************************************/
+/***********************************************************************/
+
+#ifdef HAVE_PTHREADS
+
+#include  <pthread.h>
+
+typedef struct {
+    pthread_mutex_t   lock;
+    int               has_tls;
+    pthread_key_t     tls;
+
+} thread_store_t;
+
+#define  THREAD_STORE_INITIALIZER  { PTHREAD_MUTEX_INITIALIZER, 0, 0 }
+
+#elif defined HAVE_WIN32_THREADS
+
+#include <windows.h>
+
+typedef struct {
+    int               lock_init;
+    int               has_tls;
+    DWORD             tls;
+    CRITICAL_SECTION  lock;
+
+} thread_store_t;
+
+#define  THREAD_STORE_INITIALIZER  { 0, 0, 0, {0, 0, 0, 0, 0, 0} }
+
+#else
+#  error  "no thread_store_t implementation for your platform !!"
+#endif
+
+typedef void  (*thread_store_destruct_t)(void*  value);
+
+extern void*  thread_store_get(thread_store_t*  store);
+
+extern void   thread_store_set(thread_store_t*          store, 
+                               void*                    value,
+                               thread_store_destruct_t  destroy);
+
+/***********************************************************************/
+/***********************************************************************/
+/*****                                                             *****/
+/*****         mutexes                                             *****/
+/*****                                                             *****/
+/***********************************************************************/
+/***********************************************************************/
+
+#ifdef HAVE_PTHREADS
+
+typedef pthread_mutex_t   mutex_t;
+
+#define  MUTEX_INITIALIZER  PTHREAD_MUTEX_INITIALIZER
+
+static __inline__ void  mutex_lock(mutex_t*  lock)
+{
+    pthread_mutex_lock(lock);
+}
+static __inline__ void  mutex_unlock(mutex_t*  lock)
+{
+    pthread_mutex_unlock(lock);
+}
+static __inline__ int  mutex_init(mutex_t*  lock)
+{
+    return pthread_mutex_init(lock, NULL);
+}
+static __inline__ void mutex_destroy(mutex_t*  lock)
+{
+    pthread_mutex_destroy(lock);
+}
+#endif
+
+#ifdef HAVE_WIN32_THREADS
+typedef struct { 
+    int                init;
+    CRITICAL_SECTION   lock[1];
+} mutex_t;
+
+#define  MUTEX_INITIALIZER  { 0, {{ NULL, 0, 0, NULL, NULL, 0 }} }
+
+static __inline__ void  mutex_lock(mutex_t*  lock)
+{
+    if (!lock->init) {
+        lock->init = 1;
+        InitializeCriticalSection( lock->lock );
+        lock->init = 2;
+    } else while (lock->init != 2)
+        Sleep(10);
+
+    EnterCriticalSection(lock->lock);
+}
+
+static __inline__ void  mutex_unlock(mutex_t*  lock)
+{
+    LeaveCriticalSection(lock->lock);
+}
+static __inline__ int  mutex_init(mutex_t*  lock)
+{
+    InitializeCriticalSection(lock->lock);
+    lock->init = 2;
+    return 0;
+}
+static __inline__ void  mutex_destroy(mutex_t*  lock)
+{
+    if (lock->init) {
+        lock->init = 0;
+        DeleteCriticalSection(lock->lock); 
+    }
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBS_CUTILS_THREADS_H */
diff --git a/src/devtools/adb_tcp/include/log/log.h b/src/devtools/adb_tcp/include/log/log.h
new file mode 100644
index 0000000..ace12d6
--- /dev/null
+++ b/src/devtools/adb_tcp/include/log/log.h
@@ -0,0 +1,574 @@
+/*
+ * Copyright (C) 2005-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.
+ */
+
+//
+// C/C++ logging functions.  See the logging documentation for API details.
+//
+// We'd like these to be available from C code (in case we import some from
+// somewhere), so this has a C interface.
+//
+// The output will be correct when the log file is shared between multiple
+// threads and/or multiple processes so long as the operating system
+// supports O_APPEND.  These calls have mutex-protected data structures
+// and so are NOT reentrant.  Do not use LOG in a signal handler.
+//
+#ifndef _LIBS_LOG_LOG_H
+#define _LIBS_LOG_LOG_H
+
+#include <sys/types.h>
+#ifdef HAVE_PTHREADS
+#include <pthread.h>
+#endif
+#include <stdarg.h>
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+#include <log/logd.h>
+#include <log/uio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// ---------------------------------------------------------------------
+
+/*
+ * Normally we strip ALOGV (VERBOSE messages) from release builds.
+ * You can modify this (for example with "#define LOG_NDEBUG 0"
+ * at the top of your source file) to change that behavior.
+ */
+#ifndef LOG_NDEBUG
+#ifdef NDEBUG
+#define LOG_NDEBUG 1
+#else
+#define LOG_NDEBUG 0
+#endif
+#endif
+
+/*
+ * This is the local tag used for the following simplified
+ * logging macros.  You can change this preprocessor definition
+ * before using the other macros to change the tag.
+ */
+#ifndef LOG_TAG
+#define LOG_TAG NULL
+#endif
+
+// ---------------------------------------------------------------------
+
+/*
+ * Simplified macro to send a verbose log message using the current LOG_TAG.
+ */
+#ifndef ALOGV
+#define __ALOGV(...) ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
+#if LOG_NDEBUG
+#define ALOGV(...) do { if (0) { __ALOGV(__VA_ARGS__); } } while (0)
+#else
+#define ALOGV(...) __ALOGV(__VA_ARGS__)
+#endif
+#endif
+
+#define CONDITION(cond)     (__builtin_expect((cond)!=0, 0))
+
+#ifndef ALOGV_IF
+#if LOG_NDEBUG
+#define ALOGV_IF(cond, ...)   ((void)0)
+#else
+#define ALOGV_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+#endif
+
+/*
+ * Simplified macro to send a debug log message using the current LOG_TAG.
+ */
+#ifndef ALOGD
+#define ALOGD(...) ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef ALOGD_IF
+#define ALOGD_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send an info log message using the current LOG_TAG.
+ */
+#ifndef ALOGI
+#define ALOGI(...) ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef ALOGI_IF
+#define ALOGI_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send a warning log message using the current LOG_TAG.
+ */
+#ifndef ALOGW
+#define ALOGW(...) ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef ALOGW_IF
+#define ALOGW_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send an error log message using the current LOG_TAG.
+ */
+#ifndef ALOGE
+#define ALOGE(...) ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef ALOGE_IF
+#define ALOGE_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+// ---------------------------------------------------------------------
+
+/*
+ * Conditional based on whether the current LOG_TAG is enabled at
+ * verbose priority.
+ */
+#ifndef IF_ALOGV
+#if LOG_NDEBUG
+#define IF_ALOGV() if (false)
+#else
+#define IF_ALOGV() IF_ALOG(LOG_VERBOSE, LOG_TAG)
+#endif
+#endif
+
+/*
+ * Conditional based on whether the current LOG_TAG is enabled at
+ * debug priority.
+ */
+#ifndef IF_ALOGD
+#define IF_ALOGD() IF_ALOG(LOG_DEBUG, LOG_TAG)
+#endif
+
+/*
+ * Conditional based on whether the current LOG_TAG is enabled at
+ * info priority.
+ */
+#ifndef IF_ALOGI
+#define IF_ALOGI() IF_ALOG(LOG_INFO, LOG_TAG)
+#endif
+
+/*
+ * Conditional based on whether the current LOG_TAG is enabled at
+ * warn priority.
+ */
+#ifndef IF_ALOGW
+#define IF_ALOGW() IF_ALOG(LOG_WARN, LOG_TAG)
+#endif
+
+/*
+ * Conditional based on whether the current LOG_TAG is enabled at
+ * error priority.
+ */
+#ifndef IF_ALOGE
+#define IF_ALOGE() IF_ALOG(LOG_ERROR, LOG_TAG)
+#endif
+
+
+// ---------------------------------------------------------------------
+
+/*
+ * Simplified macro to send a verbose system log message using the current LOG_TAG.
+ */
+#ifndef SLOGV
+#define __SLOGV(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
+#if LOG_NDEBUG
+#define SLOGV(...) do { if (0) { __SLOGV(__VA_ARGS__); } } while (0)
+#else
+#define SLOGV(...) __SLOGV(__VA_ARGS__)
+#endif
+#endif
+
+#define CONDITION(cond)     (__builtin_expect((cond)!=0, 0))
+
+#ifndef SLOGV_IF
+#if LOG_NDEBUG
+#define SLOGV_IF(cond, ...)   ((void)0)
+#else
+#define SLOGV_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+#endif
+
+/*
+ * Simplified macro to send a debug system log message using the current LOG_TAG.
+ */
+#ifndef SLOGD
+#define SLOGD(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef SLOGD_IF
+#define SLOGD_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send an info system log message using the current LOG_TAG.
+ */
+#ifndef SLOGI
+#define SLOGI(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef SLOGI_IF
+#define SLOGI_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send a warning system log message using the current LOG_TAG.
+ */
+#ifndef SLOGW
+#define SLOGW(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef SLOGW_IF
+#define SLOGW_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send an error system log message using the current LOG_TAG.
+ */
+#ifndef SLOGE
+#define SLOGE(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef SLOGE_IF
+#define SLOGE_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+// ---------------------------------------------------------------------
+
+/*
+ * Simplified macro to send a verbose radio log message using the current LOG_TAG.
+ */
+#ifndef RLOGV
+#define __RLOGV(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
+#if LOG_NDEBUG
+#define RLOGV(...) do { if (0) { __RLOGV(__VA_ARGS__); } } while (0)
+#else
+#define RLOGV(...) __RLOGV(__VA_ARGS__)
+#endif
+#endif
+
+#define CONDITION(cond)     (__builtin_expect((cond)!=0, 0))
+
+#ifndef RLOGV_IF
+#if LOG_NDEBUG
+#define RLOGV_IF(cond, ...)   ((void)0)
+#else
+#define RLOGV_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+#endif
+
+/*
+ * Simplified macro to send a debug radio log message using the current LOG_TAG.
+ */
+#ifndef RLOGD
+#define RLOGD(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef RLOGD_IF
+#define RLOGD_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send an info radio log message using the current LOG_TAG.
+ */
+#ifndef RLOGI
+#define RLOGI(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef RLOGI_IF
+#define RLOGI_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send a warning radio log message using the current LOG_TAG.
+ */
+#ifndef RLOGW
+#define RLOGW(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef RLOGW_IF
+#define RLOGW_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send an error radio log message using the current LOG_TAG.
+ */
+#ifndef RLOGE
+#define RLOGE(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef RLOGE_IF
+#define RLOGE_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+
+// ---------------------------------------------------------------------
+
+/*
+ * Log a fatal error.  If the given condition fails, this stops program
+ * execution like a normal assertion, but also generating the given message.
+ * It is NOT stripped from release builds.  Note that the condition test
+ * is -inverted- from the normal assert() semantics.
+ */
+#ifndef LOG_ALWAYS_FATAL_IF
+#define LOG_ALWAYS_FATAL_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)android_printAssert(#cond, LOG_TAG, ## __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+#ifndef LOG_ALWAYS_FATAL
+#define LOG_ALWAYS_FATAL(...) \
+    ( ((void)android_printAssert(NULL, LOG_TAG, ## __VA_ARGS__)) )
+#endif
+
+/*
+ * Versions of LOG_ALWAYS_FATAL_IF and LOG_ALWAYS_FATAL that
+ * are stripped out of release builds.
+ */
+#if LOG_NDEBUG
+
+#ifndef LOG_FATAL_IF
+#define LOG_FATAL_IF(cond, ...) ((void)0)
+#endif
+#ifndef LOG_FATAL
+#define LOG_FATAL(...) ((void)0)
+#endif
+
+#else
+
+#ifndef LOG_FATAL_IF
+#define LOG_FATAL_IF(cond, ...) LOG_ALWAYS_FATAL_IF(cond, ## __VA_ARGS__)
+#endif
+#ifndef LOG_FATAL
+#define LOG_FATAL(...) LOG_ALWAYS_FATAL(__VA_ARGS__)
+#endif
+
+#endif
+
+/*
+ * Assertion that generates a log message when the assertion fails.
+ * Stripped out of release builds.  Uses the current LOG_TAG.
+ */
+#ifndef ALOG_ASSERT
+#define ALOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), ## __VA_ARGS__)
+//#define ALOG_ASSERT(cond) LOG_FATAL_IF(!(cond), "Assertion failed: " #cond)
+#endif
+
+// ---------------------------------------------------------------------
+
+/*
+ * Basic log message macro.
+ *
+ * Example:
+ *  ALOG(LOG_WARN, NULL, "Failed with error %d", errno);
+ *
+ * The second argument may be NULL or "" to indicate the "global" tag.
+ */
+#ifndef ALOG
+#define ALOG(priority, tag, ...) \
+    LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__)
+#endif
+
+/*
+ * Log macro that allows you to specify a number for the priority.
+ */
+#ifndef LOG_PRI
+#define LOG_PRI(priority, tag, ...) \
+    android_printLog(priority, tag, __VA_ARGS__)
+#endif
+
+/*
+ * Log macro that allows you to pass in a varargs ("args" is a va_list).
+ */
+#ifndef LOG_PRI_VA
+#define LOG_PRI_VA(priority, tag, fmt, args) \
+    android_vprintLog(priority, NULL, tag, fmt, args)
+#endif
+
+/*
+ * Conditional given a desired logging priority and tag.
+ */
+#ifndef IF_ALOG
+#define IF_ALOG(priority, tag) \
+    if (android_testLog(ANDROID_##priority, tag))
+#endif
+
+// ---------------------------------------------------------------------
+
+/*
+ * Event logging.
+ */
+
+/*
+ * Event log entry types.  These must match up with the declarations in
+ * java/android/android/util/EventLog.java.
+ */
+typedef enum {
+    EVENT_TYPE_INT      = 0,
+    EVENT_TYPE_LONG     = 1,
+    EVENT_TYPE_STRING   = 2,
+    EVENT_TYPE_LIST     = 3,
+} AndroidEventLogType;
+#define sizeof_AndroidEventLogType sizeof(typeof_AndroidEventLogType)
+#define typeof_AndroidEventLogType unsigned char
+
+#ifndef LOG_EVENT_INT
+#define LOG_EVENT_INT(_tag, _value) {                                       \
+        int intBuf = _value;                                                \
+        (void) android_btWriteLog(_tag, EVENT_TYPE_INT, &intBuf,            \
+            sizeof(intBuf));                                                \
+    }
+#endif
+#ifndef LOG_EVENT_LONG
+#define LOG_EVENT_LONG(_tag, _value) {                                      \
+        long long longBuf = _value;                                         \
+        (void) android_btWriteLog(_tag, EVENT_TYPE_LONG, &longBuf,          \
+            sizeof(longBuf));                                               \
+    }
+#endif
+#ifndef LOG_EVENT_STRING
+#define LOG_EVENT_STRING(_tag, _value)                                      \
+        (void) __android_log_bswrite(_tag, _value);
+#endif
+/* TODO: something for LIST */
+
+/*
+ * ===========================================================================
+ *
+ * The stuff in the rest of this file should not be used directly.
+ */
+
+#define android_printLog(prio, tag, fmt...) \
+    __android_log_print(prio, tag, fmt)
+
+#define android_vprintLog(prio, cond, tag, fmt...) \
+    __android_log_vprint(prio, tag, fmt)
+
+/* XXX Macros to work around syntax errors in places where format string
+ * arg is not passed to ALOG_ASSERT, LOG_ALWAYS_FATAL or LOG_ALWAYS_FATAL_IF
+ * (happens only in debug builds).
+ */
+
+/* Returns 2nd arg.  Used to substitute default value if caller's vararg list
+ * is empty.
+ */
+#define __android_second(dummy, second, ...)     second
+
+/* If passed multiple args, returns ',' followed by all but 1st arg, otherwise
+ * returns nothing.
+ */
+#define __android_rest(first, ...)               , ## __VA_ARGS__
+
+#define android_printAssert(cond, tag, fmt...) \
+    __android_log_assert(cond, tag, \
+        __android_second(0, ## fmt, NULL) __android_rest(fmt))
+
+#define android_writeLog(prio, tag, text) \
+    __android_log_write(prio, tag, text)
+
+#define android_bWriteLog(tag, payload, len) \
+    __android_log_bwrite(tag, payload, len)
+#define android_btWriteLog(tag, type, payload, len) \
+    __android_log_btwrite(tag, type, payload, len)
+
+// TODO: remove these prototypes and their users
+#define android_testLog(prio, tag) (1)
+#define android_writevLog(vec,num) do{}while(0)
+#define android_write1Log(str,len) do{}while (0)
+#define android_setMinPriority(tag, prio) do{}while(0)
+//#define android_logToCallback(func) do{}while(0)
+#define android_logToFile(tag, file) (0)
+#define android_logToFd(tag, fd) (0)
+
+typedef enum log_id {
+    LOG_ID_MIN = 0,
+
+    LOG_ID_MAIN = 0,
+    LOG_ID_RADIO = 1,
+    LOG_ID_EVENTS = 2,
+    LOG_ID_SYSTEM = 3,
+    LOG_ID_CRASH = 4,
+
+    LOG_ID_MAX
+} log_id_t;
+#define sizeof_log_id_t sizeof(typeof_log_id_t)
+#define typeof_log_id_t unsigned char
+
+/*
+ * Send a simple string to the log.
+ */
+int __android_log_buf_write(int bufID, int prio, const char *tag, const char *text);
+int __android_log_buf_print(int bufID, int prio, const char *tag, const char *fmt, ...)
+#if defined(__GNUC__)
+    __attribute__((__format__(printf, 4, 5)))
+#endif
+    ;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBS_LOG_LOG_H */
diff --git a/src/devtools/adb_tcp/include/log/log_read.h b/src/devtools/adb_tcp/include/log/log_read.h
new file mode 100644
index 0000000..946711a
--- /dev/null
+++ b/src/devtools/adb_tcp/include/log/log_read.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2013-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 _LIBS_LOG_LOG_READ_H
+#define _LIBS_LOG_LOG_READ_H
+
+#include <stdint.h>
+#include <time.h>
+
+/* struct log_time is a wire-format variant of struct timespec */
+#define NS_PER_SEC 1000000000ULL
+
+#ifdef __cplusplus
+
+// NB: do NOT define a copy constructor. This will result in structure
+// no longer being compatible with pass-by-value which is desired
+// efficient behavior. Also, pass-by-reference breaks C/C++ ABI.
+struct log_time {
+public:
+    uint32_t tv_sec; // good to Feb 5 2106
+    uint32_t tv_nsec;
+
+    static const uint32_t tv_sec_max = 0xFFFFFFFFUL;
+    static const uint32_t tv_nsec_max = 999999999UL;
+
+    log_time(const timespec &T)
+    {
+        tv_sec = T.tv_sec;
+        tv_nsec = T.tv_nsec;
+    }
+    log_time(uint32_t sec, uint32_t nsec)
+    {
+        tv_sec = sec;
+        tv_nsec = nsec;
+    }
+    static const timespec EPOCH;
+    log_time()
+    {
+    }
+    log_time(clockid_t id)
+    {
+        timespec T;
+        clock_gettime(id, &T);
+        tv_sec = T.tv_sec;
+        tv_nsec = T.tv_nsec;
+    }
+    log_time(const char *T)
+    {
+        const uint8_t *c = (const uint8_t *) T;
+        tv_sec = c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24);
+        tv_nsec = c[4] | (c[5] << 8) | (c[6] << 16) | (c[7] << 24);
+    }
+
+    // timespec
+    bool operator== (const timespec &T) const
+    {
+        return (tv_sec == static_cast<uint32_t>(T.tv_sec))
+            && (tv_nsec == static_cast<uint32_t>(T.tv_nsec));
+    }
+    bool operator!= (const timespec &T) const
+    {
+        return !(*this == T);
+    }
+    bool operator< (const timespec &T) const
+    {
+        return (tv_sec < static_cast<uint32_t>(T.tv_sec))
+            || ((tv_sec == static_cast<uint32_t>(T.tv_sec))
+                && (tv_nsec < static_cast<uint32_t>(T.tv_nsec)));
+    }
+    bool operator>= (const timespec &T) const
+    {
+        return !(*this < T);
+    }
+    bool operator> (const timespec &T) const
+    {
+        return (tv_sec > static_cast<uint32_t>(T.tv_sec))
+            || ((tv_sec == static_cast<uint32_t>(T.tv_sec))
+                && (tv_nsec > static_cast<uint32_t>(T.tv_nsec)));
+    }
+    bool operator<= (const timespec &T) const
+    {
+        return !(*this > T);
+    }
+    log_time operator-= (const timespec &T);
+    log_time operator- (const timespec &T) const
+    {
+        log_time local(*this);
+        return local -= T;
+    }
+
+    // log_time
+    bool operator== (const log_time &T) const
+    {
+        return (tv_sec == T.tv_sec) && (tv_nsec == T.tv_nsec);
+    }
+    bool operator!= (const log_time &T) const
+    {
+        return !(*this == T);
+    }
+    bool operator< (const log_time &T) const
+    {
+        return (tv_sec < T.tv_sec)
+            || ((tv_sec == T.tv_sec) && (tv_nsec < T.tv_nsec));
+    }
+    bool operator>= (const log_time &T) const
+    {
+        return !(*this < T);
+    }
+    bool operator> (const log_time &T) const
+    {
+        return (tv_sec > T.tv_sec)
+            || ((tv_sec == T.tv_sec) && (tv_nsec > T.tv_nsec));
+    }
+    bool operator<= (const log_time &T) const
+    {
+        return !(*this > T);
+    }
+    log_time operator-= (const log_time &T);
+    log_time operator- (const log_time &T) const
+    {
+        log_time local(*this);
+        return local -= T;
+    }
+
+    uint64_t nsec() const
+    {
+        return static_cast<uint64_t>(tv_sec) * NS_PER_SEC + tv_nsec;
+    }
+
+    static const char default_format[];
+
+    // Add %#q for the fraction of a second to the standard library functions
+    char *strptime(const char *s, const char *format = default_format);
+} __attribute__((__packed__));
+
+#else
+
+typedef struct log_time {
+    uint32_t tv_sec;
+    uint32_t tv_nsec;
+} __attribute__((__packed__)) log_time;
+
+#endif
+
+#endif /* define _LIBS_LOG_LOG_READ_H */
diff --git a/src/devtools/adb_tcp/include/log/logd.h b/src/devtools/adb_tcp/include/log/logd.h
new file mode 100644
index 0000000..2e6f220
--- /dev/null
+++ b/src/devtools/adb_tcp/include/log/logd.h
@@ -0,0 +1,50 @@
+/*
+ * 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 _ANDROID_CUTILS_LOGD_H
+#define _ANDROID_CUTILS_LOGD_H
+
+/* the stable/frozen log-related definitions have been
+ * moved to this header, which is exposed by the NDK
+ */
+#include <android/log.h>
+
+/* the rest is only used internally by the system */
+#include <time.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <sys/types.h>
+#ifdef HAVE_PTHREADS
+#include <pthread.h>
+#endif
+#include <log/uio.h>
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int __android_log_bwrite(int32_t tag, const void *payload, size_t len);
+int __android_log_btwrite(int32_t tag, char type, const void *payload,
+    size_t len);
+int __android_log_bswrite(int32_t tag, const char *payload);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LOGD_H */
diff --git a/src/devtools/adb_tcp/include/log/logger.h b/src/devtools/adb_tcp/include/log/logger.h
new file mode 100644
index 0000000..53be1d3
--- /dev/null
+++ b/src/devtools/adb_tcp/include/log/logger.h
@@ -0,0 +1,189 @@
+/*
+**
+** Copyright 2007-2014, The Android Open Source Project
+**
+** This file is dual licensed.  It may be redistributed and/or modified
+** under the terms of the Apache 2.0 License OR version 2 of the GNU
+** General Public License.
+*/
+
+#ifndef _LIBS_LOG_LOGGER_H
+#define _LIBS_LOG_LOGGER_H
+
+#include <stdint.h>
+#include <log/log.h>
+#include <log/log_read.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * The userspace structure for version 1 of the logger_entry ABI.
+ * This structure is returned to userspace by the kernel logger
+ * driver unless an upgrade to a newer ABI version is requested.
+ */
+struct logger_entry {
+    uint16_t    len;    /* length of the payload */
+    uint16_t    __pad;  /* no matter what, we get 2 bytes of padding */
+    int32_t     pid;    /* generating process's pid */
+    int32_t     tid;    /* generating process's tid */
+    int32_t     sec;    /* seconds since Epoch */
+    int32_t     nsec;   /* nanoseconds */
+    char        msg[0]; /* the entry's payload */
+} __attribute__((__packed__));
+
+/*
+ * The userspace structure for version 2 of the logger_entry ABI.
+ * This structure is returned to userspace if ioctl(LOGGER_SET_VERSION)
+ * is called with version==2; or used with the user space log daemon.
+ */
+struct logger_entry_v2 {
+    uint16_t    len;       /* length of the payload */
+    uint16_t    hdr_size;  /* sizeof(struct logger_entry_v2) */
+    int32_t     pid;       /* generating process's pid */
+    int32_t     tid;       /* generating process's tid */
+    int32_t     sec;       /* seconds since Epoch */
+    int32_t     nsec;      /* nanoseconds */
+    uint32_t    euid;      /* effective UID of logger */
+    char        msg[0];    /* the entry's payload */
+} __attribute__((__packed__));
+
+struct logger_entry_v3 {
+    uint16_t    len;       /* length of the payload */
+    uint16_t    hdr_size;  /* sizeof(struct logger_entry_v3) */
+    int32_t     pid;       /* generating process's pid */
+    int32_t     tid;       /* generating process's tid */
+    int32_t     sec;       /* seconds since Epoch */
+    int32_t     nsec;      /* nanoseconds */
+    uint32_t    lid;       /* log id of the payload */
+    char        msg[0];    /* the entry's payload */
+} __attribute__((__packed__));
+
+/*
+ * The maximum size of the log entry payload that can be
+ * written to the logger. An attempt to write more than
+ * this amount will result in a truncated log entry.
+ */
+#define LOGGER_ENTRY_MAX_PAYLOAD	4076
+
+/*
+ * The maximum size of a log entry which can be read from the
+ * kernel logger driver. An attempt to read less than this amount
+ * may result in read() returning EINVAL.
+ */
+#define LOGGER_ENTRY_MAX_LEN		(5*1024)
+
+#define NS_PER_SEC 1000000000ULL
+
+struct log_msg {
+    union {
+        unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1];
+        struct logger_entry_v3 entry;
+        struct logger_entry_v3 entry_v3;
+        struct logger_entry_v2 entry_v2;
+        struct logger_entry    entry_v1;
+    } __attribute__((aligned(4)));
+#ifdef __cplusplus
+    /* Matching log_time operators */
+    bool operator== (const log_msg &T) const
+    {
+        return (entry.sec == T.entry.sec) && (entry.nsec == T.entry.nsec);
+    }
+    bool operator!= (const log_msg &T) const
+    {
+        return !(*this == T);
+    }
+    bool operator< (const log_msg &T) const
+    {
+        return (entry.sec < T.entry.sec)
+            || ((entry.sec == T.entry.sec)
+             && (entry.nsec < T.entry.nsec));
+    }
+    bool operator>= (const log_msg &T) const
+    {
+        return !(*this < T);
+    }
+    bool operator> (const log_msg &T) const
+    {
+        return (entry.sec > T.entry.sec)
+            || ((entry.sec == T.entry.sec)
+             && (entry.nsec > T.entry.nsec));
+    }
+    bool operator<= (const log_msg &T) const
+    {
+        return !(*this > T);
+    }
+    uint64_t nsec() const
+    {
+        return static_cast<uint64_t>(entry.sec) * NS_PER_SEC + entry.nsec;
+    }
+
+    /* packet methods */
+    log_id_t id()
+    {
+        return (log_id_t) entry.lid;
+    }
+    char *msg()
+    {
+        return entry.hdr_size ? (char *) buf + entry.hdr_size : entry_v1.msg;
+    }
+    unsigned int len()
+    {
+        return (entry.hdr_size ? entry.hdr_size : sizeof(entry_v1)) + entry.len;
+    }
+#endif
+};
+
+struct logger;
+
+log_id_t android_logger_get_id(struct logger *logger);
+
+int android_logger_clear(struct logger *logger);
+long android_logger_get_log_size(struct logger *logger);
+int android_logger_set_log_size(struct logger *logger, unsigned long size);
+long android_logger_get_log_readable_size(struct logger *logger);
+int android_logger_get_log_version(struct logger *logger);
+
+struct logger_list;
+
+ssize_t android_logger_get_statistics(struct logger_list *logger_list,
+                                      char *buf, size_t len);
+ssize_t android_logger_get_prune_list(struct logger_list *logger_list,
+                                      char *buf, size_t len);
+int android_logger_set_prune_list(struct logger_list *logger_list,
+                                  char *buf, size_t len);
+
+struct logger_list *android_logger_list_alloc(int mode,
+                                              unsigned int tail,
+                                              pid_t pid);
+struct logger_list *android_logger_list_alloc_time(int mode,
+                                                   log_time start,
+                                                   pid_t pid);
+void android_logger_list_free(struct logger_list *logger_list);
+/* In the purest sense, the following two are orthogonal interfaces */
+int android_logger_list_read(struct logger_list *logger_list,
+                             struct log_msg *log_msg);
+
+/* Multiple log_id_t opens */
+struct logger *android_logger_open(struct logger_list *logger_list,
+                                   log_id_t id);
+#define android_logger_close android_logger_free
+/* Single log_id_t open */
+struct logger_list *android_logger_list_open(log_id_t id,
+                                             int mode,
+                                             unsigned int tail,
+                                             pid_t pid);
+#define android_logger_list_close android_logger_list_free
+
+/*
+ * log_id_t helpers
+ */
+log_id_t android_name_to_log_id(const char *logName);
+const char *android_log_id_to_name(log_id_t log_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBS_LOG_LOGGER_H */
diff --git a/src/devtools/adb_tcp/include/log/uio.h b/src/devtools/adb_tcp/include/log/uio.h
new file mode 100644
index 0000000..cc9c9ee
--- /dev/null
+++ b/src/devtools/adb_tcp/include/log/uio.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2007-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.
+ */
+
+//
+// implementation of sys/uio.h for platforms that don't have it (Win32)
+//
+#ifndef _LIBS_CUTILS_UIO_H
+#define _LIBS_CUTILS_UIO_H
+
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#else
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stddef.h>
+
+#if 0
+struct iovec {
+    void*  iov_base;
+    size_t iov_len;
+};
+#endif
+
+extern int  readv( int  fd, struct iovec*  vecs, int  count );
+extern int  writev( int  fd, const struct iovec*  vecs, int  count );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !HAVE_SYS_UIO_H */
+
+#endif /* _LIBS_UTILS_UIO_H */
+
diff --git a/src/devtools/adb_tcp/include/mincrypt/hash-internal.h b/src/devtools/adb_tcp/include/mincrypt/hash-internal.h
new file mode 100644
index 0000000..c813b44
--- /dev/null
+++ b/src/devtools/adb_tcp/include/mincrypt/hash-internal.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2007 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.
+ */
+
+#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_
+#define SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif  // __cplusplus
+
+struct HASH_CTX;  // forward decl
+
+typedef struct HASH_VTAB {
+  void (* const init)(struct HASH_CTX*);
+  void (* const update)(struct HASH_CTX*, const void*, int);
+  const uint8_t* (* const final)(struct HASH_CTX*);
+  const uint8_t* (* const hash)(const void*, int, uint8_t*);
+  int size;
+} HASH_VTAB;
+
+typedef struct HASH_CTX {
+  const HASH_VTAB * f;
+  uint64_t count;
+  uint8_t buf[64];
+  uint32_t state[8];  // upto SHA2
+} HASH_CTX;
+
+#define HASH_init(ctx) (ctx)->f->init(ctx)
+#define HASH_update(ctx, data, len) (ctx)->f->update(ctx, data, len)
+#define HASH_final(ctx) (ctx)->f->final(ctx)
+#define HASH_hash(data, len, digest) (ctx)->f->hash(data, len, digest)
+#define HASH_size(ctx) (ctx)->f->size
+
+#ifdef __cplusplus
+}
+#endif  // __cplusplus
+
+#endif  // SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_
diff --git a/src/devtools/adb_tcp/include/mincrypt/rsa.h b/src/devtools/adb_tcp/include/mincrypt/rsa.h
new file mode 100644
index 0000000..3d0556b
--- /dev/null
+++ b/src/devtools/adb_tcp/include/mincrypt/rsa.h
@@ -0,0 +1,58 @@
+/* rsa.h
+**
+** Copyright 2008, 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.
+*/
+
+#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_RSA_H_
+#define SYSTEM_CORE_INCLUDE_MINCRYPT_RSA_H_
+
+#include <inttypes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define RSANUMBYTES 256           /* 2048 bit key length */
+#define RSANUMWORDS (RSANUMBYTES / sizeof(uint32_t))
+
+typedef struct RSAPublicKey {
+    int len;                  /* Length of n[] in number of uint32_t */
+    uint32_t n0inv;           /* -1 / n[0] mod 2^32 */
+    uint32_t n[RSANUMWORDS];  /* modulus as little endian array */
+    uint32_t rr[RSANUMWORDS]; /* R^2 as little endian array */
+    int exponent;             /* 3 or 65537 */
+} RSAPublicKey;
+
+int RSA_verify(const RSAPublicKey *key,
+               const uint8_t* signature,
+               const int len,
+               const uint8_t* hash,
+               const int hash_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_RSA_H_
diff --git a/src/devtools/adb_tcp/include/mincrypt/sha.h b/src/devtools/adb_tcp/include/mincrypt/sha.h
new file mode 100644
index 0000000..ef60aab
--- /dev/null
+++ b/src/devtools/adb_tcp/include/mincrypt/sha.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2005 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.
+ */
+#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_
+#define SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_
+
+#include <stdint.h>
+#include "hash-internal.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+typedef HASH_CTX SHA_CTX;
+
+void SHA_init(SHA_CTX* ctx);
+void SHA_update(SHA_CTX* ctx, const void* data, int len);
+const uint8_t* SHA_final(SHA_CTX* ctx);
+
+// Convenience method. Returns digest address.
+// NOTE: *digest needs to hold SHA_DIGEST_SIZE bytes.
+const uint8_t* SHA_hash(const void* data, int len, uint8_t* digest);
+
+#define SHA_DIGEST_SIZE 20
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif  // SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_
diff --git a/src/devtools/adb_tcp/include/mincrypt/sha256.h b/src/devtools/adb_tcp/include/mincrypt/sha256.h
new file mode 100644
index 0000000..3a87c31
--- /dev/null
+++ b/src/devtools/adb_tcp/include/mincrypt/sha256.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2011 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.
+ */
+
+#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_SHA256_H_
+#define SYSTEM_CORE_INCLUDE_MINCRYPT_SHA256_H_
+
+#include <stdint.h>
+#include "hash-internal.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+typedef HASH_CTX SHA256_CTX;
+
+void SHA256_init(SHA256_CTX* ctx);
+void SHA256_update(SHA256_CTX* ctx, const void* data, int len);
+const uint8_t* SHA256_final(SHA256_CTX* ctx);
+
+// Convenience method. Returns digest address.
+const uint8_t* SHA256_hash(const void* data, int len, uint8_t* digest);
+
+#define SHA256_DIGEST_SIZE 32
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif  // SYSTEM_CORE_INCLUDE_MINCRYPT_SHA256_H_
diff --git a/src/devtools/adb_tcp/include/private/android_filesystem_capability.h b/src/devtools/adb_tcp/include/private/android_filesystem_capability.h
new file mode 100644
index 0000000..0505cda
--- /dev/null
+++ b/src/devtools/adb_tcp/include/private/android_filesystem_capability.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+/*
+ * Taken from linux/capability.h, with minor modifications
+ */
+
+#ifndef _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_FILESYSTEM_CAPABILITY_H
+#define _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_FILESYSTEM_CAPABILITY_H
+
+#include <stdint.h>
+
+#define __user
+#define __u32 uint32_t
+#define __le32 uint32_t
+
+#define _LINUX_CAPABILITY_VERSION_1 0x19980330
+#define _LINUX_CAPABILITY_U32S_1 1
+#define _LINUX_CAPABILITY_VERSION_2 0x20071026
+#define _LINUX_CAPABILITY_U32S_2 2
+#define _LINUX_CAPABILITY_VERSION_3 0x20080522
+#define _LINUX_CAPABILITY_U32S_3 2
+
+typedef struct __user_cap_header_struct {
+ __u32 version;
+ int pid;
+} __user *cap_user_header_t;
+
+typedef struct __user_cap_data_struct {
+ __u32 effective;
+ __u32 permitted;
+ __u32 inheritable;
+} __user *cap_user_data_t;
+
+#define VFS_CAP_REVISION_MASK 0xFF000000
+#define VFS_CAP_REVISION_SHIFT 24
+#define VFS_CAP_FLAGS_MASK ~VFS_CAP_REVISION_MASK
+#define VFS_CAP_FLAGS_EFFECTIVE 0x000001
+#define VFS_CAP_REVISION_1 0x01000000
+#define VFS_CAP_U32_1 1
+#define XATTR_CAPS_SZ_1 (sizeof(__le32)*(1 + 2*VFS_CAP_U32_1))
+#define VFS_CAP_REVISION_2 0x02000000
+#define VFS_CAP_U32_2 2
+#define XATTR_CAPS_SZ_2 (sizeof(__le32)*(1 + 2*VFS_CAP_U32_2))
+#define XATTR_CAPS_SZ XATTR_CAPS_SZ_2
+#define VFS_CAP_U32 VFS_CAP_U32_2
+#define VFS_CAP_REVISION VFS_CAP_REVISION_2
+
+struct vfs_cap_data {
+ __le32 magic_etc;
+ struct {
+ __le32 permitted;
+ __le32 inheritable;
+ } data[VFS_CAP_U32];
+};
+
+#define _LINUX_CAPABILITY_VERSION _LINUX_CAPABILITY_VERSION_1
+#define _LINUX_CAPABILITY_U32S _LINUX_CAPABILITY_U32S_1
+#define CAP_CHOWN 0
+#define CAP_DAC_OVERRIDE 1
+#define CAP_DAC_READ_SEARCH 2
+#define CAP_FOWNER 3
+#define CAP_FSETID 4
+#define CAP_KILL 5
+#define CAP_SETGID 6
+#define CAP_SETUID 7
+#define CAP_SETPCAP 8
+#define CAP_LINUX_IMMUTABLE 9
+#define CAP_NET_BIND_SERVICE 10
+#define CAP_NET_BROADCAST 11
+#define CAP_NET_ADMIN 12
+#define CAP_NET_RAW 13
+#define CAP_IPC_LOCK 14
+#define CAP_IPC_OWNER 15
+#define CAP_SYS_MODULE 16
+#define CAP_SYS_RAWIO 17
+#define CAP_SYS_CHROOT 18
+#define CAP_SYS_PTRACE 19
+#define CAP_SYS_PACCT 20
+#define CAP_SYS_ADMIN 21
+#define CAP_SYS_BOOT 22
+#define CAP_SYS_NICE 23
+#define CAP_SYS_RESOURCE 24
+#define CAP_SYS_TIME 25
+#define CAP_SYS_TTY_CONFIG 26
+#define CAP_MKNOD 27
+#define CAP_LEASE 28
+#define CAP_AUDIT_WRITE 29
+#define CAP_AUDIT_CONTROL 30
+#define CAP_SETFCAP 31
+#define CAP_MAC_OVERRIDE 32
+#define CAP_MAC_ADMIN 33
+#define CAP_SYSLOG 34
+#define CAP_WAKE_ALARM 35
+#define CAP_LAST_CAP CAP_WAKE_ALARM
+#define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP)
+#define CAP_TO_INDEX(x) ((x) >> 5)
+#define CAP_TO_MASK(x) (1 << ((x) & 31))
+
+#undef __user
+#undef __u32
+#undef __le32
+
+#endif
diff --git a/src/devtools/adb_tcp/include/private/android_filesystem_config.h b/src/devtools/adb_tcp/include/private/android_filesystem_config.h
new file mode 100644
index 0000000..b2f91a5
--- /dev/null
+++ b/src/devtools/adb_tcp/include/private/android_filesystem_config.h
@@ -0,0 +1,315 @@
+/*
+ * 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>
+#include <stdint.h>
+
+#ifdef HAVE_ANDROID_OS
+#include <linux/capability.h>
+#else
+#include "android_filesystem_capability.h"
+#endif
+
+/* 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_CLAT          1029  /* clat part of nat464 */
+#define AID_LOOP_RADIO    1030  /* loop radio devices */
+#define AID_MEDIA_DRM     1031  /* MediaDrm plugins */
+#define AID_PACKAGE_INFO  1032  /* access to installed package details */
+#define AID_SDCARD_PICS   1033  /* external storage photos access */
+#define AID_SDCARD_AV     1034  /* external storage audio/video access */
+#define AID_SDCARD_ALL    1035  /* access all users external storage */
+#define AID_LOGD          1036  /* log daemon */
+#define AID_SHARED_RELRO  1037  /* creator of shared GNU RELRO files */
+
+#define AID_SHELL         2000  /* adb and debug shell user */
+#define AID_CACHE         2001  /* cache access */
+#define AID_DIAG          2002  /* access to diagnostic resources */
+
+/* The range 2900-2999 is reserved for OEM, and must never be
+ * used here */
+#define AID_OEM_RESERVED_START 2900
+#define AID_OEM_RESERVED_END   2999
+
+/* 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_EVERYBODY     9997  /* shared between all apps in the same profile */
+#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, },
+    { "adb",           AID_ADB, },
+    { "install",       AID_INSTALL, },
+    { "media",         AID_MEDIA, },
+    { "dhcp",          AID_DHCP, },
+    { "sdcard_rw",     AID_SDCARD_RW, },
+    { "vpn",           AID_VPN, },
+    { "keystore",      AID_KEYSTORE, },
+    { "usb",           AID_USB, },
+    { "drm",           AID_DRM, },
+    { "mdnsr",         AID_MDNSR, },
+    { "gps",           AID_GPS, },
+    // AID_UNUSED1
+    { "media_rw",      AID_MEDIA_RW, },
+    { "mtp",           AID_MTP, },
+    // AID_UNUSED2
+    { "drmrpc",        AID_DRMRPC, },
+    { "nfc",           AID_NFC, },
+    { "sdcard_r",      AID_SDCARD_R, },
+    { "clat",          AID_CLAT, },
+    { "loop_radio",    AID_LOOP_RADIO, },
+    { "mediadrm",      AID_MEDIA_DRM, },
+    { "package_info",  AID_PACKAGE_INFO, },
+    { "sdcard_pics",   AID_SDCARD_PICS, },
+    { "sdcard_av",     AID_SDCARD_AV, },
+    { "sdcard_all",    AID_SDCARD_ALL, },
+    { "logd",          AID_LOGD, },
+    { "shared_relro",  AID_SHARED_RELRO, },
+
+    { "shell",         AID_SHELL, },
+    { "cache",         AID_CACHE, },
+    { "diag",          AID_DIAG, },
+
+    { "net_bt_admin",  AID_NET_BT_ADMIN, },
+    { "net_bt",        AID_NET_BT, },
+    { "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, },
+    { "net_bt_stack",  AID_NET_BT_STACK, },
+
+    { "everybody",     AID_EVERYBODY, },
+    { "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;
+    uint64_t capabilities;
+    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 const struct fs_path_config android_dirs[] = {
+    { 00770, AID_SYSTEM, AID_CACHE,  0, "cache" },
+    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app" },
+    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private" },
+    { 00771, AID_ROOT,   AID_ROOT,   0, "data/dalvik-cache" },
+    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/data" },
+    { 00771, AID_SHELL,  AID_SHELL,  0, "data/local/tmp" },
+    { 00771, AID_SHELL,  AID_SHELL,  0, "data/local" },
+    { 01771, AID_SYSTEM, AID_MISC,   0, "data/misc" },
+    { 00770, AID_DHCP,   AID_DHCP,   0, "data/misc/dhcp" },
+    { 00771, AID_SHARED_RELRO, AID_SHARED_RELRO, 0, "data/misc/shared_relro" },
+    { 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media" },
+    { 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media/Music" },
+    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data" },
+    { 00750, AID_ROOT,   AID_SHELL,  0, "sbin" },
+    { 00755, AID_ROOT,   AID_SHELL,  0, "system/bin" },
+    { 00755, AID_ROOT,   AID_SHELL,  0, "system/vendor" },
+    { 00755, AID_ROOT,   AID_SHELL,  0, "system/xbin" },
+    { 00755, AID_ROOT,   AID_ROOT,   0, "system/etc/ppp" },
+    { 00755, AID_ROOT,   AID_SHELL,  0, "vendor" },
+    { 00777, AID_ROOT,   AID_ROOT,   0, "sdcard" },
+    { 00755, AID_ROOT,   AID_ROOT,   0, 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 const struct fs_path_config android_files[] = {
+    { 00440, AID_ROOT,      AID_SHELL,     0, "system/etc/init.goldfish.rc" },
+    { 00550, AID_ROOT,      AID_SHELL,     0, "system/etc/init.goldfish.sh" },
+    { 00440, AID_ROOT,      AID_SHELL,     0, "system/etc/init.trout.rc" },
+    { 00550, AID_ROOT,      AID_SHELL,     0, "system/etc/init.ril" },
+    { 00550, AID_ROOT,      AID_SHELL,     0, "system/etc/init.testmenu" },
+    { 00550, AID_DHCP,      AID_SHELL,     0, "system/etc/dhcpcd/dhcpcd-run-hooks" },
+    { 00444, AID_RADIO,     AID_AUDIO,     0, "system/etc/AudioPara4.csv" },
+    { 00555, AID_ROOT,      AID_ROOT,      0, "system/etc/ppp/*" },
+    { 00555, AID_ROOT,      AID_ROOT,      0, "system/etc/rc.*" },
+    { 00644, AID_SYSTEM,    AID_SYSTEM,    0, "data/app/*" },
+    { 00644, AID_MEDIA_RW,  AID_MEDIA_RW,  0, "data/media/*" },
+    { 00644, AID_SYSTEM,    AID_SYSTEM,    0, "data/app-private/*" },
+    { 00644, AID_APP,       AID_APP,       0, "data/data/*" },
+    { 00755, AID_ROOT,      AID_ROOT,      0, "system/bin/ping" },
+
+    /* the following file is INTENTIONALLY set-gid and not set-uid.
+     * Do not change. */
+    { 02750, AID_ROOT,      AID_INET,      0, "system/bin/netcfg" },
+
+    /* the following five files are INTENTIONALLY set-uid, but they
+     * are NOT included on user builds. */
+    { 04750, AID_ROOT,      AID_SHELL,     0, "system/xbin/su" },
+    { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/librank" },
+    { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/procrank" },
+    { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/procmem" },
+    { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/tcpdump" },
+    { 04770, AID_ROOT,      AID_RADIO,     0, "system/bin/pppd-ril" },
+
+    /* the following files have enhanced capabilities and ARE included in user builds. */
+    { 00750, AID_ROOT,      AID_SHELL,     (1 << CAP_SETUID) | (1 << CAP_SETGID), "system/bin/run-as" },
+
+    { 00750, AID_ROOT,      AID_ROOT,      0, "system/bin/uncrypt" },
+    { 00750, AID_ROOT,      AID_ROOT,      0, "system/bin/install-recovery.sh" },
+    { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/*" },
+    { 00755, AID_ROOT,      AID_ROOT,      0, "system/lib/valgrind/*" },
+    { 00755, AID_ROOT,      AID_ROOT,      0, "system/lib64/valgrind/*" },
+    { 00755, AID_ROOT,      AID_SHELL,     0, "system/xbin/*" },
+    { 00755, AID_ROOT,      AID_SHELL,     0, "system/vendor/bin/*" },
+    { 00755, AID_ROOT,      AID_SHELL,     0, "vendor/bin/*" },
+    { 00750, AID_ROOT,      AID_SHELL,     0, "sbin/*" },
+    { 00755, AID_ROOT,      AID_ROOT,      0, "bin/*" },
+    { 00750, AID_ROOT,      AID_SHELL,     0, "init*" },
+    { 00750, AID_ROOT,      AID_SHELL,     0, "sbin/fs_mgr" },
+    { 00640, AID_ROOT,      AID_SHELL,     0, "fstab.*" },
+    { 00644, AID_ROOT,      AID_ROOT,      0, 0 },
+};
+
+static inline void fs_config(const char *path, int dir,
+                             unsigned *uid, unsigned *gid, unsigned *mode, uint64_t *capabilities)
+{
+    const struct fs_path_config *pc;
+    int plen;
+
+    if (path[0] == '/') {
+        path++;
+    }
+
+    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;
+    *capabilities = pc->capabilities;
+
+#if 0
+    fprintf(stderr,"< '%s' '%s' %d %d %o >\n",
+            path, pc->prefix ? pc->prefix : "", *uid, *gid, *mode);
+#endif
+}
+#endif
+#endif
diff --git a/src/devtools/adb_tcp/jdwp_service.c b/src/devtools/adb_tcp/jdwp_service.c
new file mode 100644
index 0000000..cd62b55
--- /dev/null
+++ b/src/devtools/adb_tcp/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_tcp/load_file.c b/src/devtools/adb_tcp/load_file.c
new file mode 100644
index 0000000..99f2965
--- /dev/null
+++ b/src/devtools/adb_tcp/load_file.c
@@ -0,0 +1,51 @@
+/* libs/cutils/load_file.c
+**
+** Copyright 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.
+*/
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+void *load_file(const char *fn, unsigned *_sz)
+{
+    char *data;
+    int sz;
+    int fd;
+
+    data = 0;
+    fd = open(fn, O_RDONLY);
+    if(fd < 0) return 0;
+
+    sz = lseek(fd, 0, SEEK_END);
+    if(sz < 0) goto oops;
+
+    if(lseek(fd, 0, SEEK_SET) != 0) goto oops;
+
+    data = (char*) malloc(sz + 1);
+    if(data == 0) goto oops;
+
+    if(read(fd, data, sz) != sz) goto oops;
+    close(fd);
+    data[sz] = 0;
+
+    if(_sz) *_sz = sz;
+    return data;
+
+oops:
+    close(fd);
+    if(data != 0) free(data);
+    return 0;
+}
diff --git a/src/devtools/adb_tcp/logd_write.c b/src/devtools/adb_tcp/logd_write.c
new file mode 100644
index 0000000..b2668ce
--- /dev/null
+++ b/src/devtools/adb_tcp/logd_write.c
@@ -0,0 +1,499 @@
+/*
+ * Copyright (C) 2007-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.
+ */
+#include <errno.h>
+#include <fcntl.h>
+#ifdef HAVE_PTHREADS
+#include <pthread.h>
+#endif
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#if (FAKE_LOG_DEVICE == 0)
+#include <sys/socket.h>
+#include <sys/un.h>
+#endif
+#include <time.h>
+#include <unistd.h>
+
+#ifdef __BIONIC__
+#include <android/set_abort_message.h>
+#endif
+
+#include <log/logd.h>
+#include <log/logger.h>
+#include <log/log_read.h>
+#include <private/android_filesystem_config.h>
+
+#define LOG_BUF_SIZE 1024
+
+#if FAKE_LOG_DEVICE
+/* This will be defined when building for the host. */
+#include "fake_log_device.h"
+#endif
+
+static int __write_to_log_init(log_id_t, struct iovec *vec, size_t nr);
+static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = __write_to_log_init;
+#ifdef HAVE_PTHREADS
+static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+#ifndef __unused
+#define __unused  __attribute__((__unused__))
+#endif
+
+#if FAKE_LOG_DEVICE
+static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1, -1 };
+#else
+static int logd_fd = -1;
+#endif
+
+/*
+ * This is used by the C++ code to decide if it should write logs through
+ * the C code.  Basically, if /dev/socket/logd is available, we're running in
+ * the simulator rather than a desktop tool and want to use the device.
+ */
+static enum {
+    kLogUninitialized, kLogNotAvailable, kLogAvailable
+} g_log_status = kLogUninitialized;
+int __android_log_dev_available(void)
+{
+    if (g_log_status == kLogUninitialized) {
+        if (access("/dev/socket/logdw", W_OK) == 0)
+            g_log_status = kLogAvailable;
+        else
+            g_log_status = kLogNotAvailable;
+    }
+
+    return (g_log_status == kLogAvailable);
+}
+
+#if !FAKE_LOG_DEVICE
+/* give up, resources too limited */
+static int __write_to_log_null(log_id_t log_fd __unused, struct iovec *vec __unused,
+                               size_t nr __unused)
+{
+    return -1;
+}
+#endif
+
+/* log_init_lock assumed */
+static int __write_to_log_initialize()
+{
+    int i, ret = 0;
+
+#if FAKE_LOG_DEVICE
+    for (i = 0; i < LOG_ID_MAX; i++) {
+        char buf[sizeof("/dev/log_system")];
+        snprintf(buf, sizeof(buf), "/dev/log_%s", android_log_id_to_name(i));
+        log_fds[i] = fakeLogOpen(buf, O_WRONLY);
+    }
+#else
+    if (logd_fd >= 0) {
+        i = logd_fd;
+        logd_fd = -1;
+        close(i);
+    }
+
+    i = socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+    if (i < 0) {
+        ret = -errno;
+        write_to_log = __write_to_log_null;
+    } else if (fcntl(i, F_SETFL, O_NONBLOCK) < 0) {
+        ret = -errno;
+        close(i);
+        i = -1;
+        write_to_log = __write_to_log_null;
+    } else {
+        struct sockaddr_un un;
+        memset(&un, 0, sizeof(struct sockaddr_un));
+        un.sun_family = AF_UNIX;
+        strcpy(un.sun_path, "/dev/socket/logdw");
+
+        if (connect(i, (struct sockaddr *)&un, sizeof(struct sockaddr_un)) < 0) {
+            ret = -errno;
+            close(i);
+            i = -1;
+        }
+    }
+    logd_fd = i;
+#endif
+
+    return ret;
+}
+
+static int __write_to_log_kernel(log_id_t log_id, struct iovec *vec, size_t nr)
+{
+    ssize_t ret;
+#if FAKE_LOG_DEVICE
+    int log_fd;
+
+    if (/*(int)log_id >= 0 &&*/ (int)log_id < (int)LOG_ID_MAX) {
+        log_fd = log_fds[(int)log_id];
+    } else {
+        return -EBADF;
+    }
+    do {
+        ret = fakeLogWritev(log_fd, vec, nr);
+        if (ret < 0) {
+            ret = -errno;
+        }
+    } while (ret == -EINTR);
+#else
+    static const unsigned header_length = 3;
+    struct iovec newVec[nr + header_length];
+    typeof_log_id_t log_id_buf;
+    uint16_t tid;
+    struct timespec ts;
+    log_time realtime_ts;
+    size_t i, payload_size;
+    static uid_t last_uid = AID_ROOT; /* logd *always* starts up as AID_ROOT */
+
+    if (last_uid == AID_ROOT) { /* have we called to get the UID yet? */
+        last_uid = getuid();
+    }
+    if (last_uid == AID_LOGD) { /* logd, after initialization and priv drop */
+        /*
+         * ignore log messages we send to ourself (logd).
+         * Such log messages are often generated by libraries we depend on
+         * which use standard Android logging.
+         */
+        return 0;
+    }
+
+    if (logd_fd < 0) {
+        return -EBADF;
+    }
+
+    /*
+     *  struct {
+     *      // what we provide
+     *      typeof_log_id_t  log_id;
+     *      u16              tid;
+     *      log_time         realtime;
+     *      // caller provides
+     *      union {
+     *          struct {
+     *              char     prio;
+     *              char     payload[];
+     *          } string;
+     *          struct {
+     *              uint32_t tag
+     *              char     payload[];
+     *          } binary;
+     *      };
+     *  };
+     */
+
+    clock_gettime(CLOCK_REALTIME, &ts);
+    realtime_ts.tv_sec = ts.tv_sec;
+    realtime_ts.tv_nsec = ts.tv_nsec;
+
+    log_id_buf = log_id;
+    tid = gettid();
+
+    newVec[0].iov_base   = (unsigned char *) &log_id_buf;
+    newVec[0].iov_len    = sizeof_log_id_t;
+    newVec[1].iov_base   = (unsigned char *) &tid;
+    newVec[1].iov_len    = sizeof(tid);
+    newVec[2].iov_base   = (unsigned char *) &realtime_ts;
+    newVec[2].iov_len    = sizeof(log_time);
+
+    for (payload_size = 0, i = header_length; i < nr + header_length; i++) {
+        newVec[i].iov_base = vec[i - header_length].iov_base;
+        payload_size += newVec[i].iov_len = vec[i - header_length].iov_len;
+
+        if (payload_size > LOGGER_ENTRY_MAX_PAYLOAD) {
+            newVec[i].iov_len -= payload_size - LOGGER_ENTRY_MAX_PAYLOAD;
+            if (newVec[i].iov_len) {
+                ++i;
+            }
+            break;
+        }
+    }
+
+    /*
+     * The write below could be lost, but will never block.
+     *
+     * ENOTCONN occurs if logd dies.
+     * EAGAIN occurs if logd is overloaded.
+     */
+    ret = writev(logd_fd, newVec, i);
+    if (ret < 0) {
+        ret = -errno;
+        if (ret == -ENOTCONN) {
+#ifdef HAVE_PTHREADS
+            pthread_mutex_lock(&log_init_lock);
+#endif
+            ret = __write_to_log_initialize();
+#ifdef HAVE_PTHREADS
+            pthread_mutex_unlock(&log_init_lock);
+#endif
+
+            if (ret < 0) {
+                return ret;
+            }
+
+            ret = writev(logd_fd, newVec, nr + header_length);
+            if (ret < 0) {
+                ret = -errno;
+            }
+        }
+    }
+
+    if (ret > (ssize_t)(sizeof_log_id_t + sizeof(tid) + sizeof(log_time))) {
+        ret -= sizeof_log_id_t + sizeof(tid) + sizeof(log_time);
+    }
+#endif
+
+    return ret;
+}
+
+#if FAKE_LOG_DEVICE
+static const char *LOG_NAME[LOG_ID_MAX] = {
+    [LOG_ID_MAIN] = "main",
+    [LOG_ID_RADIO] = "radio",
+    [LOG_ID_EVENTS] = "events",
+    [LOG_ID_SYSTEM] = "system",
+    [LOG_ID_CRASH] = "crash"
+};
+
+const char *android_log_id_to_name(log_id_t log_id)
+{
+    if (log_id >= LOG_ID_MAX) {
+        log_id = LOG_ID_MAIN;
+    }
+    return LOG_NAME[log_id];
+}
+#endif
+
+static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr)
+{
+#ifdef HAVE_PTHREADS
+    pthread_mutex_lock(&log_init_lock);
+#endif
+
+    if (write_to_log == __write_to_log_init) {
+        int ret;
+
+        ret = __write_to_log_initialize();
+        if (ret < 0) {
+#ifdef HAVE_PTHREADS
+            pthread_mutex_unlock(&log_init_lock);
+#endif
+            return ret;
+        }
+
+        write_to_log = __write_to_log_kernel;
+    }
+
+#ifdef HAVE_PTHREADS
+    pthread_mutex_unlock(&log_init_lock);
+#endif
+
+    return write_to_log(log_id, vec, nr);
+}
+
+int __android_log_write(int prio, const char *tag, const char *msg)
+{
+    struct iovec vec[3];
+    log_id_t log_id = LOG_ID_MAIN;
+    char tmp_tag[32];
+
+    if (!tag)
+        tag = "";
+
+    /* XXX: This needs to go! */
+    if (!strcmp(tag, "HTC_RIL") ||
+        !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */
+        !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */
+        !strcmp(tag, "AT") ||
+        !strcmp(tag, "GSM") ||
+        !strcmp(tag, "STK") ||
+        !strcmp(tag, "CDMA") ||
+        !strcmp(tag, "PHONE") ||
+        !strcmp(tag, "SMS")) {
+            log_id = LOG_ID_RADIO;
+            /* Inform third party apps/ril/radio.. to use Rlog or RLOG */
+            snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag);
+            tag = tmp_tag;
+    }
+
+#if __BIONIC__
+    if (prio == ANDROID_LOG_FATAL) {
+        android_set_abort_message(msg);
+    }
+#endif
+
+    vec[0].iov_base   = (unsigned char *) &prio;
+    vec[0].iov_len    = 1;
+    vec[1].iov_base   = (void *) tag;
+    vec[1].iov_len    = strlen(tag) + 1;
+    vec[2].iov_base   = (void *) msg;
+    vec[2].iov_len    = strlen(msg) + 1;
+
+    return write_to_log(log_id, vec, 3);
+}
+
+int __android_log_buf_write(int bufID, int prio, const char *tag, const char *msg)
+{
+    struct iovec vec[3];
+    char tmp_tag[32];
+
+    if (!tag)
+        tag = "";
+
+    /* XXX: This needs to go! */
+    if ((bufID != LOG_ID_RADIO) &&
+         (!strcmp(tag, "HTC_RIL") ||
+        !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */
+        !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */
+        !strcmp(tag, "AT") ||
+        !strcmp(tag, "GSM") ||
+        !strcmp(tag, "STK") ||
+        !strcmp(tag, "CDMA") ||
+        !strcmp(tag, "PHONE") ||
+        !strcmp(tag, "SMS"))) {
+            bufID = LOG_ID_RADIO;
+            /* Inform third party apps/ril/radio.. to use Rlog or RLOG */
+            snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag);
+            tag = tmp_tag;
+    }
+
+    vec[0].iov_base   = (unsigned char *) &prio;
+    vec[0].iov_len    = 1;
+    vec[1].iov_base   = (void *) tag;
+    vec[1].iov_len    = strlen(tag) + 1;
+    vec[2].iov_base   = (void *) msg;
+    vec[2].iov_len    = strlen(msg) + 1;
+
+    return write_to_log(bufID, vec, 3);
+}
+
+int __android_log_vprint(int prio, const char *tag, const char *fmt, va_list ap)
+{
+    char buf[LOG_BUF_SIZE];
+
+    vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
+
+    return __android_log_write(prio, tag, buf);
+}
+
+int __android_log_print(int prio, const char *tag, const char *fmt, ...)
+{
+    va_list ap;
+    char buf[LOG_BUF_SIZE];
+
+    va_start(ap, fmt);
+    vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
+    va_end(ap);
+
+    return __android_log_write(prio, tag, buf);
+}
+
+int __android_log_buf_print(int bufID, int prio, const char *tag, const char *fmt, ...)
+{
+    va_list ap;
+    char buf[LOG_BUF_SIZE];
+
+    va_start(ap, fmt);
+    vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
+    va_end(ap);
+
+    return __android_log_buf_write(bufID, prio, tag, buf);
+}
+
+void __android_log_assert(const char *cond, const char *tag,
+                          const char *fmt, ...)
+{
+    char buf[LOG_BUF_SIZE];
+
+    if (fmt) {
+        va_list ap;
+        va_start(ap, fmt);
+        vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
+        va_end(ap);
+    } else {
+        /* Msg not provided, log condition.  N.B. Do not use cond directly as
+         * format string as it could contain spurious '%' syntax (e.g.
+         * "%d" in "blocks%devs == 0").
+         */
+        if (cond)
+            snprintf(buf, LOG_BUF_SIZE, "Assertion failed: %s", cond);
+        else
+            strcpy(buf, "Unspecified assertion failed");
+    }
+
+    __android_log_write(ANDROID_LOG_FATAL, tag, buf);
+    __builtin_trap(); /* trap so we have a chance to debug the situation */
+    /* NOTREACHED */
+}
+
+int __android_log_bwrite(int32_t tag, const void *payload, size_t len)
+{
+    struct iovec vec[2];
+
+    vec[0].iov_base = &tag;
+    vec[0].iov_len = sizeof(tag);
+    vec[1].iov_base = (void*)payload;
+    vec[1].iov_len = len;
+
+    return write_to_log(LOG_ID_EVENTS, vec, 2);
+}
+
+/*
+ * Like __android_log_bwrite, but takes the type as well.  Doesn't work
+ * for the general case where we're generating lists of stuff, but very
+ * handy if we just want to dump an integer into the log.
+ */
+int __android_log_btwrite(int32_t tag, char type, const void *payload,
+                          size_t len)
+{
+    struct iovec vec[3];
+
+    vec[0].iov_base = &tag;
+    vec[0].iov_len = sizeof(tag);
+    vec[1].iov_base = &type;
+    vec[1].iov_len = sizeof(type);
+    vec[2].iov_base = (void*)payload;
+    vec[2].iov_len = len;
+
+    return write_to_log(LOG_ID_EVENTS, vec, 3);
+}
+
+/*
+ * Like __android_log_bwrite, but used for writing strings to the
+ * event log.
+ */
+int __android_log_bswrite(int32_t tag, const char *payload)
+{
+    struct iovec vec[4];
+    char type = EVENT_TYPE_STRING;
+    uint32_t len = strlen(payload);
+
+    vec[0].iov_base = &tag;
+    vec[0].iov_len = sizeof(tag);
+    vec[1].iov_base = &type;
+    vec[1].iov_len = sizeof(type);
+    vec[2].iov_base = &len;
+    vec[2].iov_len = sizeof(len);
+    vec[3].iov_base = (void*)payload;
+    vec[3].iov_len = len;
+
+    return write_to_log(LOG_ID_EVENTS, vec, 4);
+}
diff --git a/src/devtools/adb_tcp/loghack.h b/src/devtools/adb_tcp/loghack.h
new file mode 100644
index 0000000..750cab0
--- /dev/null
+++ b/src/devtools/adb_tcp/loghack.h
@@ -0,0 +1,38 @@
+/*
+ * 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 is a temporary hack to enable logging from cutils.
+ */
+
+#ifndef _CUTILS_LOGHACK_H
+#define _CUTILS_LOGHACK_H
+
+#ifdef HAVE_ANDROID_OS
+#include <cutils/log.h>
+#else
+#include <stdio.h>
+#define ALOG(level, ...) \
+        ((void)printf("cutils:" level "/" LOG_TAG ": " __VA_ARGS__))
+#define ALOGV(...)   ALOG("V", __VA_ARGS__)
+#define ALOGD(...)   ALOG("D", __VA_ARGS__)
+#define ALOGI(...)   ALOG("I", __VA_ARGS__)
+#define ALOGW(...)   ALOG("W", __VA_ARGS__)
+#define ALOGE(...)   ALOG("E", __VA_ARGS__)
+#define LOG_ALWAYS_FATAL(...)   do { ALOGE(__VA_ARGS__); exit(1); } while (0)
+#endif
+
+#endif // _CUTILS_LOGHACK_H
diff --git a/src/devtools/adb_tcp/mutex_list.h b/src/devtools/adb_tcp/mutex_list.h
new file mode 100644
index 0000000..ff72751
--- /dev/null
+++ b/src/devtools/adb_tcp/mutex_list.h
@@ -0,0 +1,25 @@
+/* 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(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
diff --git a/src/devtools/adb_tcp/properties.c b/src/devtools/adb_tcp/properties.c
new file mode 100644
index 0000000..20069b0
--- /dev/null
+++ b/src/devtools/adb_tcp/properties.c
@@ -0,0 +1,546 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "properties"
+// #define LOG_NDEBUG 0
+#define   TRACE_TAG  TRACE_ADB
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <cutils/sockets.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <cutils/properties.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include "loghack.h"
+
+int8_t property_get_bool(const char *key, int8_t default_value) {
+    if (!key) {
+        return default_value;
+    }
+
+    int8_t result = default_value;
+    char buf[PROPERTY_VALUE_MAX] = {'\0',};
+
+    int len = property_get(key, buf, "");
+    if (len == 1) {
+        char ch = buf[0];
+        if (ch == '0' || ch == 'n') {
+            result = false;
+        } else if (ch == '1' || ch == 'y') {
+            result = true;
+        }
+    } else if (len > 1) {
+         if (!strcmp(buf, "no") || !strcmp(buf, "false") || !strcmp(buf, "off")) {
+            result = false;
+        } else if (!strcmp(buf, "yes") || !strcmp(buf, "true") || !strcmp(buf, "on")) {
+            result = true;
+        }
+    }
+
+    return result;
+}
+
+// Convert string property to int (default if fails); return default value if out of bounds
+static intmax_t property_get_imax(const char *key, intmax_t lower_bound, intmax_t upper_bound,
+        intmax_t default_value) {
+    if (!key) {
+        return default_value;
+    }
+
+    intmax_t result = default_value;
+    char buf[PROPERTY_VALUE_MAX] = {'\0',};
+    char *end = NULL;
+
+    int len = property_get(key, buf, "");
+    if (len > 0) {
+        int tmp = errno;
+        errno = 0;
+
+        // Infer base automatically
+        result = strtoimax(buf, &end, /*base*/0);
+        if ((result == INTMAX_MIN || result == INTMAX_MAX) && errno == ERANGE) {
+            // Over or underflow
+            result = default_value;
+            ALOGV("%s(%s,%" PRIdMAX ") - overflow", __FUNCTION__, key, default_value);
+        } else if (result < lower_bound || result > upper_bound) {
+            // Out of range of requested bounds
+            result = default_value;
+            ALOGV("%s(%s,%" PRIdMAX ") - out of range", __FUNCTION__, key, default_value);
+        } else if (end == buf) {
+            // Numeric conversion failed
+            result = default_value;
+            ALOGV("%s(%s,%" PRIdMAX ") - numeric conversion failed",
+                    __FUNCTION__, key, default_value);
+        }
+
+        errno = tmp;
+    }
+
+    return result;
+}
+
+int64_t property_get_int64(const char *key, int64_t default_value) {
+    return (int64_t)property_get_imax(key, INT64_MIN, INT64_MAX, default_value);
+}
+
+int32_t property_get_int32(const char *key, int32_t default_value) {
+    return (int32_t)property_get_imax(key, INT32_MIN, INT32_MAX, default_value);
+}
+
+#ifdef HAVE_LIBC_SYSTEM_PROPERTIES
+
+#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
+#include <sys/_system_properties.h>
+
+int property_set(const char *key, const char *value)
+{
+    return __system_property_set(key, value);
+}
+
+int property_get(const char *key, char *value, const char *default_value)
+{
+    int len;
+
+    len = __system_property_get(key, value);
+    if(len > 0) {
+        return len;
+    }
+    if(default_value) {
+        len = strlen(default_value);
+        if (len >= PROPERTY_VALUE_MAX) {
+            len = PROPERTY_VALUE_MAX - 1;
+        }
+        memcpy(value, default_value, len);
+        value[len] = '\0';
+    }
+    return len;
+}
+
+struct property_list_callback_data
+{
+    void (*propfn)(const char *key, const char *value, void *cookie);
+    void *cookie;
+};
+
+static void property_list_callback(const prop_info *pi, void *cookie)
+{
+    char name[PROP_NAME_MAX];
+    char value[PROP_VALUE_MAX];
+    struct property_list_callback_data *data = cookie;
+
+    __system_property_read(pi, name, value);
+    data->propfn(name, value, data->cookie);
+}
+
+int property_list(
+        void (*propfn)(const char *key, const char *value, void *cookie),
+        void *cookie)
+{
+    struct property_list_callback_data data = { propfn, cookie };
+    return __system_property_foreach(property_list_callback, &data);
+}
+
+#elif defined(HAVE_SYSTEM_PROPERTY_SERVER)
+
+/*
+ * The Linux simulator provides a "system property server" that uses IPC
+ * to set/get/list properties.  The file descriptor is shared by all
+ * threads in the process, so we use a mutex to ensure that requests
+ * from multiple threads don't get interleaved.
+ */
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <pthread.h>
+
+static pthread_once_t gInitOnce = PTHREAD_ONCE_INIT;
+static pthread_mutex_t gPropertyFdLock = PTHREAD_MUTEX_INITIALIZER;
+static int gPropFd = -1;
+
+/*
+ * Connect to the properties server.
+ *
+ * Returns the socket descriptor on success.
+ */
+static int connectToServer(const char* fileName)
+{
+    int sock = -1;
+    int cc;
+
+    struct sockaddr_un addr;
+    
+    sock = socket(AF_UNIX, SOCK_STREAM, 0);
+    if (sock < 0) {
+        ALOGW("UNIX domain socket create failed (errno=%d)\n", errno);
+        return -1;
+    }
+
+    /* connect to socket; fails if file doesn't exist */
+    strcpy(addr.sun_path, fileName);    // max 108 bytes
+    addr.sun_family = AF_UNIX;
+    cc = connect(sock, (struct sockaddr*) &addr, SUN_LEN(&addr));
+    if (cc < 0) {
+        // ENOENT means socket file doesn't exist
+        // ECONNREFUSED means socket exists but nobody is listening
+        //ALOGW("AF_UNIX connect failed for '%s': %s\n",
+        //    fileName, strerror(errno));
+        close(sock);
+        return -1;
+    }
+
+    return sock;
+}
+
+/*
+ * Perform one-time initialization.
+ */
+static void init(void)
+{
+    assert(gPropFd == -1);
+
+    gPropFd = connectToServer(SYSTEM_PROPERTY_PIPE_NAME);
+    if (gPropFd < 0) {
+        //ALOGW("not connected to system property server\n");
+    } else {
+        //ALOGV("Connected to system property server\n");
+    }
+}
+
+int property_get(const char *key, char *value, const char *default_value)
+{
+    char sendBuf[1+PROPERTY_KEY_MAX];
+    char recvBuf[1+PROPERTY_VALUE_MAX];
+    int len = -1;
+
+    //ALOGV("PROPERTY GET [%s]\n", key);
+
+    pthread_once(&gInitOnce, init);
+    if (gPropFd < 0) {
+        /* this mimics the behavior of the device implementation */
+        if (default_value != NULL) {
+            strcpy(value, default_value);
+            len = strlen(value);
+        }
+        return len;
+    }
+
+    if (strlen(key) >= PROPERTY_KEY_MAX) return -1;
+
+    memset(sendBuf, 0xdd, sizeof(sendBuf));    // placate valgrind
+
+    sendBuf[0] = (char) kSystemPropertyGet;
+    strcpy(sendBuf+1, key);
+
+    pthread_mutex_lock(&gPropertyFdLock);
+    if (write(gPropFd, sendBuf, sizeof(sendBuf)) != sizeof(sendBuf)) {
+        pthread_mutex_unlock(&gPropertyFdLock);
+        return -1;
+    }
+    if (read(gPropFd, recvBuf, sizeof(recvBuf)) != sizeof(recvBuf)) {
+        pthread_mutex_unlock(&gPropertyFdLock);
+        return -1;
+    }
+    pthread_mutex_unlock(&gPropertyFdLock);
+
+    /* first byte is 0 if value not defined, 1 if found */
+    if (recvBuf[0] == 0) {
+        if (default_value != NULL) {
+            strcpy(value, default_value);
+            len = strlen(value);
+        } else {
+            /*
+             * If the value isn't defined, hand back an empty string and
+             * a zero length, rather than a failure.  This seems wrong,
+             * since you can't tell the difference between "undefined" and
+             * "defined but empty", but it's what the device does.
+             */
+            value[0] = '\0';
+            len = 0;
+        }
+    } else if (recvBuf[0] == 1) {
+        strcpy(value, recvBuf+1);
+        len = strlen(value);
+    } else {
+        ALOGE("Got strange response to property_get request (%d)\n",
+            recvBuf[0]);
+        assert(0);
+        return -1;
+    }
+    //ALOGV("PROP [found=%d def='%s'] (%d) [%s]: [%s]\n",
+    //    recvBuf[0], default_value, len, key, value);
+
+    return len;
+}
+
+
+int property_set(const char *key, const char *value)
+{
+    char sendBuf[1+PROPERTY_KEY_MAX+PROPERTY_VALUE_MAX];
+    char recvBuf[1];
+    int result = -1;
+
+    //ALOGV("PROPERTY SET [%s]: [%s]\n", key, value);
+
+    pthread_once(&gInitOnce, init);
+    if (gPropFd < 0)
+        return -1;
+
+    if (strlen(key) >= PROPERTY_KEY_MAX) return -1;
+    if (strlen(value) >= PROPERTY_VALUE_MAX) return -1;
+
+    memset(sendBuf, 0xdd, sizeof(sendBuf));    // placate valgrind
+
+    sendBuf[0] = (char) kSystemPropertySet;
+    strcpy(sendBuf+1, key);
+    strcpy(sendBuf+1+PROPERTY_KEY_MAX, value);
+
+    pthread_mutex_lock(&gPropertyFdLock);
+    if (write(gPropFd, sendBuf, sizeof(sendBuf)) != sizeof(sendBuf)) {
+        pthread_mutex_unlock(&gPropertyFdLock);
+        return -1;
+    }
+    if (read(gPropFd, recvBuf, sizeof(recvBuf)) != sizeof(recvBuf)) {
+        pthread_mutex_unlock(&gPropertyFdLock);
+        return -1;
+    }
+    pthread_mutex_unlock(&gPropertyFdLock);
+
+    if (recvBuf[0] != 1)
+        return -1;
+    return 0;
+}
+
+int property_list(void (*propfn)(const char *key, const char *value, void *cookie), 
+                  void *cookie)
+{
+    //ALOGV("PROPERTY LIST\n");
+    pthread_once(&gInitOnce, init);
+    if (gPropFd < 0)
+        return -1;
+
+    return 0;
+}
+
+#elif defined(ADB_OVER_PCIE)
+
+/* SUPER-cheesy place-holder implementation for Win32 */
+
+#include <cutils/threads.h>
+
+static mutex_t  env_lock = MUTEX_INITIALIZER;
+
+int property_get(const char *key, char *value, const char *default_value)
+{
+    char ename[PROPERTY_KEY_MAX + 6];
+    char *p;
+    int len;
+    
+    len = strlen(key);
+    if(len >= PROPERTY_KEY_MAX) return -1;
+    memcpy(ename, "PROP_", 5);
+    memcpy(ename + 5, key, len + 1);
+    
+    mutex_lock(&env_lock);
+
+    p = getenv(ename);
+    if(p == 0) p = "";
+    len = strlen(p);
+    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);
+    } else {
+        memcpy(value, p, len);
+        value[len] = 0;
+    }
+
+    mutex_unlock(&env_lock);
+    
+    return len;
+}
+
+
+int property_set(const char *key, const char *value)
+{
+    char ename[PROPERTY_KEY_MAX + 6];
+    char *p;
+    int len;
+    int r;
+
+    if(strlen(value) >= PROPERTY_VALUE_MAX) return -1;
+    
+    len = strlen(key);
+    if(len >= PROPERTY_KEY_MAX) return -1;
+    memcpy(ename, "PROP_", 5);
+    memcpy(ename + 5, key, len + 1);
+
+    mutex_lock(&env_lock);
+#ifdef HAVE_MS_C_RUNTIME
+    {
+        char  temp[256];
+        snprintf( temp, sizeof(temp), "%s=%s", ename, value);
+        putenv(temp);
+        r = 0;
+    }
+#else
+    r = setenv(ename, value, 1);
+#endif
+    mutex_unlock(&env_lock);
+
+    return r;
+}
+
+int property_list(void (*propfn)(const char *key, const char *value, void *cookie),
+                  void *cookie)
+{
+    return 0;
+}
+
+#else
+
+/* UCI configuration system implementation for OpenWrt */
+#include <uci.h>
+#include "adb_trace.h"
+
+#define UCI_CONFIG_FILE          "/etc/config/usb"
+
+int property_get(const char *key, char *value, const char *default_value) {
+    if (NULL == key || NULL == value) {
+        return 0;
+    }
+    int retValue = 0;
+    struct uci_context *uciCtx = uci_alloc_context();
+    const char *pValueData = NULL;
+    struct uci_package *pkg = NULL;
+    struct uci_element *e;
+
+    // replace '.' with '_' to avoid uci r/w error
+    char tmp_string[PROPERTY_KEY_MAX];
+    int str_i = 0;
+    strncpy(tmp_string, key, PROPERTY_KEY_MAX - 1);
+    for (str_i = 0; str_i < PROPERTY_KEY_MAX; str_i++) {
+        if (tmp_string[str_i] == '.') {
+            tmp_string[str_i] = '_';
+        }
+    }
+
+
+    if (UCI_OK != uci_load(uciCtx, UCI_CONFIG_FILE, &pkg)) {
+        if (default_value) {
+            int len = strlen(default_value);
+            memcpy(value, default_value, len);
+            value[len] = '\0';
+            retValue = 1;
+        }
+        D("%s(), uci load fail, file: %s\n", __FUNCTION__, UCI_CONFIG_FILE);
+        goto cleanup;
+    }
+
+    uci_foreach_element(&pkg->sections, e) {
+        struct uci_section *s = uci_to_section(e);
+        if (NULL != (pValueData = uci_lookup_option_string(uciCtx, s, tmp_string))) {
+            if (!strncmp(pValueData, ":empty", strlen(":empty"))) {
+                value[0] = '\0';
+            } else {
+                strncpy(value, pValueData, strlen(pValueData));
+            }
+            retValue = 1;
+            D("property_get, %s: %s\n", key, value);
+        }
+    }
+    if (!retValue) {
+        if (default_value) {
+            int len = strlen(default_value);
+            memcpy(value, default_value, len);
+            value[len] = '\0';
+            retValue = 1;
+            D("property_get use default value, %s: %s\n", key, value);
+        }
+    }
+
+    uci_unload(uciCtx, pkg);
+
+cleanup:
+    uci_free_context(uciCtx);
+    uciCtx = NULL;
+    return retValue;
+}
+
+int property_set(const char *key, const char *new_value) {
+
+    if (NULL == key || NULL == new_value) {
+        return 0;
+    }
+    int retValue = 0;
+    int value = 0;
+    struct uci_context *_ctx = uci_alloc_context();
+    struct uci_ptr ptr;
+    struct uci_package *pkg = NULL;
+    memset(&ptr, 0, sizeof(ptr));
+
+    // replace '.' with '_' to avoid uci r/w error
+    char tmp_string[PROPERTY_KEY_MAX];
+    int str_i = 0;
+    strncpy(tmp_string, key, PROPERTY_KEY_MAX - 1);
+    for (str_i = 0; str_i < PROPERTY_KEY_MAX; str_i++) {
+        if (tmp_string[str_i] == '.') {
+            tmp_string[str_i] = '_';
+        }
+    }
+
+    ptr.package = "usb";
+    ptr.section = "adb";
+    ptr.option = tmp_string;
+    if (strlen(new_value) == 0) {
+        ptr.value = ":empty";
+    } else {
+        ptr.value = new_value;
+    }
+    value = uci_set(_ctx, &ptr);
+    if (value == 0) {
+        value = uci_commit(_ctx, &ptr.p, false);
+        if (value == 0) {
+            retValue = 1;
+            D("property_set ok. %s=%s return %d\n", key, new_value, value);
+        } else {
+            D("property_set uci_commit fail %s=%s return %d\n", key, new_value, value);
+        }
+    } else {
+        D("uci_set fail %s=%s return %d\n", key, new_value, value);
+    }
+    uci_unload(_ctx, ptr.p);
+    uci_free_context(_ctx);
+    _ctx = NULL;
+    return retValue;
+}
+
+int property_list(void (*propfn)(const char *key, const char *value, void *cookie),
+                  void *cookie)
+{
+    return 0;
+}
+
+#endif
diff --git a/src/devtools/adb_tcp/protocol.txt b/src/devtools/adb_tcp/protocol.txt
new file mode 100644
index 0000000..c9d3c24
--- /dev/null
+++ b/src/devtools/adb_tcp/protocol.txt
@@ -0,0 +1,271 @@
+
+--- a replacement for aproto -------------------------------------------
+
+When it comes down to it, aproto's primary purpose is to forward
+various streams between the host computer and client device (in either
+direction).
+
+This replacement further simplifies the concept, reducing the protocol
+to an extremely straightforward model optimized to accomplish the
+forwarding of these streams and removing additional state or
+complexity.
+
+The host side becomes a simple comms bridge with no "UI", which will 
+be used by either commandline or interactive tools to communicate with 
+a device or emulator that is connected to the bridge.
+
+The protocol is designed to be straightforward and well-defined enough 
+that if it needs to be reimplemented in another environment (Java 
+perhaps), there should not problems ensuring perfect interoperability.
+
+The protocol discards the layering aproto has and should allow the 
+implementation to be much more robust.
+
+
+--- protocol overview and basics ---------------------------------------
+
+The transport layer deals in "messages", which consist of a 24 byte
+header followed (optionally) by a payload.  The header consists of 6
+32 bit words which are sent across the wire in little endian format.
+
+struct message {
+    unsigned command;       /* command identifier constant      */
+    unsigned arg0;          /* first argument                   */
+    unsigned arg1;          /* second argument                  */
+    unsigned data_length;   /* length of payload (0 is allowed) */
+    unsigned data_crc32;    /* crc32 of data payload            */
+    unsigned magic;         /* command ^ 0xffffffff             */
+};
+
+Receipt of an invalid message header, corrupt message payload, or an
+unrecognized command MUST result in the closing of the remote
+connection.  The protocol depends on shared state and any break in the
+message stream will result in state getting out of sync.
+
+The following sections describe the six defined message types in
+detail.  Their format is COMMAND(arg0, arg1, payload) where the payload
+is represented by a quoted string or an empty string if none should be
+sent.
+
+The identifiers "local-id" and "remote-id" are always relative to the
+*sender* of the message, so for a receiver, the meanings are effectively
+reversed.
+
+
+
+--- CONNECT(version, maxdata, "system-identity-string") ----------------
+
+The CONNECT message establishes the presence of a remote system.
+The version is used to ensure protocol compatibility and maxdata
+declares the maximum message body size that the remote system
+is willing to accept.
+
+Currently, version=0x01000000 and maxdata=4096
+
+Both sides send a CONNECT message when the connection between them is
+established.  Until a CONNECT message is received no other messages may
+be sent.  Any messages received before a CONNECT message MUST be ignored.
+
+If a CONNECT message is received with an unknown version or insufficiently
+large maxdata value, the connection with the other side must be closed.
+
+The system identity string should be "<systemtype>:<serialno>:<banner>"
+where systemtype is "bootloader", "device", or "host", serialno is some
+kind of unique ID (or empty), and banner is a human-readable version
+or identifier string.  The banner is used to transmit useful properties.
+
+
+--- AUTH(type, 0, "data") ----------------------------------------------
+
+The AUTH message informs the recipient that authentication is required to
+connect to the sender. If type is TOKEN(1), data is a random token that
+the recipient can sign with a private key. The recipient replies with an
+AUTH packet where type is SIGNATURE(2) and data is the signature. If the
+signature verification succeeds, the sender replies with a CONNECT packet.
+
+If the signature verification fails, the sender replies with a new AUTH
+packet and a new random token, so that the recipient can retry signing
+with a different private key.
+
+Once the recipient has tried all its private keys, it can reply with an
+AUTH packet where type is RSAPUBLICKEY(3) and data is the public key. If
+possible, an on-screen confirmation may be displayed for the user to
+confirm they want to install the public key on the device.
+
+
+--- OPEN(local-id, 0, "destination") -----------------------------------
+
+The OPEN message informs the recipient that the sender has a stream
+identified by local-id that it wishes to connect to the named
+destination in the message payload.  The local-id may not be zero.
+
+The OPEN message MUST result in either a READY message indicating that
+the connection has been established (and identifying the other end) or
+a CLOSE message, indicating failure.  An OPEN message also implies
+a READY message sent at the same time.
+
+Common destination naming conventions include:
+
+* "tcp:<host>:<port>" - host may be omitted to indicate localhost
+* "udp:<host>:<port>" - host may be omitted to indicate localhost
+* "local-dgram:<identifier>"
+* "local-stream:<identifier>"
+* "shell" - local shell service
+* "upload" - service for pushing files across (like aproto's /sync)
+* "fs-bridge" - FUSE protocol filesystem bridge
+
+
+--- READY(local-id, remote-id, "") -------------------------------------
+
+The READY message informs the recipient that the sender's stream
+identified by local-id is ready for write messages and that it is
+connected to the recipient's stream identified by remote-id.
+
+Neither the local-id nor the remote-id may be zero. 
+
+A READY message containing a remote-id which does not map to an open
+stream on the recipient's side is ignored.  The stream may have been
+closed while this message was in-flight.
+
+The local-id is ignored on all but the first READY message (where it
+is used to establish the connection).  Nonetheless, the local-id MUST
+not change on later READY messages sent to the same stream.
+
+
+
+--- WRITE(0, remote-id, "data") ----------------------------------------
+
+The WRITE message sends data to the recipient's stream identified by
+remote-id.  The payload MUST be <= maxdata in length.
+
+A WRITE message containing a remote-id which does not map to an open
+stream on the recipient's side is ignored.  The stream may have been
+closed while this message was in-flight.
+
+A WRITE message may not be sent until a READY message is received.
+Once a WRITE message is sent, an additional WRITE message may not be
+sent until another READY message has been received.  Recipients of
+a WRITE message that is in violation of this requirement will CLOSE
+the connection.
+
+
+--- CLOSE(local-id, remote-id, "") -------------------------------------
+
+The CLOSE message informs recipient that the connection between the
+sender's stream (local-id) and the recipient's stream (remote-id) is
+broken.  The remote-id MUST not be zero, but the local-id MAY be zero
+if this CLOSE indicates a failed OPEN.
+
+A CLOSE message containing a remote-id which does not map to an open
+stream on the recipient's side is ignored.  The stream may have
+already been closed by the recipient while this message was in-flight.
+
+The recipient should not respond to a CLOSE message in any way.  The
+recipient should cancel pending WRITEs or CLOSEs, but this is not a
+requirement, since they will be ignored.
+
+
+--- SYNC(online, sequence, "") -----------------------------------------
+
+The SYNC message is used by the io pump to make sure that stale
+outbound messages are discarded when the connection to the remote side
+is broken.  It is only used internally to the bridge and never valid
+to send across the wire.  
+
+* when the connection to the remote side goes offline, the io pump 
+  sends a SYNC(0, 0) and starts discarding all messages
+* when the connection to the remote side is established, the io pump
+  sends a SYNC(1, token) and continues to discard messages
+* when the io pump receives a matching SYNC(1, token), it once again
+  starts accepting messages to forward to the remote side
+
+
+--- message command constants ------------------------------------------
+
+#define A_SYNC 0x434e5953
+#define A_CNXN 0x4e584e43
+#define A_AUTH 0x48545541
+#define A_OPEN 0x4e45504f
+#define A_OKAY 0x59414b4f
+#define A_CLSE 0x45534c43
+#define A_WRTE 0x45545257
+
+
+
+--- implementation details ---------------------------------------------
+
+The core of the bridge program will use three threads.  One thread
+will be a select/epoll loop to handle io between various inbound and
+outbound connections and the connection to the remote side.
+
+The remote side connection will be implemented as two threads (one for
+reading, one for writing) and a datagram socketpair to provide the
+channel between the main select/epoll thread and the remote connection
+threadpair.  The reason for this is that for usb connections, the
+kernel interface on linux and osx does not allow you to do meaningful
+nonblocking IO.
+
+The endian swapping for the message headers will happen (as needed) in
+the remote connection threadpair and that the rest of the program will
+always treat message header values as native-endian.
+
+The bridge program will be able to have a number of mini-servers
+compiled in.  They will be published under known names (examples
+"shell", "fs-bridge", etc) and upon receiving an OPEN() to such a
+service, the bridge program will create a stream socketpair and spawn
+a thread or subprocess to handle the io.
+
+
+--- simplified / embedded implementation -------------------------------
+
+For limited environments, like the bootloader, it is allowable to
+support a smaller, fixed number of channels using pre-assigned channel
+ID numbers such that only one stream may be connected to a bootloader
+endpoint at any given time.  The protocol remains unchanged, but the
+"embedded" version of it is less dynamic.
+
+The bootloader will support two streams.  A "bootloader:debug" stream,
+which may be opened to get debug messages from the bootloader and a 
+"bootloader:control", stream which will support the set of basic 
+bootloader commands.
+
+Example command stream dialogues:  
+  "flash_kernel,2515049,........\n" "okay\n" 
+  "flash_ramdisk,5038,........\n" "fail,flash write error\n" 
+  "bogus_command......" <CLOSE>
+
+
+--- future expansion ---------------------------------------------------
+
+I plan on providing either a message or a special control stream so that
+the client device could ask the host computer to setup inbound socket
+translations on the fly on behalf of the client device.
+
+
+The initial design does handshaking to provide flow control, with a
+message flow that looks like:
+
+  >OPEN <READY >WRITE <READY >WRITE <READY >WRITE <CLOSE
+
+The far side may choose to issue the READY message as soon as it receives
+a WRITE or it may defer the READY until the write to the local stream
+succeeds.  A future version may want to do some level of windowing where
+multiple WRITEs may be sent without requiring individual READY acks.
+
+------------------------------------------------------------------------
+
+--- smartsockets -------------------------------------------------------
+
+Port 5037 is used for smart sockets which allow a client on the host
+side to request access to a service in the host adb daemon or in the
+remote (device) daemon.  The service is requested by ascii name,
+preceeded by a 4 digit hex length.  Upon successful connection an
+"OKAY" response is sent, otherwise a "FAIL" message is returned.  Once
+connected the client is talking to that (remote or local) service.
+
+client: <hex4> <service-name>
+server: "OKAY"
+
+client: <hex4> <service-name>
+server: "FAIL" <hex4> <reason>
+
diff --git a/src/devtools/adb_tcp/remount_service.c b/src/devtools/adb_tcp/remount_service.c
new file mode 100644
index 0000000..72d15a1
--- /dev/null
+++ b/src/devtools/adb_tcp/remount_service.c
@@ -0,0 +1,138 @@
+/*
+ * 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 <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <unistd.h>
+
+#include "sysdeps.h"
+
+#define  TRACE_TAG  TRACE_ADB
+#include "adb.h"
+
+
+static int system_ro = 1;
+static int vendor_ro = 1;
+
+/* Returns the device used to mount a directory in /proc/mounts */
+static char *find_mount(const char *dir)
+{
+    int fd;
+    int res;
+    char *token = NULL;
+    const char delims[] = "\n";
+    char buf[4096];
+
+    fd = unix_open("/proc/mounts", O_RDONLY | O_CLOEXEC);
+    if (fd < 0)
+        return NULL;
+
+    buf[sizeof(buf) - 1] = '\0';
+    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;
+}
+
+static int hasVendorPartition()
+{
+    struct stat info;
+    if (!lstat("/vendor", &info))
+        if ((info.st_mode & S_IFMT) == S_IFDIR)
+          return true;
+    return false;
+}
+
+/* Init mounts /system as read only, remount to enable writes. */
+static int remount(const char* dir, int* dir_ro)
+{
+    char *dev;
+    int fd;
+    int OFF = 0;
+
+    if (dir_ro == 0) {
+        return 0;
+    }
+
+    dev = find_mount(dir);
+
+    if (!dev)
+        return -1;
+
+    fd = unix_open(dev, O_RDONLY | O_CLOEXEC);
+    if (fd < 0)
+        return -1;
+
+    ioctl(fd, BLKROSET, &OFF);
+    adb_close(fd);
+
+    *dir_ro = mount(dev, dir, "none", MS_REMOUNT, NULL);
+
+    free(dev);
+
+    return *dir_ro;
+}
+
+static void write_string(int fd, const char* str)
+{
+    writex(fd, str, strlen(str));
+}
+
+void remount_service(int fd, void *cookie)
+{
+    char buffer[200];
+    if (remount("/system", &system_ro)) {
+        snprintf(buffer, sizeof(buffer), "remount of system failed: %s\n",strerror(errno));
+        write_string(fd, buffer);
+    }
+
+    if (hasVendorPartition()) {
+        if (remount("/vendor", &vendor_ro)) {
+            snprintf(buffer, sizeof(buffer), "remount of vendor failed: %s\n",strerror(errno));
+            write_string(fd, buffer);
+        }
+    }
+
+    if (!system_ro && (!vendor_ro || !hasVendorPartition()))
+        write_string(fd, "remount succeeded\n");
+    else {
+        write_string(fd, "remount failed\n");
+    }
+
+    adb_close(fd);
+}
+
diff --git a/src/devtools/adb_tcp/rsa.c b/src/devtools/adb_tcp/rsa.c
new file mode 100644
index 0000000..171c437
--- /dev/null
+++ b/src/devtools/adb_tcp/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_tcp/services.c b/src/devtools/adb_tcp/services.c
new file mode 100644
index 0000000..1360782
--- /dev/null
+++ b/src/devtools/adb_tcp/services.c
@@ -0,0 +1,690 @@
+/*
+ * 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 <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <linux/reboot.h>
+#include <sys/syscall.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>
+#  include <cutils/properties.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
+
+void restart_root_service(int fd, void *cookie)
+{
+    char buf[100];
+
+    if (getuid() == 0) {
+        snprintf(buf, sizeof(buf), "adbd is already running as root\n");
+        writex(fd, buf, strlen(buf));
+        adb_close(fd);
+    } else {
+#ifndef ADB_NON_ANDROID
+        char value[PROPERTY_VALUE_MAX];
+        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;
+        }
+#endif /* !ADB_NON_ANDROID */
+
+        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) (uintptr_t) 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 restart_adbd_service(int fd, void *cookie)
+{
+    char buf[100];
+
+    snprintf(buf, sizeof(buf), "restarting service\n");
+    writex(fd, buf, strlen(buf));
+    adb_close(fd);
+}
+
+void reboot_service(int fd, void *arg)
+{
+    char buf[100];
+    char property_val[PROPERTY_VALUE_MAX];
+    int ret;
+    const char *param = (const char *)arg;
+    int cmd;
+
+     sync();
+
+    if (!param || strlen(param) == 0)
+        cmd = LINUX_REBOOT_CMD_RESTART;
+    else
+        cmd = LINUX_REBOOT_CMD_RESTART2;
+    syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, param);
+
+#if 0
+    ret = snprintf(property_val, sizeof(property_val), "reboot,%s", (char *) arg);
+    if (ret >= (int) sizeof(property_val)) {
+        snprintf(buf, sizeof(buf), "reboot string too long. length=%d\n", ret);
+        writex(fd, buf, strlen(buf));
+        goto cleanup;
+    }
+
+    ret = property_set(ANDROID_RB_PROPERTY, property_val);
+    if (ret < 0) {
+        snprintf(buf, sizeof(buf), "reboot failed: %d\n", ret);
+        writex(fd, buf, strlen(buf));
+        goto cleanup;
+    }
+    // Don't return early. Give the reboot command time to take effect
+    // to avoid messing up scripts which do "adb reboot && adb wait-for-device"
+    while(1) { pause(); }
+#endif
+cleanup:
+    free(arg);
+    adb_close(fd);
+}
+
+void reverse_service(int fd, void* arg)
+{
+    const char* command = arg;
+
+    if (handle_forward_request(command, kTransportAny, NULL, fd) < 0) {
+        sendfailmsg(fd, "not a reverse forwarding command");
+    }
+    free(arg);
+    adb_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 void init_subproc_child()
+{
+    setsid();
+
+    // Set OOM score adjustment to prevent killing
+    int fd = adb_open("/proc/self/oom_score_adj", O_WRONLY | O_CLOEXEC);
+    if (fd >= 0) {
+        adb_write(fd, "0", 1);
+        adb_close(fd);
+    } else {
+       D("adb: unable to update oom_score_adj\n");
+    }
+}
+
+static int create_subproc_pty(const char *cmd, const char *arg0, const char *arg1, pid_t *pid)
+{
+    D("create_subproc_pty(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1);
+#if defined(_WIN32)
+    fprintf(stderr, "error: create_subproc_pty not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1);
+    return -1;
+#else
+    int ptm;
+
+    ptm = unix_open("/dev/ptmx", O_RDWR | O_CLOEXEC); // | O_NOCTTY);
+    if(ptm < 0){
+        printf("[ cannot open /dev/ptmx - %s ]\n",strerror(errno));
+        return -1;
+    }
+
+    char devname[64];
+    if(grantpt(ptm) || unlockpt(ptm) || ptsname_r(ptm, devname, sizeof(devname)) != 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) {
+        init_subproc_child();
+
+        int pts = unix_open(devname, O_RDWR | O_CLOEXEC);
+        if (pts < 0) {
+            fprintf(stderr, "child failed to open pseudo-term slave: %s\n", devname);
+            exit(-1);
+        }
+
+        dup2(pts, STDIN_FILENO);
+        dup2(pts, STDOUT_FILENO);
+        dup2(pts, STDERR_FILENO);
+
+        adb_close(pts);
+        adb_close(ptm);
+
+        execl(cmd, cmd, arg0, arg1, NULL);
+        fprintf(stderr, "- exec '%s' failed: %s (%d) -\n",
+                cmd, strerror(errno), errno);
+        exit(-1);
+    } else {
+        return ptm;
+    }
+#endif /* !defined(_WIN32) */
+}
+
+static int create_subproc_raw(const char *cmd, const char *arg0, const char *arg1, pid_t *pid)
+{
+    D("create_subproc_raw(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1);
+#if defined(_WIN32)
+    fprintf(stderr, "error: create_subproc_raw not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1);
+    return -1;
+#else
+
+    // 0 is parent socket, 1 is child socket
+    int sv[2];
+    if (unix_socketpair(AF_UNIX, SOCK_STREAM, 0, sv) < 0) {
+        printf("[ cannot create socket pair - %s ]\n", strerror(errno));
+        return -1;
+    }
+
+    *pid = fork();
+    if (*pid < 0) {
+        printf("- fork failed: %s -\n", strerror(errno));
+        adb_close(sv[0]);
+        adb_close(sv[1]);
+        return -1;
+    }
+
+    if (*pid == 0) {
+        adb_close(sv[0]);
+        init_subproc_child();
+
+        dup2(sv[1], STDIN_FILENO);
+        dup2(sv[1], STDOUT_FILENO);
+        dup2(sv[1], STDERR_FILENO);
+
+        adb_close(sv[1]);
+
+        execl(cmd, cmd, arg0, arg1, NULL);
+        fprintf(stderr, "- exec '%s' failed: %s (%d) -\n",
+                cmd, strerror(errno), errno);
+        exit(-1);
+    } else {
+        adb_close(sv[1]);
+        return sv[0];
+    }
+#endif /* !defined(_WIN32) */
+}
+#endif  /* !ABD_HOST */
+
+#if ADB_HOST || ADB_NON_ANDROID
+#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) (uintptr_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, const subproc_mode mode)
+{
+    stinfo *sti;
+    adb_thread_t t;
+    int ret_fd;
+    pid_t pid = -1;
+
+    const char *arg0, *arg1;
+    if (name == 0 || *name == 0) {
+        arg0 = "-"; arg1 = 0;
+    } else {
+        arg0 = "-c"; arg1 = name;
+    }
+
+    switch (mode) {
+    case SUBPROC_PTY:
+        ret_fd = create_subproc_pty(SHELL_COMMAND, arg0, arg1, &pid);
+        break;
+    case SUBPROC_RAW:
+        ret_fd = create_subproc_raw(SHELL_COMMAND, arg0, arg1, &pid);
+        break;
+    default:
+        fprintf(stderr, "invalid subproc_mode %d\n", mode);
+        return -1;
+    }
+    D("create_subproc 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*) (uintptr_t) pid;
+    sti->fd = ret_fd;
+
+    if (adb_thread_create(&t, service_bootstrap_func, sti)) {
+        free(sti);
+        adb_close(ret_fd);
+        fprintf(stderr, "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
+            ret = socket_network_client(name + 1, port, SOCK_STREAM);
+#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("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)) {
+        ret = create_subproc_thread(name + 5, SUBPROC_RAW);
+    } 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 == NULL) 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;
+        char* c = arg;
+        for (; *c != '\0'; c++) {
+            if (*c == ':')
+                *c = ' ';
+        }
+        char* cmd;
+        if (asprintf(&cmd, "/system/bin/bu backup %s", arg) != -1) {
+            ret = create_subproc_thread(cmd, SUBPROC_RAW);
+            free(cmd);
+        }
+        free(arg);
+    } else if(!strncmp(name, "restore:", 8)) {
+        ret = create_subproc_thread("/system/bin/bu restore", SUBPROC_RAW);
+    } 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 *) (uintptr_t) port);
+    } else if(!strncmp(name, "usb:", 4)) {
+        ret = create_service_thread(restart_usb_service, NULL);
+    } else if(!strncmp(name, "reconnect:", 10)) {
+        ret = create_service_thread(restart_adbd_service, NULL);
+    } else if (!strncmp(name, "reverse:", 8)) {
+        char* cookie = strdup(name + 8);
+        if (cookie == NULL) {
+            ret = -1;
+        } else {
+            ret = create_service_thread(reverse_service, cookie);
+            if (ret < 0) {
+                free(cookie);
+            }
+        }
+#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");
+}
+
+static void connect_device(char* host, char* buffer, int buffer_size)
+{
+    int port, fd;
+    char* portstr = strchr(host, ':');
+    char hostbuf[100];
+    char serial[100];
+    int ret;
+
+    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);
+
+    fd = socket_network_client_timeout(hostbuf, port, SOCK_STREAM, 10);
+    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);
+
+    ret = register_socket_transport(fd, serial, port, 0);
+    if (ret < 0) {
+        adb_close(fd);
+        snprintf(buffer, buffer_size, "already connected to %s", serial);
+    } else {
+        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);
+    }
+}
+
+static void connect_service(int fd, void* cookie)
+{
+    char buf[4096];
+    char resp[4096];
+    char *host = cookie;
+
+    if (!strncmp(host, "emu:", 4)) {
+        connect_emulator(host + 4, buf, sizeof(buf));
+    } else {
+        connect_device(host, buf, sizeof(buf));
+    }
+
+    // Send response for emulator and device
+    snprintf(resp, sizeof(resp), "%04x%s",(unsigned)strlen(buf), buf);
+    writex(fd, resp, strlen(resp));
+    adb_close(fd);
+}
+#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);
+    } else if (!strncmp(name, "connect:", 8)) {
+        const char *host = name + 8;
+        int fd = create_service_thread(connect_service, (void *)host);
+        return create_local_socket(fd);
+    }
+    return NULL;
+}
+#endif /* ADB_HOST */
diff --git a/src/devtools/adb_tcp/sha.c b/src/devtools/adb_tcp/sha.c
new file mode 100644
index 0000000..5bef32e
--- /dev/null
+++ b/src/devtools/adb_tcp/sha.c
@@ -0,0 +1,155 @@
+/* sha.c
+**
+** Copyright 2013, 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.
+*/
+
+// Optimized for minimal code size.
+
+#include "mincrypt/sha.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+#define rol(bits, value) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+static void SHA1_Transform(SHA_CTX* ctx) {
+    uint32_t W[80];
+    uint32_t A, B, C, D, E;
+    uint8_t* p = ctx->buf;
+    int t;
+
+    for(t = 0; t < 16; ++t) {
+        uint32_t tmp =  *p++ << 24;
+        tmp |= *p++ << 16;
+        tmp |= *p++ << 8;
+        tmp |= *p++;
+        W[t] = tmp;
+    }
+
+    for(; t < 80; t++) {
+        W[t] = rol(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
+    }
+
+    A = ctx->state[0];
+    B = ctx->state[1];
+    C = ctx->state[2];
+    D = ctx->state[3];
+    E = ctx->state[4];
+
+    for(t = 0; t < 80; t++) {
+        uint32_t tmp = rol(5,A) + E + W[t];
+
+        if (t < 20)
+            tmp += (D^(B&(C^D))) + 0x5A827999;
+        else if ( t < 40)
+            tmp += (B^C^D) + 0x6ED9EBA1;
+        else if ( t < 60)
+            tmp += ((B&C)|(D&(B|C))) + 0x8F1BBCDC;
+        else
+            tmp += (B^C^D) + 0xCA62C1D6;
+
+        E = D;
+        D = C;
+        C = rol(30,B);
+        B = A;
+        A = tmp;
+    }
+
+    ctx->state[0] += A;
+    ctx->state[1] += B;
+    ctx->state[2] += C;
+    ctx->state[3] += D;
+    ctx->state[4] += E;
+}
+
+static const HASH_VTAB SHA_VTAB = {
+    SHA_init,
+    SHA_update,
+    SHA_final,
+    SHA_hash,
+    SHA_DIGEST_SIZE
+};
+
+void SHA_init(SHA_CTX* ctx) {
+    ctx->f = &SHA_VTAB;
+    ctx->state[0] = 0x67452301;
+    ctx->state[1] = 0xEFCDAB89;
+    ctx->state[2] = 0x98BADCFE;
+    ctx->state[3] = 0x10325476;
+    ctx->state[4] = 0xC3D2E1F0;
+    ctx->count = 0;
+}
+
+
+void SHA_update(SHA_CTX* ctx, const void* data, int len) {
+    int i = (int) (ctx->count & 63);
+    const uint8_t* p = (const uint8_t*)data;
+
+    ctx->count += len;
+
+    while (len--) {
+        ctx->buf[i++] = *p++;
+        if (i == 64) {
+            SHA1_Transform(ctx);
+            i = 0;
+        }
+    }
+}
+
+
+const uint8_t* SHA_final(SHA_CTX* ctx) {
+    uint8_t *p = ctx->buf;
+    uint64_t cnt = ctx->count * 8;
+    int i;
+
+    SHA_update(ctx, (uint8_t*)"\x80", 1);
+    while ((ctx->count & 63) != 56) {
+        SHA_update(ctx, (uint8_t*)"\0", 1);
+    }
+    for (i = 0; i < 8; ++i) {
+        uint8_t tmp = (uint8_t) (cnt >> ((7 - i) * 8));
+        SHA_update(ctx, &tmp, 1);
+    }
+
+    for (i = 0; i < 5; i++) {
+        uint32_t tmp = ctx->state[i];
+        *p++ = tmp >> 24;
+        *p++ = tmp >> 16;
+        *p++ = tmp >> 8;
+        *p++ = tmp >> 0;
+    }
+
+    return ctx->buf;
+}
+
+/* Convenience function */
+const uint8_t* SHA_hash(const void* data, int len, uint8_t* digest) {
+    SHA_CTX ctx;
+    SHA_init(&ctx);
+    SHA_update(&ctx, data, len);
+    memcpy(digest, SHA_final(&ctx), SHA_DIGEST_SIZE);
+    return digest;
+}
diff --git a/src/devtools/adb_tcp/sha256.c b/src/devtools/adb_tcp/sha256.c
new file mode 100644
index 0000000..eb6e308
--- /dev/null
+++ b/src/devtools/adb_tcp/sha256.c
@@ -0,0 +1,184 @@
+/* sha256.c
+**
+** Copyright 2013, 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.
+*/
+
+// Optimized for minimal code size.
+
+#include "mincrypt/sha256.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+#define ror(value, bits) (((value) >> (bits)) | ((value) << (32 - (bits))))
+#define shr(value, bits) ((value) >> (bits))
+
+static const uint32_t K[64] = {
+    0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
+    0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+    0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+    0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+    0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
+    0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+    0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
+    0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+    0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+    0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+    0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
+    0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+    0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
+    0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+    0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+    0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 };
+
+static void SHA256_Transform(SHA256_CTX* ctx) {
+    uint32_t W[64];
+    uint32_t A, B, C, D, E, F, G, H;
+    uint8_t* p = ctx->buf;
+    int t;
+
+    for(t = 0; t < 16; ++t) {
+        uint32_t tmp =  *p++ << 24;
+        tmp |= *p++ << 16;
+        tmp |= *p++ << 8;
+        tmp |= *p++;
+        W[t] = tmp;
+    }
+
+    for(; t < 64; t++) {
+        uint32_t s0 = ror(W[t-15], 7) ^ ror(W[t-15], 18) ^ shr(W[t-15], 3);
+        uint32_t s1 = ror(W[t-2], 17) ^ ror(W[t-2], 19) ^ shr(W[t-2], 10);
+        W[t] = W[t-16] + s0 + W[t-7] + s1;
+    }
+
+    A = ctx->state[0];
+    B = ctx->state[1];
+    C = ctx->state[2];
+    D = ctx->state[3];
+    E = ctx->state[4];
+    F = ctx->state[5];
+    G = ctx->state[6];
+    H = ctx->state[7];
+
+    for(t = 0; t < 64; t++) {
+        uint32_t s0 = ror(A, 2) ^ ror(A, 13) ^ ror(A, 22);
+        uint32_t maj = (A & B) ^ (A & C) ^ (B & C);
+        uint32_t t2 = s0 + maj;
+        uint32_t s1 = ror(E, 6) ^ ror(E, 11) ^ ror(E, 25);
+        uint32_t ch = (E & F) ^ ((~E) & G);
+        uint32_t t1 = H + s1 + ch + K[t] + W[t];
+
+        H = G;
+        G = F;
+        F = E;
+        E = D + t1;
+        D = C;
+        C = B;
+        B = A;
+        A = t1 + t2;
+    }
+
+    ctx->state[0] += A;
+    ctx->state[1] += B;
+    ctx->state[2] += C;
+    ctx->state[3] += D;
+    ctx->state[4] += E;
+    ctx->state[5] += F;
+    ctx->state[6] += G;
+    ctx->state[7] += H;
+}
+
+static const HASH_VTAB SHA256_VTAB = {
+    SHA256_init,
+    SHA256_update,
+    SHA256_final,
+    SHA256_hash,
+    SHA256_DIGEST_SIZE
+};
+
+void SHA256_init(SHA256_CTX* ctx) {
+    ctx->f = &SHA256_VTAB;
+    ctx->state[0] = 0x6a09e667;
+    ctx->state[1] = 0xbb67ae85;
+    ctx->state[2] = 0x3c6ef372;
+    ctx->state[3] = 0xa54ff53a;
+    ctx->state[4] = 0x510e527f;
+    ctx->state[5] = 0x9b05688c;
+    ctx->state[6] = 0x1f83d9ab;
+    ctx->state[7] = 0x5be0cd19;
+    ctx->count = 0;
+}
+
+
+void SHA256_update(SHA256_CTX* ctx, const void* data, int len) {
+    int i = (int) (ctx->count & 63);
+    const uint8_t* p = (const uint8_t*)data;
+
+    ctx->count += len;
+
+    while (len--) {
+        ctx->buf[i++] = *p++;
+        if (i == 64) {
+            SHA256_Transform(ctx);
+            i = 0;
+        }
+    }
+}
+
+
+const uint8_t* SHA256_final(SHA256_CTX* ctx) {
+    uint8_t *p = ctx->buf;
+    uint64_t cnt = ctx->count * 8;
+    int i;
+
+    SHA256_update(ctx, (uint8_t*)"\x80", 1);
+    while ((ctx->count & 63) != 56) {
+        SHA256_update(ctx, (uint8_t*)"\0", 1);
+    }
+    for (i = 0; i < 8; ++i) {
+        uint8_t tmp = (uint8_t) (cnt >> ((7 - i) * 8));
+        SHA256_update(ctx, &tmp, 1);
+    }
+
+    for (i = 0; i < 8; i++) {
+        uint32_t tmp = ctx->state[i];
+        *p++ = tmp >> 24;
+        *p++ = tmp >> 16;
+        *p++ = tmp >> 8;
+        *p++ = tmp >> 0;
+    }
+
+    return ctx->buf;
+}
+
+/* Convenience function */
+const uint8_t* SHA256_hash(const void* data, int len, uint8_t* digest) {
+    SHA256_CTX ctx;
+    SHA256_init(&ctx);
+    SHA256_update(&ctx, data, len);
+    memcpy(digest, SHA256_final(&ctx), SHA256_DIGEST_SIZE);
+    return digest;
+}
diff --git a/src/devtools/adb_tcp/socket_inaddr_any_server.c b/src/devtools/adb_tcp/socket_inaddr_any_server.c
new file mode 100644
index 0000000..6c849de
--- /dev/null
+++ b/src/devtools/adb_tcp/socket_inaddr_any_server.c
@@ -0,0 +1,68 @@
+/*
+** Copyright 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.
+*/
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifndef HAVE_WINSOCK
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#endif
+
+#include <cutils/sockets.h>
+
+#define LISTEN_BACKLOG 4
+
+/* open listen() port on any interface */
+int socket_inaddr_any_server(int port, int type)
+{
+    struct sockaddr_in addr;
+    int s, n;
+
+    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 < 0) return -1;
+
+    n = 1;
+    setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *) &n, sizeof(n));
+
+    if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+        close(s);
+        return -1;
+    }
+
+    if (type == SOCK_STREAM) {
+        int ret;
+
+        ret = listen(s, LISTEN_BACKLOG);
+
+        if (ret < 0) {
+            close(s);
+            return -1; 
+        }
+    }
+
+    return s;
+}
diff --git a/src/devtools/adb_tcp/socket_local.h b/src/devtools/adb_tcp/socket_local.h
new file mode 100644
index 0000000..45b9856
--- /dev/null
+++ b/src/devtools/adb_tcp/socket_local.h
@@ -0,0 +1,39 @@
+/*
+ * 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 __SOCKET_LOCAL_H
+#define __SOCKET_LOCAL_H
+
+#define FILESYSTEM_SOCKET_PREFIX "/tmp/" 
+#define ANDROID_RESERVED_SOCKET_PREFIX "/dev/socket/"
+
+/*
+ * Set up a given sockaddr_un, to have it refer to the given
+ * name in the given namespace. The namespace must be one
+ * of <code>ANDROID_SOCKET_NAMESPACE_ABSTRACT</code>,
+ * <code>ANDROID_SOCKET_NAMESPACE_RESERVED</code>, or
+ * <code>ANDROID_SOCKET_NAMESPACE_FILESYSTEM</code>. Upon success,
+ * the pointed at sockaddr_un is filled in and the pointed at
+ * socklen_t is set to indicate the final length. This function
+ * will fail if the namespace is invalid (not one of the indicated
+ * constants) or if the name is too long.
+ * 
+ * @return 0 on success or -1 on failure
+ */ 
+int socket_make_sockaddr_un(const char *name, int namespaceId, 
+        struct sockaddr_un *p_addr, socklen_t *alen);
+
+#endif
diff --git a/src/devtools/adb_tcp/socket_local_client.c b/src/devtools/adb_tcp/socket_local_client.c
new file mode 100644
index 0000000..ddcc2da
--- /dev/null
+++ b/src/devtools/adb_tcp/socket_local_client.c
@@ -0,0 +1,168 @@
+/*
+ * 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.
+ */
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <cutils/sockets.h>
+
+#ifdef HAVE_WINSOCK
+
+int socket_local_client(const char *name, int namespaceId, int type)
+{
+    errno = ENOSYS;
+    return -1;
+}
+
+#else /* !HAVE_WINSOCK */
+
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/select.h>
+#include <sys/types.h>
+
+#include "socket_local.h"
+
+#define UNUSED __attribute__((unused))
+
+#define LISTEN_BACKLOG 4
+
+/* Documented in header file. */
+int socket_make_sockaddr_un(const char *name, int namespaceId, 
+        struct sockaddr_un *p_addr, socklen_t *alen)
+{
+    memset (p_addr, 0, sizeof (*p_addr));
+    size_t namelen;
+
+    switch (namespaceId) {
+        case ANDROID_SOCKET_NAMESPACE_ABSTRACT:
+#ifdef HAVE_LINUX_LOCAL_SOCKET_NAMESPACE
+            namelen  = strlen(name);
+
+            // Test with length +1 for the *initial* '\0'.
+            if ((namelen + 1) > sizeof(p_addr->sun_path)) {
+                goto error;
+            }
+
+            /*
+             * Note: The path in this case is *not* supposed to be
+             * '\0'-terminated. ("man 7 unix" for the gory details.)
+             */
+            
+            p_addr->sun_path[0] = 0;
+            memcpy(p_addr->sun_path + 1, name, namelen);
+#else /*HAVE_LINUX_LOCAL_SOCKET_NAMESPACE*/
+            /* this OS doesn't have the Linux abstract namespace */
+
+            namelen = strlen(name) + strlen(FILESYSTEM_SOCKET_PREFIX);
+            /* unix_path_max appears to be missing on linux */
+            if (namelen > sizeof(*p_addr) 
+                    - offsetof(struct sockaddr_un, sun_path) - 1) {
+                goto error;
+            }
+
+            strcpy(p_addr->sun_path, FILESYSTEM_SOCKET_PREFIX);
+            strcat(p_addr->sun_path, name);
+#endif /*HAVE_LINUX_LOCAL_SOCKET_NAMESPACE*/
+        break;
+
+        case ANDROID_SOCKET_NAMESPACE_RESERVED:
+            namelen = strlen(name) + strlen(ANDROID_RESERVED_SOCKET_PREFIX);
+            /* unix_path_max appears to be missing on linux */
+            if (namelen > sizeof(*p_addr) 
+                    - offsetof(struct sockaddr_un, sun_path) - 1) {
+                goto error;
+            }
+
+            strcpy(p_addr->sun_path, ANDROID_RESERVED_SOCKET_PREFIX);
+            strcat(p_addr->sun_path, name);
+        break;
+
+        case ANDROID_SOCKET_NAMESPACE_FILESYSTEM:
+            namelen = strlen(name);
+            /* unix_path_max appears to be missing on linux */
+            if (namelen > sizeof(*p_addr) 
+                    - offsetof(struct sockaddr_un, sun_path) - 1) {
+                goto error;
+            }
+
+            strcpy(p_addr->sun_path, name);
+        break;
+        default:
+            // invalid namespace id
+            return -1;
+    }
+
+    p_addr->sun_family = AF_LOCAL;
+    *alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;
+    return 0;
+error:
+    return -1;
+}
+
+/**
+ * connect to peer named "name" on fd
+ * returns same fd or -1 on error.
+ * fd is not closed on error. that's your job.
+ * 
+ * Used by AndroidSocketImpl
+ */
+int socket_local_client_connect(int fd, const char *name, int namespaceId, 
+        int type UNUSED)
+{
+    struct sockaddr_un addr;
+    socklen_t alen;
+    int err;
+
+    err = socket_make_sockaddr_un(name, namespaceId, &addr, &alen);
+
+    if (err < 0) {
+        goto error;
+    }
+
+    if(connect(fd, (struct sockaddr *) &addr, alen) < 0) {
+        goto error;
+    }
+
+    return fd;
+
+error:
+    return -1;
+}
+
+/** 
+ * connect to peer named "name"
+ * returns fd or -1 on error
+ */
+int socket_local_client(const char *name, int namespaceId, int type)
+{
+    int s;
+
+    s = socket(AF_LOCAL, type, 0);
+    if(s < 0) return -1;
+
+    if ( 0 > socket_local_client_connect(s, name, namespaceId, type)) {
+        close(s);
+        return -1;
+    }
+
+    return s;
+}
+
+#endif /* !HAVE_WINSOCK */
diff --git a/src/devtools/adb_tcp/socket_local_server.c b/src/devtools/adb_tcp/socket_local_server.c
new file mode 100644
index 0000000..7628fe4
--- /dev/null
+++ b/src/devtools/adb_tcp/socket_local_server.c
@@ -0,0 +1,126 @@
+/* libs/cutils/socket_local_server.c
+**
+** Copyright 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.
+*/
+
+#include <cutils/sockets.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stddef.h>
+
+#ifdef HAVE_WINSOCK
+
+int socket_local_server(const char *name, int namespaceId, int type)
+{
+    errno = ENOSYS;
+    return -1;
+}
+
+#else /* !HAVE_WINSOCK */
+
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+
+#include "socket_local.h"
+
+#define LISTEN_BACKLOG 4
+
+/* Only the bottom bits are really the socket type; there are flags too. */
+#define SOCK_TYPE_MASK 0xf
+
+/**
+ * Binds a pre-created socket(AF_LOCAL) 's' to 'name'
+ * returns 's' on success, -1 on fail
+ *
+ * Does not call listen()
+ */
+int socket_local_server_bind(int s, const char *name, int namespaceId)
+{
+    struct sockaddr_un addr;
+    socklen_t alen;
+    int n;
+    int err;
+
+    err = socket_make_sockaddr_un(name, namespaceId, &addr, &alen);
+
+    if (err < 0) {
+        return -1;
+    }
+
+    /* basically: if this is a filesystem path, unlink first */
+#ifndef HAVE_LINUX_LOCAL_SOCKET_NAMESPACE
+    if (1) {
+#else
+    if (namespaceId == ANDROID_SOCKET_NAMESPACE_RESERVED
+        || namespaceId == ANDROID_SOCKET_NAMESPACE_FILESYSTEM) {
+#endif
+        /*ignore ENOENT*/
+        unlink(addr.sun_path);
+    }
+
+    n = 1;
+    setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
+
+    if(bind(s, (struct sockaddr *) &addr, alen) < 0) {
+        return -1;
+    }
+
+    return s;
+
+}
+
+
+/** Open a server-side UNIX domain datagram socket in the Linux non-filesystem 
+ *  namespace
+ *
+ *  Returns fd on success, -1 on fail
+ */
+
+int socket_local_server(const char *name, int namespace, int type)
+{
+    int err;
+    int s;
+    
+    s = socket(AF_LOCAL, type, 0);
+    if (s < 0) return -1;
+
+    err = socket_local_server_bind(s, name, namespace);
+
+    if (err < 0) {
+        close(s);
+        return -1;
+    }
+
+    if ((type & SOCK_TYPE_MASK) == SOCK_STREAM) {
+        int ret;
+
+        ret = listen(s, LISTEN_BACKLOG);
+
+        if (ret < 0) {
+            close(s);
+            return -1;
+        }
+    }
+
+    return s;
+}
+
+#endif /* !HAVE_WINSOCK */
diff --git a/src/devtools/adb_tcp/socket_loopback_client.c b/src/devtools/adb_tcp/socket_loopback_client.c
new file mode 100644
index 0000000..9aed7b7
--- /dev/null
+++ b/src/devtools/adb_tcp/socket_loopback_client.c
@@ -0,0 +1,57 @@
+/*
+** Copyright 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.
+*/
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifndef HAVE_WINSOCK
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#endif
+
+#include <cutils/sockets.h>
+
+/* Connect to port on the loopback IP interface. type is
+ * SOCK_STREAM or SOCK_DGRAM. 
+ * return is a file descriptor or -1 on error
+ */
+int socket_loopback_client(int port, int type)
+{
+    struct sockaddr_in addr;
+    int s;
+
+    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 < 0) return -1;
+
+    if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+        close(s);
+        return -1;
+    }
+
+    return s;
+
+}
+
diff --git a/src/devtools/adb_tcp/socket_loopback_server.c b/src/devtools/adb_tcp/socket_loopback_server.c
new file mode 100644
index 0000000..71afce7
--- /dev/null
+++ b/src/devtools/adb_tcp/socket_loopback_server.c
@@ -0,0 +1,69 @@
+/*
+** Copyright 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.
+*/
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define LISTEN_BACKLOG 4
+
+#ifndef HAVE_WINSOCK
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#endif
+
+#include <cutils/sockets.h>
+
+/* open listen() port on loopback interface */
+int socket_loopback_server(int port, int type)
+{
+    struct sockaddr_in addr;
+    int s, n;
+
+    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 < 0) return -1;
+
+    n = 1;
+    setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *) &n, sizeof(n));
+
+    if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+        close(s);
+        return -1;
+    }
+
+    if (type == SOCK_STREAM) {
+        int ret;
+
+        ret = listen(s, LISTEN_BACKLOG);
+
+        if (ret < 0) {
+            close(s);
+            return -1; 
+        }
+    }
+
+    return s;
+}
+
diff --git a/src/devtools/adb_tcp/socket_network_client.c b/src/devtools/adb_tcp/socket_network_client.c
new file mode 100644
index 0000000..4826033
--- /dev/null
+++ b/src/devtools/adb_tcp/socket_network_client.c
@@ -0,0 +1,126 @@
+/*
+** Copyright 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.
+*/
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include <cutils/sockets.h>
+
+/* Connect to port on the IP interface. type is
+ * SOCK_STREAM or SOCK_DGRAM. 
+ * return is a file descriptor or -1 on error
+ */
+int socket_network_client(const char *host, int port, int type)
+{
+    return socket_network_client_timeout(host, port, type, 0);
+}
+
+/* Connect to port on the IP interface. type is SOCK_STREAM or SOCK_DGRAM.
+ * timeout in seconds return is a file descriptor or -1 on error
+ */
+int socket_network_client_timeout(const char *host, int port, int type, int timeout)
+{
+    struct hostent *hp;
+    struct sockaddr_in addr;
+    socklen_t alen;
+    int s;
+    int flags = 0, error = 0, ret = 0;
+    fd_set rset, wset;
+    socklen_t len = sizeof(error);
+    struct timeval ts;
+
+    ts.tv_sec = timeout;
+    ts.tv_usec = 0;
+
+    hp = gethostbyname(host);
+    if (hp == 0) 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 < 0) return -1;
+
+    if ((flags = fcntl(s, F_GETFL, 0)) < 0) {
+        close(s);
+        return -1;
+    }
+
+    if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) {
+        close(s);
+        return -1;
+    }
+
+    if ((ret = connect(s, (struct sockaddr *) &addr, sizeof(addr))) < 0) {
+        if (errno != EINPROGRESS) {
+            close(s);
+            return -1;
+        }
+    }
+
+    if (ret == 0)
+        goto done;
+
+    FD_ZERO(&rset);
+    FD_SET(s, &rset);
+    wset = rset;
+
+    if ((ret = select(s + 1, &rset, &wset, NULL, (timeout) ? &ts : NULL)) < 0) {
+        close(s);
+        return -1;
+    }
+    if (ret == 0) {   // we had a timeout
+        errno = ETIMEDOUT;
+        close(s);
+        return -1;
+    }
+
+    if (FD_ISSET(s, &rset) || FD_ISSET(s, &wset)) {
+        if (getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
+            close(s);
+            return -1;
+        }
+    } else {
+        close(s);
+        return -1;
+    }
+
+    if (error) {  // check if we had a socket error
+        errno = error;
+        close(s);
+        return -1;
+    }
+
+done:
+    if (fcntl(s, F_SETFL, flags) < 0) {
+        close(s);
+        return -1;
+    }
+
+    return s;
+}
diff --git a/src/devtools/adb_tcp/sockets.c b/src/devtools/adb_tcp/sockets.c
new file mode 100644
index 0000000..3c2773c
--- /dev/null
+++ b/src/devtools/adb_tcp/sockets.c
@@ -0,0 +1,918 @@
+/*
+ * 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"
+
+#if !ADB_HOST
+#include <cutils/properties.h>
+#endif
+
+#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,
+};
+
+// Parse the global list of sockets to find one with id |local_id|.
+// If |peer_id| is not 0, also check that it is connected to a peer
+// with id |peer_id|. Returns an asocket handle on success, NULL on failure.
+asocket *find_local_socket(unsigned local_id, unsigned peer_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 != local_id)
+            continue;
+        if (peer_id == 0 || (s->peer && s->peer->id == peer_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++;
+
+    // Socket ids should never be 0.
+    if (local_socket_next_id == 0)
+      local_socket_next_id = 1;
+
+    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);
+        /* Note: it's important to call shutdown before disconnecting from
+         * the peer, this ensures that remote sockets can still get the id
+         * of the local socket they're connected to, to send a CLOSE()
+         * protocol event. */
+        if (s->peer->shutdown)
+          s->peer->shutdown(s->peer);
+        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=%zu\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->shutdown = NULL;
+    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
+    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;
+
+    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))
+        property_get("ro.debuggable", debug, "");
+
+    if ((!strncmp(name, "root:", 5) && getuid() != 0
+        && strcmp(debug, "1") == 0)
+        || !strncmp(name, "usb:", 4)
+        || !strncmp(name, "tcpip:", 6)
+	|| !strncmp(name, "reconnect:", 10)) {
+        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_shutdown(asocket *s)
+{
+    D("entered remote_socket_shutdown 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;
+    }
+    p->msg.arg1 = s->id;
+    send_packet(p, s->transport);
+}
+
+static void remote_socket_close(asocket *s)
+{
+    if (s->peer) {
+        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);
+    }
+    D("entered remote_socket_close RS(%d) CLOSE fd=%d peer->fd=%d\n",
+      s->id, s->fd, s->peer?s->peer->fd:-1);
+    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);
+}
+
+/* Create an asocket to exchange packets with a remote service through transport
+  |t|. Where |id| is the socket id of the corresponding service on the other
+   side of the transport (it is allocated by the remote side and _cannot_ be 0).
+   Returns a new non-NULL asocket handle. */
+asocket *create_remote_socket(unsigned id, atransport *t)
+{
+    asocket* s;
+    adisconnect* dis;
+
+    if (id == 0) fatal("invalid remote socket id (0)");
+    s = calloc(1, sizeof(aremotesocket));
+    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->shutdown = remote_socket_shutdown;
+    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->shutdown = NULL;
+    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->shutdown = NULL;
+    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->shutdown = NULL;
+        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->shutdown = NULL;
+    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);
+}
+
+static asocket *create_smart_socket(void)
+{
+    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->shutdown = NULL;
+    s->close = smart_socket_close;
+
+    D("SS(%d)\n", s->id);
+    return s;
+}
+
+void connect_to_smartsocket(asocket *s)
+{
+    D("Connecting to smart socket \n");
+    asocket *ss = create_smart_socket();
+    s->peer = ss;
+    ss->peer = s;
+    s->ready(s);
+}
diff --git a/src/devtools/adb_tcp/sysdeps.h b/src/devtools/adb_tcp/sysdeps.h
new file mode 100644
index 0000000..cc1f839
--- /dev/null
+++ b/src/devtools/adb_tcp/sysdeps.h
@@ -0,0 +1,524 @@
+/*
+ * 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 <winsock2.h>
+#include <windows.h>
+#include <ws2tcpip.h>
+#include <process.h>
+#include <fcntl.h>
+#include <io.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <ctype.h>
+#include <direct.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_network_client_timeout(const char *host, int port, int type,
+                                         int timeout);
+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/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 */
diff --git a/src/devtools/adb_tcp/sysdeps_win32.c b/src/devtools/adb_tcp/sysdeps_win32.c
new file mode 100644
index 0000000..b082c6d
--- /dev/null
+++ b/src/devtools/adb_tcp/sysdeps_win32.c
@@ -0,0 +1,2227 @@
+#include "sysdeps.h"
+#include <winsock2.h>
+#include <windows.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_network_client_timeout(const char *host, int port, int type, int timeout)
+{
+    // TODO: implement timeouts for Windows.
+    return socket_network_client(host, port, type);
+}
+
+
+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   = (const char *)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   = (char *)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", (int)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 */
+}
diff --git a/src/devtools/adb_tcp/test_track_devices.c b/src/devtools/adb_tcp/test_track_devices.c
new file mode 100644
index 0000000..77b3ad9
--- /dev/null
+++ b/src/devtools/adb_tcp/test_track_devices.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 = "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);
+}
diff --git a/src/devtools/adb_tcp/test_track_jdwp.c b/src/devtools/adb_tcp/test_track_jdwp.c
new file mode 100644
index 0000000..8ecc6b8
--- /dev/null
+++ b/src/devtools/adb_tcp/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_tcp/thread_utils.c b/src/devtools/adb_tcp/thread_utils.c
new file mode 100644
index 0000000..6f4cd3c
--- /dev/null
+++ b/src/devtools/adb_tcp/thread_utils.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2013 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 "thread_utils.h"
+
+#if defined(__APPLE__)
+
+#include <sys/syscall.h>
+
+// Mac OS >= 10.6 has a system call equivalent to Linux's gettid().
+pid_t gettid() {
+  return syscall(SYS_thread_selfid);
+}
+
+#elif !defined(__BIONIC__)
+
+// glibc doesn't implement or export either gettid or tgkill.
+#include <unistd.h>
+#include <sys/syscall.h>
+
+pid_t gettid() {
+  return syscall(__NR_gettid);
+}
+
+int tgkill(int tgid, int tid, int sig) {
+  return syscall(__NR_tgkill, tgid, tid, sig);
+}
+
+#endif
diff --git a/src/devtools/adb_tcp/thread_utils.h b/src/devtools/adb_tcp/thread_utils.h
new file mode 100644
index 0000000..ae4c929
--- /dev/null
+++ b/src/devtools/adb_tcp/thread_utils.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2013 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 _LIBBACKTRACE_THREAD_UTILS_H
+#define _LIBBACKTRACE_THREAD_UTILS_H
+
+#include <unistd.h>
+
+__BEGIN_DECLS
+
+int tgkill(int tgid, int tid, int sig);
+
+pid_t gettid();
+
+__END_DECLS
+
+#endif /* _LIBBACKTRACE_THREAD_UTILS_H */
diff --git a/src/devtools/adb_tcp/transport.c b/src/devtools/adb_tcp/transport.c
new file mode 100644
index 0000000..dbba5aa
--- /dev/null
+++ b/src/devtools/adb_tcp/transport.c
@@ -0,0 +1,1269 @@
+/*
+ * 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,
+};
+
+static atransport pending_list = {
+    .next = &pending_list,
+    .prev = &pending_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");
+        }
+    }
+
+    adb_mutex_lock(&transport_lock);
+    /* remove from pending list */
+    t->next->prev = t->prev;
+    t->prev->next = t->next;
+    /* put us on the master device list */
+    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) {
+        if (result->connection_state == CS_UNAUTHORIZED) {
+            if (error_out)
+                *error_out = "device unauthorized. Please check the confirmation dialog on your device.";
+            result = NULL;
+        }
+
+         /* 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";
+    case CS_UNAUTHORIZED: return "unauthorized";
+    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
+
+int register_socket_transport(int s, const char *serial, int port, int local)
+{
+    atransport *t = calloc(1, sizeof(atransport));
+    atransport *n;
+    char buff[32];
+
+    if (t == 0) {
+        fatal("cannot allocate atransport");
+        return -1;
+    }
+    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) {
+        free(t);
+        return -1;
+    }
+
+    adb_mutex_lock(&transport_lock);
+    for (n = pending_list.next; n != &pending_list; n = n->next) {
+        if (n->serial && !strcmp(serial, n->serial) && n->sfd == s) {
+            adb_mutex_unlock(&transport_lock);
+            free(t);
+            return -1;
+        }
+    }
+
+    for (n = transport_list.next; n != &transport_list; n = n->next) {
+        if (n->serial && !strcmp(serial, n->serial) && n->sfd == s) {
+            adb_mutex_unlock(&transport_lock);
+            free(t);
+            return -1;
+        }
+    }
+
+    t->next = &pending_list;
+    t->prev = pending_list.prev;
+    t->next->prev = t;
+    t->prev->next = t;
+    t->serial = strdup(serial);
+    adb_mutex_unlock(&transport_lock);
+
+    register_transport(t);
+    return 0;
+}
+
+#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
+
+#if (ADB_OVER_PCIE)
+void register_pcie_transport(struct pcie_handle *pcie, const char *devpath, unsigned writeable)
+{
+    atransport *t = calloc(1, sizeof(atransport));
+    if (t == 0) {
+        fatal("cannot allocate atransport");
+        return;
+    }
+    init_pcie_transport(t, pcie, devpath, (writeable ? CS_OFFLINE : CS_NOPERM));
+
+    if(devpath) {
+        t->devpath = strdup(devpath);
+    }
+
+    adb_mutex_lock(&transport_lock);
+    t->next = &pending_list;
+    t->prev = pending_list.prev;
+    t->next->prev = t;
+    t->prev->next = t;
+    adb_mutex_unlock(&transport_lock);
+
+    register_transport(t);
+}
+#else
+void register_usb_transport(usb_handle *usb, const char *serial, const char *devpath, unsigned writeable)
+{
+    atransport *t = calloc(1, sizeof(atransport));
+    if (t == 0) {
+        fatal("cannot allocate atransport");
+        return;
+    }
+    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);
+    }
+
+    adb_mutex_lock(&transport_lock);
+    t->next = &pending_list;
+    t->prev = pending_list.prev;
+    t->next->prev = t;
+    t->prev->next = t;
+    adb_mutex_unlock(&transport_lock);
+
+    register_transport(t);
+}
+#endif
+
+/* 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
+    size_t len0 = len;
+#endif
+    D("readx: fd=%d wanted=%zu\n", fd, 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=%zu got=%zu\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;
+                if (errno == EAGAIN) {
+                    adb_sleep_ms(1); // just yield some cpu time
+                    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;
+    }
+}
diff --git a/src/devtools/adb_tcp/transport.h b/src/devtools/adb_tcp/transport.h
new file mode 100644
index 0000000..992e052
--- /dev/null
+++ b/src/devtools/adb_tcp/transport.h
@@ -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 */
diff --git a/src/devtools/adb_tcp/transport_local.c b/src/devtools/adb_tcp/transport_local.c
new file mode 100644
index 0000000..1f9a1e4
--- /dev/null
+++ b/src/devtools/adb_tcp/transport_local.c
@@ -0,0 +1,446 @@
+/*
+ * 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>
+#if !ADB_HOST
+#include <cutils/properties.h>
+#endif
+
+#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  64
+
+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) (uintptr_t) 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 && !ADB_NON_ANDROID
+/*
+ * 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 <hardware/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) (uintptr_t) 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;
+#elif ADB_NON_ANDROID
+        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 *) (uintptr_t) 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;
+}
diff --git a/src/devtools/adb_tcp/transport_pcie.c b/src/devtools/adb_tcp/transport_pcie.c
new file mode 100644
index 0000000..d677587
--- /dev/null
+++ b/src/devtools/adb_tcp/transport_pcie.c
@@ -0,0 +1,230 @@
+/*
+ * 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>
+#include "transport_pcie.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);
+}
+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)
+{
+	struct pcie_handle *pcie = t->pcie;
+
+	if(unix_read(pcie->fd, &p->msg, sizeof(amessage)) < 0){
+		D("remote pcie: read terminated (message)\n");
+		return -1;
+	}
+
+	fix_endians(p);
+
+	if(check_header(p)) {
+		D("remote pcie: check_header failed\n");
+		return -1;
+	}
+
+	if(p->msg.data_length) {
+		if(unix_read(pcie->fd, p->data, p->msg.data_length) < 0){
+			D("remote pcie: terminated (data)\n");
+			return -1;
+		}
+	}
+
+	if(check_data(p)) {
+		D("remote pcie: check_data failed\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int remote_write(apacket *p, atransport *t)
+{
+    unsigned size = p->msg.data_length;
+	struct pcie_handle *pcie = t->pcie;
+
+    fix_endians(p);
+
+    if(unix_write(pcie->fd, &p->msg, sizeof(amessage)) < 0) {
+        D("remote pcie: 1 - write terminated\n");
+        return -1;
+    }
+
+    if(p->msg.data_length == 0)
+	return 0;
+
+    if(unix_write(pcie->fd, p->data, size) < 0) {
+        D("remote pcie: 2 - write terminated\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+static void remote_close(atransport *t)
+{
+    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)
+		pcie->kick(pcie);
+}
+
+void init_pcie_transport(atransport *t, struct pcie_handle *h, const char *devpath, int state)
+{
+    static char *pcie_unknow = "0123456mediatek";
+    D("transport: pcie\n");
+    /* On host side, we need open the file here */
+    if (h->fd < 0)
+	    h->fd = unix_open(devpath, O_RDWR);
+
+    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->pcie = h;
+
+    /* Device information */
+    t->serial = pcie_unknow;
+    t->device = pcie_unknow;
+    t->product = pcie_unknow;
+
+#if ADB_HOST
+    HOST = 1;
+#else
+    HOST = 0;
+#endif
+}
+
+#if ADB_HOST
+void pcie_host_init(void)
+{
+	struct pcie_handle *pcie;
+
+	pcie = calloc(1, sizeof(*pcie));
+
+	pcie->fd = unix_open(PCIE_ADB_PATH, O_RDWR);
+
+	register_pcie_transport(pcie, PCIE_ADB_PATH, 1);
+}
+
+#else
+/* For ADBD */
+static void *pcie_open_thread(void *x)
+{
+	struct pcie_handle *pcie = (struct pcie_handle *)x;
+	int fd = -1;
+	char *banner = "Start PCIe port\n";
+
+	while (1) {
+		adb_mutex_lock(&pcie->lock);
+		while (pcie->fd != -1)
+			adb_cond_wait(&pcie->notify, &pcie->lock);
+		adb_mutex_unlock(&pcie->lock);
+
+		do {
+			fd = unix_open(PCIE_ADB_PATH, O_RDWR);
+			if (fd < 0) {
+				adb_sleep_ms(1000);
+			}
+		} while (fd < 0);
+
+		pcie->fd = fd;
+		adb_write(fd, banner, strlen(banner));
+
+		/* Get PCIe config information */
+		fd = unix_open(PCIE_INFO_ADB_PATH, O_RDONLY);
+		if (fd > 0) {
+			pcie->info = calloc(1, sizeof(struct pcie_info));
+			if (pcie->info)
+				unix_read(fd, pcie->info, sizeof(pcie->info));
+
+			unix_close(fd);
+		}
+
+		register_pcie_transport(pcie, PCIE_ADB_PATH, 1);
+	}
+
+	// never gets here
+	return 0;
+}
+
+static void pcie_adbd_kick(struct pcie_handle *h)
+{
+	adb_mutex_lock(&h->lock);
+	unix_close(h->fd);
+	h->fd = -1;
+
+	adb_cond_signal(&h->notify);
+	adb_mutex_unlock(&h->lock);
+}
+
+void pcie_init(void)
+{
+    adb_thread_t tid;
+    struct pcie_handle *h;
+
+    h = calloc(1, sizeof(*h));
+
+    h->kick = pcie_adbd_kick;
+    h->fd = -1;
+
+    adb_cond_init(&h->notify, 0);
+    adb_mutex_init(&h->lock, 0);
+
+    D("[ pcie_init - starting thread ]\n");
+    if (adb_thread_create(&tid, pcie_open_thread, h)) {
+        fatal_errno("[ cannot create pcie thread ]\n");
+    }
+}
+#endif
diff --git a/src/devtools/adb_tcp/transport_pcie.h b/src/devtools/adb_tcp/transport_pcie.h
new file mode 100644
index 0000000..8c33ae0
--- /dev/null
+++ b/src/devtools/adb_tcp/transport_pcie.h
@@ -0,0 +1,26 @@
+#ifndef __TRANSPORT_PCIE__H
+#define __TRANSPORT_PCIE__H
+
+#include "fdevent.h"
+#include "adb.h"
+#include "sysdeps.h"
+
+struct pcie_info {
+	unsigned short device;
+	unsigned short vendor;
+	unsigned int class;
+};
+
+struct pcie_handle {
+	int fd;
+	struct pcie_info *info;
+
+	adb_cond_t notify;
+	adb_mutex_t lock;
+
+	int (*write)(struct pcie_handle *h, const void *data, int len);
+	int (*read)(struct pcie_handle *h, void *data, int len);
+	void (*kick)(struct pcie_handle *h);
+};
+
+#endif
diff --git a/src/devtools/adb_tcp/transport_usb.c b/src/devtools/adb_tcp/transport_usb.c
new file mode 100644
index 0000000..3d19803
--- /dev/null
+++ b/src/devtools/adb_tcp/transport_usb.c
@@ -0,0 +1,132 @@
+/*
+ * 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"
+
+#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)
+{
+    return (usb_class == ADB_CLASS && usb_subclass == ADB_SUBCLASS && usb_protocol == ADB_PROTOCOL);
+}
+#endif
diff --git a/src/devtools/adb_tcp/usb_libusb.c b/src/devtools/adb_tcp/usb_libusb.c
new file mode 100644
index 0000000..06ff5dc
--- /dev/null
+++ b/src/devtools/adb_tcp/usb_libusb.c
@@ -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");
+}
+
diff --git a/src/devtools/adb_tcp/usb_linux.c b/src/devtools/adb_tcp/usb_linux.c
new file mode 100644
index 0000000..f16bdd0
--- /dev/null
+++ b/src/devtools/adb_tcp/usb_linux.c
@@ -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 | O_CLOEXEC)) < 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 %zu 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 | O_CLOEXEC);
+    if(usb->desc < 0) {
+        /* if we fail, see if have read-only access */
+        usb->desc = unix_open(usb->fname, O_RDONLY | O_CLOEXEC);
+        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");
+    }
+}
diff --git a/src/devtools/adb_tcp/usb_linux_client.c b/src/devtools/adb_tcp/usb_linux_client.c
new file mode 100644
index 0000000..2466275
--- /dev/null
+++ b/src/devtools/adb_tcp/usb_linux_client.c
@@ -0,0 +1,744 @@
+/*
+ * 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 <stddef.h>
+#include <sys/epoll.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 MAX_PACKET_SIZE_SS	1024
+
+//#define cpu_to_le16(x)  htole16(x)
+//#define cpu_to_le32(x)  htole32(x)
+/*
+ * cpu_to_le16/32 are used when initializing structures, a context where a
+ * function call is not allowed. To solve this, we code cpu_to_le16/32 in a way
+ * that allows them to be used when initializing structures.
+ */
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define cpu_to_le16(x)  (x)
+#define cpu_to_le32(x)  (x)
+#else
+#define cpu_to_le16(x)  ((((x) >> 8) & 0xffu) | (((x) & 0xffu) << 8))
+#define cpu_to_le32(x)  \
+    ((((x) & 0xff000000u) >> 24) | (((x) & 0x00ff0000u) >>  8) | \
+    (((x) & 0x0000ff00u) <<  8) | (((x) & 0x000000ffu) << 24))
+#endif
+
+#define FFS_CONTOL_MAX_EPOLL_EVENT 50
+#define DEBUG   0
+
+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 */
+    bool ffs_control_thread_created;
+};
+
+static const struct {
+    __le32 magic;
+    __le32 length;
+    __le32 flags;
+    __le32 fs_count;
+    __le32 hs_count;
+    __le32 ss_count;
+    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;
+    struct {
+        struct usb_interface_descriptor intf;
+        struct usb_endpoint_descriptor_no_audio source;
+        struct usb_ss_ep_comp_descriptor source_comp;
+        struct usb_endpoint_descriptor_no_audio sink;
+        struct usb_ss_ep_comp_descriptor sink_comp;
+    } __attribute__((packed)) ss_descs;
+} __attribute__((packed)) descriptors = {
+    .magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
+    .length = cpu_to_le32(sizeof(descriptors)),
+    .flags = cpu_to_le32(FUNCTIONFS_HAS_FS_DESC |
+                         FUNCTIONFS_HAS_HS_DESC |
+                         FUNCTIONFS_HAS_SS_DESC),
+    .fs_count = 3,
+    .hs_count = 3,
+    .ss_count = 5,
+    .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,
+        },
+    },
+    .ss_descs = {
+        .intf = {
+            .bLength = sizeof(descriptors.ss_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.ss_descs.source),
+            .bDescriptorType = USB_DT_ENDPOINT,
+            .bEndpointAddress = 1 | USB_DIR_OUT,
+            .bmAttributes = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize = MAX_PACKET_SIZE_SS,
+        },
+        .source_comp = {
+            .bLength = sizeof(descriptors.ss_descs.source_comp),
+            .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+        },
+        .sink = {
+            .bLength = sizeof(descriptors.ss_descs.sink),
+            .bDescriptorType = USB_DT_ENDPOINT,
+            .bEndpointAddress = 2 | USB_DIR_IN,
+            .bmAttributes = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize = MAX_PACKET_SIZE_SS,
+        },
+        .sink_comp = {
+            .bLength = sizeof(descriptors.ss_descs.sink_comp),
+            .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+        },
+    },
+};
+
+#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));
+    if (h == 0) {
+        fatal("cannot allocate usb_handle");
+        return;
+    }
+
+    h->write = usb_adb_write;
+    h->read = usb_adb_read;
+    h->kick = usb_adb_kick;
+    h->bulk_in = -1;
+    h->bulk_out = -1;
+    h->control = -1;
+    h->ffs_control_thread_created = false;
+    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 *ffs_control_read_msg_thread(void *_h)
+{
+    usb_handle *h = _h;
+    int fd = h->control;
+
+    char buf[MAX_PACKET_SIZE_FS];
+    int size = 0;//event.u.setup.wLength;
+    if (DEBUG) D("FUNCTIONFS_SETUP acking host-to-device control transfer size=%d", size);
+    if (size+1 > MAX_PACKET_SIZE_FS) {
+        D("package size larger than MAX_PACKET_SIZE_FS");
+        return 0;
+    }
+
+    if (DEBUG) D("FUNCTIONFS_SETUP before get host-to-device msg size:%d", size);
+    int rc = adb_read(fd, buf, size);
+    if (DEBUG) D("FUNCTIONFS_SETUP after get host-to-device msg rc:%d", rc);
+    if (rc != size) {
+        D("Read %d bytes when trying to read control request, expected %d", rc, size);
+    }
+    return 0;
+}
+
+static char* ffs_get_event_type_code(int type) {
+    char* code;
+    switch(type) {
+        case FUNCTIONFS_BIND:
+            code = "BIND";
+            break;
+        case FUNCTIONFS_UNBIND:
+            code = "UNBIND";
+            break;
+        case FUNCTIONFS_ENABLE:
+            code = "ENABLE";
+            break;
+        case FUNCTIONFS_DISABLE:
+            code = "DISABLE";
+            break;
+        case FUNCTIONFS_SETUP:
+            code = "SETUP";
+            break;
+        case FUNCTIONFS_SUSPEND:
+            code = "SUSPEND";
+            break;
+        case FUNCTIONFS_RESUME:
+            code = "RESUME";
+            break;
+        default:
+            code = "UNKNOWN";
+            break;
+        }
+    return code;
+}
+
+static void ffs_control_event_handler(usb_handle *h) {
+    int fd = h->control;
+    struct usb_functionfs_event event;
+    int ret = 0;
+
+    if (DEBUG) D("start remote usb read control fd:%d size=%d\n", fd, (int)sizeof(event));
+    ret = adb_read(fd, &event, sizeof(event));
+    if (DEBUG) D("done remote usb read control ret=%d size=%d\n", ret, (int)sizeof(event));
+    if (ret != sizeof(event)) {
+        if (DEBUG) D("remote usb: read size:%d not expect to event size:%d\n", ret, (int)sizeof(event));
+        return;
+    }
+
+    D("event.type: %s\n", ffs_get_event_type_code(event.type));
+
+    switch (event.type) {
+        case FUNCTIONFS_SETUP: {
+            D("received FUNCTIONFS_SETUP");
+            D("bRequestType = %d",(int)(event.u.setup.bRequestType));
+            D("bRequest = %d\n", (int)(event.u.setup.bRequest));
+            D("wValue = %d\n", (int)(event.u.setup.wValue));
+            D("wIndex = %d\n", (int)(event.u.setup.wIndex));
+            D("wLength = %d\n", (int)(event.u.setup.wLength));
+
+            if ((event.u.setup.bRequestType & USB_DIR_IN)) {
+                if (DEBUG) D("FUNCTIONFS_SETUP acking device-to-host control transfer");
+                int rc = adb_write(fd, "", 0);
+                if (rc != 0) {
+                    D("Failed to write empty packet to host");
+                    break;
+                }
+            } else {
+                adb_thread_t ffs_control_read_msg_thread_ptr;
+
+                if(adb_thread_create(&ffs_control_read_msg_thread_ptr, ffs_control_read_msg_thread, h)) {
+                    fatal_errno("cannot create control thread");
+                }
+
+
+                if (DEBUG) D("Wait 100ms before kill read msg thread");
+                adb_sleep_ms(100);
+                int ret = pthread_cancel(ffs_control_read_msg_thread_ptr);
+                D("Done kill the read msg thread ret=%d", ret);
+            }
+        }
+    }
+}
+
+// -1 means failure
+static int epoll_add_fd(int epfd, int fd) {
+    struct epoll_event ev;
+    memset(&ev, 0, sizeof(ev));
+    ev.data.fd = fd;
+    ev.events = EPOLLIN;
+    // don't set the fd to edge trigger
+    // the some event like accept may be lost if two or more clients are connecting to server at the same time
+    // level trigger is preferred to avoid event lost
+    // do not set EPOLLOUT due to it will always trigger when write is available
+    if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
+        D("epoll_add_fd3() epoll_ctl() failed reason=[%s]%d epfd=%d fd=%d",
+            strerror(errno), errno, epfd, fd);
+        return -1;
+    }
+    return 0;
+}
+
+static void *ffs_control_thread(void *_h)
+{
+    usb_handle *h = _h;
+    int control_fd = h->control;
+    struct epoll_event events[FFS_CONTOL_MAX_EPOLL_EVENT];
+
+    int epfd = epoll_create(FFS_CONTOL_MAX_EPOLL_EVENT);
+    if(epfd == -1) {
+        D("ERR: epoll_create() fail reason=[%s]", strerror(errno));
+        return 0;
+    }
+
+    epoll_add_fd(epfd, control_fd);
+
+    while(1) {
+        int i;
+        int n;
+
+        D("Before ffs control thread epoll_wait");
+        n = epoll_wait(epfd, events, FFS_CONTOL_MAX_EPOLL_EVENT , -1);
+
+        for(i = 0; i < n; i++) {
+            if(events[i].data.fd == control_fd) {
+                if(events[i].events & EPOLLIN) {
+                    if (DEBUG) D("control_fd event triggered");
+                    ffs_control_event_handler(h);
+                }
+            }
+        }
+    }
+}
+
+void ffs_create_control_thread(usb_handle *h) {
+    if (h->control >= 0) {  // only for ffs usb
+        if (!h->ffs_control_thread_created) {
+            adb_thread_t ffs_control_thread_ptr;
+
+            if(adb_thread_create(&ffs_control_thread_ptr, ffs_control_thread, h)){
+                fatal_errno("cannot create ffs_control_thread");
+            } else {
+                h->ffs_control_thread_created = true;
+                if (DEBUG) D("Created ffs_control_thread success");
+            }
+        }
+    }
+}
+
+static void init_functionfs(struct usb_handle *h)
+{
+    ssize_t ret;
+
+    if (h->control < 0) { // might have already done this before
+        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;
+    }
+
+    ffs_create_control_thread(h);
+    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 && usb->bulk_in != -1 && usb->bulk_out != -1)
+            adb_cond_wait(&usb->notify, &usb->lock);
+        adb_mutex_unlock(&usb->lock);
+
+        while (1) {
+            init_functionfs(usb);
+
+            if (usb->control >= 0 && usb->bulk_in >= 0 && usb->bulk_out >= 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=%zu count=%zu ]\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);
+
+    // don't close ep0 here, since we may not need to reinitialize it with
+    // the same descriptors again. if however ep1/ep2 fail to re-open in
+    // init_functionfs, only then would we close and open ep0 again.
+    adb_close(h->bulk_out);
+    adb_close(h->bulk_in);
+    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));
+    if (h == 0) {
+        fatal("cannot allocate usb_handle");
+        return;
+    }
+
+    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;
+    h->ffs_control_thread_created = false;
+
+    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);
+}
diff --git a/src/devtools/adb_tcp/usb_osx.c b/src/devtools/adb_tcp/usb_osx.c
new file mode 100644
index 0000000..ba157f1
--- /dev/null
+++ b/src/devtools/adb_tcp/usb_osx.c
@@ -0,0 +1,531 @@
+/*
+ * 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"
+
+#define  DBG   D
+
+static IONotificationPortRef    notificationPort = 0;
+static io_iterator_t            notificationIterator;
+
+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;
+
+    //* 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);
+
+    //* 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;
+    }
+
+    //* We have to get notifications for all potential candidates and test them
+    //* at connection time because the matching rules don't allow for a
+    //* USB interface class of 0xff for class+subclass+protocol matches
+    //* See https://developer.apple.com/library/mac/qa/qa1076/_index.html
+    IOServiceAddMatchingNotification(
+            notificationPort,
+            kIOFirstMatchNotification,
+            matchingDict,
+            AndroidInterfaceAdded,
+            NULL,
+            &notificationIterator);
+
+    //* Iterate over set of matching interfaces to access already-present
+    //* devices and to arm the notification
+    AndroidInterfaceAdded(NULL, notificationIterator);
+
+    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;
+    UInt8                    class, subclass, protocol;
+    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;
+        }
+
+        kr = (*iface)->GetInterfaceClass(iface, &class);
+        kr = (*iface)->GetInterfaceSubClass(iface, &subclass);
+        kr = (*iface)->GetInterfaceProtocol(iface, &protocol);
+        if(class != ADB_CLASS || subclass != ADB_SUBCLASS || protocol != ADB_PROTOCOL) {
+            // Ignore non-ADB devices.
+            DBG("Ignoring interface with incorrect class/subclass/protocol - %d, %d, %d\n", class, subclass, protocol);
+            (*iface)->Release(iface);
+            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:%" PRIu32 "X",
+	             (unsigned int)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)
+{
+    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;
+
+    IOObjectRelease(notificationIterator);
+    IONotificationPortDestroy(notificationPort);
+
+    DBG("RunLoopThread done\n");
+    return NULL;    
+}
+
+
+static int initialized = 0;
+void usb_init()
+{
+    if (!initialized)
+    {
+        adb_thread_t    tid;
+
+        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);
+}
+
+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 (kIOUSBPipeStalled == result) {
+        DBG(" Pipe stalled, clearing stall.\n");
+        (*handle->interface)->ClearPipeStall(handle->interface, handle->bulkIn);
+        result = (*handle->interface)->ReadPipe(handle->interface, handle->bulkIn, buf, &numBytes);
+    }
+
+    if (kIOReturnSuccess == result)
+        return 0;
+    else {
+        DBG("ERR: usb_read failed with status %x\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;
+    }
+}
diff --git a/src/devtools/adb_tcp/usb_windows.c b/src/devtools/adb_tcp/usb_windows.c
new file mode 100644
index 0000000..b7ad913
--- /dev/null
+++ b/src/devtools/adb_tcp/usb_windows.c
@@ -0,0 +1,516 @@
+/*
+ * 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 <winsock2.h>
+#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,
+                                  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 = (char *)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);
+}