From 35237d135807af84bf9b0e5b8d7f8633e58db6f5 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Wed, 17 Dec 2008 18:08:08 -0800 Subject: Code drop from //branches/cupcake/...@124589 --- adb/Android.mk | 48 +++++++-- adb/OVERVIEW.TXT | 139 ++++++++++++++++++++++++++ adb/SERVICES.TXT | 245 ++++++++++++++++++++++++++++++++++++++++++++++ adb/adb.c | 108 ++++++++++---------- adb/adb.h | 23 +++-- adb/adb_client.c | 26 ++--- adb/commandline.c | 56 ++++++----- adb/file_sync_client.c | 26 ++--- adb/file_sync_service.c | 6 +- adb/framebuffer_service.c | 9 +- adb/get_my_path_windows.c | 12 +-- adb/jdwp_service.c | 4 +- adb/sockets.c | 162 ++++++++++++++++++++---------- adb/sysdeps_win32.c | 116 +++++++++++----------- adb/transport_local.c | 15 +-- adb/transport_usb.c | 12 +-- adb/usb_linux_client.c | 2 +- adb/usb_osx.c | 22 ++--- adb/usb_windows.c | 18 ++-- adb/utils.c | 106 ++++++++++++++++++++ adb/utils.h | 68 +++++++++++++ 21 files changed, 943 insertions(+), 280 deletions(-) create mode 100644 adb/OVERVIEW.TXT create mode 100644 adb/SERVICES.TXT create mode 100644 adb/utils.c create mode 100644 adb/utils.h (limited to 'adb') 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:' request, + where '' 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: + This is a special query that is sent to the ADB server when a + new emulator starts up. 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: + Ask to switch the connection to the device/emulator identified by + . 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:: + This is a special form of query, where the 'host-serial::' + prefix can be used to indicate that the client is asking the ADB server + for information related to a specific device. can be in one + of the format described below. + +host-usb: + 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: + 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: + 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'. + +:get-product + XXX + +:get-serialno + Returns the serial number of the corresponding device/emulator. + Note that emulator serial numbers are of the form "emulator-5554" + +:get-state + Returns the state of a given device as a string. + +:forward:: + Asks the ADB server to forward local connections from + to the address on a given device. + + There, 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 is one of: + + tcp: -> TCP connection on localhost: + local: -> Unix local domain socket on + + the format of is one of: + + tcp: -> TCP localhost: on device + local: -> Unix local domain socket on device + jdwp: -> JDWP thread on VM process + + 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: + 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: + 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. is a full + path from the root of the filesystem. + +tcp: + Tries to connect to tcp port on localhost. + +tcp:: + Tries to connect to tcp port on machine from + the device. This can be useful to debug some networking/proxy + issues that can only be revealed on the device itself. + +local: + Tries to connect to a Unix domain socket on the device + +localreserved: +localabstract: +localfilesystem: + Variants of local: that are used to access other Android + socket namespaces. + +log: + Opens one of the system logs (/dev/log/) 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: + 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(
) on the host and return + the corresponding IP address as a 4-byte string. + +recover: + This service is used to upload a recovery image to the device. + 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: + Connects to the JDWP thread running in the VM of process . + +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: + + : the length of all content as a 4-char hexadecimal string + : a series of ASCII lines of the following format: + "\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, ×tamp, &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 +#include #include /* 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, ¬ificationIterators[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 +#include +#include + +char* +buff_addc (char* buff, char* buffEnd, int c) +{ + int avail = buffEnd - buff; + + if (avail <= 0) /* already in overflow mode */ + return buff; + + if (avail == 1) { /* overflowing, the last byte is reserved for zero */ + buff[0] = 0; + return buff + 1; + } + + buff[0] = (char) c; /* add char and terminating zero */ + buff[1] = 0; + return buff + 1; +} + +char* +buff_adds (char* buff, char* buffEnd, const char* s) +{ + int slen = strlen(s); + + return buff_addb(buff, buffEnd, s, slen); +} + +char* +buff_addb (char* buff, char* buffEnd, const void* data, int len) +{ + int avail = (buffEnd - buff); + + if (avail <= 0 || len <= 0) /* already overflowing */ + return buff; + + if (len > avail) + len = avail; + + memcpy(buff, data, len); + + buff += len; + + /* ensure there is a terminating zero */ + if (buff >= buffEnd) { /* overflow */ + buff[-1] = 0; + } else + buff[0] = 0; + + return buff; +} + +char* +buff_add (char* buff, char* buffEnd, const char* format, ... ) +{ + int avail; + + avail = (buffEnd - buff); + + if (avail > 0) { + va_list args; + int nn; + + va_start(args, format); + nn = vsnprintf( buff, avail, format, args); + va_end(args); + + if (nn < 0) { + /* some C libraries return -1 in case of overflow, + * but they will also do that if the format spec is + * invalid. We assume ADB is not buggy enough to + * trigger that last case. */ + nn = avail; + } + else if (nn > avail) { + nn = avail; + } + + buff += nn; + + /* ensure that there is a terminating zero */ + if (buff >= buffEnd) + buff[-1] = 0; + else + buff[0] = 0; + } + return buff; +} 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 */ -- cgit v1.1