pax_global_header00006660000000000000000000000064126742724320014523gustar00rootroot0000000000000052 comment=6bffe1e6ed5a4d8263c4f4e950d79ae3c74fdf7a android-tools-5.1.1r36+git20160322/000077500000000000000000000000001267427243200162375ustar00rootroot00000000000000android-tools-5.1.1r36+git20160322/core/000077500000000000000000000000001267427243200171675ustar00rootroot00000000000000android-tools-5.1.1r36+git20160322/core/adb/000077500000000000000000000000001267427243200177155ustar00rootroot00000000000000android-tools-5.1.1r36+git20160322/core/adb/Android.mk000066400000000000000000000076611267427243200216400ustar00rootroot00000000000000# Copyright 2005 The Android Open Source Project # # Android.mk for adb # LOCAL_PATH:= $(call my-dir) # adb host tool # ========================================================= include $(CLEAR_VARS) # Default to a virtual (sockets) usb interface USB_SRCS := EXTRA_SRCS := ifeq ($(HOST_OS),linux) USB_SRCS := usb_linux.c EXTRA_SRCS := get_my_path_linux.c LOCAL_LDLIBS += -lrt -ldl -lpthread LOCAL_CFLAGS += -DWORKAROUND_BUG6558362 endif ifeq ($(HOST_OS),darwin) USB_SRCS := usb_osx.c EXTRA_SRCS := get_my_path_darwin.c LOCAL_LDLIBS += -lpthread -framework CoreFoundation -framework IOKit -framework Carbon endif ifeq ($(HOST_OS),freebsd) USB_SRCS := usb_libusb.c EXTRA_SRCS := get_my_path_freebsd.c LOCAL_LDLIBS += -lpthread -lusb endif ifeq ($(HOST_OS),windows) USB_SRCS := usb_windows.c EXTRA_SRCS := get_my_path_windows.c EXTRA_STATIC_LIBS := AdbWinApi ifneq ($(strip $(USE_CYGWIN)),) # Pure cygwin case LOCAL_LDLIBS += -lpthread -lgdi32 endif ifneq ($(strip $(USE_MINGW)),) # MinGW under Linux case LOCAL_LDLIBS += -lws2_32 -lgdi32 USE_SYSDEPS_WIN32 := 1 endif LOCAL_C_INCLUDES += development/host/windows/usb/api/ endif LOCAL_SRC_FILES := \ adb.c \ console.c \ transport.c \ transport_local.c \ transport_usb.c \ commandline.c \ adb_client.c \ adb_auth_host.c \ sockets.c \ services.c \ file_sync_client.c \ $(EXTRA_SRCS) \ $(USB_SRCS) \ usb_vendors.c LOCAL_C_INCLUDES += external/openssl/include ifneq ($(USE_SYSDEPS_WIN32),) LOCAL_SRC_FILES += sysdeps_win32.c else LOCAL_SRC_FILES += fdevent.c endif LOCAL_CFLAGS += -O2 -g -DADB_HOST=1 -Wall -Wno-unused-parameter -Werror LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE LOCAL_MODULE := adb LOCAL_MODULE_TAGS := debug LOCAL_STATIC_LIBRARIES := libzipfile libunz libcrypto_static $(EXTRA_STATIC_LIBS) ifeq ($(USE_SYSDEPS_WIN32),) LOCAL_STATIC_LIBRARIES += libcutils endif include $(BUILD_HOST_EXECUTABLE) $(call dist-for-goals,dist_files sdk,$(LOCAL_BUILT_MODULE)) ifeq ($(HOST_OS),windows) $(LOCAL_INSTALLED_MODULE): \ $(HOST_OUT_EXECUTABLES)/AdbWinApi.dll \ $(HOST_OUT_EXECUTABLES)/AdbWinUsbApi.dll endif # adbd device daemon # ========================================================= include $(CLEAR_VARS) LOCAL_SRC_FILES := \ adb.c \ fdevent.c \ transport.c \ transport_local.c \ transport_usb.c \ adb_auth_client.c \ sockets.c \ services.c \ file_sync_service.c \ jdwp_service.c \ framebuffer_service.c \ remount_service.c \ disable_verity_service.c \ usb_linux_client.c LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter -Werror LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT))) LOCAL_CFLAGS += -DALLOW_ADBD_ROOT=1 endif ifneq (,$(filter userdebug,$(TARGET_BUILD_VARIANT))) LOCAL_CFLAGS += -DALLOW_ADBD_DISABLE_VERITY=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_C_INCLUDES += system/extras/ext4_utils system/core/fs_mgr/include LOCAL_STATIC_LIBRARIES := liblog \ libfs_mgr \ libcutils \ libc \ libmincrypt \ libselinux \ libext4_utils_static include $(BUILD_EXECUTABLE) # adb host tool for device-as-host # ========================================================= ifneq ($(SDK_ONLY),true) include $(CLEAR_VARS) LOCAL_SRC_FILES := \ adb.c \ console.c \ transport.c \ transport_local.c \ transport_usb.c \ commandline.c \ adb_client.c \ adb_auth_host.c \ sockets.c \ services.c \ file_sync_client.c \ get_my_path_linux.c \ usb_linux.c \ usb_vendors.c \ fdevent.c LOCAL_CFLAGS := \ -O2 \ -g \ -DADB_HOST=1 \ -DADB_HOST_ON_TARGET=1 \ -Wall -Wno-unused-parameter -Werror \ -D_XOPEN_SOURCE \ -D_GNU_SOURCE LOCAL_C_INCLUDES += external/openssl/include LOCAL_MODULE := adb LOCAL_STATIC_LIBRARIES := libzipfile libunz libcutils liblog LOCAL_SHARED_LIBRARIES := libcrypto include $(BUILD_EXECUTABLE) endif android-tools-5.1.1r36+git20160322/core/adb/NOTICE000066400000000000000000000247761267427243200206410ustar00rootroot00000000000000 Copyright (c) 2006-2009, The Android Open Source Project Copyright 2006, Brian Swetland Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 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. Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS android-tools-5.1.1r36+git20160322/core/adb/OVERVIEW.TXT000066400000000000000000000126251267427243200215720ustar00rootroot00000000000000Implementation notes regarding ADB. I. General Overview: The Android Debug Bridge (ADB) is used to: - keep track of all Android devices and emulators instances connected to or running on a given host developer machine - implement various control commands (e.g. "adb shell", "adb pull", etc..) for the benefit of clients (command-line users, or helper programs like DDMS). These commands are what is called a 'service' in ADB. As a whole, everything works through the following components: 1. The ADB server This is a background process that runs on the host machine. Its purpose if to sense the USB ports to know when devices are attached/removed, as well as when emulator instances start/stop. It thus maintains a list of "connected devices" and assigns a 'state' to each one of them: OFFLINE, BOOTLOADER, RECOVERY or ONLINE (more on this below). The ADB server is really one giant multiplexing loop whose purpose is to orchestrate the exchange of data (packets, really) between clients, services and devices. 2. The ADB daemon (adbd) The 'adbd' program runs as a background process within an Android device or emulated system. Its purpose is to connect to the ADB server (through USB for devices, through TCP for emulators) and provide a few services for clients that run on the host. The ADB server considers that a device is ONLINE when it has successfully connected to the adbd program within it. Otherwise, the device is OFFLINE, meaning that the ADB server detected a new device/emulator, but could not connect to the adbd daemon. the BOOTLOADER and RECOVERY states correspond to alternate states of devices when they are in the bootloader or recovery mode. 3. The ADB command-line client The 'adb' command-line program is used to run adb commands from a shell or a script. It first tries to locate the ADB server on the host machine, and will start one automatically if none is found. then, the client sends its service requests to the ADB server. It doesn't need to know. Currently, a single 'adb' binary is used for both the server and client. this makes distribution and starting the server easier. 4. Services There are essentially two kinds of services that a client can talk to. Host Services: these services run within the ADB Server and thus do not need to communicate with a device at all. A typical example is "adb devices" which is used to return the list of currently known devices and their state. They are a few couple other services though. Local Services: these services either run within the adbd daemon, or are started by it on the device. The ADB server is used to multiplex streams between the client and the service running in adbd. In this case its role is to initiate the connection, then of being a pass-through for the data. II. Protocol details: 1. Client <-> Server protocol: This details the protocol used between ADB clients and the ADB server itself. The ADB server listens on TCP:localhost:5037. A client sends a request using the following format: 1. A 4-byte hexadecimal string giving the length of the payload 2. Followed by the payload itself. For example, to query the ADB server for its internal version number, the client will do the following: 1. Connect to tcp:localhost:5037 2. Send the string "000Chost:version" to the corresponding socket The 'host:' prefix is used to indicate that the request is addressed to the server itself (we will talk about other kinds of requests later). The content length is encoded in ASCII for easier debugging. The server should answer a request with one of the following: 1. For success, the 4-byte "OKAY" string 2. For failure, the 4-byte "FAIL" string, followed by a 4-byte hex length, followed by a string giving the reason for failure. 3. As a special exception, for 'host:version', a 4-byte hex string corresponding to the server's internal version number Note that the connection is still alive after an OKAY, which allows the client to make other requests. But in certain cases, an OKAY will even change the state of the connection. For example, the case of the 'host:transport:' 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. android-tools-5.1.1r36+git20160322/core/adb/SERVICES.TXT000066400000000000000000000233221267427243200215430ustar00rootroot00000000000000This file tries to document all requests a client can make to the ADB server of an adbd daemon. See the OVERVIEW.TXT document to understand what's going on here. HOST SERVICES: host:version Ask the ADB server for its internal version number. As a special exception, the server will respond with a 4-byte hex string corresponding to its internal version number, without any OKAY or FAIL. host:kill Ask the ADB server to quit immediately. This is used when the ADB client detects that an obsolete server is running after an upgrade. host:devices host:devices-l Ask to return the list of available Android devices and their state. devices-l includes the device paths in the state. After the OKAY, this is followed by a 4-byte hex len, and a string that will be dumped as-is by the client, then the connection is closed host:track-devices This is a variant of host:devices which doesn't close the connection. Instead, a new device list description is sent each time a device is added/removed or the state of a given device changes (hex4 + content). This allows tools like DDMS to track the state of connected devices in real-time without polling the server repeatedly. host:emulator: 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 there 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-devpath Returns the device path of the corresponding device/emulator. :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. :forward:norebind:; Same as :forward:; except that it will fail it there is already a forward connection from . Used to implement 'adb forward --no-rebind ' :killforward: Remove any existing forward local connection from . This is used to implement 'adb forward --remove ' :killforward-all Remove all forward network connections. This is used to implement 'adb forward --remove-all'. :list-forward List all existing forward connections from this server. This returns something that looks like the following: : The length of the payload, as 4 hexadecimal chars. : A series of lines of the following format: " " " " "\n" Where is a device serial number. is the host-specific endpoint (e.g. tcp:9000). is the device-specific endpoint. Used to implement 'adb forward --list'. LOCAL SERVICES: All the queries below assumed that you already switched the transport to a real device, or that you have used a query prefix as described above. shell:command arg1 arg2 ... Run 'command arg1 arg2 ...' in a shell on the device, and return its output and error streams. Note that arguments must be separated by spaces. If an argument contains a space, it must be quoted with double-quotes. Arguments cannot contain double quotes or things will go very wrong. Note that this is the non-interactive version of "adb shell" shell: Start an interactive shell session on the device. Redirect stdin/stdout/stderr as appropriate. Note that the ADB server uses this to implement "adb shell", but will also cook the input before sending it to the device (see interactive_shell() in commandline.c) remount: Ask adbd to remount the device's filesystem in read-write mode, instead of read-only. This is usually necessary before performing an "adb sync" or "adb push" request. This request may not succeed on certain builds which do not allow that. dev: Opens a device file and connects the client directly to it for read/write purposes. Useful for debugging, but may require special privileges and thus may not run on all devices. 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. framebuffer: This service is used to send snapshots of the framebuffer to a client. It requires sufficient privileges but works as follow: After the OKAY, the service sends 16-byte binary structure containing the following fields (little-endian format): depth: uint32_t: framebuffer depth size: uint32_t: framebuffer size in bytes width: uint32_t: framebuffer width in pixels height: uint32_t: framebuffer height in pixels With the current implementation, depth is always 16, and size is always width*height*2 Then, each time the client wants a snapshot, it should send one byte through the channel, which will trigger the service to send it 'size' bytes of framebuffer data. If the adbd daemon doesn't have sufficient privileges to open the framebuffer device, the connection is simply closed immediately. jdwp: 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 reverse: This implements the 'adb reverse' feature, i.e. the ability to reverse socket connections from a device to the host. is one of the forwarding commands that are described above, as in: list-forward forward:; forward:norebind:; killforward-all killforward: Note that in this case, corresponds to the socket on the device and corresponds to the socket on the host. The output of reverse:list-forward is the same as host:list-forward except that will be just 'host'. android-tools-5.1.1r36+git20160322/core/adb/SYNC.TXT000066400000000000000000000070051267427243200210740ustar00rootroot00000000000000This file tries to document file related requests a client can make to the ADB server of an adbd daemon. See the OVERVIEW.TXT document to understand what's going on here. See the SERVICES.TXT to learn more about the other requests that are possible. SYNC SERVICES: Requesting the sync service ("sync:") using the protocol as described in SERVICES.TXT sets the connection in sync mode. This mode is a binary mode that differ from the regular adb protocol. The connection stays in sync mode until explicitly terminated (see below). After the initial "sync:" command is sent the server must respond with either "OKAY" or "FAIL" as per usual. In sync mode both the server and the client will frequently use eight-byte packets to communicate in this document called sync request and sync responses. The first four bytes is an id and specifies sync request is represented by four utf-8 characters. The last four bytes is a Little-Endian integer, with various uses. This number will be called "length" below. In fact all binary integers are Little-Endian in the sync mode. Sync mode is implicitly exited after each sync request, and normal adb communication follows as described in SERVICES.TXT. The following sync requests are accepted: LIST - List the files in a folder SEND - Send a file to device RECV - Retreive a file from device Not yet documented: STAT - Stat a file ULNK - Unlink (remove) a file. (Not currently supported) For all of the sync request above the must be followed by length number of bytes containing an utf-8 string with a remote filename. LIST: Lists files in the directory specified by the remote filename. The server will respond with zero or more directory entries or "dents". The directory entries will be returned in the following form 1. A four-byte sync response id beeing "DENT" 2. A four-byte integer representing file mode. 3. A four-byte integer representing file size. 4. A four-byte integer representing last modified time. 5. A four-byte integer representing file name length. 6. length number of bytes containing an utf-8 string representing the file name. When an sync response "DONE" is received the listing is done. SEND: The remote file name is split into two parts separated by the last comma (","). The first part is the actual path, while the second is a decimal encoded file mode containing the permissions of the file on device. Note that some file types will be deleted before the copying starts, and if the transfer fails. Some file types will not be deleted, which allows adb push disk_image /some_block_device to work. After this the actual file is sent in chunks. Each chucks has the following format. A sync request with id "DATA" and length equal to the chunk size. After follows chunk size number of bytes. This is repeated until the file is transfered. Each chunk must not be larger than 64k. When the file is tranfered a sync request "DONE" is sent, where length is set to the last modified time for the file. The server responds to this last request (but not to chuck requests) with an "OKAY" sync response (length can be ignored). RECV: Retrieves a file from device to a local file. The remote path is the path to the file that will be returned. Just as for the SEND sync request the file received is split up into chunks. The sync response id is "DATA" and length is the chuck size. After follows chunk size number of bytes. This is repeated until the file is transfered. Each chuck will not be larger than 64k. When the file is transfered a sync resopnse "DONE" is retrieved where the length can be ignored. android-tools-5.1.1r36+git20160322/core/adb/adb.c000066400000000000000000001416551267427243200206230ustar00rootroot00000000000000/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define TRACE_TAG TRACE_ADB #include #include #include #include #include #include #include #include #include #include #include "sysdeps.h" #include "adb.h" #include "adb_auth.h" #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) #if !ADB_HOST #include #include #include #include #include #include #include #else #include "usb_vendors.h" #endif #if ADB_TRACE ADB_MUTEX_DEFINE( D_lock ); #endif int HOST = 0; int gListenAll = 0; static int auth_enabled = 0; #if !ADB_HOST static const char *adb_device_banner = "device"; static const char *root_seclabel = NULL; #endif void fatal(const char *fmt, ...) { va_list ap; va_start(ap, fmt); fprintf(stderr, "error: "); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); va_end(ap); exit(-1); } void fatal_errno(const char *fmt, ...) { va_list ap; va_start(ap, fmt); fprintf(stderr, "error: %s: ", strerror(errno)); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); va_end(ap); exit(-1); } int adb_trace_mask; /* read a comma/space/colum/semi-column separated list of tags * from the ADB_TRACE environment variable and build the trace * mask from it. note that '1' and 'all' are special cases to * enable all tracing */ void adb_trace_init(void) { const char* p = getenv("ADB_TRACE"); const char* q; static const struct { const char* tag; int flag; } tags[] = { { "1", 0 }, { "all", 0 }, { "adb", TRACE_ADB }, { "sockets", TRACE_SOCKETS }, { "packets", TRACE_PACKETS }, { "rwx", TRACE_RWX }, { "usb", TRACE_USB }, { "sync", TRACE_SYNC }, { "sysdeps", TRACE_SYSDEPS }, { "transport", TRACE_TRANSPORT }, { "jdwp", TRACE_JDWP }, { "services", TRACE_SERVICES }, { "auth", TRACE_AUTH }, { NULL, 0 } }; if (p == NULL) return; /* use a comma/column/semi-colum/space separated list */ while (*p) { int len, tagn; q = strpbrk(p, " ,:;"); if (q == NULL) { q = p + strlen(p); } len = q - p; for (tagn = 0; tags[tagn].tag != NULL; tagn++) { int taglen = strlen(tags[tagn].tag); if (len == taglen && !memcmp(tags[tagn].tag, p, len) ) { int flag = tags[tagn].flag; if (flag == 0) { adb_trace_mask = ~0; return; } adb_trace_mask |= (1 << flag); break; } } p = q; if (*p) p++; } } #if !ADB_HOST /* * Implements ADB tracing inside the emulator. */ #include /* * Redefine open and write for qemu_pipe.h that contains inlined references * to those routines. We will redifine them back after qemu_pipe.h inclusion. */ #undef open #undef write #define open adb_open #define write adb_write #include #undef open #undef write #define open ___xxx_open #define write ___xxx_write /* A handle to adb-debug qemud service in the emulator. */ int adb_debug_qemu = -1; /* Initializes connection with the adb-debug qemud service in the emulator. */ static int adb_qemu_trace_init(void) { char con_name[32]; if (adb_debug_qemu >= 0) { return 0; } /* adb debugging QEMUD service connection request. */ snprintf(con_name, sizeof(con_name), "qemud:adb-debug"); adb_debug_qemu = qemu_pipe_open(con_name); return (adb_debug_qemu >= 0) ? 0 : -1; } void adb_qemu_trace(const char* fmt, ...) { va_list args; va_start(args, fmt); char msg[1024]; if (adb_debug_qemu >= 0) { vsnprintf(msg, sizeof(msg), fmt, args); adb_write(adb_debug_qemu, msg, strlen(msg)); } } #endif /* !ADB_HOST */ apacket *get_apacket(void) { apacket *p = malloc(sizeof(apacket)); if(p == 0) fatal("failed to allocate an apacket"); memset(p, 0, sizeof(apacket) - MAX_PAYLOAD); return p; } void put_apacket(apacket *p) { free(p); } void handle_online(atransport *t) { D("adb: online\n"); t->online = 1; } void handle_offline(atransport *t) { D("adb: offline\n"); //Close the associated usb t->online = 0; run_transport_disconnects(t); } #if DEBUG_PACKETS #define DUMPMAX 32 void print_packet(const char *label, apacket *p) { char *tag; char *x; unsigned count; switch(p->msg.command){ case A_SYNC: tag = "SYNC"; break; case A_CNXN: tag = "CNXN" ; break; case A_OPEN: tag = "OPEN"; break; case A_OKAY: tag = "OKAY"; break; case A_CLSE: tag = "CLSE"; break; case A_WRTE: tag = "WRTE"; break; case A_AUTH: tag = "AUTH"; break; default: tag = "????"; break; } fprintf(stderr, "%s: %s %08x %08x %04x \"", label, tag, p->msg.arg0, p->msg.arg1, p->msg.data_length); count = p->msg.data_length; x = (char*) p->data; if(count > DUMPMAX) { count = DUMPMAX; tag = "\n"; } else { tag = "\"\n"; } while(count-- > 0){ if((*x >= ' ') && (*x < 127)) { fputc(*x, stderr); } else { fputc('.', stderr); } x++; } fputs(tag, stderr); } #endif static void send_ready(unsigned local, unsigned remote, atransport *t) { D("Calling send_ready \n"); apacket *p = get_apacket(); p->msg.command = A_OKAY; p->msg.arg0 = local; p->msg.arg1 = remote; send_packet(p, t); } static void send_close(unsigned local, unsigned remote, atransport *t) { D("Calling send_close \n"); apacket *p = get_apacket(); p->msg.command = A_CLSE; p->msg.arg0 = local; p->msg.arg1 = remote; send_packet(p, t); } static size_t fill_connect_data(char *buf, size_t bufsize) { #if ADB_HOST return snprintf(buf, bufsize, "host::") + 1; #else static const char *cnxn_props[] = { "ro.product.name", "ro.product.model", "ro.product.device", }; static const int num_cnxn_props = ARRAY_SIZE(cnxn_props); int i; size_t remaining = bufsize; size_t len; len = snprintf(buf, remaining, "%s::", adb_device_banner); remaining -= len; buf += len; for (i = 0; i < num_cnxn_props; i++) { char value[PROPERTY_VALUE_MAX]; property_get(cnxn_props[i], value, ""); len = snprintf(buf, remaining, "%s=%s;", cnxn_props[i], value); remaining -= len; buf += len; } return bufsize - remaining + 1; #endif } #if !ADB_HOST static void send_msg_with_header(int fd, const char* msg, size_t msglen) { char header[5]; if (msglen > 0xffff) msglen = 0xffff; snprintf(header, sizeof(header), "%04x", (unsigned)msglen); writex(fd, header, 4); writex(fd, msg, msglen); } #endif static void send_msg_with_okay(int fd, const char* msg, size_t msglen) { char header[9]; if (msglen > 0xffff) msglen = 0xffff; snprintf(header, sizeof(header), "OKAY%04x", (unsigned)msglen); writex(fd, header, 8); writex(fd, msg, msglen); } static void send_connect(atransport *t) { D("Calling send_connect \n"); apacket *cp = get_apacket(); cp->msg.command = A_CNXN; cp->msg.arg0 = A_VERSION; cp->msg.arg1 = MAX_PAYLOAD; cp->msg.data_length = fill_connect_data((char *)cp->data, sizeof(cp->data)); send_packet(cp, t); } void send_auth_request(atransport *t) { D("Calling send_auth_request\n"); apacket *p; int ret; ret = adb_auth_generate_token(t->token, sizeof(t->token)); if (ret != sizeof(t->token)) { D("Error generating token ret=%d\n", ret); return; } p = get_apacket(); memcpy(p->data, t->token, ret); p->msg.command = A_AUTH; p->msg.arg0 = ADB_AUTH_TOKEN; p->msg.data_length = ret; send_packet(p, t); } static void send_auth_response(uint8_t *token, size_t token_size, atransport *t) { D("Calling send_auth_response\n"); apacket *p = get_apacket(); int ret; ret = adb_auth_sign(t->key, token, token_size, p->data); if (!ret) { D("Error signing the token\n"); put_apacket(p); return; } p->msg.command = A_AUTH; p->msg.arg0 = ADB_AUTH_SIGNATURE; p->msg.data_length = ret; send_packet(p, t); } static void send_auth_publickey(atransport *t) { D("Calling send_auth_publickey\n"); apacket *p = get_apacket(); int ret; ret = adb_auth_get_userkey(p->data, sizeof(p->data)); if (!ret) { D("Failed to get user public key\n"); put_apacket(p); return; } p->msg.command = A_AUTH; p->msg.arg0 = ADB_AUTH_RSAPUBLICKEY; p->msg.data_length = ret; send_packet(p, t); } void adb_auth_verified(atransport *t) { handle_online(t); send_connect(t); } static char *connection_state_name(atransport *t) { if (t == NULL) { return "unknown"; } switch(t->connection_state) { case CS_BOOTLOADER: return "bootloader"; case CS_DEVICE: return "device"; case CS_RECOVERY: return "recovery"; case CS_SIDELOAD: return "sideload"; case CS_OFFLINE: return "offline"; case CS_UNAUTHORIZED: return "unauthorized"; default: return "unknown"; } } /* qual_overwrite is used to overwrite a qualifier string. dst is a * pointer to a char pointer. It is assumed that if *dst is non-NULL, it * was malloc'ed and needs to freed. *dst will be set to a dup of src. */ static void qual_overwrite(char **dst, const char *src) { if (!dst) return; free(*dst); *dst = NULL; if (!src || !*src) return; *dst = strdup(src); } void parse_banner(char *banner, atransport *t) { static const char *prop_seps = ";"; static const char key_val_sep = '='; char *cp; char *type; D("parse_banner: %s\n", banner); type = banner; cp = strchr(type, ':'); if (cp) { *cp++ = 0; /* Nothing is done with second field. */ cp = strchr(cp, ':'); if (cp) { char *save; char *key; key = adb_strtok_r(cp + 1, prop_seps, &save); while (key) { cp = strchr(key, key_val_sep); if (cp) { *cp++ = '\0'; if (!strcmp(key, "ro.product.name")) qual_overwrite(&t->product, cp); else if (!strcmp(key, "ro.product.model")) qual_overwrite(&t->model, cp); else if (!strcmp(key, "ro.product.device")) qual_overwrite(&t->device, cp); } key = adb_strtok_r(NULL, prop_seps, &save); } } } if(!strcmp(type, "bootloader")){ D("setting connection_state to CS_BOOTLOADER\n"); t->connection_state = CS_BOOTLOADER; update_transports(); return; } if(!strcmp(type, "device")) { D("setting connection_state to CS_DEVICE\n"); t->connection_state = CS_DEVICE; update_transports(); return; } if(!strcmp(type, "recovery")) { D("setting connection_state to CS_RECOVERY\n"); t->connection_state = CS_RECOVERY; update_transports(); return; } if(!strcmp(type, "sideload")) { D("setting connection_state to CS_SIDELOAD\n"); t->connection_state = CS_SIDELOAD; update_transports(); return; } t->connection_state = CS_HOST; } void handle_packet(apacket *p, atransport *t) { asocket *s; D("handle_packet() %c%c%c%c\n", ((char*) (&(p->msg.command)))[0], ((char*) (&(p->msg.command)))[1], ((char*) (&(p->msg.command)))[2], ((char*) (&(p->msg.command)))[3]); print_packet("recv", p); switch(p->msg.command){ case A_SYNC: if(p->msg.arg0){ send_packet(p, t); if(HOST) send_connect(t); } else { t->connection_state = CS_OFFLINE; handle_offline(t); send_packet(p, t); } return; case A_CNXN: /* CONNECT(version, maxdata, "system-id-string") */ /* XXX verify version, etc */ if(t->connection_state != CS_OFFLINE) { t->connection_state = CS_OFFLINE; handle_offline(t); } parse_banner((char*) p->data, t); if (HOST || !auth_enabled) { handle_online(t); if(!HOST) send_connect(t); } else { send_auth_request(t); } break; case A_AUTH: if (p->msg.arg0 == ADB_AUTH_TOKEN) { t->connection_state = CS_UNAUTHORIZED; t->key = adb_auth_nextkey(t->key); if (t->key) { send_auth_response(p->data, p->msg.data_length, t); } else { /* No more private keys to try, send the public key */ send_auth_publickey(t); } } else if (p->msg.arg0 == ADB_AUTH_SIGNATURE) { if (adb_auth_verify(t->token, p->data, p->msg.data_length)) { adb_auth_verified(t); t->failed_auth_attempts = 0; } else { if (t->failed_auth_attempts++ > 10) adb_sleep_ms(1000); send_auth_request(t); } } else if (p->msg.arg0 == ADB_AUTH_RSAPUBLICKEY) { adb_auth_confirm_key(p->data, p->msg.data_length, t); } break; case A_OPEN: /* OPEN(local-id, 0, "destination") */ if (t->online && p->msg.arg0 != 0 && p->msg.arg1 == 0) { char *name = (char*) p->data; name[p->msg.data_length > 0 ? p->msg.data_length - 1 : 0] = 0; s = create_local_service_socket(name); if(s == 0) { send_close(0, p->msg.arg0, t); } else { s->peer = create_remote_socket(p->msg.arg0, t); s->peer->peer = s; send_ready(s->id, s->peer->id, t); s->ready(s); } } break; case A_OKAY: /* READY(local-id, remote-id, "") */ if (t->online && p->msg.arg0 != 0 && p->msg.arg1 != 0) { if((s = find_local_socket(p->msg.arg1, 0))) { if(s->peer == 0) { /* On first READY message, create the connection. */ s->peer = create_remote_socket(p->msg.arg0, t); s->peer->peer = s; s->ready(s); } else if (s->peer->id == p->msg.arg0) { /* Other READY messages must use the same local-id */ s->ready(s); } else { D("Invalid A_OKAY(%d,%d), expected A_OKAY(%d,%d) on transport %s\n", p->msg.arg0, p->msg.arg1, s->peer->id, p->msg.arg1, t->serial); } } } break; case A_CLSE: /* CLOSE(local-id, remote-id, "") or CLOSE(0, remote-id, "") */ if (t->online && p->msg.arg1 != 0) { if((s = find_local_socket(p->msg.arg1, p->msg.arg0))) { /* According to protocol.txt, p->msg.arg0 might be 0 to indicate * a failed OPEN only. However, due to a bug in previous ADB * versions, CLOSE(0, remote-id, "") was also used for normal * CLOSE() operations. * * This is bad because it means a compromised adbd could * send packets to close connections between the host and * other devices. To avoid this, only allow this if the local * socket has a peer on the same transport. */ if (p->msg.arg0 == 0 && s->peer && s->peer->transport != t) { D("Invalid A_CLSE(0, %u) from transport %s, expected transport %s\n", p->msg.arg1, t->serial, s->peer->transport->serial); } else { s->close(s); } } } break; case A_WRTE: /* WRITE(local-id, remote-id, ) */ if (t->online && p->msg.arg0 != 0 && p->msg.arg1 != 0) { if((s = find_local_socket(p->msg.arg1, p->msg.arg0))) { unsigned rid = p->msg.arg0; p->len = p->msg.data_length; if(s->enqueue(s, p) == 0) { D("Enqueue the socket\n"); send_ready(s->id, rid, t); } return; } } break; default: printf("handle_packet: what is %08x?!\n", p->msg.command); } put_apacket(p); } alistener listener_list = { .next = &listener_list, .prev = &listener_list, }; static void ss_listener_event_func(int _fd, unsigned ev, void *_l) { asocket *s; if(ev & FDE_READ) { struct sockaddr addr; socklen_t alen; int fd; alen = sizeof(addr); fd = adb_socket_accept(_fd, &addr, &alen); if(fd < 0) return; adb_socket_setbufsize(fd, CHUNK_SIZE); s = create_local_socket(fd); if(s) { connect_to_smartsocket(s); return; } adb_close(fd); } } static void listener_event_func(int _fd, unsigned ev, void *_l) { alistener *l = _l; asocket *s; if(ev & FDE_READ) { struct sockaddr addr; socklen_t alen; int fd; alen = sizeof(addr); fd = adb_socket_accept(_fd, &addr, &alen); if(fd < 0) return; s = create_local_socket(fd); if(s) { s->transport = l->transport; connect_to_remote(s, l->connect_to); return; } adb_close(fd); } } static void free_listener(alistener* l) { if (l->next) { l->next->prev = l->prev; l->prev->next = l->next; l->next = l->prev = l; } // closes the corresponding fd fdevent_remove(&l->fde); if (l->local_name) free((char*)l->local_name); if (l->connect_to) free((char*)l->connect_to); if (l->transport) { remove_transport_disconnect(l->transport, &l->disconnect); } free(l); } static void listener_disconnect(void* _l, atransport* t) { alistener* l = _l; free_listener(l); } int local_name_to_fd(const char *name) { int port; if(!strncmp("tcp:", name, 4)){ int ret; port = atoi(name + 4); if (gListenAll > 0) { ret = socket_inaddr_any_server(port, SOCK_STREAM); } else { ret = socket_loopback_server(port, SOCK_STREAM); } return ret; } #ifndef HAVE_WIN32_IPC /* no Unix-domain sockets on Win32 */ // It's non-sensical to support the "reserved" space on the adb host side if(!strncmp(name, "local:", 6)) { return socket_local_server(name + 6, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM); } else if(!strncmp(name, "localabstract:", 14)) { return socket_local_server(name + 14, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM); } else if(!strncmp(name, "localfilesystem:", 16)) { return socket_local_server(name + 16, ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM); } #endif printf("unknown local portname '%s'\n", name); return -1; } // Write a single line describing a listener to a user-provided buffer. // Appends a trailing zero, even in case of truncation, but the function // returns the full line length. // If |buffer| is NULL, does not write but returns required size. static int format_listener(alistener* l, char* buffer, size_t buffer_len) { // Format is simply: // // " " " " "\n" // int local_len = strlen(l->local_name); int connect_len = strlen(l->connect_to); int serial_len = strlen(l->transport->serial); if (buffer != NULL) { snprintf(buffer, buffer_len, "%s %s %s\n", l->transport->serial, l->local_name, l->connect_to); } // NOTE: snprintf() on Windows returns -1 in case of truncation, so // return the computed line length instead. return local_len + connect_len + serial_len + 3; } // Write the list of current listeners (network redirections) into a // user-provided buffer. Appends a trailing zero, even in case of // trunctaion, but return the full size in bytes. // If |buffer| is NULL, does not write but returns required size. static int format_listeners(char* buf, size_t buflen) { alistener* l; int result = 0; for (l = listener_list.next; l != &listener_list; l = l->next) { // Ignore special listeners like those for *smartsocket* if (l->connect_to[0] == '*') continue; int len = format_listener(l, buf, buflen); // Ensure there is space for the trailing zero. result += len; if (buf != NULL) { buf += len; buflen -= len; if (buflen <= 0) break; } } return result; } static int remove_listener(const char *local_name, atransport* transport) { alistener *l; for (l = listener_list.next; l != &listener_list; l = l->next) { if (!strcmp(local_name, l->local_name)) { listener_disconnect(l, l->transport); return 0; } } return -1; } static void remove_all_listeners(void) { alistener *l, *l_next; for (l = listener_list.next; l != &listener_list; l = l_next) { l_next = l->next; // Never remove smart sockets. if (l->connect_to[0] == '*') continue; listener_disconnect(l, l->transport); } } // error/status codes for install_listener. typedef enum { INSTALL_STATUS_OK = 0, INSTALL_STATUS_INTERNAL_ERROR = -1, INSTALL_STATUS_CANNOT_BIND = -2, INSTALL_STATUS_CANNOT_REBIND = -3, } install_status_t; static install_status_t install_listener(const char *local_name, const char *connect_to, atransport* transport, int no_rebind) { alistener *l; //printf("install_listener('%s','%s')\n", local_name, connect_to); for(l = listener_list.next; l != &listener_list; l = l->next){ if(strcmp(local_name, l->local_name) == 0) { char *cto; /* can't repurpose a smartsocket */ if(l->connect_to[0] == '*') { return INSTALL_STATUS_INTERNAL_ERROR; } /* can't repurpose a listener if 'no_rebind' is true */ if (no_rebind) { return INSTALL_STATUS_CANNOT_REBIND; } cto = strdup(connect_to); if(cto == 0) { return INSTALL_STATUS_INTERNAL_ERROR; } //printf("rebinding '%s' to '%s'\n", local_name, connect_to); free((void*) l->connect_to); l->connect_to = cto; if (l->transport != transport) { remove_transport_disconnect(l->transport, &l->disconnect); l->transport = transport; add_transport_disconnect(l->transport, &l->disconnect); } return INSTALL_STATUS_OK; } } if((l = calloc(1, sizeof(alistener))) == 0) goto nomem; if((l->local_name = strdup(local_name)) == 0) goto nomem; if((l->connect_to = strdup(connect_to)) == 0) goto nomem; l->fd = local_name_to_fd(local_name); if(l->fd < 0) { free((void*) l->local_name); free((void*) l->connect_to); free(l); printf("cannot bind '%s'\n", local_name); return -2; } close_on_exec(l->fd); if(!strcmp(l->connect_to, "*smartsocket*")) { fdevent_install(&l->fde, l->fd, ss_listener_event_func, l); } else { fdevent_install(&l->fde, l->fd, listener_event_func, l); } fdevent_set(&l->fde, FDE_READ); l->next = &listener_list; l->prev = listener_list.prev; l->next->prev = l; l->prev->next = l; l->transport = transport; if (transport) { l->disconnect.opaque = l; l->disconnect.func = listener_disconnect; add_transport_disconnect(transport, &l->disconnect); } return INSTALL_STATUS_OK; nomem: fatal("cannot allocate listener"); return INSTALL_STATUS_INTERNAL_ERROR; } #ifdef HAVE_WIN32_PROC static BOOL WINAPI ctrlc_handler(DWORD type) { exit(STATUS_CONTROL_C_EXIT); return TRUE; } #endif static void adb_cleanup(void) { usb_cleanup(); } void start_logging(void) { #ifdef HAVE_WIN32_PROC char temp[ MAX_PATH ]; FILE* fnul; FILE* flog; GetTempPath( sizeof(temp) - 8, temp ); strcat( temp, "adb.log" ); /* Win32 specific redirections */ fnul = fopen( "NUL", "rt" ); if (fnul != NULL) stdin[0] = fnul[0]; flog = fopen( temp, "at" ); if (flog == NULL) flog = fnul; setvbuf( flog, NULL, _IONBF, 0 ); stdout[0] = flog[0]; stderr[0] = flog[0]; fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid()); #else int fd; fd = unix_open("/dev/null", O_RDONLY); dup2(fd, 0); adb_close(fd); fd = unix_open("/tmp/adb.log", O_WRONLY | O_CREAT | O_APPEND, 0640); if(fd < 0) { fd = unix_open("/dev/null", O_WRONLY); } dup2(fd, 1); dup2(fd, 2); adb_close(fd); fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid()); #endif } #if !ADB_HOST void start_device_log(void) { int fd; char path[PATH_MAX]; struct tm now; time_t t; char value[PROPERTY_VALUE_MAX]; // read the trace mask from persistent property persist.adb.trace_mask // give up if the property is not set or cannot be parsed property_get("persist.adb.trace_mask", value, ""); if (sscanf(value, "%x", &adb_trace_mask) != 1) return; adb_mkdir("/data/adb", 0775); tzset(); time(&t); localtime_r(&t, &now); strftime(path, sizeof(path), "/data/adb/adb-%Y-%m-%d-%H-%M-%S.txt", &now); fd = unix_open(path, O_WRONLY | O_CREAT | O_TRUNC, 0640); if (fd < 0) return; // redirect stdout and stderr to the log file dup2(fd, 1); dup2(fd, 2); fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid()); adb_close(fd); fd = unix_open("/dev/null", O_RDONLY); dup2(fd, 0); adb_close(fd); } #endif #if ADB_HOST #ifdef WORKAROUND_BUG6558362 #include #define AFFINITY_ENVVAR "ADB_CPU_AFFINITY_BUG6558362" void adb_set_affinity(void) { cpu_set_t cpu_set; const char* cpunum_str = getenv(AFFINITY_ENVVAR); char* strtol_res; int cpu_num; if (!cpunum_str || !*cpunum_str) return; cpu_num = strtol(cpunum_str, &strtol_res, 0); if (*strtol_res != '\0') fatal("bad number (%s) in env var %s. Expecting 0..n.\n", cpunum_str, AFFINITY_ENVVAR); sched_getaffinity(0, sizeof(cpu_set), &cpu_set); D("orig cpu_set[0]=0x%08lx\n", cpu_set.__bits[0]); CPU_ZERO(&cpu_set); CPU_SET(cpu_num, &cpu_set); sched_setaffinity(0, sizeof(cpu_set), &cpu_set); sched_getaffinity(0, sizeof(cpu_set), &cpu_set); D("new cpu_set[0]=0x%08lx\n", cpu_set.__bits[0]); } #endif int launch_server(int server_port) { #ifdef HAVE_WIN32_PROC /* we need to start the server in the background */ /* we create a PIPE that will be used to wait for the server's "OK" */ /* message since the pipe handles must be inheritable, we use a */ /* security attribute */ HANDLE pipe_read, pipe_write; HANDLE stdout_handle, stderr_handle; SECURITY_ATTRIBUTES sa; STARTUPINFO startup; PROCESS_INFORMATION pinfo; char program_path[ MAX_PATH ]; int ret; sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; /* create pipe, and ensure its read handle isn't inheritable */ ret = CreatePipe( &pipe_read, &pipe_write, &sa, 0 ); if (!ret) { fprintf(stderr, "CreatePipe() failure, error %ld\n", GetLastError() ); return -1; } SetHandleInformation( pipe_read, HANDLE_FLAG_INHERIT, 0 ); /* Some programs want to launch an adb command and collect its output by * calling CreateProcess with inheritable stdout/stderr handles, then * using read() to get its output. When this happens, the stdout/stderr * handles passed to the adb client process will also be inheritable. * When starting the adb server here, care must be taken to reset them * to non-inheritable. * Otherwise, something bad happens: even if the adb command completes, * the calling process is stuck while read()-ing from the stdout/stderr * descriptors, because they're connected to corresponding handles in the * adb server process (even if the latter never uses/writes to them). */ stdout_handle = GetStdHandle( STD_OUTPUT_HANDLE ); stderr_handle = GetStdHandle( STD_ERROR_HANDLE ); if (stdout_handle != INVALID_HANDLE_VALUE) { SetHandleInformation( stdout_handle, HANDLE_FLAG_INHERIT, 0 ); } if (stderr_handle != INVALID_HANDLE_VALUE) { SetHandleInformation( stderr_handle, HANDLE_FLAG_INHERIT, 0 ); } ZeroMemory( &startup, sizeof(startup) ); startup.cb = sizeof(startup); startup.hStdInput = GetStdHandle( STD_INPUT_HANDLE ); startup.hStdOutput = pipe_write; startup.hStdError = GetStdHandle( STD_ERROR_HANDLE ); startup.dwFlags = STARTF_USESTDHANDLES; ZeroMemory( &pinfo, sizeof(pinfo) ); /* get path of current program */ GetModuleFileName( NULL, program_path, sizeof(program_path) ); ret = CreateProcess( program_path, /* program path */ "adb fork-server server", /* the fork-server argument will set the debug = 2 in the child */ NULL, /* process handle is not inheritable */ NULL, /* thread handle is not inheritable */ TRUE, /* yes, inherit some handles */ DETACHED_PROCESS, /* the new process doesn't have a console */ NULL, /* use parent's environment block */ NULL, /* use parent's starting directory */ &startup, /* startup info, i.e. std handles */ &pinfo ); CloseHandle( pipe_write ); if (!ret) { fprintf(stderr, "CreateProcess failure, error %ld\n", GetLastError() ); CloseHandle( pipe_read ); return -1; } CloseHandle( pinfo.hProcess ); CloseHandle( pinfo.hThread ); /* wait for the "OK\n" message */ { char temp[3]; DWORD count; ret = ReadFile( pipe_read, temp, 3, &count, NULL ); CloseHandle( pipe_read ); if ( !ret ) { fprintf(stderr, "could not read ok from ADB Server, error = %ld\n", GetLastError() ); return -1; } if (count != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') { fprintf(stderr, "ADB server didn't ACK\n" ); return -1; } } #elif defined(HAVE_FORKEXEC) char path[PATH_MAX]; int fd[2]; // set up a pipe so the child can tell us when it is ready. // fd[0] will be parent's end, and fd[1] will get mapped to stderr in the child. if (pipe(fd)) { fprintf(stderr, "pipe failed in launch_server, errno: %d\n", errno); return -1; } get_my_path(path, PATH_MAX); pid_t pid = fork(); if(pid < 0) return -1; if (pid == 0) { // child side of the fork // redirect stderr to the pipe // we use stderr instead of stdout due to stdout's buffering behavior. adb_close(fd[0]); dup2(fd[1], STDERR_FILENO); adb_close(fd[1]); char str_port[30]; snprintf(str_port, sizeof(str_port), "%d", server_port); // child process int result = execl(path, "adb", "-P", str_port, "fork-server", "server", NULL); // this should not return fprintf(stderr, "OOPS! execl returned %d, errno: %d\n", result, errno); } else { // parent side of the fork char temp[3]; temp[0] = 'A'; temp[1] = 'B'; temp[2] = 'C'; // wait for the "OK\n" message adb_close(fd[1]); int ret = adb_read(fd[0], temp, 3); int saved_errno = errno; adb_close(fd[0]); if (ret < 0) { fprintf(stderr, "could not read ok from ADB Server, errno = %d\n", saved_errno); return -1; } if (ret != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') { fprintf(stderr, "ADB server didn't ACK\n" ); return -1; } setsid(); } #else #error "cannot implement background server start on this platform" #endif return 0; } #endif /* Constructs a local name of form tcp:port. * target_str points to the target string, it's content will be overwritten. * target_size is the capacity of the target string. * server_port is the port number to use for the local name. */ void build_local_name(char* target_str, size_t target_size, int server_port) { snprintf(target_str, target_size, "tcp:%d", server_port); } #if !ADB_HOST static void drop_capabilities_bounding_set_if_needed() { #ifdef ALLOW_ADBD_ROOT char value[PROPERTY_VALUE_MAX]; property_get("ro.debuggable", value, ""); if (strcmp(value, "1") == 0) { return; } #endif int i; for (i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0; i++) { if (i == CAP_SETUID || i == CAP_SETGID) { // CAP_SETUID CAP_SETGID needed by /system/bin/run-as continue; } int err = prctl(PR_CAPBSET_DROP, i, 0, 0, 0); // Some kernels don't have file capabilities compiled in, and // prctl(PR_CAPBSET_DROP) returns EINVAL. Don't automatically // die when we see such misconfigured kernels. if ((err < 0) && (errno != EINVAL)) { exit(1); } } } static int should_drop_privileges() { #ifndef ALLOW_ADBD_ROOT return 1; #else /* ALLOW_ADBD_ROOT */ int secure = 0; char value[PROPERTY_VALUE_MAX]; /* run adbd in secure mode if ro.secure is set and ** we are not in the emulator */ property_get("ro.kernel.qemu", value, ""); if (strcmp(value, "1") != 0) { property_get("ro.secure", value, "1"); if (strcmp(value, "1") == 0) { // don't run as root if ro.secure is set... secure = 1; // ... except we allow running as root in userdebug builds if the // service.adb.root property has been set by the "adb root" command property_get("ro.debuggable", value, ""); if (strcmp(value, "1") == 0) { property_get("service.adb.root", value, ""); if (strcmp(value, "1") == 0) { secure = 0; } } } } return secure; #endif /* ALLOW_ADBD_ROOT */ } #endif /* !ADB_HOST */ int adb_main(int is_daemon, int server_port) { #if !ADB_HOST int port; char value[PROPERTY_VALUE_MAX]; umask(000); #endif atexit(adb_cleanup); #ifdef HAVE_WIN32_PROC SetConsoleCtrlHandler( ctrlc_handler, TRUE ); #elif defined(HAVE_FORKEXEC) // No SIGCHLD. Let the service subproc handle its children. signal(SIGPIPE, SIG_IGN); #endif init_transport_registration(); #if ADB_HOST HOST = 1; #ifdef WORKAROUND_BUG6558362 if(is_daemon) adb_set_affinity(); #endif usb_vendors_init(); usb_init(); local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT); adb_auth_init(); char local_name[30]; build_local_name(local_name, sizeof(local_name), server_port); if(install_listener(local_name, "*smartsocket*", NULL, 0)) { exit(1); } #else property_get("ro.adb.secure", value, "0"); auth_enabled = !strcmp(value, "1"); if (auth_enabled) adb_auth_init(); // Our external storage path may be different than apps, since // we aren't able to bind mount after dropping root. const char* adb_external_storage = getenv("ADB_EXTERNAL_STORAGE"); if (NULL != adb_external_storage) { setenv("EXTERNAL_STORAGE", adb_external_storage, 1); } else { D("Warning: ADB_EXTERNAL_STORAGE is not set. Leaving EXTERNAL_STORAGE" " unchanged.\n"); } /* add extra groups: ** AID_ADB to access the USB driver ** AID_LOG to read system logs (adb logcat) ** AID_INPUT to diagnose input issues (getevent) ** AID_INET to diagnose network issues (netcfg, ping) ** AID_GRAPHICS to access the frame buffer ** AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump) ** AID_SDCARD_R to allow reading from the SD card ** AID_SDCARD_RW to allow writing to the SD card ** AID_NET_BW_STATS to read out qtaguid statistics */ gid_t groups[] = { AID_ADB, AID_LOG, AID_INPUT, AID_INET, AID_GRAPHICS, AID_NET_BT, AID_NET_BT_ADMIN, AID_SDCARD_R, AID_SDCARD_RW, AID_NET_BW_STATS }; if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) { exit(1); } /* don't listen on a port (default 5037) if running in secure mode */ /* don't run as root if we are running in secure mode */ if (should_drop_privileges()) { drop_capabilities_bounding_set_if_needed(); /* then switch user and group to "shell" */ if (setgid(AID_SHELL) != 0) { exit(1); } if (setuid(AID_SHELL) != 0) { exit(1); } D("Local port disabled\n"); } else { char local_name[30]; if ((root_seclabel != NULL) && (is_selinux_enabled() > 0)) { // b/12587913: fix setcon to allow const pointers if (setcon((char *)root_seclabel) < 0) { exit(1); } } build_local_name(local_name, sizeof(local_name), server_port); if(install_listener(local_name, "*smartsocket*", NULL, 0)) { exit(1); } } int usb = 0; if (access(USB_ADB_PATH, F_OK) == 0 || access(USB_FFS_ADB_EP0, F_OK) == 0) { // listen on USB usb_init(); usb = 1; } // If one of these properties is set, also listen on that port // If one of the properties isn't set and we couldn't listen on usb, // listen on the default port. property_get("service.adb.tcp.port", value, ""); if (!value[0]) { property_get("persist.adb.tcp.port", value, ""); } if (sscanf(value, "%d", &port) == 1 && port > 0) { printf("using port=%d\n", port); // listen on TCP port specified by service.adb.tcp.port property local_init(port); } else if (!usb) { // listen on default port local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT); } D("adb_main(): pre init_jdwp()\n"); init_jdwp(); D("adb_main(): post init_jdwp()\n"); #endif if (is_daemon) { // inform our parent that we are up and running. #ifdef HAVE_WIN32_PROC DWORD count; WriteFile( GetStdHandle( STD_OUTPUT_HANDLE ), "OK\n", 3, &count, NULL ); #elif defined(HAVE_FORKEXEC) fprintf(stderr, "OK\n"); #endif start_logging(); } D("Event loop starting\n"); fdevent_loop(); usb_cleanup(); return 0; } // Try to handle a network forwarding request. // This returns 1 on success, 0 on failure, and -1 to indicate this is not // a forwarding-related request. int handle_forward_request(const char* service, transport_type ttype, char* serial, int reply_fd) { if (!strcmp(service, "list-forward")) { // Create the list of forward redirections. int buffer_size = format_listeners(NULL, 0); // Add one byte for the trailing zero. char* buffer = malloc(buffer_size + 1); if (buffer == NULL) { sendfailmsg(reply_fd, "not enough memory"); return 1; } (void) format_listeners(buffer, buffer_size + 1); #if ADB_HOST send_msg_with_okay(reply_fd, buffer, buffer_size); #else send_msg_with_header(reply_fd, buffer, buffer_size); #endif free(buffer); return 1; } if (!strcmp(service, "killforward-all")) { remove_all_listeners(); #if ADB_HOST /* On the host: 1st OKAY is connect, 2nd OKAY is status */ adb_write(reply_fd, "OKAY", 4); #endif adb_write(reply_fd, "OKAY", 4); return 1; } if (!strncmp(service, "forward:",8) || !strncmp(service, "killforward:",12)) { char *local, *remote, *err; int r; atransport *transport; int createForward = strncmp(service, "kill", 4); int no_rebind = 0; local = strchr(service, ':') + 1; // Handle forward:norebind:... here if (createForward && !strncmp(local, "norebind:", 9)) { no_rebind = 1; local = strchr(local, ':') + 1; } remote = strchr(local,';'); if (createForward) { // Check forward: parameter format: ';' if(remote == 0) { sendfailmsg(reply_fd, "malformed forward spec"); return 1; } *remote++ = 0; if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')) { sendfailmsg(reply_fd, "malformed forward spec"); return 1; } } else { // Check killforward: parameter format: '' if (local[0] == 0) { sendfailmsg(reply_fd, "malformed forward spec"); return 1; } } transport = acquire_one_transport(CS_ANY, ttype, serial, &err); if (!transport) { sendfailmsg(reply_fd, err); return 1; } if (createForward) { r = install_listener(local, remote, transport, no_rebind); } else { r = remove_listener(local, transport); } if(r == 0) { #if ADB_HOST /* On the host: 1st OKAY is connect, 2nd OKAY is status */ writex(reply_fd, "OKAY", 4); #endif writex(reply_fd, "OKAY", 4); return 1; } if (createForward) { const char* message; switch (r) { case INSTALL_STATUS_CANNOT_BIND: message = "cannot bind to socket"; break; case INSTALL_STATUS_CANNOT_REBIND: message = "cannot rebind existing socket"; break; default: message = "internal error"; } sendfailmsg(reply_fd, message); } else { sendfailmsg(reply_fd, "cannot remove listener"); } return 1; } return 0; } int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s) { atransport *transport = NULL; if(!strcmp(service, "kill")) { fprintf(stderr,"adb server killed by remote request\n"); fflush(stdout); adb_write(reply_fd, "OKAY", 4); usb_cleanup(); exit(0); } #if ADB_HOST // "transport:" is used for switching transport with a specified serial number // "transport-usb:" is used for switching transport to the only USB transport // "transport-local:" is used for switching transport to the only local transport // "transport-any:" is used for switching transport to the only transport if (!strncmp(service, "transport", strlen("transport"))) { char* error_string = "unknown failure"; transport_type type = kTransportAny; if (!strncmp(service, "transport-usb", strlen("transport-usb"))) { type = kTransportUsb; } else if (!strncmp(service, "transport-local", strlen("transport-local"))) { type = kTransportLocal; } else if (!strncmp(service, "transport-any", strlen("transport-any"))) { type = kTransportAny; } else if (!strncmp(service, "transport:", strlen("transport:"))) { service += strlen("transport:"); serial = service; } transport = acquire_one_transport(CS_ANY, type, serial, &error_string); if (transport) { s->transport = transport; adb_write(reply_fd, "OKAY", 4); } else { sendfailmsg(reply_fd, error_string); } return 1; } // return a list of all connected devices if (!strncmp(service, "devices", 7)) { char buffer[4096]; int use_long = !strcmp(service+7, "-l"); if (use_long || service[7] == 0) { memset(buffer, 0, sizeof(buffer)); D("Getting device list \n"); list_transports(buffer, sizeof(buffer), use_long); D("Wrote device list \n"); send_msg_with_okay(reply_fd, buffer, strlen(buffer)); return 0; } } // remove TCP transport if (!strncmp(service, "disconnect:", 11)) { char buffer[4096]; memset(buffer, 0, sizeof(buffer)); char* serial = service + 11; if (serial[0] == 0) { // disconnect from all TCP devices unregister_all_tcp_transports(); } else { char hostbuf[100]; // assume port 5555 if no port is specified if (!strchr(serial, ':')) { snprintf(hostbuf, sizeof(hostbuf) - 1, "%s:5555", serial); serial = hostbuf; } atransport *t = find_transport(serial); if (t) { unregister_transport(t); } else { snprintf(buffer, sizeof(buffer), "No such device %s", serial); } } send_msg_with_okay(reply_fd, buffer, strlen(buffer)); return 0; } // returns our value for ADB_SERVER_VERSION if (!strcmp(service, "version")) { char version[12]; snprintf(version, sizeof version, "%04x", ADB_SERVER_VERSION); send_msg_with_okay(reply_fd, version, strlen(version)); return 0; } if(!strncmp(service,"get-serialno",strlen("get-serialno"))) { char *out = "unknown"; transport = acquire_one_transport(CS_ANY, ttype, serial, NULL); if (transport && transport->serial) { out = transport->serial; } send_msg_with_okay(reply_fd, out, strlen(out)); return 0; } if(!strncmp(service,"get-devpath",strlen("get-devpath"))) { char *out = "unknown"; transport = acquire_one_transport(CS_ANY, ttype, serial, NULL); if (transport && transport->devpath) { out = transport->devpath; } send_msg_with_okay(reply_fd, out, strlen(out)); return 0; } // indicates a new emulator instance has started if (!strncmp(service,"emulator:",9)) { int port = atoi(service+9); local_connect(port); /* we don't even need to send a reply */ return 0; } if(!strncmp(service,"get-state",strlen("get-state"))) { transport = acquire_one_transport(CS_ANY, ttype, serial, NULL); char *state = connection_state_name(transport); send_msg_with_okay(reply_fd, state, strlen(state)); return 0; } #endif // ADB_HOST int ret = handle_forward_request(service, ttype, serial, reply_fd); if (ret >= 0) return ret - 1; return -1; } int main(int argc, char **argv) { #if ADB_HOST adb_sysdeps_init(); adb_trace_init(); D("Handling commandline()\n"); return adb_commandline(argc - 1, argv + 1); #else /* If adbd runs inside the emulator this will enable adb tracing via * adb-debug qemud service in the emulator. */ adb_qemu_trace_init(); while(1) { int c; int option_index = 0; static struct option opts[] = { {"root_seclabel", required_argument, 0, 's' }, {"device_banner", required_argument, 0, 'b' } }; c = getopt_long(argc, argv, "", opts, &option_index); if (c == -1) break; switch (c) { case 's': root_seclabel = optarg; break; case 'b': adb_device_banner = optarg; break; default: break; } } start_device_log(); D("Handling main()\n"); return adb_main(0, DEFAULT_ADB_PORT); #endif } android-tools-5.1.1r36+git20160322/core/adb/adb.h000066400000000000000000000275531267427243200206300ustar00rootroot00000000000000/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef __ADB_H #define __ADB_H #include #include "adb_trace.h" #include "transport.h" /* readx(), writex() */ #define MAX_PAYLOAD 4096 #define A_SYNC 0x434e5953 #define A_CNXN 0x4e584e43 #define A_OPEN 0x4e45504f #define A_OKAY 0x59414b4f #define A_CLSE 0x45534c43 #define A_WRTE 0x45545257 #define A_AUTH 0x48545541 #define A_VERSION 0x01000000 // ADB protocol version #define ADB_VERSION_MAJOR 1 // Used for help/version information #define ADB_VERSION_MINOR 0 // Used for help/version information #define ADB_SERVER_VERSION 32 // Increment this when we want to force users to start a new adb server typedef struct amessage amessage; typedef struct apacket apacket; typedef struct asocket asocket; typedef struct alistener alistener; typedef struct aservice aservice; typedef struct atransport atransport; typedef struct adisconnect adisconnect; typedef struct usb_handle usb_handle; struct amessage { unsigned command; /* command identifier constant */ unsigned arg0; /* first argument */ unsigned arg1; /* second argument */ unsigned data_length; /* length of payload (0 is allowed) */ unsigned data_check; /* checksum of data payload */ unsigned magic; /* command ^ 0xffffffff */ }; struct apacket { apacket *next; unsigned len; unsigned char *ptr; amessage msg; unsigned char data[MAX_PAYLOAD]; }; /* An asocket represents one half of a connection between a local and ** remote entity. A local asocket is bound to a file descriptor. A ** remote asocket is bound to the protocol engine. */ struct asocket { /* chain pointers for the local/remote list of ** asockets that this asocket lives in */ asocket *next; asocket *prev; /* the unique identifier for this asocket */ unsigned id; /* flag: set when the socket's peer has closed ** but packets are still queued for delivery */ int closing; /* flag: quit adbd when both ends close the ** local service socket */ int exit_on_close; /* the asocket we are connected to */ asocket *peer; /* For local asockets, the fde is used to bind ** us to our fd event system. For remote asockets ** these fields are not used. */ fdevent fde; int fd; /* queue of apackets waiting to be written */ apacket *pkt_first; apacket *pkt_last; /* enqueue is called by our peer when it has data ** for us. It should return 0 if we can accept more ** data or 1 if not. If we return 1, we must call ** peer->ready() when we once again are ready to ** receive data. */ int (*enqueue)(asocket *s, apacket *pkt); /* ready is called by the peer when it is ready for ** us to send data via enqueue again */ void (*ready)(asocket *s); /* shutdown is called by the peer before it goes away. ** the socket should not do any further calls on its peer. ** Always followed by a call to close. Optional, i.e. can be NULL. */ void (*shutdown)(asocket *s); /* close is called by the peer when it has gone away. ** we are not allowed to make any further calls on the ** peer once our close method is called. */ void (*close)(asocket *s); /* A socket is bound to atransport */ atransport *transport; }; /* the adisconnect structure is used to record a callback that ** will be called whenever a transport is disconnected (e.g. by the user) ** this should be used to cleanup objects that depend on the ** transport (e.g. remote sockets, listeners, etc...) */ struct adisconnect { void (*func)(void* opaque, atransport* t); void* opaque; adisconnect* next; adisconnect* prev; }; /* a transport object models the connection to a remote device or emulator ** there is one transport per connected device/emulator. a "local transport" ** connects through TCP (for the emulator), while a "usb transport" through ** USB (for real devices) ** ** note that kTransportHost doesn't really correspond to a real transport ** object, it's a special value used to indicate that a client wants to ** connect to a service implemented within the ADB server itself. */ typedef enum transport_type { kTransportUsb, kTransportLocal, kTransportAny, kTransportHost, } transport_type; #define TOKEN_SIZE 20 struct atransport { atransport *next; atransport *prev; int (*read_from_remote)(apacket *p, atransport *t); int (*write_to_remote)(apacket *p, atransport *t); void (*close)(atransport *t); void (*kick)(atransport *t); int fd; int transport_socket; fdevent transport_fde; int ref_count; unsigned sync_token; int connection_state; int online; transport_type type; /* usb handle or socket fd as needed */ usb_handle *usb; int sfd; /* used to identify transports for clients */ char *serial; char *product; char *model; char *device; char *devpath; int adb_port; // Use for emulators (local transport) /* a list of adisconnect callbacks called when the transport is kicked */ int kicked; adisconnect disconnects; void *key; unsigned char token[TOKEN_SIZE]; fdevent auth_fde; unsigned failed_auth_attempts; }; /* A listener is an entity which binds to a local port ** and, upon receiving a connection on that port, creates ** an asocket to connect the new local connection to a ** specific remote service. ** ** TODO: some listeners read from the new connection to ** determine what exact service to connect to on the far ** side. */ struct alistener { alistener *next; alistener *prev; fdevent fde; int fd; const char *local_name; const char *connect_to; atransport *transport; adisconnect disconnect; }; void print_packet(const char *label, apacket *p); asocket *find_local_socket(unsigned local_id, unsigned remote_id); void install_local_socket(asocket *s); void remove_socket(asocket *s); void close_all_sockets(atransport *t); #define LOCAL_CLIENT_PREFIX "emulator-" asocket *create_local_socket(int fd); asocket *create_local_service_socket(const char *destination); asocket *create_remote_socket(unsigned id, atransport *t); void connect_to_remote(asocket *s, const char *destination); void connect_to_smartsocket(asocket *s); void fatal(const char *fmt, ...); void fatal_errno(const char *fmt, ...); void handle_packet(apacket *p, atransport *t); void send_packet(apacket *p, atransport *t); void get_my_path(char *s, size_t maxLen); int launch_server(int server_port); int adb_main(int is_daemon, int server_port); /* transports are ref-counted ** get_device_transport does an acquire on your behalf before returning */ void init_transport_registration(void); int list_transports(char *buf, size_t bufsize, int long_listing); void update_transports(void); asocket* create_device_tracker(void); /* Obtain a transport from the available transports. ** If state is != CS_ANY, only transports in that state are considered. ** If serial is non-NULL then only the device with that serial will be chosen. ** If no suitable transport is found, error is set. */ atransport *acquire_one_transport(int state, transport_type ttype, const char* serial, char **error_out); void add_transport_disconnect( atransport* t, adisconnect* dis ); void remove_transport_disconnect( atransport* t, adisconnect* dis ); void run_transport_disconnects( atransport* t ); void kick_transport( atransport* t ); /* initialize a transport object's func pointers and state */ #if ADB_HOST int get_available_local_transport_index(); #endif int init_socket_transport(atransport *t, int s, int port, int local); void init_usb_transport(atransport *t, usb_handle *usb, int state); /* for MacOS X cleanup */ void close_usb_devices(); /* cause new transports to be init'd and added to the list */ int register_socket_transport(int s, const char *serial, int port, int local); /* these should only be used for the "adb disconnect" command */ void unregister_transport(atransport *t); void unregister_all_tcp_transports(); void register_usb_transport(usb_handle *h, const char *serial, const char *devpath, unsigned writeable); /* this should only be used for transports with connection_state == CS_NOPERM */ void unregister_usb_transport(usb_handle *usb); atransport *find_transport(const char *serial); #if ADB_HOST atransport* find_emulator_transport_by_adb_port(int adb_port); #endif int service_to_fd(const char *name); #if ADB_HOST asocket *host_service_to_socket(const char* name, const char *serial); #endif #if !ADB_HOST int init_jdwp(void); asocket* create_jdwp_service_socket(); asocket* create_jdwp_tracker_service_socket(); int create_jdwp_connection_fd(int jdwp_pid); #endif int handle_forward_request(const char* service, transport_type ttype, char* serial, int reply_fd); #if !ADB_HOST void framebuffer_service(int fd, void *cookie); void remount_service(int fd, void *cookie); void disable_verity_service(int fd, void* cookie); #endif /* packet allocator */ apacket *get_apacket(void); void put_apacket(apacket *p); int check_header(apacket *p); int check_data(apacket *p); #if !DEBUG_PACKETS #define print_packet(tag,p) do {} while (0) #endif #if ADB_HOST_ON_TARGET /* adb and adbd are coexisting on the target, so use 5038 for adb * to avoid conflicting with adbd's usage of 5037 */ # define DEFAULT_ADB_PORT 5038 #else # define DEFAULT_ADB_PORT 5037 #endif #define DEFAULT_ADB_LOCAL_TRANSPORT_PORT 5555 #define ADB_CLASS 0xff #define ADB_SUBCLASS 0x42 #define ADB_PROTOCOL 0x1 void local_init(int port); int local_connect(int port); int local_connect_arbitrary_ports(int console_port, int adb_port); /* usb host/client interface */ void usb_init(); void usb_cleanup(); int usb_write(usb_handle *h, const void *data, int len); int usb_read(usb_handle *h, void *data, int len); int usb_close(usb_handle *h); void usb_kick(usb_handle *h); /* used for USB device detection */ #if ADB_HOST int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol); #endif unsigned host_to_le32(unsigned n); int adb_commandline(int argc, char **argv); int connection_state(atransport *t); #define CS_ANY -1 #define CS_OFFLINE 0 #define CS_BOOTLOADER 1 #define CS_DEVICE 2 #define CS_HOST 3 #define CS_RECOVERY 4 #define CS_NOPERM 5 /* Insufficient permissions to communicate with the device */ #define CS_SIDELOAD 6 #define CS_UNAUTHORIZED 7 extern int HOST; extern int SHELL_EXIT_NOTIFY_FD; typedef enum { SUBPROC_PTY = 0, SUBPROC_RAW = 1, } subproc_mode; #define CHUNK_SIZE (64*1024) #if !ADB_HOST #define USB_ADB_PATH "/dev/android_adb" #define USB_FFS_ADB_PATH "/dev/usb-ffs/adb/" #define USB_FFS_ADB_EP(x) USB_FFS_ADB_PATH#x #define USB_FFS_ADB_EP0 USB_FFS_ADB_EP(ep0) #define USB_FFS_ADB_OUT USB_FFS_ADB_EP(ep1) #define USB_FFS_ADB_IN USB_FFS_ADB_EP(ep2) #endif int sendfailmsg(int fd, const char *reason); int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s); #endif android-tools-5.1.1r36+git20160322/core/adb/adb_auth.h000066400000000000000000000036241267427243200216420ustar00rootroot00000000000000/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef __ADB_AUTH_H #define __ADB_AUTH_H void adb_auth_init(void); int adb_auth_keygen(const char* filename); void adb_auth_verified(atransport *t); void send_auth_request(atransport *t); /* AUTH packets first argument */ /* Request */ #define ADB_AUTH_TOKEN 1 /* Response */ #define ADB_AUTH_SIGNATURE 2 #define ADB_AUTH_RSAPUBLICKEY 3 #if ADB_HOST int adb_auth_sign(void *key, void *token, size_t token_size, void *sig); void *adb_auth_nextkey(void *current); int adb_auth_get_userkey(unsigned char *data, size_t len); static inline int adb_auth_generate_token(void *token, size_t token_size) { return 0; } static inline int adb_auth_verify(void *token, void *sig, int siglen) { return 0; } static inline void adb_auth_confirm_key(unsigned char *data, size_t len, atransport *t) { } #else // !ADB_HOST static inline int adb_auth_sign(void* key, void *token, size_t token_size, void *sig) { return 0; } static inline void *adb_auth_nextkey(void *current) { return NULL; } static inline int adb_auth_get_userkey(unsigned char *data, size_t len) { return 0; } int adb_auth_generate_token(void *token, size_t token_size); int adb_auth_verify(void *token, void *sig, int siglen); void adb_auth_confirm_key(unsigned char *data, size_t len, atransport *t); #endif // ADB_HOST #endif // __ADB_AUTH_H android-tools-5.1.1r36+git20160322/core/adb/adb_auth_client.c000066400000000000000000000140231267427243200231660ustar00rootroot00000000000000/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include "sysdeps.h" #include "adb.h" #include "adb_auth.h" #include "fdevent.h" #include "mincrypt/rsa.h" #include "mincrypt/sha.h" #define TRACE_TAG TRACE_AUTH struct adb_public_key { struct listnode node; RSAPublicKey key; }; static char *key_paths[] = { "/adb_keys", "/data/misc/adb/adb_keys", NULL }; static fdevent listener_fde; static int framework_fd = -1; static void usb_disconnected(void* unused, atransport* t); static struct adisconnect usb_disconnect = { usb_disconnected, 0, 0, 0 }; static atransport* usb_transport; static bool needs_retry = false; static void read_keys(const char *file, struct listnode *list) { struct adb_public_key *key; FILE *f; char buf[MAX_PAYLOAD]; char *sep; int ret; f = fopen(file, "re"); if (!f) { D("Can't open '%s'\n", file); return; } while (fgets(buf, sizeof(buf), f)) { /* Allocate 4 extra bytes to decode the base64 data in-place */ key = calloc(1, sizeof(*key) + 4); if (!key) { D("Can't malloc key\n"); break; } sep = strpbrk(buf, " \t"); if (sep) *sep = '\0'; ret = __b64_pton(buf, (u_char *)&key->key, sizeof(key->key) + 4); if (ret != sizeof(key->key)) { D("%s: Invalid base64 data ret=%d\n", file, ret); free(key); continue; } if (key->key.len != RSANUMWORDS) { D("%s: Invalid key len %d\n", file, key->key.len); free(key); continue; } list_add_tail(list, &key->node); } fclose(f); } static void free_keys(struct listnode *list) { struct listnode *item; while (!list_empty(list)) { item = list_head(list); list_remove(item); free(node_to_item(item, struct adb_public_key, node)); } } static void load_keys(struct listnode *list) { char *path; char **paths = key_paths; struct stat buf; list_init(list); while ((path = *paths++)) { if (!stat(path, &buf)) { D("Loading keys from '%s'\n", path); read_keys(path, list); } } } int adb_auth_generate_token(void *token, size_t token_size) { FILE *f; int ret; f = fopen("/dev/urandom", "re"); if (!f) return 0; ret = fread(token, token_size, 1, f); fclose(f); return ret * token_size; } int adb_auth_verify(void *token, void *sig, int siglen) { struct listnode *item; struct adb_public_key *key; struct listnode key_list; int ret = 0; if (siglen != RSANUMBYTES) return 0; load_keys(&key_list); list_for_each(item, &key_list) { key = node_to_item(item, struct adb_public_key, node); ret = RSA_verify(&key->key, sig, siglen, token, SHA_DIGEST_SIZE); if (ret) break; } free_keys(&key_list); return ret; } static void usb_disconnected(void* unused, atransport* t) { D("USB disconnect\n"); remove_transport_disconnect(usb_transport, &usb_disconnect); usb_transport = NULL; needs_retry = false; } static void adb_auth_event(int fd, unsigned events, void *data) { char response[2]; int ret; if (events & FDE_READ) { ret = unix_read(fd, response, sizeof(response)); if (ret <= 0) { D("Framework disconnect\n"); if (usb_transport) fdevent_remove(&usb_transport->auth_fde); framework_fd = -1; } else if (ret == 2 && response[0] == 'O' && response[1] == 'K') { if (usb_transport) adb_auth_verified(usb_transport); } } } void adb_auth_confirm_key(unsigned char *key, size_t len, atransport *t) { char msg[MAX_PAYLOAD]; int ret; if (!usb_transport) { usb_transport = t; add_transport_disconnect(t, &usb_disconnect); } if (framework_fd < 0) { D("Client not connected\n"); needs_retry = true; return; } if (key[len - 1] != '\0') { D("Key must be a null-terminated string\n"); return; } ret = snprintf(msg, sizeof(msg), "PK%s", key); if (ret >= (signed)sizeof(msg)) { D("Key too long. ret=%d", ret); return; } D("Sending '%s'\n", msg); ret = unix_write(framework_fd, msg, ret); if (ret < 0) { D("Failed to write PK, errno=%d\n", errno); return; } fdevent_install(&t->auth_fde, framework_fd, adb_auth_event, t); fdevent_add(&t->auth_fde, FDE_READ); } static void adb_auth_listener(int fd, unsigned events, void *data) { struct sockaddr addr; socklen_t alen; int s; alen = sizeof(addr); s = adb_socket_accept(fd, &addr, &alen); if (s < 0) { D("Failed to accept: errno=%d\n", errno); return; } framework_fd = s; if (needs_retry) { needs_retry = false; send_auth_request(usb_transport); } } void adb_auth_init(void) { int fd, ret; fd = android_get_control_socket("adbd"); if (fd < 0) { D("Failed to get adbd socket\n"); return; } fcntl(fd, F_SETFD, FD_CLOEXEC); ret = listen(fd, 4); if (ret < 0) { D("Failed to listen on '%d'\n", fd); return; } fdevent_install(&listener_fde, fd, adb_auth_listener, NULL); fdevent_add(&listener_fde, FDE_READ); } android-tools-5.1.1r36+git20160322/core/adb/adb_auth_host.c000066400000000000000000000235171267427243200226750ustar00rootroot00000000000000/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #ifdef _WIN32 # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN # endif # include "windows.h" # include "shlobj.h" #else # include # include # include #endif #include #include "sysdeps.h" #include "adb.h" #include "adb_auth.h" /* HACK: we need the RSAPublicKey struct * but RSA_verify conflits with openssl */ #define RSA_verify RSA_verify_mincrypt #include "mincrypt/rsa.h" #undef RSA_verify #include #include #include #include #include #include #define TRACE_TAG TRACE_AUTH #define ANDROID_PATH ".android" #define ADB_KEY_FILE "adbkey" struct adb_private_key { struct listnode node; RSA *rsa; }; static struct listnode key_list; /* Convert OpenSSL RSA private key to android pre-computed RSAPublicKey format */ static int RSA_to_RSAPublicKey(RSA *rsa, RSAPublicKey *pkey) { int ret = 1; unsigned int i; BN_CTX* ctx = BN_CTX_new(); BIGNUM* r32 = BN_new(); BIGNUM* rr = BN_new(); BIGNUM* r = BN_new(); BIGNUM* rem = BN_new(); BIGNUM* n = BN_new(); BIGNUM* n0inv = BN_new(); if (RSA_size(rsa) != RSANUMBYTES) { ret = 0; goto out; } BN_set_bit(r32, 32); BN_copy(n, rsa->n); BN_set_bit(r, RSANUMWORDS * 32); BN_mod_sqr(rr, r, n, ctx); BN_div(NULL, rem, n, r32, ctx); BN_mod_inverse(n0inv, rem, r32, ctx); pkey->len = RSANUMWORDS; pkey->n0inv = 0 - BN_get_word(n0inv); for (i = 0; i < RSANUMWORDS; i++) { BN_div(rr, rem, rr, r32, ctx); pkey->rr[i] = BN_get_word(rem); BN_div(n, rem, n, r32, ctx); pkey->n[i] = BN_get_word(rem); } pkey->exponent = BN_get_word(rsa->e); out: BN_free(n0inv); BN_free(n); BN_free(rem); BN_free(r); BN_free(rr); BN_free(r32); BN_CTX_free(ctx); return ret; } static void get_user_info(char *buf, size_t len) { char hostname[1024], username[1024]; int ret = -1; if (getenv("HOSTNAME") != NULL) { strncpy(hostname, getenv("HOSTNAME"), sizeof(hostname)); hostname[sizeof(hostname)-1] = '\0'; ret = 0; } #ifndef _WIN32 if (ret < 0) ret = gethostname(hostname, sizeof(hostname)); #endif if (ret < 0) strcpy(hostname, "unknown"); ret = -1; if (getenv("LOGNAME") != NULL) { strncpy(username, getenv("LOGNAME"), sizeof(username)); username[sizeof(username)-1] = '\0'; ret = 0; } #if !defined _WIN32 && !defined ADB_HOST_ON_TARGET if (ret < 0) ret = getlogin_r(username, sizeof(username)); #endif if (ret < 0) strcpy(username, "unknown"); ret = snprintf(buf, len, " %s@%s", username, hostname); if (ret >= (signed)len) buf[len - 1] = '\0'; } static int write_public_keyfile(RSA *private_key, const char *private_key_path) { RSAPublicKey pkey; BIO *bio, *b64, *bfile; char path[PATH_MAX], info[MAX_PAYLOAD]; int ret; ret = snprintf(path, sizeof(path), "%s.pub", private_key_path); if (ret >= (signed)sizeof(path)) return 0; ret = RSA_to_RSAPublicKey(private_key, &pkey); if (!ret) { D("Failed to convert to publickey\n"); return 0; } bfile = BIO_new_file(path, "w"); if (!bfile) { D("Failed to open '%s'\n", path); return 0; } D("Writing public key to '%s'\n", path); b64 = BIO_new(BIO_f_base64()); BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); bio = BIO_push(b64, bfile); BIO_write(bio, &pkey, sizeof(pkey)); (void) BIO_flush(bio); BIO_pop(b64); BIO_free(b64); get_user_info(info, sizeof(info)); BIO_write(bfile, info, strlen(info)); (void) BIO_flush(bfile); BIO_free_all(bfile); return 1; } static int generate_key(const char *file) { EVP_PKEY* pkey = EVP_PKEY_new(); BIGNUM* exponent = BN_new(); RSA* rsa = RSA_new(); mode_t old_mask; FILE *f = NULL; int ret = 0; D("generate_key '%s'\n", file); if (!pkey || !exponent || !rsa) { D("Failed to allocate key\n"); goto out; } BN_set_word(exponent, RSA_F4); RSA_generate_key_ex(rsa, 2048, exponent, NULL); EVP_PKEY_set1_RSA(pkey, rsa); old_mask = umask(077); f = fopen(file, "w"); if (!f) { D("Failed to open '%s'\n", file); umask(old_mask); goto out; } umask(old_mask); if (!PEM_write_PrivateKey(f, pkey, NULL, NULL, 0, NULL, NULL)) { D("Failed to write key\n"); goto out; } if (!write_public_keyfile(rsa, file)) { D("Failed to write public key\n"); goto out; } ret = 1; out: if (f) fclose(f); EVP_PKEY_free(pkey); RSA_free(rsa); BN_free(exponent); return ret; } static int read_key(const char *file, struct listnode *list) { struct adb_private_key *key; FILE *f; D("read_key '%s'\n", file); f = fopen(file, "r"); if (!f) { D("Failed to open '%s'\n", file); return 0; } key = malloc(sizeof(*key)); if (!key) { D("Failed to alloc key\n"); fclose(f); return 0; } key->rsa = RSA_new(); if (!PEM_read_RSAPrivateKey(f, &key->rsa, NULL, NULL)) { D("Failed to read key\n"); fclose(f); RSA_free(key->rsa); free(key); return 0; } fclose(f); list_add_tail(list, &key->node); return 1; } static int get_user_keyfilepath(char *filename, size_t len) { const char *format, *home; char android_dir[PATH_MAX]; struct stat buf; #ifdef _WIN32 char path[PATH_MAX]; home = getenv("ANDROID_SDK_HOME"); if (!home) { SHGetFolderPath(NULL, CSIDL_PROFILE, NULL, 0, path); home = path; } format = "%s\\%s"; #else home = getenv("HOME"); if (!home) return -1; format = "%s/%s"; #endif D("home '%s'\n", home); if (snprintf(android_dir, sizeof(android_dir), format, home, ANDROID_PATH) >= (int)sizeof(android_dir)) return -1; if (stat(android_dir, &buf)) { if (adb_mkdir(android_dir, 0750) < 0) { D("Cannot mkdir '%s'", android_dir); return -1; } } return snprintf(filename, len, format, android_dir, ADB_KEY_FILE); } static int get_user_key(struct listnode *list) { struct stat buf; char path[PATH_MAX]; int ret; ret = get_user_keyfilepath(path, sizeof(path)); if (ret < 0 || ret >= (signed)sizeof(path)) { D("Error getting user key filename"); return 0; } D("user key '%s'\n", path); if (stat(path, &buf) == -1) { if (!generate_key(path)) { D("Failed to generate new key\n"); return 0; } } return read_key(path, list); } static void get_vendor_keys(struct listnode *list) { const char *adb_keys_path; char keys_path[MAX_PAYLOAD]; char *path; char *save; struct stat buf; adb_keys_path = getenv("ADB_VENDOR_KEYS"); if (!adb_keys_path) return; strncpy(keys_path, adb_keys_path, sizeof(keys_path)); path = adb_strtok_r(keys_path, ENV_PATH_SEPARATOR_STR, &save); while (path) { D("Reading: '%s'\n", path); if (stat(path, &buf)) D("Can't read '%s'\n", path); else if (!read_key(path, list)) D("Failed to read '%s'\n", path); path = adb_strtok_r(NULL, ENV_PATH_SEPARATOR_STR, &save); } } int adb_auth_sign(void *node, void *token, size_t token_size, void *sig) { unsigned int len; struct adb_private_key *key = node_to_item(node, struct adb_private_key, node); if (!RSA_sign(NID_sha1, token, token_size, sig, &len, key->rsa)) { return 0; } D("adb_auth_sign len=%d\n", len); return (int)len; } void *adb_auth_nextkey(void *current) { struct listnode *item; if (list_empty(&key_list)) return NULL; if (!current) return list_head(&key_list); list_for_each(item, &key_list) { if (item == current) { /* current is the last item, we tried all the keys */ if (item->next == &key_list) return NULL; return item->next; } } return NULL; } int adb_auth_get_userkey(unsigned char *data, size_t len) { char path[PATH_MAX]; char *file; int ret; ret = get_user_keyfilepath(path, sizeof(path) - 4); if (ret < 0 || ret >= (signed)(sizeof(path) - 4)) { D("Error getting user key filename"); return 0; } strcat(path, ".pub"); file = load_file(path, (unsigned*)&ret); if (!file) { D("Can't load '%s'\n", path); return 0; } if (len < (size_t)(ret + 1)) { D("%s: Content too large ret=%d\n", path, ret); return 0; } memcpy(data, file, ret); data[ret] = '\0'; return ret + 1; } int adb_auth_keygen(const char* filename) { adb_trace_mask |= (1 << TRACE_AUTH); return (generate_key(filename) == 0); } void adb_auth_init(void) { int ret; D("adb_auth_init\n"); list_init(&key_list); ret = get_user_key(&key_list); if (!ret) { D("Failed to get user key\n"); return; } get_vendor_keys(&key_list); } android-tools-5.1.1r36+git20160322/core/adb/adb_client.c000066400000000000000000000206171267427243200221530ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include "sysdeps.h" #define TRACE_TAG TRACE_ADB #include "adb_client.h" static transport_type __adb_transport = kTransportAny; static const char* __adb_serial = NULL; static int __adb_server_port = DEFAULT_ADB_PORT; static const char* __adb_server_name = NULL; void adb_set_transport(transport_type type, const char* serial) { __adb_transport = type; __adb_serial = serial; } void adb_set_tcp_specifics(int server_port) { __adb_server_port = server_port; } void adb_set_tcp_name(const char* hostname) { __adb_server_name = hostname; } int adb_get_emulator_console_port(void) { const char* serial = __adb_serial; int port; if (serial == NULL) { /* if no specific device was specified, we need to look at */ /* the list of connected devices, and extract an emulator */ /* name from it. two emulators is an error */ char* tmp = adb_query("host:devices"); char* p = tmp; if(!tmp) { printf("no emulator connected\n"); return -1; } while (*p) { char* q = strchr(p, '\n'); if (q != NULL) *q++ = 0; else q = p + strlen(p); if (!memcmp(p, LOCAL_CLIENT_PREFIX, sizeof(LOCAL_CLIENT_PREFIX)-1)) { if (serial != NULL) { /* more than one emulator listed */ free(tmp); return -2; } serial = p; } p = q; } free(tmp); if (serial == NULL) return -1; /* no emulator found */ } else { if (memcmp(serial, LOCAL_CLIENT_PREFIX, sizeof(LOCAL_CLIENT_PREFIX)-1) != 0) return -1; /* not an emulator */ } serial += sizeof(LOCAL_CLIENT_PREFIX)-1; port = strtol(serial, NULL, 10); return port; } static char __adb_error[256] = { 0 }; const char *adb_error(void) { return __adb_error; } static int switch_socket_transport(int fd) { char service[64]; char tmp[5]; int len; if (__adb_serial) snprintf(service, sizeof service, "host:transport:%s", __adb_serial); else { char* transport_type = "???"; switch (__adb_transport) { case kTransportUsb: transport_type = "transport-usb"; break; case kTransportLocal: transport_type = "transport-local"; break; case kTransportAny: transport_type = "transport-any"; break; case kTransportHost: // no switch necessary return 0; break; } snprintf(service, sizeof service, "host:%s", transport_type); } len = strlen(service); snprintf(tmp, sizeof tmp, "%04x", len); if(writex(fd, tmp, 4) || writex(fd, service, len)) { strcpy(__adb_error, "write failure during connection"); adb_close(fd); return -1; } D("Switch transport in progress\n"); if(adb_status(fd)) { adb_close(fd); D("Switch transport failed\n"); return -1; } D("Switch transport success\n"); return 0; } int adb_status(int fd) { unsigned char buf[5]; unsigned len; if(readx(fd, buf, 4)) { strcpy(__adb_error, "protocol fault (no status)"); return -1; } if(!memcmp(buf, "OKAY", 4)) { return 0; } if(memcmp(buf, "FAIL", 4)) { sprintf(__adb_error, "protocol fault (status %02x %02x %02x %02x?!)", buf[0], buf[1], buf[2], buf[3]); return -1; } if(readx(fd, buf, 4)) { strcpy(__adb_error, "protocol fault (status len)"); return -1; } buf[4] = 0; len = strtoul((char*)buf, 0, 16); if(len > 255) len = 255; if(readx(fd, __adb_error, len)) { strcpy(__adb_error, "protocol fault (status read)"); return -1; } __adb_error[len] = 0; return -1; } int _adb_connect(const char *service) { char tmp[5]; int len; int fd; D("_adb_connect: %s\n", service); len = strlen(service); if((len < 1) || (len > 1024)) { strcpy(__adb_error, "service name too long"); return -1; } snprintf(tmp, sizeof tmp, "%04x", len); if (__adb_server_name) fd = socket_network_client(__adb_server_name, __adb_server_port, SOCK_STREAM); else fd = socket_loopback_client(__adb_server_port, SOCK_STREAM); if(fd < 0) { strcpy(__adb_error, "cannot connect to daemon"); return -2; } if (memcmp(service,"host",4) != 0 && switch_socket_transport(fd)) { return -1; } if(writex(fd, tmp, 4) || writex(fd, service, len)) { strcpy(__adb_error, "write failure during connection"); adb_close(fd); return -1; } if(adb_status(fd)) { adb_close(fd); return -1; } D("_adb_connect: return fd %d\n", fd); return fd; } int adb_connect(const char *service) { // first query the adb server's version int fd = _adb_connect("host:version"); D("adb_connect: service %s\n", service); if(fd == -2 && __adb_server_name) { fprintf(stderr,"** Cannot start server on remote host\n"); return fd; } else if(fd == -2) { fprintf(stdout,"* daemon not running. starting it now on port %d *\n", __adb_server_port); start_server: if(launch_server(__adb_server_port)) { fprintf(stderr,"* failed to start daemon *\n"); return -1; } else { fprintf(stdout,"* daemon started successfully *\n"); } /* give the server some time to start properly and detect devices */ adb_sleep_ms(3000); // fall through to _adb_connect } else { // if server was running, check its version to make sure it is not out of date char buf[100]; size_t n; int version = ADB_SERVER_VERSION - 1; // if we have a file descriptor, then parse version result if(fd >= 0) { if(readx(fd, buf, 4)) goto error; buf[4] = 0; n = strtoul(buf, 0, 16); if(n > sizeof(buf)) goto error; if(readx(fd, buf, n)) goto error; adb_close(fd); if (sscanf(buf, "%04x", &version) != 1) goto error; } else { // if fd is -1, then check for "unknown host service", // which would indicate a version of adb that does not support the version command if (strcmp(__adb_error, "unknown host service") != 0) return fd; } if(version != ADB_SERVER_VERSION) { printf("adb server is out of date. killing...\n"); fd = _adb_connect("host:kill"); adb_close(fd); /* XXX can we better detect its death? */ adb_sleep_ms(2000); goto start_server; } } // if the command is start-server, we are done. if (!strcmp(service, "host:start-server")) return 0; fd = _adb_connect(service); if(fd == -1) { D("_adb_connect error: %s\n", __adb_error); } else if(fd == -2) { fprintf(stderr,"** daemon still not running\n"); } D("adb_connect: return fd %d\n", fd); return fd; error: adb_close(fd); return -1; } int adb_command(const char *service) { int fd = adb_connect(service); if(fd < 0) { fprintf(stderr, "error: %s\n", adb_error()); return -1; } if(adb_status(fd)) { adb_close(fd); return -1; } return 0; } char *adb_query(const char *service) { char buf[5]; unsigned n; char *tmp; D("adb_query: %s\n", service); int fd = adb_connect(service); if(fd < 0) { fprintf(stderr,"error: %s\n", __adb_error); return 0; } if(readx(fd, buf, 4)) goto oops; buf[4] = 0; n = strtoul(buf, 0, 16); if(n >= 0xffff) { strcpy(__adb_error, "reply is too long (>= 64kB)"); goto oops; } tmp = malloc(n + 1); if(tmp == 0) goto oops; if(readx(fd, tmp, n) == 0) { tmp[n] = 0; adb_close(fd); return tmp; } free(tmp); oops: adb_close(fd); return 0; } android-tools-5.1.1r36+git20160322/core/adb/adb_client.h000066400000000000000000000032361267427243200221560ustar00rootroot00000000000000#ifndef _ADB_CLIENT_H_ #define _ADB_CLIENT_H_ #include "adb.h" /* connect to adb, connect to the named service, and return ** a valid fd for interacting with that service upon success ** or a negative number on failure */ int adb_connect(const char *service); int _adb_connect(const char *service); /* connect to adb, connect to the named service, return 0 if ** the connection succeeded AND the service returned OKAY */ int adb_command(const char *service); /* connect to adb, connect to the named service, return ** a malloc'd string of its response upon success or NULL ** on failure. */ char *adb_query(const char *service); /* Set the preferred transport to connect to. */ void adb_set_transport(transport_type type, const char* serial); /* Set TCP specifics of the transport to use */ void adb_set_tcp_specifics(int server_port); /* Set TCP Hostname of the transport to use */ void adb_set_tcp_name(const char* hostname); /* Return the console port of the currently connected emulator (if any) * of -1 if there is no emulator, and -2 if there is more than one. * assumes adb_set_transport() was alled previously... */ int adb_get_emulator_console_port(void); /* send commands to the current emulator instance. will fail if there * is zero, or more than one emulator connected (or if you use -s * with a that does not designate an emulator) */ int adb_send_emulator_command(int argc, char** argv); /* return verbose error string from last operation */ const char *adb_error(void); /* read a standard adb status response (OKAY|FAIL) and ** return 0 in the event of OKAY, -1 in the event of FAIL ** or protocol error */ int adb_status(int fd); #endif android-tools-5.1.1r36+git20160322/core/adb/adb_trace.h000066400000000000000000000127671267427243200220070ustar00rootroot00000000000000/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef __ADB_TRACE_H #define __ADB_TRACE_H #if !ADB_HOST #include #endif /* define ADB_TRACE to 1 to enable tracing support, or 0 to disable it */ #define ADB_TRACE 1 /* IMPORTANT: if you change the following list, don't * forget to update the corresponding 'tags' table in * the adb_trace_init() function implemented in adb.c */ typedef enum { TRACE_ADB = 0, /* 0x001 */ TRACE_SOCKETS, TRACE_PACKETS, TRACE_TRANSPORT, TRACE_RWX, /* 0x010 */ TRACE_USB, TRACE_SYNC, TRACE_SYSDEPS, TRACE_JDWP, /* 0x100 */ TRACE_SERVICES, TRACE_AUTH, TRACE_FDEVENT, } AdbTrace; #if ADB_TRACE #if !ADB_HOST /* * When running inside the emulator, guest's adbd can connect to 'adb-debug' * qemud service that can display adb trace messages (on condition that emulator * has been started with '-debug adb' option). */ /* Delivers a trace message to the emulator via QEMU pipe. */ void adb_qemu_trace(const char* fmt, ...); /* Macro to use to send ADB trace messages to the emulator. */ #define DQ(...) adb_qemu_trace(__VA_ARGS__) #else #define DQ(...) ((void)0) #endif /* !ADB_HOST */ extern int adb_trace_mask; extern unsigned char adb_trace_output_count; void adb_trace_init(void); # define ADB_TRACING ((adb_trace_mask & (1 << TRACE_TAG)) != 0) /* you must define TRACE_TAG before using this macro */ #if ADB_HOST # define D(...) \ do { \ if (ADB_TRACING) { \ int save_errno = errno; \ adb_mutex_lock(&D_lock); \ fprintf(stderr, "%s::%s():", \ __FILE__, __FUNCTION__); \ errno = save_errno; \ fprintf(stderr, __VA_ARGS__ ); \ fflush(stderr); \ adb_mutex_unlock(&D_lock); \ errno = save_errno; \ } \ } while (0) # define DR(...) \ do { \ if (ADB_TRACING) { \ int save_errno = errno; \ adb_mutex_lock(&D_lock); \ errno = save_errno; \ fprintf(stderr, __VA_ARGS__ ); \ fflush(stderr); \ adb_mutex_unlock(&D_lock); \ errno = save_errno; \ } \ } while (0) # define DD(...) \ do { \ int save_errno = errno; \ adb_mutex_lock(&D_lock); \ fprintf(stderr, "%s::%s():", \ __FILE__, __FUNCTION__); \ errno = save_errno; \ fprintf(stderr, __VA_ARGS__ ); \ fflush(stderr); \ adb_mutex_unlock(&D_lock); \ errno = save_errno; \ } while (0) #else # define D(...) \ do { \ if (ADB_TRACING) { \ __android_log_print( \ ANDROID_LOG_INFO, \ __FUNCTION__, \ __VA_ARGS__ ); \ } \ } while (0) # define DR(...) \ do { \ if (ADB_TRACING) { \ __android_log_print( \ ANDROID_LOG_INFO, \ __FUNCTION__, \ __VA_ARGS__ ); \ } \ } while (0) # define DD(...) \ do { \ __android_log_print( \ ANDROID_LOG_INFO, \ __FUNCTION__, \ __VA_ARGS__ ); \ } while (0) #endif /* ADB_HOST */ #else # define D(...) ((void)0) # define DR(...) ((void)0) # define DD(...) ((void)0) # define ADB_TRACING 0 #endif /* ADB_TRACE */ #endif /* __ADB_TRACE_H */ android-tools-5.1.1r36+git20160322/core/adb/commandline.c000066400000000000000000001751021267427243200223550ustar00rootroot00000000000000/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "sysdeps.h" #ifdef HAVE_TERMIO_H #include #endif #define TRACE_TAG TRACE_ADB #include "adb.h" #include "adb_client.h" #include "adb_auth.h" #include "file_sync_service.h" static int do_cmd(transport_type ttype, char* serial, char *cmd, ...); void get_my_path(char *s, size_t maxLen); int find_sync_dirs(const char *srcarg, char **android_srcdir_out, char **data_srcdir_out, char **vendor_srcdir_out); int install_app(transport_type transport, char* serial, int argc, char** argv); int install_multiple_app(transport_type transport, char* serial, int argc, char** argv); int uninstall_app(transport_type transport, char* serial, int argc, char** argv); static const char *gProductOutPath = NULL; extern int gListenAll; static char *product_file(const char *extra) { int n; char *x; if (gProductOutPath == NULL) { fprintf(stderr, "adb: Product directory not specified; " "use -p or define ANDROID_PRODUCT_OUT\n"); exit(1); } n = strlen(gProductOutPath) + strlen(extra) + 2; x = malloc(n); if (x == 0) { fprintf(stderr, "adb: Out of memory (product_file())\n"); exit(1); } snprintf(x, (size_t)n, "%s" OS_PATH_SEPARATOR_STR "%s", gProductOutPath, extra); return x; } void version(FILE * out) { fprintf(out, "Android Debug Bridge version %d.%d.%d\n", ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION); } void help() { version(stderr); fprintf(stderr, "\n" " -a - directs adb to listen on all interfaces for a connection\n" " -d - directs command to the only connected USB device\n" " returns an error if more than one USB device is present.\n" " -e - directs command to the only running emulator.\n" " returns an error if more than one emulator is running.\n" " -s - directs command to the device or emulator with the given\n" " serial number or qualifier. Overrides ANDROID_SERIAL\n" " environment variable.\n" " -p - simple product name like 'sooner', or\n" " a relative/absolute path to a product\n" " out directory like 'out/target/product/sooner'.\n" " If -p is not specified, the ANDROID_PRODUCT_OUT\n" " environment variable is used, which must\n" " be an absolute path.\n" " -H - Name of adb server host (default: localhost)\n" " -P - Port of adb server (default: 5037)\n" " devices [-l] - list all connected devices\n" " ('-l' will also list device qualifiers)\n" " connect [:] - connect to a device via TCP/IP\n" " Port 5555 is used by default if no port number is specified.\n" " disconnect [[:]] - disconnect from a TCP/IP device.\n" " Port 5555 is used by default if no port number is specified.\n" " Using this command with no additional arguments\n" " will disconnect from all connected TCP/IP devices.\n" "\n" "device commands:\n" " adb push [-p] \n" " - copy file/dir to device\n" " ('-p' to display the transfer progress)\n" " adb pull [-p] [-a] []\n" " - copy file/dir from device\n" " ('-p' to display the transfer progress)\n" " ('-a' means copy timestamp and mode)\n" " adb sync [ ] - copy host->device only if changed\n" " (-l means list but don't copy)\n" " (see 'adb help all')\n" " adb shell - run remote shell interactively\n" " adb shell - run remote shell command\n" " adb emu - run emulator console command\n" " adb logcat [ ] - View device log\n" " adb forward --list - list all forward socket connections.\n" " the format is a list of lines with the following format:\n" " \" \" \" \" \"\\n\"\n" " adb forward - forward socket connections\n" " forward specs are one of: \n" " tcp:\n" " localabstract:\n" " localreserved:\n" " localfilesystem:\n" " dev:\n" " jdwp: (remote only)\n" " adb forward --no-rebind \n" " - same as 'adb forward ' but fails\n" " if is already forwarded\n" " adb forward --remove - remove a specific forward socket connection\n" " adb forward --remove-all - remove all forward socket connections\n" " adb reverse --list - list all reverse socket connections from device\n" " adb reverse - reverse socket connections\n" " reverse specs are one of:\n" " tcp:\n" " localabstract:\n" " localreserved:\n" " localfilesystem:\n" " adb reverse --norebind \n" " - same as 'adb reverse ' but fails\n" " if is already reversed.\n" " adb reverse --remove \n" " - remove a specific reversed socket connection\n" " adb reverse --remove-all - remove all reversed socket connections from device\n" " adb jdwp - list PIDs of processes hosting a JDWP transport\n" " adb install [-lrtsd] \n" " adb install-multiple [-lrtsdp] \n" " - push this package file to the device and install it\n" " (-l: forward lock application)\n" " (-r: replace existing application)\n" " (-t: allow test packages)\n" " (-s: install application on sdcard)\n" " (-d: allow version code downgrade)\n" " (-p: partial application install)\n" " adb uninstall [-k] - remove this app package from the device\n" " ('-k' means keep the data and cache directories)\n" " adb bugreport - return all information from the device\n" " that should be included in a bug report.\n" "\n" " adb backup [-f ] [-apk|-noapk] [-obb|-noobb] [-shared|-noshared] [-all] [-system|-nosystem] []\n" " - write an archive of the device's data to .\n" " If no -f option is supplied then the data is written\n" " to \"backup.ab\" in the current directory.\n" " (-apk|-noapk enable/disable backup of the .apks themselves\n" " in the archive; the default is noapk.)\n" " (-obb|-noobb enable/disable backup of any installed apk expansion\n" " (aka .obb) files associated with each application; the default\n" " is noobb.)\n" " (-shared|-noshared enable/disable backup of the device's\n" " shared storage / SD card contents; the default is noshared.)\n" " (-all means to back up all installed applications)\n" " (-system|-nosystem toggles whether -all automatically includes\n" " system applications; the default is to include system apps)\n" " ( is the list of applications to be backed up. If\n" " the -all or -shared flags are passed, then the package\n" " list is optional. Applications explicitly given on the\n" " command line will be included even if -nosystem would\n" " ordinarily cause them to be omitted.)\n" "\n" " adb restore - restore device contents from the backup archive\n" "\n" " adb disable-verity - disable dm-verity checking on USERDEBUG builds\n" " adb keygen - generate adb public/private key. The private key is stored in ,\n" " and the public key is stored in .pub. Any existing files\n" " are overwritten.\n" " adb help - show this help message\n" " adb version - show version num\n" "\n" "scripting:\n" " adb wait-for-device - block until device is online\n" " adb start-server - ensure that there is a server running\n" " adb kill-server - kill the server if it is running\n" " adb get-state - prints: offline | bootloader | device\n" " adb get-serialno - prints: \n" " adb get-devpath - prints: \n" " adb status-window - continuously print device status for a specified device\n" " adb remount - remounts the /system and /vendor (if present) partitions on the device read-write\n" " adb reboot [bootloader|recovery] - reboots the device, optionally into the bootloader or recovery program\n" " adb reboot-bootloader - reboots the device into the bootloader\n" " adb root - restarts the adbd daemon with root permissions\n" " adb usb - restarts the adbd daemon listening on USB\n" " adb tcpip - restarts the adbd daemon listening on TCP on the specified port\n" "networking:\n" " adb ppp [parameters] - Run PPP over USB.\n" " Note: you should not automatically start a PPP connection.\n" " refers to the tty for PPP stream. Eg. dev:/dev/omap_csmi_tty1\n" " [parameters] - Eg. defaultroute debug dump local notty usepeerdns\n" "\n" "adb sync notes: adb sync [ ]\n" " can be interpreted in several ways:\n" "\n" " - If is not specified, /system, /vendor (if present), and /data partitions will be updated.\n" "\n" " - If it is \"system\", \"vendor\" or \"data\", only the corresponding partition\n" " is updated.\n" "\n" "environmental variables:\n" " ADB_TRACE - Print debug information. A comma separated list of the following values\n" " 1 or all, adb, sockets, packets, rwx, usb, sync, sysdeps, transport, jdwp\n" " ANDROID_SERIAL - The serial number to connect to. -s takes priority over this if given.\n" " ANDROID_LOG_TAGS - When used with the logcat option, only these debug tags are printed.\n" ); } int usage() { help(); return 1; } #ifdef HAVE_TERMIO_H static struct termios tio_save; static void stdin_raw_init(int fd) { struct termios tio; if(tcgetattr(fd, &tio)) return; if(tcgetattr(fd, &tio_save)) return; tio.c_lflag = 0; /* disable CANON, ECHO*, etc */ /* no timeout but request at least one character per read */ tio.c_cc[VTIME] = 0; tio.c_cc[VMIN] = 1; tcsetattr(fd, TCSANOW, &tio); tcflush(fd, TCIFLUSH); } static void stdin_raw_restore(int fd) { tcsetattr(fd, TCSANOW, &tio_save); tcflush(fd, TCIFLUSH); } #endif static void read_and_dump(int fd) { char buf[4096]; int len; while(fd >= 0) { D("read_and_dump(): pre adb_read(fd=%d)\n", fd); len = adb_read(fd, buf, 4096); D("read_and_dump(): post adb_read(fd=%d): len=%d\n", fd, len); if(len == 0) { break; } if(len < 0) { if(errno == EINTR) continue; break; } fwrite(buf, 1, len, stdout); fflush(stdout); } } static void read_status_line(int fd, char* buf, size_t count) { count--; while (count > 0) { int len = adb_read(fd, buf, count); if (len == 0) { break; } else if (len < 0) { if (errno == EINTR) continue; break; } buf += len; count -= len; } *buf = '\0'; } static void copy_to_file(int inFd, int outFd) { const size_t BUFSIZE = 32 * 1024; char* buf = (char*) malloc(BUFSIZE); int len; long total = 0; D("copy_to_file(%d -> %d)\n", inFd, outFd); #ifdef HAVE_TERMIO_H if (inFd == STDIN_FILENO) { stdin_raw_init(STDIN_FILENO); } #endif for (;;) { if (inFd == STDIN_FILENO) { len = unix_read(inFd, buf, BUFSIZE); } else { len = adb_read(inFd, buf, BUFSIZE); } if (len == 0) { D("copy_to_file() : read 0 bytes; exiting\n"); break; } if (len < 0) { if (errno == EINTR) { D("copy_to_file() : EINTR, retrying\n"); continue; } D("copy_to_file() : error %d\n", errno); break; } if (outFd == STDOUT_FILENO) { fwrite(buf, 1, len, stdout); fflush(stdout); } else { adb_write(outFd, buf, len); } total += len; } #ifdef HAVE_TERMIO_H if (inFd == STDIN_FILENO) { stdin_raw_restore(STDIN_FILENO); } #endif D("copy_to_file() finished after %lu bytes\n", total); free(buf); } static void *stdin_read_thread(void *x) { int fd, fdi; unsigned char buf[1024]; int r, n; int state = 0; int *fds = (int*) x; fd = fds[0]; fdi = fds[1]; free(fds); for(;;) { /* fdi is really the client's stdin, so use read, not adb_read here */ D("stdin_read_thread(): pre unix_read(fdi=%d,...)\n", fdi); r = unix_read(fdi, buf, 1024); D("stdin_read_thread(): post unix_read(fdi=%d,...)\n", fdi); if(r == 0) break; if(r < 0) { if(errno == EINTR) continue; break; } for(n = 0; n < r; n++){ switch(buf[n]) { case '\n': state = 1; break; case '\r': state = 1; break; case '~': if(state == 1) state++; break; case '.': if(state == 2) { fprintf(stderr,"\n* disconnect *\n"); #ifdef HAVE_TERMIO_H stdin_raw_restore(fdi); #endif exit(0); } default: state = 0; } } r = adb_write(fd, buf, r); if(r <= 0) { break; } } return 0; } int interactive_shell(void) { adb_thread_t thr; int fdi, fd; int *fds; fd = adb_connect("shell:"); if(fd < 0) { fprintf(stderr,"error: %s\n", adb_error()); return 1; } fdi = 0; //dup(0); fds = malloc(sizeof(int) * 2); fds[0] = fd; fds[1] = fdi; #ifdef HAVE_TERMIO_H stdin_raw_init(fdi); #endif adb_thread_create(&thr, stdin_read_thread, fds); read_and_dump(fd); #ifdef HAVE_TERMIO_H stdin_raw_restore(fdi); #endif return 0; } static void format_host_command(char* buffer, size_t buflen, const char* command, transport_type ttype, const char* serial) { if (serial) { snprintf(buffer, buflen, "host-serial:%s:%s", serial, command); } else { const char* prefix = "host"; if (ttype == kTransportUsb) prefix = "host-usb"; else if (ttype == kTransportLocal) prefix = "host-local"; snprintf(buffer, buflen, "%s:%s", prefix, command); } } int adb_download_buffer(const char *service, const char *fn, const void* data, int sz, unsigned progress) { char buf[4096]; unsigned total; int fd; const unsigned char *ptr; sprintf(buf,"%s:%d", service, sz); fd = adb_connect(buf); if(fd < 0) { fprintf(stderr,"error: %s\n", adb_error()); return -1; } int opt = CHUNK_SIZE; opt = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &opt, sizeof(opt)); total = sz; ptr = data; if(progress) { char *x = strrchr(service, ':'); if(x) service = x + 1; } while(sz > 0) { unsigned xfer = (sz > CHUNK_SIZE) ? CHUNK_SIZE : sz; if(writex(fd, ptr, xfer)) { adb_status(fd); fprintf(stderr,"* failed to write data '%s' *\n", adb_error()); return -1; } sz -= xfer; ptr += xfer; if(progress) { printf("sending: '%s' %4d%% \r", fn, (int)(100LL - ((100LL * sz) / (total)))); fflush(stdout); } } if(progress) { printf("\n"); } if(readx(fd, buf, 4)){ fprintf(stderr,"* error reading response *\n"); adb_close(fd); return -1; } if(memcmp(buf, "OKAY", 4)) { buf[4] = 0; fprintf(stderr,"* error response '%s' *\n", buf); adb_close(fd); return -1; } adb_close(fd); return 0; } int adb_download(const char *service, const char *fn, unsigned progress) { void *data; unsigned sz; data = load_file(fn, &sz); if(data == 0) { fprintf(stderr,"* cannot read '%s' *\n", fn); return -1; } int status = adb_download_buffer(service, fn, data, sz, progress); free(data); return status; } #define SIDELOAD_HOST_BLOCK_SIZE (CHUNK_SIZE) /* * The sideload-host protocol serves the data in a file (given on the * command line) to the client, using a simple protocol: * * - The connect message includes the total number of bytes in the * file and a block size chosen by us. * * - The other side sends the desired block number as eight decimal * digits (eg "00000023" for block 23). Blocks are numbered from * zero. * * - We send back the data of the requested block. The last block is * likely to be partial; when the last block is requested we only * send the part of the block that exists, it's not padded up to the * block size. * * - When the other side sends "DONEDONE" instead of a block number, * we hang up. */ int adb_sideload_host(const char* fn) { uint8_t* data; unsigned sz; size_t xfer = 0; int status; printf("loading: '%s'", fn); fflush(stdout); data = load_file(fn, &sz); if (data == 0) { printf("\n"); fprintf(stderr, "* cannot read '%s' *\n", fn); return -1; } char buf[100]; sprintf(buf, "sideload-host:%d:%d", sz, SIDELOAD_HOST_BLOCK_SIZE); int fd = adb_connect(buf); if (fd < 0) { // Try falling back to the older sideload method. Maybe this // is an older device that doesn't support sideload-host. printf("\n"); status = adb_download_buffer("sideload", fn, data, sz, 1); goto done; } int opt = SIDELOAD_HOST_BLOCK_SIZE; opt = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &opt, sizeof(opt)); int last_percent = -1; for (;;) { if (readx(fd, buf, 8)) { fprintf(stderr, "* failed to read command: %s\n", adb_error()); status = -1; goto done; } if (strncmp("DONEDONE", buf, 8) == 0) { status = 0; break; } buf[8] = '\0'; int block = strtol(buf, NULL, 10); size_t offset = block * SIDELOAD_HOST_BLOCK_SIZE; if (offset >= sz) { fprintf(stderr, "* attempt to read past end: %s\n", adb_error()); status = -1; goto done; } uint8_t* start = data + offset; size_t offset_end = offset + SIDELOAD_HOST_BLOCK_SIZE; size_t to_write = SIDELOAD_HOST_BLOCK_SIZE; if (offset_end > sz) { to_write = sz - offset; } if(writex(fd, start, to_write)) { adb_status(fd); fprintf(stderr,"* failed to write data '%s' *\n", adb_error()); status = -1; goto done; } xfer += to_write; // For normal OTA packages, we expect to transfer every byte // twice, plus a bit of overhead (one read during // verification, one read of each byte for installation, plus // extra access to things like the zip central directory). // This estimate of the completion becomes 100% when we've // transferred ~2.13 (=100/47) times the package size. int percent = (int)(xfer * 47LL / (sz ? sz : 1)); if (percent != last_percent) { printf("\rserving: '%s' (~%d%%) ", fn, percent); fflush(stdout); last_percent = percent; } } printf("\rTotal xfer: %.2fx%*s\n", (double)xfer / (sz ? sz : 1), (int)strlen(fn)+10, ""); done: if (fd >= 0) adb_close(fd); free(data); return status; } static void status_window(transport_type ttype, const char* serial) { char command[4096]; char *state = 0; char *laststate = 0; /* silence stderr */ #ifdef _WIN32 /* XXX: TODO */ #else int fd; fd = unix_open("/dev/null", O_WRONLY); dup2(fd, 2); adb_close(fd); #endif format_host_command(command, sizeof command, "get-state", ttype, serial); for(;;) { adb_sleep_ms(250); if(state) { free(state); state = 0; } state = adb_query(command); if(state) { if(laststate && !strcmp(state,laststate)){ continue; } else { if(laststate) free(laststate); laststate = strdup(state); } } printf("%c[2J%c[2H", 27, 27); printf("Android Debug Bridge\n"); printf("State: %s\n", state ? state : "offline"); fflush(stdout); } } static int should_escape(const char c) { return (c == ' ' || c == '\'' || c == '"' || c == '\\' || c == '(' || c == ')'); } /* Duplicate and escape given argument. */ static char *escape_arg(const char *s) { const char *ts; size_t alloc_len; char *ret; char *dest; alloc_len = 0; for (ts = s; *ts != '\0'; ts++) { alloc_len++; if (should_escape(*ts)) { alloc_len++; } } if (alloc_len == 0) { // Preserve empty arguments ret = (char *) malloc(3); ret[0] = '\"'; ret[1] = '\"'; ret[2] = '\0'; return ret; } ret = (char *) malloc(alloc_len + 1); dest = ret; for (ts = s; *ts != '\0'; ts++) { if (should_escape(*ts)) { *dest++ = '\\'; } *dest++ = *ts; } *dest++ = '\0'; return ret; } /** * Run ppp in "notty" mode against a resource listed as the first parameter * eg: * * ppp dev:/dev/omap_csmi_tty0 * */ int ppp(int argc, char **argv) { #ifdef HAVE_WIN32_PROC fprintf(stderr, "error: adb %s not implemented on Win32\n", argv[0]); return -1; #else char *adb_service_name; pid_t pid; int fd; if (argc < 2) { fprintf(stderr, "usage: adb %s [ppp opts]\n", argv[0]); return 1; } adb_service_name = argv[1]; fd = adb_connect(adb_service_name); if(fd < 0) { fprintf(stderr,"Error: Could not open adb service: %s. Error: %s\n", adb_service_name, adb_error()); return 1; } pid = fork(); if (pid < 0) { perror("from fork()"); return 1; } else if (pid == 0) { int err; int i; const char **ppp_args; // copy args ppp_args = (const char **) alloca(sizeof(char *) * argc + 1); ppp_args[0] = "pppd"; for (i = 2 ; i < argc ; i++) { //argv[2] and beyond become ppp_args[1] and beyond ppp_args[i - 1] = argv[i]; } ppp_args[i-1] = NULL; // child side dup2(fd, STDIN_FILENO); dup2(fd, STDOUT_FILENO); adb_close(STDERR_FILENO); adb_close(fd); err = execvp("pppd", (char * const *)ppp_args); if (err < 0) { perror("execing pppd"); } exit(-1); } else { // parent side adb_close(fd); return 0; } #endif /* !HAVE_WIN32_PROC */ } static int send_shellcommand(transport_type transport, char* serial, char* buf) { int fd, ret; for(;;) { fd = adb_connect(buf); if(fd >= 0) break; fprintf(stderr,"- waiting for device -\n"); adb_sleep_ms(1000); do_cmd(transport, serial, "wait-for-device", 0); } read_and_dump(fd); ret = adb_close(fd); if (ret) perror("close"); return ret; } static int logcat(transport_type transport, char* serial, int argc, char **argv) { char buf[4096]; char *log_tags; char *quoted; log_tags = getenv("ANDROID_LOG_TAGS"); quoted = escape_arg(log_tags == NULL ? "" : log_tags); snprintf(buf, sizeof(buf), "shell:export ANDROID_LOG_TAGS=\"%s\"; exec logcat", quoted); free(quoted); if (!strcmp(argv[0], "longcat")) { strncat(buf, " -v long", sizeof(buf) - 1); } argc -= 1; argv += 1; while(argc-- > 0) { quoted = escape_arg(*argv++); strncat(buf, " ", sizeof(buf) - 1); strncat(buf, quoted, sizeof(buf) - 1); free(quoted); } send_shellcommand(transport, serial, buf); return 0; } static int mkdirs(const char *path) { int ret; char *x = (char *)path + 1; for(;;) { x = adb_dirstart(x); if(x == 0) return 0; *x = 0; ret = adb_mkdir(path, 0775); *x = OS_PATH_SEPARATOR; if((ret < 0) && (errno != EEXIST)) { return ret; } x++; } return 0; } static int backup(int argc, char** argv) { char buf[4096]; char default_name[32]; const char* filename = strcpy(default_name, "./backup.ab"); int fd, outFd; int i, j; /* find, extract, and use any -f argument */ for (i = 1; i < argc; i++) { if (!strcmp("-f", argv[i])) { if (i == argc-1) { fprintf(stderr, "adb: -f passed with no filename\n"); return usage(); } filename = argv[i+1]; for (j = i+2; j <= argc; ) { argv[i++] = argv[j++]; } argc -= 2; argv[argc] = NULL; } } /* bare "adb backup" or "adb backup -f filename" are not valid invocations */ if (argc < 2) return usage(); adb_unlink(filename); mkdirs(filename); outFd = adb_creat(filename, 0640); if (outFd < 0) { fprintf(stderr, "adb: unable to open file %s\n", filename); return -1; } snprintf(buf, sizeof(buf), "backup"); for (argc--, argv++; argc; argc--, argv++) { strncat(buf, ":", sizeof(buf) - strlen(buf) - 1); strncat(buf, argv[0], sizeof(buf) - strlen(buf) - 1); } D("backup. filename=%s buf=%s\n", filename, buf); fd = adb_connect(buf); if (fd < 0) { fprintf(stderr, "adb: unable to connect for backup\n"); adb_close(outFd); return -1; } printf("Now unlock your device and confirm the backup operation.\n"); copy_to_file(fd, outFd); adb_close(fd); adb_close(outFd); return 0; } static int restore(int argc, char** argv) { const char* filename; int fd, tarFd; if (argc != 2) return usage(); filename = argv[1]; tarFd = adb_open(filename, O_RDONLY); if (tarFd < 0) { fprintf(stderr, "adb: unable to open file %s\n", filename); return -1; } fd = adb_connect("restore:"); if (fd < 0) { fprintf(stderr, "adb: unable to connect for restore\n"); adb_close(tarFd); return -1; } printf("Now unlock your device and confirm the restore operation.\n"); copy_to_file(tarFd, fd); adb_close(fd); adb_close(tarFd); return 0; } #define SENTINEL_FILE "config" OS_PATH_SEPARATOR_STR "envsetup.make" static int top_works(const char *top) { if (top != NULL && adb_is_absolute_host_path(top)) { char path_buf[PATH_MAX]; snprintf(path_buf, sizeof(path_buf), "%s" OS_PATH_SEPARATOR_STR SENTINEL_FILE, top); return access(path_buf, F_OK) == 0; } return 0; } static char *find_top_from(const char *indir, char path_buf[PATH_MAX]) { strcpy(path_buf, indir); while (1) { if (top_works(path_buf)) { return path_buf; } char *s = adb_dirstop(path_buf); if (s != NULL) { *s = '\0'; } else { path_buf[0] = '\0'; return NULL; } } } static char *find_top(char path_buf[PATH_MAX]) { char *top = getenv("ANDROID_BUILD_TOP"); if (top != NULL && top[0] != '\0') { if (!top_works(top)) { fprintf(stderr, "adb: bad ANDROID_BUILD_TOP value \"%s\"\n", top); return NULL; } } else { top = getenv("TOP"); if (top != NULL && top[0] != '\0') { if (!top_works(top)) { fprintf(stderr, "adb: bad TOP value \"%s\"\n", top); return NULL; } } else { top = NULL; } } if (top != NULL) { /* The environment pointed to a top directory that works. */ strcpy(path_buf, top); return path_buf; } /* The environment didn't help. Walk up the tree from the CWD * to see if we can find the top. */ char dir[PATH_MAX]; top = find_top_from(getcwd(dir, sizeof(dir)), path_buf); if (top == NULL) { /* If the CWD isn't under a good-looking top, see if the * executable is. */ get_my_path(dir, PATH_MAX); top = find_top_from(dir, path_buf); } return top; } /* may be: * - A simple product name * e.g., "sooner" TODO: debug? sooner-debug, sooner:debug? * - A relative path from the CWD to the ANDROID_PRODUCT_OUT dir * e.g., "out/target/product/sooner" * - An absolute path to the PRODUCT_OUT dir * e.g., "/src/device/out/target/product/sooner" * * Given , try to construct an absolute path to the * ANDROID_PRODUCT_OUT dir. */ static const char *find_product_out_path(const char *hint) { static char path_buf[PATH_MAX]; if (hint == NULL || hint[0] == '\0') { return NULL; } /* If it's already absolute, don't bother doing any work. */ if (adb_is_absolute_host_path(hint)) { strcpy(path_buf, hint); return path_buf; } /* If there are any slashes in it, assume it's a relative path; * make it absolute. */ if (adb_dirstart(hint) != NULL) { if (getcwd(path_buf, sizeof(path_buf)) == NULL) { fprintf(stderr, "adb: Couldn't get CWD: %s\n", strerror(errno)); return NULL; } if (strlen(path_buf) + 1 + strlen(hint) >= sizeof(path_buf)) { fprintf(stderr, "adb: Couldn't assemble path\n"); return NULL; } strcat(path_buf, OS_PATH_SEPARATOR_STR); strcat(path_buf, hint); return path_buf; } /* It's a string without any slashes. Try to do something with it. * * Try to find the root of the build tree, and build a PRODUCT_OUT * path from there. */ char top_buf[PATH_MAX]; const char *top = find_top(top_buf); if (top == NULL) { fprintf(stderr, "adb: Couldn't find top of build tree\n"); return NULL; } //TODO: if we have a way to indicate debug, look in out/debug/target/... snprintf(path_buf, sizeof(path_buf), "%s" OS_PATH_SEPARATOR_STR "out" OS_PATH_SEPARATOR_STR "target" OS_PATH_SEPARATOR_STR "product" OS_PATH_SEPARATOR_STR "%s", top_buf, hint); if (access(path_buf, F_OK) < 0) { fprintf(stderr, "adb: Couldn't find a product dir " "based on \"-p %s\"; \"%s\" doesn't exist\n", hint, path_buf); return NULL; } return path_buf; } static void parse_push_pull_args(char **arg, int narg, char const **path1, char const **path2, int *show_progress, int *copy_attrs) { *show_progress = 0; *copy_attrs = 0; while (narg > 0) { if (!strcmp(*arg, "-p")) { *show_progress = 1; } else if (!strcmp(*arg, "-a")) { *copy_attrs = 1; } else { break; } ++arg; --narg; } if (narg > 0) { *path1 = *arg; ++arg; --narg; } if (narg > 0) { *path2 = *arg; } } int adb_commandline(int argc, char **argv) { char buf[4096]; int no_daemon = 0; int is_daemon = 0; int is_server = 0; int persist = 0; int r; transport_type ttype = kTransportAny; char* serial = NULL; char* server_port_str = NULL; /* If defined, this should be an absolute path to * the directory containing all of the various system images * for a particular product. If not defined, and the adb * command requires this information, then the user must * specify the path using "-p". */ gProductOutPath = getenv("ANDROID_PRODUCT_OUT"); if (gProductOutPath == NULL || gProductOutPath[0] == '\0') { gProductOutPath = NULL; } // TODO: also try TARGET_PRODUCT/TARGET_DEVICE as a hint serial = getenv("ANDROID_SERIAL"); /* Validate and assign the server port */ server_port_str = getenv("ANDROID_ADB_SERVER_PORT"); int server_port = DEFAULT_ADB_PORT; if (server_port_str && strlen(server_port_str) > 0) { server_port = (int) strtol(server_port_str, NULL, 0); if (server_port <= 0 || server_port > 65535) { fprintf(stderr, "adb: Env var ANDROID_ADB_SERVER_PORT must be a positive number less than 65535. Got \"%s\"\n", server_port_str); return usage(); } } /* modifiers and flags */ while(argc > 0) { if(!strcmp(argv[0],"server")) { is_server = 1; } else if(!strcmp(argv[0],"nodaemon")) { no_daemon = 1; } else if (!strcmp(argv[0], "fork-server")) { /* this is a special flag used only when the ADB client launches the ADB Server */ is_daemon = 1; } else if(!strcmp(argv[0],"persist")) { persist = 1; } else if(!strncmp(argv[0], "-p", 2)) { const char *product = NULL; if (argv[0][2] == '\0') { if (argc < 2) return usage(); product = argv[1]; argc--; argv++; } else { product = argv[0] + 2; } gProductOutPath = find_product_out_path(product); if (gProductOutPath == NULL) { fprintf(stderr, "adb: could not resolve \"-p %s\"\n", product); return usage(); } } else if (argv[0][0]=='-' && argv[0][1]=='s') { if (isdigit(argv[0][2])) { serial = argv[0] + 2; } else { if(argc < 2 || argv[0][2] != '\0') return usage(); serial = argv[1]; argc--; argv++; } } else if (!strcmp(argv[0],"-d")) { ttype = kTransportUsb; } else if (!strcmp(argv[0],"-e")) { ttype = kTransportLocal; } else if (!strcmp(argv[0],"-a")) { gListenAll = 1; } else if(!strncmp(argv[0], "-H", 2)) { const char *hostname = NULL; if (argv[0][2] == '\0') { if (argc < 2) return usage(); hostname = argv[1]; argc--; argv++; } else { hostname = argv[0] + 2; } adb_set_tcp_name(hostname); } else if(!strncmp(argv[0], "-P", 2)) { if (argv[0][2] == '\0') { if (argc < 2) return usage(); server_port_str = argv[1]; argc--; argv++; } else { server_port_str = argv[0] + 2; } if (strlen(server_port_str) > 0) { server_port = (int) strtol(server_port_str, NULL, 0); if (server_port <= 0 || server_port > 65535) { fprintf(stderr, "adb: port number must be a positive number less than 65536. Got \"%s\"\n", server_port_str); return usage(); } } else { fprintf(stderr, "adb: port number must be a positive number less than 65536. Got empty string.\n"); return usage(); } } else { /* out of recognized modifiers and flags */ break; } argc--; argv++; } adb_set_transport(ttype, serial); adb_set_tcp_specifics(server_port); if (is_server) { if (no_daemon || is_daemon) { r = adb_main(is_daemon, server_port); } else { r = launch_server(server_port); } if(r) { fprintf(stderr,"* could not start server *\n"); } return r; } top: if(argc == 0) { return usage(); } /* adb_connect() commands */ if(!strcmp(argv[0], "devices")) { char *tmp; char *listopt; if (argc < 2) listopt = ""; else if (argc == 2 && !strcmp(argv[1], "-l")) listopt = argv[1]; else { fprintf(stderr, "Usage: adb devices [-l]\n"); return 1; } snprintf(buf, sizeof buf, "host:%s%s", argv[0], listopt); tmp = adb_query(buf); if(tmp) { printf("List of devices attached \n"); printf("%s\n", tmp); return 0; } else { return 1; } } if(!strcmp(argv[0], "connect")) { char *tmp; if (argc != 2) { fprintf(stderr, "Usage: adb connect [:]\n"); return 1; } snprintf(buf, sizeof buf, "host:connect:%s", argv[1]); tmp = adb_query(buf); if(tmp) { printf("%s\n", tmp); return 0; } else { return 1; } } if(!strcmp(argv[0], "disconnect")) { char *tmp; if (argc > 2) { fprintf(stderr, "Usage: adb disconnect [[:]]\n"); return 1; } if (argc == 2) { snprintf(buf, sizeof buf, "host:disconnect:%s", argv[1]); } else { snprintf(buf, sizeof buf, "host:disconnect:"); } tmp = adb_query(buf); if(tmp) { printf("%s\n", tmp); return 0; } else { return 1; } } if (!strcmp(argv[0], "emu")) { return adb_send_emulator_command(argc, argv); } if(!strcmp(argv[0], "shell") || !strcmp(argv[0], "hell")) { int r; int fd; char h = (argv[0][0] == 'h'); if (h) { printf("\x1b[41;33m"); fflush(stdout); } if(argc < 2) { D("starting interactive shell\n"); r = interactive_shell(); if (h) { printf("\x1b[0m"); fflush(stdout); } return r; } snprintf(buf, sizeof(buf), "shell:%s", argv[1]); argc -= 2; argv += 2; while (argc-- > 0) { char *quoted = escape_arg(*argv++); strncat(buf, " ", sizeof(buf) - 1); strncat(buf, quoted, sizeof(buf) - 1); free(quoted); } for(;;) { D("interactive shell loop. buff=%s\n", buf); fd = adb_connect(buf); if(fd >= 0) { D("about to read_and_dump(fd=%d)\n", fd); read_and_dump(fd); D("read_and_dump() done.\n"); adb_close(fd); r = 0; } else { fprintf(stderr,"error: %s\n", adb_error()); r = -1; } if(persist) { fprintf(stderr,"\n- waiting for device -\n"); adb_sleep_ms(1000); do_cmd(ttype, serial, "wait-for-device", 0); } else { if (h) { printf("\x1b[0m"); fflush(stdout); } D("interactive shell loop. return r=%d\n", r); return r; } } } if (!strcmp(argv[0], "exec-in") || !strcmp(argv[0], "exec-out")) { int exec_in = !strcmp(argv[0], "exec-in"); int fd; snprintf(buf, sizeof buf, "exec:%s", argv[1]); argc -= 2; argv += 2; while (argc-- > 0) { char *quoted = escape_arg(*argv++); strncat(buf, " ", sizeof(buf) - 1); strncat(buf, quoted, sizeof(buf) - 1); free(quoted); } fd = adb_connect(buf); if (fd < 0) { fprintf(stderr, "error: %s\n", adb_error()); return -1; } if (exec_in) { copy_to_file(STDIN_FILENO, fd); } else { copy_to_file(fd, STDOUT_FILENO); } adb_close(fd); return 0; } if(!strcmp(argv[0], "kill-server")) { int fd; fd = _adb_connect("host:kill"); if(fd == -1) { fprintf(stderr,"* server not running *\n"); return 1; } return 0; } if(!strcmp(argv[0], "sideload")) { if(argc != 2) return usage(); if (adb_sideload_host(argv[1])) { return 1; } else { return 0; } } if(!strcmp(argv[0], "remount") || !strcmp(argv[0], "reboot") || !strcmp(argv[0], "reboot-bootloader") || !strcmp(argv[0], "tcpip") || !strcmp(argv[0], "usb") || !strcmp(argv[0], "root") || !strcmp(argv[0], "disable-verity")) { char command[100]; if (!strcmp(argv[0], "reboot-bootloader")) snprintf(command, sizeof(command), "reboot:bootloader"); else if (argc > 1) snprintf(command, sizeof(command), "%s:%s", argv[0], argv[1]); else snprintf(command, sizeof(command), "%s:", argv[0]); int fd = adb_connect(command); if(fd >= 0) { read_and_dump(fd); adb_close(fd); return 0; } fprintf(stderr,"error: %s\n", adb_error()); return 1; } if(!strcmp(argv[0], "bugreport")) { if (argc != 1) return usage(); do_cmd(ttype, serial, "shell", "bugreport", 0); return 0; } /* adb_command() wrapper commands */ if(!strncmp(argv[0], "wait-for-", strlen("wait-for-"))) { char* service = argv[0]; if (!strncmp(service, "wait-for-device", strlen("wait-for-device"))) { if (ttype == kTransportUsb) { service = "wait-for-usb"; } else if (ttype == kTransportLocal) { service = "wait-for-local"; } else { service = "wait-for-any"; } } format_host_command(buf, sizeof buf, service, ttype, serial); if (adb_command(buf)) { D("failure: %s *\n",adb_error()); fprintf(stderr,"error: %s\n", adb_error()); return 1; } /* Allow a command to be run after wait-for-device, * e.g. 'adb wait-for-device shell'. */ if(argc > 1) { argc--; argv++; goto top; } return 0; } if(!strcmp(argv[0], "forward") || !strcmp(argv[0], "reverse")) { char host_prefix[64]; char reverse = (char) !strcmp(argv[0], "reverse"); char remove = 0; char remove_all = 0; char list = 0; char no_rebind = 0; // Parse options here. while (argc > 1 && argv[1][0] == '-') { if (!strcmp(argv[1], "--list")) list = 1; else if (!strcmp(argv[1], "--remove")) remove = 1; else if (!strcmp(argv[1], "--remove-all")) remove_all = 1; else if (!strcmp(argv[1], "--no-rebind")) no_rebind = 1; else { return usage(); } argc--; argv++; } // Ensure we can only use one option at a time. if (list + remove + remove_all + no_rebind > 1) { return usage(); } // Determine the for this command. if (reverse) { snprintf(host_prefix, sizeof host_prefix, "reverse"); } else { if (serial) { snprintf(host_prefix, sizeof host_prefix, "host-serial:%s", serial); } else if (ttype == kTransportUsb) { snprintf(host_prefix, sizeof host_prefix, "host-usb"); } else if (ttype == kTransportLocal) { snprintf(host_prefix, sizeof host_prefix, "host-local"); } else { snprintf(host_prefix, sizeof host_prefix, "host"); } } // Implement forward --list if (list) { if (argc != 1) return usage(); snprintf(buf, sizeof buf, "%s:list-forward", host_prefix); char* forwards = adb_query(buf); if (forwards == NULL) { fprintf(stderr, "error: %s\n", adb_error()); return 1; } printf("%s", forwards); free(forwards); return 0; } // Implement forward --remove-all else if (remove_all) { if (argc != 1) return usage(); snprintf(buf, sizeof buf, "%s:killforward-all", host_prefix); } // Implement forward --remove else if (remove) { if (argc != 2) return usage(); snprintf(buf, sizeof buf, "%s:killforward:%s", host_prefix, argv[1]); } // Or implement one of: // forward // forward --no-rebind else { if (argc != 3) return usage(); const char* command = no_rebind ? "forward:norebind:" : "forward"; snprintf(buf, sizeof buf, "%s:%s:%s;%s", host_prefix, command, argv[1], argv[2]); } if(adb_command(buf)) { fprintf(stderr,"error: %s\n", adb_error()); return 1; } return 0; } /* do_sync_*() commands */ if(!strcmp(argv[0], "ls")) { if(argc != 2) return usage(); return do_sync_ls(argv[1]); } if(!strcmp(argv[0], "push")) { int show_progress = 0; int copy_attrs = 0; // unused const char* lpath = NULL, *rpath = NULL; parse_push_pull_args(&argv[1], argc - 1, &lpath, &rpath, &show_progress, ©_attrs); if ((lpath != NULL) && (rpath != NULL)) { return do_sync_push(lpath, rpath, show_progress); } return usage(); } if(!strcmp(argv[0], "pull")) { int show_progress = 0; int copy_attrs = 0; const char* rpath = NULL, *lpath = "."; parse_push_pull_args(&argv[1], argc - 1, &rpath, &lpath, &show_progress, ©_attrs); if (rpath != NULL) { return do_sync_pull(rpath, lpath, show_progress, copy_attrs); } return usage(); } if (!strcmp(argv[0], "install")) { if (argc < 2) return usage(); return install_app(ttype, serial, argc, argv); } if (!strcmp(argv[0], "install-multiple")) { if (argc < 2) return usage(); return install_multiple_app(ttype, serial, argc, argv); } if (!strcmp(argv[0], "uninstall")) { if (argc < 2) return usage(); return uninstall_app(ttype, serial, argc, argv); } if(!strcmp(argv[0], "sync")) { char *srcarg, *android_srcpath, *data_srcpath, *vendor_srcpath; int listonly = 0; int ret; if(argc < 2) { /* No local path was specified. */ srcarg = NULL; } else if (argc >= 2 && strcmp(argv[1], "-l") == 0) { listonly = 1; if (argc == 3) { srcarg = argv[2]; } else { srcarg = NULL; } } else if(argc == 2) { /* A local path or "android"/"data" arg was specified. */ srcarg = argv[1]; } else { return usage(); } ret = find_sync_dirs(srcarg, &android_srcpath, &data_srcpath, &vendor_srcpath); if(ret != 0) return usage(); if(android_srcpath != NULL) ret = do_sync_sync(android_srcpath, "/system", listonly); if(ret == 0 && vendor_srcpath != NULL) ret = do_sync_sync(vendor_srcpath, "/vendor", listonly); if(ret == 0 && data_srcpath != NULL) ret = do_sync_sync(data_srcpath, "/data", listonly); free(android_srcpath); free(vendor_srcpath); free(data_srcpath); return ret; } /* passthrough commands */ if(!strcmp(argv[0],"get-state") || !strcmp(argv[0],"get-serialno") || !strcmp(argv[0],"get-devpath")) { char *tmp; format_host_command(buf, sizeof buf, argv[0], ttype, serial); tmp = adb_query(buf); if(tmp) { printf("%s\n", tmp); return 0; } else { return 1; } } /* other commands */ if(!strcmp(argv[0],"status-window")) { status_window(ttype, serial); return 0; } if(!strcmp(argv[0],"logcat") || !strcmp(argv[0],"lolcat") || !strcmp(argv[0],"longcat")) { return logcat(ttype, serial, argc, argv); } if(!strcmp(argv[0],"ppp")) { return ppp(argc, argv); } if (!strcmp(argv[0], "start-server")) { return adb_connect("host:start-server"); } if (!strcmp(argv[0], "backup")) { return backup(argc, argv); } if (!strcmp(argv[0], "restore")) { return restore(argc, argv); } if (!strcmp(argv[0], "keygen")) { if (argc < 2) return usage(); return adb_auth_keygen(argv[1]); } if (!strcmp(argv[0], "jdwp")) { int fd = adb_connect("jdwp"); if (fd >= 0) { read_and_dump(fd); adb_close(fd); return 0; } else { fprintf(stderr, "error: %s\n", adb_error()); return -1; } } /* "adb /?" is a common idiom under Windows */ if(!strcmp(argv[0], "help") || !strcmp(argv[0], "/?")) { help(); return 0; } if(!strcmp(argv[0], "version")) { version(stdout); return 0; } usage(); return 1; } #define MAX_ARGV_LENGTH 16 static int do_cmd(transport_type ttype, char* serial, char *cmd, ...) { char *argv[MAX_ARGV_LENGTH]; int argc; va_list ap; va_start(ap, cmd); argc = 0; if (serial) { argv[argc++] = "-s"; argv[argc++] = serial; } else if (ttype == kTransportUsb) { argv[argc++] = "-d"; } else if (ttype == kTransportLocal) { argv[argc++] = "-e"; } argv[argc++] = cmd; while(argc < MAX_ARGV_LENGTH && (argv[argc] = va_arg(ap, char*)) != 0) argc++; assert(argc < MAX_ARGV_LENGTH); va_end(ap); #if 0 int n; fprintf(stderr,"argc = %d\n",argc); for(n = 0; n < argc; n++) { fprintf(stderr,"argv[%d] = \"%s\"\n", n, argv[n]); } #endif return adb_commandline(argc, argv); } int find_sync_dirs(const char *srcarg, char **android_srcdir_out, char **data_srcdir_out, char **vendor_srcdir_out) { char *android_srcdir = NULL, *data_srcdir = NULL, *vendor_srcdir = NULL; struct stat st; if(srcarg == NULL) { android_srcdir = product_file("system"); data_srcdir = product_file("data"); vendor_srcdir = product_file("vendor"); /* Check if vendor partition exists */ if (lstat(vendor_srcdir, &st) || !S_ISDIR(st.st_mode)) vendor_srcdir = NULL; } else { /* srcarg may be "data", "system" or NULL. * if srcarg is NULL, then both data and system are synced */ if(strcmp(srcarg, "system") == 0) { android_srcdir = product_file("system"); } else if(strcmp(srcarg, "data") == 0) { data_srcdir = product_file("data"); } else if(strcmp(srcarg, "vendor") == 0) { vendor_srcdir = product_file("vendor"); } else { /* It's not "system", "vendor", or "data". */ return 1; } } if(android_srcdir_out != NULL) *android_srcdir_out = android_srcdir; else free(android_srcdir); if(vendor_srcdir_out != NULL) *vendor_srcdir_out = vendor_srcdir; else free(vendor_srcdir); if(data_srcdir_out != NULL) *data_srcdir_out = data_srcdir; else free(data_srcdir); return 0; } static int pm_command(transport_type transport, char* serial, int argc, char** argv) { char buf[4096]; snprintf(buf, sizeof(buf), "shell:pm"); while(argc-- > 0) { char *quoted = escape_arg(*argv++); strncat(buf, " ", sizeof(buf) - 1); strncat(buf, quoted, sizeof(buf) - 1); free(quoted); } send_shellcommand(transport, serial, buf); return 0; } int uninstall_app(transport_type transport, char* serial, int argc, char** argv) { /* if the user choose the -k option, we refuse to do it until devices are out with the option to uninstall the remaining data somehow (adb/ui) */ if (argc == 3 && strcmp(argv[1], "-k") == 0) { printf( "The -k option uninstalls the application while retaining the data/cache.\n" "At the moment, there is no way to remove the remaining data.\n" "You will have to reinstall the application with the same signature, and fully uninstall it.\n" "If you truly wish to continue, execute 'adb shell pm uninstall -k %s'\n", argv[2]); return -1; } /* 'adb uninstall' takes the same arguments as 'pm uninstall' on device */ return pm_command(transport, serial, argc, argv); } static int delete_file(transport_type transport, char* serial, char* filename) { char buf[4096]; char* quoted; snprintf(buf, sizeof(buf), "shell:rm -f "); quoted = escape_arg(filename); strncat(buf, quoted, sizeof(buf)-1); free(quoted); send_shellcommand(transport, serial, buf); return 0; } static const char* get_basename(const char* filename) { const char* basename = adb_dirstop(filename); if (basename) { basename++; return basename; } else { return filename; } } int install_app(transport_type transport, char* serial, int argc, char** argv) { static const char *const DATA_DEST = "/data/local/tmp/%s"; static const char *const SD_DEST = "/sdcard/tmp/%s"; const char* where = DATA_DEST; int i; struct stat sb; for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-s")) { where = SD_DEST; } } // Find last APK argument. // All other arguments passed through verbatim. int last_apk = -1; for (i = argc - 1; i >= 0; i--) { char* file = argv[i]; char* dot = strrchr(file, '.'); if (dot && !strcasecmp(dot, ".apk")) { if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) { fprintf(stderr, "Invalid APK file: %s\n", file); return -1; } last_apk = i; break; } } if (last_apk == -1) { fprintf(stderr, "Missing APK file\n"); return -1; } char* apk_file = argv[last_apk]; char apk_dest[PATH_MAX]; snprintf(apk_dest, sizeof apk_dest, where, get_basename(apk_file)); int err = do_sync_push(apk_file, apk_dest, 0 /* no show progress */); if (err) { goto cleanup_apk; } else { argv[last_apk] = apk_dest; /* destination name, not source location */ } pm_command(transport, serial, argc, argv); cleanup_apk: delete_file(transport, serial, apk_dest); return err; } int install_multiple_app(transport_type transport, char* serial, int argc, char** argv) { char buf[1024]; int i; struct stat sb; unsigned long long total_size = 0; // Find all APK arguments starting at end. // All other arguments passed through verbatim. int first_apk = -1; for (i = argc - 1; i >= 0; i--) { char* file = argv[i]; char* dot = strrchr(file, '.'); if (dot && !strcasecmp(dot, ".apk")) { if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) { fprintf(stderr, "Invalid APK file: %s\n", file); return -1; } total_size += sb.st_size; first_apk = i; } else { break; } } if (first_apk == -1) { fprintf(stderr, "Missing APK file\n"); return 1; } snprintf(buf, sizeof(buf), "exec:pm install-create -S %lld", total_size); for (i = 1; i < first_apk; i++) { char *quoted = escape_arg(argv[i]); strncat(buf, " ", sizeof(buf) - 1); strncat(buf, quoted, sizeof(buf) - 1); free(quoted); } // Create install session int fd = adb_connect(buf); if (fd < 0) { fprintf(stderr, "Connect error for create: %s\n", adb_error()); return -1; } read_status_line(fd, buf, sizeof(buf)); adb_close(fd); int session_id = -1; if (!strncmp("Success", buf, 7)) { char* start = strrchr(buf, '['); char* end = strrchr(buf, ']'); if (start && end) { *end = '\0'; session_id = strtol(start + 1, NULL, 10); } } if (session_id < 0) { fprintf(stderr, "Failed to create session\n"); fputs(buf, stderr); return -1; } // Valid session, now stream the APKs int success = 1; for (i = first_apk; i < argc; i++) { char* file = argv[i]; if (stat(file, &sb) == -1) { fprintf(stderr, "Failed to stat %s\n", file); success = 0; goto finalize_session; } snprintf(buf, sizeof(buf), "exec:pm install-write -S %lld %d %d_%s -", (long long int) sb.st_size, session_id, i, get_basename(file)); int localFd = adb_open(file, O_RDONLY); if (localFd < 0) { fprintf(stderr, "Failed to open %s: %s\n", file, adb_error()); success = 0; goto finalize_session; } int remoteFd = adb_connect(buf); if (remoteFd < 0) { fprintf(stderr, "Connect error for write: %s\n", adb_error()); adb_close(localFd); success = 0; goto finalize_session; } copy_to_file(localFd, remoteFd); read_status_line(remoteFd, buf, sizeof(buf)); adb_close(localFd); adb_close(remoteFd); if (strncmp("Success", buf, 7)) { fprintf(stderr, "Failed to write %s\n", file); fputs(buf, stderr); success = 0; goto finalize_session; } } finalize_session: // Commit session if we streamed everything okay; otherwise abandon if (success) { snprintf(buf, sizeof(buf), "exec:pm install-commit %d", session_id); } else { snprintf(buf, sizeof(buf), "exec:pm install-abandon %d", session_id); } fd = adb_connect(buf); if (fd < 0) { fprintf(stderr, "Connect error for finalize: %s\n", adb_error()); return -1; } read_status_line(fd, buf, sizeof(buf)); adb_close(fd); if (!strncmp("Success", buf, 7)) { fputs(buf, stderr); return 0; } else { fprintf(stderr, "Failed to finalize session\n"); fputs(buf, stderr); return -1; } } android-tools-5.1.1r36+git20160322/core/adb/console.c000066400000000000000000000017611267427243200215300ustar00rootroot00000000000000#include "sysdeps.h" #include "adb.h" #include "adb_client.h" #include static int connect_to_console(void) { int fd, port; port = adb_get_emulator_console_port(); if (port < 0) { if (port == -2) fprintf(stderr, "error: more than one emulator detected. use -s option\n"); else fprintf(stderr, "error: no emulator detected\n"); return -1; } fd = socket_loopback_client( port, SOCK_STREAM ); if (fd < 0) { fprintf(stderr, "error: could not connect to TCP port %d\n", port); return -1; } return fd; } int adb_send_emulator_command(int argc, char** argv) { int fd, nn; fd = connect_to_console(); if (fd < 0) return 1; #define QUIT "quit\n" for (nn = 1; nn < argc; nn++) { adb_write( fd, argv[nn], strlen(argv[nn]) ); adb_write( fd, (nn == argc-1) ? "\n" : " ", 1 ); } adb_write( fd, QUIT, sizeof(QUIT)-1 ); adb_close(fd); return 0; } android-tools-5.1.1r36+git20160322/core/adb/disable_verity_service.c000066400000000000000000000132711267427243200246120ustar00rootroot00000000000000/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "sysdeps.h" #define TRACE_TAG TRACE_ADB #include "adb.h" #include #include #include #include #include #include "cutils/properties.h" #include "ext4_sb.h" #include #define FSTAB_PREFIX "/fstab." struct fstab *fstab; __attribute__((__format__(printf, 2, 3))) __nonnull((2)) static void write_console(int fd, const char* format, ...) { char buffer[256]; va_list args; va_start (args, format); vsnprintf (buffer, sizeof(buffer), format, args); va_end (args); adb_write(fd, buffer, strnlen(buffer, sizeof(buffer))); } static int get_target_device_size(int fd, const char *blk_device, uint64_t *device_size) { int data_device; struct ext4_super_block sb; struct fs_info info; info.len = 0; /* Only len is set to 0 to ask the device for real size. */ data_device = adb_open(blk_device, O_RDONLY | O_CLOEXEC); if (data_device < 0) { write_console(fd, "Error opening block device (%s)\n", strerror(errno)); return -1; } if (lseek64(data_device, 1024, SEEK_SET) < 0) { write_console(fd, "Error seeking to superblock\n"); adb_close(data_device); return -1; } if (adb_read(data_device, &sb, sizeof(sb)) != sizeof(sb)) { write_console(fd, "Error reading superblock\n"); adb_close(data_device); return -1; } ext4_parse_sb(&sb, &info); *device_size = info.len; adb_close(data_device); return 0; } static int disable_verity(int fd, const char *block_device, const char* mount_point) { uint32_t magic_number; const uint32_t voff = VERITY_METADATA_MAGIC_DISABLE; uint64_t device_length; int device; int retval = -1; device = adb_open(block_device, O_RDWR | O_CLOEXEC); if (device == -1) { write_console(fd, "Could not open block device %s (%s).\n", block_device, strerror(errno)); write_console(fd, "Maybe run adb remount?\n"); goto errout; } // find the start of the verity metadata if (get_target_device_size(fd, (char*)block_device, &device_length) < 0) { write_console(fd, "Could not get target device size.\n"); goto errout; } if (lseek64(device, device_length, SEEK_SET) < 0) { write_console(fd, "Could not seek to start of verity metadata block.\n"); goto errout; } // check the magic number if (adb_read(device, &magic_number, sizeof(magic_number)) != sizeof(magic_number)) { write_console(fd, "Couldn't read magic number!\n"); goto errout; } if (magic_number == VERITY_METADATA_MAGIC_DISABLE) { write_console(fd, "Verity already disabled on %s\n", mount_point); goto errout; } if (magic_number != VERITY_METADATA_MAGIC_NUMBER) { write_console(fd, "Couldn't find verity metadata at offset %"PRIu64"!\n", device_length); goto errout; } if (lseek64(device, device_length, SEEK_SET) < 0) { write_console(fd, "Could not seek to start of verity metadata block.\n"); goto errout; } if (adb_write(device, &voff, sizeof(voff)) != sizeof(voff)) { write_console(fd, "Could not set verity disabled flag on device %s\n", block_device); goto errout; } write_console(fd, "Verity disabled on %s\n", mount_point); retval = 0; errout: if (device != -1) adb_close(device); return retval; } void disable_verity_service(int fd, void* cookie) { #ifdef ALLOW_ADBD_DISABLE_VERITY char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)]; char propbuf[PROPERTY_VALUE_MAX]; int i; bool any_disabled = false; property_get("ro.secure", propbuf, "0"); if (strcmp(propbuf, "1")) { write_console(fd, "verity not enabled - ENG build\n"); goto errout; } property_get("ro.debuggable", propbuf, "0"); if (strcmp(propbuf, "1")) { write_console(fd, "verity cannot be disabled - USER build\n"); goto errout; } property_get("ro.hardware", propbuf, ""); snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf); fstab = fs_mgr_read_fstab(fstab_filename); if (!fstab) { write_console(fd, "Failed to open %s\nMaybe run adb root?\n", fstab_filename); goto errout; } /* Loop through entries looking for ones that vold manages */ for (i = 0; i < fstab->num_entries; i++) { if(fs_mgr_is_verified(&fstab->recs[i])) { if (!disable_verity(fd, fstab->recs[i].blk_device, fstab->recs[i].mount_point)) { any_disabled = true; } } } if (any_disabled) { write_console(fd, "Now reboot your device for settings to take effect\n"); } #else write_console(fd, "disable-verity only works for userdebug builds\n"); #endif errout: adb_close(fd); } android-tools-5.1.1r36+git20160322/core/adb/fdevent.c000066400000000000000000000417771267427243200215340ustar00rootroot00000000000000/* http://frotznet.googlecode.com/svn/trunk/utils/fdevent.c ** ** Copyright 2006, Brian Swetland ** ** 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 #include #include #include #include #include #include #include #include #include "adb_trace.h" #include "fdevent.h" #include "transport.h" #include "sysdeps.h" #define TRACE_TAG TRACE_FDEVENT /* !!! Do not enable DEBUG for the adb that will run as the server: ** both stdout and stderr are used to communicate between the client ** and server. Any extra output will cause failures. */ #define DEBUG 0 /* non-0 will break adb server */ // This socket is used when a subproc shell service exists. // It wakes up the fdevent_loop() and cause the correct handling // of the shell's pseudo-tty master. I.e. force close it. int SHELL_EXIT_NOTIFY_FD = -1; static void fatal(const char *fn, const char *fmt, ...) { va_list ap; va_start(ap, fmt); fprintf(stderr, "%s:", fn); vfprintf(stderr, fmt, ap); va_end(ap); abort(); } #define FATAL(x...) fatal(__FUNCTION__, x) #if DEBUG static void dump_fde(fdevent *fde, const char *info) { adb_mutex_lock(&D_lock); fprintf(stderr,"FDE #%03d %c%c%c %s\n", fde->fd, fde->state & FDE_READ ? 'R' : ' ', fde->state & FDE_WRITE ? 'W' : ' ', fde->state & FDE_ERROR ? 'E' : ' ', info); adb_mutex_unlock(&D_lock); } #else #define dump_fde(fde, info) do { } while(0) #endif #define FDE_EVENTMASK 0x00ff #define FDE_STATEMASK 0xff00 #define FDE_ACTIVE 0x0100 #define FDE_PENDING 0x0200 #define FDE_CREATED 0x0400 static void fdevent_plist_enqueue(fdevent *node); static void fdevent_plist_remove(fdevent *node); static fdevent *fdevent_plist_dequeue(void); static void fdevent_subproc_event_func(int fd, unsigned events, void *userdata); static fdevent list_pending = { .next = &list_pending, .prev = &list_pending, }; static fdevent **fd_table = 0; static int fd_table_max = 0; #ifdef CRAPTASTIC //HAVE_EPOLL #include static int epoll_fd = -1; static void fdevent_init() { /* XXX: what's a good size for the passed in hint? */ epoll_fd = epoll_create(256); if(epoll_fd < 0) { perror("epoll_create() failed"); exit(1); } /* mark for close-on-exec */ fcntl(epoll_fd, F_SETFD, FD_CLOEXEC); } static void fdevent_connect(fdevent *fde) { struct epoll_event ev; memset(&ev, 0, sizeof(ev)); ev.events = 0; ev.data.ptr = fde; #if 0 if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fde->fd, &ev)) { perror("epoll_ctl() failed\n"); exit(1); } #endif } static void fdevent_disconnect(fdevent *fde) { struct epoll_event ev; memset(&ev, 0, sizeof(ev)); ev.events = 0; ev.data.ptr = fde; /* technically we only need to delete if we ** were actively monitoring events, but let's ** be aggressive and do it anyway, just in case ** something's out of sync */ epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fde->fd, &ev); } static void fdevent_update(fdevent *fde, unsigned events) { struct epoll_event ev; int active; active = (fde->state & FDE_EVENTMASK) != 0; memset(&ev, 0, sizeof(ev)); ev.events = 0; ev.data.ptr = fde; if(events & FDE_READ) ev.events |= EPOLLIN; if(events & FDE_WRITE) ev.events |= EPOLLOUT; if(events & FDE_ERROR) ev.events |= (EPOLLERR | EPOLLHUP); fde->state = (fde->state & FDE_STATEMASK) | events; if(active) { /* we're already active. if we're changing to *no* ** events being monitored, we need to delete, otherwise ** we need to just modify */ if(ev.events) { if(epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fde->fd, &ev)) { perror("epoll_ctl() failed\n"); exit(1); } } else { if(epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fde->fd, &ev)) { perror("epoll_ctl() failed\n"); exit(1); } } } else { /* we're not active. if we're watching events, we need ** to add, otherwise we can just do nothing */ if(ev.events) { if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fde->fd, &ev)) { perror("epoll_ctl() failed\n"); exit(1); } } } } static void fdevent_process() { struct epoll_event events[256]; fdevent *fde; int i, n; n = epoll_wait(epoll_fd, events, 256, -1); if(n < 0) { if(errno == EINTR) return; perror("epoll_wait"); exit(1); } for(i = 0; i < n; i++) { struct epoll_event *ev = events + i; fde = ev->data.ptr; if(ev->events & EPOLLIN) { fde->events |= FDE_READ; } if(ev->events & EPOLLOUT) { fde->events |= FDE_WRITE; } if(ev->events & (EPOLLERR | EPOLLHUP)) { fde->events |= FDE_ERROR; } if(fde->events) { if(fde->state & FDE_PENDING) continue; fde->state |= FDE_PENDING; fdevent_plist_enqueue(fde); } } } #else /* USE_SELECT */ #ifdef HAVE_WINSOCK #include #else #include #endif static fd_set read_fds; static fd_set write_fds; static fd_set error_fds; static int select_n = 0; static void fdevent_init(void) { FD_ZERO(&read_fds); FD_ZERO(&write_fds); FD_ZERO(&error_fds); } static void fdevent_connect(fdevent *fde) { if(fde->fd >= select_n) { select_n = fde->fd + 1; } } static void fdevent_disconnect(fdevent *fde) { int i, n; FD_CLR(fde->fd, &read_fds); FD_CLR(fde->fd, &write_fds); FD_CLR(fde->fd, &error_fds); for(n = 0, i = 0; i < select_n; i++) { if(fd_table[i] != 0) n = i; } select_n = n + 1; } static void fdevent_update(fdevent *fde, unsigned events) { if(events & FDE_READ) { FD_SET(fde->fd, &read_fds); } else { FD_CLR(fde->fd, &read_fds); } if(events & FDE_WRITE) { FD_SET(fde->fd, &write_fds); } else { FD_CLR(fde->fd, &write_fds); } if(events & FDE_ERROR) { FD_SET(fde->fd, &error_fds); } else { FD_CLR(fde->fd, &error_fds); } fde->state = (fde->state & FDE_STATEMASK) | events; } /* Looks at fd_table[] for bad FDs and sets bit in fds. ** Returns the number of bad FDs. */ static int fdevent_fd_check(fd_set *fds) { int i, n = 0; fdevent *fde; for(i = 0; i < select_n; i++) { fde = fd_table[i]; if(fde == 0) continue; if(fcntl(i, F_GETFL, NULL) < 0) { FD_SET(i, fds); n++; // fde->state |= FDE_DONT_CLOSE; } } return n; } #if !DEBUG static inline void dump_all_fds(const char *extra_msg) {} #else static void dump_all_fds(const char *extra_msg) { int i; fdevent *fde; // per fd: 4 digits (but really: log10(FD_SETSIZE)), 1 staus, 1 blank char msg_buff[FD_SETSIZE*6 + 1], *pb=msg_buff; size_t max_chars = FD_SETSIZE * 6 + 1; int printed_out; #define SAFE_SPRINTF(...) \ do { \ printed_out = snprintf(pb, max_chars, __VA_ARGS__); \ if (printed_out <= 0) { \ D("... snprintf failed.\n"); \ return; \ } \ if (max_chars < (unsigned int)printed_out) { \ D("... snprintf out of space.\n"); \ return; \ } \ pb += printed_out; \ max_chars -= printed_out; \ } while(0) for(i = 0; i < select_n; i++) { fde = fd_table[i]; SAFE_SPRINTF("%d", i); if(fde == 0) { SAFE_SPRINTF("? "); continue; } if(fcntl(i, F_GETFL, NULL) < 0) { SAFE_SPRINTF("b"); } SAFE_SPRINTF(" "); } D("%s fd_table[]->fd = {%s}\n", extra_msg, msg_buff); } #endif static void fdevent_process() { int i, n; fdevent *fde; unsigned events; fd_set rfd, wfd, efd; memcpy(&rfd, &read_fds, sizeof(fd_set)); memcpy(&wfd, &write_fds, sizeof(fd_set)); memcpy(&efd, &error_fds, sizeof(fd_set)); dump_all_fds("pre select()"); n = select(select_n, &rfd, &wfd, &efd, NULL); int saved_errno = errno; D("select() returned n=%d, errno=%d\n", n, n<0?saved_errno:0); dump_all_fds("post select()"); if(n < 0) { switch(saved_errno) { case EINTR: return; case EBADF: // Can't trust the FD sets after an error. FD_ZERO(&wfd); FD_ZERO(&efd); FD_ZERO(&rfd); break; default: D("Unexpected select() error=%d\n", saved_errno); return; } } if(n <= 0) { // We fake a read, as the rest of the code assumes // that errors will be detected at that point. n = fdevent_fd_check(&rfd); } for(i = 0; (i < select_n) && (n > 0); i++) { events = 0; if(FD_ISSET(i, &rfd)) { events |= FDE_READ; n--; } if(FD_ISSET(i, &wfd)) { events |= FDE_WRITE; n--; } if(FD_ISSET(i, &efd)) { events |= FDE_ERROR; n--; } if(events) { fde = fd_table[i]; if(fde == 0) FATAL("missing fde for fd %d\n", i); fde->events |= events; D("got events fde->fd=%d events=%04x, state=%04x\n", fde->fd, fde->events, fde->state); if(fde->state & FDE_PENDING) continue; fde->state |= FDE_PENDING; fdevent_plist_enqueue(fde); } } } #endif static void fdevent_register(fdevent *fde) { if(fde->fd < 0) { FATAL("bogus negative fd (%d)\n", fde->fd); } if(fde->fd >= fd_table_max) { int oldmax = fd_table_max; if(fde->fd > 32000) { FATAL("bogus huuuuge fd (%d)\n", fde->fd); } if(fd_table_max == 0) { fdevent_init(); fd_table_max = 256; } while(fd_table_max <= fde->fd) { fd_table_max *= 2; } fd_table = realloc(fd_table, sizeof(fdevent*) * fd_table_max); if(fd_table == 0) { FATAL("could not expand fd_table to %d entries\n", fd_table_max); } memset(fd_table + oldmax, 0, sizeof(int) * (fd_table_max - oldmax)); } fd_table[fde->fd] = fde; } static void fdevent_unregister(fdevent *fde) { if((fde->fd < 0) || (fde->fd >= fd_table_max)) { FATAL("fd out of range (%d)\n", fde->fd); } if(fd_table[fde->fd] != fde) { FATAL("fd_table out of sync [%d]\n", fde->fd); } fd_table[fde->fd] = 0; if(!(fde->state & FDE_DONT_CLOSE)) { dump_fde(fde, "close"); adb_close(fde->fd); } } static void fdevent_plist_enqueue(fdevent *node) { fdevent *list = &list_pending; node->next = list; node->prev = list->prev; node->prev->next = node; list->prev = node; } static void fdevent_plist_remove(fdevent *node) { node->prev->next = node->next; node->next->prev = node->prev; node->next = 0; node->prev = 0; } static fdevent *fdevent_plist_dequeue(void) { fdevent *list = &list_pending; fdevent *node = list->next; if(node == list) return 0; list->next = node->next; list->next->prev = list; node->next = 0; node->prev = 0; return node; } static void fdevent_call_fdfunc(fdevent* fde) { unsigned events = fde->events; fde->events = 0; if(!(fde->state & FDE_PENDING)) return; fde->state &= (~FDE_PENDING); dump_fde(fde, "callback"); fde->func(fde->fd, events, fde->arg); } static void fdevent_subproc_event_func(int fd, unsigned ev, void *userdata) { D("subproc handling on fd=%d ev=%04x\n", fd, ev); // Hook oneself back into the fde's suitable for select() on read. if((fd < 0) || (fd >= fd_table_max)) { FATAL("fd %d out of range for fd_table \n", fd); } fdevent *fde = fd_table[fd]; fdevent_add(fde, FDE_READ); if(ev & FDE_READ){ int subproc_fd; if(readx(fd, &subproc_fd, sizeof(subproc_fd))) { FATAL("Failed to read the subproc's fd from fd=%d\n", fd); } if((subproc_fd < 0) || (subproc_fd >= fd_table_max)) { D("subproc_fd %d out of range 0, fd_table_max=%d\n", subproc_fd, fd_table_max); return; } fdevent *subproc_fde = fd_table[subproc_fd]; if(!subproc_fde) { D("subproc_fd %d cleared from fd_table\n", subproc_fd); return; } if(subproc_fde->fd != subproc_fd) { // Already reallocated? D("subproc_fd %d != fd_table[].fd %d\n", subproc_fd, subproc_fde->fd); return; } subproc_fde->force_eof = 1; int rcount = 0; ioctl(subproc_fd, FIONREAD, &rcount); D("subproc with fd=%d has rcount=%d err=%d\n", subproc_fd, rcount, errno); if(rcount) { // If there is data left, it will show up in the select(). // This works because there is no other thread reading that // data when in this fd_func(). return; } D("subproc_fde.state=%04x\n", subproc_fde->state); subproc_fde->events |= FDE_READ; if(subproc_fde->state & FDE_PENDING) { return; } subproc_fde->state |= FDE_PENDING; fdevent_call_fdfunc(subproc_fde); } } fdevent *fdevent_create(int fd, fd_func func, void *arg) { fdevent *fde = (fdevent*) malloc(sizeof(fdevent)); if(fde == 0) return 0; fdevent_install(fde, fd, func, arg); fde->state |= FDE_CREATED; return fde; } void fdevent_destroy(fdevent *fde) { if(fde == 0) return; if(!(fde->state & FDE_CREATED)) { FATAL("fde %p not created by fdevent_create()\n", fde); } fdevent_remove(fde); } void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg) { memset(fde, 0, sizeof(fdevent)); fde->state = FDE_ACTIVE; fde->fd = fd; fde->force_eof = 0; fde->func = func; fde->arg = arg; #ifndef HAVE_WINSOCK fcntl(fd, F_SETFL, O_NONBLOCK); #endif fdevent_register(fde); dump_fde(fde, "connect"); fdevent_connect(fde); fde->state |= FDE_ACTIVE; } void fdevent_remove(fdevent *fde) { if(fde->state & FDE_PENDING) { fdevent_plist_remove(fde); } if(fde->state & FDE_ACTIVE) { fdevent_disconnect(fde); dump_fde(fde, "disconnect"); fdevent_unregister(fde); } fde->state = 0; fde->events = 0; } void fdevent_set(fdevent *fde, unsigned events) { events &= FDE_EVENTMASK; if((fde->state & FDE_EVENTMASK) == events) return; if(fde->state & FDE_ACTIVE) { fdevent_update(fde, events); dump_fde(fde, "update"); } fde->state = (fde->state & FDE_STATEMASK) | events; if(fde->state & FDE_PENDING) { /* if we're pending, make sure ** we don't signal an event that ** is no longer wanted. */ fde->events &= (~events); if(fde->events == 0) { fdevent_plist_remove(fde); fde->state &= (~FDE_PENDING); } } } void fdevent_add(fdevent *fde, unsigned events) { fdevent_set( fde, (fde->state & FDE_EVENTMASK) | (events & FDE_EVENTMASK)); } void fdevent_del(fdevent *fde, unsigned events) { fdevent_set( fde, (fde->state & FDE_EVENTMASK) & (~(events & FDE_EVENTMASK))); } void fdevent_subproc_setup() { int s[2]; if(adb_socketpair(s)) { FATAL("cannot create shell-exit socket-pair\n"); } SHELL_EXIT_NOTIFY_FD = s[0]; fdevent *fde; fde = fdevent_create(s[1], fdevent_subproc_event_func, NULL); if(!fde) FATAL("cannot create fdevent for shell-exit handler\n"); fdevent_add(fde, FDE_READ); } void fdevent_loop() { fdevent *fde; fdevent_subproc_setup(); for(;;) { D("--- ---- waiting for events\n"); fdevent_process(); while((fde = fdevent_plist_dequeue())) { fdevent_call_fdfunc(fde); } } } android-tools-5.1.1r36+git20160322/core/adb/fdevent.h000066400000000000000000000042101267427243200215160ustar00rootroot00000000000000/* * Copyright (C) 2006 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef __FDEVENT_H #define __FDEVENT_H #include /* for int64_t */ /* events that may be observed */ #define FDE_READ 0x0001 #define FDE_WRITE 0x0002 #define FDE_ERROR 0x0004 #define FDE_TIMEOUT 0x0008 /* features that may be set (via the events set/add/del interface) */ #define FDE_DONT_CLOSE 0x0080 typedef struct fdevent fdevent; typedef void (*fd_func)(int fd, unsigned events, void *userdata); /* Allocate and initialize a new fdevent object * Note: use FD_TIMER as 'fd' to create a fd-less object * (used to implement timers). */ fdevent *fdevent_create(int fd, fd_func func, void *arg); /* Uninitialize and deallocate an fdevent object that was ** created by fdevent_create() */ void fdevent_destroy(fdevent *fde); /* Initialize an fdevent object that was externally allocated */ void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg); /* Uninitialize an fdevent object that was initialized by ** fdevent_install() */ void fdevent_remove(fdevent *item); /* Change which events should cause notifications */ void fdevent_set(fdevent *fde, unsigned events); void fdevent_add(fdevent *fde, unsigned events); void fdevent_del(fdevent *fde, unsigned events); void fdevent_set_timeout(fdevent *fde, int64_t timeout_ms); /* loop forever, handling events. */ void fdevent_loop(); struct fdevent { fdevent *next; fdevent *prev; int fd; int force_eof; unsigned short state; unsigned short events; fd_func func; void *arg; }; #endif android-tools-5.1.1r36+git20160322/core/adb/file_sync_client.c000066400000000000000000000624241267427243200234020ustar00rootroot00000000000000/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "sysdeps.h" #include "adb.h" #include "adb_client.h" #include "file_sync_service.h" static unsigned long long total_bytes; static long long start_time; static long long NOW() { struct timeval tv; gettimeofday(&tv, 0); return ((long long) tv.tv_usec) + 1000000LL * ((long long) tv.tv_sec); } static void BEGIN() { total_bytes = 0; start_time = NOW(); } static void END() { long long t = NOW() - start_time; if(total_bytes == 0) return; if (t == 0) /* prevent division by 0 :-) */ t = 1000000; fprintf(stderr,"%lld KB/s (%lld bytes in %lld.%03llds)\n", ((total_bytes * 1000000LL) / t) / 1024LL, total_bytes, (t / 1000000LL), (t % 1000000LL) / 1000LL); } static const char* transfer_progress_format = "\rTransferring: %llu/%llu (%d%%)"; static void print_transfer_progress(unsigned long long bytes_current, unsigned long long bytes_total) { if (bytes_total == 0) return; fprintf(stderr, transfer_progress_format, bytes_current, bytes_total, (int) (bytes_current * 100 / bytes_total)); if (bytes_current == bytes_total) { fputc('\n', stderr); } fflush(stderr); } void sync_quit(int fd) { syncmsg msg; msg.req.id = ID_QUIT; msg.req.namelen = 0; writex(fd, &msg.req, sizeof(msg.req)); } typedef void (*sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char *name, void *cookie); int sync_ls(int fd, const char *path, sync_ls_cb func, void *cookie) { syncmsg msg; char buf[257]; int len; len = strlen(path); if(len > 1024) goto fail; msg.req.id = ID_LIST; msg.req.namelen = htoll(len); if(writex(fd, &msg.req, sizeof(msg.req)) || writex(fd, path, len)) { goto fail; } for(;;) { if(readx(fd, &msg.dent, sizeof(msg.dent))) break; if(msg.dent.id == ID_DONE) return 0; if(msg.dent.id != ID_DENT) break; len = ltohl(msg.dent.namelen); if(len > 256) break; if(readx(fd, buf, len)) break; buf[len] = 0; func(ltohl(msg.dent.mode), ltohl(msg.dent.size), ltohl(msg.dent.time), buf, cookie); } fail: adb_close(fd); return -1; } typedef struct syncsendbuf syncsendbuf; struct syncsendbuf { unsigned id; unsigned size; char data[SYNC_DATA_MAX]; }; static syncsendbuf send_buffer; int sync_readtime(int fd, const char *path, unsigned int *timestamp, unsigned int *mode) { syncmsg msg; int len = strlen(path); msg.req.id = ID_STAT; msg.req.namelen = htoll(len); if(writex(fd, &msg.req, sizeof(msg.req)) || writex(fd, path, len)) { return -1; } if(readx(fd, &msg.stat, sizeof(msg.stat))) { return -1; } if(msg.stat.id != ID_STAT) { return -1; } *timestamp = ltohl(msg.stat.time); *mode = ltohl(msg.stat.mode); return 0; } static int sync_start_readtime(int fd, const char *path) { syncmsg msg; int len = strlen(path); msg.req.id = ID_STAT; msg.req.namelen = htoll(len); if(writex(fd, &msg.req, sizeof(msg.req)) || writex(fd, path, len)) { return -1; } return 0; } static int sync_finish_readtime(int fd, unsigned int *timestamp, unsigned int *mode, unsigned int *size) { syncmsg msg; if(readx(fd, &msg.stat, sizeof(msg.stat))) return -1; if(msg.stat.id != ID_STAT) return -1; *timestamp = ltohl(msg.stat.time); *mode = ltohl(msg.stat.mode); *size = ltohl(msg.stat.size); return 0; } int sync_readmode(int fd, const char *path, unsigned *mode) { syncmsg msg; int len = strlen(path); msg.req.id = ID_STAT; msg.req.namelen = htoll(len); if(writex(fd, &msg.req, sizeof(msg.req)) || writex(fd, path, len)) { return -1; } if(readx(fd, &msg.stat, sizeof(msg.stat))) { return -1; } if(msg.stat.id != ID_STAT) { return -1; } *mode = ltohl(msg.stat.mode); return 0; } static int write_data_file(int fd, const char *path, syncsendbuf *sbuf, int show_progress) { int lfd, err = 0; unsigned long long size = 0; lfd = adb_open(path, O_RDONLY); if(lfd < 0) { fprintf(stderr,"cannot open '%s': %s\n", path, strerror(errno)); return -1; } if (show_progress) { // Determine local file size. struct stat st; if (fstat(lfd, &st)) { fprintf(stderr,"cannot stat '%s': %s\n", path, strerror(errno)); return -1; } size = st.st_size; } sbuf->id = ID_DATA; for(;;) { int ret; ret = adb_read(lfd, sbuf->data, SYNC_DATA_MAX); if(!ret) break; if(ret < 0) { if(errno == EINTR) continue; fprintf(stderr,"cannot read '%s': %s\n", path, strerror(errno)); break; } sbuf->size = htoll(ret); if(writex(fd, sbuf, sizeof(unsigned) * 2 + ret)){ err = -1; break; } total_bytes += ret; if (show_progress) { print_transfer_progress(total_bytes, size); } } adb_close(lfd); return err; } static int write_data_buffer(int fd, char* file_buffer, int size, syncsendbuf *sbuf, int show_progress) { int err = 0; int total = 0; sbuf->id = ID_DATA; while (total < size) { int count = size - total; if (count > SYNC_DATA_MAX) { count = SYNC_DATA_MAX; } memcpy(sbuf->data, &file_buffer[total], count); sbuf->size = htoll(count); if(writex(fd, sbuf, sizeof(unsigned) * 2 + count)){ err = -1; break; } total += count; total_bytes += count; if (show_progress) { print_transfer_progress(total, size); } } return err; } #ifdef HAVE_SYMLINKS static int write_data_link(int fd, const char *path, syncsendbuf *sbuf) { int len, ret; len = readlink(path, sbuf->data, SYNC_DATA_MAX-1); if(len < 0) { fprintf(stderr, "error reading link '%s': %s\n", path, strerror(errno)); return -1; } sbuf->data[len] = '\0'; sbuf->size = htoll(len + 1); sbuf->id = ID_DATA; ret = writex(fd, sbuf, sizeof(unsigned) * 2 + len + 1); if(ret) return -1; total_bytes += len + 1; return 0; } #endif static int sync_send(int fd, const char *lpath, const char *rpath, unsigned mtime, mode_t mode, int show_progress) { syncmsg msg; int len, r; syncsendbuf *sbuf = &send_buffer; char* file_buffer = NULL; int size = 0; char tmp[64]; len = strlen(rpath); if(len > 1024) goto fail; snprintf(tmp, sizeof(tmp), ",%d", mode); r = strlen(tmp); msg.req.id = ID_SEND; msg.req.namelen = htoll(len + r); if(writex(fd, &msg.req, sizeof(msg.req)) || writex(fd, rpath, len) || writex(fd, tmp, r)) { free(file_buffer); goto fail; } if (file_buffer) { write_data_buffer(fd, file_buffer, size, sbuf, show_progress); free(file_buffer); } else if (S_ISREG(mode)) write_data_file(fd, lpath, sbuf, show_progress); #ifdef HAVE_SYMLINKS else if (S_ISLNK(mode)) write_data_link(fd, lpath, sbuf); #endif else goto fail; msg.data.id = ID_DONE; msg.data.size = htoll(mtime); if(writex(fd, &msg.data, sizeof(msg.data))) goto fail; if(readx(fd, &msg.status, sizeof(msg.status))) return -1; if(msg.status.id != ID_OKAY) { if(msg.status.id == ID_FAIL) { len = ltohl(msg.status.msglen); if(len > 256) len = 256; if(readx(fd, sbuf->data, len)) { return -1; } sbuf->data[len] = 0; } else strcpy(sbuf->data, "unknown reason"); fprintf(stderr,"failed to copy '%s' to '%s': %s\n", lpath, rpath, sbuf->data); return -1; } return 0; fail: fprintf(stderr,"protocol failure\n"); adb_close(fd); return -1; } static int mkdirs(const char *name) { int ret; char *x = (char *)name + 1; for(;;) { x = adb_dirstart(x); if(x == 0) return 0; *x = 0; ret = adb_mkdir(name, 0775); *x = OS_PATH_SEPARATOR; if((ret < 0) && (errno != EEXIST)) { return ret; } x++; } return 0; } int sync_recv(int fd, const char *rpath, const char *lpath, int show_progress) { syncmsg msg; int len; int lfd = -1; char *buffer = send_buffer.data; unsigned id; unsigned long long size = 0; len = strlen(rpath); if(len > 1024) return -1; if (show_progress) { // Determine remote file size. syncmsg stat_msg; stat_msg.req.id = ID_STAT; stat_msg.req.namelen = htoll(len); if (writex(fd, &stat_msg.req, sizeof(stat_msg.req)) || writex(fd, rpath, len)) { return -1; } if (readx(fd, &stat_msg.stat, sizeof(stat_msg.stat))) { return -1; } if (stat_msg.stat.id != ID_STAT) return -1; size = ltohl(stat_msg.stat.size); } msg.req.id = ID_RECV; msg.req.namelen = htoll(len); if(writex(fd, &msg.req, sizeof(msg.req)) || writex(fd, rpath, len)) { return -1; } if(readx(fd, &msg.data, sizeof(msg.data))) { return -1; } id = msg.data.id; if((id == ID_DATA) || (id == ID_DONE)) { adb_unlink(lpath); mkdirs(lpath); lfd = adb_creat(lpath, 0644); if(lfd < 0) { fprintf(stderr,"cannot create '%s': %s\n", lpath, strerror(errno)); return -1; } goto handle_data; } else { goto remote_error; } for(;;) { if(readx(fd, &msg.data, sizeof(msg.data))) { return -1; } id = msg.data.id; handle_data: len = ltohl(msg.data.size); if(id == ID_DONE) break; if(id != ID_DATA) goto remote_error; if(len > SYNC_DATA_MAX) { fprintf(stderr,"data overrun\n"); adb_close(lfd); return -1; } if(readx(fd, buffer, len)) { adb_close(lfd); return -1; } if(writex(lfd, buffer, len)) { fprintf(stderr,"cannot write '%s': %s\n", rpath, strerror(errno)); adb_close(lfd); return -1; } total_bytes += len; if (show_progress) { print_transfer_progress(total_bytes, size); } } adb_close(lfd); return 0; remote_error: adb_close(lfd); adb_unlink(lpath); if(id == ID_FAIL) { len = ltohl(msg.data.size); if(len > 256) len = 256; if(readx(fd, buffer, len)) { return -1; } buffer[len] = 0; } else { memcpy(buffer, &id, 4); buffer[4] = 0; // strcpy(buffer,"unknown reason"); } fprintf(stderr,"failed to copy '%s' to '%s': %s\n", rpath, lpath, buffer); return 0; } /* --- */ static void do_sync_ls_cb(unsigned mode, unsigned size, unsigned time, const char *name, void *cookie) { printf("%08x %08x %08x %s\n", mode, size, time, name); } int do_sync_ls(const char *path) { int fd = adb_connect("sync:"); if(fd < 0) { fprintf(stderr,"error: %s\n", adb_error()); return 1; } if(sync_ls(fd, path, do_sync_ls_cb, 0)) { return 1; } else { sync_quit(fd); return 0; } } typedef struct copyinfo copyinfo; struct copyinfo { copyinfo *next; const char *src; const char *dst; unsigned int time; unsigned int mode; unsigned int size; int flag; //char data[0]; }; copyinfo *mkcopyinfo(const char *spath, const char *dpath, const char *name, int isdir) { int slen = strlen(spath); int dlen = strlen(dpath); int nlen = strlen(name); int ssize = slen + nlen + 2; int dsize = dlen + nlen + 2; copyinfo *ci = malloc(sizeof(copyinfo) + ssize + dsize); if(ci == 0) { fprintf(stderr,"out of memory\n"); abort(); } ci->next = 0; ci->time = 0; ci->mode = 0; ci->size = 0; ci->flag = 0; ci->src = (const char*)(ci + 1); ci->dst = ci->src + ssize; snprintf((char*) ci->src, ssize, isdir ? "%s%s/" : "%s%s", spath, name); snprintf((char*) ci->dst, dsize, isdir ? "%s%s/" : "%s%s", dpath, name); // fprintf(stderr,"mkcopyinfo('%s','%s')\n", ci->src, ci->dst); return ci; } static int local_build_list(copyinfo **filelist, const char *lpath, const char *rpath) { DIR *d; struct dirent *de; struct stat st; copyinfo *dirlist = 0; copyinfo *ci, *next; // fprintf(stderr,"local_build_list('%s','%s')\n", lpath, rpath); d = opendir(lpath); if(d == 0) { fprintf(stderr,"cannot open '%s': %s\n", lpath, strerror(errno)); return -1; } while((de = readdir(d))) { char stat_path[PATH_MAX]; char *name = de->d_name; if(name[0] == '.') { if(name[1] == 0) continue; if((name[1] == '.') && (name[2] == 0)) continue; } /* * We could use d_type if HAVE_DIRENT_D_TYPE is defined, but reiserfs * always returns DT_UNKNOWN, so we just use stat() for all cases. */ if (strlen(lpath) + strlen(de->d_name) + 1 > sizeof(stat_path)) continue; strcpy(stat_path, lpath); strcat(stat_path, de->d_name); if(!lstat(stat_path, &st)) { if (S_ISDIR(st.st_mode)) { ci = mkcopyinfo(lpath, rpath, name, 1); ci->next = dirlist; dirlist = ci; } else { ci = mkcopyinfo(lpath, rpath, name, 0); if(lstat(ci->src, &st)) { fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno)); free(ci); closedir(d); return -1; } if(!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) { fprintf(stderr, "skipping special file '%s'\n", ci->src); free(ci); } else { ci->time = st.st_mtime; ci->mode = st.st_mode; ci->size = st.st_size; ci->next = *filelist; *filelist = ci; } } } else { fprintf(stderr, "cannot lstat '%s': %s\n",stat_path , strerror(errno)); } } closedir(d); for(ci = dirlist; ci != 0; ci = next) { next = ci->next; local_build_list(filelist, ci->src, ci->dst); free(ci); } return 0; } static int copy_local_dir_remote(int fd, const char *lpath, const char *rpath, int checktimestamps, int listonly) { copyinfo *filelist = 0; copyinfo *ci, *next; int pushed = 0; int skipped = 0; if((lpath[0] == 0) || (rpath[0] == 0)) return -1; if(lpath[strlen(lpath) - 1] != '/') { int tmplen = strlen(lpath)+2; char *tmp = malloc(tmplen); if(tmp == 0) return -1; snprintf(tmp, tmplen, "%s/",lpath); lpath = tmp; } if(rpath[strlen(rpath) - 1] != '/') { int tmplen = strlen(rpath)+2; char *tmp = malloc(tmplen); if(tmp == 0) return -1; snprintf(tmp, tmplen, "%s/",rpath); rpath = tmp; } if(local_build_list(&filelist, lpath, rpath)) { return -1; } if(checktimestamps){ for(ci = filelist; ci != 0; ci = ci->next) { if(sync_start_readtime(fd, ci->dst)) { return 1; } } for(ci = filelist; ci != 0; ci = ci->next) { unsigned int timestamp, mode, size; if(sync_finish_readtime(fd, ×tamp, &mode, &size)) return 1; if(size == ci->size) { /* for links, we cannot update the atime/mtime */ if((S_ISREG(ci->mode & mode) && timestamp == ci->time) || (S_ISLNK(ci->mode & mode) && timestamp >= ci->time)) ci->flag = 1; } } } for(ci = filelist; ci != 0; ci = next) { next = ci->next; if(ci->flag == 0) { fprintf(stderr,"%spush: %s -> %s\n", listonly ? "would " : "", ci->src, ci->dst); if(!listonly && sync_send(fd, ci->src, ci->dst, ci->time, ci->mode, 0 /* no show progress */)) { return 1; } pushed++; } else { skipped++; } free(ci); } fprintf(stderr,"%d file%s pushed. %d file%s skipped.\n", pushed, (pushed == 1) ? "" : "s", skipped, (skipped == 1) ? "" : "s"); return 0; } int do_sync_push(const char *lpath, const char *rpath, int show_progress) { struct stat st; unsigned mode; int fd; fd = adb_connect("sync:"); if(fd < 0) { fprintf(stderr,"error: %s\n", adb_error()); return 1; } if(stat(lpath, &st)) { fprintf(stderr,"cannot stat '%s': %s\n", lpath, strerror(errno)); sync_quit(fd); return 1; } if(S_ISDIR(st.st_mode)) { BEGIN(); if(copy_local_dir_remote(fd, lpath, rpath, 0, 0)) { return 1; } else { END(); sync_quit(fd); } } else { if(sync_readmode(fd, rpath, &mode)) { return 1; } if((mode != 0) && S_ISDIR(mode)) { /* if we're copying a local file to a remote directory, ** we *really* want to copy to remotedir + "/" + localfilename */ const char *name = adb_dirstop(lpath); if(name == 0) { name = lpath; } else { name++; } int tmplen = strlen(name) + strlen(rpath) + 2; char *tmp = malloc(strlen(name) + strlen(rpath) + 2); if(tmp == 0) return 1; snprintf(tmp, tmplen, "%s/%s", rpath, name); rpath = tmp; } BEGIN(); if(sync_send(fd, lpath, rpath, st.st_mtime, st.st_mode, show_progress)) { return 1; } else { END(); sync_quit(fd); return 0; } } return 0; } typedef struct { copyinfo **filelist; copyinfo **dirlist; const char *rpath; const char *lpath; } sync_ls_build_list_cb_args; void sync_ls_build_list_cb(unsigned mode, unsigned size, unsigned time, const char *name, void *cookie) { sync_ls_build_list_cb_args *args = (sync_ls_build_list_cb_args *)cookie; copyinfo *ci; if (S_ISDIR(mode)) { copyinfo **dirlist = args->dirlist; /* Don't try recursing down "." or ".." */ if (name[0] == '.') { if (name[1] == '\0') return; if ((name[1] == '.') && (name[2] == '\0')) return; } ci = mkcopyinfo(args->rpath, args->lpath, name, 1); ci->next = *dirlist; *dirlist = ci; } else if (S_ISREG(mode) || S_ISLNK(mode)) { copyinfo **filelist = args->filelist; ci = mkcopyinfo(args->rpath, args->lpath, name, 0); ci->time = time; ci->mode = mode; ci->size = size; ci->next = *filelist; *filelist = ci; } else { fprintf(stderr, "skipping special file '%s'\n", name); } } static int remote_build_list(int syncfd, copyinfo **filelist, const char *rpath, const char *lpath) { copyinfo *dirlist = NULL; sync_ls_build_list_cb_args args; args.filelist = filelist; args.dirlist = &dirlist; args.rpath = rpath; args.lpath = lpath; /* Put the files/dirs in rpath on the lists. */ if (sync_ls(syncfd, rpath, sync_ls_build_list_cb, (void *)&args)) { return 1; } /* Recurse into each directory we found. */ while (dirlist != NULL) { copyinfo *next = dirlist->next; if (remote_build_list(syncfd, filelist, dirlist->src, dirlist->dst)) { return 1; } free(dirlist); dirlist = next; } return 0; } static int set_time_and_mode(const char *lpath, unsigned int time, unsigned int mode) { struct utimbuf times = { time, time }; int r1 = utime(lpath, ×); /* use umask for permissions */ mode_t mask=umask(0000); umask(mask); int r2 = chmod(lpath, mode & ~mask); return r1 ? : r2; } static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath, int copy_attrs) { copyinfo *filelist = 0; copyinfo *ci, *next; int pulled = 0; int skipped = 0; /* Make sure that both directory paths end in a slash. */ if (rpath[0] == 0 || lpath[0] == 0) return -1; if (rpath[strlen(rpath) - 1] != '/') { int tmplen = strlen(rpath) + 2; char *tmp = malloc(tmplen); if (tmp == 0) return -1; snprintf(tmp, tmplen, "%s/", rpath); rpath = tmp; } if (lpath[strlen(lpath) - 1] != '/') { int tmplen = strlen(lpath) + 2; char *tmp = malloc(tmplen); if (tmp == 0) return -1; snprintf(tmp, tmplen, "%s/", lpath); lpath = tmp; } fprintf(stderr, "pull: building file list...\n"); /* Recursively build the list of files to copy. */ if (remote_build_list(fd, &filelist, rpath, lpath)) { return -1; } for (ci = filelist; ci != 0; ci = next) { next = ci->next; if (ci->flag == 0) { fprintf(stderr, "pull: %s -> %s\n", ci->src, ci->dst); if (sync_recv(fd, ci->src, ci->dst, 0 /* no show progress */)) { return 1; } if (copy_attrs && set_time_and_mode(ci->dst, ci->time, ci->mode)) { return 1; } pulled++; } else { skipped++; } free(ci); } fprintf(stderr, "%d file%s pulled. %d file%s skipped.\n", pulled, (pulled == 1) ? "" : "s", skipped, (skipped == 1) ? "" : "s"); return 0; } int do_sync_pull(const char *rpath, const char *lpath, int show_progress, int copy_attrs) { unsigned mode, time; struct stat st; int fd; fd = adb_connect("sync:"); if(fd < 0) { fprintf(stderr,"error: %s\n", adb_error()); return 1; } if(sync_readtime(fd, rpath, &time, &mode)) { return 1; } if(mode == 0) { fprintf(stderr,"remote object '%s' does not exist\n", rpath); return 1; } if(S_ISREG(mode) || S_ISLNK(mode) || S_ISCHR(mode) || S_ISBLK(mode)) { if(stat(lpath, &st) == 0) { if(S_ISDIR(st.st_mode)) { /* if we're copying a remote file to a local directory, ** we *really* want to copy to localdir + "/" + remotefilename */ const char *name = adb_dirstop(rpath); if(name == 0) { name = rpath; } else { name++; } int tmplen = strlen(name) + strlen(lpath) + 2; char *tmp = malloc(tmplen); if(tmp == 0) return 1; snprintf(tmp, tmplen, "%s/%s", lpath, name); lpath = tmp; } } BEGIN(); if (sync_recv(fd, rpath, lpath, show_progress)) { return 1; } else { if (copy_attrs && set_time_and_mode(lpath, time, mode)) return 1; END(); sync_quit(fd); return 0; } } else if(S_ISDIR(mode)) { BEGIN(); if (copy_remote_dir_local(fd, rpath, lpath, copy_attrs)) { return 1; } else { END(); sync_quit(fd); return 0; } } else { fprintf(stderr,"remote object '%s' not a file or directory\n", rpath); return 1; } } int do_sync_sync(const char *lpath, const char *rpath, int listonly) { fprintf(stderr,"syncing %s...\n",rpath); int fd = adb_connect("sync:"); if(fd < 0) { fprintf(stderr,"error: %s\n", adb_error()); return 1; } BEGIN(); if(copy_local_dir_remote(fd, lpath, rpath, 1, listonly)){ return 1; } else { END(); sync_quit(fd); return 0; } } android-tools-5.1.1r36+git20160322/core/adb/file_sync_service.c000066400000000000000000000262471267427243200235670ustar00rootroot00000000000000/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include "sysdeps.h" #define TRACE_TAG TRACE_SYNC #include "adb.h" #include "file_sync_service.h" /* TODO: use fs_config to configure permissions on /data */ static bool is_on_system(const char *name) { const char *SYSTEM = "/system/"; return (strncmp(SYSTEM, name, strlen(SYSTEM)) == 0); } static bool is_on_vendor(const char *name) { const char *VENDOR = "/vendor/"; return (strncmp(VENDOR, name, strlen(VENDOR)) == 0); } static int mkdirs(char *name) { int ret; char *x = name + 1; uid_t uid = -1; gid_t gid = -1; unsigned int mode = 0775; uint64_t cap = 0; if(name[0] != '/') return -1; for(;;) { x = adb_dirstart(x); if(x == 0) return 0; *x = 0; if (is_on_system(name) || is_on_vendor(name)) { fs_config(name, 1, &uid, &gid, &mode, &cap); } ret = adb_mkdir(name, mode); if((ret < 0) && (errno != EEXIST)) { D("mkdir(\"%s\") -> %s\n", name, strerror(errno)); *x = '/'; return ret; } else if(ret == 0) { ret = chown(name, uid, gid); if (ret < 0) { *x = '/'; return ret; } selinux_android_restorecon(name, 0); } *x++ = '/'; } return 0; } static int do_stat(int s, const char *path) { syncmsg msg; struct stat st; msg.stat.id = ID_STAT; if(lstat(path, &st)) { msg.stat.mode = 0; msg.stat.size = 0; msg.stat.time = 0; } else { msg.stat.mode = htoll(st.st_mode); msg.stat.size = htoll(st.st_size); msg.stat.time = htoll(st.st_mtime); } return writex(s, &msg.stat, sizeof(msg.stat)); } static int do_list(int s, const char *path) { DIR *d; struct dirent *de; struct stat st; syncmsg msg; int len; char tmp[1024 + 256 + 1]; char *fname; len = strlen(path); memcpy(tmp, path, len); tmp[len] = '/'; fname = tmp + len + 1; msg.dent.id = ID_DENT; d = opendir(path); if(d == 0) goto done; while((de = readdir(d))) { int len = strlen(de->d_name); /* not supposed to be possible, but if it does happen, let's not buffer overrun */ if(len > 256) continue; strcpy(fname, de->d_name); if(lstat(tmp, &st) == 0) { msg.dent.mode = htoll(st.st_mode); msg.dent.size = htoll(st.st_size); msg.dent.time = htoll(st.st_mtime); msg.dent.namelen = htoll(len); if(writex(s, &msg.dent, sizeof(msg.dent)) || writex(s, de->d_name, len)) { closedir(d); return -1; } } } closedir(d); done: msg.dent.id = ID_DONE; msg.dent.mode = 0; msg.dent.size = 0; msg.dent.time = 0; msg.dent.namelen = 0; return writex(s, &msg.dent, sizeof(msg.dent)); } static int fail_message(int s, const char *reason) { syncmsg msg; int len = strlen(reason); D("sync: failure: %s\n", reason); msg.data.id = ID_FAIL; msg.data.size = htoll(len); if(writex(s, &msg.data, sizeof(msg.data)) || writex(s, reason, len)) { return -1; } else { return 0; } } static int fail_errno(int s) { return fail_message(s, strerror(errno)); } static int handle_send_file(int s, char *path, uid_t uid, gid_t gid, mode_t mode, char *buffer, bool do_unlink) { syncmsg msg; unsigned int timestamp = 0; int fd; fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode); if(fd < 0 && errno == ENOENT) { if(mkdirs(path) != 0) { if(fail_errno(s)) return -1; fd = -1; } else { fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode); } } if(fd < 0 && errno == EEXIST) { fd = adb_open_mode(path, O_WRONLY | O_CLOEXEC, mode); } if(fd < 0) { if(fail_errno(s)) return -1; fd = -1; } else { if(fchown(fd, uid, gid) != 0) { fail_errno(s); errno = 0; } /* * fchown clears the setuid bit - restore it if present. * Ignore the result of calling fchmod. It's not supported * by all filesystems. b/12441485 */ fchmod(fd, mode); } for(;;) { unsigned int len; if(readx(s, &msg.data, sizeof(msg.data))) goto fail; if(msg.data.id != ID_DATA) { if(msg.data.id == ID_DONE) { timestamp = ltohl(msg.data.size); break; } fail_message(s, "invalid data message"); goto fail; } len = ltohl(msg.data.size); if(len > SYNC_DATA_MAX) { fail_message(s, "oversize data message"); goto fail; } if(readx(s, buffer, len)) goto fail; if(fd < 0) continue; if(writex(fd, buffer, len)) { int saved_errno = errno; adb_close(fd); if (do_unlink) adb_unlink(path); fd = -1; errno = saved_errno; if(fail_errno(s)) return -1; } } if(fd >= 0) { struct utimbuf u; adb_close(fd); selinux_android_restorecon(path, 0); u.actime = timestamp; u.modtime = timestamp; utime(path, &u); msg.status.id = ID_OKAY; msg.status.msglen = 0; if(writex(s, &msg.status, sizeof(msg.status))) return -1; } return 0; fail: if(fd >= 0) adb_close(fd); if (do_unlink) adb_unlink(path); return -1; } #ifdef HAVE_SYMLINKS static int handle_send_link(int s, char *path, char *buffer) { syncmsg msg; unsigned int len; int ret; if(readx(s, &msg.data, sizeof(msg.data))) return -1; if(msg.data.id != ID_DATA) { fail_message(s, "invalid data message: expected ID_DATA"); return -1; } len = ltohl(msg.data.size); if(len > SYNC_DATA_MAX) { fail_message(s, "oversize data message"); return -1; } if(readx(s, buffer, len)) return -1; ret = symlink(buffer, path); if(ret && errno == ENOENT) { if(mkdirs(path) != 0) { fail_errno(s); return -1; } ret = symlink(buffer, path); } if(ret) { fail_errno(s); return -1; } if(readx(s, &msg.data, sizeof(msg.data))) return -1; if(msg.data.id == ID_DONE) { msg.status.id = ID_OKAY; msg.status.msglen = 0; if(writex(s, &msg.status, sizeof(msg.status))) return -1; } else { fail_message(s, "invalid data message: expected ID_DONE"); return -1; } return 0; } #endif /* HAVE_SYMLINKS */ static int do_send(int s, char *path, char *buffer) { char *tmp; unsigned int mode; int is_link, ret; bool do_unlink; tmp = strrchr(path,','); if(tmp) { *tmp = 0; errno = 0; mode = strtoul(tmp + 1, NULL, 0); #ifndef HAVE_SYMLINKS is_link = 0; #else is_link = S_ISLNK((mode_t) mode); #endif mode &= 0777; } if(!tmp || errno) { mode = 0644; is_link = 0; do_unlink = true; } else { struct stat st; /* Don't delete files before copying if they are not "regular" */ do_unlink = lstat(path, &st) || S_ISREG(st.st_mode) || S_ISLNK(st.st_mode); if (do_unlink) { adb_unlink(path); } } #ifdef HAVE_SYMLINKS if(is_link) ret = handle_send_link(s, path, buffer); else { #else { #endif uid_t uid = -1; gid_t gid = -1; uint64_t cap = 0; /* copy user permission bits to "group" and "other" permissions */ mode |= ((mode >> 3) & 0070); mode |= ((mode >> 3) & 0007); tmp = path; if(*tmp == '/') { tmp++; } if (is_on_system(path) || is_on_vendor(path)) { fs_config(tmp, 0, &uid, &gid, &mode, &cap); } ret = handle_send_file(s, path, uid, gid, mode, buffer, do_unlink); } return ret; } static int do_recv(int s, const char *path, char *buffer) { syncmsg msg; int fd, r; fd = adb_open(path, O_RDONLY | O_CLOEXEC); if(fd < 0) { if(fail_errno(s)) return -1; return 0; } msg.data.id = ID_DATA; for(;;) { r = adb_read(fd, buffer, SYNC_DATA_MAX); if(r <= 0) { if(r == 0) break; if(errno == EINTR) continue; r = fail_errno(s); adb_close(fd); return r; } msg.data.size = htoll(r); if(writex(s, &msg.data, sizeof(msg.data)) || writex(s, buffer, r)) { adb_close(fd); return -1; } } adb_close(fd); msg.data.id = ID_DONE; msg.data.size = 0; if(writex(s, &msg.data, sizeof(msg.data))) { return -1; } return 0; } void file_sync_service(int fd, void *cookie) { syncmsg msg; char name[1025]; unsigned namelen; char *buffer = malloc(SYNC_DATA_MAX); if(buffer == 0) goto fail; for(;;) { D("sync: waiting for command\n"); if(readx(fd, &msg.req, sizeof(msg.req))) { fail_message(fd, "command read failure"); break; } namelen = ltohl(msg.req.namelen); if(namelen > 1024) { fail_message(fd, "invalid namelen"); break; } if(readx(fd, name, namelen)) { fail_message(fd, "filename read failure"); break; } name[namelen] = 0; msg.req.namelen = 0; D("sync: '%s' '%s'\n", (char*) &msg.req, name); switch(msg.req.id) { case ID_STAT: if(do_stat(fd, name)) goto fail; break; case ID_LIST: if(do_list(fd, name)) goto fail; break; case ID_SEND: if(do_send(fd, name, buffer)) goto fail; break; case ID_RECV: if(do_recv(fd, name, buffer)) goto fail; break; case ID_QUIT: goto fail; default: fail_message(fd, "unknown command"); goto fail; } } fail: if(buffer != 0) free(buffer); D("sync: done\n"); adb_close(fd); } android-tools-5.1.1r36+git20160322/core/adb/file_sync_service.h000066400000000000000000000046321267427243200235660ustar00rootroot00000000000000/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _FILE_SYNC_SERVICE_H_ #define _FILE_SYNC_SERVICE_H_ #ifdef HAVE_BIG_ENDIAN static inline unsigned __swap_uint32(unsigned x) { return (((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24); } #define htoll(x) __swap_uint32(x) #define ltohl(x) __swap_uint32(x) #define MKID(a,b,c,d) ((d) | ((c) << 8) | ((b) << 16) | ((a) << 24)) #else #define htoll(x) (x) #define ltohl(x) (x) #define MKID(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24)) #endif #define ID_STAT MKID('S','T','A','T') #define ID_LIST MKID('L','I','S','T') #define ID_ULNK MKID('U','L','N','K') #define ID_SEND MKID('S','E','N','D') #define ID_RECV MKID('R','E','C','V') #define ID_DENT MKID('D','E','N','T') #define ID_DONE MKID('D','O','N','E') #define ID_DATA MKID('D','A','T','A') #define ID_OKAY MKID('O','K','A','Y') #define ID_FAIL MKID('F','A','I','L') #define ID_QUIT MKID('Q','U','I','T') typedef union { unsigned id; struct { unsigned id; unsigned namelen; } req; struct { unsigned id; unsigned mode; unsigned size; unsigned time; } stat; struct { unsigned id; unsigned mode; unsigned size; unsigned time; unsigned namelen; } dent; struct { unsigned id; unsigned size; } data; struct { unsigned id; unsigned msglen; } status; } syncmsg; void file_sync_service(int fd, void *cookie); int do_sync_ls(const char *path); int do_sync_push(const char *lpath, const char *rpath, int show_progress); int do_sync_sync(const char *lpath, const char *rpath, int listonly); int do_sync_pull(const char *rpath, const char *lpath, int show_progress, int pullTime); #define SYNC_DATA_MAX (64*1024) #endif android-tools-5.1.1r36+git20160322/core/adb/framebuffer_service.c000066400000000000000000000121121267427243200240620ustar00rootroot00000000000000/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include "fdevent.h" #include "adb.h" #include #include #include /* TODO: ** - sync with vsync to avoid tearing */ /* This version number defines the format of the fbinfo struct. It must match versioning in ddms where this data is consumed. */ #define DDMS_RAWIMAGE_VERSION 1 struct fbinfo { unsigned int version; unsigned int bpp; unsigned int size; unsigned int width; unsigned int height; unsigned int red_offset; unsigned int red_length; unsigned int blue_offset; unsigned int blue_length; unsigned int green_offset; unsigned int green_length; unsigned int alpha_offset; unsigned int alpha_length; } __attribute__((packed)); void framebuffer_service(int fd, void *cookie) { struct fbinfo fbinfo; unsigned int i, bsize; char buf[640]; int fd_screencap; int w, h, f; int fds[2]; if (pipe2(fds, O_CLOEXEC) < 0) goto pipefail; pid_t pid = fork(); if (pid < 0) goto done; if (pid == 0) { dup2(fds[1], STDOUT_FILENO); close(fds[0]); close(fds[1]); const char* command = "screencap"; const char *args[2] = {command, NULL}; execvp(command, (char**)args); exit(1); } fd_screencap = fds[0]; /* read w, h & format */ if(readx(fd_screencap, &w, 4)) goto done; if(readx(fd_screencap, &h, 4)) goto done; if(readx(fd_screencap, &f, 4)) goto done; fbinfo.version = DDMS_RAWIMAGE_VERSION; /* see hardware/hardware.h */ switch (f) { case 1: /* RGBA_8888 */ fbinfo.bpp = 32; fbinfo.size = w * h * 4; fbinfo.width = w; fbinfo.height = h; fbinfo.red_offset = 0; fbinfo.red_length = 8; fbinfo.green_offset = 8; fbinfo.green_length = 8; fbinfo.blue_offset = 16; fbinfo.blue_length = 8; fbinfo.alpha_offset = 24; fbinfo.alpha_length = 8; break; case 2: /* RGBX_8888 */ fbinfo.bpp = 32; fbinfo.size = w * h * 4; fbinfo.width = w; fbinfo.height = h; fbinfo.red_offset = 0; fbinfo.red_length = 8; fbinfo.green_offset = 8; fbinfo.green_length = 8; fbinfo.blue_offset = 16; fbinfo.blue_length = 8; fbinfo.alpha_offset = 24; fbinfo.alpha_length = 0; break; case 3: /* RGB_888 */ fbinfo.bpp = 24; fbinfo.size = w * h * 3; fbinfo.width = w; fbinfo.height = h; fbinfo.red_offset = 0; fbinfo.red_length = 8; fbinfo.green_offset = 8; fbinfo.green_length = 8; fbinfo.blue_offset = 16; fbinfo.blue_length = 8; fbinfo.alpha_offset = 24; fbinfo.alpha_length = 0; break; case 4: /* RGB_565 */ fbinfo.bpp = 16; fbinfo.size = w * h * 2; fbinfo.width = w; fbinfo.height = h; fbinfo.red_offset = 11; fbinfo.red_length = 5; fbinfo.green_offset = 5; fbinfo.green_length = 6; fbinfo.blue_offset = 0; fbinfo.blue_length = 5; fbinfo.alpha_offset = 0; fbinfo.alpha_length = 0; break; case 5: /* BGRA_8888 */ fbinfo.bpp = 32; fbinfo.size = w * h * 4; fbinfo.width = w; fbinfo.height = h; fbinfo.red_offset = 16; fbinfo.red_length = 8; fbinfo.green_offset = 8; fbinfo.green_length = 8; fbinfo.blue_offset = 0; fbinfo.blue_length = 8; fbinfo.alpha_offset = 24; fbinfo.alpha_length = 8; break; default: goto done; } /* write header */ if(writex(fd, &fbinfo, sizeof(fbinfo))) goto done; /* write data */ for(i = 0; i < fbinfo.size; i += bsize) { bsize = sizeof(buf); if (i + bsize > fbinfo.size) bsize = fbinfo.size - i; if(readx(fd_screencap, buf, bsize)) goto done; if(writex(fd, buf, bsize)) goto done; } done: TEMP_FAILURE_RETRY(waitpid(pid, NULL, 0)); close(fds[0]); close(fds[1]); pipefail: close(fd); } android-tools-5.1.1r36+git20160322/core/adb/get_my_path_darwin.c000066400000000000000000000020671267427243200237320ustar00rootroot00000000000000/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #import #include void get_my_path(char *s, size_t maxLen) { CFBundleRef mainBundle = CFBundleGetMainBundle(); CFURLRef executableURL = CFBundleCopyExecutableURL(mainBundle); CFStringRef executablePathString = CFURLCopyFileSystemPath(executableURL, kCFURLPOSIXPathStyle); CFRelease(executableURL); CFStringGetFileSystemRepresentation(executablePathString, s, maxLen); CFRelease(executablePathString); } android-tools-5.1.1r36+git20160322/core/adb/get_my_path_freebsd.c000066400000000000000000000017671267427243200240660ustar00rootroot00000000000000/* * Copyright (C) 2009 bsdroid project * Alexey Tarasov * * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include void get_my_path(char *exe, size_t maxLen) { char proc[64]; snprintf(proc, sizeof(proc), "/proc/%d/file", getpid()); int err = readlink(proc, exe, maxLen - 1); exe[err > 0 ? err : 0] = '\0'; } android-tools-5.1.1r36+git20160322/core/adb/get_my_path_linux.c000066400000000000000000000017021267427243200236000ustar00rootroot00000000000000/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include void get_my_path(char *exe, size_t maxLen) { char proc[64]; snprintf(proc, sizeof proc, "/proc/%d/exe", getpid()); int err = readlink(proc, exe, maxLen - 1); if(err > 0) { exe[err] = '\0'; } else { exe[0] = '\0'; } } android-tools-5.1.1r36+git20160322/core/adb/get_my_path_windows.c000066400000000000000000000017021267427243200241330ustar00rootroot00000000000000/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include void get_my_path(char *exe, size_t maxLen) { char *r; /* XXX: should be GetModuleFileNameA */ if (GetModuleFileName(NULL, exe, maxLen) > 0) { r = strrchr(exe, '\\'); if (r != NULL) *r = '\0'; } else { exe[0] = '\0'; } } android-tools-5.1.1r36+git20160322/core/adb/jdwp_service.c000066400000000000000000000473051267427243200225560ustar00rootroot00000000000000/* implement the "debug-ports" and "track-debug-ports" device services */ #include "sysdeps.h" #define TRACE_TAG TRACE_JDWP #include "adb.h" #include #include #include #include /* here's how these things work. when adbd starts, it creates a unix server socket named @vm-debug-control (@ is a shortcut for "first byte is zero" to use the private namespace instead of the file system) when a new JDWP daemon thread starts in a new VM process, it creates a connection to @vm-debug-control to announce its availability. JDWP thread @vm-debug-control | | |-------------------------------> | | hello I'm in process | | | | | the connection is kept alive. it will be closed automatically if the JDWP process terminates (this allows adbd to detect dead processes). adbd thus maintains a list of "active" JDWP processes. it can send its content to clients through the "device:debug-ports" service, or even updates through the "device:track-debug-ports" service. when a debugger wants to connect, it simply runs the command equivalent to "adb forward tcp: jdwp:" "jdwp:" is a new forward destination format used to target a given JDWP process on the device. when sutch a request arrives, adbd does the following: - first, it calls socketpair() to create a pair of equivalent sockets. - it attaches the first socket in the pair to a local socket which is itself attached to the transport's remote socket: - it sends the file descriptor of the second socket directly to the JDWP process with the help of sendmsg() JDWP thread @vm-debug-control | | | <----------------------| | OK, try this file descriptor | | | | | then, the JDWP thread uses this new socket descriptor as its pass-through connection to the debugger (and receives the JDWP-Handshake message, answers to it, etc...) this gives the following graphics: ____________________________________ | | | ADB Server (host) | | | Debugger <---> LocalSocket <----> RemoteSocket | | ^^ | |___________________________||_______| || Transport || (TCP for emulator - USB for device) || || ___________________________||_______ | || | | ADBD (device) || | | VV | JDWP <======> LocalSocket <----> RemoteSocket | | | |____________________________________| due to the way adb works, this doesn't need a special socket type or fancy handling of socket termination if either the debugger or the JDWP process closes the connection. THIS IS THE SIMPLEST IMPLEMENTATION I COULD FIND, IF YOU HAPPEN TO HAVE A BETTER IDEA, LET ME KNOW - Digit **********************************************************************/ /** JDWP PID List Support Code ** for each JDWP process, we record its pid and its connected socket **/ #define MAX_OUT_FDS 4 #if !ADB_HOST #include #include typedef struct JdwpProcess JdwpProcess; struct JdwpProcess { JdwpProcess* next; JdwpProcess* prev; int pid; int socket; fdevent* fde; char in_buff[4]; /* input character to read PID */ int in_len; /* number from JDWP process */ int out_fds[MAX_OUT_FDS]; /* output array of file descriptors */ int out_count; /* to send to the JDWP process */ }; static JdwpProcess _jdwp_list; static int jdwp_process_list( char* buffer, int bufferlen ) { char* end = buffer + bufferlen; char* p = buffer; JdwpProcess* proc = _jdwp_list.next; for ( ; proc != &_jdwp_list; proc = proc->next ) { int len; /* skip transient connections */ if (proc->pid < 0) continue; len = snprintf(p, end-p, "%d\n", proc->pid); if (p + len >= end) break; p += len; } p[0] = 0; return (p - buffer); } static int jdwp_process_list_msg( char* buffer, int bufferlen ) { char head[5]; int len = jdwp_process_list( buffer+4, bufferlen-4 ); snprintf(head, sizeof head, "%04x", len); memcpy(buffer, head, 4); return len + 4; } static void jdwp_process_list_updated(void); static void jdwp_process_free( JdwpProcess* proc ) { if (proc) { int n; proc->prev->next = proc->next; proc->next->prev = proc->prev; if (proc->socket >= 0) { adb_shutdown(proc->socket); adb_close(proc->socket); proc->socket = -1; } if (proc->fde != NULL) { fdevent_destroy(proc->fde); proc->fde = NULL; } proc->pid = -1; for (n = 0; n < proc->out_count; n++) { adb_close(proc->out_fds[n]); } proc->out_count = 0; free(proc); jdwp_process_list_updated(); } } static void jdwp_process_event(int, unsigned, void*); /* forward */ static JdwpProcess* jdwp_process_alloc( int socket ) { JdwpProcess* proc = calloc(1,sizeof(*proc)); if (proc == NULL) { D("not enough memory to create new JDWP process\n"); return NULL; } proc->socket = socket; proc->pid = -1; proc->next = proc; proc->prev = proc; proc->fde = fdevent_create( socket, jdwp_process_event, proc ); if (proc->fde == NULL) { D("could not create fdevent for new JDWP process\n" ); free(proc); return NULL; } proc->fde->state |= FDE_DONT_CLOSE; proc->in_len = 0; proc->out_count = 0; /* append to list */ proc->next = &_jdwp_list; proc->prev = proc->next->prev; proc->prev->next = proc; proc->next->prev = proc; /* start by waiting for the PID */ fdevent_add(proc->fde, FDE_READ); return proc; } static void jdwp_process_event( int socket, unsigned events, void* _proc ) { JdwpProcess* proc = _proc; if (events & FDE_READ) { if (proc->pid < 0) { /* read the PID as a 4-hexchar string */ char* p = proc->in_buff + proc->in_len; int size = 4 - proc->in_len; char temp[5]; while (size > 0) { int len = recv( socket, p, size, 0 ); if (len < 0) { if (errno == EINTR) continue; if (errno == EAGAIN) return; /* this can fail here if the JDWP process crashes very fast */ D("weird unknown JDWP process failure: %s\n", strerror(errno)); goto CloseProcess; } if (len == 0) { /* end of stream ? */ D("weird end-of-stream from unknown JDWP process\n"); goto CloseProcess; } p += len; proc->in_len += len; size -= len; } /* we have read 4 characters, now decode the pid */ memcpy(temp, proc->in_buff, 4); temp[4] = 0; if (sscanf( temp, "%04x", &proc->pid ) != 1) { D("could not decode JDWP %p PID number: '%s'\n", proc, temp); goto CloseProcess; } /* all is well, keep reading to detect connection closure */ D("Adding pid %d to jdwp process list\n", proc->pid); jdwp_process_list_updated(); } else { /* the pid was read, if we get there it's probably because the connection * was closed (e.g. the JDWP process exited or crashed) */ char buf[32]; for (;;) { int len = recv(socket, buf, sizeof(buf), 0); if (len <= 0) { if (len < 0 && errno == EINTR) continue; if (len < 0 && errno == EAGAIN) return; else { D("terminating JDWP %d connection: %s\n", proc->pid, strerror(errno)); break; } } else { D( "ignoring unexpected JDWP %d control socket activity (%d bytes)\n", proc->pid, len ); } } CloseProcess: if (proc->pid >= 0) D( "remove pid %d to jdwp process list\n", proc->pid ); jdwp_process_free(proc); return; } } if (events & FDE_WRITE) { D("trying to write to JDWP pid controli (count=%d first=%d) %d\n", proc->pid, proc->out_count, proc->out_fds[0]); if (proc->out_count > 0) { int fd = proc->out_fds[0]; int n, ret; struct cmsghdr* cmsg; struct msghdr msg; struct iovec iov; char dummy = '!'; char buffer[sizeof(struct cmsghdr) + sizeof(int)]; int flags; iov.iov_base = &dummy; iov.iov_len = 1; msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_flags = 0; msg.msg_control = buffer; msg.msg_controllen = sizeof(buffer); cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_len = msg.msg_controllen; cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; ((int*)CMSG_DATA(cmsg))[0] = fd; flags = fcntl(proc->socket,F_GETFL,0); if (flags == -1) { D("failed to get cntl flags for socket %d: %s\n", proc->pid, strerror(errno)); goto CloseProcess; } if (fcntl(proc->socket, F_SETFL, flags & ~O_NONBLOCK) == -1) { D("failed to remove O_NONBLOCK flag for socket %d: %s\n", proc->pid, strerror(errno)); goto CloseProcess; } for (;;) { ret = sendmsg(proc->socket, &msg, 0); if (ret >= 0) { adb_close(fd); break; } if (errno == EINTR) continue; D("sending new file descriptor to JDWP %d failed: %s\n", proc->pid, strerror(errno)); goto CloseProcess; } D("sent file descriptor %d to JDWP process %d\n", fd, proc->pid); for (n = 1; n < proc->out_count; n++) proc->out_fds[n-1] = proc->out_fds[n]; if (fcntl(proc->socket, F_SETFL, flags) == -1) { D("failed to set O_NONBLOCK flag for socket %d: %s\n", proc->pid, strerror(errno)); goto CloseProcess; } if (--proc->out_count == 0) fdevent_del( proc->fde, FDE_WRITE ); } } } int create_jdwp_connection_fd(int pid) { JdwpProcess* proc = _jdwp_list.next; D("looking for pid %d in JDWP process list\n", pid); for ( ; proc != &_jdwp_list; proc = proc->next ) { if (proc->pid == pid) { goto FoundIt; } } D("search failed !!\n"); return -1; FoundIt: { int fds[2]; if (proc->out_count >= MAX_OUT_FDS) { D("%s: too many pending JDWP connection for pid %d\n", __FUNCTION__, pid); return -1; } if (adb_socketpair(fds) < 0) { D("%s: socket pair creation failed: %s\n", __FUNCTION__, strerror(errno)); return -1; } proc->out_fds[ proc->out_count ] = fds[1]; if (++proc->out_count == 1) fdevent_add( proc->fde, FDE_WRITE ); return fds[0]; } } /** VM DEBUG CONTROL SOCKET ** ** we do implement a custom asocket to receive the data **/ /* name of the debug control Unix socket */ #define JDWP_CONTROL_NAME "\0jdwp-control" #define JDWP_CONTROL_NAME_LEN (sizeof(JDWP_CONTROL_NAME)-1) typedef struct { int listen_socket; fdevent* fde; } JdwpControl; static void jdwp_control_event(int s, unsigned events, void* user); static int jdwp_control_init( JdwpControl* control, const char* sockname, int socknamelen ) { struct sockaddr_un addr; socklen_t addrlen; int s; int maxpath = sizeof(addr.sun_path); int pathlen = socknamelen; if (pathlen >= maxpath) { D( "vm debug control socket name too long (%d extra chars)\n", pathlen+1-maxpath ); return -1; } memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; memcpy(addr.sun_path, sockname, socknamelen); s = socket( AF_UNIX, SOCK_STREAM, 0 ); if (s < 0) { D( "could not create vm debug control socket. %d: %s\n", errno, strerror(errno)); return -1; } addrlen = (pathlen + sizeof(addr.sun_family)); if (bind(s, (struct sockaddr*)&addr, addrlen) < 0) { D( "could not bind vm debug control socket: %d: %s\n", errno, strerror(errno) ); adb_close(s); return -1; } if ( listen(s, 4) < 0 ) { D("listen failed in jdwp control socket: %d: %s\n", errno, strerror(errno)); adb_close(s); return -1; } control->listen_socket = s; control->fde = fdevent_create(s, jdwp_control_event, control); if (control->fde == NULL) { D( "could not create fdevent for jdwp control socket\n" ); adb_close(s); return -1; } /* only wait for incoming connections */ fdevent_add(control->fde, FDE_READ); close_on_exec(s); D("jdwp control socket started (%d)\n", control->listen_socket); return 0; } static void jdwp_control_event( int s, unsigned events, void* _control ) { JdwpControl* control = (JdwpControl*) _control; if (events & FDE_READ) { struct sockaddr addr; socklen_t addrlen = sizeof(addr); int s = -1; JdwpProcess* proc; do { s = adb_socket_accept( control->listen_socket, &addr, &addrlen ); if (s < 0) { if (errno == EINTR) continue; if (errno == ECONNABORTED) { /* oops, the JDWP process died really quick */ D("oops, the JDWP process died really quick\n"); return; } /* the socket is probably closed ? */ D( "weird accept() failed on jdwp control socket: %s\n", strerror(errno) ); return; } } while (s < 0); proc = jdwp_process_alloc( s ); if (proc == NULL) return; } } static JdwpControl _jdwp_control; /** "jdwp" local service implementation ** this simply returns the list of known JDWP process pids **/ typedef struct { asocket socket; int pass; } JdwpSocket; static void jdwp_socket_close( asocket* s ) { asocket* peer = s->peer; remove_socket(s); if (peer) { peer->peer = NULL; peer->close(peer); } free(s); } static int jdwp_socket_enqueue( asocket* s, apacket* p ) { /* you can't write to this asocket */ put_apacket(p); s->peer->close(s->peer); return -1; } static void jdwp_socket_ready( asocket* s ) { JdwpSocket* jdwp = (JdwpSocket*)s; asocket* peer = jdwp->socket.peer; /* on the first call, send the list of pids, * on the second one, close the connection */ if (jdwp->pass == 0) { apacket* p = get_apacket(); p->len = jdwp_process_list((char*)p->data, MAX_PAYLOAD); peer->enqueue(peer, p); jdwp->pass = 1; } else { peer->close(peer); } } asocket* create_jdwp_service_socket( void ) { JdwpSocket* s = calloc(sizeof(*s),1); if (s == NULL) return NULL; install_local_socket(&s->socket); s->socket.ready = jdwp_socket_ready; s->socket.enqueue = jdwp_socket_enqueue; s->socket.close = jdwp_socket_close; s->pass = 0; return &s->socket; } /** "track-jdwp" local service implementation ** this periodically sends the list of known JDWP process pids ** to the client... **/ typedef struct JdwpTracker JdwpTracker; struct JdwpTracker { asocket socket; JdwpTracker* next; JdwpTracker* prev; int need_update; }; static JdwpTracker _jdwp_trackers_list; static void jdwp_process_list_updated(void) { char buffer[1024]; int len; JdwpTracker* t = _jdwp_trackers_list.next; len = jdwp_process_list_msg(buffer, sizeof(buffer)); for ( ; t != &_jdwp_trackers_list; t = t->next ) { apacket* p = get_apacket(); asocket* peer = t->socket.peer; memcpy(p->data, buffer, len); p->len = len; peer->enqueue( peer, p ); } } static void jdwp_tracker_close( asocket* s ) { JdwpTracker* tracker = (JdwpTracker*) s; asocket* peer = s->peer; if (peer) { peer->peer = NULL; peer->close(peer); } remove_socket(s); tracker->prev->next = tracker->next; tracker->next->prev = tracker->prev; free(s); } static void jdwp_tracker_ready( asocket* s ) { JdwpTracker* t = (JdwpTracker*) s; if (t->need_update) { apacket* p = get_apacket(); t->need_update = 0; p->len = jdwp_process_list_msg((char*)p->data, sizeof(p->data)); s->peer->enqueue(s->peer, p); } } static int jdwp_tracker_enqueue( asocket* s, apacket* p ) { /* you can't write to this socket */ put_apacket(p); s->peer->close(s->peer); return -1; } asocket* create_jdwp_tracker_service_socket( void ) { JdwpTracker* t = calloc(sizeof(*t),1); if (t == NULL) return NULL; t->next = &_jdwp_trackers_list; t->prev = t->next->prev; t->next->prev = t; t->prev->next = t; install_local_socket(&t->socket); t->socket.ready = jdwp_tracker_ready; t->socket.enqueue = jdwp_tracker_enqueue; t->socket.close = jdwp_tracker_close; t->need_update = 1; return &t->socket; } int init_jdwp(void) { _jdwp_list.next = &_jdwp_list; _jdwp_list.prev = &_jdwp_list; _jdwp_trackers_list.next = &_jdwp_trackers_list; _jdwp_trackers_list.prev = &_jdwp_trackers_list; return jdwp_control_init( &_jdwp_control, JDWP_CONTROL_NAME, JDWP_CONTROL_NAME_LEN ); } #endif /* !ADB_HOST */ android-tools-5.1.1r36+git20160322/core/adb/mutex_list.h000066400000000000000000000014471267427243200222710ustar00rootroot00000000000000/* the list of mutexes used by adb */ /* #ifndef __MUTEX_LIST_H * Do not use an include-guard. This file is included once to declare the locks * and once in win32 to actually do the runtime initialization. */ #ifndef ADB_MUTEX #error ADB_MUTEX not defined when including this file #endif ADB_MUTEX(socket_list_lock) ADB_MUTEX(transport_lock) #if ADB_HOST ADB_MUTEX(local_transports_lock) #endif ADB_MUTEX(usb_lock) // Sadly logging to /data/adb/adb-... is not thread safe. // After modifying adb.h::D() to count invocations: // DEBUG(jpa):0:Handling main() // DEBUG(jpa):1:[ usb_init - starting thread ] // (Oopsies, no :2:, and matching message is also gone.) // DEBUG(jpa):3:[ usb_thread - opening device ] // DEBUG(jpa):4:jdwp control socket started (10) ADB_MUTEX(D_lock) #undef ADB_MUTEX android-tools-5.1.1r36+git20160322/core/adb/protocol.txt000066400000000000000000000262341267427243200223260ustar00rootroot00000000000000 --- a replacement for aproto ------------------------------------------- When it comes down to it, aproto's primary purpose is to forward various streams between the host computer and client device (in either direction). This replacement further simplifies the concept, reducing the protocol to an extremely straightforward model optimized to accomplish the forwarding of these streams and removing additional state or complexity. The host side becomes a simple comms bridge with no "UI", which will be used by either commandline or interactive tools to communicate with a device or emulator that is connected to the bridge. The protocol is designed to be straightforward and well-defined enough that if it needs to be reimplemented in another environment (Java perhaps), there should not problems ensuring perfect interoperability. The protocol discards the layering aproto has and should allow the implementation to be much more robust. --- protocol overview and basics --------------------------------------- The transport layer deals in "messages", which consist of a 24 byte header followed (optionally) by a payload. The header consists of 6 32 bit words which are sent across the wire in little endian format. struct message { unsigned command; /* command identifier constant */ unsigned arg0; /* first argument */ unsigned arg1; /* second argument */ unsigned data_length; /* length of payload (0 is allowed) */ unsigned data_crc32; /* crc32 of data payload */ unsigned magic; /* command ^ 0xffffffff */ }; Receipt of an invalid message header, corrupt message payload, or an unrecognized command MUST result in the closing of the remote connection. The protocol depends on shared state and any break in the message stream will result in state getting out of sync. The following sections describe the six defined message types in detail. Their format is COMMAND(arg0, arg1, payload) where the payload is represented by a quoted string or an empty string if none should be sent. The identifiers "local-id" and "remote-id" are always relative to the *sender* of the message, so for a receiver, the meanings are effectively reversed. --- CONNECT(version, maxdata, "system-identity-string") ---------------- The CONNECT message establishes the presence of a remote system. The version is used to ensure protocol compatibility and maxdata declares the maximum message body size that the remote system is willing to accept. Currently, version=0x01000000 and maxdata=4096 Both sides send a CONNECT message when the connection between them is established. Until a CONNECT message is received no other messages may be sent. Any messages received before a CONNECT message MUST be ignored. If a CONNECT message is received with an unknown version or insufficiently large maxdata value, the connection with the other side must be closed. The system identity string should be "::" where systemtype is "bootloader", "device", or "host", serialno is some kind of unique ID (or empty), and banner is a human-readable version or identifier string. The banner is used to transmit useful properties. --- AUTH(type, 0, "data") ---------------------------------------------- The AUTH message informs the recipient that authentication is required to connect to the sender. If type is TOKEN(1), data is a random token that the recipient can sign with a private key. The recipient replies with an AUTH packet where type is SIGNATURE(2) and data is the signature. If the signature verification succeeds, the sender replies with a CONNECT packet. If the signature verification fails, the sender replies with a new AUTH packet and a new random token, so that the recipient can retry signing with a different private key. Once the recipient has tried all its private keys, it can reply with an AUTH packet where type is RSAPUBLICKEY(3) and data is the public key. If possible, an on-screen confirmation may be displayed for the user to confirm they want to install the public key on the device. --- OPEN(local-id, 0, "destination") ----------------------------------- The OPEN message informs the recipient that the sender has a stream identified by local-id that it wishes to connect to the named destination in the message payload. The local-id may not be zero. The OPEN message MUST result in either a READY message indicating that the connection has been established (and identifying the other end) or a CLOSE message, indicating failure. An OPEN message also implies a READY message sent at the same time. Common destination naming conventions include: * "tcp::" - host may be omitted to indicate localhost * "udp::" - host may be omitted to indicate localhost * "local-dgram:" * "local-stream:" * "shell" - local shell service * "upload" - service for pushing files across (like aproto's /sync) * "fs-bridge" - FUSE protocol filesystem bridge --- READY(local-id, remote-id, "") ------------------------------------- The READY message informs the recipient that the sender's stream identified by local-id is ready for write messages and that it is connected to the recipient's stream identified by remote-id. Neither the local-id nor the remote-id may be zero. A READY message containing a remote-id which does not map to an open stream on the recipient's side is ignored. The stream may have been closed while this message was in-flight. The local-id is ignored on all but the first READY message (where it is used to establish the connection). Nonetheless, the local-id MUST not change on later READY messages sent to the same stream. --- WRITE(0, remote-id, "data") ---------------------------------------- The WRITE message sends data to the recipient's stream identified by remote-id. The payload MUST be <= maxdata in length. A WRITE message containing a remote-id which does not map to an open stream on the recipient's side is ignored. The stream may have been closed while this message was in-flight. A WRITE message may not be sent until a READY message is received. Once a WRITE message is sent, an additional WRITE message may not be sent until another READY message has been received. Recipients of a WRITE message that is in violation of this requirement will CLOSE the connection. --- CLOSE(local-id, remote-id, "") ------------------------------------- The CLOSE message informs recipient that the connection between the sender's stream (local-id) and the recipient's stream (remote-id) is broken. The remote-id MUST not be zero, but the local-id MAY be zero if this CLOSE indicates a failed OPEN. A CLOSE message containing a remote-id which does not map to an open stream on the recipient's side is ignored. The stream may have already been closed by the recipient while this message was in-flight. The recipient should not respond to a CLOSE message in any way. The recipient should cancel pending WRITEs or CLOSEs, but this is not a requirement, since they will be ignored. --- SYNC(online, sequence, "") ----------------------------------------- The SYNC message is used by the io pump to make sure that stale outbound messages are discarded when the connection to the remote side is broken. It is only used internally to the bridge and never valid to send across the wire. * when the connection to the remote side goes offline, the io pump sends a SYNC(0, 0) and starts discarding all messages * when the connection to the remote side is established, the io pump sends a SYNC(1, token) and continues to discard messages * when the io pump receives a matching SYNC(1, token), it once again starts accepting messages to forward to the remote side --- message command constants ------------------------------------------ #define A_SYNC 0x434e5953 #define A_CNXN 0x4e584e43 #define A_AUTH 0x48545541 #define A_OPEN 0x4e45504f #define A_OKAY 0x59414b4f #define A_CLSE 0x45534c43 #define A_WRTE 0x45545257 --- implementation details --------------------------------------------- The core of the bridge program will use three threads. One thread will be a select/epoll loop to handle io between various inbound and outbound connections and the connection to the remote side. The remote side connection will be implemented as two threads (one for reading, one for writing) and a datagram socketpair to provide the channel between the main select/epoll thread and the remote connection threadpair. The reason for this is that for usb connections, the kernel interface on linux and osx does not allow you to do meaningful nonblocking IO. The endian swapping for the message headers will happen (as needed) in the remote connection threadpair and that the rest of the program will always treat message header values as native-endian. The bridge program will be able to have a number of mini-servers compiled in. They will be published under known names (examples "shell", "fs-bridge", etc) and upon receiving an OPEN() to such a service, the bridge program will create a stream socketpair and spawn a thread or subprocess to handle the io. --- simplified / embedded implementation ------------------------------- For limited environments, like the bootloader, it is allowable to support a smaller, fixed number of channels using pre-assigned channel ID numbers such that only one stream may be connected to a bootloader endpoint at any given time. The protocol remains unchanged, but the "embedded" version of it is less dynamic. The bootloader will support two streams. A "bootloader:debug" stream, which may be opened to get debug messages from the bootloader and a "bootloader:control", stream which will support the set of basic bootloader commands. Example command stream dialogues: "flash_kernel,2515049,........\n" "okay\n" "flash_ramdisk,5038,........\n" "fail,flash write error\n" "bogus_command......" --- future expansion --------------------------------------------------- I plan on providing either a message or a special control stream so that the client device could ask the host computer to setup inbound socket translations on the fly on behalf of the client device. The initial design does handshaking to provide flow control, with a message flow that looks like: >OPEN WRITE WRITE WRITE server: "OKAY" client: server: "FAIL" android-tools-5.1.1r36+git20160322/core/adb/remount_service.c000066400000000000000000000104641267427243200232770ustar00rootroot00000000000000/* * 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 "sysdeps.h" #include #include #include #include #include #include #include #include "cutils/properties.h" #define TRACE_TAG TRACE_ADB #include "adb.h" static int system_ro = 1; static int vendor_ro = 1; /* Returns the device used to mount a directory in /proc/mounts */ static char *find_mount(const char *dir) { int fd; int res; char *token = NULL; const char delims[] = "\n"; char buf[4096]; fd = unix_open("/proc/mounts", O_RDONLY | O_CLOEXEC); if (fd < 0) return NULL; buf[sizeof(buf) - 1] = '\0'; adb_read(fd, buf, sizeof(buf) - 1); adb_close(fd); token = strtok(buf, delims); while (token) { char mount_dev[256]; char mount_dir[256]; int mount_freq; int mount_passno; res = sscanf(token, "%255s %255s %*s %*s %d %d\n", mount_dev, mount_dir, &mount_freq, &mount_passno); mount_dev[255] = 0; mount_dir[255] = 0; if (res == 4 && (strcmp(dir, mount_dir) == 0)) return strdup(mount_dev); token = strtok(NULL, delims); } return NULL; } static int hasVendorPartition() { struct stat info; if (!lstat("/vendor", &info)) if ((info.st_mode & S_IFMT) == S_IFDIR) return true; return false; } /* Init mounts /system as read only, remount to enable writes. */ static int remount(const char* dir, int* dir_ro) { char *dev; int fd; int OFF = 0; if (dir_ro == 0) { return 0; } dev = find_mount(dir); if (!dev) return -1; fd = unix_open(dev, O_RDONLY | O_CLOEXEC); if (fd < 0) return -1; ioctl(fd, BLKROSET, &OFF); adb_close(fd); *dir_ro = mount(dev, dir, "none", MS_REMOUNT, NULL); free(dev); return *dir_ro; } static void write_string(int fd, const char* str) { writex(fd, str, strlen(str)); } void remount_service(int fd, void *cookie) { char buffer[200]; char prop_buf[PROPERTY_VALUE_MAX]; bool system_verified = false, vendor_verified = false; property_get("partition.system.verified", prop_buf, "0"); if (!strcmp(prop_buf, "1")) { system_verified = true; } property_get("partition.vendor.verified", prop_buf, "0"); if (!strcmp(prop_buf, "1")) { vendor_verified = true; } if (system_verified || vendor_verified) { // Allow remount but warn of likely bad effects bool both = system_verified && vendor_verified; snprintf(buffer, sizeof(buffer), "dm_verity is enabled on the %s%s%s partition%s.\n", system_verified ? "system" : "", both ? " and " : "", vendor_verified ? "vendor" : "", both ? "s" : ""); write_string(fd, buffer); snprintf(buffer, sizeof(buffer), "Use \"adb disable-verity\" to disable verity.\n" "If you do not, remount may succeed, however, you will still " "not be able to write to these volumes.\n"); write_string(fd, buffer); } if (remount("/system", &system_ro)) { snprintf(buffer, sizeof(buffer), "remount of system failed: %s\n",strerror(errno)); write_string(fd, buffer); } if (hasVendorPartition()) { if (remount("/vendor", &vendor_ro)) { snprintf(buffer, sizeof(buffer), "remount of vendor failed: %s\n",strerror(errno)); write_string(fd, buffer); } } if (!system_ro && (!vendor_ro || !hasVendorPartition())) write_string(fd, "remount succeeded\n"); else { write_string(fd, "remount failed\n"); } adb_close(fd); } android-tools-5.1.1r36+git20160322/core/adb/services.c000066400000000000000000000462721267427243200217170ustar00rootroot00000000000000/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include "sysdeps.h" #define TRACE_TAG TRACE_SERVICES #include "adb.h" #include "file_sync_service.h" #if ADB_HOST # ifndef HAVE_WINSOCK # include # include # include # endif #else # include # include #endif typedef struct stinfo stinfo; struct stinfo { void (*func)(int fd, void *cookie); int fd; void *cookie; }; void *service_bootstrap_func(void *x) { stinfo *sti = x; sti->func(sti->fd, sti->cookie); free(sti); return 0; } #if !ADB_HOST void restart_root_service(int fd, void *cookie) { char buf[100]; char value[PROPERTY_VALUE_MAX]; if (getuid() == 0) { snprintf(buf, sizeof(buf), "adbd is already running as root\n"); writex(fd, buf, strlen(buf)); adb_close(fd); } else { property_get("ro.debuggable", value, ""); if (strcmp(value, "1") != 0) { snprintf(buf, sizeof(buf), "adbd cannot run as root in production builds\n"); writex(fd, buf, strlen(buf)); adb_close(fd); return; } property_set("service.adb.root", "1"); snprintf(buf, sizeof(buf), "restarting adbd as root\n"); writex(fd, buf, strlen(buf)); adb_close(fd); } } void restart_tcp_service(int fd, void *cookie) { char buf[100]; char value[PROPERTY_VALUE_MAX]; int port = (int) (uintptr_t) cookie; if (port <= 0) { snprintf(buf, sizeof(buf), "invalid port\n"); writex(fd, buf, strlen(buf)); adb_close(fd); return; } snprintf(value, sizeof(value), "%d", port); property_set("service.adb.tcp.port", value); snprintf(buf, sizeof(buf), "restarting in TCP mode port: %d\n", port); writex(fd, buf, strlen(buf)); adb_close(fd); } void restart_usb_service(int fd, void *cookie) { char buf[100]; property_set("service.adb.tcp.port", "0"); snprintf(buf, sizeof(buf), "restarting in USB mode\n"); writex(fd, buf, strlen(buf)); adb_close(fd); } void reboot_service(int fd, void *arg) { char buf[100]; char property_val[PROPERTY_VALUE_MAX]; int ret; sync(); ret = snprintf(property_val, sizeof(property_val), "reboot,%s", (char *) arg); if (ret >= (int) sizeof(property_val)) { snprintf(buf, sizeof(buf), "reboot string too long. length=%d\n", ret); writex(fd, buf, strlen(buf)); goto cleanup; } ret = property_set(ANDROID_RB_PROPERTY, property_val); if (ret < 0) { snprintf(buf, sizeof(buf), "reboot failed: %d\n", ret); writex(fd, buf, strlen(buf)); goto cleanup; } // Don't return early. Give the reboot command time to take effect // to avoid messing up scripts which do "adb reboot && adb wait-for-device" while(1) { pause(); } cleanup: free(arg); adb_close(fd); } void reverse_service(int fd, void* arg) { const char* command = arg; if (handle_forward_request(command, kTransportAny, NULL, fd) < 0) { sendfailmsg(fd, "not a reverse forwarding command"); } free(arg); adb_close(fd); } #endif static int create_service_thread(void (*func)(int, void *), void *cookie) { stinfo *sti; adb_thread_t t; int s[2]; if(adb_socketpair(s)) { printf("cannot create service socket pair\n"); return -1; } sti = malloc(sizeof(stinfo)); if(sti == 0) fatal("cannot allocate stinfo"); sti->func = func; sti->cookie = cookie; sti->fd = s[1]; if(adb_thread_create( &t, service_bootstrap_func, sti)){ free(sti); adb_close(s[0]); adb_close(s[1]); printf("cannot create service thread\n"); return -1; } D("service thread started, %d:%d\n",s[0], s[1]); return s[0]; } #if !ADB_HOST static void init_subproc_child() { setsid(); // Set OOM score adjustment to prevent killing int fd = adb_open("/proc/self/oom_score_adj", O_WRONLY | O_CLOEXEC); if (fd >= 0) { adb_write(fd, "0", 1); adb_close(fd); } else { D("adb: unable to update oom_score_adj\n"); } } static int create_subproc_pty(const char *cmd, const char *arg0, const char *arg1, pid_t *pid) { D("create_subproc_pty(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1); #ifdef HAVE_WIN32_PROC fprintf(stderr, "error: create_subproc_pty not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1); return -1; #else /* !HAVE_WIN32_PROC */ int ptm; ptm = unix_open("/dev/ptmx", O_RDWR | O_CLOEXEC); // | O_NOCTTY); if(ptm < 0){ printf("[ cannot open /dev/ptmx - %s ]\n",strerror(errno)); return -1; } char devname[64]; if(grantpt(ptm) || unlockpt(ptm) || ptsname_r(ptm, devname, sizeof(devname)) != 0) { printf("[ trouble with /dev/ptmx - %s ]\n", strerror(errno)); adb_close(ptm); return -1; } *pid = fork(); if(*pid < 0) { printf("- fork failed: %s -\n", strerror(errno)); adb_close(ptm); return -1; } if (*pid == 0) { init_subproc_child(); int pts = unix_open(devname, O_RDWR | O_CLOEXEC); if (pts < 0) { fprintf(stderr, "child failed to open pseudo-term slave: %s\n", devname); exit(-1); } dup2(pts, STDIN_FILENO); dup2(pts, STDOUT_FILENO); dup2(pts, STDERR_FILENO); adb_close(pts); adb_close(ptm); execl(cmd, cmd, arg0, arg1, NULL); fprintf(stderr, "- exec '%s' failed: %s (%d) -\n", cmd, strerror(errno), errno); exit(-1); } else { return ptm; } #endif /* !HAVE_WIN32_PROC */ } static int create_subproc_raw(const char *cmd, const char *arg0, const char *arg1, pid_t *pid) { D("create_subproc_raw(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1); #ifdef HAVE_WIN32_PROC fprintf(stderr, "error: create_subproc_raw not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1); return -1; #else /* !HAVE_WIN32_PROC */ // 0 is parent socket, 1 is child socket int sv[2]; if (unix_socketpair(AF_UNIX, SOCK_STREAM, 0, sv) < 0) { printf("[ cannot create socket pair - %s ]\n", strerror(errno)); return -1; } *pid = fork(); if (*pid < 0) { printf("- fork failed: %s -\n", strerror(errno)); adb_close(sv[0]); adb_close(sv[1]); return -1; } if (*pid == 0) { adb_close(sv[0]); init_subproc_child(); dup2(sv[1], STDIN_FILENO); dup2(sv[1], STDOUT_FILENO); dup2(sv[1], STDERR_FILENO); adb_close(sv[1]); execl(cmd, cmd, arg0, arg1, NULL); fprintf(stderr, "- exec '%s' failed: %s (%d) -\n", cmd, strerror(errno), errno); exit(-1); } else { adb_close(sv[1]); return sv[0]; } #endif /* !HAVE_WIN32_PROC */ } #endif /* !ABD_HOST */ #if ADB_HOST #define SHELL_COMMAND "/bin/sh" #else #define SHELL_COMMAND "/system/bin/sh" #endif #if !ADB_HOST static void subproc_waiter_service(int fd, void *cookie) { pid_t pid = (pid_t) (uintptr_t) cookie; D("entered. fd=%d of pid=%d\n", fd, pid); for (;;) { int status; pid_t p = waitpid(pid, &status, 0); if (p == pid) { D("fd=%d, post waitpid(pid=%d) status=%04x\n", fd, p, status); if (WIFSIGNALED(status)) { D("*** Killed by signal %d\n", WTERMSIG(status)); break; } else if (!WIFEXITED(status)) { D("*** Didn't exit!!. status %d\n", status); break; } else if (WEXITSTATUS(status) >= 0) { D("*** Exit code %d\n", WEXITSTATUS(status)); break; } } } D("shell exited fd=%d of pid=%d err=%d\n", fd, pid, errno); if (SHELL_EXIT_NOTIFY_FD >=0) { int res; res = writex(SHELL_EXIT_NOTIFY_FD, &fd, sizeof(fd)); D("notified shell exit via fd=%d for pid=%d res=%d errno=%d\n", SHELL_EXIT_NOTIFY_FD, pid, res, errno); } } static int create_subproc_thread(const char *name, const subproc_mode mode) { stinfo *sti; adb_thread_t t; int ret_fd; pid_t pid = -1; const char *arg0, *arg1; if (name == 0 || *name == 0) { arg0 = "-"; arg1 = 0; } else { arg0 = "-c"; arg1 = name; } switch (mode) { case SUBPROC_PTY: ret_fd = create_subproc_pty(SHELL_COMMAND, arg0, arg1, &pid); break; case SUBPROC_RAW: ret_fd = create_subproc_raw(SHELL_COMMAND, arg0, arg1, &pid); break; default: fprintf(stderr, "invalid subproc_mode %d\n", mode); return -1; } D("create_subproc ret_fd=%d pid=%d\n", ret_fd, pid); sti = malloc(sizeof(stinfo)); if(sti == 0) fatal("cannot allocate stinfo"); sti->func = subproc_waiter_service; sti->cookie = (void*) (uintptr_t) pid; sti->fd = ret_fd; if (adb_thread_create(&t, service_bootstrap_func, sti)) { free(sti); adb_close(ret_fd); fprintf(stderr, "cannot create service thread\n"); return -1; } D("service thread started, fd=%d pid=%d\n", ret_fd, pid); return ret_fd; } #endif int service_to_fd(const char *name) { int ret = -1; if(!strncmp(name, "tcp:", 4)) { int port = atoi(name + 4); name = strchr(name + 4, ':'); if(name == 0) { ret = socket_loopback_client(port, SOCK_STREAM); if (ret >= 0) disable_tcp_nagle(ret); } else { #if ADB_HOST ret = socket_network_client(name + 1, port, SOCK_STREAM); #else return -1; #endif } #ifndef HAVE_WINSOCK /* winsock doesn't implement unix domain sockets */ } else if(!strncmp(name, "local:", 6)) { ret = socket_local_client(name + 6, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM); } else if(!strncmp(name, "localreserved:", 14)) { ret = socket_local_client(name + 14, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM); } else if(!strncmp(name, "localabstract:", 14)) { ret = socket_local_client(name + 14, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM); } else if(!strncmp(name, "localfilesystem:", 16)) { ret = socket_local_client(name + 16, ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM); #endif #if !ADB_HOST } else if(!strncmp("dev:", name, 4)) { ret = unix_open(name + 4, O_RDWR | O_CLOEXEC); } else if(!strncmp(name, "framebuffer:", 12)) { ret = create_service_thread(framebuffer_service, 0); } else if (!strncmp(name, "jdwp:", 5)) { ret = create_jdwp_connection_fd(atoi(name+5)); } else if(!HOST && !strncmp(name, "shell:", 6)) { ret = create_subproc_thread(name + 6, SUBPROC_PTY); } else if(!HOST && !strncmp(name, "exec:", 5)) { ret = create_subproc_thread(name + 5, SUBPROC_RAW); } else if(!strncmp(name, "sync:", 5)) { ret = create_service_thread(file_sync_service, NULL); } else if(!strncmp(name, "remount:", 8)) { ret = create_service_thread(remount_service, NULL); } else if(!strncmp(name, "reboot:", 7)) { void* arg = strdup(name + 7); if (arg == NULL) return -1; ret = create_service_thread(reboot_service, arg); } else if(!strncmp(name, "root:", 5)) { ret = create_service_thread(restart_root_service, NULL); } else if(!strncmp(name, "backup:", 7)) { char* arg = strdup(name + 7); if (arg == NULL) return -1; char* c = arg; for (; *c != '\0'; c++) { if (*c == ':') *c = ' '; } char* cmd; if (asprintf(&cmd, "/system/bin/bu backup %s", arg) != -1) { ret = create_subproc_thread(cmd, SUBPROC_RAW); free(cmd); } free(arg); } else if(!strncmp(name, "restore:", 8)) { ret = create_subproc_thread("/system/bin/bu restore", SUBPROC_RAW); } else if(!strncmp(name, "tcpip:", 6)) { int port; if (sscanf(name + 6, "%d", &port) == 0) { port = 0; } ret = create_service_thread(restart_tcp_service, (void *) (uintptr_t) port); } else if(!strncmp(name, "usb:", 4)) { ret = create_service_thread(restart_usb_service, NULL); } else if (!strncmp(name, "reverse:", 8)) { char* cookie = strdup(name + 8); if (cookie == NULL) { ret = -1; } else { ret = create_service_thread(reverse_service, cookie); if (ret < 0) { free(cookie); } } } else if(!strncmp(name, "disable-verity:", 15)) { ret = create_service_thread(disable_verity_service, NULL); #endif } if (ret >= 0) { close_on_exec(ret); } return ret; } #if ADB_HOST struct state_info { transport_type transport; char* serial; int state; }; static void wait_for_state(int fd, void* cookie) { struct state_info* sinfo = cookie; char* err = "unknown error"; D("wait_for_state %d\n", sinfo->state); atransport *t = acquire_one_transport(sinfo->state, sinfo->transport, sinfo->serial, &err); if(t != 0) { writex(fd, "OKAY", 4); } else { sendfailmsg(fd, err); } if (sinfo->serial) free(sinfo->serial); free(sinfo); adb_close(fd); D("wait_for_state is done\n"); } static void connect_device(char* host, char* buffer, int buffer_size) { int port, fd; char* portstr = strchr(host, ':'); char hostbuf[100]; char serial[100]; int ret; strncpy(hostbuf, host, sizeof(hostbuf) - 1); if (portstr) { if (portstr - host >= (ptrdiff_t)sizeof(hostbuf)) { snprintf(buffer, buffer_size, "bad host name %s", host); return; } // zero terminate the host at the point we found the colon hostbuf[portstr - host] = 0; if (sscanf(portstr + 1, "%d", &port) == 0) { snprintf(buffer, buffer_size, "bad port number %s", portstr); return; } } else { port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT; } snprintf(serial, sizeof(serial), "%s:%d", hostbuf, port); fd = socket_network_client_timeout(hostbuf, port, SOCK_STREAM, 10); if (fd < 0) { snprintf(buffer, buffer_size, "unable to connect to %s:%d", host, port); return; } D("client: connected on remote on fd %d\n", fd); close_on_exec(fd); disable_tcp_nagle(fd); ret = register_socket_transport(fd, serial, port, 0); if (ret < 0) { adb_close(fd); snprintf(buffer, buffer_size, "already connected to %s", serial); } else { snprintf(buffer, buffer_size, "connected to %s", serial); } } void connect_emulator(char* port_spec, char* buffer, int buffer_size) { char* port_separator = strchr(port_spec, ','); if (!port_separator) { snprintf(buffer, buffer_size, "unable to parse '%s' as ,", port_spec); return; } // Zero-terminate console port and make port_separator point to 2nd port. *port_separator++ = 0; int console_port = strtol(port_spec, NULL, 0); int adb_port = strtol(port_separator, NULL, 0); if (!(console_port > 0 && adb_port > 0)) { *(port_separator - 1) = ','; snprintf(buffer, buffer_size, "Invalid port numbers: Expected positive numbers, got '%s'", port_spec); return; } /* Check if the emulator is already known. * Note: There's a small but harmless race condition here: An emulator not * present just yet could be registered by another invocation right * after doing this check here. However, local_connect protects * against double-registration too. From here, a better error message * can be produced. In the case of the race condition, the very specific * error message won't be shown, but the data doesn't get corrupted. */ atransport* known_emulator = find_emulator_transport_by_adb_port(adb_port); if (known_emulator != NULL) { snprintf(buffer, buffer_size, "Emulator on port %d already registered.", adb_port); return; } /* Check if more emulators can be registered. Similar unproblematic * race condition as above. */ int candidate_slot = get_available_local_transport_index(); if (candidate_slot < 0) { snprintf(buffer, buffer_size, "Cannot accept more emulators."); return; } /* Preconditions met, try to connect to the emulator. */ if (!local_connect_arbitrary_ports(console_port, adb_port)) { snprintf(buffer, buffer_size, "Connected to emulator on ports %d,%d", console_port, adb_port); } else { snprintf(buffer, buffer_size, "Could not connect to emulator on ports %d,%d", console_port, adb_port); } } static void connect_service(int fd, void* cookie) { char buf[4096]; char resp[4096]; char *host = cookie; if (!strncmp(host, "emu:", 4)) { connect_emulator(host + 4, buf, sizeof(buf)); } else { connect_device(host, buf, sizeof(buf)); } // Send response for emulator and device snprintf(resp, sizeof(resp), "%04x%s",(unsigned)strlen(buf), buf); writex(fd, resp, strlen(resp)); adb_close(fd); } #endif #if ADB_HOST asocket* host_service_to_socket(const char* name, const char *serial) { if (!strcmp(name,"track-devices")) { return create_device_tracker(); } else if (!strncmp(name, "wait-for-", strlen("wait-for-"))) { struct state_info* sinfo = malloc(sizeof(struct state_info)); if (serial) sinfo->serial = strdup(serial); else sinfo->serial = NULL; name += strlen("wait-for-"); if (!strncmp(name, "local", strlen("local"))) { sinfo->transport = kTransportLocal; sinfo->state = CS_DEVICE; } else if (!strncmp(name, "usb", strlen("usb"))) { sinfo->transport = kTransportUsb; sinfo->state = CS_DEVICE; } else if (!strncmp(name, "any", strlen("any"))) { sinfo->transport = kTransportAny; sinfo->state = CS_DEVICE; } else { free(sinfo); return NULL; } int fd = create_service_thread(wait_for_state, sinfo); return create_local_socket(fd); } else if (!strncmp(name, "connect:", 8)) { const char *host = name + 8; int fd = create_service_thread(connect_service, (void *)host); return create_local_socket(fd); } return NULL; } #endif /* ADB_HOST */ android-tools-5.1.1r36+git20160322/core/adb/sockets.c000066400000000000000000000617201267427243200215420ustar00rootroot00000000000000/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include "sysdeps.h" #if !ADB_HOST #include #endif #define TRACE_TAG TRACE_SOCKETS #include "adb.h" ADB_MUTEX_DEFINE( socket_list_lock ); static void local_socket_close_locked(asocket *s); int sendfailmsg(int fd, const char *reason) { char buf[9]; int len; len = strlen(reason); if(len > 0xffff) len = 0xffff; snprintf(buf, sizeof buf, "FAIL%04x", len); if(writex(fd, buf, 8)) return -1; return writex(fd, reason, len); } //extern int online; static unsigned local_socket_next_id = 1; static asocket local_socket_list = { .next = &local_socket_list, .prev = &local_socket_list, }; /* the the list of currently closing local sockets. ** these have no peer anymore, but still packets to ** write to their fd. */ static asocket local_socket_closing_list = { .next = &local_socket_closing_list, .prev = &local_socket_closing_list, }; // Parse the global list of sockets to find one with id |local_id|. // If |peer_id| is not 0, also check that it is connected to a peer // with id |peer_id|. Returns an asocket handle on success, NULL on failure. asocket *find_local_socket(unsigned local_id, unsigned peer_id) { asocket *s; asocket *result = NULL; adb_mutex_lock(&socket_list_lock); for (s = local_socket_list.next; s != &local_socket_list; s = s->next) { if (s->id != local_id) continue; if (peer_id == 0 || (s->peer && s->peer->id == peer_id)) { result = s; } break; } adb_mutex_unlock(&socket_list_lock); return result; } static void insert_local_socket(asocket* s, asocket* list) { s->next = list; s->prev = s->next->prev; s->prev->next = s; s->next->prev = s; } void install_local_socket(asocket *s) { adb_mutex_lock(&socket_list_lock); s->id = local_socket_next_id++; // Socket ids should never be 0. if (local_socket_next_id == 0) local_socket_next_id = 1; insert_local_socket(s, &local_socket_list); adb_mutex_unlock(&socket_list_lock); } void remove_socket(asocket *s) { // socket_list_lock should already be held if (s->prev && s->next) { s->prev->next = s->next; s->next->prev = s->prev; s->next = 0; s->prev = 0; s->id = 0; } } void close_all_sockets(atransport *t) { asocket *s; /* this is a little gross, but since s->close() *will* modify ** the list out from under you, your options are limited. */ adb_mutex_lock(&socket_list_lock); restart: for(s = local_socket_list.next; s != &local_socket_list; s = s->next){ if(s->transport == t || (s->peer && s->peer->transport == t)) { local_socket_close_locked(s); goto restart; } } adb_mutex_unlock(&socket_list_lock); } static int local_socket_enqueue(asocket *s, apacket *p) { D("LS(%d): enqueue %d\n", s->id, p->len); p->ptr = p->data; /* if there is already data queue'd, we will receive ** events when it's time to write. just add this to ** the tail */ if(s->pkt_first) { goto enqueue; } /* write as much as we can, until we ** would block or there is an error/eof */ while(p->len > 0) { int r = adb_write(s->fd, p->ptr, p->len); if(r > 0) { p->len -= r; p->ptr += r; continue; } if((r == 0) || (errno != EAGAIN)) { D( "LS(%d): not ready, errno=%d: %s\n", s->id, errno, strerror(errno) ); s->close(s); return 1; /* not ready (error) */ } else { break; } } if(p->len == 0) { put_apacket(p); return 0; /* ready for more data */ } enqueue: p->next = 0; if(s->pkt_first) { s->pkt_last->next = p; } else { s->pkt_first = p; } s->pkt_last = p; /* make sure we are notified when we can drain the queue */ fdevent_add(&s->fde, FDE_WRITE); return 1; /* not ready (backlog) */ } static void local_socket_ready(asocket *s) { /* far side is ready for data, pay attention to readable events */ fdevent_add(&s->fde, FDE_READ); // D("LS(%d): ready()\n", s->id); } static void local_socket_close(asocket *s) { adb_mutex_lock(&socket_list_lock); local_socket_close_locked(s); adb_mutex_unlock(&socket_list_lock); } // be sure to hold the socket list lock when calling this static void local_socket_destroy(asocket *s) { apacket *p, *n; int exit_on_close = s->exit_on_close; D("LS(%d): destroying fde.fd=%d\n", s->id, s->fde.fd); /* IMPORTANT: the remove closes the fd ** that belongs to this socket */ fdevent_remove(&s->fde); /* dispose of any unwritten data */ for(p = s->pkt_first; p; p = n) { D("LS(%d): discarding %d bytes\n", s->id, p->len); n = p->next; put_apacket(p); } remove_socket(s); free(s); if (exit_on_close) { D("local_socket_destroy: exiting\n"); exit(1); } } static void local_socket_close_locked(asocket *s) { D("entered. LS(%d) fd=%d\n", s->id, s->fd); if(s->peer) { D("LS(%d): closing peer. peer->id=%d peer->fd=%d\n", s->id, s->peer->id, s->peer->fd); /* Note: it's important to call shutdown before disconnecting from * the peer, this ensures that remote sockets can still get the id * of the local socket they're connected to, to send a CLOSE() * protocol event. */ if (s->peer->shutdown) s->peer->shutdown(s->peer); s->peer->peer = 0; // tweak to avoid deadlock if (s->peer->close == local_socket_close) { local_socket_close_locked(s->peer); } else { s->peer->close(s->peer); } s->peer = 0; } /* If we are already closing, or if there are no ** pending packets, destroy immediately */ if (s->closing || s->pkt_first == NULL) { int id = s->id; local_socket_destroy(s); D("LS(%d): closed\n", id); return; } /* otherwise, put on the closing list */ D("LS(%d): closing\n", s->id); s->closing = 1; fdevent_del(&s->fde, FDE_READ); remove_socket(s); D("LS(%d): put on socket_closing_list fd=%d\n", s->id, s->fd); insert_local_socket(s, &local_socket_closing_list); } static void local_socket_event_func(int fd, unsigned ev, void *_s) { asocket *s = _s; D("LS(%d): event_func(fd=%d(==%d), ev=%04x)\n", s->id, s->fd, fd, ev); /* put the FDE_WRITE processing before the FDE_READ ** in order to simplify the code. */ if(ev & FDE_WRITE){ apacket *p; while((p = s->pkt_first) != 0) { while(p->len > 0) { int r = adb_write(fd, p->ptr, p->len); if(r > 0) { p->ptr += r; p->len -= r; continue; } if(r < 0) { /* returning here is ok because FDE_READ will ** be processed in the next iteration loop */ if(errno == EAGAIN) return; if(errno == EINTR) continue; } D(" closing after write because r=%d and errno is %d\n", r, errno); s->close(s); return; } if(p->len == 0) { s->pkt_first = p->next; if(s->pkt_first == 0) s->pkt_last = 0; put_apacket(p); } } /* if we sent the last packet of a closing socket, ** we can now destroy it. */ if (s->closing) { D(" closing because 'closing' is set after write\n"); s->close(s); return; } /* no more packets queued, so we can ignore ** writable events again and tell our peer ** to resume writing */ fdevent_del(&s->fde, FDE_WRITE); s->peer->ready(s->peer); } if(ev & FDE_READ){ apacket *p = get_apacket(); unsigned char *x = p->data; size_t avail = MAX_PAYLOAD; int r; int is_eof = 0; while(avail > 0) { r = adb_read(fd, x, avail); D("LS(%d): post adb_read(fd=%d,...) r=%d (errno=%d) avail=%zu\n", s->id, s->fd, r, r<0?errno:0, avail); if(r > 0) { avail -= r; x += r; continue; } if(r < 0) { if(errno == EAGAIN) break; if(errno == EINTR) continue; } /* r = 0 or unhandled error */ is_eof = 1; break; } D("LS(%d): fd=%d post avail loop. r=%d is_eof=%d forced_eof=%d\n", s->id, s->fd, r, is_eof, s->fde.force_eof); if((avail == MAX_PAYLOAD) || (s->peer == 0)) { put_apacket(p); } else { p->len = MAX_PAYLOAD - avail; r = s->peer->enqueue(s->peer, p); D("LS(%d): fd=%d post peer->enqueue(). r=%d\n", s->id, s->fd, r); if(r < 0) { /* error return means they closed us as a side-effect ** and we must return immediately. ** ** note that if we still have buffered packets, the ** socket will be placed on the closing socket list. ** this handler function will be called again ** to process FDE_WRITE events. */ return; } if(r > 0) { /* if the remote cannot accept further events, ** we disable notification of READs. They'll ** be enabled again when we get a call to ready() */ fdevent_del(&s->fde, FDE_READ); } } /* Don't allow a forced eof if data is still there */ if((s->fde.force_eof && !r) || is_eof) { D(" closing because is_eof=%d r=%d s->fde.force_eof=%d\n", is_eof, r, s->fde.force_eof); s->close(s); } } if(ev & FDE_ERROR){ /* this should be caught be the next read or write ** catching it here means we may skip the last few ** bytes of readable data. */ // s->close(s); D("LS(%d): FDE_ERROR (fd=%d)\n", s->id, s->fd); return; } } asocket *create_local_socket(int fd) { asocket *s = calloc(1, sizeof(asocket)); if (s == NULL) fatal("cannot allocate socket"); s->fd = fd; s->enqueue = local_socket_enqueue; s->ready = local_socket_ready; s->shutdown = NULL; s->close = local_socket_close; install_local_socket(s); fdevent_install(&s->fde, fd, local_socket_event_func, s); /* fdevent_add(&s->fde, FDE_ERROR); */ //fprintf(stderr, "Created local socket in create_local_socket \n"); D("LS(%d): created (fd=%d)\n", s->id, s->fd); return s; } asocket *create_local_service_socket(const char *name) { asocket *s; int fd; #if !ADB_HOST char debug[PROPERTY_VALUE_MAX]; #endif #if !ADB_HOST if (!strcmp(name,"jdwp")) { return create_jdwp_service_socket(); } if (!strcmp(name,"track-jdwp")) { return create_jdwp_tracker_service_socket(); } #endif fd = service_to_fd(name); if(fd < 0) return 0; s = create_local_socket(fd); D("LS(%d): bound to '%s' via %d\n", s->id, name, fd); #if !ADB_HOST if (!strncmp(name, "root:", 5)) property_get("ro.debuggable", debug, ""); if ((!strncmp(name, "root:", 5) && getuid() != 0 && strcmp(debug, "1") == 0) || !strncmp(name, "usb:", 4) || !strncmp(name, "tcpip:", 6)) { D("LS(%d): enabling exit_on_close\n", s->id); s->exit_on_close = 1; } #endif return s; } #if ADB_HOST static asocket *create_host_service_socket(const char *name, const char* serial) { asocket *s; s = host_service_to_socket(name, serial); if (s != NULL) { D("LS(%d) bound to '%s'\n", s->id, name); return s; } return s; } #endif /* ADB_HOST */ /* a Remote socket is used to send/receive data to/from a given transport object ** it needs to be closed when the transport is forcibly destroyed by the user */ typedef struct aremotesocket { asocket socket; adisconnect disconnect; } aremotesocket; static int remote_socket_enqueue(asocket *s, apacket *p) { D("entered remote_socket_enqueue RS(%d) WRITE fd=%d peer.fd=%d\n", s->id, s->fd, s->peer->fd); p->msg.command = A_WRTE; p->msg.arg0 = s->peer->id; p->msg.arg1 = s->id; p->msg.data_length = p->len; send_packet(p, s->transport); return 1; } static void remote_socket_ready(asocket *s) { D("entered remote_socket_ready RS(%d) OKAY fd=%d peer.fd=%d\n", s->id, s->fd, s->peer->fd); apacket *p = get_apacket(); p->msg.command = A_OKAY; p->msg.arg0 = s->peer->id; p->msg.arg1 = s->id; send_packet(p, s->transport); } static void remote_socket_shutdown(asocket *s) { D("entered remote_socket_shutdown RS(%d) CLOSE fd=%d peer->fd=%d\n", s->id, s->fd, s->peer?s->peer->fd:-1); apacket *p = get_apacket(); p->msg.command = A_CLSE; if(s->peer) { p->msg.arg0 = s->peer->id; } p->msg.arg1 = s->id; send_packet(p, s->transport); } static void remote_socket_close(asocket *s) { if (s->peer) { s->peer->peer = 0; D("RS(%d) peer->close()ing peer->id=%d peer->fd=%d\n", s->id, s->peer->id, s->peer->fd); s->peer->close(s->peer); } D("entered remote_socket_close RS(%d) CLOSE fd=%d peer->fd=%d\n", s->id, s->fd, s->peer?s->peer->fd:-1); D("RS(%d): closed\n", s->id); remove_transport_disconnect( s->transport, &((aremotesocket*)s)->disconnect ); free(s); } static void remote_socket_disconnect(void* _s, atransport* t) { asocket* s = _s; asocket* peer = s->peer; D("remote_socket_disconnect RS(%d)\n", s->id); if (peer) { peer->peer = NULL; peer->close(peer); } remove_transport_disconnect( s->transport, &((aremotesocket*)s)->disconnect ); free(s); } /* Create an asocket to exchange packets with a remote service through transport |t|. Where |id| is the socket id of the corresponding service on the other side of the transport (it is allocated by the remote side and _cannot_ be 0). Returns a new non-NULL asocket handle. */ asocket *create_remote_socket(unsigned id, atransport *t) { asocket* s; adisconnect* dis; if (id == 0) fatal("invalid remote socket id (0)"); s = calloc(1, sizeof(aremotesocket)); dis = &((aremotesocket*)s)->disconnect; if (s == NULL) fatal("cannot allocate socket"); s->id = id; s->enqueue = remote_socket_enqueue; s->ready = remote_socket_ready; s->shutdown = remote_socket_shutdown; s->close = remote_socket_close; s->transport = t; dis->func = remote_socket_disconnect; dis->opaque = s; add_transport_disconnect( t, dis ); D("RS(%d): created\n", s->id); return s; } void connect_to_remote(asocket *s, const char *destination) { D("Connect_to_remote call RS(%d) fd=%d\n", s->id, s->fd); apacket *p = get_apacket(); int len = strlen(destination) + 1; if(len > (MAX_PAYLOAD-1)) { fatal("destination oversized"); } D("LS(%d): connect('%s')\n", s->id, destination); p->msg.command = A_OPEN; p->msg.arg0 = s->id; p->msg.data_length = len; strcpy((char*) p->data, destination); send_packet(p, s->transport); } /* this is used by magic sockets to rig local sockets to send the go-ahead message when they connect */ static void local_socket_ready_notify(asocket *s) { s->ready = local_socket_ready; s->shutdown = NULL; s->close = local_socket_close; adb_write(s->fd, "OKAY", 4); s->ready(s); } /* this is used by magic sockets to rig local sockets to send the failure message if they are closed before connected (to avoid closing them without a status message) */ static void local_socket_close_notify(asocket *s) { s->ready = local_socket_ready; s->shutdown = NULL; s->close = local_socket_close; sendfailmsg(s->fd, "closed"); s->close(s); } unsigned unhex(unsigned char *s, int len) { unsigned n = 0, c; while(len-- > 0) { switch((c = *s++)) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': c -= '0'; break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': c = c - 'a' + 10; break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': c = c - 'A' + 10; break; default: return 0xffffffff; } n = (n << 4) | c; } return n; } #define PREFIX(str) { str, sizeof(str) - 1 } static const struct prefix_struct { const char *str; const size_t len; } prefixes[] = { PREFIX("usb:"), PREFIX("product:"), PREFIX("model:"), PREFIX("device:"), }; static const int num_prefixes = (sizeof(prefixes) / sizeof(prefixes[0])); /* skip_host_serial return the position in a string skipping over the 'serial' parameter in the ADB protocol, where parameter string may be a host:port string containing the protocol delimiter (colon). */ char *skip_host_serial(char *service) { char *first_colon, *serial_end; int i; for (i = 0; i < num_prefixes; i++) { if (!strncmp(service, prefixes[i].str, prefixes[i].len)) return strchr(service + prefixes[i].len, ':'); } first_colon = strchr(service, ':'); if (!first_colon) { /* No colon in service string. */ return NULL; } serial_end = first_colon; if (isdigit(serial_end[1])) { serial_end++; while ((*serial_end) && isdigit(*serial_end)) { serial_end++; } if ((*serial_end) != ':') { // Something other than numbers was found, reset the end. serial_end = first_colon; } } return serial_end; } static int smart_socket_enqueue(asocket *s, apacket *p) { unsigned len; #if ADB_HOST char *service = NULL; char* serial = NULL; transport_type ttype = kTransportAny; #endif D("SS(%d): enqueue %d\n", s->id, p->len); if(s->pkt_first == 0) { s->pkt_first = p; s->pkt_last = p; } else { if((s->pkt_first->len + p->len) > MAX_PAYLOAD) { D("SS(%d): overflow\n", s->id); put_apacket(p); goto fail; } memcpy(s->pkt_first->data + s->pkt_first->len, p->data, p->len); s->pkt_first->len += p->len; put_apacket(p); p = s->pkt_first; } /* don't bother if we can't decode the length */ if(p->len < 4) return 0; len = unhex(p->data, 4); if((len < 1) || (len > 1024)) { D("SS(%d): bad size (%d)\n", s->id, len); goto fail; } D("SS(%d): len is %d\n", s->id, len ); /* can't do anything until we have the full header */ if((len + 4) > p->len) { D("SS(%d): waiting for %d more bytes\n", s->id, len+4 - p->len); return 0; } p->data[len + 4] = 0; D("SS(%d): '%s'\n", s->id, (char*) (p->data + 4)); #if ADB_HOST service = (char *)p->data + 4; if(!strncmp(service, "host-serial:", strlen("host-serial:"))) { char* serial_end; service += strlen("host-serial:"); // serial number should follow "host:" and could be a host:port string. serial_end = skip_host_serial(service); if (serial_end) { *serial_end = 0; // terminate string serial = service; service = serial_end + 1; } } else if (!strncmp(service, "host-usb:", strlen("host-usb:"))) { ttype = kTransportUsb; service += strlen("host-usb:"); } else if (!strncmp(service, "host-local:", strlen("host-local:"))) { ttype = kTransportLocal; service += strlen("host-local:"); } else if (!strncmp(service, "host:", strlen("host:"))) { ttype = kTransportAny; service += strlen("host:"); } else { service = NULL; } if (service) { asocket *s2; /* some requests are handled immediately -- in that ** case the handle_host_request() routine has sent ** the OKAY or FAIL message and all we have to do ** is clean up. */ if(handle_host_request(service, ttype, serial, s->peer->fd, s) == 0) { /* XXX fail message? */ D( "SS(%d): handled host service '%s'\n", s->id, service ); goto fail; } if (!strncmp(service, "transport", strlen("transport"))) { D( "SS(%d): okay transport\n", s->id ); p->len = 0; return 0; } /* try to find a local service with this name. ** if no such service exists, we'll fail out ** and tear down here. */ s2 = create_host_service_socket(service, serial); if(s2 == 0) { D( "SS(%d): couldn't create host service '%s'\n", s->id, service ); sendfailmsg(s->peer->fd, "unknown host service"); goto fail; } /* we've connected to a local host service, ** so we make our peer back into a regular ** local socket and bind it to the new local ** service socket, acknowledge the successful ** connection, and close this smart socket now ** that its work is done. */ adb_write(s->peer->fd, "OKAY", 4); s->peer->ready = local_socket_ready; s->peer->shutdown = NULL; s->peer->close = local_socket_close; s->peer->peer = s2; s2->peer = s->peer; s->peer = 0; D( "SS(%d): okay\n", s->id ); s->close(s); /* initial state is "ready" */ s2->ready(s2); return 0; } #else /* !ADB_HOST */ if (s->transport == NULL) { char* error_string = "unknown failure"; s->transport = acquire_one_transport (CS_ANY, kTransportAny, NULL, &error_string); if (s->transport == NULL) { sendfailmsg(s->peer->fd, error_string); goto fail; } } #endif if(!(s->transport) || (s->transport->connection_state == CS_OFFLINE)) { /* if there's no remote we fail the connection ** right here and terminate it */ sendfailmsg(s->peer->fd, "device offline (x)"); goto fail; } /* instrument our peer to pass the success or fail ** message back once it connects or closes, then ** detach from it, request the connection, and ** tear down */ s->peer->ready = local_socket_ready_notify; s->peer->shutdown = NULL; s->peer->close = local_socket_close_notify; s->peer->peer = 0; /* give him our transport and upref it */ s->peer->transport = s->transport; connect_to_remote(s->peer, (char*) (p->data + 4)); s->peer = 0; s->close(s); return 1; fail: /* we're going to close our peer as a side-effect, so ** return -1 to signal that state to the local socket ** who is enqueueing against us */ s->close(s); return -1; } static void smart_socket_ready(asocket *s) { D("SS(%d): ready\n", s->id); } static void smart_socket_close(asocket *s) { D("SS(%d): closed\n", s->id); if(s->pkt_first){ put_apacket(s->pkt_first); } if(s->peer) { s->peer->peer = 0; s->peer->close(s->peer); s->peer = 0; } free(s); } static asocket *create_smart_socket(void) { D("Creating smart socket \n"); asocket *s = calloc(1, sizeof(asocket)); if (s == NULL) fatal("cannot allocate socket"); s->enqueue = smart_socket_enqueue; s->ready = smart_socket_ready; s->shutdown = NULL; s->close = smart_socket_close; D("SS(%d)\n", s->id); return s; } void connect_to_smartsocket(asocket *s) { D("Connecting to smart socket \n"); asocket *ss = create_smart_socket(); s->peer = ss; ss->peer = s; s->ready(s); } android-tools-5.1.1r36+git20160322/core/adb/sysdeps.h000066400000000000000000000310451267427243200215630ustar00rootroot00000000000000/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* this file contains system-dependent definitions used by ADB * they're related to threads, sockets and file descriptors */ #ifndef _ADB_SYSDEPS_H #define _ADB_SYSDEPS_H #ifdef __CYGWIN__ # undef _WIN32 #endif #ifdef _WIN32 #include #include #include #include #include #include #include #include #include #include #define OS_PATH_SEPARATOR '\\' #define OS_PATH_SEPARATOR_STR "\\" #define ENV_PATH_SEPARATOR_STR ";" typedef CRITICAL_SECTION adb_mutex_t; #define ADB_MUTEX_DEFINE(x) adb_mutex_t x /* declare all mutexes */ /* For win32, adb_sysdeps_init() will do the mutex runtime initialization. */ #define ADB_MUTEX(x) extern adb_mutex_t x; #include "mutex_list.h" extern void adb_sysdeps_init(void); static __inline__ void adb_mutex_lock( adb_mutex_t* lock ) { EnterCriticalSection( lock ); } static __inline__ void adb_mutex_unlock( adb_mutex_t* lock ) { LeaveCriticalSection( lock ); } typedef struct { unsigned tid; } adb_thread_t; typedef void* (*adb_thread_func_t)(void* arg); typedef void (*win_thread_func_t)(void* arg); static __inline__ int adb_thread_create( adb_thread_t *thread, adb_thread_func_t func, void* arg) { thread->tid = _beginthread( (win_thread_func_t)func, 0, arg ); if (thread->tid == (unsigned)-1L) { return -1; } return 0; } static __inline__ void close_on_exec(int fd) { /* nothing really */ } extern void disable_tcp_nagle(int fd); #define lstat stat /* no symlinks on Win32 */ #define S_ISLNK(m) 0 /* no symlinks on Win32 */ static __inline__ int adb_unlink(const char* path) { int rc = unlink(path); if (rc == -1 && errno == EACCES) { /* unlink returns EACCES when the file is read-only, so we first */ /* try to make it writable, then unlink again... */ rc = chmod(path, _S_IREAD|_S_IWRITE ); if (rc == 0) rc = unlink(path); } return rc; } #undef unlink #define unlink ___xxx_unlink static __inline__ int adb_mkdir(const char* path, int mode) { return _mkdir(path); } #undef mkdir #define mkdir ___xxx_mkdir extern int adb_open(const char* path, int options); extern int adb_creat(const char* path, int mode); extern int adb_read(int fd, void* buf, int len); extern int adb_write(int fd, const void* buf, int len); extern int adb_lseek(int fd, int pos, int where); extern int adb_shutdown(int fd); extern int adb_close(int fd); static __inline__ int unix_close(int fd) { return close(fd); } #undef close #define close ____xxx_close static __inline__ int unix_read(int fd, void* buf, size_t len) { return read(fd, buf, len); } #undef read #define read ___xxx_read static __inline__ int unix_write(int fd, const void* buf, size_t len) { return write(fd, buf, len); } #undef write #define write ___xxx_write static __inline__ int adb_open_mode(const char* path, int options, int mode) { return adb_open(path, options); } static __inline__ int unix_open(const char* path, int options,...) { if ((options & O_CREAT) == 0) { return open(path, options); } else { int mode; va_list args; va_start( args, options ); mode = va_arg( args, int ); va_end( args ); return open(path, options, mode); } } #define open ___xxx_unix_open /* normally provided by */ extern void* load_file(const char* pathname, unsigned* psize); /* normally provided by */ extern int socket_loopback_client(int port, int type); extern int socket_network_client(const char *host, int port, int type); extern int socket_network_client_timeout(const char *host, int port, int type, int timeout); extern int socket_loopback_server(int port, int type); extern int socket_inaddr_any_server(int port, int type); /* normally provided by "fdevent.h" */ #define FDE_READ 0x0001 #define FDE_WRITE 0x0002 #define FDE_ERROR 0x0004 #define FDE_DONT_CLOSE 0x0080 typedef struct fdevent fdevent; typedef void (*fd_func)(int fd, unsigned events, void *userdata); fdevent *fdevent_create(int fd, fd_func func, void *arg); void fdevent_destroy(fdevent *fde); void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg); void fdevent_remove(fdevent *item); void fdevent_set(fdevent *fde, unsigned events); void fdevent_add(fdevent *fde, unsigned events); void fdevent_del(fdevent *fde, unsigned events); void fdevent_loop(); struct fdevent { fdevent *next; fdevent *prev; int fd; int force_eof; unsigned short state; unsigned short events; fd_func func; void *arg; }; static __inline__ void adb_sleep_ms( int mseconds ) { Sleep( mseconds ); } extern int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen); #undef accept #define accept ___xxx_accept static __inline__ int adb_socket_setbufsize( int fd, int bufsize ) { int opt = bufsize; return setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char*)&opt, sizeof(opt)); } extern int adb_socketpair( int sv[2] ); static __inline__ char* adb_dirstart( const char* path ) { char* p = strchr(path, '/'); char* p2 = strchr(path, '\\'); if ( !p ) p = p2; else if ( p2 && p2 > p ) p = p2; return p; } static __inline__ char* adb_dirstop( const char* path ) { char* p = strrchr(path, '/'); char* p2 = strrchr(path, '\\'); if ( !p ) p = p2; else if ( p2 && p2 > p ) p = p2; return p; } static __inline__ int adb_is_absolute_host_path( const char* path ) { return isalpha(path[0]) && path[1] == ':' && path[2] == '\\'; } extern char* adb_strtok_r(char *str, const char *delim, char **saveptr); #else /* !_WIN32 a.k.a. Unix */ #include "fdevent.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * TEMP_FAILURE_RETRY is defined by some, but not all, versions of * . (Alas, it is not as standard as we'd hoped!) So, if it's * not already defined, then define it here. */ #ifndef TEMP_FAILURE_RETRY /* Used to retry syscalls that can return EINTR. */ #define TEMP_FAILURE_RETRY(exp) ({ \ typeof (exp) _rc; \ do { \ _rc = (exp); \ } while (_rc == -1 && errno == EINTR); \ _rc; }) #endif #define OS_PATH_SEPARATOR '/' #define OS_PATH_SEPARATOR_STR "/" #define ENV_PATH_SEPARATOR_STR ":" typedef pthread_mutex_t adb_mutex_t; #define ADB_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER #define adb_mutex_init pthread_mutex_init #define adb_mutex_lock pthread_mutex_lock #define adb_mutex_unlock pthread_mutex_unlock #define adb_mutex_destroy pthread_mutex_destroy #define ADB_MUTEX_DEFINE(m) adb_mutex_t m = PTHREAD_MUTEX_INITIALIZER #define adb_cond_t pthread_cond_t #define adb_cond_init pthread_cond_init #define adb_cond_wait pthread_cond_wait #define adb_cond_broadcast pthread_cond_broadcast #define adb_cond_signal pthread_cond_signal #define adb_cond_destroy pthread_cond_destroy /* declare all mutexes */ #define ADB_MUTEX(x) extern adb_mutex_t x; #include "mutex_list.h" static __inline__ void close_on_exec(int fd) { fcntl( fd, F_SETFD, FD_CLOEXEC ); } static __inline__ int unix_open(const char* path, int options,...) { if ((options & O_CREAT) == 0) { return TEMP_FAILURE_RETRY( open(path, options) ); } else { int mode; va_list args; va_start( args, options ); mode = va_arg( args, int ); va_end( args ); return TEMP_FAILURE_RETRY( open( path, options, mode ) ); } } static __inline__ int adb_open_mode( const char* pathname, int options, int mode ) { return TEMP_FAILURE_RETRY( open( pathname, options, mode ) ); } static __inline__ int adb_open( const char* pathname, int options ) { int fd = TEMP_FAILURE_RETRY( open( pathname, options ) ); if (fd < 0) return -1; close_on_exec( fd ); return fd; } #undef open #define open ___xxx_open static __inline__ int adb_shutdown(int fd) { return shutdown(fd, SHUT_RDWR); } #undef shutdown #define shutdown ____xxx_shutdown static __inline__ int adb_close(int fd) { return close(fd); } #undef close #define close ____xxx_close static __inline__ int adb_read(int fd, void* buf, size_t len) { return TEMP_FAILURE_RETRY( read( fd, buf, len ) ); } #undef read #define read ___xxx_read static __inline__ int adb_write(int fd, const void* buf, size_t len) { return TEMP_FAILURE_RETRY( write( fd, buf, len ) ); } #undef write #define write ___xxx_write static __inline__ int adb_lseek(int fd, int pos, int where) { return lseek(fd, pos, where); } #undef lseek #define lseek ___xxx_lseek static __inline__ int adb_unlink(const char* path) { return unlink(path); } #undef unlink #define unlink ___xxx_unlink static __inline__ int adb_creat(const char* path, int mode) { int fd = TEMP_FAILURE_RETRY( creat( path, mode ) ); if ( fd < 0 ) return -1; close_on_exec(fd); return fd; } #undef creat #define creat ___xxx_creat static __inline__ int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen) { int fd; fd = TEMP_FAILURE_RETRY( accept( serverfd, addr, addrlen ) ); if (fd >= 0) close_on_exec(fd); return fd; } #undef accept #define accept ___xxx_accept #define unix_read adb_read #define unix_write adb_write #define unix_close adb_close typedef pthread_t adb_thread_t; typedef void* (*adb_thread_func_t)( void* arg ); static __inline__ int adb_thread_create( adb_thread_t *pthread, adb_thread_func_t start, void* arg ) { pthread_attr_t attr; pthread_attr_init (&attr); pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); return pthread_create( pthread, &attr, start, arg ); } static __inline__ int adb_socket_setbufsize( int fd, int bufsize ) { int opt = bufsize; return setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)); } static __inline__ void disable_tcp_nagle(int fd) { int on = 1; setsockopt( fd, IPPROTO_TCP, TCP_NODELAY, (void*)&on, sizeof(on) ); } static __inline__ int unix_socketpair( int d, int type, int protocol, int sv[2] ) { return socketpair( d, type, protocol, sv ); } static __inline__ int adb_socketpair( int sv[2] ) { int rc; rc = unix_socketpair( AF_UNIX, SOCK_STREAM, 0, sv ); if (rc < 0) return -1; close_on_exec( sv[0] ); close_on_exec( sv[1] ); return 0; } #undef socketpair #define socketpair ___xxx_socketpair static __inline__ void adb_sleep_ms( int mseconds ) { usleep( mseconds*1000 ); } static __inline__ int adb_mkdir(const char* path, int mode) { return mkdir(path, mode); } #undef mkdir #define mkdir ___xxx_mkdir static __inline__ void adb_sysdeps_init(void) { } static __inline__ char* adb_dirstart(const char* path) { return strchr(path, '/'); } static __inline__ char* adb_dirstop(const char* path) { return strrchr(path, '/'); } static __inline__ int adb_is_absolute_host_path( const char* path ) { return path[0] == '/'; } static __inline__ char* adb_strtok_r(char *str, const char *delim, char **saveptr) { return strtok_r(str, delim, saveptr); } #undef strtok_r #define strtok_r ___xxx_strtok_r #endif /* !_WIN32 */ #endif /* _ADB_SYSDEPS_H */ android-tools-5.1.1r36+git20160322/core/adb/sysdeps_win32.c000066400000000000000000001671371267427243200226140ustar00rootroot00000000000000#include "sysdeps.h" #include #include #include #include #include #define TRACE_TAG TRACE_SYSDEPS #include "adb.h" extern void fatal(const char *fmt, ...); #define assert(cond) do { if (!(cond)) fatal( "assertion failed '%s' on %s:%ld\n", #cond, __FILE__, __LINE__ ); } while (0) /**************************************************************************/ /**************************************************************************/ /***** *****/ /***** replaces libs/cutils/load_file.c *****/ /***** *****/ /**************************************************************************/ /**************************************************************************/ void *load_file(const char *fn, unsigned *_sz) { HANDLE file; char *data; DWORD file_size; file = CreateFile( fn, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL ); if (file == INVALID_HANDLE_VALUE) return NULL; file_size = GetFileSize( file, NULL ); data = NULL; if (file_size > 0) { data = (char*) malloc( file_size + 1 ); if (data == NULL) { D("load_file: could not allocate %ld bytes\n", file_size ); file_size = 0; } else { DWORD out_bytes; if ( !ReadFile( file, data, file_size, &out_bytes, NULL ) || out_bytes != file_size ) { D("load_file: could not read %ld bytes from '%s'\n", file_size, fn); free(data); data = NULL; file_size = 0; } } } CloseHandle( file ); *_sz = (unsigned) file_size; return data; } /**************************************************************************/ /**************************************************************************/ /***** *****/ /***** common file descriptor handling *****/ /***** *****/ /**************************************************************************/ /**************************************************************************/ typedef const struct FHClassRec_* FHClass; typedef struct FHRec_* FH; typedef struct EventHookRec_* EventHook; typedef struct FHClassRec_ { void (*_fh_init) ( FH f ); int (*_fh_close)( FH f ); int (*_fh_lseek)( FH f, int pos, int origin ); int (*_fh_read) ( FH f, void* buf, int len ); int (*_fh_write)( FH f, const void* buf, int len ); void (*_fh_hook) ( FH f, int events, EventHook hook ); } FHClassRec; /* used to emulate unix-domain socket pairs */ typedef struct SocketPairRec_* SocketPair; typedef struct FHRec_ { FHClass clazz; int used; int eof; union { HANDLE handle; SOCKET socket; SocketPair pair; } u; HANDLE event; int mask; char name[32]; } FHRec; #define fh_handle u.handle #define fh_socket u.socket #define fh_pair u.pair #define WIN32_FH_BASE 100 #define WIN32_MAX_FHS 128 static adb_mutex_t _win32_lock; static FHRec _win32_fhs[ WIN32_MAX_FHS ]; static int _win32_fh_count; static FH _fh_from_int( int fd ) { FH f; fd -= WIN32_FH_BASE; if (fd < 0 || fd >= _win32_fh_count) { D( "_fh_from_int: invalid fd %d\n", fd + WIN32_FH_BASE ); errno = EBADF; return NULL; } f = &_win32_fhs[fd]; if (f->used == 0) { D( "_fh_from_int: invalid fd %d\n", fd + WIN32_FH_BASE ); errno = EBADF; return NULL; } return f; } static int _fh_to_int( FH f ) { if (f && f->used && f >= _win32_fhs && f < _win32_fhs + WIN32_MAX_FHS) return (int)(f - _win32_fhs) + WIN32_FH_BASE; return -1; } static FH _fh_alloc( FHClass clazz ) { int nn; FH f = NULL; adb_mutex_lock( &_win32_lock ); if (_win32_fh_count < WIN32_MAX_FHS) { f = &_win32_fhs[ _win32_fh_count++ ]; goto Exit; } for (nn = 0; nn < WIN32_MAX_FHS; nn++) { if ( _win32_fhs[nn].clazz == NULL) { f = &_win32_fhs[nn]; goto Exit; } } D( "_fh_alloc: no more free file descriptors\n" ); Exit: if (f) { f->clazz = clazz; f->used = 1; f->eof = 0; clazz->_fh_init(f); } adb_mutex_unlock( &_win32_lock ); return f; } static int _fh_close( FH f ) { if ( f->used ) { f->clazz->_fh_close( f ); f->used = 0; f->eof = 0; f->clazz = NULL; } return 0; } /* forward definitions */ static const FHClassRec _fh_file_class; static const FHClassRec _fh_socket_class; /**************************************************************************/ /**************************************************************************/ /***** *****/ /***** file-based descriptor handling *****/ /***** *****/ /**************************************************************************/ /**************************************************************************/ static void _fh_file_init( FH f ) { f->fh_handle = INVALID_HANDLE_VALUE; } static int _fh_file_close( FH f ) { CloseHandle( f->fh_handle ); f->fh_handle = INVALID_HANDLE_VALUE; return 0; } static int _fh_file_read( FH f, void* buf, int len ) { DWORD read_bytes; if ( !ReadFile( f->fh_handle, buf, (DWORD)len, &read_bytes, NULL ) ) { D( "adb_read: could not read %d bytes from %s\n", len, f->name ); errno = EIO; return -1; } else if (read_bytes < (DWORD)len) { f->eof = 1; } return (int)read_bytes; } static int _fh_file_write( FH f, const void* buf, int len ) { DWORD wrote_bytes; if ( !WriteFile( f->fh_handle, buf, (DWORD)len, &wrote_bytes, NULL ) ) { D( "adb_file_write: could not write %d bytes from %s\n", len, f->name ); errno = EIO; return -1; } else if (wrote_bytes < (DWORD)len) { f->eof = 1; } return (int)wrote_bytes; } static int _fh_file_lseek( FH f, int pos, int origin ) { DWORD method; DWORD result; switch (origin) { case SEEK_SET: method = FILE_BEGIN; break; case SEEK_CUR: method = FILE_CURRENT; break; case SEEK_END: method = FILE_END; break; default: errno = EINVAL; return -1; } result = SetFilePointer( f->fh_handle, pos, NULL, method ); if (result == INVALID_SET_FILE_POINTER) { errno = EIO; return -1; } else { f->eof = 0; } return (int)result; } static void _fh_file_hook( FH f, int event, EventHook eventhook ); /* forward */ static const FHClassRec _fh_file_class = { _fh_file_init, _fh_file_close, _fh_file_lseek, _fh_file_read, _fh_file_write, _fh_file_hook }; /**************************************************************************/ /**************************************************************************/ /***** *****/ /***** file-based descriptor handling *****/ /***** *****/ /**************************************************************************/ /**************************************************************************/ int adb_open(const char* path, int options) { FH f; DWORD desiredAccess = 0; DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; switch (options) { case O_RDONLY: desiredAccess = GENERIC_READ; break; case O_WRONLY: desiredAccess = GENERIC_WRITE; break; case O_RDWR: desiredAccess = GENERIC_READ | GENERIC_WRITE; break; default: D("adb_open: invalid options (0x%0x)\n", options); errno = EINVAL; return -1; } f = _fh_alloc( &_fh_file_class ); if ( !f ) { errno = ENOMEM; return -1; } f->fh_handle = CreateFile( path, desiredAccess, shareMode, NULL, OPEN_EXISTING, 0, NULL ); if ( f->fh_handle == INVALID_HANDLE_VALUE ) { _fh_close(f); D( "adb_open: could not open '%s':", path ); switch (GetLastError()) { case ERROR_FILE_NOT_FOUND: D( "file not found\n" ); errno = ENOENT; return -1; case ERROR_PATH_NOT_FOUND: D( "path not found\n" ); errno = ENOTDIR; return -1; default: D( "unknown error\n" ); errno = ENOENT; return -1; } } snprintf( f->name, sizeof(f->name), "%d(%s)", _fh_to_int(f), path ); D( "adb_open: '%s' => fd %d\n", path, _fh_to_int(f) ); return _fh_to_int(f); } /* ignore mode on Win32 */ int adb_creat(const char* path, int mode) { FH f; f = _fh_alloc( &_fh_file_class ); if ( !f ) { errno = ENOMEM; return -1; } f->fh_handle = CreateFile( path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); if ( f->fh_handle == INVALID_HANDLE_VALUE ) { _fh_close(f); D( "adb_creat: could not open '%s':", path ); switch (GetLastError()) { case ERROR_FILE_NOT_FOUND: D( "file not found\n" ); errno = ENOENT; return -1; case ERROR_PATH_NOT_FOUND: D( "path not found\n" ); errno = ENOTDIR; return -1; default: D( "unknown error\n" ); errno = ENOENT; return -1; } } snprintf( f->name, sizeof(f->name), "%d(%s)", _fh_to_int(f), path ); D( "adb_creat: '%s' => fd %d\n", path, _fh_to_int(f) ); return _fh_to_int(f); } int adb_read(int fd, void* buf, int len) { FH f = _fh_from_int(fd); if (f == NULL) { return -1; } return f->clazz->_fh_read( f, buf, len ); } int adb_write(int fd, const void* buf, int len) { FH f = _fh_from_int(fd); if (f == NULL) { return -1; } return f->clazz->_fh_write(f, buf, len); } int adb_lseek(int fd, int pos, int where) { FH f = _fh_from_int(fd); if (!f) { return -1; } return f->clazz->_fh_lseek(f, pos, where); } int adb_shutdown(int fd) { FH f = _fh_from_int(fd); if (!f) { return -1; } D( "adb_shutdown: %s\n", f->name); shutdown( f->fh_socket, SD_BOTH ); return 0; } int adb_close(int fd) { FH f = _fh_from_int(fd); if (!f) { return -1; } D( "adb_close: %s\n", f->name); _fh_close(f); return 0; } /**************************************************************************/ /**************************************************************************/ /***** *****/ /***** socket-based file descriptors *****/ /***** *****/ /**************************************************************************/ /**************************************************************************/ static void _socket_set_errno( void ) { switch (WSAGetLastError()) { case 0: errno = 0; break; case WSAEWOULDBLOCK: errno = EAGAIN; break; case WSAEINTR: errno = EINTR; break; default: D( "_socket_set_errno: unhandled value %d\n", WSAGetLastError() ); errno = EINVAL; } } static void _fh_socket_init( FH f ) { f->fh_socket = INVALID_SOCKET; f->event = WSACreateEvent(); f->mask = 0; } static int _fh_socket_close( FH f ) { /* gently tell any peer that we're closing the socket */ shutdown( f->fh_socket, SD_BOTH ); closesocket( f->fh_socket ); f->fh_socket = INVALID_SOCKET; CloseHandle( f->event ); f->mask = 0; return 0; } static int _fh_socket_lseek( FH f, int pos, int origin ) { errno = EPIPE; return -1; } static int _fh_socket_read( FH f, void* buf, int len ) { int result = recv( f->fh_socket, buf, len, 0 ); if (result == SOCKET_ERROR) { _socket_set_errno(); result = -1; } return result; } static int _fh_socket_write( FH f, const void* buf, int len ) { int result = send( f->fh_socket, buf, len, 0 ); if (result == SOCKET_ERROR) { _socket_set_errno(); result = -1; } return result; } static void _fh_socket_hook( FH f, int event, EventHook hook ); /* forward */ static const FHClassRec _fh_socket_class = { _fh_socket_init, _fh_socket_close, _fh_socket_lseek, _fh_socket_read, _fh_socket_write, _fh_socket_hook }; /**************************************************************************/ /**************************************************************************/ /***** *****/ /***** replacement for libs/cutils/socket_xxxx.c *****/ /***** *****/ /**************************************************************************/ /**************************************************************************/ #include static int _winsock_init; static void _cleanup_winsock( void ) { WSACleanup(); } static void _init_winsock( void ) { if (!_winsock_init) { WSADATA wsaData; int rc = WSAStartup( MAKEWORD(2,2), &wsaData); if (rc != 0) { fatal( "adb: could not initialize Winsock\n" ); } atexit( _cleanup_winsock ); _winsock_init = 1; } } int socket_loopback_client(int port, int type) { FH f = _fh_alloc( &_fh_socket_class ); struct sockaddr_in addr; SOCKET s; if (!f) return -1; if (!_winsock_init) _init_winsock(); memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); s = socket(AF_INET, type, 0); if(s == INVALID_SOCKET) { D("socket_loopback_client: could not create socket\n" ); _fh_close(f); return -1; } f->fh_socket = s; if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { D("socket_loopback_client: could not connect to %s:%d\n", type != SOCK_STREAM ? "udp" : "tcp", port ); _fh_close(f); return -1; } snprintf( f->name, sizeof(f->name), "%d(lo-client:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port ); D( "socket_loopback_client: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) ); return _fh_to_int(f); } #define LISTEN_BACKLOG 4 int socket_loopback_server(int port, int type) { FH f = _fh_alloc( &_fh_socket_class ); struct sockaddr_in addr; SOCKET s; int n; if (!f) { return -1; } if (!_winsock_init) _init_winsock(); memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); s = socket(AF_INET, type, 0); if(s == INVALID_SOCKET) return -1; f->fh_socket = s; n = 1; setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*)&n, sizeof(n)); if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { _fh_close(f); return -1; } if (type == SOCK_STREAM) { int ret; ret = listen(s, LISTEN_BACKLOG); if (ret < 0) { _fh_close(f); return -1; } } snprintf( f->name, sizeof(f->name), "%d(lo-server:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port ); D( "socket_loopback_server: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) ); return _fh_to_int(f); } int socket_network_client(const char *host, int port, int type) { FH f = _fh_alloc( &_fh_socket_class ); struct hostent *hp; struct sockaddr_in addr; SOCKET s; if (!f) return -1; if (!_winsock_init) _init_winsock(); hp = gethostbyname(host); if(hp == 0) { _fh_close(f); return -1; } memset(&addr, 0, sizeof(addr)); addr.sin_family = hp->h_addrtype; addr.sin_port = htons(port); memcpy(&addr.sin_addr, hp->h_addr, hp->h_length); s = socket(hp->h_addrtype, type, 0); if(s == INVALID_SOCKET) { _fh_close(f); return -1; } f->fh_socket = s; if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { _fh_close(f); return -1; } snprintf( f->name, sizeof(f->name), "%d(net-client:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port ); D( "socket_network_client: host '%s' port %d type %s => fd %d\n", host, port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) ); return _fh_to_int(f); } int socket_network_client_timeout(const char *host, int port, int type, int timeout) { // TODO: implement timeouts for Windows. return socket_network_client(host, port, type); } int socket_inaddr_any_server(int port, int type) { FH f = _fh_alloc( &_fh_socket_class ); struct sockaddr_in addr; SOCKET s; int n; if (!f) return -1; if (!_winsock_init) _init_winsock(); memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = htonl(INADDR_ANY); s = socket(AF_INET, type, 0); if(s == INVALID_SOCKET) { _fh_close(f); return -1; } f->fh_socket = s; n = 1; setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*)&n, sizeof(n)); if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { _fh_close(f); return -1; } if (type == SOCK_STREAM) { int ret; ret = listen(s, LISTEN_BACKLOG); if (ret < 0) { _fh_close(f); return -1; } } snprintf( f->name, sizeof(f->name), "%d(any-server:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port ); D( "socket_inaddr_server: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) ); return _fh_to_int(f); } #undef accept int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen) { FH serverfh = _fh_from_int(serverfd); FH fh; if ( !serverfh || serverfh->clazz != &_fh_socket_class ) { D( "adb_socket_accept: invalid fd %d\n", serverfd ); return -1; } fh = _fh_alloc( &_fh_socket_class ); if (!fh) { D( "adb_socket_accept: not enough memory to allocate accepted socket descriptor\n" ); return -1; } fh->fh_socket = accept( serverfh->fh_socket, addr, addrlen ); if (fh->fh_socket == INVALID_SOCKET) { _fh_close( fh ); D( "adb_socket_accept: accept on fd %d return error %ld\n", serverfd, GetLastError() ); return -1; } snprintf( fh->name, sizeof(fh->name), "%d(accept:%s)", _fh_to_int(fh), serverfh->name ); D( "adb_socket_accept on fd %d returns fd %d\n", serverfd, _fh_to_int(fh) ); return _fh_to_int(fh); } void disable_tcp_nagle(int fd) { FH fh = _fh_from_int(fd); int on = 1; if ( !fh || fh->clazz != &_fh_socket_class ) return; setsockopt( fh->fh_socket, IPPROTO_TCP, TCP_NODELAY, (const char*)&on, sizeof(on) ); } /**************************************************************************/ /**************************************************************************/ /***** *****/ /***** emulated socketpairs *****/ /***** *****/ /**************************************************************************/ /**************************************************************************/ /* we implement socketpairs directly in use space for the following reasons: * - it avoids copying data from/to the Nt kernel * - it allows us to implement fdevent hooks easily and cheaply, something * that is not possible with standard Win32 pipes !! * * basically, we use two circular buffers, each one corresponding to a given * direction. * * each buffer is implemented as two regions: * * region A which is (a_start,a_end) * region B which is (0, b_end) with b_end <= a_start * * an empty buffer has: a_start = a_end = b_end = 0 * * a_start is the pointer where we start reading data * a_end is the pointer where we start writing data, unless it is BUFFER_SIZE, * then you start writing at b_end * * the buffer is full when b_end == a_start && a_end == BUFFER_SIZE * * there is room when b_end < a_start || a_end < BUFER_SIZE * * when reading, a_start is incremented, it a_start meets a_end, then * we do: a_start = 0, a_end = b_end, b_end = 0, and keep going on.. */ #define BIP_BUFFER_SIZE 4096 #if 0 #include # define BIPD(x) D x # define BIPDUMP bip_dump_hex static void bip_dump_hex( const unsigned char* ptr, size_t len ) { int nn, len2 = len; if (len2 > 8) len2 = 8; for (nn = 0; nn < len2; nn++) printf("%02x", ptr[nn]); printf(" "); for (nn = 0; nn < len2; nn++) { int c = ptr[nn]; if (c < 32 || c > 127) c = '.'; printf("%c", c); } printf("\n"); fflush(stdout); } #else # define BIPD(x) do {} while (0) # define BIPDUMP(p,l) BIPD(p) #endif typedef struct BipBufferRec_ { int a_start; int a_end; int b_end; int fdin; int fdout; int closed; int can_write; /* boolean */ HANDLE evt_write; /* event signaled when one can write to a buffer */ int can_read; /* boolean */ HANDLE evt_read; /* event signaled when one can read from a buffer */ CRITICAL_SECTION lock; unsigned char buff[ BIP_BUFFER_SIZE ]; } BipBufferRec, *BipBuffer; static void bip_buffer_init( BipBuffer buffer ) { D( "bit_buffer_init %p\n", buffer ); buffer->a_start = 0; buffer->a_end = 0; buffer->b_end = 0; buffer->can_write = 1; buffer->can_read = 0; buffer->fdin = 0; buffer->fdout = 0; buffer->closed = 0; buffer->evt_write = CreateEvent( NULL, TRUE, TRUE, NULL ); buffer->evt_read = CreateEvent( NULL, TRUE, FALSE, NULL ); InitializeCriticalSection( &buffer->lock ); } static void bip_buffer_close( BipBuffer bip ) { bip->closed = 1; if (!bip->can_read) { SetEvent( bip->evt_read ); } if (!bip->can_write) { SetEvent( bip->evt_write ); } } static void bip_buffer_done( BipBuffer bip ) { BIPD(( "bip_buffer_done: %d->%d\n", bip->fdin, bip->fdout )); CloseHandle( bip->evt_read ); CloseHandle( bip->evt_write ); DeleteCriticalSection( &bip->lock ); } static int bip_buffer_write( BipBuffer bip, const void* src, int len ) { int avail, count = 0; if (len <= 0) return 0; BIPD(( "bip_buffer_write: enter %d->%d len %d\n", bip->fdin, bip->fdout, len )); BIPDUMP( src, len ); EnterCriticalSection( &bip->lock ); while (!bip->can_write) { int ret; LeaveCriticalSection( &bip->lock ); if (bip->closed) { errno = EPIPE; return -1; } /* spinlocking here is probably unfair, but let's live with it */ ret = WaitForSingleObject( bip->evt_write, INFINITE ); if (ret != WAIT_OBJECT_0) { /* buffer probably closed */ D( "bip_buffer_write: error %d->%d WaitForSingleObject returned %d, error %ld\n", bip->fdin, bip->fdout, ret, GetLastError() ); return 0; } if (bip->closed) { errno = EPIPE; return -1; } EnterCriticalSection( &bip->lock ); } BIPD(( "bip_buffer_write: exec %d->%d len %d\n", bip->fdin, bip->fdout, len )); avail = BIP_BUFFER_SIZE - bip->a_end; if (avail > 0) { /* we can append to region A */ if (avail > len) avail = len; memcpy( bip->buff + bip->a_end, src, avail ); src = (const char *)src + avail; count += avail; len -= avail; bip->a_end += avail; if (bip->a_end == BIP_BUFFER_SIZE && bip->a_start == 0) { bip->can_write = 0; ResetEvent( bip->evt_write ); goto Exit; } } if (len == 0) goto Exit; avail = bip->a_start - bip->b_end; assert( avail > 0 ); /* since can_write is TRUE */ if (avail > len) avail = len; memcpy( bip->buff + bip->b_end, src, avail ); count += avail; bip->b_end += avail; if (bip->b_end == bip->a_start) { bip->can_write = 0; ResetEvent( bip->evt_write ); } Exit: assert( count > 0 ); if ( !bip->can_read ) { bip->can_read = 1; SetEvent( bip->evt_read ); } BIPD(( "bip_buffer_write: exit %d->%d count %d (as=%d ae=%d be=%d cw=%d cr=%d\n", bip->fdin, bip->fdout, count, bip->a_start, bip->a_end, bip->b_end, bip->can_write, bip->can_read )); LeaveCriticalSection( &bip->lock ); return count; } static int bip_buffer_read( BipBuffer bip, void* dst, int len ) { int avail, count = 0; if (len <= 0) return 0; BIPD(( "bip_buffer_read: enter %d->%d len %d\n", bip->fdin, bip->fdout, len )); EnterCriticalSection( &bip->lock ); while ( !bip->can_read ) { #if 0 LeaveCriticalSection( &bip->lock ); errno = EAGAIN; return -1; #else int ret; LeaveCriticalSection( &bip->lock ); if (bip->closed) { errno = EPIPE; return -1; } ret = WaitForSingleObject( bip->evt_read, INFINITE ); if (ret != WAIT_OBJECT_0) { /* probably closed buffer */ D( "bip_buffer_read: error %d->%d WaitForSingleObject returned %d, error %ld\n", bip->fdin, bip->fdout, ret, GetLastError()); return 0; } if (bip->closed) { errno = EPIPE; return -1; } EnterCriticalSection( &bip->lock ); #endif } BIPD(( "bip_buffer_read: exec %d->%d len %d\n", bip->fdin, bip->fdout, len )); avail = bip->a_end - bip->a_start; assert( avail > 0 ); /* since can_read is TRUE */ if (avail > len) avail = len; memcpy( dst, bip->buff + bip->a_start, avail ); dst = (char *)dst + avail; count += avail; len -= avail; bip->a_start += avail; if (bip->a_start < bip->a_end) goto Exit; bip->a_start = 0; bip->a_end = bip->b_end; bip->b_end = 0; avail = bip->a_end; if (avail > 0) { if (avail > len) avail = len; memcpy( dst, bip->buff, avail ); count += avail; bip->a_start += avail; if ( bip->a_start < bip->a_end ) goto Exit; bip->a_start = bip->a_end = 0; } bip->can_read = 0; ResetEvent( bip->evt_read ); Exit: assert( count > 0 ); if (!bip->can_write ) { bip->can_write = 1; SetEvent( bip->evt_write ); } BIPDUMP( (const unsigned char*)dst - count, count ); BIPD(( "bip_buffer_read: exit %d->%d count %d (as=%d ae=%d be=%d cw=%d cr=%d\n", bip->fdin, bip->fdout, count, bip->a_start, bip->a_end, bip->b_end, bip->can_write, bip->can_read )); LeaveCriticalSection( &bip->lock ); return count; } typedef struct SocketPairRec_ { BipBufferRec a2b_bip; BipBufferRec b2a_bip; FH a_fd; int used; } SocketPairRec; void _fh_socketpair_init( FH f ) { f->fh_pair = NULL; } static int _fh_socketpair_close( FH f ) { if ( f->fh_pair ) { SocketPair pair = f->fh_pair; if ( f == pair->a_fd ) { pair->a_fd = NULL; } bip_buffer_close( &pair->b2a_bip ); bip_buffer_close( &pair->a2b_bip ); if ( --pair->used == 0 ) { bip_buffer_done( &pair->b2a_bip ); bip_buffer_done( &pair->a2b_bip ); free( pair ); } f->fh_pair = NULL; } return 0; } static int _fh_socketpair_lseek( FH f, int pos, int origin ) { errno = ESPIPE; return -1; } static int _fh_socketpair_read( FH f, void* buf, int len ) { SocketPair pair = f->fh_pair; BipBuffer bip; if (!pair) return -1; if ( f == pair->a_fd ) bip = &pair->b2a_bip; else bip = &pair->a2b_bip; return bip_buffer_read( bip, buf, len ); } static int _fh_socketpair_write( FH f, const void* buf, int len ) { SocketPair pair = f->fh_pair; BipBuffer bip; if (!pair) return -1; if ( f == pair->a_fd ) bip = &pair->a2b_bip; else bip = &pair->b2a_bip; return bip_buffer_write( bip, buf, len ); } static void _fh_socketpair_hook( FH f, int event, EventHook hook ); /* forward */ static const FHClassRec _fh_socketpair_class = { _fh_socketpair_init, _fh_socketpair_close, _fh_socketpair_lseek, _fh_socketpair_read, _fh_socketpair_write, _fh_socketpair_hook }; int adb_socketpair( int sv[2] ) { FH fa, fb; SocketPair pair; fa = _fh_alloc( &_fh_socketpair_class ); fb = _fh_alloc( &_fh_socketpair_class ); if (!fa || !fb) goto Fail; pair = malloc( sizeof(*pair) ); if (pair == NULL) { D("adb_socketpair: not enough memory to allocate pipes\n" ); goto Fail; } bip_buffer_init( &pair->a2b_bip ); bip_buffer_init( &pair->b2a_bip ); fa->fh_pair = pair; fb->fh_pair = pair; pair->used = 2; pair->a_fd = fa; sv[0] = _fh_to_int(fa); sv[1] = _fh_to_int(fb); pair->a2b_bip.fdin = sv[0]; pair->a2b_bip.fdout = sv[1]; pair->b2a_bip.fdin = sv[1]; pair->b2a_bip.fdout = sv[0]; snprintf( fa->name, sizeof(fa->name), "%d(pair:%d)", sv[0], sv[1] ); snprintf( fb->name, sizeof(fb->name), "%d(pair:%d)", sv[1], sv[0] ); D( "adb_socketpair: returns (%d, %d)\n", sv[0], sv[1] ); return 0; Fail: _fh_close(fb); _fh_close(fa); return -1; } /**************************************************************************/ /**************************************************************************/ /***** *****/ /***** fdevents emulation *****/ /***** *****/ /***** this is a very simple implementation, we rely on the fact *****/ /***** that ADB doesn't use FDE_ERROR. *****/ /***** *****/ /**************************************************************************/ /**************************************************************************/ #define FATAL(x...) fatal(__FUNCTION__, x) #if DEBUG static void dump_fde(fdevent *fde, const char *info) { fprintf(stderr,"FDE #%03d %c%c%c %s\n", fde->fd, fde->state & FDE_READ ? 'R' : ' ', fde->state & FDE_WRITE ? 'W' : ' ', fde->state & FDE_ERROR ? 'E' : ' ', info); } #else #define dump_fde(fde, info) do { } while(0) #endif #define FDE_EVENTMASK 0x00ff #define FDE_STATEMASK 0xff00 #define FDE_ACTIVE 0x0100 #define FDE_PENDING 0x0200 #define FDE_CREATED 0x0400 static void fdevent_plist_enqueue(fdevent *node); static void fdevent_plist_remove(fdevent *node); static fdevent *fdevent_plist_dequeue(void); static fdevent list_pending = { .next = &list_pending, .prev = &list_pending, }; static fdevent **fd_table = 0; static int fd_table_max = 0; typedef struct EventLooperRec_* EventLooper; typedef struct EventHookRec_ { EventHook next; FH fh; HANDLE h; int wanted; /* wanted event flags */ int ready; /* ready event flags */ void* aux; void (*prepare)( EventHook hook ); int (*start) ( EventHook hook ); void (*stop) ( EventHook hook ); int (*check) ( EventHook hook ); int (*peek) ( EventHook hook ); } EventHookRec; static EventHook _free_hooks; static EventHook event_hook_alloc( FH fh ) { EventHook hook = _free_hooks; if (hook != NULL) _free_hooks = hook->next; else { hook = malloc( sizeof(*hook) ); if (hook == NULL) fatal( "could not allocate event hook\n" ); } hook->next = NULL; hook->fh = fh; hook->wanted = 0; hook->ready = 0; hook->h = INVALID_HANDLE_VALUE; hook->aux = NULL; hook->prepare = NULL; hook->start = NULL; hook->stop = NULL; hook->check = NULL; hook->peek = NULL; return hook; } static void event_hook_free( EventHook hook ) { hook->fh = NULL; hook->wanted = 0; hook->ready = 0; hook->next = _free_hooks; _free_hooks = hook; } static void event_hook_signal( EventHook hook ) { FH f = hook->fh; int fd = _fh_to_int(f); fdevent* fde = fd_table[ fd - WIN32_FH_BASE ]; if (fde != NULL && fde->fd == fd) { if ((fde->state & FDE_PENDING) == 0) { fde->state |= FDE_PENDING; fdevent_plist_enqueue( fde ); } fde->events |= hook->wanted; } } #define MAX_LOOPER_HANDLES WIN32_MAX_FHS typedef struct EventLooperRec_ { EventHook hooks; HANDLE htab[ MAX_LOOPER_HANDLES ]; int htab_count; } EventLooperRec; static EventHook* event_looper_find_p( EventLooper looper, FH fh ) { EventHook *pnode = &looper->hooks; EventHook node = *pnode; for (;;) { if ( node == NULL || node->fh == fh ) break; pnode = &node->next; node = *pnode; } return pnode; } static void event_looper_hook( EventLooper looper, int fd, int events ) { FH f = _fh_from_int(fd); EventHook *pnode; EventHook node; if (f == NULL) /* invalid arg */ { D("event_looper_hook: invalid fd=%d\n", fd); return; } pnode = event_looper_find_p( looper, f ); node = *pnode; if ( node == NULL ) { node = event_hook_alloc( f ); node->next = *pnode; *pnode = node; } if ( (node->wanted & events) != events ) { /* this should update start/stop/check/peek */ D("event_looper_hook: call hook for %d (new=%x, old=%x)\n", fd, node->wanted, events); f->clazz->_fh_hook( f, events & ~node->wanted, node ); node->wanted |= events; } else { D("event_looper_hook: ignoring events %x for %d wanted=%x)\n", events, fd, node->wanted); } } static void event_looper_unhook( EventLooper looper, int fd, int events ) { FH fh = _fh_from_int(fd); EventHook *pnode = event_looper_find_p( looper, fh ); EventHook node = *pnode; if (node != NULL) { int events2 = events & node->wanted; if ( events2 == 0 ) { D( "event_looper_unhook: events %x not registered for fd %d\n", events, fd ); return; } node->wanted &= ~events2; if (!node->wanted) { *pnode = node->next; event_hook_free( node ); } } } /* * A fixer for WaitForMultipleObjects on condition that there are more than 64 * handles to wait on. * * In cetain cases DDMS may establish more than 64 connections with ADB. For * instance, this may happen if there are more than 64 processes running on a * device, or there are multiple devices connected (including the emulator) with * the combined number of running processes greater than 64. In this case using * WaitForMultipleObjects to wait on connection events simply wouldn't cut, * because of the API limitations (64 handles max). So, we need to provide a way * to scale WaitForMultipleObjects to accept an arbitrary number of handles. The * easiest (and "Microsoft recommended") way to do that would be dividing the * handle array into chunks with the chunk size less than 64, and fire up as many * waiting threads as there are chunks. Then each thread would wait on a chunk of * handles, and will report back to the caller which handle has been set. * Here is the implementation of that algorithm. */ /* Number of handles to wait on in each wating thread. */ #define WAIT_ALL_CHUNK_SIZE 63 /* Descriptor for a wating thread */ typedef struct WaitForAllParam { /* A handle to an event to signal when waiting is over. This handle is shared * accross all the waiting threads, so each waiting thread knows when any * other thread has exited, so it can exit too. */ HANDLE main_event; /* Upon exit from a waiting thread contains the index of the handle that has * been signaled. The index is an absolute index of the signaled handle in * the original array. This pointer is shared accross all the waiting threads * and it's not guaranteed (due to a race condition) that when all the * waiting threads exit, the value contained here would indicate the first * handle that was signaled. This is fine, because the caller cares only * about any handle being signaled. It doesn't care about the order, nor * about the whole list of handles that were signaled. */ LONG volatile *signaled_index; /* Array of handles to wait on in a waiting thread. */ HANDLE* handles; /* Number of handles in 'handles' array to wait on. */ int handles_count; /* Index inside the main array of the first handle in the 'handles' array. */ int first_handle_index; /* Waiting thread handle. */ HANDLE thread; } WaitForAllParam; /* Waiting thread routine. */ static unsigned __stdcall _in_waiter_thread(void* arg) { HANDLE wait_on[WAIT_ALL_CHUNK_SIZE + 1]; int res; WaitForAllParam* const param = (WaitForAllParam*)arg; /* We have to wait on the main_event in order to be notified when any of the * sibling threads is exiting. */ wait_on[0] = param->main_event; /* The rest of the handles go behind the main event handle. */ memcpy(wait_on + 1, param->handles, param->handles_count * sizeof(HANDLE)); res = WaitForMultipleObjects(param->handles_count + 1, wait_on, FALSE, INFINITE); if (res > 0 && res < (param->handles_count + 1)) { /* One of the original handles got signaled. Save its absolute index into * the output variable. */ InterlockedCompareExchange(param->signaled_index, res - 1L + param->first_handle_index, -1L); } /* Notify the caller (and the siblings) that the wait is over. */ SetEvent(param->main_event); _endthreadex(0); return 0; } /* WaitForMultipeObjects fixer routine. * Param: * handles Array of handles to wait on. * handles_count Number of handles in the array. * Return: * (>= 0 && < handles_count) - Index of the signaled handle in the array, or * WAIT_FAILED on an error. */ static int _wait_for_all(HANDLE* handles, int handles_count) { WaitForAllParam* threads; HANDLE main_event; int chunks, chunk, remains; /* This variable is going to be accessed by several threads at the same time, * this is bound to fail randomly when the core is run on multi-core machines. * To solve this, we need to do the following (1 _and_ 2): * 1. Use the "volatile" qualifier to ensure the compiler doesn't optimize * out the reads/writes in this function unexpectedly. * 2. Ensure correct memory ordering. The "simple" way to do that is to wrap * all accesses inside a critical section. But we can also use * InterlockedCompareExchange() which always provide a full memory barrier * on Win32. */ volatile LONG sig_index = -1; /* Calculate number of chunks, and allocate thread param array. */ chunks = handles_count / WAIT_ALL_CHUNK_SIZE; remains = handles_count % WAIT_ALL_CHUNK_SIZE; threads = (WaitForAllParam*)malloc((chunks + (remains ? 1 : 0)) * sizeof(WaitForAllParam)); if (threads == NULL) { D("Unable to allocate thread array for %d handles.", handles_count); return (int)WAIT_FAILED; } /* Create main event to wait on for all waiting threads. This is a "manualy * reset" event that will remain set once it was set. */ main_event = CreateEvent(NULL, TRUE, FALSE, NULL); if (main_event == NULL) { D("Unable to create main event. Error: %d", (int)GetLastError()); free(threads); return (int)WAIT_FAILED; } /* * Initialize waiting thread parameters. */ for (chunk = 0; chunk < chunks; chunk++) { threads[chunk].main_event = main_event; threads[chunk].signaled_index = &sig_index; threads[chunk].first_handle_index = WAIT_ALL_CHUNK_SIZE * chunk; threads[chunk].handles = handles + threads[chunk].first_handle_index; threads[chunk].handles_count = WAIT_ALL_CHUNK_SIZE; } if (remains) { threads[chunk].main_event = main_event; threads[chunk].signaled_index = &sig_index; threads[chunk].first_handle_index = WAIT_ALL_CHUNK_SIZE * chunk; threads[chunk].handles = handles + threads[chunk].first_handle_index; threads[chunk].handles_count = remains; chunks++; } /* Start the waiting threads. */ for (chunk = 0; chunk < chunks; chunk++) { /* Note that using adb_thread_create is not appropriate here, since we * need a handle to wait on for thread termination. */ threads[chunk].thread = (HANDLE)_beginthreadex(NULL, 0, _in_waiter_thread, &threads[chunk], 0, NULL); if (threads[chunk].thread == NULL) { /* Unable to create a waiter thread. Collapse. */ D("Unable to create a waiting thread %d of %d. errno=%d", chunk, chunks, errno); chunks = chunk; SetEvent(main_event); break; } } /* Wait on any of the threads to get signaled. */ WaitForSingleObject(main_event, INFINITE); /* Wait on all the waiting threads to exit. */ for (chunk = 0; chunk < chunks; chunk++) { WaitForSingleObject(threads[chunk].thread, INFINITE); CloseHandle(threads[chunk].thread); } CloseHandle(main_event); free(threads); const int ret = (int)InterlockedCompareExchange(&sig_index, -1, -1); return (ret >= 0) ? ret : (int)WAIT_FAILED; } static EventLooperRec win32_looper; static void fdevent_init(void) { win32_looper.htab_count = 0; win32_looper.hooks = NULL; } static void fdevent_connect(fdevent *fde) { EventLooper looper = &win32_looper; int events = fde->state & FDE_EVENTMASK; if (events != 0) event_looper_hook( looper, fde->fd, events ); } static void fdevent_disconnect(fdevent *fde) { EventLooper looper = &win32_looper; int events = fde->state & FDE_EVENTMASK; if (events != 0) event_looper_unhook( looper, fde->fd, events ); } static void fdevent_update(fdevent *fde, unsigned events) { EventLooper looper = &win32_looper; unsigned events0 = fde->state & FDE_EVENTMASK; if (events != events0) { int removes = events0 & ~events; int adds = events & ~events0; if (removes) { D("fdevent_update: remove %x from %d\n", removes, fde->fd); event_looper_unhook( looper, fde->fd, removes ); } if (adds) { D("fdevent_update: add %x to %d\n", adds, fde->fd); event_looper_hook ( looper, fde->fd, adds ); } } } static void fdevent_process() { EventLooper looper = &win32_looper; EventHook hook; int gotone = 0; /* if we have at least one ready hook, execute it/them */ for (hook = looper->hooks; hook; hook = hook->next) { hook->ready = 0; if (hook->prepare) { hook->prepare(hook); if (hook->ready != 0) { event_hook_signal( hook ); gotone = 1; } } } /* nothing's ready yet, so wait for something to happen */ if (!gotone) { looper->htab_count = 0; for (hook = looper->hooks; hook; hook = hook->next) { if (hook->start && !hook->start(hook)) { D( "fdevent_process: error when starting a hook\n" ); return; } if (hook->h != INVALID_HANDLE_VALUE) { int nn; for (nn = 0; nn < looper->htab_count; nn++) { if ( looper->htab[nn] == hook->h ) goto DontAdd; } looper->htab[ looper->htab_count++ ] = hook->h; DontAdd: ; } } if (looper->htab_count == 0) { D( "fdevent_process: nothing to wait for !!\n" ); return; } do { int wait_ret; D( "adb_win32: waiting for %d events\n", looper->htab_count ); if (looper->htab_count > MAXIMUM_WAIT_OBJECTS) { D("handle count %d exceeds MAXIMUM_WAIT_OBJECTS.\n", looper->htab_count); wait_ret = _wait_for_all(looper->htab, looper->htab_count); } else { wait_ret = WaitForMultipleObjects( looper->htab_count, looper->htab, FALSE, INFINITE ); } if (wait_ret == (int)WAIT_FAILED) { D( "adb_win32: wait failed, error %ld\n", GetLastError() ); } else { D( "adb_win32: got one (index %d)\n", wait_ret ); /* according to Cygwin, some objects like consoles wake up on "inappropriate" events * like mouse movements. we need to filter these with the "check" function */ if ((unsigned)wait_ret < (unsigned)looper->htab_count) { for (hook = looper->hooks; hook; hook = hook->next) { if ( looper->htab[wait_ret] == hook->h && (!hook->check || hook->check(hook)) ) { D( "adb_win32: signaling %s for %x\n", hook->fh->name, hook->ready ); event_hook_signal( hook ); gotone = 1; break; } } } } } while (!gotone); for (hook = looper->hooks; hook; hook = hook->next) { if (hook->stop) hook->stop( hook ); } } for (hook = looper->hooks; hook; hook = hook->next) { if (hook->peek && hook->peek(hook)) event_hook_signal( hook ); } } static void fdevent_register(fdevent *fde) { int fd = fde->fd - WIN32_FH_BASE; if(fd < 0) { FATAL("bogus negative fd (%d)\n", fde->fd); } if(fd >= fd_table_max) { int oldmax = fd_table_max; if(fde->fd > 32000) { FATAL("bogus huuuuge fd (%d)\n", fde->fd); } if(fd_table_max == 0) { fdevent_init(); fd_table_max = 256; } while(fd_table_max <= fd) { fd_table_max *= 2; } fd_table = realloc(fd_table, sizeof(fdevent*) * fd_table_max); if(fd_table == 0) { FATAL("could not expand fd_table to %d entries\n", fd_table_max); } memset(fd_table + oldmax, 0, sizeof(int) * (fd_table_max - oldmax)); } fd_table[fd] = fde; } static void fdevent_unregister(fdevent *fde) { int fd = fde->fd - WIN32_FH_BASE; if((fd < 0) || (fd >= fd_table_max)) { FATAL("fd out of range (%d)\n", fde->fd); } if(fd_table[fd] != fde) { FATAL("fd_table out of sync"); } fd_table[fd] = 0; if(!(fde->state & FDE_DONT_CLOSE)) { dump_fde(fde, "close"); adb_close(fde->fd); } } static void fdevent_plist_enqueue(fdevent *node) { fdevent *list = &list_pending; node->next = list; node->prev = list->prev; node->prev->next = node; list->prev = node; } static void fdevent_plist_remove(fdevent *node) { node->prev->next = node->next; node->next->prev = node->prev; node->next = 0; node->prev = 0; } static fdevent *fdevent_plist_dequeue(void) { fdevent *list = &list_pending; fdevent *node = list->next; if(node == list) return 0; list->next = node->next; list->next->prev = list; node->next = 0; node->prev = 0; return node; } fdevent *fdevent_create(int fd, fd_func func, void *arg) { fdevent *fde = (fdevent*) malloc(sizeof(fdevent)); if(fde == 0) return 0; fdevent_install(fde, fd, func, arg); fde->state |= FDE_CREATED; return fde; } void fdevent_destroy(fdevent *fde) { if(fde == 0) return; if(!(fde->state & FDE_CREATED)) { FATAL("fde %p not created by fdevent_create()\n", fde); } fdevent_remove(fde); } void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg) { memset(fde, 0, sizeof(fdevent)); fde->state = FDE_ACTIVE; fde->fd = fd; fde->func = func; fde->arg = arg; fdevent_register(fde); dump_fde(fde, "connect"); fdevent_connect(fde); fde->state |= FDE_ACTIVE; } void fdevent_remove(fdevent *fde) { if(fde->state & FDE_PENDING) { fdevent_plist_remove(fde); } if(fde->state & FDE_ACTIVE) { fdevent_disconnect(fde); dump_fde(fde, "disconnect"); fdevent_unregister(fde); } fde->state = 0; fde->events = 0; } void fdevent_set(fdevent *fde, unsigned events) { events &= FDE_EVENTMASK; if((fde->state & FDE_EVENTMASK) == (int)events) return; if(fde->state & FDE_ACTIVE) { fdevent_update(fde, events); dump_fde(fde, "update"); } fde->state = (fde->state & FDE_STATEMASK) | events; if(fde->state & FDE_PENDING) { /* if we're pending, make sure ** we don't signal an event that ** is no longer wanted. */ fde->events &= (~events); if(fde->events == 0) { fdevent_plist_remove(fde); fde->state &= (~FDE_PENDING); } } } void fdevent_add(fdevent *fde, unsigned events) { fdevent_set( fde, (fde->state & FDE_EVENTMASK) | (events & FDE_EVENTMASK)); } void fdevent_del(fdevent *fde, unsigned events) { fdevent_set( fde, (fde->state & FDE_EVENTMASK) & (~(events & FDE_EVENTMASK))); } void fdevent_loop() { fdevent *fde; for(;;) { #if DEBUG fprintf(stderr,"--- ---- waiting for events\n"); #endif fdevent_process(); while((fde = fdevent_plist_dequeue())) { unsigned events = fde->events; fde->events = 0; fde->state &= (~FDE_PENDING); dump_fde(fde, "callback"); fde->func(fde->fd, events, fde->arg); } } } /** FILE EVENT HOOKS **/ static void _event_file_prepare( EventHook hook ) { if (hook->wanted & (FDE_READ|FDE_WRITE)) { /* we can always read/write */ hook->ready |= hook->wanted & (FDE_READ|FDE_WRITE); } } static int _event_file_peek( EventHook hook ) { return (hook->wanted & (FDE_READ|FDE_WRITE)); } static void _fh_file_hook( FH f, int events, EventHook hook ) { hook->h = f->fh_handle; hook->prepare = _event_file_prepare; hook->peek = _event_file_peek; } /** SOCKET EVENT HOOKS **/ static void _event_socket_verify( EventHook hook, WSANETWORKEVENTS* evts ) { if ( evts->lNetworkEvents & (FD_READ|FD_ACCEPT|FD_CLOSE) ) { if (hook->wanted & FDE_READ) hook->ready |= FDE_READ; if ((evts->iErrorCode[FD_READ] != 0) && hook->wanted & FDE_ERROR) hook->ready |= FDE_ERROR; } if ( evts->lNetworkEvents & (FD_WRITE|FD_CONNECT|FD_CLOSE) ) { if (hook->wanted & FDE_WRITE) hook->ready |= FDE_WRITE; if ((evts->iErrorCode[FD_WRITE] != 0) && hook->wanted & FDE_ERROR) hook->ready |= FDE_ERROR; } if ( evts->lNetworkEvents & FD_OOB ) { if (hook->wanted & FDE_ERROR) hook->ready |= FDE_ERROR; } } static void _event_socket_prepare( EventHook hook ) { WSANETWORKEVENTS evts; /* look if some of the events we want already happened ? */ if (!WSAEnumNetworkEvents( hook->fh->fh_socket, NULL, &evts )) _event_socket_verify( hook, &evts ); } static int _socket_wanted_to_flags( int wanted ) { int flags = 0; if (wanted & FDE_READ) flags |= FD_READ | FD_ACCEPT | FD_CLOSE; if (wanted & FDE_WRITE) flags |= FD_WRITE | FD_CONNECT | FD_CLOSE; if (wanted & FDE_ERROR) flags |= FD_OOB; return flags; } static int _event_socket_start( EventHook hook ) { /* create an event which we're going to wait for */ FH fh = hook->fh; long flags = _socket_wanted_to_flags( hook->wanted ); hook->h = fh->event; if (hook->h == INVALID_HANDLE_VALUE) { D( "_event_socket_start: no event for %s\n", fh->name ); return 0; } if ( flags != fh->mask ) { D( "_event_socket_start: hooking %s for %x (flags %ld)\n", hook->fh->name, hook->wanted, flags ); if ( WSAEventSelect( fh->fh_socket, hook->h, flags ) ) { D( "_event_socket_start: WSAEventSelect() for %s failed, error %d\n", hook->fh->name, WSAGetLastError() ); CloseHandle( hook->h ); hook->h = INVALID_HANDLE_VALUE; exit(1); return 0; } fh->mask = flags; } return 1; } static void _event_socket_stop( EventHook hook ) { hook->h = INVALID_HANDLE_VALUE; } static int _event_socket_check( EventHook hook ) { int result = 0; FH fh = hook->fh; WSANETWORKEVENTS evts; if (!WSAEnumNetworkEvents( fh->fh_socket, hook->h, &evts ) ) { _event_socket_verify( hook, &evts ); result = (hook->ready != 0); if (result) { ResetEvent( hook->h ); } } D( "_event_socket_check %s returns %d\n", fh->name, result ); return result; } static int _event_socket_peek( EventHook hook ) { WSANETWORKEVENTS evts; FH fh = hook->fh; /* look if some of the events we want already happened ? */ if (!WSAEnumNetworkEvents( fh->fh_socket, NULL, &evts )) { _event_socket_verify( hook, &evts ); if (hook->ready) ResetEvent( hook->h ); } return hook->ready != 0; } static void _fh_socket_hook( FH f, int events, EventHook hook ) { hook->prepare = _event_socket_prepare; hook->start = _event_socket_start; hook->stop = _event_socket_stop; hook->check = _event_socket_check; hook->peek = _event_socket_peek; _event_socket_start( hook ); } /** SOCKETPAIR EVENT HOOKS **/ static void _event_socketpair_prepare( EventHook hook ) { FH fh = hook->fh; SocketPair pair = fh->fh_pair; BipBuffer rbip = (pair->a_fd == fh) ? &pair->b2a_bip : &pair->a2b_bip; BipBuffer wbip = (pair->a_fd == fh) ? &pair->a2b_bip : &pair->b2a_bip; if (hook->wanted & FDE_READ && rbip->can_read) hook->ready |= FDE_READ; if (hook->wanted & FDE_WRITE && wbip->can_write) hook->ready |= FDE_WRITE; } static int _event_socketpair_start( EventHook hook ) { FH fh = hook->fh; SocketPair pair = fh->fh_pair; BipBuffer rbip = (pair->a_fd == fh) ? &pair->b2a_bip : &pair->a2b_bip; BipBuffer wbip = (pair->a_fd == fh) ? &pair->a2b_bip : &pair->b2a_bip; if (hook->wanted == FDE_READ) hook->h = rbip->evt_read; else if (hook->wanted == FDE_WRITE) hook->h = wbip->evt_write; else { D("_event_socketpair_start: can't handle FDE_READ+FDE_WRITE\n" ); return 0; } D( "_event_socketpair_start: hook %s for %x wanted=%x\n", hook->fh->name, _fh_to_int(fh), hook->wanted); return 1; } static int _event_socketpair_peek( EventHook hook ) { _event_socketpair_prepare( hook ); return hook->ready != 0; } static void _fh_socketpair_hook( FH fh, int events, EventHook hook ) { hook->prepare = _event_socketpair_prepare; hook->start = _event_socketpair_start; hook->peek = _event_socketpair_peek; } void adb_sysdeps_init( void ) { #define ADB_MUTEX(x) InitializeCriticalSection( & x ); #include "mutex_list.h" InitializeCriticalSection( &_win32_lock ); } /* Windows doesn't have strtok_r. Use the one from bionic. */ /* * Copyright (c) 1988 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ char * adb_strtok_r(char *s, const char *delim, char **last) { char *spanp; int c, sc; char *tok; if (s == NULL && (s = *last) == NULL) return (NULL); /* * Skip (span) leading delimiters (s += strspn(s, delim), sort of). */ cont: c = *s++; for (spanp = (char *)delim; (sc = *spanp++) != 0;) { if (c == sc) goto cont; } if (c == 0) { /* no non-delimiter characters */ *last = NULL; return (NULL); } tok = s - 1; /* * Scan token (scan for delimiters: s += strcspn(s, delim), sort of). * Note that delim must have one NUL; we stop if we see that, too. */ for (;;) { c = *s++; spanp = (char *)delim; do { if ((sc = *spanp++) == c) { if (c == 0) s = NULL; else s[-1] = 0; *last = s; return (tok); } } while (sc != 0); } /* NOTREACHED */ } android-tools-5.1.1r36+git20160322/core/adb/test_track_devices.c000066400000000000000000000045771267427243200237430ustar00rootroot00000000000000/* a simple test program, connects to ADB server, and opens a track-devices session */ #include #include #include #include #include #include static void panic( const char* msg ) { fprintf(stderr, "PANIC: %s: %s\n", msg, strerror(errno)); exit(1); } static int unix_write( int fd, const char* buf, int len ) { int result = 0; while (len > 0) { int len2 = write(fd, buf, len); if (len2 < 0) { if (errno == EINTR || errno == EAGAIN) continue; return -1; } result += len2; len -= len2; buf += len2; } return result; } static int unix_read( int fd, char* buf, int len ) { int result = 0; while (len > 0) { int len2 = read(fd, buf, len); if (len2 < 0) { if (errno == EINTR || errno == EAGAIN) continue; return -1; } result += len2; len -= len2; buf += len2; } return result; } int main( void ) { int ret, s; struct sockaddr_in server; char buffer[1024]; const char* request = "host:track-devices"; int len; memset( &server, 0, sizeof(server) ); server.sin_family = AF_INET; server.sin_port = htons(5037); server.sin_addr.s_addr = htonl(INADDR_LOOPBACK); s = socket( PF_INET, SOCK_STREAM, 0 ); ret = connect( s, (struct sockaddr*) &server, sizeof(server) ); if (ret < 0) panic( "could not connect to server" ); /* send the request */ len = snprintf( buffer, sizeof buffer, "%04x%s", strlen(request), request ); if (unix_write(s, buffer, len) < 0) panic( "could not send request" ); /* read the OKAY answer */ if (unix_read(s, buffer, 4) != 4) panic( "could not read request" ); printf( "server answer: %.*s\n", 4, buffer ); /* now loop */ for (;;) { char head[5] = "0000"; if (unix_read(s, head, 4) < 0) panic("could not read length"); if ( sscanf( head, "%04x", &len ) != 1 ) panic("could not decode length"); if (unix_read(s, buffer, len) != len) panic("could not read data"); printf( "received header %.*s (%d bytes):\n%.*s", 4, head, len, len, buffer ); } close(s); } android-tools-5.1.1r36+git20160322/core/adb/test_track_jdwp.c000066400000000000000000000045671267427243200232640ustar00rootroot00000000000000/* a simple test program, connects to ADB server, and opens a track-devices session */ #include #include #include #include #include #include static void panic( const char* msg ) { fprintf(stderr, "PANIC: %s: %s\n", msg, strerror(errno)); exit(1); } static int unix_write( int fd, const char* buf, int len ) { int result = 0; while (len > 0) { int len2 = write(fd, buf, len); if (len2 < 0) { if (errno == EINTR || errno == EAGAIN) continue; return -1; } result += len2; len -= len2; buf += len2; } return result; } static int unix_read( int fd, char* buf, int len ) { int result = 0; while (len > 0) { int len2 = read(fd, buf, len); if (len2 < 0) { if (errno == EINTR || errno == EAGAIN) continue; return -1; } result += len2; len -= len2; buf += len2; } return result; } int main( void ) { int ret, s; struct sockaddr_in server; char buffer[1024]; const char* request = "track-jdwp"; int len; memset( &server, 0, sizeof(server) ); server.sin_family = AF_INET; server.sin_port = htons(5037); server.sin_addr.s_addr = htonl(INADDR_LOOPBACK); s = socket( PF_INET, SOCK_STREAM, 0 ); ret = connect( s, (struct sockaddr*) &server, sizeof(server) ); if (ret < 0) panic( "could not connect to server" ); /* send the request */ len = snprintf( buffer, sizeof buffer, "%04x%s", strlen(request), request ); if (unix_write(s, buffer, len) < 0) panic( "could not send request" ); /* read the OKAY answer */ if (unix_read(s, buffer, 4) != 4) panic( "could not read request" ); printf( "server answer: %.*s\n", 4, buffer ); /* now loop */ for (;;) { char head[5] = "0000"; if (unix_read(s, head, 4) < 0) panic("could not read length"); if ( sscanf( head, "%04x", &len ) != 1 ) panic("could not decode length"); if (unix_read(s, buffer, len) != len) panic("could not read data"); printf( "received header %.*s (%d bytes):\n%.*s", 4, head, len, len, buffer ); } close(s); } android-tools-5.1.1r36+git20160322/core/adb/transport.c000066400000000000000000000765631267427243200221360ustar00rootroot00000000000000/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include "sysdeps.h" #define TRACE_TAG TRACE_TRANSPORT #include "adb.h" static void transport_unref(atransport *t); static atransport transport_list = { .next = &transport_list, .prev = &transport_list, }; static atransport pending_list = { .next = &pending_list, .prev = &pending_list, }; ADB_MUTEX_DEFINE( transport_lock ); #if ADB_TRACE #define MAX_DUMP_HEX_LEN 16 static void dump_hex( const unsigned char* ptr, size_t len ) { int nn, len2 = len; // Build a string instead of logging each character. // MAX chars in 2 digit hex, one space, MAX chars, one '\0'. char buffer[MAX_DUMP_HEX_LEN *2 + 1 + MAX_DUMP_HEX_LEN + 1 ], *pb = buffer; if (len2 > MAX_DUMP_HEX_LEN) len2 = MAX_DUMP_HEX_LEN; for (nn = 0; nn < len2; nn++) { sprintf(pb, "%02x", ptr[nn]); pb += 2; } sprintf(pb++, " "); for (nn = 0; nn < len2; nn++) { int c = ptr[nn]; if (c < 32 || c > 127) c = '.'; *pb++ = c; } *pb++ = '\0'; DR("%s\n", buffer); } #endif void kick_transport(atransport* t) { if (t && !t->kicked) { int kicked; adb_mutex_lock(&transport_lock); kicked = t->kicked; if (!kicked) t->kicked = 1; adb_mutex_unlock(&transport_lock); if (!kicked) t->kick(t); } } void run_transport_disconnects(atransport* t) { adisconnect* dis = t->disconnects.next; D("%s: run_transport_disconnects\n", t->serial); while (dis != &t->disconnects) { adisconnect* next = dis->next; dis->func( dis->opaque, t ); dis = next; } } #if ADB_TRACE static void dump_packet(const char* name, const char* func, apacket* p) { unsigned command = p->msg.command; int len = p->msg.data_length; char cmd[9]; char arg0[12], arg1[12]; int n; for (n = 0; n < 4; n++) { int b = (command >> (n*8)) & 255; if (b < 32 || b >= 127) break; cmd[n] = (char)b; } if (n == 4) { cmd[4] = 0; } else { /* There is some non-ASCII name in the command, so dump * the hexadecimal value instead */ snprintf(cmd, sizeof cmd, "%08x", command); } if (p->msg.arg0 < 256U) snprintf(arg0, sizeof arg0, "%d", p->msg.arg0); else snprintf(arg0, sizeof arg0, "0x%x", p->msg.arg0); if (p->msg.arg1 < 256U) snprintf(arg1, sizeof arg1, "%d", p->msg.arg1); else snprintf(arg1, sizeof arg1, "0x%x", p->msg.arg1); D("%s: %s: [%s] arg0=%s arg1=%s (len=%d) ", name, func, cmd, arg0, arg1, len); dump_hex(p->data, len); } #endif /* ADB_TRACE */ static int read_packet(int fd, const char* name, apacket** ppacket) { char *p = (char*)ppacket; /* really read a packet address */ int r; int len = sizeof(*ppacket); char buff[8]; if (!name) { snprintf(buff, sizeof buff, "fd=%d", fd); name = buff; } while(len > 0) { r = adb_read(fd, p, len); if(r > 0) { len -= r; p += r; } else { D("%s: read_packet (fd=%d), error ret=%d errno=%d: %s\n", name, fd, r, errno, strerror(errno)); if((r < 0) && (errno == EINTR)) continue; return -1; } } #if ADB_TRACE if (ADB_TRACING) { dump_packet(name, "from remote", *ppacket); } #endif return 0; } static int write_packet(int fd, const char* name, apacket** ppacket) { char *p = (char*) ppacket; /* we really write the packet address */ int r, len = sizeof(ppacket); char buff[8]; if (!name) { snprintf(buff, sizeof buff, "fd=%d", fd); name = buff; } #if ADB_TRACE if (ADB_TRACING) { dump_packet(name, "to remote", *ppacket); } #endif len = sizeof(ppacket); while(len > 0) { r = adb_write(fd, p, len); if(r > 0) { len -= r; p += r; } else { D("%s: write_packet (fd=%d) error ret=%d errno=%d: %s\n", name, fd, r, errno, strerror(errno)); if((r < 0) && (errno == EINTR)) continue; return -1; } } return 0; } static void transport_socket_events(int fd, unsigned events, void *_t) { atransport *t = _t; D("transport_socket_events(fd=%d, events=%04x,...)\n", fd, events); if(events & FDE_READ){ apacket *p = 0; if(read_packet(fd, t->serial, &p)){ D("%s: failed to read packet from transport socket on fd %d\n", t->serial, fd); } else { handle_packet(p, (atransport *) _t); } } } void send_packet(apacket *p, atransport *t) { unsigned char *x; unsigned sum; unsigned count; p->msg.magic = p->msg.command ^ 0xffffffff; count = p->msg.data_length; x = (unsigned char *) p->data; sum = 0; while(count-- > 0){ sum += *x++; } p->msg.data_check = sum; print_packet("send", p); if (t == NULL) { D("Transport is null \n"); // Zap errno because print_packet() and other stuff have errno effect. errno = 0; fatal_errno("Transport is null"); } if(write_packet(t->transport_socket, t->serial, &p)){ fatal_errno("cannot enqueue packet on transport socket"); } } /* The transport is opened by transport_register_func before ** the input and output threads are started. ** ** The output thread issues a SYNC(1, token) message to let ** the input thread know to start things up. In the event ** of transport IO failure, the output thread will post a ** SYNC(0,0) message to ensure shutdown. ** ** The transport will not actually be closed until both ** threads exit, but the input thread will kick the transport ** on its way out to disconnect the underlying device. */ static void *output_thread(void *_t) { atransport *t = _t; apacket *p; D("%s: starting transport output thread on fd %d, SYNC online (%d)\n", t->serial, t->fd, t->sync_token + 1); p = get_apacket(); p->msg.command = A_SYNC; p->msg.arg0 = 1; p->msg.arg1 = ++(t->sync_token); p->msg.magic = A_SYNC ^ 0xffffffff; if(write_packet(t->fd, t->serial, &p)) { put_apacket(p); D("%s: failed to write SYNC packet\n", t->serial); goto oops; } D("%s: data pump started\n", t->serial); for(;;) { p = get_apacket(); if(t->read_from_remote(p, t) == 0){ D("%s: received remote packet, sending to transport\n", t->serial); if(write_packet(t->fd, t->serial, &p)){ put_apacket(p); D("%s: failed to write apacket to transport\n", t->serial); goto oops; } } else { D("%s: remote read failed for transport\n", t->serial); put_apacket(p); break; } } D("%s: SYNC offline for transport\n", t->serial); p = get_apacket(); p->msg.command = A_SYNC; p->msg.arg0 = 0; p->msg.arg1 = 0; p->msg.magic = A_SYNC ^ 0xffffffff; if(write_packet(t->fd, t->serial, &p)) { put_apacket(p); D("%s: failed to write SYNC apacket to transport", t->serial); } oops: D("%s: transport output thread is exiting\n", t->serial); kick_transport(t); transport_unref(t); return 0; } static void *input_thread(void *_t) { atransport *t = _t; apacket *p; int active = 0; D("%s: starting transport input thread, reading from fd %d\n", t->serial, t->fd); for(;;){ if(read_packet(t->fd, t->serial, &p)) { D("%s: failed to read apacket from transport on fd %d\n", t->serial, t->fd ); break; } if(p->msg.command == A_SYNC){ if(p->msg.arg0 == 0) { D("%s: transport SYNC offline\n", t->serial); put_apacket(p); break; } else { if(p->msg.arg1 == t->sync_token) { D("%s: transport SYNC online\n", t->serial); active = 1; } else { D("%s: transport ignoring SYNC %d != %d\n", t->serial, p->msg.arg1, t->sync_token); } } } else { if(active) { D("%s: transport got packet, sending to remote\n", t->serial); t->write_to_remote(p, t); } else { D("%s: transport ignoring packet while offline\n", t->serial); } } put_apacket(p); } // this is necessary to avoid a race condition that occured when a transport closes // while a client socket is still active. close_all_sockets(t); D("%s: transport input thread is exiting, fd %d\n", t->serial, t->fd); kick_transport(t); transport_unref(t); return 0; } static int transport_registration_send = -1; static int transport_registration_recv = -1; static fdevent transport_registration_fde; #if ADB_HOST static int list_transports_msg(char* buffer, size_t bufferlen) { char head[5]; int len; len = list_transports(buffer+4, bufferlen-4, 0); snprintf(head, sizeof(head), "%04x", len); memcpy(buffer, head, 4); len += 4; return len; } /* this adds support required by the 'track-devices' service. * this is used to send the content of "list_transport" to any * number of client connections that want it through a single * live TCP connection */ typedef struct device_tracker device_tracker; struct device_tracker { asocket socket; int update_needed; device_tracker* next; }; /* linked list of all device trackers */ static device_tracker* device_tracker_list; static void device_tracker_remove( device_tracker* tracker ) { device_tracker** pnode = &device_tracker_list; device_tracker* node = *pnode; adb_mutex_lock( &transport_lock ); while (node) { if (node == tracker) { *pnode = node->next; break; } pnode = &node->next; node = *pnode; } adb_mutex_unlock( &transport_lock ); } static void device_tracker_close( asocket* socket ) { device_tracker* tracker = (device_tracker*) socket; asocket* peer = socket->peer; D( "device tracker %p removed\n", tracker); if (peer) { peer->peer = NULL; peer->close(peer); } device_tracker_remove(tracker); free(tracker); } static int device_tracker_enqueue( asocket* socket, apacket* p ) { /* you can't read from a device tracker, close immediately */ put_apacket(p); device_tracker_close(socket); return -1; } static int device_tracker_send( device_tracker* tracker, const char* buffer, int len ) { apacket* p = get_apacket(); asocket* peer = tracker->socket.peer; memcpy(p->data, buffer, len); p->len = len; return peer->enqueue( peer, p ); } static void device_tracker_ready( asocket* socket ) { device_tracker* tracker = (device_tracker*) socket; /* we want to send the device list when the tracker connects * for the first time, even if no update occured */ if (tracker->update_needed > 0) { char buffer[1024]; int len; tracker->update_needed = 0; len = list_transports_msg(buffer, sizeof(buffer)); device_tracker_send(tracker, buffer, len); } } asocket* create_device_tracker(void) { device_tracker* tracker = calloc(1,sizeof(*tracker)); if(tracker == 0) fatal("cannot allocate device tracker"); D( "device tracker %p created\n", tracker); tracker->socket.enqueue = device_tracker_enqueue; tracker->socket.ready = device_tracker_ready; tracker->socket.close = device_tracker_close; tracker->update_needed = 1; tracker->next = device_tracker_list; device_tracker_list = tracker; return &tracker->socket; } /* call this function each time the transport list has changed */ void update_transports(void) { char buffer[1024]; int len; device_tracker* tracker; len = list_transports_msg(buffer, sizeof(buffer)); tracker = device_tracker_list; while (tracker != NULL) { device_tracker* next = tracker->next; /* note: this may destroy the tracker if the connection is closed */ device_tracker_send(tracker, buffer, len); tracker = next; } } #else void update_transports(void) { // nothing to do on the device side } #endif // ADB_HOST typedef struct tmsg tmsg; struct tmsg { atransport *transport; int action; }; static int transport_read_action(int fd, struct tmsg* m) { char *p = (char*)m; int len = sizeof(*m); int r; while(len > 0) { r = adb_read(fd, p, len); if(r > 0) { len -= r; p += r; } else { if((r < 0) && (errno == EINTR)) continue; D("transport_read_action: on fd %d, error %d: %s\n", fd, errno, strerror(errno)); return -1; } } return 0; } static int transport_write_action(int fd, struct tmsg* m) { char *p = (char*)m; int len = sizeof(*m); int r; while(len > 0) { r = adb_write(fd, p, len); if(r > 0) { len -= r; p += r; } else { if((r < 0) && (errno == EINTR)) continue; D("transport_write_action: on fd %d, error %d: %s\n", fd, errno, strerror(errno)); return -1; } } return 0; } static void transport_registration_func(int _fd, unsigned ev, void *data) { tmsg m; adb_thread_t output_thread_ptr; adb_thread_t input_thread_ptr; int s[2]; atransport *t; if(!(ev & FDE_READ)) { return; } if(transport_read_action(_fd, &m)) { fatal_errno("cannot read transport registration socket"); } t = m.transport; if(m.action == 0){ D("transport: %s removing and free'ing %d\n", t->serial, t->transport_socket); /* IMPORTANT: the remove closes one half of the ** socket pair. The close closes the other half. */ fdevent_remove(&(t->transport_fde)); adb_close(t->fd); adb_mutex_lock(&transport_lock); t->next->prev = t->prev; t->prev->next = t->next; adb_mutex_unlock(&transport_lock); run_transport_disconnects(t); if (t->product) free(t->product); if (t->serial) free(t->serial); if (t->model) free(t->model); if (t->device) free(t->device); if (t->devpath) free(t->devpath); memset(t,0xee,sizeof(atransport)); free(t); update_transports(); return; } /* don't create transport threads for inaccessible devices */ if (t->connection_state != CS_NOPERM) { /* initial references are the two threads */ t->ref_count = 2; if(adb_socketpair(s)) { fatal_errno("cannot open transport socketpair"); } D("transport: %s (%d,%d) starting\n", t->serial, s[0], s[1]); t->transport_socket = s[0]; t->fd = s[1]; fdevent_install(&(t->transport_fde), t->transport_socket, transport_socket_events, t); fdevent_set(&(t->transport_fde), FDE_READ); if(adb_thread_create(&input_thread_ptr, input_thread, t)){ fatal_errno("cannot create input thread"); } if(adb_thread_create(&output_thread_ptr, output_thread, t)){ fatal_errno("cannot create output thread"); } } adb_mutex_lock(&transport_lock); /* remove from pending list */ t->next->prev = t->prev; t->prev->next = t->next; /* put us on the master device list */ t->next = &transport_list; t->prev = transport_list.prev; t->next->prev = t; t->prev->next = t; adb_mutex_unlock(&transport_lock); t->disconnects.next = t->disconnects.prev = &t->disconnects; update_transports(); } void init_transport_registration(void) { int s[2]; if(adb_socketpair(s)){ fatal_errno("cannot open transport registration socketpair"); } transport_registration_send = s[0]; transport_registration_recv = s[1]; fdevent_install(&transport_registration_fde, transport_registration_recv, transport_registration_func, 0); fdevent_set(&transport_registration_fde, FDE_READ); } /* the fdevent select pump is single threaded */ static void register_transport(atransport *transport) { tmsg m; m.transport = transport; m.action = 1; D("transport: %s registered\n", transport->serial); if(transport_write_action(transport_registration_send, &m)) { fatal_errno("cannot write transport registration socket\n"); } } static void remove_transport(atransport *transport) { tmsg m; m.transport = transport; m.action = 0; D("transport: %s removed\n", transport->serial); if(transport_write_action(transport_registration_send, &m)) { fatal_errno("cannot write transport registration socket\n"); } } static void transport_unref_locked(atransport *t) { t->ref_count--; if (t->ref_count == 0) { D("transport: %s unref (kicking and closing)\n", t->serial); if (!t->kicked) { t->kicked = 1; t->kick(t); } t->close(t); remove_transport(t); } else { D("transport: %s unref (count=%d)\n", t->serial, t->ref_count); } } static void transport_unref(atransport *t) { if (t) { adb_mutex_lock(&transport_lock); transport_unref_locked(t); adb_mutex_unlock(&transport_lock); } } void add_transport_disconnect(atransport* t, adisconnect* dis) { adb_mutex_lock(&transport_lock); dis->next = &t->disconnects; dis->prev = dis->next->prev; dis->prev->next = dis; dis->next->prev = dis; adb_mutex_unlock(&transport_lock); } void remove_transport_disconnect(atransport* t, adisconnect* dis) { dis->prev->next = dis->next; dis->next->prev = dis->prev; dis->next = dis->prev = dis; } static int qual_char_is_invalid(char ch) { if ('A' <= ch && ch <= 'Z') return 0; if ('a' <= ch && ch <= 'z') return 0; if ('0' <= ch && ch <= '9') return 0; return 1; } static int qual_match(const char *to_test, const char *prefix, const char *qual, int sanitize_qual) { if (!to_test || !*to_test) /* Return true if both the qual and to_test are null strings. */ return !qual || !*qual; if (!qual) return 0; if (prefix) { while (*prefix) { if (*prefix++ != *to_test++) return 0; } } while (*qual) { char ch = *qual++; if (sanitize_qual && qual_char_is_invalid(ch)) ch = '_'; if (ch != *to_test++) return 0; } /* Everything matched so far. Return true if *to_test is a NUL. */ return !*to_test; } atransport *acquire_one_transport(int state, transport_type ttype, const char* serial, char** error_out) { atransport *t; atransport *result = NULL; int ambiguous = 0; retry: if (error_out) *error_out = "device not found"; adb_mutex_lock(&transport_lock); for (t = transport_list.next; t != &transport_list; t = t->next) { if (t->connection_state == CS_NOPERM) { if (error_out) *error_out = "insufficient permissions for device"; continue; } /* check for matching serial number */ if (serial) { if ((t->serial && !strcmp(serial, t->serial)) || (t->devpath && !strcmp(serial, t->devpath)) || qual_match(serial, "product:", t->product, 0) || qual_match(serial, "model:", t->model, 1) || qual_match(serial, "device:", t->device, 0)) { if (result) { if (error_out) *error_out = "more than one device"; ambiguous = 1; result = NULL; break; } result = t; } } else { if (ttype == kTransportUsb && t->type == kTransportUsb) { if (result) { if (error_out) *error_out = "more than one device"; ambiguous = 1; result = NULL; break; } result = t; } else if (ttype == kTransportLocal && t->type == kTransportLocal) { if (result) { if (error_out) *error_out = "more than one emulator"; ambiguous = 1; result = NULL; break; } result = t; } else if (ttype == kTransportAny) { if (result) { if (error_out) *error_out = "more than one device and emulator"; ambiguous = 1; result = NULL; break; } result = t; } } } adb_mutex_unlock(&transport_lock); if (result) { if (result->connection_state == CS_UNAUTHORIZED) { if (error_out) *error_out = "device unauthorized. Please check the confirmation dialog on your device."; result = NULL; } /* offline devices are ignored -- they are either being born or dying */ if (result && result->connection_state == CS_OFFLINE) { if (error_out) *error_out = "device offline"; result = NULL; } /* check for required connection state */ if (result && state != CS_ANY && result->connection_state != state) { if (error_out) *error_out = "invalid device state"; result = NULL; } } if (result) { /* found one that we can take */ if (error_out) *error_out = NULL; } else if (state != CS_ANY && (serial || !ambiguous)) { adb_sleep_ms(1000); goto retry; } return result; } #if ADB_HOST static const char *statename(atransport *t) { switch(t->connection_state){ case CS_OFFLINE: return "offline"; case CS_BOOTLOADER: return "bootloader"; case CS_DEVICE: return "device"; case CS_HOST: return "host"; case CS_RECOVERY: return "recovery"; case CS_SIDELOAD: return "sideload"; case CS_NOPERM: return "no permissions"; case CS_UNAUTHORIZED: return "unauthorized"; default: return "unknown"; } } static void add_qual(char **buf, size_t *buf_size, const char *prefix, const char *qual, int sanitize_qual) { size_t len; int prefix_len; if (!buf || !*buf || !buf_size || !*buf_size || !qual || !*qual) return; len = snprintf(*buf, *buf_size, "%s%n%s", prefix, &prefix_len, qual); if (sanitize_qual) { char *cp; for (cp = *buf + prefix_len; cp < *buf + len; cp++) { if (qual_char_is_invalid(*cp)) *cp = '_'; } } *buf_size -= len; *buf += len; } static size_t format_transport(atransport *t, char *buf, size_t bufsize, int long_listing) { const char* serial = t->serial; if (!serial || !serial[0]) serial = "????????????"; if (!long_listing) { return snprintf(buf, bufsize, "%s\t%s\n", serial, statename(t)); } else { size_t len, remaining = bufsize; len = snprintf(buf, remaining, "%-22s %s", serial, statename(t)); remaining -= len; buf += len; add_qual(&buf, &remaining, " ", t->devpath, 0); add_qual(&buf, &remaining, " product:", t->product, 0); add_qual(&buf, &remaining, " model:", t->model, 1); add_qual(&buf, &remaining, " device:", t->device, 0); len = snprintf(buf, remaining, "\n"); remaining -= len; return bufsize - remaining; } } int list_transports(char *buf, size_t bufsize, int long_listing) { char* p = buf; char* end = buf + bufsize; int len; atransport *t; /* XXX OVERRUN PROBLEMS XXX */ adb_mutex_lock(&transport_lock); for(t = transport_list.next; t != &transport_list; t = t->next) { len = format_transport(t, p, end - p, long_listing); if (p + len >= end) { /* discard last line if buffer is too short */ break; } p += len; } p[0] = 0; adb_mutex_unlock(&transport_lock); return p - buf; } /* hack for osx */ void close_usb_devices() { atransport *t; adb_mutex_lock(&transport_lock); for(t = transport_list.next; t != &transport_list; t = t->next) { if ( !t->kicked ) { t->kicked = 1; t->kick(t); } } adb_mutex_unlock(&transport_lock); } #endif // ADB_HOST int register_socket_transport(int s, const char *serial, int port, int local) { atransport *t = calloc(1, sizeof(atransport)); atransport *n; char buff[32]; if (!serial) { snprintf(buff, sizeof buff, "T-%p", t); serial = buff; } D("transport: %s init'ing for socket %d, on port %d\n", serial, s, port); if (init_socket_transport(t, s, port, local) < 0) { free(t); return -1; } adb_mutex_lock(&transport_lock); for (n = pending_list.next; n != &pending_list; n = n->next) { if (n->serial && !strcmp(serial, n->serial)) { adb_mutex_unlock(&transport_lock); free(t); return -1; } } for (n = transport_list.next; n != &transport_list; n = n->next) { if (n->serial && !strcmp(serial, n->serial)) { adb_mutex_unlock(&transport_lock); free(t); return -1; } } t->next = &pending_list; t->prev = pending_list.prev; t->next->prev = t; t->prev->next = t; t->serial = strdup(serial); adb_mutex_unlock(&transport_lock); register_transport(t); return 0; } #if ADB_HOST atransport *find_transport(const char *serial) { atransport *t; adb_mutex_lock(&transport_lock); for(t = transport_list.next; t != &transport_list; t = t->next) { if (t->serial && !strcmp(serial, t->serial)) { break; } } adb_mutex_unlock(&transport_lock); if (t != &transport_list) return t; else return 0; } void unregister_transport(atransport *t) { adb_mutex_lock(&transport_lock); t->next->prev = t->prev; t->prev->next = t->next; adb_mutex_unlock(&transport_lock); kick_transport(t); transport_unref(t); } // unregisters all non-emulator TCP transports void unregister_all_tcp_transports() { atransport *t, *next; adb_mutex_lock(&transport_lock); for (t = transport_list.next; t != &transport_list; t = next) { next = t->next; if (t->type == kTransportLocal && t->adb_port == 0) { t->next->prev = t->prev; t->prev->next = next; // we cannot call kick_transport when holding transport_lock if (!t->kicked) { t->kicked = 1; t->kick(t); } transport_unref_locked(t); } } adb_mutex_unlock(&transport_lock); } #endif void register_usb_transport(usb_handle *usb, const char *serial, const char *devpath, unsigned writeable) { atransport *t = calloc(1, sizeof(atransport)); D("transport: %p init'ing for usb_handle %p (sn='%s')\n", t, usb, serial ? serial : ""); init_usb_transport(t, usb, (writeable ? CS_OFFLINE : CS_NOPERM)); if(serial) { t->serial = strdup(serial); } if(devpath) { t->devpath = strdup(devpath); } adb_mutex_lock(&transport_lock); t->next = &pending_list; t->prev = pending_list.prev; t->next->prev = t; t->prev->next = t; adb_mutex_unlock(&transport_lock); register_transport(t); } /* this should only be used for transports with connection_state == CS_NOPERM */ void unregister_usb_transport(usb_handle *usb) { atransport *t; adb_mutex_lock(&transport_lock); for(t = transport_list.next; t != &transport_list; t = t->next) { if (t->usb == usb && t->connection_state == CS_NOPERM) { t->next->prev = t->prev; t->prev->next = t->next; break; } } adb_mutex_unlock(&transport_lock); } #undef TRACE_TAG #define TRACE_TAG TRACE_RWX int readx(int fd, void *ptr, size_t len) { char *p = ptr; int r; #if ADB_TRACE size_t len0 = len; #endif D("readx: fd=%d wanted=%zu\n", fd, len); while(len > 0) { r = adb_read(fd, p, len); if(r > 0) { len -= r; p += r; } else { if (r < 0) { D("readx: fd=%d error %d: %s\n", fd, errno, strerror(errno)); if (errno == EINTR) continue; } else { D("readx: fd=%d disconnected\n", fd); } return -1; } } #if ADB_TRACE D("readx: fd=%d wanted=%zu got=%zu\n", fd, len0, len0 - len); dump_hex( ptr, len0 ); #endif return 0; } int writex(int fd, const void *ptr, size_t len) { char *p = (char*) ptr; int r; #if ADB_TRACE D("writex: fd=%d len=%d: ", fd, (int)len); dump_hex( ptr, len ); #endif while(len > 0) { r = adb_write(fd, p, len); if(r > 0) { len -= r; p += r; } else { if (r < 0) { D("writex: fd=%d error %d: %s\n", fd, errno, strerror(errno)); if (errno == EINTR) continue; if (errno == EAGAIN) { adb_sleep_ms(1); // just yield some cpu time continue; } } else { D("writex: fd=%d disconnected\n", fd); } return -1; } } return 0; } int check_header(apacket *p) { if(p->msg.magic != (p->msg.command ^ 0xffffffff)) { D("check_header(): invalid magic\n"); return -1; } if(p->msg.data_length > MAX_PAYLOAD) { D("check_header(): %d > MAX_PAYLOAD\n", p->msg.data_length); return -1; } return 0; } int check_data(apacket *p) { unsigned count, sum; unsigned char *x; count = p->msg.data_length; x = p->data; sum = 0; while(count-- > 0) { sum += *x++; } if(sum != p->msg.data_check) { return -1; } else { return 0; } } android-tools-5.1.1r36+git20160322/core/adb/transport.h000066400000000000000000000016421267427243200221250ustar00rootroot00000000000000/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef __TRANSPORT_H #define __TRANSPORT_H /* convenience wrappers around read/write that will retry on ** EINTR and/or short read/write. Returns 0 on success, -1 ** on error or EOF. */ int readx(int fd, void *ptr, size_t len); int writex(int fd, const void *ptr, size_t len); #endif /* __TRANSPORT_H */ android-tools-5.1.1r36+git20160322/core/adb/transport_local.c000066400000000000000000000332051267427243200232720ustar00rootroot00000000000000/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include "sysdeps.h" #include #if !ADB_HOST #include #endif #define TRACE_TAG TRACE_TRANSPORT #include "adb.h" #ifdef HAVE_BIG_ENDIAN #define H4(x) (((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24) static inline void fix_endians(apacket *p) { p->msg.command = H4(p->msg.command); p->msg.arg0 = H4(p->msg.arg0); p->msg.arg1 = H4(p->msg.arg1); p->msg.data_length = H4(p->msg.data_length); p->msg.data_check = H4(p->msg.data_check); p->msg.magic = H4(p->msg.magic); } #else #define fix_endians(p) do {} while (0) #endif #if ADB_HOST /* we keep a list of opened transports. The atransport struct knows to which * local transport it is connected. The list is used to detect when we're * trying to connect twice to a given local transport. */ #define ADB_LOCAL_TRANSPORT_MAX 64 ADB_MUTEX_DEFINE( local_transports_lock ); static atransport* local_transports[ ADB_LOCAL_TRANSPORT_MAX ]; #endif /* ADB_HOST */ static int remote_read(apacket *p, atransport *t) { if(readx(t->sfd, &p->msg, sizeof(amessage))){ D("remote local: read terminated (message)\n"); return -1; } fix_endians(p); #if 0 && defined HAVE_BIG_ENDIAN D("read remote packet: %04x arg0=%0x arg1=%0x data_length=%0x data_check=%0x magic=%0x\n", p->msg.command, p->msg.arg0, p->msg.arg1, p->msg.data_length, p->msg.data_check, p->msg.magic); #endif if(check_header(p)) { D("bad header: terminated (data)\n"); return -1; } if(readx(t->sfd, p->data, p->msg.data_length)){ D("remote local: terminated (data)\n"); return -1; } if(check_data(p)) { D("bad data: terminated (data)\n"); return -1; } return 0; } static int remote_write(apacket *p, atransport *t) { int length = p->msg.data_length; fix_endians(p); #if 0 && defined HAVE_BIG_ENDIAN D("write remote packet: %04x arg0=%0x arg1=%0x data_length=%0x data_check=%0x magic=%0x\n", p->msg.command, p->msg.arg0, p->msg.arg1, p->msg.data_length, p->msg.data_check, p->msg.magic); #endif if(writex(t->sfd, &p->msg, sizeof(amessage) + length)) { D("remote local: write terminated\n"); return -1; } return 0; } int local_connect(int port) { return local_connect_arbitrary_ports(port-1, port); } int local_connect_arbitrary_ports(int console_port, int adb_port) { char buf[64]; int fd = -1; #if ADB_HOST const char *host = getenv("ADBHOST"); if (host) { fd = socket_network_client(host, adb_port, SOCK_STREAM); } #endif if (fd < 0) { fd = socket_loopback_client(adb_port, SOCK_STREAM); } if (fd >= 0) { D("client: connected on remote on fd %d\n", fd); close_on_exec(fd); disable_tcp_nagle(fd); snprintf(buf, sizeof buf, "%s%d", LOCAL_CLIENT_PREFIX, console_port); register_socket_transport(fd, buf, adb_port, 1); return 0; } return -1; } static void *client_socket_thread(void *x) { #if ADB_HOST int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT; int count = ADB_LOCAL_TRANSPORT_MAX; D("transport: client_socket_thread() starting\n"); /* try to connect to any number of running emulator instances */ /* this is only done when ADB starts up. later, each new emulator */ /* will send a message to ADB to indicate that is is starting up */ for ( ; count > 0; count--, port += 2 ) { (void) local_connect(port); } #endif return 0; } static void *server_socket_thread(void * arg) { int serverfd, fd; struct sockaddr addr; socklen_t alen; int port = (int) (uintptr_t) arg; D("transport: server_socket_thread() starting\n"); serverfd = -1; for(;;) { if(serverfd == -1) { serverfd = socket_inaddr_any_server(port, SOCK_STREAM); if(serverfd < 0) { D("server: cannot bind socket yet\n"); adb_sleep_ms(1000); continue; } close_on_exec(serverfd); } alen = sizeof(addr); D("server: trying to get new connection from %d\n", port); fd = adb_socket_accept(serverfd, &addr, &alen); if(fd >= 0) { D("server: new connection on fd %d\n", fd); close_on_exec(fd); disable_tcp_nagle(fd); register_socket_transport(fd, "host", port, 1); } } D("transport: server_socket_thread() exiting\n"); return 0; } /* This is relevant only for ADB daemon running inside the emulator. */ #if !ADB_HOST /* * Redefine open and write for qemu_pipe.h that contains inlined references * to those routines. We will redifine them back after qemu_pipe.h inclusion. */ #undef open #undef write #define open adb_open #define write adb_write #include #undef open #undef write #define open ___xxx_open #define write ___xxx_write /* A worker thread that monitors host connections, and registers a transport for * every new host connection. This thread replaces server_socket_thread on * condition that adbd daemon runs inside the emulator, and emulator uses QEMUD * pipe to communicate with adbd daemon inside the guest. This is done in order * to provide more robust communication channel between ADB host and guest. The * main issue with server_socket_thread approach is that it runs on top of TCP, * and thus is sensitive to network disruptions. For instance, the * ConnectionManager may decide to reset all network connections, in which case * the connection between ADB host and guest will be lost. To make ADB traffic * independent from the network, we use here 'adb' QEMUD service to transfer data * between the host, and the guest. See external/qemu/android/adb-*.* that * implements the emulator's side of the protocol. Another advantage of using * QEMUD approach is that ADB will be up much sooner, since it doesn't depend * anymore on network being set up. * The guest side of the protocol contains the following phases: * - Connect with adb QEMUD service. In this phase a handle to 'adb' QEMUD service * is opened, and it becomes clear whether or not emulator supports that * protocol. * - Wait for the ADB host to create connection with the guest. This is done by * sending an 'accept' request to the adb QEMUD service, and waiting on * response. * - When new ADB host connection is accepted, the connection with adb QEMUD * service is registered as the transport, and a 'start' request is sent to the * adb QEMUD service, indicating that the guest is ready to receive messages. * Note that the guest will ignore messages sent down from the emulator before * the transport registration is completed. That's why we need to send the * 'start' request after the transport is registered. */ static void *qemu_socket_thread(void * arg) { /* 'accept' request to the adb QEMUD service. */ static const char _accept_req[] = "accept"; /* 'start' request to the adb QEMUD service. */ static const char _start_req[] = "start"; /* 'ok' reply from the adb QEMUD service. */ static const char _ok_resp[] = "ok"; const int port = (int) (uintptr_t) arg; int res, fd; char tmp[256]; char con_name[32]; D("transport: qemu_socket_thread() starting\n"); /* adb QEMUD service connection request. */ snprintf(con_name, sizeof(con_name), "qemud:adb:%d", port); /* Connect to the adb QEMUD service. */ fd = qemu_pipe_open(con_name); if (fd < 0) { /* This could be an older version of the emulator, that doesn't * implement adb QEMUD service. Fall back to the old TCP way. */ adb_thread_t thr; D("adb service is not available. Falling back to TCP socket.\n"); adb_thread_create(&thr, server_socket_thread, arg); return 0; } for(;;) { /* * Wait till the host creates a new connection. */ /* Send the 'accept' request. */ res = adb_write(fd, _accept_req, strlen(_accept_req)); if ((size_t)res == strlen(_accept_req)) { /* Wait for the response. In the response we expect 'ok' on success, * or 'ko' on failure. */ res = adb_read(fd, tmp, sizeof(tmp)); if (res != 2 || memcmp(tmp, _ok_resp, 2)) { D("Accepting ADB host connection has failed.\n"); adb_close(fd); } else { /* Host is connected. Register the transport, and start the * exchange. */ register_socket_transport(fd, "host", port, 1); adb_write(fd, _start_req, strlen(_start_req)); } /* Prepare for accepting of the next ADB host connection. */ fd = qemu_pipe_open(con_name); if (fd < 0) { D("adb service become unavailable.\n"); return 0; } } else { D("Unable to send the '%s' request to ADB service.\n", _accept_req); return 0; } } D("transport: qemu_socket_thread() exiting\n"); return 0; } #endif // !ADB_HOST void local_init(int port) { adb_thread_t thr; void* (*func)(void *); if(HOST) { func = client_socket_thread; } else { #if ADB_HOST func = server_socket_thread; #else /* For the adbd daemon in the system image we need to distinguish * between the device, and the emulator. */ char is_qemu[PROPERTY_VALUE_MAX]; property_get("ro.kernel.qemu", is_qemu, ""); if (!strcmp(is_qemu, "1")) { /* Running inside the emulator: use QEMUD pipe as the transport. */ func = qemu_socket_thread; } else { /* Running inside the device: use TCP socket as the transport. */ func = server_socket_thread; } #endif // !ADB_HOST } D("transport: local %s init\n", HOST ? "client" : "server"); if(adb_thread_create(&thr, func, (void *) (uintptr_t) port)) { fatal_errno("cannot create local socket %s thread", HOST ? "client" : "server"); } } static void remote_kick(atransport *t) { int fd = t->sfd; t->sfd = -1; adb_shutdown(fd); adb_close(fd); #if ADB_HOST if(HOST) { int nn; adb_mutex_lock( &local_transports_lock ); for (nn = 0; nn < ADB_LOCAL_TRANSPORT_MAX; nn++) { if (local_transports[nn] == t) { local_transports[nn] = NULL; break; } } adb_mutex_unlock( &local_transports_lock ); } #endif } static void remote_close(atransport *t) { adb_close(t->fd); } #if ADB_HOST /* Only call this function if you already hold local_transports_lock. */ atransport* find_emulator_transport_by_adb_port_locked(int adb_port) { int i; for (i = 0; i < ADB_LOCAL_TRANSPORT_MAX; i++) { if (local_transports[i] && local_transports[i]->adb_port == adb_port) { return local_transports[i]; } } return NULL; } atransport* find_emulator_transport_by_adb_port(int adb_port) { adb_mutex_lock( &local_transports_lock ); atransport* result = find_emulator_transport_by_adb_port_locked(adb_port); adb_mutex_unlock( &local_transports_lock ); return result; } /* Only call this function if you already hold local_transports_lock. */ int get_available_local_transport_index_locked() { int i; for (i = 0; i < ADB_LOCAL_TRANSPORT_MAX; i++) { if (local_transports[i] == NULL) { return i; } } return -1; } int get_available_local_transport_index() { adb_mutex_lock( &local_transports_lock ); int result = get_available_local_transport_index_locked(); adb_mutex_unlock( &local_transports_lock ); return result; } #endif int init_socket_transport(atransport *t, int s, int adb_port, int local) { int fail = 0; t->kick = remote_kick; t->close = remote_close; t->read_from_remote = remote_read; t->write_to_remote = remote_write; t->sfd = s; t->sync_token = 1; t->connection_state = CS_OFFLINE; t->type = kTransportLocal; t->adb_port = 0; #if ADB_HOST if (HOST && local) { adb_mutex_lock( &local_transports_lock ); { t->adb_port = adb_port; atransport* existing_transport = find_emulator_transport_by_adb_port_locked(adb_port); int index = get_available_local_transport_index_locked(); if (existing_transport != NULL) { D("local transport for port %d already registered (%p)?\n", adb_port, existing_transport); fail = -1; } else if (index < 0) { // Too many emulators. D("cannot register more emulators. Maximum is %d\n", ADB_LOCAL_TRANSPORT_MAX); fail = -1; } else { local_transports[index] = t; } } adb_mutex_unlock( &local_transports_lock ); } #endif return fail; } android-tools-5.1.1r36+git20160322/core/adb/transport_usb.c000066400000000000000000000065241267427243200227750ustar00rootroot00000000000000/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #define TRACE_TAG TRACE_TRANSPORT #include "adb.h" #if ADB_HOST #include "usb_vendors.h" #endif #ifdef HAVE_BIG_ENDIAN #define H4(x) (((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24) static inline void fix_endians(apacket *p) { p->msg.command = H4(p->msg.command); p->msg.arg0 = H4(p->msg.arg0); p->msg.arg1 = H4(p->msg.arg1); p->msg.data_length = H4(p->msg.data_length); p->msg.data_check = H4(p->msg.data_check); p->msg.magic = H4(p->msg.magic); } unsigned host_to_le32(unsigned n) { return H4(n); } #else #define fix_endians(p) do {} while (0) unsigned host_to_le32(unsigned n) { return n; } #endif static int remote_read(apacket *p, atransport *t) { if(usb_read(t->usb, &p->msg, sizeof(amessage))){ D("remote usb: read terminated (message)\n"); return -1; } fix_endians(p); if(check_header(p)) { D("remote usb: check_header failed\n"); return -1; } if(p->msg.data_length) { if(usb_read(t->usb, p->data, p->msg.data_length)){ D("remote usb: terminated (data)\n"); return -1; } } if(check_data(p)) { D("remote usb: check_data failed\n"); return -1; } return 0; } static int remote_write(apacket *p, atransport *t) { unsigned size = p->msg.data_length; fix_endians(p); if(usb_write(t->usb, &p->msg, sizeof(amessage))) { D("remote usb: 1 - write terminated\n"); return -1; } if(p->msg.data_length == 0) return 0; if(usb_write(t->usb, &p->data, size)) { D("remote usb: 2 - write terminated\n"); return -1; } return 0; } static void remote_close(atransport *t) { usb_close(t->usb); t->usb = 0; } static void remote_kick(atransport *t) { usb_kick(t->usb); } void init_usb_transport(atransport *t, usb_handle *h, int state) { D("transport: usb\n"); t->close = remote_close; t->kick = remote_kick; t->read_from_remote = remote_read; t->write_to_remote = remote_write; t->sync_token = 1; t->connection_state = state; t->type = kTransportUsb; t->usb = h; #if ADB_HOST HOST = 1; #else HOST = 0; #endif } #if ADB_HOST int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol) { unsigned i; for (i = 0; i < vendorIdCount; i++) { if (vid == vendorIds[i]) { if (usb_class == ADB_CLASS && usb_subclass == ADB_SUBCLASS && usb_protocol == ADB_PROTOCOL) { return 1; } return 0; } } return 0; } #endif android-tools-5.1.1r36+git20160322/core/adb/usb_libusb.c000066400000000000000000000372451267427243200222250ustar00rootroot00000000000000/* * Copyright (C) 2009 bsdroid project * Alexey Tarasov * * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sysdeps.h" #define TRACE_TAG TRACE_USB #include "adb.h" static adb_mutex_t usb_lock = ADB_MUTEX_INITIALIZER; static libusb_context *ctx = NULL; struct usb_handle { usb_handle *prev; usb_handle *next; libusb_device *dev; libusb_device_handle *devh; int interface; uint8_t dev_bus; uint8_t dev_addr; int zero_mask; unsigned char end_point_address[2]; char serial[128]; adb_cond_t notify; adb_mutex_t lock; }; static struct usb_handle handle_list = { .prev = &handle_list, .next = &handle_list, }; void usb_cleanup() { libusb_exit(ctx); } void report_bulk_libusb_error(int r) { switch (r) { case LIBUSB_ERROR_TIMEOUT: D("Transfer timeout\n"); break; case LIBUSB_ERROR_PIPE: D("Control request is not supported\n"); break; case LIBUSB_ERROR_OVERFLOW: D("Device offered more data\n"); break; case LIBUSB_ERROR_NO_DEVICE : D("Device was disconnected\n"); break; default: D("Error %d during transfer\n", r); break; }; } static int usb_bulk_write(usb_handle *uh, const void *data, int len) { int r = 0; int transferred = 0; r = libusb_bulk_transfer(uh->devh, uh->end_point_address[1], (void *)data, len, &transferred, 0); if (r != 0) { D("usb_bulk_write(): "); report_bulk_libusb_error(r); return r; } return (transferred); } static int usb_bulk_read(usb_handle *uh, void *data, int len) { int r = 0; int transferred = 0; r = libusb_bulk_transfer(uh->devh, uh->end_point_address[0], data, len, &transferred, 0); if (r != 0) { D("usb_bulk_read(): "); report_bulk_libusb_error(r); return r; } return (transferred); } int usb_write(struct usb_handle *uh, const void *_data, int len) { unsigned char *data = (unsigned char*) _data; int n; int need_zero = 0; if (uh->zero_mask == 1) { if (!(len & uh->zero_mask)) { need_zero = 1; } } D("usb_write(): %p:%d -> transport %p\n", _data, len, uh); while (len > 0) { int xfer = (len > 4096) ? 4096 : len; n = usb_bulk_write(uh, data, xfer); if (n != xfer) { D("usb_write(): failed for transport %p (%d bytes left)\n", uh, len); return -1; } len -= xfer; data += xfer; } if (need_zero){ n = usb_bulk_write(uh, _data, 0); if (n < 0) { D("usb_write(): failed to finish operation for transport %p\n", uh); } return n; } return 0; } int usb_read(struct usb_handle *uh, void *_data, int len) { unsigned char *data = (unsigned char*) _data; int n; D("usb_read(): %p:%d <- transport %p\n", _data, len, uh); while (len > 0) { int xfer = (len > 4096) ? 4096 : len; n = usb_bulk_read(uh, data, xfer); if (n != xfer) { if (n > 0) { data += n; len -= n; continue; } D("usb_read(): failed for transport %p (%d bytes left)\n", uh, len); return -1; } len -= xfer; data += xfer; } return 0; } int usb_close(struct usb_handle *h) { D("usb_close(): closing transport %p\n", h); adb_mutex_lock(&usb_lock); h->next->prev = h->prev; h->prev->next = h->next; h->prev = NULL; h->next = NULL; libusb_release_interface(h->devh, h->interface); libusb_close(h->devh); libusb_unref_device(h->dev); adb_mutex_unlock(&usb_lock); free(h); return (0); } void usb_kick(struct usb_handle *h) { D("usb_cick(): kicking transport %p\n", h); adb_mutex_lock(&h->lock); unregister_usb_transport(h); adb_mutex_unlock(&h->lock); h->next->prev = h->prev; h->prev->next = h->next; h->prev = NULL; h->next = NULL; libusb_release_interface(h->devh, h->interface); libusb_close(h->devh); libusb_unref_device(h->dev); free(h); } int check_usb_interface(libusb_interface *interface, libusb_device_descriptor *desc, struct usb_handle *uh) { int e; if (interface->num_altsetting == 0) { D("check_usb_interface(): No interface settings\n"); return -1; } libusb_interface_descriptor *idesc = &interface->altsetting[0]; if (idesc->bNumEndpoints != 2) { D("check_usb_interface(): Interface have not 2 endpoints, ignoring\n"); return -1; } for (e = 0; e < idesc->bNumEndpoints; e++) { libusb_endpoint_descriptor *edesc = &idesc->endpoint[e]; if (edesc->bmAttributes != LIBUSB_TRANSFER_TYPE_BULK) { D("check_usb_interface(): Endpoint (%u) is not bulk (%u), ignoring\n", edesc->bmAttributes, LIBUSB_TRANSFER_TYPE_BULK); return -1; } if (edesc->bEndpointAddress & LIBUSB_ENDPOINT_IN) uh->end_point_address[0] = edesc->bEndpointAddress; else uh->end_point_address[1] = edesc->bEndpointAddress; /* aproto 01 needs 0 termination */ if (idesc->bInterfaceProtocol == 0x01) { uh->zero_mask = edesc->wMaxPacketSize - 1; D("check_usb_interface(): Forced Android interface protocol v.1\n"); } } D("check_usb_interface(): Device: %04x:%04x " "iclass: %x, isclass: %x, iproto: %x ep: %x/%x-> ", desc->idVendor, desc->idProduct, idesc->bInterfaceClass, idesc->bInterfaceSubClass, idesc->bInterfaceProtocol, uh->end_point_address[0], uh->end_point_address[1]); if (!is_adb_interface(desc->idVendor, desc->idProduct, idesc->bInterfaceClass, idesc->bInterfaceSubClass, idesc->bInterfaceProtocol)) { D("not matches\n"); return -1; } D("matches\n"); return 1; } int check_usb_interfaces(libusb_config_descriptor *config, libusb_device_descriptor *desc, struct usb_handle *uh) { int i; for (i = 0; i < config->bNumInterfaces; ++i) { if (check_usb_interface(&config->interface[i], desc, uh) != -1) { /* found some interface and saved information about it */ D("check_usb_interfaces(): Interface %d of %04x:%04x " "matches Android device\n", i, desc->idVendor, desc->idProduct); return i; } } return -1; } int register_device(struct usb_handle *uh, const char *serial) { D("register_device(): Registering %p [%s] as USB transport\n", uh, serial); struct usb_handle *usb= NULL; usb = calloc(1, sizeof(struct usb_handle)); memcpy(usb, uh, sizeof(struct usb_handle)); strcpy(usb->serial, uh->serial); adb_cond_init(&usb->notify, 0); adb_mutex_init(&usb->lock, 0); adb_mutex_lock(&usb_lock); usb->next = &handle_list; usb->prev = handle_list.prev; usb->prev->next = usb; usb->next->prev = usb; adb_mutex_unlock(&usb_lock); register_usb_transport(usb, serial, NULL, 1); return (1); } int already_registered(usb_handle *uh) { struct usb_handle *usb= NULL; int exists = 0; adb_mutex_lock(&usb_lock); for (usb = handle_list.next; usb != &handle_list; usb = usb->next) { if ((usb->dev_bus == uh->dev_bus) && (usb->dev_addr == uh->dev_addr)) { exists = 1; break; } } adb_mutex_unlock(&usb_lock); return exists; } void check_device(libusb_device *dev) { struct usb_handle uh; int i = 0; int found = -1; char serial[256] = {0}; libusb_device_descriptor desc; libusb_config_descriptor *config = NULL; int r = libusb_get_device_descriptor(dev, &desc); if (r != LIBUSB_SUCCESS) { D("check_device(): Failed to get device descriptor\n"); return; } if ((desc.idVendor == 0) && (desc.idProduct == 0)) return; D("check_device(): Probing usb device %04x:%04x\n", desc.idVendor, desc.idProduct); if (!is_adb_interface (desc.idVendor, desc.idProduct, ADB_CLASS, ADB_SUBCLASS, ADB_PROTOCOL)) { D("check_device(): Ignored due unknown vendor id\n"); return; } uh.dev_bus = libusb_get_bus_number(dev); uh.dev_addr = libusb_get_device_address(dev); if (already_registered(&uh)) { D("check_device(): Device (bus: %d, address: %d) " "is already registered\n", uh.dev_bus, uh.dev_addr); return; } D("check_device(): Device bus: %d, address: %d\n", uh.dev_bus, uh.dev_addr); r = libusb_get_active_config_descriptor(dev, &config); if (r != 0) { if (r == LIBUSB_ERROR_NOT_FOUND) { D("check_device(): Device %4x:%4x is unconfigured\n", desc.idVendor, desc.idProduct); return; } D("check_device(): Failed to get configuration for %4x:%4x\n", desc.idVendor, desc.idProduct); return; } if (config == NULL) { D("check_device(): Sanity check failed after " "getting active config\n"); return; } if (config->interface != NULL) { found = check_usb_interfaces(config, &desc, &uh); } /* not needed anymore */ libusb_free_config_descriptor(config); r = libusb_open(dev, &uh.devh); uh.dev = dev; if (r != 0) { switch (r) { case LIBUSB_ERROR_NO_MEM: D("check_device(): Memory allocation problem\n"); break; case LIBUSB_ERROR_ACCESS: D("check_device(): Permissions problem, " "current user priveleges are messed up?\n"); break; case LIBUSB_ERROR_NO_DEVICE: D("check_device(): Device disconected, bad cable?\n"); break; default: D("check_device(): libusb triggered error %d\n", r); } // skip rest found = -1; } if (found >= 0) { D("check_device(): Device matches Android interface\n"); // read the device's serial number memset(serial, 0, sizeof(serial)); uh.interface = found; r = libusb_claim_interface(uh.devh, uh.interface); if (r < 0) { D("check_device(): Failed to claim interface %d\n", uh.interface); goto fail; } if (desc.iSerialNumber) { // reading serial uint16_t buffer[128] = {0}; uint16_t languages[128] = {0}; int languageCount = 0; memset(languages, 0, sizeof(languages)); r = libusb_control_transfer(uh.devh, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE, LIBUSB_REQUEST_GET_DESCRIPTOR, LIBUSB_DT_STRING << 8, 0, (uint8_t *)languages, sizeof(languages), 0); if (r <= 0) { D("check_device(): Failed to get languages count\n"); goto fail; } languageCount = (r - 2) / 2; for (i = 1; i <= languageCount; ++i) { memset(buffer, 0, sizeof(buffer)); r = libusb_control_transfer(uh.devh, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE, LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_STRING << 8) | desc.iSerialNumber, languages[i], (uint8_t *)buffer, sizeof(buffer), 0); if (r > 0) { /* converting serial */ int j = 0; r /= 2; for (j = 1; j < r; ++j) serial[j - 1] = buffer[j]; serial[j - 1] = '\0'; break; /* languagesCount cycle */ } } if (register_device(&uh, serial) == 0) { D("check_device(): Failed to register device\n"); goto fail_interface; } libusb_ref_device(dev); } } return; fail_interface: libusb_release_interface(uh.devh, uh.interface); fail: libusb_close(uh.devh); uh.devh = NULL; } int check_device_connected(struct usb_handle *uh) { int r = libusb_kernel_driver_active(uh->devh, uh->interface); if (r == LIBUSB_ERROR_NO_DEVICE) return 0; if (r < 0) return -1; return 1; } void kick_disconnected() { struct usb_handle *usb= NULL; adb_mutex_lock(&usb_lock); for (usb = handle_list.next; usb != &handle_list; usb = usb->next) { if (check_device_connected(usb) == 0) { D("kick_disconnected(): Transport %p is not online anymore\n", usb); usb_kick(usb); } } adb_mutex_unlock(&usb_lock); } void scan_usb_devices() { D("scan_usb_devices(): started\n"); libusb_device **devs= NULL; libusb_device *dev= NULL; ssize_t cnt = libusb_get_device_list(ctx, &devs); if (cnt < 0) { D("scan_usb_devices(): Failed to get device list (error: %d)\n", cnt); return; } int i = 0; while ((dev = devs[i++]) != NULL) { check_device(dev); } libusb_free_device_list(devs, 1); } void * device_poll_thread(void* unused) { D("device_poll_thread(): Created USB scan thread\n"); for (;;) { sleep(5); kick_disconnected(); scan_usb_devices(); } /* never reaching this point */ return (NULL); } static void sigalrm_handler(int signo) { /* nothing */ } void usb_init() { D("usb_init(): started\n"); adb_thread_t tid; struct sigaction actions; int r = libusb_init(&ctx); if (r != LIBUSB_SUCCESS) { err(EX_IOERR, "Failed to init libusb\n"); } memset(&actions, 0, sizeof(actions)); sigemptyset(&actions.sa_mask); actions.sa_flags = 0; actions.sa_handler = sigalrm_handler; sigaction(SIGALRM, &actions, NULL); /* initial device scan */ scan_usb_devices(); /* starting USB event polling thread */ if (adb_thread_create(&tid, device_poll_thread, NULL)) { err(EX_IOERR, "cannot create USB scan thread\n"); } D("usb_init(): finished\n"); } android-tools-5.1.1r36+git20160322/core/adb/usb_linux.c000066400000000000000000000517551267427243200221060ustar00rootroot00000000000000/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20) #include #else #include #endif #include #include "sysdeps.h" #define TRACE_TAG TRACE_USB #include "adb.h" /* usb scan debugging is waaaay too verbose */ #define DBGX(x...) ADB_MUTEX_DEFINE( usb_lock ); struct usb_handle { usb_handle *prev; usb_handle *next; char fname[64]; int desc; unsigned char ep_in; unsigned char ep_out; unsigned zero_mask; unsigned writeable; struct usbdevfs_urb urb_in; struct usbdevfs_urb urb_out; int urb_in_busy; int urb_out_busy; int dead; adb_cond_t notify; adb_mutex_t lock; // for garbage collecting disconnected devices int mark; // ID of thread currently in REAPURB pthread_t reaper_thread; }; static usb_handle handle_list = { .prev = &handle_list, .next = &handle_list, }; static int known_device(const char *dev_name) { usb_handle *usb; adb_mutex_lock(&usb_lock); for(usb = handle_list.next; usb != &handle_list; usb = usb->next){ if(!strcmp(usb->fname, dev_name)) { // set mark flag to indicate this device is still alive usb->mark = 1; adb_mutex_unlock(&usb_lock); return 1; } } adb_mutex_unlock(&usb_lock); return 0; } static void kick_disconnected_devices() { usb_handle *usb; adb_mutex_lock(&usb_lock); // kick any devices in the device list that were not found in the device scan for(usb = handle_list.next; usb != &handle_list; usb = usb->next){ if (usb->mark == 0) { usb_kick(usb); } else { usb->mark = 0; } } adb_mutex_unlock(&usb_lock); } static void register_device(const char *dev_name, const char *devpath, unsigned char ep_in, unsigned char ep_out, int ifc, int serial_index, unsigned zero_mask); static inline int badname(const char *name) { while(*name) { if(!isdigit(*name++)) return 1; } return 0; } static void find_usb_device(const char *base, void (*register_device_callback) (const char *, const char *, unsigned char, unsigned char, int, int, unsigned)) { char busname[32], devname[32]; unsigned char local_ep_in, local_ep_out; DIR *busdir , *devdir ; struct dirent *de; int fd ; busdir = opendir(base); if(busdir == 0) return; while((de = readdir(busdir)) != 0) { if(badname(de->d_name)) continue; snprintf(busname, sizeof busname, "%s/%s", base, de->d_name); devdir = opendir(busname); if(devdir == 0) continue; // DBGX("[ scanning %s ]\n", busname); while((de = readdir(devdir))) { unsigned char devdesc[4096]; unsigned char* bufptr = devdesc; unsigned char* bufend; struct usb_device_descriptor* device; struct usb_config_descriptor* config; struct usb_interface_descriptor* interface; struct usb_endpoint_descriptor *ep1, *ep2; unsigned zero_mask = 0; unsigned vid, pid; size_t desclength; if(badname(de->d_name)) continue; snprintf(devname, sizeof devname, "%s/%s", busname, de->d_name); if(known_device(devname)) { DBGX("skipping %s\n", devname); continue; } // DBGX("[ scanning %s ]\n", devname); if((fd = unix_open(devname, O_RDONLY | O_CLOEXEC)) < 0) { continue; } desclength = adb_read(fd, devdesc, sizeof(devdesc)); bufend = bufptr + desclength; // should have device and configuration descriptors, and atleast two endpoints if (desclength < USB_DT_DEVICE_SIZE + USB_DT_CONFIG_SIZE) { D("desclength %zu is too small\n", desclength); adb_close(fd); continue; } device = (struct usb_device_descriptor*)bufptr; bufptr += USB_DT_DEVICE_SIZE; if((device->bLength != USB_DT_DEVICE_SIZE) || (device->bDescriptorType != USB_DT_DEVICE)) { adb_close(fd); continue; } vid = device->idVendor; pid = device->idProduct; DBGX("[ %s is V:%04x P:%04x ]\n", devname, vid, pid); // should have config descriptor next config = (struct usb_config_descriptor *)bufptr; bufptr += USB_DT_CONFIG_SIZE; if (config->bLength != USB_DT_CONFIG_SIZE || config->bDescriptorType != USB_DT_CONFIG) { D("usb_config_descriptor not found\n"); adb_close(fd); continue; } // loop through all the descriptors and look for the ADB interface while (bufptr < bufend) { unsigned char length = bufptr[0]; unsigned char type = bufptr[1]; if (type == USB_DT_INTERFACE) { interface = (struct usb_interface_descriptor *)bufptr; bufptr += length; if (length != USB_DT_INTERFACE_SIZE) { D("interface descriptor has wrong size\n"); break; } DBGX("bInterfaceClass: %d, bInterfaceSubClass: %d," "bInterfaceProtocol: %d, bNumEndpoints: %d\n", interface->bInterfaceClass, interface->bInterfaceSubClass, interface->bInterfaceProtocol, interface->bNumEndpoints); if (interface->bNumEndpoints == 2 && is_adb_interface(vid, pid, interface->bInterfaceClass, interface->bInterfaceSubClass, interface->bInterfaceProtocol)) { struct stat st; char pathbuf[128]; char link[256]; char *devpath = NULL; DBGX("looking for bulk endpoints\n"); // looks like ADB... ep1 = (struct usb_endpoint_descriptor *)bufptr; bufptr += USB_DT_ENDPOINT_SIZE; ep2 = (struct usb_endpoint_descriptor *)bufptr; bufptr += USB_DT_ENDPOINT_SIZE; if (bufptr > devdesc + desclength || ep1->bLength != USB_DT_ENDPOINT_SIZE || ep1->bDescriptorType != USB_DT_ENDPOINT || ep2->bLength != USB_DT_ENDPOINT_SIZE || ep2->bDescriptorType != USB_DT_ENDPOINT) { D("endpoints not found\n"); break; } // both endpoints should be bulk if (ep1->bmAttributes != USB_ENDPOINT_XFER_BULK || ep2->bmAttributes != USB_ENDPOINT_XFER_BULK) { D("bulk endpoints not found\n"); continue; } /* aproto 01 needs 0 termination */ if(interface->bInterfaceProtocol == 0x01) { zero_mask = ep1->wMaxPacketSize - 1; } // we have a match. now we just need to figure out which is in and which is out. if (ep1->bEndpointAddress & USB_ENDPOINT_DIR_MASK) { local_ep_in = ep1->bEndpointAddress; local_ep_out = ep2->bEndpointAddress; } else { local_ep_in = ep2->bEndpointAddress; local_ep_out = ep1->bEndpointAddress; } // Determine the device path if (!fstat(fd, &st) && S_ISCHR(st.st_mode)) { char *slash; ssize_t link_len; snprintf(pathbuf, sizeof(pathbuf), "/sys/dev/char/%d:%d", major(st.st_rdev), minor(st.st_rdev)); link_len = readlink(pathbuf, link, sizeof(link) - 1); if (link_len > 0) { link[link_len] = '\0'; slash = strrchr(link, '/'); if (slash) { snprintf(pathbuf, sizeof(pathbuf), "usb:%s", slash + 1); devpath = pathbuf; } } } register_device_callback(devname, devpath, local_ep_in, local_ep_out, interface->bInterfaceNumber, device->iSerialNumber, zero_mask); break; } } else { bufptr += length; } } // end of while adb_close(fd); } // end of devdir while closedir(devdir); } //end of busdir while closedir(busdir); } void usb_cleanup() { } static int usb_bulk_write(usb_handle *h, const void *data, int len) { struct usbdevfs_urb *urb = &h->urb_out; int res; struct timeval tv; struct timespec ts; memset(urb, 0, sizeof(*urb)); urb->type = USBDEVFS_URB_TYPE_BULK; urb->endpoint = h->ep_out; urb->status = -1; urb->buffer = (void*) data; urb->buffer_length = len; D("++ write ++\n"); adb_mutex_lock(&h->lock); if(h->dead) { res = -1; goto fail; } do { res = ioctl(h->desc, USBDEVFS_SUBMITURB, urb); } while((res < 0) && (errno == EINTR)); if(res < 0) { goto fail; } res = -1; h->urb_out_busy = 1; for(;;) { /* time out after five seconds */ gettimeofday(&tv, NULL); ts.tv_sec = tv.tv_sec + 5; ts.tv_nsec = tv.tv_usec * 1000L; res = pthread_cond_timedwait(&h->notify, &h->lock, &ts); if(res < 0 || h->dead) { break; } if(h->urb_out_busy == 0) { if(urb->status == 0) { res = urb->actual_length; } break; } } fail: adb_mutex_unlock(&h->lock); D("-- write --\n"); return res; } static int usb_bulk_read(usb_handle *h, void *data, int len) { struct usbdevfs_urb *urb = &h->urb_in; struct usbdevfs_urb *out = NULL; int res; memset(urb, 0, sizeof(*urb)); urb->type = USBDEVFS_URB_TYPE_BULK; urb->endpoint = h->ep_in; urb->status = -1; urb->buffer = data; urb->buffer_length = len; adb_mutex_lock(&h->lock); if(h->dead) { res = -1; goto fail; } do { res = ioctl(h->desc, USBDEVFS_SUBMITURB, urb); } while((res < 0) && (errno == EINTR)); if(res < 0) { goto fail; } h->urb_in_busy = 1; for(;;) { D("[ reap urb - wait ]\n"); h->reaper_thread = pthread_self(); adb_mutex_unlock(&h->lock); res = ioctl(h->desc, USBDEVFS_REAPURB, &out); int saved_errno = errno; adb_mutex_lock(&h->lock); h->reaper_thread = 0; if(h->dead) { res = -1; break; } if(res < 0) { if(saved_errno == EINTR) { continue; } D("[ reap urb - error ]\n"); break; } D("[ urb @%p status = %d, actual = %d ]\n", out, out->status, out->actual_length); if(out == &h->urb_in) { D("[ reap urb - IN complete ]\n"); h->urb_in_busy = 0; if(urb->status == 0) { res = urb->actual_length; } else { res = -1; } break; } if(out == &h->urb_out) { D("[ reap urb - OUT compelete ]\n"); h->urb_out_busy = 0; adb_cond_broadcast(&h->notify); } } fail: adb_mutex_unlock(&h->lock); return res; } int usb_write(usb_handle *h, const void *_data, int len) { unsigned char *data = (unsigned char*) _data; int n; int need_zero = 0; if(h->zero_mask) { /* if we need 0-markers and our transfer ** is an even multiple of the packet size, ** we make note of it */ if(!(len & h->zero_mask)) { need_zero = 1; } } while(len > 0) { int xfer = (len > 4096) ? 4096 : len; n = usb_bulk_write(h, data, xfer); if(n != xfer) { D("ERROR: n = %d, errno = %d (%s)\n", n, errno, strerror(errno)); return -1; } len -= xfer; data += xfer; } if(need_zero){ n = usb_bulk_write(h, _data, 0); return n; } return 0; } int usb_read(usb_handle *h, void *_data, int len) { unsigned char *data = (unsigned char*) _data; int n; D("++ usb_read ++\n"); while(len > 0) { int xfer = (len > 4096) ? 4096 : len; D("[ usb read %d fd = %d], fname=%s\n", xfer, h->desc, h->fname); n = usb_bulk_read(h, data, xfer); D("[ usb read %d ] = %d, fname=%s\n", xfer, n, h->fname); if(n != xfer) { if((errno == ETIMEDOUT) && (h->desc != -1)) { D("[ timeout ]\n"); if(n > 0){ data += n; len -= n; } continue; } D("ERROR: n = %d, errno = %d (%s)\n", n, errno, strerror(errno)); return -1; } len -= xfer; data += xfer; } D("-- usb_read --\n"); return 0; } void usb_kick(usb_handle *h) { D("[ kicking %p (fd = %d) ]\n", h, h->desc); adb_mutex_lock(&h->lock); if(h->dead == 0) { h->dead = 1; if (h->writeable) { /* HACK ALERT! ** Sometimes we get stuck in ioctl(USBDEVFS_REAPURB). ** This is a workaround for that problem. */ if (h->reaper_thread) { pthread_kill(h->reaper_thread, SIGALRM); } /* cancel any pending transactions ** these will quietly fail if the txns are not active, ** but this ensures that a reader blocked on REAPURB ** will get unblocked */ ioctl(h->desc, USBDEVFS_DISCARDURB, &h->urb_in); ioctl(h->desc, USBDEVFS_DISCARDURB, &h->urb_out); h->urb_in.status = -ENODEV; h->urb_out.status = -ENODEV; h->urb_in_busy = 0; h->urb_out_busy = 0; adb_cond_broadcast(&h->notify); } else { unregister_usb_transport(h); } } adb_mutex_unlock(&h->lock); } int usb_close(usb_handle *h) { D("[ usb close ... ]\n"); adb_mutex_lock(&usb_lock); h->next->prev = h->prev; h->prev->next = h->next; h->prev = 0; h->next = 0; adb_close(h->desc); D("[ usb closed %p (fd = %d) ]\n", h, h->desc); adb_mutex_unlock(&usb_lock); free(h); return 0; } static void register_device(const char *dev_name, const char *devpath, unsigned char ep_in, unsigned char ep_out, int interface, int serial_index, unsigned zero_mask) { usb_handle* usb = 0; int n = 0; char serial[256]; /* Since Linux will not reassign the device ID (and dev_name) ** as long as the device is open, we can add to the list here ** once we open it and remove from the list when we're finally ** closed and everything will work out fine. ** ** If we have a usb_handle on the list 'o handles with a matching ** name, we have no further work to do. */ adb_mutex_lock(&usb_lock); for(usb = handle_list.next; usb != &handle_list; usb = usb->next){ if(!strcmp(usb->fname, dev_name)) { adb_mutex_unlock(&usb_lock); return; } } adb_mutex_unlock(&usb_lock); D("[ usb located new device %s (%d/%d/%d) ]\n", dev_name, ep_in, ep_out, interface); usb = calloc(1, sizeof(usb_handle)); strcpy(usb->fname, dev_name); usb->ep_in = ep_in; usb->ep_out = ep_out; usb->zero_mask = zero_mask; usb->writeable = 1; adb_cond_init(&usb->notify, 0); adb_mutex_init(&usb->lock, 0); /* initialize mark to 1 so we don't get garbage collected after the device scan */ usb->mark = 1; usb->reaper_thread = 0; usb->desc = unix_open(usb->fname, O_RDWR | O_CLOEXEC); if(usb->desc < 0) { /* if we fail, see if have read-only access */ usb->desc = unix_open(usb->fname, O_RDONLY | O_CLOEXEC); if(usb->desc < 0) goto fail; usb->writeable = 0; D("[ usb open read-only %s fd = %d]\n", usb->fname, usb->desc); } else { D("[ usb open %s fd = %d]\n", usb->fname, usb->desc); n = ioctl(usb->desc, USBDEVFS_CLAIMINTERFACE, &interface); if(n != 0) goto fail; } /* read the device's serial number */ serial[0] = 0; memset(serial, 0, sizeof(serial)); if (serial_index) { struct usbdevfs_ctrltransfer ctrl; __u16 buffer[128]; __u16 languages[128]; int i, result; int languageCount = 0; memset(languages, 0, sizeof(languages)); memset(&ctrl, 0, sizeof(ctrl)); // read list of supported languages ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE; ctrl.bRequest = USB_REQ_GET_DESCRIPTOR; ctrl.wValue = (USB_DT_STRING << 8) | 0; ctrl.wIndex = 0; ctrl.wLength = sizeof(languages); ctrl.data = languages; ctrl.timeout = 1000; result = ioctl(usb->desc, USBDEVFS_CONTROL, &ctrl); if (result > 0) languageCount = (result - 2) / 2; for (i = 1; i <= languageCount; i++) { memset(buffer, 0, sizeof(buffer)); memset(&ctrl, 0, sizeof(ctrl)); ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE; ctrl.bRequest = USB_REQ_GET_DESCRIPTOR; ctrl.wValue = (USB_DT_STRING << 8) | serial_index; ctrl.wIndex = __le16_to_cpu(languages[i]); ctrl.wLength = sizeof(buffer); ctrl.data = buffer; ctrl.timeout = 1000; result = ioctl(usb->desc, USBDEVFS_CONTROL, &ctrl); if (result > 0) { int i; // skip first word, and copy the rest to the serial string, changing shorts to bytes. result /= 2; for (i = 1; i < result; i++) serial[i - 1] = __le16_to_cpu(buffer[i]); serial[i - 1] = 0; break; } } } /* add to the end of the active handles */ adb_mutex_lock(&usb_lock); usb->next = &handle_list; usb->prev = handle_list.prev; usb->prev->next = usb; usb->next->prev = usb; adb_mutex_unlock(&usb_lock); register_usb_transport(usb, serial, devpath, usb->writeable); return; fail: D("[ usb open %s error=%d, err_str = %s]\n", usb->fname, errno, strerror(errno)); if(usb->desc >= 0) { adb_close(usb->desc); } free(usb); } void* device_poll_thread(void* unused) { D("Created device thread\n"); for(;;) { /* XXX use inotify */ find_usb_device("/dev/bus/usb", register_device); kick_disconnected_devices(); sleep(1); } return NULL; } static void sigalrm_handler(int signo) { // don't need to do anything here } void usb_init() { adb_thread_t tid; struct sigaction actions; memset(&actions, 0, sizeof(actions)); sigemptyset(&actions.sa_mask); actions.sa_flags = 0; actions.sa_handler = sigalrm_handler; sigaction(SIGALRM,& actions, NULL); if(adb_thread_create(&tid, device_poll_thread, NULL)){ fatal_errno("cannot create input thread"); } } android-tools-5.1.1r36+git20160322/core/adb/usb_linux_client.c000066400000000000000000000315261267427243200234360ustar00rootroot00000000000000/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include "sysdeps.h" #define TRACE_TAG TRACE_USB #include "adb.h" #define MAX_PACKET_SIZE_FS 64 #define MAX_PACKET_SIZE_HS 512 #define cpu_to_le16(x) htole16(x) #define cpu_to_le32(x) htole32(x) struct usb_handle { adb_cond_t notify; adb_mutex_t lock; int (*write)(usb_handle *h, const void *data, int len); int (*read)(usb_handle *h, void *data, int len); void (*kick)(usb_handle *h); // Legacy f_adb int fd; // FunctionFS int control; int bulk_out; /* "out" from the host's perspective => source for adbd */ int bulk_in; /* "in" from the host's perspective => sink for adbd */ }; static const struct { struct usb_functionfs_descs_head header; struct { struct usb_interface_descriptor intf; struct usb_endpoint_descriptor_no_audio source; struct usb_endpoint_descriptor_no_audio sink; } __attribute__((packed)) fs_descs, hs_descs; } __attribute__((packed)) descriptors = { .header = { .magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC), .length = cpu_to_le32(sizeof(descriptors)), .fs_count = 3, .hs_count = 3, }, .fs_descs = { .intf = { .bLength = sizeof(descriptors.fs_descs.intf), .bDescriptorType = USB_DT_INTERFACE, .bInterfaceNumber = 0, .bNumEndpoints = 2, .bInterfaceClass = ADB_CLASS, .bInterfaceSubClass = ADB_SUBCLASS, .bInterfaceProtocol = ADB_PROTOCOL, .iInterface = 1, /* first string from the provided table */ }, .source = { .bLength = sizeof(descriptors.fs_descs.source), .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = 1 | USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = MAX_PACKET_SIZE_FS, }, .sink = { .bLength = sizeof(descriptors.fs_descs.sink), .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = 2 | USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = MAX_PACKET_SIZE_FS, }, }, .hs_descs = { .intf = { .bLength = sizeof(descriptors.hs_descs.intf), .bDescriptorType = USB_DT_INTERFACE, .bInterfaceNumber = 0, .bNumEndpoints = 2, .bInterfaceClass = ADB_CLASS, .bInterfaceSubClass = ADB_SUBCLASS, .bInterfaceProtocol = ADB_PROTOCOL, .iInterface = 1, /* first string from the provided table */ }, .source = { .bLength = sizeof(descriptors.hs_descs.source), .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = 1 | USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = MAX_PACKET_SIZE_HS, }, .sink = { .bLength = sizeof(descriptors.hs_descs.sink), .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = 2 | USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = MAX_PACKET_SIZE_HS, }, }, }; #define STR_INTERFACE_ "ADB Interface" static const struct { struct usb_functionfs_strings_head header; struct { __le16 code; const char str1[sizeof(STR_INTERFACE_)]; } __attribute__((packed)) lang0; } __attribute__((packed)) strings = { .header = { .magic = cpu_to_le32(FUNCTIONFS_STRINGS_MAGIC), .length = cpu_to_le32(sizeof(strings)), .str_count = cpu_to_le32(1), .lang_count = cpu_to_le32(1), }, .lang0 = { cpu_to_le16(0x0409), /* en-us */ STR_INTERFACE_, }, }; static void *usb_adb_open_thread(void *x) { struct usb_handle *usb = (struct usb_handle *)x; int fd; while (1) { // wait until the USB device needs opening adb_mutex_lock(&usb->lock); while (usb->fd != -1) adb_cond_wait(&usb->notify, &usb->lock); adb_mutex_unlock(&usb->lock); D("[ usb_thread - opening device ]\n"); do { /* XXX use inotify? */ fd = unix_open("/dev/android_adb", O_RDWR); if (fd < 0) { // to support older kernels fd = unix_open("/dev/android", O_RDWR); } if (fd < 0) { adb_sleep_ms(1000); } } while (fd < 0); D("[ opening device succeeded ]\n"); close_on_exec(fd); usb->fd = fd; D("[ usb_thread - registering device ]\n"); register_usb_transport(usb, 0, 0, 1); } // never gets here return 0; } static int usb_adb_write(usb_handle *h, const void *data, int len) { int n; D("about to write (fd=%d, len=%d)\n", h->fd, len); n = adb_write(h->fd, data, len); if(n != len) { D("ERROR: fd = %d, n = %d, errno = %d (%s)\n", h->fd, n, errno, strerror(errno)); return -1; } D("[ done fd=%d ]\n", h->fd); return 0; } static int usb_adb_read(usb_handle *h, void *data, int len) { int n; D("about to read (fd=%d, len=%d)\n", h->fd, len); n = adb_read(h->fd, data, len); if(n != len) { D("ERROR: fd = %d, n = %d, errno = %d (%s)\n", h->fd, n, errno, strerror(errno)); return -1; } D("[ done fd=%d ]\n", h->fd); return 0; } static void usb_adb_kick(usb_handle *h) { D("usb_kick\n"); adb_mutex_lock(&h->lock); adb_close(h->fd); h->fd = -1; // notify usb_adb_open_thread that we are disconnected adb_cond_signal(&h->notify); adb_mutex_unlock(&h->lock); } static void usb_adb_init() { usb_handle *h; adb_thread_t tid; int fd; h = calloc(1, sizeof(usb_handle)); h->write = usb_adb_write; h->read = usb_adb_read; h->kick = usb_adb_kick; h->fd = -1; adb_cond_init(&h->notify, 0); adb_mutex_init(&h->lock, 0); // Open the file /dev/android_adb_enable to trigger // the enabling of the adb USB function in the kernel. // We never touch this file again - just leave it open // indefinitely so the kernel will know when we are running // and when we are not. fd = unix_open("/dev/android_adb_enable", O_RDWR); if (fd < 0) { D("failed to open /dev/android_adb_enable\n"); } else { close_on_exec(fd); } D("[ usb_init - starting thread ]\n"); if(adb_thread_create(&tid, usb_adb_open_thread, h)){ fatal_errno("cannot create usb thread"); } } static void init_functionfs(struct usb_handle *h) { ssize_t ret; if (h->control < 0) { // might have already done this before D("OPENING %s\n", USB_FFS_ADB_EP0); h->control = adb_open(USB_FFS_ADB_EP0, O_RDWR); if (h->control < 0) { D("[ %s: cannot open control endpoint: errno=%d]\n", USB_FFS_ADB_EP0, errno); goto err; } ret = adb_write(h->control, &descriptors, sizeof(descriptors)); if (ret < 0) { D("[ %s: write descriptors failed: errno=%d ]\n", USB_FFS_ADB_EP0, errno); goto err; } ret = adb_write(h->control, &strings, sizeof(strings)); if (ret < 0) { D("[ %s: writing strings failed: errno=%d]\n", USB_FFS_ADB_EP0, errno); goto err; } } h->bulk_out = adb_open(USB_FFS_ADB_OUT, O_RDWR); if (h->bulk_out < 0) { D("[ %s: cannot open bulk-out ep: errno=%d ]\n", USB_FFS_ADB_OUT, errno); goto err; } h->bulk_in = adb_open(USB_FFS_ADB_IN, O_RDWR); if (h->bulk_in < 0) { D("[ %s: cannot open bulk-in ep: errno=%d ]\n", USB_FFS_ADB_IN, errno); goto err; } return; err: if (h->bulk_in > 0) { adb_close(h->bulk_in); h->bulk_in = -1; } if (h->bulk_out > 0) { adb_close(h->bulk_out); h->bulk_out = -1; } if (h->control > 0) { adb_close(h->control); h->control = -1; } return; } static void *usb_ffs_open_thread(void *x) { struct usb_handle *usb = (struct usb_handle *)x; while (1) { // wait until the USB device needs opening adb_mutex_lock(&usb->lock); while (usb->control != -1 && usb->bulk_in != -1 && usb->bulk_out != -1) adb_cond_wait(&usb->notify, &usb->lock); adb_mutex_unlock(&usb->lock); while (1) { init_functionfs(usb); if (usb->control >= 0 && usb->bulk_in >= 0 && usb->bulk_out >= 0) break; adb_sleep_ms(1000); } D("[ usb_thread - registering device ]\n"); register_usb_transport(usb, 0, 0, 1); } // never gets here return 0; } static int bulk_write(int bulk_in, const char *buf, size_t length) { size_t count = 0; int ret; do { ret = adb_write(bulk_in, buf + count, length - count); if (ret < 0) { if (errno != EINTR) return ret; } else { count += ret; } } while (count < length); D("[ bulk_write done fd=%d ]\n", bulk_in); return count; } static int usb_ffs_write(usb_handle *h, const void *data, int len) { int n; D("about to write (fd=%d, len=%d)\n", h->bulk_in, len); n = bulk_write(h->bulk_in, data, len); if (n != len) { D("ERROR: fd = %d, n = %d, errno = %d (%s)\n", h->bulk_in, n, errno, strerror(errno)); return -1; } D("[ done fd=%d ]\n", h->bulk_in); return 0; } static int bulk_read(int bulk_out, char *buf, size_t length) { size_t count = 0; int ret; do { ret = adb_read(bulk_out, buf + count, length - count); if (ret < 0) { if (errno != EINTR) { D("[ bulk_read failed fd=%d length=%zu count=%zu ]\n", bulk_out, length, count); return ret; } } else { count += ret; } } while (count < length); return count; } static int usb_ffs_read(usb_handle *h, void *data, int len) { int n; D("about to read (fd=%d, len=%d)\n", h->bulk_out, len); n = bulk_read(h->bulk_out, data, len); if (n != len) { D("ERROR: fd = %d, n = %d, errno = %d (%s)\n", h->bulk_out, n, errno, strerror(errno)); return -1; } D("[ done fd=%d ]\n", h->bulk_out); return 0; } static void usb_ffs_kick(usb_handle *h) { int err; err = ioctl(h->bulk_in, FUNCTIONFS_CLEAR_HALT); if (err < 0) D("[ kick: source (fd=%d) clear halt failed (%d) ]", h->bulk_in, errno); err = ioctl(h->bulk_out, FUNCTIONFS_CLEAR_HALT); if (err < 0) D("[ kick: sink (fd=%d) clear halt failed (%d) ]", h->bulk_out, errno); adb_mutex_lock(&h->lock); // don't close ep0 here, since we may not need to reinitialize it with // the same descriptors again. if however ep1/ep2 fail to re-open in // init_functionfs, only then would we close and open ep0 again. adb_close(h->bulk_out); adb_close(h->bulk_in); h->bulk_out = h->bulk_in = -1; // notify usb_ffs_open_thread that we are disconnected adb_cond_signal(&h->notify); adb_mutex_unlock(&h->lock); } static void usb_ffs_init() { usb_handle *h; adb_thread_t tid; D("[ usb_init - using FunctionFS ]\n"); h = calloc(1, sizeof(usb_handle)); h->write = usb_ffs_write; h->read = usb_ffs_read; h->kick = usb_ffs_kick; h->control = -1; h->bulk_out = -1; h->bulk_out = -1; adb_cond_init(&h->notify, 0); adb_mutex_init(&h->lock, 0); D("[ usb_init - starting thread ]\n"); if (adb_thread_create(&tid, usb_ffs_open_thread, h)){ fatal_errno("[ cannot create usb thread ]\n"); } } void usb_init() { if (access(USB_FFS_ADB_EP0, F_OK) == 0) usb_ffs_init(); else usb_adb_init(); } void usb_cleanup() { } int usb_write(usb_handle *h, const void *data, int len) { return h->write(h, data, len); } int usb_read(usb_handle *h, void *data, int len) { return h->read(h, data, len); } int usb_close(usb_handle *h) { return 0; } void usb_kick(usb_handle *h) { h->kick(h); } android-tools-5.1.1r36+git20160322/core/adb/usb_osx.c000066400000000000000000000423511267427243200215500ustar00rootroot00000000000000/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include "sysdeps.h" #include #define TRACE_TAG TRACE_USB #include "adb.h" #include "usb_vendors.h" #define DBG D static IONotificationPortRef notificationPort = 0; static io_iterator_t* notificationIterators; struct usb_handle { UInt8 bulkIn; UInt8 bulkOut; IOUSBInterfaceInterface **interface; io_object_t usbNotification; unsigned int zero_mask; }; static CFRunLoopRef currentRunLoop = 0; static pthread_mutex_t start_lock; static pthread_cond_t start_cond; static void AndroidInterfaceAdded(void *refCon, io_iterator_t iterator); static void AndroidInterfaceNotify(void *refCon, io_iterator_t iterator, natural_t messageType, void *messageArgument); static usb_handle* CheckInterface(IOUSBInterfaceInterface **iface, UInt16 vendor, UInt16 product); static int InitUSB() { CFMutableDictionaryRef matchingDict; CFRunLoopSourceRef runLoopSource; SInt32 vendor, if_subclass, if_protocol; unsigned i; //* To set up asynchronous notifications, create a notification port and //* add its run loop event source to the program's run loop notificationPort = IONotificationPortCreate(kIOMasterPortDefault); runLoopSource = IONotificationPortGetRunLoopSource(notificationPort); CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode); memset(notificationIterators, 0, sizeof(notificationIterators)); //* loop through all supported vendors for (i = 0; i < vendorIdCount; i++) { //* Create our matching dictionary to find the Android device's //* adb interface //* IOServiceAddMatchingNotification consumes the reference, so we do //* not need to release this matchingDict = IOServiceMatching(kIOUSBInterfaceClassName); if (!matchingDict) { DBG("ERR: Couldn't create USB matching dictionary.\n"); return -1; } //* Match based on vendor id, interface subclass and protocol vendor = vendorIds[i]; if_subclass = ADB_SUBCLASS; if_protocol = ADB_PROTOCOL; CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorID), CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vendor)); CFDictionarySetValue(matchingDict, CFSTR(kUSBInterfaceSubClass), CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &if_subclass)); CFDictionarySetValue(matchingDict, CFSTR(kUSBInterfaceProtocol), CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &if_protocol)); IOServiceAddMatchingNotification( notificationPort, kIOFirstMatchNotification, matchingDict, AndroidInterfaceAdded, NULL, ¬ificationIterators[i]); //* Iterate over set of matching interfaces to access already-present //* devices and to arm the notification AndroidInterfaceAdded(NULL, notificationIterators[i]); } return 0; } static void AndroidInterfaceAdded(void *refCon, io_iterator_t iterator) { kern_return_t kr; io_service_t usbDevice; io_service_t usbInterface; IOCFPlugInInterface **plugInInterface = NULL; IOUSBInterfaceInterface220 **iface = NULL; IOUSBDeviceInterface197 **dev = NULL; HRESULT result; SInt32 score; UInt32 locationId; UInt16 vendor; UInt16 product; UInt8 serialIndex; char serial[256]; char devpathBuf[64]; char *devpath = NULL; while ((usbInterface = IOIteratorNext(iterator))) { //* Create an intermediate interface plugin kr = IOCreatePlugInInterfaceForService(usbInterface, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, &plugInInterface, &score); IOObjectRelease(usbInterface); if ((kIOReturnSuccess != kr) || (!plugInInterface)) { DBG("ERR: Unable to create an interface plug-in (%08x)\n", kr); continue; } //* This gets us the interface object result = (*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID) &iface); //* We only needed the plugin to get the interface, so discard it (*plugInInterface)->Release(plugInInterface); if (result || !iface) { DBG("ERR: Couldn't query the interface (%08x)\n", (int) result); continue; } //* this gets us an ioservice, with which we will find the actual //* device; after getting a plugin, and querying the interface, of //* course. //* Gotta love OS X kr = (*iface)->GetDevice(iface, &usbDevice); if (kIOReturnSuccess != kr || !usbDevice) { DBG("ERR: Couldn't grab device from interface (%08x)\n", kr); continue; } plugInInterface = NULL; score = 0; //* create an intermediate device plugin kr = IOCreatePlugInInterfaceForService(usbDevice, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plugInInterface, &score); //* only needed this to find the plugin (void)IOObjectRelease(usbDevice); if ((kIOReturnSuccess != kr) || (!plugInInterface)) { DBG("ERR: Unable to create a device plug-in (%08x)\n", kr); continue; } result = (*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID) &dev); //* only needed this to query the plugin (*plugInInterface)->Release(plugInInterface); if (result || !dev) { DBG("ERR: Couldn't create a device interface (%08x)\n", (int) result); continue; } //* Now after all that, we actually have a ref to the device and //* the interface that matched our criteria kr = (*dev)->GetDeviceVendor(dev, &vendor); kr = (*dev)->GetDeviceProduct(dev, &product); kr = (*dev)->GetLocationID(dev, &locationId); if (kr == 0) { snprintf(devpathBuf, sizeof(devpathBuf), "usb:%lX", locationId); devpath = devpathBuf; } kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex); if (serialIndex > 0) { IOUSBDevRequest req; UInt16 buffer[256]; UInt16 languages[128]; memset(languages, 0, sizeof(languages)); req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice); req.bRequest = kUSBRqGetDescriptor; req.wValue = (kUSBStringDesc << 8) | 0; req.wIndex = 0; req.pData = languages; req.wLength = sizeof(languages); kr = (*dev)->DeviceRequest(dev, &req); if (kr == kIOReturnSuccess && req.wLenDone > 0) { int langCount = (req.wLenDone - 2) / 2, lang; for (lang = 1; lang <= langCount; lang++) { memset(buffer, 0, sizeof(buffer)); memset(&req, 0, sizeof(req)); req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice); req.bRequest = kUSBRqGetDescriptor; req.wValue = (kUSBStringDesc << 8) | serialIndex; req.wIndex = languages[lang]; req.pData = buffer; req.wLength = sizeof(buffer); kr = (*dev)->DeviceRequest(dev, &req); if (kr == kIOReturnSuccess && req.wLenDone > 0) { int i, count; // skip first word, and copy the rest to the serial string, // changing shorts to bytes. count = (req.wLenDone - 1) / 2; for (i = 0; i < count; i++) serial[i] = buffer[i + 1]; serial[i] = 0; break; } } } } (*dev)->Release(dev); DBG("INFO: Found vid=%04x pid=%04x serial=%s\n", vendor, product, serial); usb_handle* handle = CheckInterface((IOUSBInterfaceInterface**)iface, vendor, product); if (handle == NULL) { DBG("ERR: Could not find device interface: %08x\n", kr); (*iface)->Release(iface); continue; } DBG("AndroidDeviceAdded calling register_usb_transport\n"); register_usb_transport(handle, (serial[0] ? serial : NULL), devpath, 1); // Register for an interest notification of this device being removed. // Pass the reference to our private data as the refCon for the // notification. kr = IOServiceAddInterestNotification(notificationPort, usbInterface, kIOGeneralInterest, AndroidInterfaceNotify, handle, &handle->usbNotification); if (kIOReturnSuccess != kr) { DBG("ERR: Unable to create interest notification (%08x)\n", kr); } } } static void AndroidInterfaceNotify(void *refCon, io_service_t service, natural_t messageType, void *messageArgument) { usb_handle *handle = (usb_handle *)refCon; if (messageType == kIOMessageServiceIsTerminated) { if (!handle) { DBG("ERR: NULL handle\n"); return; } DBG("AndroidInterfaceNotify\n"); IOObjectRelease(handle->usbNotification); usb_kick(handle); } } //* TODO: simplify this further since we only register to get ADB interface //* subclass+protocol events static usb_handle* CheckInterface(IOUSBInterfaceInterface **interface, UInt16 vendor, UInt16 product) { usb_handle* handle = NULL; IOReturn kr; UInt8 interfaceNumEndpoints, interfaceClass, interfaceSubClass, interfaceProtocol; UInt8 endpoint; //* Now open the interface. This will cause the pipes associated with //* the endpoints in the interface descriptor to be instantiated kr = (*interface)->USBInterfaceOpen(interface); if (kr != kIOReturnSuccess) { DBG("ERR: Could not open interface: (%08x)\n", kr); return NULL; } //* Get the number of endpoints associated with this interface kr = (*interface)->GetNumEndpoints(interface, &interfaceNumEndpoints); if (kr != kIOReturnSuccess) { DBG("ERR: Unable to get number of endpoints: (%08x)\n", kr); goto err_get_num_ep; } //* Get interface class, subclass and protocol if ((*interface)->GetInterfaceClass(interface, &interfaceClass) != kIOReturnSuccess || (*interface)->GetInterfaceSubClass(interface, &interfaceSubClass) != kIOReturnSuccess || (*interface)->GetInterfaceProtocol(interface, &interfaceProtocol) != kIOReturnSuccess) { DBG("ERR: Unable to get interface class, subclass and protocol\n"); goto err_get_interface_class; } //* check to make sure interface class, subclass and protocol match ADB //* avoid opening mass storage endpoints if (!is_adb_interface(vendor, product, interfaceClass, interfaceSubClass, interfaceProtocol)) goto err_bad_adb_interface; handle = calloc(1, sizeof(usb_handle)); //* Iterate over the endpoints for this interface and find the first //* bulk in/out pipes available. These will be our read/write pipes. for (endpoint = 0; endpoint <= interfaceNumEndpoints; endpoint++) { UInt8 transferType; UInt16 maxPacketSize; UInt8 interval; UInt8 number; UInt8 direction; kr = (*interface)->GetPipeProperties(interface, endpoint, &direction, &number, &transferType, &maxPacketSize, &interval); if (kIOReturnSuccess == kr) { if (kUSBBulk != transferType) continue; if (kUSBIn == direction) handle->bulkIn = endpoint; if (kUSBOut == direction) handle->bulkOut = endpoint; handle->zero_mask = maxPacketSize - 1; } else { DBG("ERR: FindDeviceInterface - could not get pipe properties\n"); goto err_get_pipe_props; } } handle->interface = interface; return handle; err_get_pipe_props: free(handle); err_bad_adb_interface: err_get_interface_class: err_get_num_ep: (*interface)->USBInterfaceClose(interface); return NULL; } void* RunLoopThread(void* unused) { unsigned i; InitUSB(); currentRunLoop = CFRunLoopGetCurrent(); // Signal the parent that we are running adb_mutex_lock(&start_lock); adb_cond_signal(&start_cond); adb_mutex_unlock(&start_lock); CFRunLoopRun(); currentRunLoop = 0; for (i = 0; i < vendorIdCount; i++) { IOObjectRelease(notificationIterators[i]); } IONotificationPortDestroy(notificationPort); DBG("RunLoopThread done\n"); return NULL; } static int initialized = 0; void usb_init() { if (!initialized) { adb_thread_t tid; notificationIterators = (io_iterator_t*)malloc( vendorIdCount * sizeof(io_iterator_t)); adb_mutex_init(&start_lock, NULL); adb_cond_init(&start_cond, NULL); if(adb_thread_create(&tid, RunLoopThread, NULL)) fatal_errno("cannot create input thread"); // Wait for initialization to finish adb_mutex_lock(&start_lock); adb_cond_wait(&start_cond, &start_lock); adb_mutex_unlock(&start_lock); adb_mutex_destroy(&start_lock); adb_cond_destroy(&start_cond); initialized = 1; } } void usb_cleanup() { DBG("usb_cleanup\n"); close_usb_devices(); if (currentRunLoop) CFRunLoopStop(currentRunLoop); if (notificationIterators != NULL) { free(notificationIterators); notificationIterators = NULL; } } int usb_write(usb_handle *handle, const void *buf, int len) { IOReturn result; if (!len) return 0; if (!handle) return -1; if (NULL == handle->interface) { DBG("ERR: usb_write interface was null\n"); return -1; } if (0 == handle->bulkOut) { DBG("ERR: bulkOut endpoint not assigned\n"); return -1; } result = (*handle->interface)->WritePipe( handle->interface, handle->bulkOut, (void *)buf, len); if ((result == 0) && (handle->zero_mask)) { /* we need 0-markers and our transfer */ if(!(len & handle->zero_mask)) { result = (*handle->interface)->WritePipe( handle->interface, handle->bulkOut, (void *)buf, 0); } } if (0 == result) return 0; DBG("ERR: usb_write failed with status %d\n", result); return -1; } int usb_read(usb_handle *handle, void *buf, int len) { IOReturn result; UInt32 numBytes = len; if (!len) { return 0; } if (!handle) { return -1; } if (NULL == handle->interface) { DBG("ERR: usb_read interface was null\n"); return -1; } if (0 == handle->bulkIn) { DBG("ERR: bulkIn endpoint not assigned\n"); return -1; } result = (*handle->interface)->ReadPipe(handle->interface, handle->bulkIn, buf, &numBytes); if (kIOUSBPipeStalled == result) { DBG(" Pipe stalled, clearing stall.\n"); (*handle->interface)->ClearPipeStall(handle->interface, handle->bulkIn); result = (*handle->interface)->ReadPipe(handle->interface, handle->bulkIn, buf, &numBytes); } if (kIOReturnSuccess == result) return 0; else { DBG("ERR: usb_read failed with status %x\n", result); } return -1; } int usb_close(usb_handle *handle) { return 0; } void usb_kick(usb_handle *handle) { /* release the interface */ if (!handle) return; if (handle->interface) { (*handle->interface)->USBInterfaceClose(handle->interface); (*handle->interface)->Release(handle->interface); handle->interface = 0; } } android-tools-5.1.1r36+git20160322/core/adb/usb_vendors.c000077500000000000000000000252631267427243200224250ustar00rootroot00000000000000/* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "usb_vendors.h" #include #include #ifdef _WIN32 # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN # endif # include "windows.h" # include "shlobj.h" #else # include # include #endif #include "sysdeps.h" #include "adb.h" #define ANDROID_PATH ".android" #define ANDROID_ADB_INI "adb_usb.ini" #define TRACE_TAG TRACE_USB /* Keep the list below sorted alphabetically by #define name */ // Acer's USB Vendor ID #define VENDOR_ID_ACER 0x0502 // Allwinner's USB Vendor ID #define VENDOR_ID_ALLWINNER 0x1F3A // Amlogic's USB Vendor ID #define VENDOR_ID_AMLOGIC 0x1b8e // AnyDATA's USB Vendor ID #define VENDOR_ID_ANYDATA 0x16D5 // Archos's USB Vendor ID #define VENDOR_ID_ARCHOS 0x0E79 // Asus's USB Vendor ID #define VENDOR_ID_ASUS 0x0b05 // BYD's USB Vendor ID #define VENDOR_ID_BYD 0x1D91 // Compal's USB Vendor ID #define VENDOR_ID_COMPAL 0x04B7 // Compalcomm's USB Vendor ID #define VENDOR_ID_COMPALCOMM 0x1219 // Dell's USB Vendor ID #define VENDOR_ID_DELL 0x413c // ECS's USB Vendor ID #define VENDOR_ID_ECS 0x03fc // EMERGING_TECH's USB Vendor ID #define VENDOR_ID_EMERGING_TECH 0x297F // Emerson's USB Vendor ID #define VENDOR_ID_EMERSON 0x2207 // Foxconn's USB Vendor ID #define VENDOR_ID_FOXCONN 0x0489 // Fujitsu's USB Vendor ID #define VENDOR_ID_FUJITSU 0x04C5 // Funai's USB Vendor ID #define VENDOR_ID_FUNAI 0x0F1C // Garmin-Asus's USB Vendor ID #define VENDOR_ID_GARMIN_ASUS 0x091E // Gigabyte's USB Vendor ID #define VENDOR_ID_GIGABYTE 0x0414 // Gigaset's USB Vendor ID #define VENDOR_ID_GIGASET 0x1E85 // GIONEE's USB Vendor ID #define VENDOR_ID_GIONEE 0x271D // Google's USB Vendor ID #define VENDOR_ID_GOOGLE 0x18d1 // Haier's USB Vendor ID #define VENDOR_ID_HAIER 0x201E // Harris's USB Vendor ID #define VENDOR_ID_HARRIS 0x19A5 // Hisense's USB Vendor ID #define VENDOR_ID_HISENSE 0x109b // Honeywell's USB Vendor ID #define VENDOR_ID_HONEYWELL 0x0c2e // HP's USB Vendor ID #define VENDOR_ID_HP 0x03f0 // HTC's USB Vendor ID #define VENDOR_ID_HTC 0x0bb4 // Huawei's USB Vendor ID #define VENDOR_ID_HUAWEI 0x12D1 // INQ Mobile's USB Vendor ID #define VENDOR_ID_INQ_MOBILE 0x2314 // Intel's USB Vendor ID #define VENDOR_ID_INTEL 0x8087 // Intermec's USB Vendor ID #define VENDOR_ID_INTERMEC 0x067e // IRiver's USB Vendor ID #define VENDOR_ID_IRIVER 0x2420 // K-Touch's USB Vendor ID #define VENDOR_ID_K_TOUCH 0x24E3 // KT Tech's USB Vendor ID #define VENDOR_ID_KT_TECH 0x2116 // Kobo's USB Vendor ID #define VENDOR_ID_KOBO 0x2237 // Kyocera's USB Vendor ID #define VENDOR_ID_KYOCERA 0x0482 // Lab126's USB Vendor ID #define VENDOR_ID_LAB126 0x1949 // Lenovo's USB Vendor ID #define VENDOR_ID_LENOVO 0x17EF // LenovoMobile's USB Vendor ID #define VENDOR_ID_LENOVOMOBILE 0x2006 // LG's USB Vendor ID #define VENDOR_ID_LGE 0x1004 // Lumigon's USB Vendor ID #define VENDOR_ID_LUMIGON 0x25E3 // Motorola's USB Vendor ID #define VENDOR_ID_MOTOROLA 0x22b8 // MSI's USB Vendor ID #define VENDOR_ID_MSI 0x0DB0 // MTK's USB Vendor ID #define VENDOR_ID_MTK 0x0e8d // NEC's USB Vendor ID #define VENDOR_ID_NEC 0x0409 // B&N Nook's USB Vendor ID #define VENDOR_ID_NOOK 0x2080 // Nvidia's USB Vendor ID #define VENDOR_ID_NVIDIA 0x0955 // OPPO's USB Vendor ID #define VENDOR_ID_OPPO 0x22D9 // On-The-Go-Video's USB Vendor ID #define VENDOR_ID_OTGV 0x2257 // OUYA's USB Vendor ID #define VENDOR_ID_OUYA 0x2836 // Pantech's USB Vendor ID #define VENDOR_ID_PANTECH 0x10A9 // Pegatron's USB Vendor ID #define VENDOR_ID_PEGATRON 0x1D4D // Philips's USB Vendor ID #define VENDOR_ID_PHILIPS 0x0471 // Panasonic Mobile Communication's USB Vendor ID #define VENDOR_ID_PMC 0x04DA // Positivo's USB Vendor ID #define VENDOR_ID_POSITIVO 0x1662 // Prestigio's USB Vendor ID #define VENDOR_ID_PRESTIGIO 0x29e4 // Qisda's USB Vendor ID #define VENDOR_ID_QISDA 0x1D45 // Qualcomm's USB Vendor ID #define VENDOR_ID_QUALCOMM 0x05c6 // Quanta's USB Vendor ID #define VENDOR_ID_QUANTA 0x0408 // Rockchip's USB Vendor ID #define VENDOR_ID_ROCKCHIP 0x2207 // Samsung's USB Vendor ID #define VENDOR_ID_SAMSUNG 0x04e8 // Sharp's USB Vendor ID #define VENDOR_ID_SHARP 0x04dd // SK Telesys's USB Vendor ID #define VENDOR_ID_SK_TELESYS 0x1F53 // Smartisan's USB Vendor ID #define VENDOR_ID_SMARTISAN 0x29a9 // Sony's USB Vendor ID #define VENDOR_ID_SONY 0x054C // Sony Ericsson's USB Vendor ID #define VENDOR_ID_SONY_ERICSSON 0x0FCE // T & A Mobile Phones' USB Vendor ID #define VENDOR_ID_T_AND_A 0x1BBB // TechFaith's USB Vendor ID #define VENDOR_ID_TECHFAITH 0x1d09 // Teleepoch's USB Vendor ID #define VENDOR_ID_TELEEPOCH 0x2340 // Texas Instruments's USB Vendor ID #define VENDOR_ID_TI 0x0451 // Toshiba's USB Vendor ID #define VENDOR_ID_TOSHIBA 0x0930 // Unowhy's USB Vendor ID #define VENDOR_ID_UNOWHY 0x2A49 // Vizio's USB Vendor ID #define VENDOR_ID_VIZIO 0xE040 // Wacom's USB Vendor ID #define VENDOR_ID_WACOM 0x0531 // Xiaomi's USB Vendor ID #define VENDOR_ID_XIAOMI 0x2717 // YotaDevices's USB Vendor ID #define VENDOR_ID_YOTADEVICES 0x2916 // Yulong Coolpad's USB Vendor ID #define VENDOR_ID_YULONG_COOLPAD 0x1EBF // ZTE's USB Vendor ID #define VENDOR_ID_ZTE 0x19D2 /* Keep the list above sorted alphabetically by #define name */ /** built-in vendor list */ /* Keep the list below sorted alphabetically */ int builtInVendorIds[] = { VENDOR_ID_ACER, VENDOR_ID_ALLWINNER, VENDOR_ID_AMLOGIC, VENDOR_ID_ANYDATA, VENDOR_ID_ARCHOS, VENDOR_ID_ASUS, VENDOR_ID_BYD, VENDOR_ID_COMPAL, VENDOR_ID_COMPALCOMM, VENDOR_ID_DELL, VENDOR_ID_ECS, VENDOR_ID_EMERGING_TECH, VENDOR_ID_EMERSON, VENDOR_ID_FOXCONN, VENDOR_ID_FUJITSU, VENDOR_ID_FUNAI, VENDOR_ID_GARMIN_ASUS, VENDOR_ID_GIGABYTE, VENDOR_ID_GIGASET, VENDOR_ID_GIONEE, VENDOR_ID_GOOGLE, VENDOR_ID_HAIER, VENDOR_ID_HARRIS, VENDOR_ID_HISENSE, VENDOR_ID_HONEYWELL, VENDOR_ID_HP, VENDOR_ID_HTC, VENDOR_ID_HUAWEI, VENDOR_ID_INQ_MOBILE, VENDOR_ID_INTEL, VENDOR_ID_INTERMEC, VENDOR_ID_IRIVER, VENDOR_ID_KOBO, VENDOR_ID_K_TOUCH, VENDOR_ID_KT_TECH, VENDOR_ID_KYOCERA, VENDOR_ID_LAB126, VENDOR_ID_LENOVO, VENDOR_ID_LENOVOMOBILE, VENDOR_ID_LGE, VENDOR_ID_LUMIGON, VENDOR_ID_MOTOROLA, VENDOR_ID_MSI, VENDOR_ID_MTK, VENDOR_ID_NEC, VENDOR_ID_NOOK, VENDOR_ID_NVIDIA, VENDOR_ID_OPPO, VENDOR_ID_OTGV, VENDOR_ID_OUYA, VENDOR_ID_PANTECH, VENDOR_ID_PEGATRON, VENDOR_ID_PHILIPS, VENDOR_ID_PMC, VENDOR_ID_POSITIVO, VENDOR_ID_PRESTIGIO, VENDOR_ID_QISDA, VENDOR_ID_QUALCOMM, VENDOR_ID_QUANTA, VENDOR_ID_ROCKCHIP, VENDOR_ID_SAMSUNG, VENDOR_ID_SHARP, VENDOR_ID_SK_TELESYS, VENDOR_ID_SMARTISAN, VENDOR_ID_SONY, VENDOR_ID_SONY_ERICSSON, VENDOR_ID_T_AND_A, VENDOR_ID_TECHFAITH, VENDOR_ID_TELEEPOCH, VENDOR_ID_TI, VENDOR_ID_TOSHIBA, VENDOR_ID_UNOWHY, VENDOR_ID_VIZIO, VENDOR_ID_WACOM, VENDOR_ID_XIAOMI, VENDOR_ID_YOTADEVICES, VENDOR_ID_YULONG_COOLPAD, VENDOR_ID_ZTE, }; /* Keep the list above sorted alphabetically */ #define BUILT_IN_VENDOR_COUNT (sizeof(builtInVendorIds)/sizeof(builtInVendorIds[0])) /* max number of supported vendor ids (built-in + 3rd party). increase as needed */ #define VENDOR_COUNT_MAX 128 int vendorIds[VENDOR_COUNT_MAX]; unsigned vendorIdCount = 0; int get_adb_usb_ini(char* buff, size_t len); void usb_vendors_init(void) { if (VENDOR_COUNT_MAX < BUILT_IN_VENDOR_COUNT) { fprintf(stderr, "VENDOR_COUNT_MAX not big enough for built-in vendor list.\n"); exit(2); } /* add the built-in vendors at the beginning of the array */ memcpy(vendorIds, builtInVendorIds, sizeof(builtInVendorIds)); /* default array size is the number of built-in vendors */ vendorIdCount = BUILT_IN_VENDOR_COUNT; if (VENDOR_COUNT_MAX == BUILT_IN_VENDOR_COUNT) return; char temp[PATH_MAX]; if (get_adb_usb_ini(temp, sizeof(temp)) == 0) { FILE * f = fopen(temp, "rt"); if (f != NULL) { /* The vendor id file is pretty basic. 1 vendor id per line. Lines starting with # are comments */ while (fgets(temp, sizeof(temp), f) != NULL) { if (temp[0] == '#') continue; long value = strtol(temp, NULL, 0); if (errno == EINVAL || errno == ERANGE || value > INT_MAX || value < 0) { fprintf(stderr, "Invalid content in %s. Quitting.\n", ANDROID_ADB_INI); exit(2); } vendorIds[vendorIdCount++] = (int)value; /* make sure we don't go beyond the array */ if (vendorIdCount == VENDOR_COUNT_MAX) { break; } } fclose(f); } } } /* Utils methods */ /* builds the path to the adb vendor id file. returns 0 if success */ int build_path(char* buff, size_t len, const char* format, const char* home) { if (snprintf(buff, len, format, home, ANDROID_PATH, ANDROID_ADB_INI) >= (signed)len) { return 1; } return 0; } /* fills buff with the path to the adb vendor id file. returns 0 if success */ int get_adb_usb_ini(char* buff, size_t len) { #ifdef _WIN32 const char* home = getenv("ANDROID_SDK_HOME"); if (home != NULL) { return build_path(buff, len, "%s\\%s\\%s", home); } else { char path[MAX_PATH]; SHGetFolderPath( NULL, CSIDL_PROFILE, NULL, 0, path); return build_path(buff, len, "%s\\%s\\%s", path); } #else const char* home = getenv("HOME"); if (home == NULL) home = "/tmp"; return build_path(buff, len, "%s/%s/%s", home); #endif } android-tools-5.1.1r36+git20160322/core/adb/usb_vendors.h000066400000000000000000000013741267427243200224240ustar00rootroot00000000000000/* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef __USB_VENDORS_H #define __USB_VENDORS_H extern int vendorIds[]; extern unsigned vendorIdCount; void usb_vendors_init(void); #endif android-tools-5.1.1r36+git20160322/core/adb/usb_windows.c000066400000000000000000000335051267427243200224320ustar00rootroot00000000000000/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include "sysdeps.h" #define TRACE_TAG TRACE_USB #include "adb.h" /** Structure usb_handle describes our connection to the usb device via AdbWinApi.dll. This structure is returned from usb_open() routine and is expected in each subsequent call that is accessing the device. */ struct usb_handle { /// Previous entry in the list of opened usb handles usb_handle *prev; /// Next entry in the list of opened usb handles usb_handle *next; /// Handle to USB interface ADBAPIHANDLE adb_interface; /// Handle to USB read pipe (endpoint) ADBAPIHANDLE adb_read_pipe; /// Handle to USB write pipe (endpoint) ADBAPIHANDLE adb_write_pipe; /// Interface name char* interface_name; /// Mask for determining when to use zero length packets unsigned zero_mask; }; /// Class ID assigned to the device by androidusb.sys static const GUID usb_class_id = ANDROID_USB_CLASS_ID; /// List of opened usb handles static usb_handle handle_list = { .prev = &handle_list, .next = &handle_list, }; /// Locker for the list of opened usb handles ADB_MUTEX_DEFINE( usb_lock ); /// Checks if there is opened usb handle in handle_list for this device. int known_device(const char* dev_name); /// Checks if there is opened usb handle in handle_list for this device. /// usb_lock mutex must be held before calling this routine. int known_device_locked(const char* dev_name); /// Registers opened usb handle (adds it to handle_list). int register_new_device(usb_handle* handle); /// Checks if interface (device) matches certain criteria int recognized_device(usb_handle* handle); /// Enumerates present and available interfaces (devices), opens new ones and /// registers usb transport for them. void find_devices(); /// Entry point for thread that polls (every second) for new usb interfaces. /// This routine calls find_devices in infinite loop. void* device_poll_thread(void* unused); /// Initializes this module void usb_init(); /// Cleans up this module void usb_cleanup(); /// Opens usb interface (device) by interface (device) name. usb_handle* do_usb_open(const wchar_t* interface_name); /// Writes data to the opened usb handle int usb_write(usb_handle* handle, const void* data, int len); /// Reads data using the opened usb handle int usb_read(usb_handle *handle, void* data, int len); /// Cleans up opened usb handle void usb_cleanup_handle(usb_handle* handle); /// Cleans up (but don't close) opened usb handle void usb_kick(usb_handle* handle); /// Closes opened usb handle int usb_close(usb_handle* handle); /// Gets interface (device) name for an opened usb handle const char *usb_name(usb_handle* handle); int known_device_locked(const char* dev_name) { usb_handle* usb; if (NULL != dev_name) { // Iterate through the list looking for the name match. for(usb = handle_list.next; usb != &handle_list; usb = usb->next) { // In Windows names are not case sensetive! if((NULL != usb->interface_name) && (0 == stricmp(usb->interface_name, dev_name))) { return 1; } } } return 0; } int known_device(const char* dev_name) { int ret = 0; if (NULL != dev_name) { adb_mutex_lock(&usb_lock); ret = known_device_locked(dev_name); adb_mutex_unlock(&usb_lock); } return ret; } int register_new_device(usb_handle* handle) { if (NULL == handle) return 0; adb_mutex_lock(&usb_lock); // Check if device is already in the list if (known_device_locked(handle->interface_name)) { adb_mutex_unlock(&usb_lock); return 0; } // Not in the list. Add this handle to the list. handle->next = &handle_list; handle->prev = handle_list.prev; handle->prev->next = handle; handle->next->prev = handle; adb_mutex_unlock(&usb_lock); return 1; } void* device_poll_thread(void* unused) { D("Created device thread\n"); while(1) { find_devices(); adb_sleep_ms(1000); } return NULL; } void usb_init() { adb_thread_t tid; if(adb_thread_create(&tid, device_poll_thread, NULL)) { fatal_errno("cannot create input thread"); } } void usb_cleanup() { } usb_handle* do_usb_open(const wchar_t* interface_name) { // Allocate our handle usb_handle* ret = (usb_handle*)malloc(sizeof(usb_handle)); if (NULL == ret) return NULL; // Set linkers back to the handle ret->next = ret; ret->prev = ret; // Create interface. ret->adb_interface = AdbCreateInterfaceByName(interface_name); if (NULL == ret->adb_interface) { free(ret); errno = GetLastError(); return NULL; } // Open read pipe (endpoint) ret->adb_read_pipe = AdbOpenDefaultBulkReadEndpoint(ret->adb_interface, AdbOpenAccessTypeReadWrite, AdbOpenSharingModeReadWrite); if (NULL != ret->adb_read_pipe) { // Open write pipe (endpoint) ret->adb_write_pipe = AdbOpenDefaultBulkWriteEndpoint(ret->adb_interface, AdbOpenAccessTypeReadWrite, AdbOpenSharingModeReadWrite); if (NULL != ret->adb_write_pipe) { // Save interface name unsigned long name_len = 0; // First get expected name length AdbGetInterfaceName(ret->adb_interface, NULL, &name_len, true); if (0 != name_len) { ret->interface_name = (char*)malloc(name_len); if (NULL != ret->interface_name) { // Now save the name if (AdbGetInterfaceName(ret->adb_interface, ret->interface_name, &name_len, true)) { // We're done at this point return ret; } } else { SetLastError(ERROR_OUTOFMEMORY); } } } } // Something went wrong. int saved_errno = GetLastError(); usb_cleanup_handle(ret); free(ret); SetLastError(saved_errno); return NULL; } int usb_write(usb_handle* handle, const void* data, int len) { unsigned long time_out = 5000; unsigned long written = 0; int ret; D("usb_write %d\n", len); if (NULL != handle) { // Perform write ret = AdbWriteEndpointSync(handle->adb_write_pipe, (void*)data, (unsigned long)len, &written, time_out); int saved_errno = GetLastError(); if (ret) { // Make sure that we've written what we were asked to write D("usb_write got: %ld, expected: %d\n", written, len); if (written == (unsigned long)len) { if(handle->zero_mask && (len & handle->zero_mask) == 0) { // Send a zero length packet AdbWriteEndpointSync(handle->adb_write_pipe, (void*)data, 0, &written, time_out); } return 0; } } else { // assume ERROR_INVALID_HANDLE indicates we are disconnected if (saved_errno == ERROR_INVALID_HANDLE) usb_kick(handle); } errno = saved_errno; } else { D("usb_write NULL handle\n"); SetLastError(ERROR_INVALID_HANDLE); } D("usb_write failed: %d\n", errno); return -1; } int usb_read(usb_handle *handle, void* data, int len) { unsigned long time_out = 0; unsigned long read = 0; int ret; D("usb_read %d\n", len); if (NULL != handle) { while (len > 0) { int xfer = (len > 4096) ? 4096 : len; ret = AdbReadEndpointSync(handle->adb_read_pipe, data, (unsigned long)xfer, &read, time_out); int saved_errno = GetLastError(); D("usb_write got: %ld, expected: %d, errno: %d\n", read, xfer, saved_errno); if (ret) { data = (char *)data + read; len -= read; if (len == 0) return 0; } else { // assume ERROR_INVALID_HANDLE indicates we are disconnected if (saved_errno == ERROR_INVALID_HANDLE) usb_kick(handle); break; } errno = saved_errno; } } else { D("usb_read NULL handle\n"); SetLastError(ERROR_INVALID_HANDLE); } D("usb_read failed: %d\n", errno); return -1; } void usb_cleanup_handle(usb_handle* handle) { if (NULL != handle) { if (NULL != handle->interface_name) free(handle->interface_name); if (NULL != handle->adb_write_pipe) AdbCloseHandle(handle->adb_write_pipe); if (NULL != handle->adb_read_pipe) AdbCloseHandle(handle->adb_read_pipe); if (NULL != handle->adb_interface) AdbCloseHandle(handle->adb_interface); handle->interface_name = NULL; handle->adb_write_pipe = NULL; handle->adb_read_pipe = NULL; handle->adb_interface = NULL; } } void usb_kick(usb_handle* handle) { if (NULL != handle) { adb_mutex_lock(&usb_lock); usb_cleanup_handle(handle); adb_mutex_unlock(&usb_lock); } else { SetLastError(ERROR_INVALID_HANDLE); errno = ERROR_INVALID_HANDLE; } } int usb_close(usb_handle* handle) { D("usb_close\n"); if (NULL != handle) { // Remove handle from the list adb_mutex_lock(&usb_lock); if ((handle->next != handle) && (handle->prev != handle)) { handle->next->prev = handle->prev; handle->prev->next = handle->next; handle->prev = handle; handle->next = handle; } adb_mutex_unlock(&usb_lock); // Cleanup handle usb_cleanup_handle(handle); free(handle); } return 0; } const char *usb_name(usb_handle* handle) { if (NULL == handle) { SetLastError(ERROR_INVALID_HANDLE); errno = ERROR_INVALID_HANDLE; return NULL; } return (const char*)handle->interface_name; } int recognized_device(usb_handle* handle) { if (NULL == handle) return 0; // Check vendor and product id first USB_DEVICE_DESCRIPTOR device_desc; if (!AdbGetUsbDeviceDescriptor(handle->adb_interface, &device_desc)) { return 0; } // Then check interface properties USB_INTERFACE_DESCRIPTOR interf_desc; if (!AdbGetUsbInterfaceDescriptor(handle->adb_interface, &interf_desc)) { return 0; } // Must have two endpoints if (2 != interf_desc.bNumEndpoints) { return 0; } if (is_adb_interface(device_desc.idVendor, device_desc.idProduct, interf_desc.bInterfaceClass, interf_desc.bInterfaceSubClass, interf_desc.bInterfaceProtocol)) { if(interf_desc.bInterfaceProtocol == 0x01) { AdbEndpointInformation endpoint_info; // assuming zero is a valid bulk endpoint ID if (AdbGetEndpointInformation(handle->adb_interface, 0, &endpoint_info)) { handle->zero_mask = endpoint_info.max_packet_size - 1; } } return 1; } return 0; } void find_devices() { usb_handle* handle = NULL; char entry_buffer[2048]; char interf_name[2048]; AdbInterfaceInfo* next_interface = (AdbInterfaceInfo*)(&entry_buffer[0]); unsigned long entry_buffer_size = sizeof(entry_buffer); char* copy_name; // Enumerate all present and active interfaces. ADBAPIHANDLE enum_handle = AdbEnumInterfaces(usb_class_id, true, true, true); if (NULL == enum_handle) return; while (AdbNextInterface(enum_handle, next_interface, &entry_buffer_size)) { // TODO: FIXME - temp hack converting wchar_t into char. // It would be better to change AdbNextInterface so it will return // interface name as single char string. const wchar_t* wchar_name = next_interface->device_name; for(copy_name = interf_name; L'\0' != *wchar_name; wchar_name++, copy_name++) { *copy_name = (char)(*wchar_name); } *copy_name = '\0'; // Lets see if we already have this device in the list if (!known_device(interf_name)) { // This seems to be a new device. Open it! handle = do_usb_open(next_interface->device_name); if (NULL != handle) { // Lets see if this interface (device) belongs to us if (recognized_device(handle)) { D("adding a new device %s\n", interf_name); char serial_number[512]; unsigned long serial_number_len = sizeof(serial_number); if (AdbGetSerialNumber(handle->adb_interface, serial_number, &serial_number_len, true)) { // Lets make sure that we don't duplicate this device if (register_new_device(handle)) { register_usb_transport(handle, serial_number, NULL, 1); } else { D("register_new_device failed for %s\n", interf_name); usb_cleanup_handle(handle); free(handle); } } else { D("cannot get serial number\n"); usb_cleanup_handle(handle); free(handle); } } else { usb_cleanup_handle(handle); free(handle); } } } entry_buffer_size = sizeof(entry_buffer); } AdbCloseHandle(enum_handle); } android-tools-5.1.1r36+git20160322/core/fastboot/000077500000000000000000000000001267427243200210105ustar00rootroot00000000000000android-tools-5.1.1r36+git20160322/core/fastboot/Android.mk000066400000000000000000000052521267427243200227250ustar00rootroot00000000000000# Copyright (C) 2007 Google Inc. # # 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. LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_C_INCLUDES := $(LOCAL_PATH)/../mkbootimg \ $(LOCAL_PATH)/../../extras/ext4_utils \ $(LOCAL_PATH)/../../extras/f2fs_utils LOCAL_SRC_FILES := protocol.c engine.c bootimg.c fastboot.c util.c fs.c LOCAL_MODULE := fastboot LOCAL_MODULE_TAGS := debug LOCAL_CFLAGS += -std=gnu99 -Werror ifeq ($(HOST_OS),linux) LOCAL_SRC_FILES += usb_linux.c util_linux.c endif ifeq ($(HOST_OS),darwin) LOCAL_SRC_FILES += usb_osx.c util_osx.c LOCAL_LDLIBS += -lpthread -framework CoreFoundation -framework IOKit \ -framework Carbon endif ifeq ($(HOST_OS),windows) LOCAL_SRC_FILES += usb_windows.c util_windows.c EXTRA_STATIC_LIBS := AdbWinApi ifneq ($(strip $(USE_CYGWIN)),) # Pure cygwin case LOCAL_LDLIBS += -lpthread endif ifneq ($(strip $(USE_MINGW)),) # MinGW under Linux case LOCAL_LDLIBS += -lws2_32 USE_SYSDEPS_WIN32 := 1 endif LOCAL_C_INCLUDES += development/host/windows/usb/api endif LOCAL_STATIC_LIBRARIES := \ $(EXTRA_STATIC_LIBS) \ libzipfile \ libunz \ libext4_utils_host \ libsparse_host \ libz ifneq ($(HOST_OS),windows) LOCAL_STATIC_LIBRARIES += libselinux endif # HOST_OS != windows ifeq ($(HOST_OS),linux) # libf2fs_dlutils_host will dlopen("libf2fs_fmt_host_dyn") LOCAL_CFLAGS += -DUSE_F2FS LOCAL_LDFLAGS += -ldl -rdynamic -Wl,-rpath,. LOCAL_REQUIRED_MODULES := libf2fs_fmt_host_dyn # The following libf2fs_* are from system/extras/f2fs_utils, # and do not use code in external/f2fs-tools. LOCAL_STATIC_LIBRARIES += libf2fs_utils_host libf2fs_ioutils_host libf2fs_dlutils_host endif include $(BUILD_HOST_EXECUTABLE) my_dist_files := $(LOCAL_BUILT_MODULE) ifeq ($(HOST_OS),linux) my_dist_files += $(HOST_LIBRARY_PATH)/libf2fs_fmt_host_dyn$(HOST_SHLIB_SUFFIX) endif $(call dist-for-goals,dist_files sdk,$(my_dist_files)) my_dist_files := ifeq ($(HOST_OS),linux) include $(CLEAR_VARS) LOCAL_SRC_FILES := usbtest.c usb_linux.c util.c LOCAL_MODULE := usbtest LOCAL_CFLAGS := -Werror include $(BUILD_HOST_EXECUTABLE) endif ifeq ($(HOST_OS),windows) $(LOCAL_INSTALLED_MODULE): $(HOST_OUT_EXECUTABLES)/AdbWinApi.dll endif android-tools-5.1.1r36+git20160322/core/fastboot/bootimg.c000066400000000000000000000061231267427243200226160ustar00rootroot00000000000000/* * Copyright (C) 2008 The Android Open Source Project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include void bootimg_set_cmdline(boot_img_hdr *h, const char *cmdline) { strcpy((char*) h->cmdline, cmdline); } boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size, unsigned kernel_offset, void *ramdisk, unsigned ramdisk_size, unsigned ramdisk_offset, void *second, unsigned second_size, unsigned second_offset, unsigned page_size, unsigned base, unsigned tags_offset, unsigned *bootimg_size) { unsigned kernel_actual; unsigned ramdisk_actual; unsigned second_actual; unsigned page_mask; boot_img_hdr *hdr; page_mask = page_size - 1; kernel_actual = (kernel_size + page_mask) & (~page_mask); ramdisk_actual = (ramdisk_size + page_mask) & (~page_mask); second_actual = (second_size + page_mask) & (~page_mask); *bootimg_size = page_size + kernel_actual + ramdisk_actual + second_actual; hdr = calloc(*bootimg_size, 1); if(hdr == 0) { return hdr; } memcpy(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE); hdr->kernel_size = kernel_size; hdr->ramdisk_size = ramdisk_size; hdr->second_size = second_size; hdr->kernel_addr = base + kernel_offset; hdr->ramdisk_addr = base + ramdisk_offset; hdr->second_addr = base + second_offset; hdr->tags_addr = base + tags_offset; hdr->page_size = page_size; memcpy(hdr->magic + page_size, kernel, kernel_size); memcpy(hdr->magic + page_size + kernel_actual, ramdisk, ramdisk_size); memcpy(hdr->magic + page_size + kernel_actual + ramdisk_actual, second, second_size); return hdr; } android-tools-5.1.1r36+git20160322/core/fastboot/engine.c000066400000000000000000000247261267427243200224340ustar00rootroot00000000000000/* * Copyright (C) 2008 The Android Open Source Project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "fastboot.h" #include "fs.h" #include #include #include #include #include #include #include #include #include #ifdef USE_MINGW #include #else #include #endif #ifndef __unused #define __unused __attribute__((__unused__)) #endif #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) #define OP_DOWNLOAD 1 #define OP_COMMAND 2 #define OP_QUERY 3 #define OP_NOTICE 4 #define OP_DOWNLOAD_SPARSE 5 #define OP_WAIT_FOR_DISCONNECT 6 typedef struct Action Action; #define CMD_SIZE 64 struct Action { unsigned op; Action *next; char cmd[CMD_SIZE]; const char *prod; void *data; unsigned size; const char *msg; int (*func)(Action *a, int status, char *resp); double start; }; static Action *action_list = 0; static Action *action_last = 0; int fb_getvar(struct usb_handle *usb, char *response, const char *fmt, ...) { char cmd[CMD_SIZE] = "getvar:"; int getvar_len = strlen(cmd); va_list args; response[FB_RESPONSE_SZ] = '\0'; va_start(args, fmt); vsnprintf(cmd + getvar_len, sizeof(cmd) - getvar_len, fmt, args); va_end(args); cmd[CMD_SIZE - 1] = '\0'; return fb_command_response(usb, cmd, response); } /* Return true if this partition is supported by the fastboot format command. * It is also used to determine if we should first erase a partition before * flashing it with an ext4 filesystem. See needs_erase() * * Not all devices report the filesystem type, so don't report any errors, * just return false. */ int fb_format_supported(usb_handle *usb, const char *partition, const char *type_override) { char fs_type[FB_RESPONSE_SZ + 1] = {0,}; int status; if (type_override) { return !!fs_get_generator(type_override); } status = fb_getvar(usb, fs_type, "partition-type:%s", partition); if (status) { return 0; } return !!fs_get_generator(fs_type); } static int cb_default(Action *a, int status, char *resp) { if (status) { fprintf(stderr,"FAILED (%s)\n", resp); } else { double split = now(); fprintf(stderr,"OKAY [%7.3fs]\n", (split - a->start)); a->start = split; } return status; } static Action *queue_action(unsigned op, const char *fmt, ...) { Action *a; va_list ap; size_t cmdsize; a = calloc(1, sizeof(Action)); if (a == 0) die("out of memory"); va_start(ap, fmt); cmdsize = vsnprintf(a->cmd, sizeof(a->cmd), fmt, ap); va_end(ap); if (cmdsize >= sizeof(a->cmd)) { free(a); die("Command length (%d) exceeds maximum size (%d)", cmdsize, sizeof(a->cmd)); } if (action_last) { action_last->next = a; } else { action_list = a; } action_last = a; a->op = op; a->func = cb_default; a->start = -1; return a; } void fb_queue_erase(const char *ptn) { Action *a; a = queue_action(OP_COMMAND, "erase:%s", ptn); a->msg = mkmsg("erasing '%s'", ptn); } void fb_queue_flash(const char *ptn, void *data, unsigned sz) { Action *a; a = queue_action(OP_DOWNLOAD, ""); a->data = data; a->size = sz; a->msg = mkmsg("sending '%s' (%d KB)", ptn, sz / 1024); a = queue_action(OP_COMMAND, "flash:%s", ptn); a->msg = mkmsg("writing '%s'", ptn); } void fb_queue_flash_sparse(const char *ptn, struct sparse_file *s, unsigned sz) { Action *a; a = queue_action(OP_DOWNLOAD_SPARSE, ""); a->data = s; a->size = 0; a->msg = mkmsg("sending sparse '%s' (%d KB)", ptn, sz / 1024); a = queue_action(OP_COMMAND, "flash:%s", ptn); a->msg = mkmsg("writing '%s'", ptn); } static int match(char *str, const char **value, unsigned count) { unsigned n; for (n = 0; n < count; n++) { const char *val = value[n]; int len = strlen(val); int match; if ((len > 1) && (val[len-1] == '*')) { len--; match = !strncmp(val, str, len); } else { match = !strcmp(val, str); } if (match) return 1; } return 0; } static int cb_check(Action *a, int status, char *resp, int invert) { const char **value = a->data; unsigned count = a->size; unsigned n; int yes; if (status) { fprintf(stderr,"FAILED (%s)\n", resp); return status; } if (a->prod) { if (strcmp(a->prod, cur_product) != 0) { double split = now(); fprintf(stderr,"IGNORE, product is %s required only for %s [%7.3fs]\n", cur_product, a->prod, (split - a->start)); a->start = split; return 0; } } yes = match(resp, value, count); if (invert) yes = !yes; if (yes) { double split = now(); fprintf(stderr,"OKAY [%7.3fs]\n", (split - a->start)); a->start = split; return 0; } fprintf(stderr,"FAILED\n\n"); fprintf(stderr,"Device %s is '%s'.\n", a->cmd + 7, resp); fprintf(stderr,"Update %s '%s'", invert ? "rejects" : "requires", value[0]); for (n = 1; n < count; n++) { fprintf(stderr," or '%s'", value[n]); } fprintf(stderr,".\n\n"); return -1; } static int cb_require(Action *a, int status, char *resp) { return cb_check(a, status, resp, 0); } static int cb_reject(Action *a, int status, char *resp) { return cb_check(a, status, resp, 1); } void fb_queue_require(const char *prod, const char *var, int invert, unsigned nvalues, const char **value) { Action *a; a = queue_action(OP_QUERY, "getvar:%s", var); a->prod = prod; a->data = value; a->size = nvalues; a->msg = mkmsg("checking %s", var); a->func = invert ? cb_reject : cb_require; if (a->data == 0) die("out of memory"); } static int cb_display(Action *a, int status, char *resp) { if (status) { fprintf(stderr, "%s FAILED (%s)\n", a->cmd, resp); return status; } fprintf(stderr, "%s: %s\n", (char*) a->data, resp); return 0; } void fb_queue_display(const char *var, const char *prettyname) { Action *a; a = queue_action(OP_QUERY, "getvar:%s", var); a->data = strdup(prettyname); if (a->data == 0) die("out of memory"); a->func = cb_display; } static int cb_save(Action *a, int status, char *resp) { if (status) { fprintf(stderr, "%s FAILED (%s)\n", a->cmd, resp); return status; } strncpy(a->data, resp, a->size); return 0; } void fb_queue_query_save(const char *var, char *dest, unsigned dest_size) { Action *a; a = queue_action(OP_QUERY, "getvar:%s", var); a->data = (void *)dest; a->size = dest_size; a->func = cb_save; } static int cb_do_nothing(Action *a __unused, int status __unused, char *resp __unused) { fprintf(stderr,"\n"); return 0; } void fb_queue_reboot(void) { Action *a = queue_action(OP_COMMAND, "reboot"); a->func = cb_do_nothing; a->msg = "rebooting"; } void fb_queue_command(const char *cmd, const char *msg) { Action *a = queue_action(OP_COMMAND, cmd); a->msg = msg; } void fb_queue_download(const char *name, void *data, unsigned size) { Action *a = queue_action(OP_DOWNLOAD, ""); a->data = data; a->size = size; a->msg = mkmsg("downloading '%s'", name); } void fb_queue_notice(const char *notice) { Action *a = queue_action(OP_NOTICE, ""); a->data = (void*) notice; } void fb_queue_wait_for_disconnect(void) { queue_action(OP_WAIT_FOR_DISCONNECT, ""); } int fb_execute_queue(usb_handle *usb) { Action *a; char resp[FB_RESPONSE_SZ+1]; int status = 0; a = action_list; if (!a) return status; resp[FB_RESPONSE_SZ] = 0; double start = -1; for (a = action_list; a; a = a->next) { a->start = now(); if (start < 0) start = a->start; if (a->msg) { // fprintf(stderr,"%30s... ",a->msg); fprintf(stderr,"%s...\n",a->msg); } if (a->op == OP_DOWNLOAD) { status = fb_download_data(usb, a->data, a->size); status = a->func(a, status, status ? fb_get_error() : ""); if (status) break; } else if (a->op == OP_COMMAND) { status = fb_command(usb, a->cmd); status = a->func(a, status, status ? fb_get_error() : ""); if (status) break; } else if (a->op == OP_QUERY) { status = fb_command_response(usb, a->cmd, resp); status = a->func(a, status, status ? fb_get_error() : resp); if (status) break; } else if (a->op == OP_NOTICE) { fprintf(stderr,"%s\n",(char*)a->data); } else if (a->op == OP_DOWNLOAD_SPARSE) { status = fb_download_data_sparse(usb, a->data); status = a->func(a, status, status ? fb_get_error() : ""); if (status) break; } else if (a->op == OP_WAIT_FOR_DISCONNECT) { usb_wait_for_disconnect(usb); } else { die("bogus action"); } } fprintf(stderr,"finished. total time: %.3fs\n", (now() - start)); return status; } int fb_queue_is_empty(void) { return (action_list == NULL); } android-tools-5.1.1r36+git20160322/core/fastboot/fastboot.c000066400000000000000000001054021267427243200227770ustar00rootroot00000000000000/* * Copyright (C) 2008 The Android Open Source Project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #define _LARGEFILE64_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "fastboot.h" #include "fs.h" #ifndef O_BINARY #define O_BINARY 0 #endif #define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a))) char cur_product[FB_RESPONSE_SZ + 1]; void bootimg_set_cmdline(boot_img_hdr *h, const char *cmdline); boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size, unsigned kernel_offset, void *ramdisk, unsigned ramdisk_size, unsigned ramdisk_offset, void *second, unsigned second_size, unsigned second_offset, unsigned page_size, unsigned base, unsigned tags_offset, unsigned *bootimg_size); static usb_handle *usb = 0; static const char *serial = 0; static const char *product = 0; static const char *cmdline = 0; static unsigned short vendor_id = 0; static int long_listing = 0; static int64_t sparse_limit = -1; static int64_t target_sparse_limit = -1; unsigned page_size = 2048; unsigned base_addr = 0x10000000; unsigned kernel_offset = 0x00008000; unsigned ramdisk_offset = 0x01000000; unsigned second_offset = 0x00f00000; unsigned tags_offset = 0x00000100; enum fb_buffer_type { FB_BUFFER, FB_BUFFER_SPARSE, }; struct fastboot_buffer { enum fb_buffer_type type; void *data; unsigned int sz; }; static struct { char img_name[13]; char sig_name[13]; char part_name[9]; bool is_optional; } images[] = { {"boot.img", "boot.sig", "boot", false}, {"recovery.img", "recovery.sig", "recovery", true}, {"system.img", "system.sig", "system", false}, {"vendor.img", "vendor.sig", "vendor", true}, }; void get_my_path(char *path); char *find_item(const char *item, const char *product) { char *dir; char *fn; char path[PATH_MAX + 128]; if(!strcmp(item,"boot")) { fn = "boot.img"; } else if(!strcmp(item,"recovery")) { fn = "recovery.img"; } else if(!strcmp(item,"system")) { fn = "system.img"; } else if(!strcmp(item,"vendor")) { fn = "vendor.img"; } else if(!strcmp(item,"userdata")) { fn = "userdata.img"; } else if(!strcmp(item,"cache")) { fn = "cache.img"; } else if(!strcmp(item,"info")) { fn = "android-info.txt"; } else { fprintf(stderr,"unknown partition '%s'\n", item); return 0; } if(product) { get_my_path(path); sprintf(path + strlen(path), "../../../target/product/%s/%s", product, fn); return strdup(path); } dir = getenv("ANDROID_PRODUCT_OUT"); if((dir == 0) || (dir[0] == 0)) { die("neither -p product specified nor ANDROID_PRODUCT_OUT set"); return 0; } sprintf(path, "%s/%s", dir, fn); return strdup(path); } static int64_t file_size(int fd) { struct stat st; int ret; ret = fstat(fd, &st); return ret ? -1 : st.st_size; } static void *load_fd(int fd, unsigned *_sz) { char *data; int sz; int errno_tmp; data = 0; sz = file_size(fd); if (sz < 0) { goto oops; } data = (char*) malloc(sz); if(data == 0) goto oops; if(read(fd, data, sz) != sz) goto oops; close(fd); if(_sz) *_sz = sz; return data; oops: errno_tmp = errno; close(fd); if(data != 0) free(data); errno = errno_tmp; return 0; } static void *load_file(const char *fn, unsigned *_sz) { int fd; fd = open(fn, O_RDONLY | O_BINARY); if(fd < 0) return 0; return load_fd(fd, _sz); } int match_fastboot_with_serial(usb_ifc_info *info, const char *local_serial) { if(!(vendor_id && (info->dev_vendor == vendor_id)) && (info->dev_vendor != 0x18d1) && // Google (info->dev_vendor != 0x8087) && // Intel (info->dev_vendor != 0x0451) && (info->dev_vendor != 0x0502) && (info->dev_vendor != 0x0fce) && // Sony Ericsson (info->dev_vendor != 0x05c6) && // Qualcomm (info->dev_vendor != 0x22b8) && // Motorola (info->dev_vendor != 0x0955) && // Nvidia (info->dev_vendor != 0x413c) && // DELL (info->dev_vendor != 0x2314) && // INQ Mobile (info->dev_vendor != 0x0b05) && // Asus (info->dev_vendor != 0x0bb4)) // HTC return -1; if(info->ifc_class != 0xff) return -1; if(info->ifc_subclass != 0x42) return -1; if(info->ifc_protocol != 0x03) return -1; // require matching serial number or device path if requested // at the command line with the -s option. if (local_serial && (strcmp(local_serial, info->serial_number) != 0 && strcmp(local_serial, info->device_path) != 0)) return -1; return 0; } int match_fastboot(usb_ifc_info *info) { return match_fastboot_with_serial(info, serial); } int list_devices_callback(usb_ifc_info *info) { if (match_fastboot_with_serial(info, NULL) == 0) { char* serial = info->serial_number; if (!info->writable) { serial = "no permissions"; // like "adb devices" } if (!serial[0]) { serial = "????????????"; } // output compatible with "adb devices" if (!long_listing) { printf("%s\tfastboot\n", serial); } else if (!info->device_path) { printf("%-22s fastboot\n", serial); } else { printf("%-22s fastboot %s\n", serial, info->device_path); } } return -1; } usb_handle *open_device(void) { static usb_handle *usb = 0; int announce = 1; if(usb) return usb; for(;;) { usb = usb_open(match_fastboot); if(usb) return usb; if(announce) { announce = 0; fprintf(stderr,"< waiting for device >\n"); } usleep(1000); } } void list_devices(void) { // We don't actually open a USB device here, // just getting our callback called so we can // list all the connected devices. usb_open(list_devices_callback); } void usage(void) { fprintf(stderr, /* 1234567890123456789012345678901234567890123456789012345678901234567890123456 */ "usage: fastboot [