summaryrefslogtreecommitdiffstats
path: root/adb
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2008-12-17 18:08:08 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2008-12-17 18:08:08 -0800
commit35237d135807af84bf9b0e5b8d7f8633e58db6f5 (patch)
treed8bcf3ada2182d248604728285dd80abb466f22a /adb
parent4f6e8d7a00cbeda1e70cc15be9c4af1018bdad53 (diff)
downloadsystem_core-35237d135807af84bf9b0e5b8d7f8633e58db6f5.zip
system_core-35237d135807af84bf9b0e5b8d7f8633e58db6f5.tar.gz
system_core-35237d135807af84bf9b0e5b8d7f8633e58db6f5.tar.bz2
Code drop from //branches/cupcake/...@124589
Diffstat (limited to 'adb')
-rw-r--r--adb/Android.mk48
-rw-r--r--adb/OVERVIEW.TXT139
-rw-r--r--adb/SERVICES.TXT245
-rw-r--r--adb/adb.c108
-rw-r--r--adb/adb.h23
-rw-r--r--adb/adb_client.c26
-rw-r--r--adb/commandline.c56
-rw-r--r--adb/file_sync_client.c26
-rw-r--r--adb/file_sync_service.c6
-rw-r--r--adb/framebuffer_service.c9
-rw-r--r--adb/get_my_path_windows.c12
-rw-r--r--adb/jdwp_service.c4
-rw-r--r--adb/sockets.c162
-rw-r--r--adb/sysdeps_win32.c116
-rw-r--r--adb/transport_local.c15
-rw-r--r--adb/transport_usb.c12
-rw-r--r--adb/usb_linux_client.c2
-rw-r--r--adb/usb_osx.c22
-rw-r--r--adb/usb_windows.c18
-rw-r--r--adb/utils.c106
-rw-r--r--adb/utils.h68
21 files changed, 943 insertions, 280 deletions
diff --git a/adb/Android.mk b/adb/Android.mk
index 8ac5eb4..c06485f 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -7,6 +7,7 @@ LOCAL_PATH:= $(call my-dir)
# adb host tool
# =========================================================
+ifneq ($(TARGET_SIMULATOR),true) # not 64 bit clean (also unused with the sim)
include $(CLEAR_VARS)
# Default to a virtual (sockets) usb interface
@@ -29,7 +30,7 @@ ifeq ($(HOST_OS),windows)
USB_SRCS := usb_windows.c
EXTRA_SRCS := get_my_path_windows.c
EXTRA_STATIC_LIBS := AdbWinApi
- LOCAL_C_INCLUDES += /usr/include/w32api/ddk $(LOCAL_PATH)/../windows/usb/api
+ LOCAL_C_INCLUDES += /usr/include/w32api/ddk development/host/windows/usb/api/
ifneq ($(strip $(USE_CYGWIN)),)
LOCAL_LDLIBS += -lpthread
else
@@ -51,7 +52,8 @@ LOCAL_SRC_FILES := \
file_sync_client.c \
$(EXTRA_SRCS) \
$(USB_SRCS) \
- shlist.c
+ shlist.c \
+ utils.c \
ifneq ($(USE_SYSDEPS_WIN32),)
@@ -69,6 +71,8 @@ endif
include $(BUILD_HOST_EXECUTABLE)
+$(call dist-for-goals,droid,$(LOCAL_BUILT_MODULE))
+
ifeq ($(HOST_OS),windows)
$(LOCAL_INSTALLED_MODULE): $(HOST_OUT_EXECUTABLES)/AdbWinApi.dll
endif
@@ -81,10 +85,25 @@ LOCAL_MODULE := kdbg
include $(BUILD_HOST_EXECUTABLE)
endif
+endif
# adbd device daemon
# =========================================================
-ifeq ($(TARGET_ARCH),arm)
+
+# build adbd in all non-simulator builds
+BUILD_ADBD := false
+ifneq ($(TARGET_SIMULATOR),true)
+ BUILD_ADBD := true
+endif
+
+# build adbd for the Linux simulator build
+# so we can use it to test the adb USB gadget driver on x86
+ifeq ($(HOST_OS),linux)
+ BUILD_ADBD := true
+endif
+
+
+ifeq ($(BUILD_ADBD),true)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
@@ -99,18 +118,31 @@ LOCAL_SRC_FILES := \
framebuffer_service.c \
remount_service.c \
usb_linux_client.c \
- log_service.c
+ log_service.c \
+ utils.c \
-
-LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -DANDROID_GADGET=1 -Wall -Wno-unused-parameter
+LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter
LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
+
+# TODO: This should probably be board specific, whether or not the kernel has
+# the gadget driver; rather than relying on the architecture type.
+ifeq ($(TARGET_ARCH),arm)
+LOCAL_CFLAGS += -DANDROID_GADGET=1
+endif
+
LOCAL_MODULE := adbd
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)
LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)
-LOCAL_STATIC_LIBRARIES := libcutils libc
+ifeq ($(TARGET_SIMULATOR),true)
+ LOCAL_STATIC_LIBRARIES := libcutils
+ LOCAL_LDLIBS += -lpthread
+ include $(BUILD_HOST_EXECUTABLE)
+else
+ LOCAL_STATIC_LIBRARIES := libcutils libc
+ include $(BUILD_EXECUTABLE)
+endif
-include $(BUILD_EXECUTABLE)
endif
diff --git a/adb/OVERVIEW.TXT b/adb/OVERVIEW.TXT
new file mode 100644
index 0000000..6a5191a
--- /dev/null
+++ b/adb/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 succesfully
+ 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/adb/SERVICES.TXT b/adb/SERVICES.TXT
new file mode 100644
index 0000000..d059e18
--- /dev/null
+++ b/adb/SERVICES.TXT
@@ -0,0 +1,245 @@
+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
+ Ask to return the list of available Android devices and their
+ 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 therre 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-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.
+
+
+
+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)
+
+bootdebug:
+ Ask debugging information to the bootloader. The adbd daemon will
+ respond with FAIL to this request.
+
+bootloader:<command>
+ Send a request to the bootloader. This can also work if the device
+ is currently in the bootloader state. The adbd daemon will respond
+ with FAIL to such requests.
+
+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
+ priviledges 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.
+
+log:<name>
+ Opens one of the system logs (/dev/log/<name>) and allows the client
+ to read them directly. Used to implement 'adb logcat'. The stream
+ will be read-only for the client.
+
+framebuffer:
+ This service is used to send snapshots of the framebuffer to a client.
+ It requires sufficient priviledges 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 priviledges to open
+ the framebuffer device, the connection is simply closed immediately.
+
+dns:<server-name>
+ This service is an exception because it only runs within the ADB server.
+ It is used to implement USB networking, i.e. to provide a network connection
+ to the device through the host machine (note: this is the exact opposite of
+ network thetering).
+
+ It is used to perform a gethostbyname(<address>) on the host and return
+ the corresponding IP address as a 4-byte string.
+
+recover:<size>
+ This service is used to upload a recovery image to the device. <size>
+ must be a number corresponding to the size of the file. The service works
+ by:
+
+ - creating a file named /tmp/update
+ - reading 'size' bytes from the client and writing them to /tmp/update
+ - when everything is read succesfully, create a file named /tmp/update.start
+
+ This service can only work when the device is in recovery mode. Otherwise,
+ the /tmp directory doesn't exist and the connection will be 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
diff --git a/adb/adb.c b/adb/adb.c
index a50ef33..27d0c81 100644
--- a/adb/adb.c
+++ b/adb/adb.c
@@ -67,59 +67,59 @@ int adb_trace_mask;
*/
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 },
+ 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 },
- { 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++;
- }
+ { 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++;
+ }
}
@@ -783,8 +783,8 @@ int launch_server()
// child process
int result = execl(path, "adb", "fork-server", "server", NULL);
- // this should not return
- fprintf(stderr, "OOPS! execl returned %d, errno: %d\n", result, errno);
+ // this should not return
+ fprintf(stderr, "OOPS! execl returned %d, errno: %d\n", result, errno);
} else {
// parent side of the fork
@@ -894,7 +894,7 @@ int adb_main(int is_daemon)
if(access("/dev/android_adb", F_OK) == 0 ||
access("/dev/android", F_OK) == 0) {
usb_init();
- } else {
+ } else {
local_init();
}
init_jdwp();
diff --git a/adb/adb.h b/adb/adb.h
index 5a74b7b..a17c8dd 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -79,6 +79,11 @@ struct asocket {
*/
unsigned id;
+ /* flag: set when the socket's peer has closed
+ ** but packets are still queued for delivery
+ */
+ int closing;
+
/* the asocket we are connected to
*/
@@ -309,15 +314,15 @@ int writex(int fd, const void *ptr, size_t len);
* the adb_trace_init() function implemented in adb.c
*/
typedef enum {
- TRACE_ADB = 0,
- TRACE_SOCKETS,
- TRACE_PACKETS,
- TRACE_TRANSPORT,
- TRACE_RWX,
- TRACE_USB,
- TRACE_SYNC,
- TRACE_SYSDEPS,
- TRACE_JDWP,
+ TRACE_ADB = 0,
+ TRACE_SOCKETS,
+ TRACE_PACKETS,
+ TRACE_TRANSPORT,
+ TRACE_RWX,
+ TRACE_USB,
+ TRACE_SYNC,
+ TRACE_SYSDEPS,
+ TRACE_JDWP,
} AdbTrace;
#if ADB_TRACE
diff --git a/adb/adb_client.c b/adb/adb_client.c
index c1b87ee..5868744 100644
--- a/adb/adb_client.c
+++ b/adb/adb_client.c
@@ -211,7 +211,7 @@ int adb_connect(const char *service)
return -1;
} else {
fprintf(stdout,"* daemon started successfully *\n");
- }
+ }
/* give the server some time to start properly and detect devices */
adb_sleep_ms(2000);
// fall through to _adb_connect
@@ -223,13 +223,13 @@ int adb_connect(const char *service)
// if we have a file descriptor, then parse version result
if(fd >= 0) {
- if(readx(fd, buf, 4)) goto error;
+ if(readx(fd, buf, 4)) goto error;
- buf[4] = 0;
- n = strtoul(buf, 0, 16);
- if(n > (int)sizeof(buf)) goto error;
- if(readx(fd, buf, n)) goto error;
- adb_close(fd);
+ buf[4] = 0;
+ n = strtoul(buf, 0, 16);
+ if(n > (int)sizeof(buf)) goto error;
+ if(readx(fd, buf, n)) goto error;
+ adb_close(fd);
if (sscanf(buf, "%04x", &version) != 1) goto error;
} else {
@@ -240,14 +240,14 @@ int adb_connect(const char *service)
}
if(version != ADB_SERVER_VERSION) {
- printf("adb server is out of date. killing...\n");
- fd = _adb_connect("host:kill");
- adb_close(fd);
+ 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);
+ /* XXX can we better detect its death? */
+ adb_sleep_ms(2000);
goto start_server;
- }
+ }
}
// if the command is start-server, we are done.
diff --git a/adb/commandline.c b/adb/commandline.c
index c1ef8b0..cbf079c 100644
--- a/adb/commandline.c
+++ b/adb/commandline.c
@@ -296,8 +296,8 @@ static void *stdin_read_thread(void *x)
buf_ptr[cmdlen] = '\0';
if( (item = shListFindItem( &history, (void *)buf_ptr, shItemCmp )) == NULL ) {
shListInsFirstItem( &history, (void *)buf_ptr );
- item = &history;
- }
+ item = &history;
+ }
}
}
cmdlen = 0;
@@ -322,8 +322,8 @@ static void *stdin_read_thread(void *x)
default:
#ifdef SH_HISTORY
if( buf[n] == SH_DEL_CHAR ) {
- if( cmdlen > 0 )
- cmdlen--;
+ if( cmdlen > 0 )
+ cmdlen--;
}
else {
realbuf[cmdlen] = buf[n];
@@ -478,7 +478,7 @@ static void status_window(transport_type ttype, const char* serial)
#ifdef _WIN32
/* XXX: TODO */
#else
- int fd;
+ int fd;
fd = unix_open("/dev/null", O_WRONLY);
dup2(fd, 2);
adb_close(fd);
@@ -512,7 +512,7 @@ static void status_window(transport_type ttype, const char* serial)
}
}
-/** duplicate string and quote all \ " ( ) chars */
+/** duplicate string and quote all \ " ( ) chars + space character. */
static char *
dupAndQuote(const char *s)
{
@@ -527,7 +527,7 @@ dupAndQuote(const char *s)
for( ;*ts != '\0'; ts++) {
alloc_len++;
- if (*ts == '"' || *ts == '\\') {
+ if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
alloc_len++;
}
}
@@ -538,7 +538,7 @@ dupAndQuote(const char *s)
dest = ret;
for ( ;*ts != '\0'; ts++) {
- if (*ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
+ if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
*dest++ = '\\';
}
@@ -561,7 +561,7 @@ int ppp(int argc, char **argv)
{
#ifdef HAVE_WIN32_PROC
fprintf(stderr, "error: adb %s not implemented on Win32\n", argv[0]);
- return -1;
+ return -1;
#else
char *adb_service_name;
pid_t pid;
@@ -657,8 +657,8 @@ static int logcat(transport_type transport, char* serial, int argc, char **argv)
quoted_log_tags = dupAndQuote(log_tags == NULL ? "" : log_tags);
snprintf(buf, sizeof(buf),
- "shell:export ANDROID_LOG_TAGS=\"\%s\" ; exec logcat",
- quoted_log_tags);
+ "shell:export ANDROID_LOG_TAGS=\"\%s\" ; exec logcat",
+ quoted_log_tags);
free(quoted_log_tags);
@@ -847,7 +847,7 @@ int adb_commandline(int argc, char **argv)
if (gProductOutPath == NULL || gProductOutPath[0] == '\0') {
gProductOutPath = NULL;
}
- // TODO: also try TARGET_PRODUCT as a hint
+ // TODO: also try TARGET_PRODUCT/TARGET_DEVICE as a hint
/* modifiers and flags */
while(argc > 0) {
@@ -1077,15 +1077,15 @@ top:
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;
+ /* 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")) {
@@ -1299,7 +1299,7 @@ static int pm_command(transport_type transport, char* serial,
while(argc-- > 0) {
char *quoted;
- quoted = dupAndQuote (*argv++);
+ quoted = dupAndQuote(*argv++);
strncat(buf, " ", sizeof(buf)-1);
strncat(buf, quoted, sizeof(buf)-1);
@@ -1312,6 +1312,18 @@ static int pm_command(transport_type transport, char* serial,
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);
}
diff --git a/adb/file_sync_client.c b/adb/file_sync_client.c
index f9e80ed..4e6d385 100644
--- a/adb/file_sync_client.c
+++ b/adb/file_sync_client.c
@@ -55,7 +55,7 @@ static void END()
if(total_bytes == 0) return;
if (t == 0) /* prevent division by 0 :-) */
- t = 1000000;
+ t = 1000000;
fprintf(stderr,"%lld KB/s (%d bytes in %lld.%03llds)\n",
((((long long) total_bytes) * 1000000LL) / t) / 1024LL,
@@ -227,14 +227,14 @@ static int write_data_file(int fd, const char *path, syncsendbuf *sbuf)
if(ret < 0) {
if(errno == EINTR)
- continue;
+ 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;
+ err = -1;
break;
}
total_bytes += ret;
@@ -259,7 +259,7 @@ static int write_data_buffer(int fd, char* file_buffer, int size, syncsendbuf *s
memcpy(sbuf->data, &file_buffer[total], count);
sbuf->size = htoll(count);
if(writex(fd, sbuf, sizeof(unsigned) * 2 + count)){
- err = -1;
+ err = -1;
break;
}
total += count;
@@ -277,7 +277,7 @@ static int write_data_link(int fd, const char *path, syncsendbuf *sbuf)
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;
+ return -1;
}
sbuf->data[len] = '\0';
@@ -377,10 +377,10 @@ static int sync_send(int fd, const char *lpath, const char *rpath,
}
if (file_buffer) {
- write_data_buffer(fd, file_buffer, size, sbuf);
- free(file_buffer);
+ write_data_buffer(fd, file_buffer, size, sbuf);
+ free(file_buffer);
} else if (S_ISREG(mode))
- write_data_file(fd, lpath, sbuf);
+ write_data_file(fd, lpath, sbuf);
#ifdef HAVE_SYMLINKS
else if (S_ISLNK(mode))
write_data_link(fd, lpath, sbuf);
@@ -641,7 +641,7 @@ static int local_build_list(copyinfo **filelist,
} else {
ci = mkcopyinfo(lpath, rpath, name, 0);
if(lstat(ci->src, &st)) {
- closedir(d);
+ closedir(d);
fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno));
return -1;
}
@@ -651,7 +651,7 @@ static int local_build_list(copyinfo **filelist,
} else {
ci->time = st.st_mtime;
ci->mode = st.st_mode;
- ci->size = st.st_size;
+ ci->size = st.st_size;
ci->next = *filelist;
*filelist = ci;
}
@@ -707,12 +707,12 @@ static int copy_local_dir_remote(int fd, const char *lpath, const char *rpath, i
unsigned int timestamp, mode, size;
if(sync_finish_readtime(fd, &timestamp, &mode, &size))
return 1;
- if(size == ci->size) {
+ 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))
+ (S_ISLNK(ci->mode & mode) && timestamp >= ci->time))
ci->flag = 1;
- }
+ }
}
}
for(ci = filelist; ci != 0; ci = next) {
diff --git a/adb/file_sync_service.c b/adb/file_sync_service.c
index 21f8af7..a231e93 100644
--- a/adb/file_sync_service.c
+++ b/adb/file_sync_service.c
@@ -164,12 +164,12 @@ static int handle_send_file(int s, char *path, mode_t mode, char *buffer)
}
if(fd < 0) {
if(fail_errno(s))
- return -1;
+ return -1;
fd = -1;
}
for(;;) {
- unsigned int len;
+ unsigned int len;
if(readx(s, &msg.data, sizeof(msg.data)))
goto fail;
@@ -264,7 +264,7 @@ static int handle_send_link(int s, char *path, char *buffer)
return -1;
} else {
fail_message(s, "invalid data message: expected ID_DONE");
- return -1;
+ return -1;
}
return 0;
diff --git a/adb/framebuffer_service.c b/adb/framebuffer_service.c
index 1d2c4b5..0de0dd5 100644
--- a/adb/framebuffer_service.c
+++ b/adb/framebuffer_service.c
@@ -24,6 +24,7 @@
#include "adb.h"
#include <linux/fb.h>
+#include <sys/ioctl.h>
#include <sys/mman.h>
/* TODO:
@@ -37,9 +38,9 @@ void framebuffer_service(int fd, void *cookie)
int fb;
void *ptr = MAP_FAILED;
char x;
-
+
unsigned fbinfo[4];
-
+
fb = open("/dev/graphics/fb0", O_RDONLY);
if(fb < 0) goto done;
@@ -53,14 +54,14 @@ void framebuffer_service(int fd, void *cookie)
ptr = mmap(0, fbinfo[1], PROT_READ, MAP_SHARED, fb, 0);
if(ptr == MAP_FAILED) goto done;
-
+
if(writex(fd, fbinfo, sizeof(unsigned) * 4)) goto done;
for(;;) {
if(readx(fd, &x, 1)) goto done;
if(writex(fd, ptr, fbinfo[1])) goto done;
}
-
+
done:
if(ptr != MAP_FAILED) munmap(ptr, fbinfo[1]);
if(fb >= 0) close(fb);
diff --git a/adb/get_my_path_windows.c b/adb/get_my_path_windows.c
index 64a597d..fc7143c 100644
--- a/adb/get_my_path_windows.c
+++ b/adb/get_my_path_windows.c
@@ -20,12 +20,12 @@
void get_my_path(char exe[PATH_MAX])
{
- char* r;
+ char* r;
- GetModuleFileName( NULL, exe, PATH_MAX-1 );
- exe[PATH_MAX-1] = 0;
- r = strrchr( exe, '\\' );
- if (r)
- *r = 0;
+ GetModuleFileName( NULL, exe, PATH_MAX-1 );
+ exe[PATH_MAX-1] = 0;
+ r = strrchr( exe, '\\' );
+ if (r)
+ *r = 0;
}
diff --git a/adb/jdwp_service.c b/adb/jdwp_service.c
index 43dc69e..ae7f12d 100644
--- a/adb/jdwp_service.c
+++ b/adb/jdwp_service.c
@@ -287,7 +287,7 @@ jdwp_process_event( int socket, unsigned events, void* _proc )
if (len <= 0) {
if (len < 0 && errno == EINTR)
continue;
- if (len < 0 && errno == EAGAIN)
+ if (len < 0 && errno == EAGAIN)
return;
else {
D("terminating JDWP %d connection: %s\n", proc->pid,
@@ -295,7 +295,7 @@ jdwp_process_event( int socket, unsigned events, void* _proc )
break;
}
}
- else {
+ else {
D( "ignoring unexpected JDWP %d control socket activity (%d bytes)\n",
proc->pid, len );
}
diff --git a/adb/sockets.c b/adb/sockets.c
index b9c9ae1..9f1b598 100644
--- a/adb/sockets.c
+++ b/adb/sockets.c
@@ -50,6 +50,15 @@ static asocket local_socket_list = {
.prev = &local_socket_list,
};
+/* the the list of currently closing local sockets.
+** these have no peer anymore, but still packets to
+** write to their fd.
+*/
+static asocket local_socket_closing_list = {
+ .next = &local_socket_closing_list,
+ .prev = &local_socket_closing_list,
+};
+
asocket *find_local_socket(unsigned id)
{
asocket *s;
@@ -64,16 +73,22 @@ asocket *find_local_socket(unsigned id)
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++;
-
- s->next = &local_socket_list;
- s->prev = local_socket_list.prev;
- s->prev->next = s;
- s->next->prev = s;
+ insert_local_socket(s, &local_socket_list);
adb_mutex_unlock(&socket_list_lock);
}
@@ -177,19 +192,11 @@ static void local_socket_close(asocket *s)
adb_mutex_unlock(&socket_list_lock);
}
-static void local_socket_close_locked(asocket *s)
+// be sure to hold the socket list lock when calling this
+static void local_socket_destroy(asocket *s)
{
apacket *p, *n;
- if(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);
- }
-
/* IMPORTANT: the remove closes the fd
** that belongs to this socket
*/
@@ -201,16 +208,94 @@ static void local_socket_close_locked(asocket *s)
n = p->next;
put_apacket(p);
}
-
- D("LS(%d): closed\n", s->id);
remove_socket(s);
free(s);
}
+
+static void local_socket_close_locked(asocket *s)
+{
+ if(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);
+ }
+
+ /* 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);
+ insert_local_socket(s, &local_socket_closing_list);
+}
+
static void local_socket_event_func(int fd, unsigned ev, void *_s)
{
asocket *s = _s;
+ /* 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;
+ }
+ 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) {
+ 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;
@@ -244,7 +329,12 @@ static void local_socket_event_func(int fd, unsigned ev, void *_s)
if(r < 0) {
/* error return means they closed us as a side-effect
- ** and we must retutn immediately
+ ** 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;
}
@@ -261,42 +351,6 @@ static void local_socket_event_func(int fd, unsigned ev, void *_s)
if(is_eof) {
s->close(s);
}
- return;
- }
-
- 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) {
- if(errno == EAGAIN) return;
- if(errno == EINTR) continue;
- }
- 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);
- }
- }
-
- /* 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);
- return;
}
if(ev & FDE_ERROR){
diff --git a/adb/sysdeps_win32.c b/adb/sysdeps_win32.c
index 9d6a596..c2a9a98 100644
--- a/adb/sysdeps_win32.c
+++ b/adb/sysdeps_win32.c
@@ -940,12 +940,12 @@ bip_buffer_write( BipBuffer bip, const void* src, int len )
/* we can append to region A */
if (avail > len)
avail = len;
-
+
memcpy( bip->buff + bip->a_end, src, avail );
src += avail;
count += avail;
len -= avail;
-
+
bip->a_end += avail;
if (bip->a_end == BIP_BUFFER_SIZE && bip->a_start == 0) {
bip->can_write = 0;
@@ -953,25 +953,25 @@ bip_buffer_write( BipBuffer bip, const void* src, int len )
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 );
@@ -979,7 +979,7 @@ Exit:
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 );
@@ -991,12 +991,12 @@ 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 )
{
@@ -1007,7 +1007,7 @@ bip_buffer_read( BipBuffer bip, void* dst, int len )
#else
int ret;
LeaveCriticalSection( &bip->lock );
-
+
if (bip->closed) {
errno = EPIPE;
return -1;
@@ -1023,30 +1023,30 @@ bip_buffer_read( BipBuffer bip, void* dst, int len )
return -1;
}
EnterCriticalSection( &bip->lock );
-#endif
+#endif
}
BIPD(( "bip_buffer_read: exec %d->%d len %d\n", bip->fdin, bip->fdout, len ));
-
+
avail = bip->a_end - bip->a_start;
assert( avail > 0 ); /* since can_read is TRUE */
-
+
if (avail > len)
avail = len;
-
+
memcpy( dst, bip->buff + bip->a_start, avail );
dst += avail;
count += avail;
len -= avail;
-
+
bip->a_start += avail;
if (bip->a_start < bip->a_end)
goto Exit;
-
+
bip->a_start = 0;
bip->a_end = bip->b_end;
bip->b_end = 0;
-
+
avail = bip->a_end;
if (avail > 0) {
if (avail > len)
@@ -1054,13 +1054,13 @@ bip_buffer_read( BipBuffer bip, void* dst, int 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 );
@@ -1071,22 +1071,22 @@ Exit:
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 )
@@ -1103,7 +1103,7 @@ _fh_socketpair_close( FH f )
if ( f == pair->a_fd ) {
pair->a_fd = NULL;
}
-
+
bip_buffer_close( &pair->b2a_bip );
bip_buffer_close( &pair->a2b_bip );
@@ -1199,7 +1199,7 @@ int adb_socketpair( int sv[2] )
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];
@@ -1303,7 +1303,7 @@ event_hook_alloc( FH fh )
hook->stop = NULL;
hook->check = NULL;
hook->peek = NULL;
-
+
return hook;
}
@@ -1324,7 +1324,7 @@ 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;
@@ -1365,7 +1365,7 @@ 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;
@@ -1397,7 +1397,7 @@ 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 ) {
@@ -1424,7 +1424,7 @@ 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 );
}
@@ -1433,7 +1433,7 @@ 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 );
}
@@ -1462,7 +1462,7 @@ 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;
@@ -1479,7 +1479,7 @@ static void fdevent_process()
if (!gotone)
{
looper->htab_count = 0;
-
+
for (hook = looper->hooks; hook; hook = hook->next)
{
if (hook->start && !hook->start(hook)) {
@@ -1519,7 +1519,7 @@ static void fdevent_process()
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
*/
@@ -1561,7 +1561,7 @@ static void fdevent_register(fdevent *fde)
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) {
@@ -1587,7 +1587,7 @@ static void fdevent_register(fdevent *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);
}
@@ -1626,9 +1626,9 @@ 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;
@@ -1689,9 +1689,9 @@ void fdevent_remove(fdevent *fde)
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");
@@ -1727,13 +1727,13 @@ void fdevent_del(fdevent *fde, unsigned events)
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;
@@ -1793,7 +1793,7 @@ static void _event_socket_verify( EventHook hook, WSANETWORKEVENTS* evts )
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 );
@@ -1819,13 +1819,13 @@ 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 ) ) {
@@ -1850,7 +1850,7 @@ 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);
@@ -1866,7 +1866,7 @@ 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 );
@@ -1886,40 +1886,40 @@ static void _fh_socket_hook( FH f, int events, EventHook hook )
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;
diff --git a/adb/transport_local.c b/adb/transport_local.c
index 0e8b732..be01f29 100644
--- a/adb/transport_local.c
+++ b/adb/transport_local.c
@@ -76,7 +76,7 @@ static int remote_read(apacket *p, atransport *t)
}
if(check_data(p)) {
- D("bad data: terminated (data)\n");
+ D("bad data: terminated (data)\n");
return -1;
}
@@ -107,15 +107,16 @@ int local_connect(int port)
char buf[64];
int fd = -1;
- fd = socket_loopback_client(port, SOCK_STREAM);
#if ADB_HOST
- if(fd < 0) {
- const char *host = getenv("ADBHOST");
- if(host) {
- fd = socket_network_client(host, port, SOCK_STREAM);
- }
+ const char *host = getenv("ADBHOST");
+ if (host) {
+ fd = socket_network_client(host, port, SOCK_STREAM);
}
#endif
+ if (fd < 0) {
+ fd = socket_loopback_client(port, SOCK_STREAM);
+ }
+
if (fd >= 0) {
D("client: connected on remote on fd %d\n", fd);
close_on_exec(fd);
diff --git a/adb/transport_usb.c b/adb/transport_usb.c
index 4da7e8b..01c4a7e 100644
--- a/adb/transport_usb.c
+++ b/adb/transport_usb.c
@@ -55,7 +55,7 @@ static int remote_read(apacket *p, atransport *t)
}
fix_endians(p);
-
+
if(check_header(p)) {
D("remote usb: check_header failed\n");
return -1;
@@ -79,9 +79,9 @@ static int remote_read(apacket *p, atransport *t)
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;
@@ -91,7 +91,7 @@ static int remote_write(apacket *p, atransport *t)
D("remote usb: 2 - write terminated\n");
return -1;
}
-
+
return 0;
}
@@ -117,7 +117,7 @@ void init_usb_transport(atransport *t, usb_handle *h)
t->connection_state = CS_OFFLINE;
t->type = kTransportUsb;
t->usb = h;
-
+
#if ADB_HOST
HOST = 1;
#else
@@ -135,7 +135,7 @@ int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_
/* not supported */
return 0;
}
-
+
/* class:vendor (0xff) subclass:android (0x42) proto:adb (0x01) */
if(usb_class == 0xff) {
if((usb_subclass == 0x42) && (usb_protocol == 0x01)) {
diff --git a/adb/usb_linux_client.c b/adb/usb_linux_client.c
index e265a1c..530bd04 100644
--- a/adb/usb_linux_client.c
+++ b/adb/usb_linux_client.c
@@ -118,7 +118,7 @@ void usb_init()
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
diff --git a/adb/usb_osx.c b/adb/usb_osx.c
index 8ea84f9..49e1eef 100644
--- a/adb/usb_osx.c
+++ b/adb/usb_osx.c
@@ -72,13 +72,13 @@ InitUSB()
CFRunLoopSourceRef runLoopSource;
SInt32 vendor, product;
int i;
-
+
//* To set up asynchronous notifications, create a notification port and
//* add its run loop event source to the program's run loop
notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
runLoopSource = IONotificationPortGetRunLoopSource(notificationPort);
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode);
-
+
memset(notificationIterators, 0, sizeof(notificationIterators));
//* loop through all supported vendor/product pairs
@@ -86,19 +86,19 @@ InitUSB()
//* Create our matching dictionary to find the Android device
//* IOServiceAddMatchingNotification consumes the reference, so we do not need to release this
matchingDict = IOServiceMatching(kIOUSBDeviceClassName);
-
+
if (!matchingDict) {
DBG("ERR: Couldn't create USB matching dictionary.\n");
return -1;
}
-
+
//* Set up two matching dictionaries, one for each product ID we support.
//* This will cause the kernel to notify us only if the vendor and product IDs match.
vendor = kSupportedDevices[i].vid;
product = kSupportedDevices[i].pid;
- CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorID), CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vendor));
- CFDictionarySetValue(matchingDict, CFSTR(kUSBProductID), CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &product));
-
+ CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorID), CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vendor));
+ CFDictionarySetValue(matchingDict, CFSTR(kUSBProductID), CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &product));
+
//* Now set up two notifications: one to be called when a raw device
//* is first matched by the I/O Kit and another to be called when the
//* device is terminated.
@@ -110,7 +110,7 @@ InitUSB()
AndroidDeviceAdded,
NULL,
&notificationIterators[i]);
-
+
//* Iterate over set of matching devices to access already-present devices
//* and to arm the notification
AndroidDeviceAdded(NULL, notificationIterators[i]);
@@ -173,7 +173,7 @@ AndroidDeviceAdded(void *refCon, io_iterator_t iterator)
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++)
@@ -401,8 +401,8 @@ void* RunLoopThread(void* unused)
currentRunLoop = 0;
for (i = 0; i < kSupportedDeviceCount; i++) {
- IOObjectRelease(notificationIterators[i]);
- }
+ IOObjectRelease(notificationIterators[i]);
+ }
IONotificationPortDestroy(notificationPort);
DBG("RunLoopThread done\n");
diff --git a/adb/usb_windows.c b/adb/usb_windows.c
index 5b0f11f..7ddaa0c 100644
--- a/adb/usb_windows.c
+++ b/adb/usb_windows.c
@@ -308,11 +308,11 @@ int usb_read(usb_handle *handle, void* data, int len) {
while (len > 0) {
int xfer = (len > 4096) ? 4096 : len;
- ret = AdbReadEndpointSync(handle->adb_read_pipe,
- (void*)data,
- (unsigned long)xfer,
- &read,
- time_out);
+ ret = AdbReadEndpointSync(handle->adb_read_pipe,
+ (void*)data,
+ (unsigned long)xfer,
+ &read,
+ time_out);
errno = GetLastError();
D("usb_write got: %ld, expected: %d, errno: %d\n", read, xfer, errno);
if (ret) {
@@ -475,11 +475,11 @@ void find_devices() {
// 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) {
+ 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);
+ 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,
@@ -488,7 +488,7 @@ void find_devices() {
true)) {
// Lets make sure that we don't duplicate this device
if (register_new_device(handle)) {
- register_usb_transport(handle, serial_number);
+ register_usb_transport(handle, serial_number);
} else {
D("register_new_device failed for %s\n", interf_name);
usb_cleanup_handle(handle);
diff --git a/adb/utils.c b/adb/utils.c
new file mode 100644
index 0000000..91518ba
--- /dev/null
+++ b/adb/utils.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "utils.h"
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+char*
+buff_addc (char* buff, char* buffEnd, int c)
+{
+ int avail = buffEnd - buff;
+
+ if (avail <= 0) /* already in overflow mode */
+ return buff;
+
+ if (avail == 1) { /* overflowing, the last byte is reserved for zero */
+ buff[0] = 0;
+ return buff + 1;
+ }
+
+ buff[0] = (char) c; /* add char and terminating zero */
+ buff[1] = 0;
+ return buff + 1;
+}
+
+char*
+buff_adds (char* buff, char* buffEnd, const char* s)
+{
+ int slen = strlen(s);
+
+ return buff_addb(buff, buffEnd, s, slen);
+}
+
+char*
+buff_addb (char* buff, char* buffEnd, const void* data, int len)
+{
+ int avail = (buffEnd - buff);
+
+ if (avail <= 0 || len <= 0) /* already overflowing */
+ return buff;
+
+ if (len > avail)
+ len = avail;
+
+ memcpy(buff, data, len);
+
+ buff += len;
+
+ /* ensure there is a terminating zero */
+ if (buff >= buffEnd) { /* overflow */
+ buff[-1] = 0;
+ } else
+ buff[0] = 0;
+
+ return buff;
+}
+
+char*
+buff_add (char* buff, char* buffEnd, const char* format, ... )
+{
+ int avail;
+
+ avail = (buffEnd - buff);
+
+ if (avail > 0) {
+ va_list args;
+ int nn;
+
+ va_start(args, format);
+ nn = vsnprintf( buff, avail, format, args);
+ va_end(args);
+
+ if (nn < 0) {
+ /* some C libraries return -1 in case of overflow,
+ * but they will also do that if the format spec is
+ * invalid. We assume ADB is not buggy enough to
+ * trigger that last case. */
+ nn = avail;
+ }
+ else if (nn > avail) {
+ nn = avail;
+ }
+
+ buff += nn;
+
+ /* ensure that there is a terminating zero */
+ if (buff >= buffEnd)
+ buff[-1] = 0;
+ else
+ buff[0] = 0;
+ }
+ return buff;
+}
diff --git a/adb/utils.h b/adb/utils.h
new file mode 100644
index 0000000..f70ecd2
--- /dev/null
+++ b/adb/utils.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef _ADB_UTILS_H
+#define _ADB_UTILS_H
+
+/* bounded buffer functions */
+
+/* all these functions are used to append data to a bounded buffer.
+ *
+ * after each operation, the buffer is guaranteed to be zero-terminated,
+ * even in the case of an overflow. they all return the new buffer position
+ * which allows one to use them in succession, only checking for overflows
+ * at the end. For example:
+ *
+ * BUFF_DECL(temp,p,end,1024);
+ * char* p;
+ *
+ * p = buff_addc(temp, end, '"');
+ * p = buff_adds(temp, end, string);
+ * p = buff_addc(temp, end, '"');
+ *
+ * if (p >= end) {
+ * overflow detected. note that 'temp' is
+ * zero-terminated for safety.
+ * }
+ * return strdup(temp);
+ */
+
+/* tries to add a character to the buffer, in case of overflow
+ * this will only write a terminating zero and return buffEnd.
+ */
+char* buff_addc (char* buff, char* buffEnd, int c);
+
+/* tries to add a string to the buffer */
+char* buff_adds (char* buff, char* buffEnd, const char* s);
+
+/* tries to add a bytes to the buffer. the input can contain zero bytes,
+ * but a terminating zero will always be appended at the end anyway
+ */
+char* buff_addb (char* buff, char* buffEnd, const void* data, int len);
+
+/* tries to add a formatted string to a bounded buffer */
+char* buff_add (char* buff, char* buffEnd, const char* format, ... );
+
+/* convenience macro used to define a bounded buffer, as well as
+ * a 'cursor' and 'end' variables all in one go.
+ *
+ * note: this doesn't place an initial terminating zero in the buffer,
+ * you need to use one of the buff_ functions for this. or simply
+ * do _cursor[0] = 0 manually.
+ */
+#define BUFF_DECL(_buff,_cursor,_end,_size) \
+ char _buff[_size], *_cursor=_buff, *_end = _cursor + (_size)
+
+#endif /* _ADB_UTILS_H */