diff --git a/adb/.clang-format b/adb/.clang-format deleted file mode 120000 index 1af4f51dd79a9722446d986554c14e3245158c8a..0000000000000000000000000000000000000000 --- a/adb/.clang-format +++ /dev/null @@ -1 +0,0 @@ -../.clang-format-4 \ No newline at end of file diff --git a/adb/Android.bp b/adb/Android.bp deleted file mode 100644 index dee48bf80f7e0c8b734d5c897d43ec1ce43963df..0000000000000000000000000000000000000000 --- a/adb/Android.bp +++ /dev/null @@ -1,821 +0,0 @@ -// Copyright (C) 2017 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. - -cc_defaults { - name: "adb_defaults", - - cflags: [ - "-Wall", - "-Wextra", - "-Werror", - "-Wexit-time-destructors", - "-Wno-unused-parameter", - "-Wno-missing-field-initializers", - "-Wthread-safety", - "-Wvla", - "-DADB_HOST=1", // overridden by adbd_defaults - "-DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION=1", - ], - cpp_std: "experimental", - - use_version_lib: true, - compile_multilib: "first", - - target: { - darwin: { - host_ldlibs: [ - "-lpthread", - "-framework CoreFoundation", - "-framework IOKit", - "-lobjc", - ], - }, - - windows: { - cflags: [ - // Define windows.h and tchar.h Unicode preprocessor symbols so that - // CreateFile(), _tfopen(), etc. map to versions that take wchar_t*, breaking the - // build if you accidentally pass char*. Fix by calling like: - // std::wstring path_wide; - // if (!android::base::UTF8ToWide(path_utf8, &path_wide)) { /* error handling */ } - // CreateFileW(path_wide.c_str()); - "-DUNICODE=1", - "-D_UNICODE=1", - - // Unlike on Linux, -std=gnu++ doesn't set _GNU_SOURCE on Windows. - "-D_GNU_SOURCE", - - // MinGW hides some things behind _POSIX_SOURCE. - "-D_POSIX_SOURCE", - - // libusb uses __stdcall on a variadic function, which gets ignored. - "-Wno-ignored-attributes", - - // Not supported yet. - "-Wno-thread-safety", - ], - - host_ldlibs: [ - "-lws2_32", - "-lgdi32", - "-luserenv", - ], - }, - }, -} - -cc_defaults { - name: "adbd_defaults", - defaults: ["adb_defaults"], - - cflags: ["-UADB_HOST", "-DADB_HOST=0"], -} - -cc_defaults { - name: "host_adbd_supported", - - host_supported: true, - target: { - linux: { - enabled: true, - host_ldlibs: [ - "-lresolv", // b64_pton - "-lutil", // forkpty - ], - }, - darwin: { - enabled: false, - }, - windows: { - enabled: false, - }, - }, -} - -cc_defaults { - name: "libadbd_binary_dependencies", - static_libs: [ - "libadb_crypto", - "libadb_pairing_connection", - "libadb_tls_connection", - "libadbd", - "libadbd_core", - "libadbconnection_server", - "libasyncio", - "libbrotli", - "libcutils_sockets", - "libdiagnose_usb", - "libmdnssd", - "libbase", - - "libadb_protos", - ], - - shared_libs: [ - "libadbd_auth", - "libadbd_fs", - "libcrypto", - "libcrypto_utils", - "liblog", - "libselinux", - ], - - target: { - recovery: { - exclude_static_libs: [ - "libadb_pairing_auth", - "libadb_pairing_connection", - ], - }, - }, -} - -// libadb -// ========================================================= -// These files are compiled for both the host and the device. -libadb_srcs = [ - "adb.cpp", - "adb_io.cpp", - "adb_listeners.cpp", - "adb_trace.cpp", - "adb_unique_fd.cpp", - "adb_utils.cpp", - "fdevent/fdevent.cpp", - "fdevent/fdevent_poll.cpp", - "services.cpp", - "sockets.cpp", - "socket_spec.cpp", - "sysdeps/errno.cpp", - "transport.cpp", - "transport_fd.cpp", - "transport_local.cpp", - "types.cpp", -] - -libadb_posix_srcs = [ - "sysdeps_unix.cpp", - "sysdeps/posix/network.cpp", -] - -libadb_linux_srcs = [ - "fdevent/fdevent_epoll.cpp", -] - -libadb_test_srcs = [ - "adb_io_test.cpp", - "adb_listeners_test.cpp", - "adb_utils_test.cpp", - "fdevent/fdevent_test.cpp", - "socket_spec_test.cpp", - "socket_test.cpp", - "sysdeps_test.cpp", - "sysdeps/stat_test.cpp", - "transport_test.cpp", - "types_test.cpp", -] - -cc_library_host_static { - name: "libadb_host", - defaults: ["adb_defaults"], - - srcs: libadb_srcs + [ - "client/auth.cpp", - "client/adb_wifi.cpp", - "client/usb_libusb.cpp", - "client/usb_dispatch.cpp", - "client/transport_mdns.cpp", - "client/transport_usb.cpp", - "client/pairing/pairing_client.cpp", - ], - - generated_headers: ["platform_tools_version"], - - target: { - linux: { - srcs: ["client/usb_linux.cpp"] + libadb_linux_srcs, - }, - darwin: { - srcs: ["client/usb_osx.cpp"], - }, - not_windows: { - srcs: libadb_posix_srcs, - }, - windows: { - enabled: true, - srcs: [ - "client/usb_windows.cpp", - "sysdeps_win32.cpp", - "sysdeps/win32/errno.cpp", - "sysdeps/win32/stat.cpp", - ], - shared_libs: ["AdbWinApi"], - }, - }, - - static_libs: [ - "libadb_crypto", - "libadb_protos", - "libadb_pairing_connection", - "libadb_tls_connection", - "libbase", - "libcrypto_utils", - "libcrypto", - "libdiagnose_usb", - "libmdnssd", - "libusb", - "libutils", - "liblog", - "libcutils", - "libprotobuf-cpp-lite", - ], -} - -cc_test_host { - name: "adb_test", - defaults: ["adb_defaults"], - srcs: libadb_test_srcs, - static_libs: [ - "libadb_crypto_static", - "libadb_host", - "libadb_pairing_auth_static", - "libadb_pairing_connection_static", - "libadb_protos_static", - "libadb_tls_connection_static", - "libbase", - "libcutils", - "libcrypto_utils", - "libcrypto", - "liblog", - "libmdnssd", - "libdiagnose_usb", - "libprotobuf-cpp-lite", - "libssl", - "libusb", - ], - - target: { - windows: { - enabled: true, - ldflags: ["-municode"], - shared_libs: ["AdbWinApi"], - }, - }, -} - -cc_binary_host { - name: "adb", - - stl: "libc++_static", - defaults: ["adb_defaults"], - - srcs: [ - "client/adb_client.cpp", - "client/bugreport.cpp", - "client/commandline.cpp", - "client/file_sync_client.cpp", - "client/main.cpp", - "client/console.cpp", - "client/adb_install.cpp", - "client/line_printer.cpp", - "client/fastdeploy.cpp", - "client/fastdeploycallbacks.cpp", - "client/incremental.cpp", - "client/incremental_server.cpp", - "client/incremental_utils.cpp", - "shell_service_protocol.cpp", - ], - - generated_headers: [ - "bin2c_fastdeployagent", - "bin2c_fastdeployagentscript" - ], - - static_libs: [ - "libadb_crypto", - "libadb_host", - "libadb_pairing_auth", - "libadb_pairing_connection", - "libadb_protos", - "libadb_tls_connection", - "libandroidfw", - "libbase", - "libbrotli", - "libcutils", - "libcrypto_utils", - "libcrypto", - "libfastdeploy_host", - "libdiagnose_usb", - "liblog", - "liblz4", - "libmdnssd", - "libprotobuf-cpp-lite", - "libssl", - "libusb", - "libutils", - "liblog", - "libziparchive", - "libz", - ], - - // Don't add anything here, we don't want additional shared dependencies - // on the host adb tool, and shared libraries that link against libc++ - // will violate ODR - shared_libs: [], - - // Archive adb, adb.exe. - dist: { - targets: [ - "dist_files", - "sdk", - "win_sdk", - ], - }, - - target: { - darwin: { - cflags: [ - "-Wno-sizeof-pointer-memaccess", - ], - }, - windows: { - enabled: true, - ldflags: ["-municode"], - shared_libs: ["AdbWinApi"], - required: [ - "AdbWinUsbApi", - ], - }, - }, -} - -// libadbd_core contains the common sources to build libadbd and libadbd_services. -cc_library_static { - name: "libadbd_core", - defaults: ["adbd_defaults", "host_adbd_supported"], - recovery_available: true, - - // libminadbd wants both, as it's used to build native tests. - compile_multilib: "both", - - srcs: libadb_srcs + libadb_linux_srcs + libadb_posix_srcs + [ - "daemon/auth.cpp", - "daemon/jdwp_service.cpp", - "daemon/logging.cpp", - "daemon/adb_wifi.cpp", - ], - - generated_headers: ["platform_tools_version"], - - static_libs: [ - "libadbconnection_server", - "libdiagnose_usb", - ], - - shared_libs: [ - "libadb_crypto", - "libadb_pairing_connection", - "libadb_protos", - "libadb_tls_connection", - "libadbd_auth", - "libasyncio", - "libbase", - "libcrypto", - "libcrypto_utils", - "libcutils_sockets", - "liblog", - ], - - target: { - android: { - whole_static_libs: [ - "libqemu_pipe", - ], - srcs: [ - "daemon/transport_qemu.cpp", - "daemon/usb.cpp", - "daemon/usb_ffs.cpp", - ] - }, - recovery: { - exclude_shared_libs: [ - "libadb_pairing_auth", - "libadb_pairing_connection", - ], - } - }, - - apex_available: [ - "//apex_available:platform", - "com.android.adbd", - ], - visibility: [ - "//bootable/recovery/minadbd", - "//system/core/adb", - ], -} - -cc_library { - name: "libadbd_services", - defaults: ["adbd_defaults", "host_adbd_supported"], - recovery_available: true, - compile_multilib: "both", - - srcs: [ - "daemon/file_sync_service.cpp", - "daemon/services.cpp", - "daemon/shell_service.cpp", - "shell_service_protocol.cpp", - ], - - cflags: [ - "-D_GNU_SOURCE", - "-Wno-deprecated-declarations", - ], - - static_libs: [ - "libadbconnection_server", - "libadbd_core", - "libbrotli", - "libdiagnose_usb", - ], - - shared_libs: [ - "libadb_crypto", - "libadb_pairing_connection", - "libadb_protos", - "libadb_tls_connection", - "libasyncio", - "libbase", - "libcrypto_utils", - "libcutils_sockets", - - // APEX dependencies. - "libadbd_auth", - "libadbd_fs", - "libcrypto", - "liblog", - ], - - target: { - android: { - srcs: [ - "daemon/abb_service.cpp", - "daemon/framebuffer_service.cpp", - "daemon/mdns.cpp", - "daemon/restart_service.cpp", - ], - shared_libs: [ - "libmdnssd", - "libselinux", - ], - }, - recovery: { - exclude_srcs: [ - "daemon/abb_service.cpp", - ], - exclude_shared_libs: [ - "libadb_pairing_auth", - "libadb_pairing_connection", - ], - }, - }, - - apex_available: [ - "//apex_available:platform", - "com.android.adbd", - ], - visibility: [ - "//system/core/adb", - ], - -} - -cc_library { - name: "libadbd", - defaults: ["adbd_defaults", "host_adbd_supported"], - recovery_available: true, - apex_available: ["com.android.adbd"], - - // avoid getting duplicate symbol of android::build::getbuildnumber(). - use_version_lib: false, - - // libminadbd wants both, as it's used to build native tests. - compile_multilib: "both", - - shared_libs: [ - "libadb_crypto", - "libadb_pairing_connection", - "libadb_tls_connection", - "libasyncio", - "libbase", - "libcrypto", - "libcrypto_utils", - "liblog", - "libselinux", - - // APEX dependencies on the system image. - "libadbd_auth", - "libadbd_fs", - "libadbd_services", - ], - - target: { - recovery: { - exclude_shared_libs: [ - "libadb_pairing_auth", - "libadb_pairing_connection", - ], - } - }, - - static_libs: [ - "libadbd_core", - "libbrotli", - "libcutils_sockets", - "libdiagnose_usb", - "libmdnssd", - ], - - visibility: [ - "//bootable/recovery/minadbd", - "//system/core/adb", - ], -} - -cc_binary { - name: "adbd", - defaults: ["adbd_defaults", "host_adbd_supported", "libadbd_binary_dependencies"], - recovery_available: true, - apex_available: ["com.android.adbd"], - - srcs: [ - "daemon/main.cpp", - ], - - cflags: [ - "-D_GNU_SOURCE", - "-Wno-deprecated-declarations", - ], - - strip: { - keep_symbols: true, - }, - - static_libs: [ - "libadbd", - "libadbd_services", - "libasyncio", - "libcap", - "libminijail", - "libssl", - ], - - shared_libs: [ - "libadb_protos", - "libadbd_auth", - ], - - target: { - recovery: { - exclude_shared_libs: [ - "libadb_pairing_auth", - "libadb_pairing_connection", - ], - } - }, -} - -phony { - // Interface between adbd in a module and the system. - name: "adbd_system_api", - required: [ - "libadbd_auth", - "libadbd_fs", - "abb", - "reboot", - "set-verity-state", - ] -} - -phony { - name: "adbd_system_api_recovery", - required: [ - "libadbd_auth", - "libadbd_fs", - "reboot.recovery", - ], -} - -cc_binary { - name: "abb", - - defaults: ["adbd_defaults"], - stl: "libc++", - recovery_available: false, - - srcs: [ - "daemon/abb.cpp", - ], - - cflags: [ - "-D_GNU_SOURCE", - "-Wno-deprecated-declarations", - ], - - strip: { - keep_symbols: true, - }, - - static_libs: [ - "libadbd_core", - "libadbd_services", - "libcmd", - ], - - shared_libs: [ - "libbase", - "libbinder", - "liblog", - "libutils", - "libselinux", - ], -} - -cc_test { - name: "adbd_test", - - defaults: ["adbd_defaults", "libadbd_binary_dependencies"], - - recovery_available: false, - srcs: libadb_test_srcs + [ - "daemon/services.cpp", - "daemon/shell_service.cpp", - "daemon/shell_service_test.cpp", - "shell_service_protocol.cpp", - "shell_service_protocol_test.cpp", - "mdns_test.cpp", - ], - - test_config: "adb_test.xml", - - shared_libs: [ - "liblog", - ], - - static_libs: [ - "libadbd", - "libadbd_auth", - "libbase", - "libcrypto_utils", - "libusb", - ], - test_suites: ["device-tests", "mts"], - require_root: true, -} - -python_test_host { - name: "adb_integration_test_adb", - main: "test_adb.py", - srcs: [ - "test_adb.py", - ], - test_config: "adb_integration_test_adb.xml", - test_suites: ["general-tests"], - version: { - py2: { - enabled: false, - }, - py3: { - enabled: true, - }, - }, -} - -python_test_host { - name: "adb_integration_test_device", - main: "test_device.py", - srcs: [ - "test_device.py", - ], - libs: [ - "adb_py", - ], - test_config: "adb_integration_test_device.xml", - test_suites: ["general-tests"], - version: { - py2: { - enabled: false, - }, - py3: { - enabled: true, - }, - }, -} - -// Note: using pipe for xxd to control the variable name generated -// the default name used by xxd is the path to the input file. -java_genrule { - name: "bin2c_fastdeployagent", - out: ["deployagent.inc"], - srcs: [":deployagent"], - cmd: "(echo 'unsigned char kDeployAgent[] = {' && xxd -i <$(in) && echo '};') > $(out)", -} - -genrule { - name: "bin2c_fastdeployagentscript", - out: ["deployagentscript.inc"], - srcs: ["fastdeploy/deployagent/deployagent.sh"], - cmd: "(echo 'unsigned char kDeployAgentScript[] = {' && xxd -i <$(in) && echo '};') > $(out)", -} - -cc_library_host_static { - name: "libfastdeploy_host", - defaults: ["adb_defaults"], - srcs: [ - "fastdeploy/deploypatchgenerator/apk_archive.cpp", - "fastdeploy/deploypatchgenerator/deploy_patch_generator.cpp", - "fastdeploy/deploypatchgenerator/patch_utils.cpp", - "fastdeploy/proto/ApkEntry.proto", - ], - static_libs: [ - "libadb_host", - "libandroidfw", - "libbase", - "libcutils", - "libcrypto_utils", - "libcrypto", - "libdiagnose_usb", - "liblog", - "libmdnssd", - "libusb", - "libutils", - "libziparchive", - "libz", - ], - proto: { - type: "lite", - export_proto_headers: true, - }, - target: { - windows: { - enabled: true, - shared_libs: ["AdbWinApi"], - }, - }, -} - -cc_test_host { - name: "fastdeploy_test", - defaults: ["adb_defaults"], - srcs: [ - "fastdeploy/deploypatchgenerator/apk_archive_test.cpp", - "fastdeploy/deploypatchgenerator/deploy_patch_generator_test.cpp", - "fastdeploy/deploypatchgenerator/patch_utils_test.cpp", - ], - static_libs: [ - "libadb_crypto_static", - "libadb_host", - "libadb_pairing_auth_static", - "libadb_pairing_connection_static", - "libadb_protos_static", - "libadb_tls_connection_static", - "libandroidfw", - "libbase", - "libcutils", - "libcrypto_utils", - "libcrypto", - "libdiagnose_usb", - "libfastdeploy_host", - "liblog", - "libmdnssd", - "libprotobuf-cpp-lite", - "libssl", - "libusb", - "libutils", - "libziparchive", - "libz", - ], - target: { - windows: { - enabled: true, - shared_libs: ["AdbWinApi"], - }, - }, - data: [ - "fastdeploy/testdata/rotating_cube-metadata-release.data", - "fastdeploy/testdata/rotating_cube-release.apk", - "fastdeploy/testdata/sample.apk", - "fastdeploy/testdata/sample.cd", - ], -} diff --git a/adb/MODULE_LICENSE_APACHE2 b/adb/MODULE_LICENSE_APACHE2 deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/adb/NOTICE b/adb/NOTICE deleted file mode 100644 index 9ffcc081334e42af903248455cd52d6743d3715a..0000000000000000000000000000000000000000 --- a/adb/NOTICE +++ /dev/null @@ -1,191 +0,0 @@ - - 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 - diff --git a/adb/OVERVIEW.TXT b/adb/OVERVIEW.TXT deleted file mode 100644 index f0b184c9925142fb32ddcb2beb4fd05cec6d8985..0000000000000000000000000000000000000000 --- a/adb/OVERVIEW.TXT +++ /dev/null @@ -1,135 +0,0 @@ -Implementation notes regarding ADB. - -I. General Overview: - -The Android Debug Bridge (ADB) is used to: - -- keep track of all Android devices and emulators instances - connected to or running on a given host developer machine - -- implement various control commands (e.g. "adb shell", "adb pull", etc.) - for the benefit of clients (command-line users, or helper programs like - DDMS). These commands are called 'services' 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 - is 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. - - 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 - states. They are a few 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. - - Note that the connection is still alive after an OKAY, which allows the - client to make other requests. But in certain cases, an OKAY will even - change the state of the connection. - - For example, the case of the 'host:transport:' request, - where '' is used to identify a given device/emulator; after - the "OKAY" answer, all further requests made by the client will go - directly to the corresponding adbd daemon. - - The file SERVICES.TXT lists all services currently implemented by ADB. - - - 2. Transports: - - An ADB transport models a connection between the ADB server and one device - or emulator. There are currently two kinds of transports: - - - USB transports, for physical devices through USB - - - Local transports, for emulators running on the host, connected to - the server through TCP - - In theory, it should be possible to write a local transport that proxies - a connection between an ADB server and a device/emulator connected to/ - running on another machine. This hasn't been done yet though. - - Each transport can carry one or more multiplexed streams between clients - and the device/emulator they point to. The ADB server must handle - unexpected transport disconnections (e.g. when a device is physically - unplugged) properly. diff --git a/adb/OWNERS b/adb/OWNERS deleted file mode 100644 index 643b4489f343c838a9548cd4cf6bf71951488a24..0000000000000000000000000000000000000000 --- a/adb/OWNERS +++ /dev/null @@ -1,2 +0,0 @@ -jmgao@google.com -yabinc@google.com diff --git a/adb/SERVICES.TXT b/adb/SERVICES.TXT deleted file mode 100644 index 3e18a54e7035fab17001ff07a9fab5c282af5e8b..0000000000000000000000000000000000000000 --- a/adb/SERVICES.TXT +++ /dev/null @@ -1,255 +0,0 @@ -This file tries to document all requests a client can make -to the ADB server of an adbd daemon. See the OVERVIEW.TXT document -to understand what's going on here. - -HOST SERVICES: - -host:version - Ask the ADB server for its internal version number. - -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 synchronization 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'. diff --git a/adb/SOCKET-ACTIVATION.txt b/adb/SOCKET-ACTIVATION.txt deleted file mode 100644 index 4ef62ac9d5629256163ba9443e3fad161975d96c..0000000000000000000000000000000000000000 --- a/adb/SOCKET-ACTIVATION.txt +++ /dev/null @@ -1,42 +0,0 @@ -adb can be configured to work with systemd-style socket activation, -allowing the daemon to start automatically when the adb control port -is forwarded across a network. You need two files, placed in the usual -systemd service directories (e.g., ~/.config/systemd/user for a user -service). - -adb.service: - ---- START adb.service CUT HERE --- -[Unit] -Description=adb -After=adb.socket -Requires=adb.socket -[Service] -Type=simple -# FD 3 is part of the systemd interface -ExecStart=/path/to/adb server nodaemon -L acceptfd:3 ---- END adb.service CUT HERE --- - ---- START adb.socket CUT HERE --- -[Unit] -Description=adb -PartOf=adb.service -[Socket] -ListenStream=127.0.0.1:5037 -Accept=no -[Install] -WantedBy=sockets.target ---- END adb.socket CUT HERE --- - -After installing the adb service, the adb server will be started -automatically on any connection to 127.0.0.1:5037 (the default adb -control port), even after adb kill-server kills the server. - -Other "superserver" launcher systems (like macOS launchd) can be -configured analogously. The important part is that adb be started with -"server" and "nodaemon" command line arguments and that the listen -address (passed to -L) name a file descriptor that's ready to -accept(2) connections and that's already bound to the desired address -and listening. inetd-style pre-accepted sockets do _not_ work in this -configuration: the file descriptor passed to acceptfd must be the -serve socket, not the accepted connection socket. diff --git a/adb/SYNC.TXT b/adb/SYNC.TXT deleted file mode 100644 index 4445a76174a1abb54b4c3026f3fcfec9b6970a13..0000000000000000000000000000000000000000 --- a/adb/SYNC.TXT +++ /dev/null @@ -1,80 +0,0 @@ -This file tries to document file-related requests a client can make -to the ADB server of an adbd daemon. See the OVERVIEW.TXT document -to understand what's going on here. See the SERVICES.TXT to learn more -about the other requests that are possible. - -SYNC SERVICES: - - -Requesting the sync service ("sync:") using the protocol as described in -SERVICES.TXT sets the connection in sync mode. This mode is a binary mode that -differs 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 these are called sync requests and sync -responses. The first four bytes are an id that specifies the sync request. It is -represented by four utf-8 characters. The last four bytes are 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 -RECV - Retrieve a file from device -SEND - Send a file to device -STAT - Stat a file - -All of the sync requests above must be followed by "length": the number of -bytes containing a 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 "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 a 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 chunk 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 -transferred. Each chunk must not be larger than 64k. - -When the file is transferred 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 chunk 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 chunk size. After follows chunk size number of bytes. This is repeated -until the file is transferred. Each chunk will not be larger than 64k. - -When the file is transferred a sync response "DONE" is retrieved where the -length can be ignored. diff --git a/adb/adb.bash b/adb/adb.bash deleted file mode 100644 index b1b3957c0e8432eb5e3032ca6925c90d3e2fbeff..0000000000000000000000000000000000000000 --- a/adb/adb.bash +++ /dev/null @@ -1,499 +0,0 @@ -# /* vim: set ai ts=4 ft=sh: */ -# -# Copyright 2011, The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -_adb() { - if ! check_type "$1" >/dev/null; then - return - fi - - if check_type _init_completion >/dev/null; then - _init_completion || return - fi - - local where i cur serial - COMPREPLY=() - - serial="${ANDROID_SERIAL:-none}" - where=OPTIONS - for ((i=1; i <= COMP_CWORD; i++)); do - cur="${COMP_WORDS[i]}" - case "${cur}" in - -s) - where=OPT_SERIAL - ;; - -p) - where=OPT_PATH - ;; - -*) - where=OPTIONS - ;; - *) - if [[ $where == OPT_SERIAL ]]; then - where=OPT_SERIAL_ARG - serial=${cur} - else - where=COMMAND - break - fi - ;; - esac - done - - if [[ $where == COMMAND && $i -ge $COMP_CWORD ]]; then - where=OPTIONS - fi - - OPTIONS="-d -e -s -p" - COMMAND="devices connect disconnect push pull sync shell emu logcat lolcat forward jdwp install uninstall bugreport help version start-server kill-server get-state get-serialno status-window remount reboot reboot-bootloader root usb tcpip disable-verity" - - case $where in - OPTIONS|OPT_SERIAL|OPT_PATH) - COMPREPLY=( $(compgen -W "$OPTIONS $COMMAND" -- "$cur") ) - ;; - OPT_SERIAL_ARG) - local devices=$(command adb devices 2> /dev/null | grep -v "List of devices" | awk '{ print $1 }') - COMPREPLY=( $(compgen -W "${devices}" -- ${cur}) ) - ;; - COMMAND) - if [[ $i -eq $COMP_CWORD ]]; then - COMPREPLY=( $(compgen -W "$COMMAND" -- "$cur") ) - else - i=$((i+1)) - case "${cur}" in - install) - _adb_cmd_install "$serial" $i - ;; - sideload) - _adb_cmd_sideload "$serial" $i - ;; - pull) - _adb_cmd_pull "$serial" $i - ;; - push) - _adb_cmd_push "$serial" $i - ;; - reboot) - if [[ $COMP_CWORD == $i ]]; then - args="bootloader recovery" - COMPREPLY=( $(compgen -W "${args}" -- "${COMP_WORDS[i]}") ) - fi - ;; - shell) - _adb_cmd_shell "$serial" $i - ;; - uninstall) - _adb_cmd_uninstall "$serial" $i - ;; - esac - fi - ;; - esac - - return 0 -} - -_adb_cmd_install() { - local serial i cur where - - serial=$1 - i=$2 - - where=OPTIONS - for ((; i <= COMP_CWORD; i++)); do - cur="${COMP_WORDS[i]}" - case "${cur}" in - -*) - where=OPTIONS - ;; - *) - where=FILE - break - ;; - esac - done - - cur="${COMP_WORDS[COMP_CWORD]}" - if [[ $where == OPTIONS ]]; then - COMPREPLY=( $(compgen -W "-d -l -r -s" -- "${cur}") ) - return - fi - - _adb_util_complete_local_file "${cur}" '!*.apk' -} - -_adb_cmd_sideload() { - local serial i cur - - serial=$1 - i=$2 - - cur="${COMP_WORDS[COMP_CWORD]}" - - _adb_util_complete_local_file "${cur}" '!*.zip' -} - -_adb_cmd_push() { - local serial IFS=$'\n' i cur - - serial=$1 - i=$2 - - cur="${COMP_WORDS[COMP_CWORD]}" - - if [[ $COMP_CWORD == $i ]]; then - _adb_util_complete_local_file "${cur}" - elif [[ $COMP_CWORD == $(($i+1)) ]]; then - if [ "${cur}" == "" ]; then - cur="/" - fi - _adb_util_list_files $serial "${cur}" - fi -} - -_adb_cmd_pull() { - local serial IFS=$'\n' i cur - - serial=$1 - i=$2 - - cur="${COMP_WORDS[COMP_CWORD]}" - - if [[ $COMP_CWORD == $i ]]; then - if [ "${cur}" == "" ]; then - cur="/" - fi - _adb_util_list_files $serial "${cur}" - elif [[ $COMP_CWORD == $(($i+1)) ]]; then - _adb_util_complete_local_file "${cur}" - fi -} - -_adb_cmd_shell() { - local serial IFS=$'\n' i cur - local -a args - - serial=$1 - i=$2 - - cur="${COMP_WORDS[i]}" - if [ "$serial" != "none" ]; then - args=(-s $serial) - fi - - if [[ $i -eq $COMP_CWORD && ${cur:0:1} != "/" ]]; then - paths=$(command adb ${args[@]} shell echo '$'PATH 2> /dev/null | tr -d '\r' | tr : '\n') - COMMAND=$(command adb ${args[@]} shell ls $paths '2>' /dev/null | tr -d '\r' | { - while read -r tmp; do - command=${tmp##*/} - printf '%s\n' "$command" - done - }) - COMPREPLY=( $(compgen -W "$COMMAND" -- "$cur") ) - return 0 - fi - - i=$((i+1)) - case "$cur" in - ls) - _adb_shell_file_command $serial $i "--color -A -C -F -H -L -R -S -Z -a -c -d -f -h -i -k -l -m -n -p -q -r -s -t -u -x -1" - ;; - cat) - _adb_shell_file_command $serial $i "-h -e -t -u -v" - ;; - dumpsys) - _adb_cmd_shell_dumpsys "$serial" $i - ;; - am) - _adb_cmd_shell_am "$serial" $i - ;; - pm) - _adb_cmd_shell_pm "$serial" $i - ;; - /*) - _adb_util_list_files $serial "$cur" - ;; - *) - COMPREPLY=( ) - ;; - esac - - return 0 -} - -_adb_cmd_shell_dumpsys() { - local serial i cur - local -a args - local candidates - - unset IFS - - serial=$1 - i=$2 - - if [ "$serial" != "none" ]; then - args=(-s $serial) - fi - - if (( $i == $COMP_CWORD )) ; then - cur="${COMP_WORDS[COMP_CWORD]}" - # First line is a header, so need "1d". - candidates=$(command adb ${args[@]} shell dumpsys -l 2> /dev/null | sed -e '1d;s/^ *//' | tr -d '\r') - candidates="-l $candidates" - COMPREPLY=( $(compgen -W "$candidates" -- "$cur") ) - return 0 - fi - - COMPREPLY=( ) - return 0 -} - -_adb_cmd_shell_am() { - local serial i cur - local candidates - - unset IFS - - serial=$1 - i=$2 - - if (( $i == $COMP_CWORD )) ; then - cur="${COMP_WORDS[COMP_CWORD]}" - candidates="broadcast clear-debug-app clear-watch-heap dumpheap force-stop get-config get-inactive hang idle-maintenance instrument kill kill-all monitor package-importance profile restart screen-compat send-trim-memory set-debug-app set-inactive set-watch-heap stack start startservice start-user stopservice stop-user suppress-resize-config-changes switch-user task to-app-uri to-intent-uri to-uri" - COMPREPLY=( $(compgen -W "$candidates" -- "$cur") ) - return 0 - fi - - COMPREPLY=( ) - return 0 -} - - -_adb_cmd_shell_pm() { - local serial i cur - local candidates - - unset IFS - - serial=$1 - i=$2 - - if (( $i == $COMP_CWORD )) ; then - cur="${COMP_WORDS[COMP_CWORD]}" - candidates="-l -lf -p clear create-user default-state disable" - candidates+=" disable-until-used disable-user dump enable" - candidates+=" get-app-link get-install-location get-max-users" - candidates+=" get-max-running-users grant hide install" - candidates+=" install-abandon install-commit install-create" - candidates+=" install-write list move-package" - candidates+=" move-primary-storage path remove-user" - candidates+=" reset-permissions revoke set-app-link" - candidates+=" set-installer set-install-location" - candidates+=" set-permission-enforced trim-caches unhide" - candidates+=" uninstall" - COMPREPLY=( $(compgen -W "$candidates" -- "$cur") ) - return 0 - fi - - if (( $i + 1 == $COMP_CWORD )) && [[ "${COMP_WORDS[COMP_CWORD -1]}" == "list" ]] ; then - cur="${COMP_WORDS[COMP_CWORD]}" - candidates="packages permission-groups permissions instrumentation features libraries users" - COMPREPLY=( $(compgen -W "$candidates" -- "$cur") ) - return 0 - fi - - COMPREPLY=( ) - return 0 -} - -_adb_cmd_uninstall() { - local serial i where cur packages - - serial=$1 - i=$2 - if [ "$serial" != "none" ]; then - args=(-s $serial) - fi - - where=OPTIONS - for ((; i <= COMP_CWORD; i++)); do - cur="${COMP_WORDS[i]}" - case "${cur}" in - -*) - where=OPTIONS - ;; - *) - where=FILE - break - ;; - esac - done - - cur="${COMP_WORDS[COMP_CWORD]}" - if [[ $where == OPTIONS ]]; then - COMPREPLY=( $(compgen -W "-k" -- "${cur}") ) - fi - - packages="$( - command adb ${args[@]} shell pm list packages '2>' /dev/null 2> /dev/null | tr -d '\r' | { - while read -r tmp; do - local package=${tmp#package:} - echo -n "${package} " - done - } - )" - - COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -W "${packages}" -- "${cur}") ) -} - -_adb_shell_file_command() { - local serial i cur file options - local -a args - - serial=$1 - i=$2 - if [ "$serial" != "none" ]; then - args=(-s $serial) - fi - options=$3 - - where=OPTIONS - for ((; i <= COMP_CWORD; i++)); do - cur="${COMP_WORDS[i]}" - case "${cur}" in - -*) - where=OPTIONS - ;; - *) - where=FILE - break - ;; - esac - done - - file="${COMP_WORDS[COMP_CWORD]}" - if [[ ${file} == "" ]]; then - file="/" - fi - - case $where in - OPTIONS) - unset IFS - COMPREPLY=( $(compgen -W "$options" -- "$cur") ) - ;; - FILE) - _adb_util_list_files $serial "$file" - ;; - esac - - return 0 -} - -_adb_util_list_files() { - local serial dir IFS=$'\n' - local -a toks - local -a args - - serial="$1" - file="$2" - - if [ "$serial" != "none" ]; then - args=(-s $serial) - fi - - if [[ $( command adb ${args[@]} shell ls -dF / '2>/dev/null' | tr -d '\r' ) == "d /" ]] ; then - toks=( ${toks[@]-} $( - command adb ${args[@]} shell ls -dF ${file}"*" '2>' /dev/null 2> /dev/null | tr -d '\r' | { - while read -r tmp; do - filetype=${tmp%% *} - filename=${tmp:${#filetype}+1} - if [[ ${filetype:${#filetype}-1:1} == d ]]; then - printf '%s/\n' "$filename" - else - printf '%s\n' "$filename" - fi - done - } - )) - else - toks=( ${toks[@]-} $( - command adb ${args[@]} shell ls -dp ${file}"*" '2>/dev/null' 2> /dev/null | tr -d '\r' - )) - fi - - # Since we're probably doing file completion here, don't add a space after. - if [[ $(check_type compopt) == "builtin" ]]; then - compopt -o nospace - fi - - COMPREPLY=( ${COMPREPLY[@]:-} "${toks[@]}" ) -} - -_adb_util_complete_local_file() -{ - local file xspec i j IFS=$'\n' - local -a dirs files - - file=$1 - xspec=$2 - - # Since we're probably doing file completion here, don't add a space after. - if [[ $(check_type compopt) == "builtin" ]]; then - compopt -o plusdirs - if [[ "${xspec}" == "" ]]; then - COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -f -- "${cur}") ) - else - compopt +o filenames - COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -f -X "${xspec}" -- "${cur}") ) - fi - else - # Work-around for shells with no compopt - - dirs=( $(compgen -d -- "${cur}" ) ) - - if [[ "${xspec}" == "" ]]; then - files=( ${COMPREPLY[@]:-} $(compgen -f -- "${cur}") ) - else - files=( ${COMPREPLY[@]:-} $(compgen -f -X "${xspec}" -- "${cur}") ) - fi - - COMPREPLY=( $( - for i in "${files[@]}"; do - local skip= - for j in "${dirs[@]}"; do - if [[ $i == $j ]]; then - skip=1 - break - fi - done - [[ -n $skip ]] || printf "%s\n" "$i" - done - )) - - COMPREPLY=( ${COMPREPLY[@]:-} $( - for i in "${dirs[@]}"; do - printf "%s/\n" "$i" - done - )) - fi -} - - -if [[ $(check_type compopt) == "builtin" ]]; then - complete -F _adb adb -else - complete -o nospace -F _adb adb -fi diff --git a/adb/adb.cpp b/adb/adb.cpp deleted file mode 100644 index c3e9731a30b57eea518cee7a193d68b612afbf13..0000000000000000000000000000000000000000 --- a/adb/adb.cpp +++ /dev/null @@ -1,1359 +0,0 @@ -/* - * 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 ADB - -#include "sysdeps.h" -#include "adb.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "adb_auth.h" -#include "adb_io.h" -#include "adb_listeners.h" -#include "adb_unique_fd.h" -#include "adb_utils.h" -#include "adb_wifi.h" -#include "sysdeps/chrono.h" -#include "transport.h" - -#if !ADB_HOST -#include -#include -#include -using namespace std::chrono_literals; - -#include "daemon/logging.h" -#endif - -#if ADB_HOST -#include "client/usb.h" -#endif - -std::string adb_version() { - // Don't change the format of this --- it's parsed by ddmlib. - return android::base::StringPrintf( - "Android Debug Bridge version %d.%d.%d\n" - "Version %s-%s\n" - "Installed as %s\n", - ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION, - PLATFORM_TOOLS_VERSION, android::build::GetBuildNumber().c_str(), - android::base::GetExecutablePath().c_str()); -} - -uint32_t calculate_apacket_checksum(const apacket* p) { - uint32_t sum = 0; - for (size_t i = 0; i < p->msg.data_length; ++i) { - sum += static_cast(p->payload[i]); - } - return sum; -} - -apacket* get_apacket(void) -{ - apacket* p = new apacket(); - if (p == nullptr) { - LOG(FATAL) << "failed to allocate an apacket"; - } - - memset(&p->msg, 0, sizeof(p->msg)); - return p; -} - -void put_apacket(apacket *p) -{ - delete p; -} - -void handle_online(atransport *t) -{ - D("adb: online"); - t->online = 1; - t->SetConnectionEstablished(true); -} - -void handle_offline(atransport *t) -{ - if (t->GetConnectionState() == kCsOffline) { - LOG(INFO) << t->serial_name() << ": already offline"; - return; - } - - LOG(INFO) << t->serial_name() << ": offline"; - - t->SetConnectionState(kCsOffline); - - // Close the associated usb - t->online = 0; - - // This is necessary to avoid a race condition that occurred when a transport closes - // while a client socket is still active. - close_all_sockets(t); - - t->RunDisconnects(); -} - -#if DEBUG_PACKETS -#define DUMPMAX 32 -void print_packet(const char *label, apacket *p) -{ - const char* tag; - 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; - case A_STLS: - tag = "STLS"; - 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; - const char* x = p->payload.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"); - 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"); - apacket *p = get_apacket(); - p->msg.command = A_CLSE; - p->msg.arg0 = local; - p->msg.arg1 = remote; - send_packet(p, t); -} - -std::string get_connection_string() { - std::vector connection_properties; - -#if !ADB_HOST - static const char* cnxn_props[] = { - "ro.product.name", - "ro.product.model", - "ro.product.device", - }; - - for (const auto& prop : cnxn_props) { - std::string value = std::string(prop) + "=" + android::base::GetProperty(prop, ""); - connection_properties.push_back(value); - } -#endif - - connection_properties.push_back(android::base::StringPrintf( - "features=%s", FeatureSetToString(supported_features()).c_str())); - - return android::base::StringPrintf( - "%s::%s", adb_device_banner, - android::base::Join(connection_properties, ';').c_str()); -} - -void send_tls_request(atransport* t) { - D("Calling send_tls_request"); - apacket* p = get_apacket(); - p->msg.command = A_STLS; - p->msg.arg0 = A_STLS_VERSION; - p->msg.data_length = 0; - send_packet(p, t); -} - -void send_connect(atransport* t) { - D("Calling send_connect"); - apacket* cp = get_apacket(); - cp->msg.command = A_CNXN; - // Send the max supported version, but because the transport is - // initialized to A_VERSION_MIN, this will be compatible with every - // device. - cp->msg.arg0 = A_VERSION; - cp->msg.arg1 = t->get_max_payload(); - - std::string connection_str = get_connection_string(); - // Connect and auth packets are limited to MAX_PAYLOAD_V1 because we don't - // yet know how much data the other size is willing to accept. - if (connection_str.length() > MAX_PAYLOAD_V1) { - LOG(FATAL) << "Connection banner is too long (length = " - << connection_str.length() << ")"; - } - - cp->payload.assign(connection_str.begin(), connection_str.end()); - cp->msg.data_length = cp->payload.size(); - - send_packet(cp, t); -} - -void parse_banner(const std::string& banner, atransport* t) { - D("parse_banner: %s", banner.c_str()); - - // The format is something like: - // "device::ro.product.name=x;ro.product.model=y;ro.product.device=z;". - std::vector pieces = android::base::Split(banner, ":"); - - // Reset the features list or else if the server sends no features we may - // keep the existing feature set (http://b/24405971). - t->SetFeatures(""); - - if (pieces.size() > 2) { - const std::string& props = pieces[2]; - for (const auto& prop : android::base::Split(props, ";")) { - // The list of properties was traditionally ;-terminated rather than ;-separated. - if (prop.empty()) continue; - - std::vector key_value = android::base::Split(prop, "="); - if (key_value.size() != 2) continue; - - const std::string& key = key_value[0]; - const std::string& value = key_value[1]; - if (key == "ro.product.name") { - t->product = value; - } else if (key == "ro.product.model") { - t->model = value; - } else if (key == "ro.product.device") { - t->device = value; - } else if (key == "features") { - t->SetFeatures(value); - } - } - } - - const std::string& type = pieces[0]; - if (type == "bootloader") { - D("setting connection_state to kCsBootloader"); - t->SetConnectionState(kCsBootloader); - } else if (type == "device") { - D("setting connection_state to kCsDevice"); - t->SetConnectionState(kCsDevice); - } else if (type == "recovery") { - D("setting connection_state to kCsRecovery"); - t->SetConnectionState(kCsRecovery); - } else if (type == "sideload") { - D("setting connection_state to kCsSideload"); - t->SetConnectionState(kCsSideload); - } else if (type == "rescue") { - D("setting connection_state to kCsRescue"); - t->SetConnectionState(kCsRescue); - } else { - D("setting connection_state to kCsHost"); - t->SetConnectionState(kCsHost); - } -} - -static void handle_new_connection(atransport* t, apacket* p) { - handle_offline(t); - - t->update_version(p->msg.arg0, p->msg.arg1); - std::string banner(p->payload.begin(), p->payload.end()); - parse_banner(banner, t); - -#if ADB_HOST - handle_online(t); -#else - ADB_LOG(Connection) << "received CNXN: version=" << p->msg.arg0 << ", maxdata = " << p->msg.arg1 - << ", banner = '" << banner << "'"; - - if (t->use_tls) { - // We still handshake in TLS mode. If auth_required is disabled, - // we'll just not verify the client's certificate. This should be the - // first packet the client receives to indicate the new protocol. - send_tls_request(t); - } else if (!auth_required) { - LOG(INFO) << "authentication not required"; - handle_online(t); - send_connect(t); - } else { - send_auth_request(t); - } -#endif - - update_transports(); -} - -void handle_packet(apacket *p, atransport *t) -{ - D("handle_packet() %c%c%c%c", ((char*) (&(p->msg.command)))[0], - ((char*) (&(p->msg.command)))[1], - ((char*) (&(p->msg.command)))[2], - ((char*) (&(p->msg.command)))[3]); - print_packet("recv", p); - CHECK_EQ(p->payload.size(), p->msg.data_length); - - switch(p->msg.command){ - case A_CNXN: // CONNECT(version, maxdata, "system-id-string") - handle_new_connection(t, p); - break; - case A_STLS: // TLS(version, "") - t->use_tls = true; -#if ADB_HOST - send_tls_request(t); - adb_auth_tls_handshake(t); -#else - adbd_auth_tls_handshake(t); -#endif - break; - - case A_AUTH: - // All AUTH commands are ignored in TLS mode - if (t->use_tls) { - break; - } - switch (p->msg.arg0) { -#if ADB_HOST - case ADB_AUTH_TOKEN: - if (t->GetConnectionState() != kCsAuthorizing) { - t->SetConnectionState(kCsAuthorizing); - } - send_auth_response(p->payload.data(), p->msg.data_length, t); - break; -#else - case ADB_AUTH_SIGNATURE: { - // TODO: Switch to string_view. - std::string signature(p->payload.begin(), p->payload.end()); - std::string auth_key; - if (adbd_auth_verify(t->token, sizeof(t->token), signature, &auth_key)) { - adbd_auth_verified(t); - t->failed_auth_attempts = 0; - t->auth_key = auth_key; - adbd_notify_framework_connected_key(t); - } else { - if (t->failed_auth_attempts++ > 256) std::this_thread::sleep_for(1s); - send_auth_request(t); - } - break; - } - - case ADB_AUTH_RSAPUBLICKEY: - t->auth_key = std::string(p->payload.data()); - adbd_auth_confirm_key(t); - break; -#endif - default: - t->SetConnectionState(kCsOffline); - handle_offline(t); - break; - } - break; - - case A_OPEN: /* OPEN(local-id, 0, "destination") */ - if (t->online && p->msg.arg0 != 0 && p->msg.arg1 == 0) { - std::string_view address(p->payload.begin(), p->payload.size()); - - // Historically, we received service names as a char*, and stopped at the first NUL - // byte. The client sent strings with null termination, which post-string_view, start - // being interpreted as part of the string, unless we explicitly strip them. - address = StripTrailingNulls(address); - - asocket* s = create_local_service_socket(address, t); - if (s == nullptr) { - 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) { - asocket* s = find_local_socket(p->msg.arg1, 0); - if (s) { - if(s->peer == nullptr) { - /* 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", p->msg.arg0, - p->msg.arg1, s->peer->id, p->msg.arg1, t->serial.c_str()); - } - } else { - // When receiving A_OKAY from device for A_OPEN request, the host server may - // have closed the local socket because of client disconnection. Then we need - // to send A_CLSE back to device to close the service on device. - send_close(p->msg.arg1, p->msg.arg0, t); - } - } - break; - - case A_CLSE: /* CLOSE(local-id, remote-id, "") or CLOSE(0, remote-id, "") */ - if (t->online && p->msg.arg1 != 0) { - asocket* s = find_local_socket(p->msg.arg1, p->msg.arg0); - if (s) { - /* 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", p->msg.arg1, - t->serial.c_str(), s->peer->transport->serial.c_str()); - } else { - s->close(s); - } - } - } - break; - - case A_WRTE: /* WRITE(local-id, remote-id, ) */ - if (t->online && p->msg.arg0 != 0 && p->msg.arg1 != 0) { - asocket* s = find_local_socket(p->msg.arg1, p->msg.arg0); - if (s) { - unsigned rid = p->msg.arg0; - if (s->enqueue(s, std::move(p->payload)) == 0) { - D("Enqueue the socket"); - send_ready(s->id, rid, t); - } - } - } - break; - - default: - printf("handle_packet: what is %08x?!\n", p->msg.command); - } - - put_apacket(p); -} - -#if ADB_HOST - -#ifdef _WIN32 - -// Try to make a handle non-inheritable and if there is an error, don't output -// any error info, but leave GetLastError() for the caller to read. This is -// convenient if the caller is expecting that this may fail and they'd like to -// ignore such a failure. -static bool _try_make_handle_noninheritable(HANDLE h) { - if (h != INVALID_HANDLE_VALUE && h != NULL) { - return SetHandleInformation(h, HANDLE_FLAG_INHERIT, 0) ? true : false; - } - - return true; -} - -// Try to make a handle non-inheritable with the expectation that this should -// succeed, so if this fails, output error info. -static bool _make_handle_noninheritable(HANDLE h) { - if (!_try_make_handle_noninheritable(h)) { - // Show the handle value to give us a clue in case we have problems - // with pseudo-handle values. - fprintf(stderr, "adb: cannot make handle 0x%p non-inheritable: %s\n", h, - android::base::SystemErrorCodeToString(GetLastError()).c_str()); - return false; - } - - return true; -} - -// Create anonymous pipe, preventing inheritance of the read pipe and setting -// security of the write pipe to sa. -static bool _create_anonymous_pipe(unique_handle* pipe_read_out, - unique_handle* pipe_write_out, - SECURITY_ATTRIBUTES* sa) { - HANDLE pipe_read_raw = NULL; - HANDLE pipe_write_raw = NULL; - if (!CreatePipe(&pipe_read_raw, &pipe_write_raw, sa, 0)) { - fprintf(stderr, "adb: CreatePipe failed: %s\n", - android::base::SystemErrorCodeToString(GetLastError()).c_str()); - return false; - } - - unique_handle pipe_read(pipe_read_raw); - pipe_read_raw = NULL; - unique_handle pipe_write(pipe_write_raw); - pipe_write_raw = NULL; - - if (!_make_handle_noninheritable(pipe_read.get())) { - return false; - } - - *pipe_read_out = std::move(pipe_read); - *pipe_write_out = std::move(pipe_write); - - return true; -} - -// Read from a pipe (that we take ownership of) and write the result to stdout/stderr. Return on -// error or when the pipe is closed. Internally makes inheritable handles, so this should not be -// called if subprocesses may be started concurrently. -static unsigned _redirect_pipe_thread(HANDLE h, DWORD nStdHandle) { - // Take ownership of the HANDLE and close when we're done. - unique_handle read_pipe(h); - const char* output_name = nStdHandle == STD_OUTPUT_HANDLE ? "stdout" : "stderr"; - const int original_fd = fileno(nStdHandle == STD_OUTPUT_HANDLE ? stdout : stderr); - std::unique_ptr stream(nullptr, fclose); - - if (original_fd == -1) { - fprintf(stderr, "adb: failed to get file descriptor for %s: %s\n", output_name, - strerror(errno)); - return EXIT_FAILURE; - } - - // If fileno() is -2, stdout/stderr is not associated with an output stream, so we should read, - // but don't write. Otherwise, make a FILE* identical to stdout/stderr except that it is in - // binary mode with no CR/LR translation since we're reading raw. - if (original_fd >= 0) { - // This internally makes a duplicate file handle that is inheritable, so callers should not - // call this function if subprocesses may be started concurrently. - const int fd = dup(original_fd); - if (fd == -1) { - fprintf(stderr, "adb: failed to duplicate file descriptor for %s: %s\n", output_name, - strerror(errno)); - return EXIT_FAILURE; - } - - // Note that although we call fdopen() below with a binary flag, it may not adhere to that - // flag, so we have to set the mode manually. - if (_setmode(fd, _O_BINARY) == -1) { - fprintf(stderr, "adb: failed to set binary mode for duplicate of %s: %s\n", output_name, - strerror(errno)); - unix_close(fd); - return EXIT_FAILURE; - } - - stream.reset(fdopen(fd, "wb")); - if (stream.get() == nullptr) { - fprintf(stderr, "adb: failed to open duplicate stream for %s: %s\n", output_name, - strerror(errno)); - unix_close(fd); - return EXIT_FAILURE; - } - - // Unbuffer the stream because it will be buffered by default and we want subprocess output - // to be shown immediately. - if (setvbuf(stream.get(), NULL, _IONBF, 0) == -1) { - fprintf(stderr, "adb: failed to unbuffer %s: %s\n", output_name, strerror(errno)); - return EXIT_FAILURE; - } - - // fd will be closed when stream is closed. - } - - while (true) { - char buf[64 * 1024]; - DWORD bytes_read = 0; - if (!ReadFile(read_pipe.get(), buf, sizeof(buf), &bytes_read, NULL)) { - const DWORD err = GetLastError(); - // ERROR_BROKEN_PIPE is expected when the subprocess closes - // the other end of the pipe. - if (err == ERROR_BROKEN_PIPE) { - return EXIT_SUCCESS; - } else { - fprintf(stderr, "adb: failed to read from %s: %s\n", output_name, - android::base::SystemErrorCodeToString(err).c_str()); - return EXIT_FAILURE; - } - } - - // Don't try to write if our stdout/stderr was not setup by the parent process. - if (stream) { - // fwrite() actually calls adb_fwrite() which can write UTF-8 to the console. - const size_t bytes_written = fwrite(buf, 1, bytes_read, stream.get()); - if (bytes_written != bytes_read) { - fprintf(stderr, "adb: error: only wrote %zu of %lu bytes to %s\n", bytes_written, - bytes_read, output_name); - return EXIT_FAILURE; - } - } - } -} - -static unsigned __stdcall _redirect_stdout_thread(HANDLE h) { - adb_thread_setname("stdout redirect"); - return _redirect_pipe_thread(h, STD_OUTPUT_HANDLE); -} - -static unsigned __stdcall _redirect_stderr_thread(HANDLE h) { - adb_thread_setname("stderr redirect"); - return _redirect_pipe_thread(h, STD_ERROR_HANDLE); -} - -#endif - -static void ReportServerStartupFailure(pid_t pid) { - fprintf(stderr, "ADB server didn't ACK\n"); - fprintf(stderr, "Full server startup log: %s\n", GetLogFilePath().c_str()); - fprintf(stderr, "Server had pid: %d\n", pid); - - android::base::unique_fd fd(unix_open(GetLogFilePath(), O_RDONLY)); - if (fd == -1) return; - - // Let's not show more than 128KiB of log... - unix_lseek(fd, -128 * 1024, SEEK_END); - std::string content; - if (!android::base::ReadFdToString(fd, &content)) return; - - std::string header = android::base::StringPrintf("--- adb starting (pid %d) ---", pid); - std::vector lines = android::base::Split(content, "\n"); - int i = lines.size() - 1; - while (i >= 0 && lines[i] != header) --i; - while (static_cast(i) < lines.size()) fprintf(stderr, "%s\n", lines[i++].c_str()); -} - -int launch_server(const std::string& socket_spec) { -#if defined(_WIN32) - /* we need to start the server in the background */ - /* we create a PIPE that will be used to wait for the server's "OK" */ - /* message since the pipe handles must be inheritable, we use a */ - /* security attribute */ - SECURITY_ATTRIBUTES sa; - sa.nLength = sizeof(sa); - sa.lpSecurityDescriptor = NULL; - sa.bInheritHandle = TRUE; - - // Redirect stdin to Windows /dev/null. If we instead pass an original - // stdin/stdout/stderr handle and it is a console handle, when the adb - // server starts up, the C Runtime will see a console handle for a process - // that isn't connected to a console and it will configure - // stdin/stdout/stderr to be closed. At that point, freopen() could be used - // to reopen stderr/out, but it would take more massaging to fixup the file - // descriptor number that freopen() uses. It's simplest to avoid all of this - // complexity by just redirecting stdin to `nul' and then the C Runtime acts - // as expected. - unique_handle nul_read(CreateFileW(L"nul", GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, NULL)); - if (nul_read.get() == INVALID_HANDLE_VALUE) { - fprintf(stderr, "adb: CreateFileW 'nul' failed: %s\n", - android::base::SystemErrorCodeToString(GetLastError()).c_str()); - return -1; - } - - // Create pipes with non-inheritable read handle, inheritable write handle. We need to connect - // the subprocess to pipes instead of just letting the subprocess inherit our existing - // stdout/stderr handles because a DETACHED_PROCESS cannot write to a console that it is not - // attached to. - unique_handle ack_read, ack_write; - if (!_create_anonymous_pipe(&ack_read, &ack_write, &sa)) { - return -1; - } - unique_handle stdout_read, stdout_write; - if (!_create_anonymous_pipe(&stdout_read, &stdout_write, &sa)) { - return -1; - } - unique_handle stderr_read, stderr_write; - if (!_create_anonymous_pipe(&stderr_read, &stderr_write, &sa)) { - return -1; - } - - /* 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). - * Note that even if we don't pass these handles in the STARTUPINFO struct, - * if they're marked inheritable, they're still inherited, requiring us to - * deal with this. - * - * If we're still having problems with inheriting random handles in the - * future, consider using PROC_THREAD_ATTRIBUTE_HANDLE_LIST to explicitly - * specify which handles should be inherited: http://blogs.msdn.com/b/oldnewthing/archive/2011/12/16/10248328.aspx - * - * Older versions of Windows return console pseudo-handles that cannot be - * made non-inheritable, so ignore those failures. - */ - _try_make_handle_noninheritable(GetStdHandle(STD_INPUT_HANDLE)); - _try_make_handle_noninheritable(GetStdHandle(STD_OUTPUT_HANDLE)); - _try_make_handle_noninheritable(GetStdHandle(STD_ERROR_HANDLE)); - - STARTUPINFOW startup; - ZeroMemory( &startup, sizeof(startup) ); - startup.cb = sizeof(startup); - startup.hStdInput = nul_read.get(); - startup.hStdOutput = stdout_write.get(); - startup.hStdError = stderr_write.get(); - startup.dwFlags = STARTF_USESTDHANDLES; - - // Verify that the pipe_write handle value can be passed on the command line - // as %d and that the rest of adb code can pass it around in an int. - const int ack_write_as_int = cast_handle_to_int(ack_write.get()); - if (cast_int_to_handle(ack_write_as_int) != ack_write.get()) { - // If this fires, either handle values are larger than 32-bits or else - // there is a bug in our casting. - // https://msdn.microsoft.com/en-us/library/windows/desktop/aa384203%28v=vs.85%29.aspx - fprintf(stderr, "adb: cannot fit pipe handle value into 32-bits: 0x%p\n", ack_write.get()); - return -1; - } - - // get path of current program - WCHAR program_path[MAX_PATH]; - const DWORD module_result = GetModuleFileNameW(NULL, program_path, - arraysize(program_path)); - if ((module_result >= arraysize(program_path)) || (module_result == 0)) { - // String truncation or some other error. - fprintf(stderr, "adb: cannot get executable path: %s\n", - android::base::SystemErrorCodeToString(GetLastError()).c_str()); - return -1; - } - - WCHAR args[64]; - snwprintf(args, arraysize(args), L"adb -L %s fork-server server --reply-fd %d", - socket_spec.c_str(), ack_write_as_int); - - PROCESS_INFORMATION pinfo; - ZeroMemory(&pinfo, sizeof(pinfo)); - - if (!CreateProcessW( - program_path, /* program path */ - args, - /* 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 )) { - fprintf(stderr, "adb: CreateProcessW failed: %s\n", - android::base::SystemErrorCodeToString(GetLastError()).c_str()); - return -1; - } - - unique_handle process_handle(pinfo.hProcess); - pinfo.hProcess = NULL; - - // Close handles that we no longer need to complete the rest. - CloseHandle(pinfo.hThread); - pinfo.hThread = NULL; - - nul_read.reset(); - ack_write.reset(); - stdout_write.reset(); - stderr_write.reset(); - - // Start threads to read from subprocess stdout/stderr and write to ours to make subprocess - // errors easier to diagnose. Note that the threads internally create inheritable handles, but - // that is ok because we've already spawned the subprocess. - - // In the past, reading from a pipe before the child process's C Runtime - // started up and called GetFileType() caused a hang: http://blogs.msdn.com/b/oldnewthing/archive/2011/12/02/10243553.aspx#10244216 - // This is reportedly fixed in Windows Vista: https://support.microsoft.com/en-us/kb/2009703 - // I was unable to reproduce the problem on Windows XP. It sounds like a - // Windows Update may have fixed this: https://www.duckware.com/tech/peeknamedpipe.html - unique_handle stdout_thread(reinterpret_cast( - _beginthreadex(NULL, 0, _redirect_stdout_thread, stdout_read.get(), - 0, NULL))); - if (stdout_thread.get() == nullptr) { - fprintf(stderr, "adb: cannot create thread: %s\n", strerror(errno)); - return -1; - } - stdout_read.release(); // Transfer ownership to new thread - - unique_handle stderr_thread(reinterpret_cast( - _beginthreadex(NULL, 0, _redirect_stderr_thread, stderr_read.get(), - 0, NULL))); - if (stderr_thread.get() == nullptr) { - fprintf(stderr, "adb: cannot create thread: %s\n", strerror(errno)); - return -1; - } - stderr_read.release(); // Transfer ownership to new thread - - bool got_ack = false; - - // Wait for the "OK\n" message, for the pipe to be closed, or other error. - { - char temp[3]; - DWORD count = 0; - - if (ReadFile(ack_read.get(), temp, sizeof(temp), &count, NULL)) { - const CHAR expected[] = "OK\n"; - const DWORD expected_length = arraysize(expected) - 1; - if (count == expected_length && - memcmp(temp, expected, expected_length) == 0) { - got_ack = true; - } else { - ReportServerStartupFailure(pinfo.dwProcessId); - return -1; - } - } else { - const DWORD err = GetLastError(); - // If the ACK was not written and the process exited, GetLastError() - // is probably ERROR_BROKEN_PIPE, in which case that info is not - // useful to the user. - fprintf(stderr, "could not read ok from ADB Server%s\n", - err == ERROR_BROKEN_PIPE ? "" : - android::base::StringPrintf(": %s", - android::base::SystemErrorCodeToString(err).c_str()).c_str()); - } - } - - // Always try to wait a bit for threads reading stdout/stderr to finish. - // If the process started ok, it should close the pipes causing the threads - // to finish. If the process had an error, it should exit, also causing - // the pipes to be closed. In that case we want to read all of the output - // and write it out so that the user can diagnose failures. - const DWORD thread_timeout_ms = 15 * 1000; - const HANDLE threads[] = { stdout_thread.get(), stderr_thread.get() }; - const DWORD wait_result = WaitForMultipleObjects(arraysize(threads), - threads, TRUE, thread_timeout_ms); - if (wait_result == WAIT_TIMEOUT) { - // Threads did not finish after waiting a little while. Perhaps the - // server didn't close pipes, or it is hung. - fprintf(stderr, "adb: timed out waiting for threads to finish reading from ADB server\n"); - // Process handles are signaled when the process exits, so if we wait - // on the handle for 0 seconds and it returns 'timeout', that means that - // the process is still running. - if (WaitForSingleObject(process_handle.get(), 0) == WAIT_TIMEOUT) { - // We could TerminateProcess(), but that seems somewhat presumptive. - fprintf(stderr, "adb: server is running with process id %lu\n", pinfo.dwProcessId); - } - return -1; - } - - if (wait_result != WAIT_OBJECT_0) { - fprintf(stderr, "adb: unexpected result waiting for threads: %lu: %s\n", wait_result, - android::base::SystemErrorCodeToString(GetLastError()).c_str()); - return -1; - } - - // For now ignore the thread exit codes and assume they worked properly. - - if (!got_ack) { - return -1; - } -#else /* !defined(_WIN32) */ - // set up a pipe so the child can tell us when it is ready. - unique_fd pipe_read, pipe_write; - if (!Pipe(&pipe_read, &pipe_write)) { - fprintf(stderr, "pipe failed in launch_server, errno: %d\n", errno); - return -1; - } - - std::string path = android::base::GetExecutablePath(); - - pid_t pid = fork(); - if (pid < 0) return -1; - - if (pid == 0) { - // child side of the fork - pipe_read.reset(); - - // android::base::Pipe unconditionally opens the pipe with O_CLOEXEC. - // Undo this manually. - fcntl(pipe_write.get(), F_SETFD, 0); - - char reply_fd[30]; - snprintf(reply_fd, sizeof(reply_fd), "%d", pipe_write.get()); - // child process - int result = execl(path.c_str(), "adb", "-L", socket_spec.c_str(), "fork-server", "server", - "--reply-fd", reply_fd, NULL); - // this should not return - fprintf(stderr, "adb: execl returned %d: %s\n", result, strerror(errno)); - } else { - // parent side of the fork - char temp[3] = {}; - // wait for the "OK\n" message - pipe_write.reset(); - int ret = adb_read(pipe_read.get(), temp, 3); - int saved_errno = errno; - pipe_read.reset(); - 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') { - ReportServerStartupFailure(pid); - return -1; - } - } -#endif /* !defined(_WIN32) */ - return 0; -} -#endif /* ADB_HOST */ - -bool handle_forward_request(const char* service, atransport* transport, int reply_fd) { - return handle_forward_request(service, [transport](std::string*) { return transport; }, - reply_fd); -} - -// Try to handle a network forwarding request. -bool handle_forward_request(const char* service, - std::function transport_acquirer, - int reply_fd) { - if (!strcmp(service, "list-forward")) { - // Create the list of forward redirections. - std::string listeners = format_listeners(); -#if ADB_HOST - SendOkay(reply_fd); -#endif - SendProtocolString(reply_fd, listeners); - return true; - } - - if (!strcmp(service, "killforward-all")) { - remove_all_listeners(); -#if ADB_HOST - /* On the host: 1st OKAY is connect, 2nd OKAY is status */ - SendOkay(reply_fd); -#endif - SendOkay(reply_fd); - return true; - } - - if (!strncmp(service, "forward:", 8) || !strncmp(service, "killforward:", 12)) { - // killforward:local - // forward:(norebind:)?local;remote - std::string error; - atransport* transport = transport_acquirer(&error); - if (!transport) { - SendFail(reply_fd, error); - return true; - } - - bool kill_forward = false; - bool no_rebind = false; - if (android::base::StartsWith(service, "killforward:")) { - kill_forward = true; - service += 12; - } else { - service += 8; // skip past "forward:" - if (android::base::StartsWith(service, "norebind:")) { - no_rebind = true; - service += 9; - } - } - - std::vector pieces = android::base::Split(service, ";"); - - if (kill_forward) { - // Check killforward: parameter format: '' - if (pieces.size() != 1 || pieces[0].empty()) { - SendFail(reply_fd, android::base::StringPrintf("bad killforward: %s", service)); - return true; - } - } else { - // Check forward: parameter format: ';' - if (pieces.size() != 2 || pieces[0].empty() || pieces[1].empty() || pieces[1][0] == '*') { - SendFail(reply_fd, android::base::StringPrintf("bad forward: %s", service)); - return true; - } - } - - InstallStatus r; - int resolved_tcp_port = 0; - if (kill_forward) { - r = remove_listener(pieces[0].c_str(), transport); - } else { - r = install_listener(pieces[0], pieces[1].c_str(), transport, no_rebind, - &resolved_tcp_port, &error); - } - if (r == INSTALL_STATUS_OK) { -#if ADB_HOST - // On the host: 1st OKAY is connect, 2nd OKAY is status. - SendOkay(reply_fd); -#endif - SendOkay(reply_fd); - - // If a TCP port was resolved, send the actual port number back. - if (resolved_tcp_port != 0) { - SendProtocolString(reply_fd, android::base::StringPrintf("%d", resolved_tcp_port)); - } - - return true; - } - - std::string message; - switch (r) { - case INSTALL_STATUS_OK: message = "success (!)"; break; - case INSTALL_STATUS_INTERNAL_ERROR: message = "internal error"; break; - case INSTALL_STATUS_CANNOT_BIND: - message = android::base::StringPrintf("cannot bind listener: %s", - error.c_str()); - break; - case INSTALL_STATUS_CANNOT_REBIND: - message = android::base::StringPrintf("cannot rebind existing socket"); - break; - case INSTALL_STATUS_LISTENER_NOT_FOUND: - message = android::base::StringPrintf("listener '%s' not found", service); - break; - } - SendFail(reply_fd, message); - return true; - } - - return false; -} - -#if ADB_HOST -static int SendOkay(int fd, const std::string& s) { - SendOkay(fd); - SendProtocolString(fd, s); - return 0; -} - -HostRequestResult handle_host_request(std::string_view service, TransportType type, - const char* serial, TransportId transport_id, int reply_fd, - asocket* s) { - if (service == "kill") { - fprintf(stderr, "adb server killed by remote request\n"); - fflush(stdout); - - // Send a reply even though we don't read it anymore, so that old versions - // of adb that do read it don't spew error messages. - SendOkay(reply_fd); - - // Rely on process exit to close the socket for us. - exit(0); - } - - LOG(DEBUG) << "handle_host_request(" << service << ")"; - - // Transport selection: - if (service.starts_with("transport") || service.starts_with("tport:")) { - TransportType type = kTransportAny; - - std::string serial_storage; - bool legacy = true; - - // New transport selection protocol: - // This is essentially identical to the previous version, except it returns the selected - // transport id to the caller as well. - if (android::base::ConsumePrefix(&service, "tport:")) { - legacy = false; - if (android::base::ConsumePrefix(&service, "serial:")) { - serial_storage = service; - serial = serial_storage.c_str(); - } else if (service == "usb") { - type = kTransportUsb; - } else if (service == "local") { - type = kTransportLocal; - } else if (service == "any") { - type = kTransportAny; - } - - // Selection by id is unimplemented, since you obviously already know the transport id - // you're connecting to. - } else { - if (android::base::ConsumePrefix(&service, "transport-id:")) { - if (!ParseUint(&transport_id, service)) { - SendFail(reply_fd, "invalid transport id"); - return HostRequestResult::Handled; - } - } else if (service == "transport-usb") { - type = kTransportUsb; - } else if (service == "transport-local") { - type = kTransportLocal; - } else if (service == "transport-any") { - type = kTransportAny; - } else if (android::base::ConsumePrefix(&service, "transport:")) { - serial_storage = service; - serial = serial_storage.c_str(); - } - } - - std::string error; - atransport* t = acquire_one_transport(type, serial, transport_id, nullptr, &error); - if (t != nullptr) { - s->transport = t; - SendOkay(reply_fd); - - if (!legacy) { - // Nothing we can do if this fails. - WriteFdExactly(reply_fd, &t->id, sizeof(t->id)); - } - - return HostRequestResult::SwitchedTransport; - } else { - SendFail(reply_fd, error); - return HostRequestResult::Handled; - } - } - - // return a list of all connected devices - if (service == "devices" || service == "devices-l") { - bool long_listing = service == "devices-l"; - D("Getting device list..."); - std::string device_list = list_transports(long_listing); - D("Sending device list..."); - SendOkay(reply_fd, device_list); - return HostRequestResult::Handled; - } - - if (service == "reconnect-offline") { - std::string response; - close_usb_devices([&response](const atransport* transport) { - if (!ConnectionStateIsOnline(transport->GetConnectionState())) { - response += "reconnecting " + transport->serial_name() + "\n"; - return true; - } - return false; - }, true); - if (!response.empty()) { - response.resize(response.size() - 1); - } - SendOkay(reply_fd, response); - return HostRequestResult::Handled; - } - - if (service == "features") { - std::string error; - atransport* t = - s->transport ? s->transport - : acquire_one_transport(type, serial, transport_id, nullptr, &error); - if (t != nullptr) { - SendOkay(reply_fd, FeatureSetToString(t->features())); - } else { - SendFail(reply_fd, error); - } - return HostRequestResult::Handled; - } - - if (service == "host-features") { - FeatureSet features = supported_features(); - // Abuse features to report libusb status. - if (should_use_libusb()) { - features.insert(kFeatureLibusb); - } - features.insert(kFeaturePushSync); - SendOkay(reply_fd, FeatureSetToString(features)); - return HostRequestResult::Handled; - } - - // remove TCP transport - if (service.starts_with("disconnect:")) { - std::string address(service.substr(11)); - if (address.empty()) { - kick_all_tcp_devices(); - SendOkay(reply_fd, "disconnected everything"); - return HostRequestResult::Handled; - } - - std::string serial; - std::string host; - int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT; - std::string error; - if (address.starts_with("vsock:") || address.starts_with("localfilesystem:")) { - serial = address; - } else if (!android::base::ParseNetAddress(address, &host, &port, &serial, &error)) { - SendFail(reply_fd, android::base::StringPrintf("couldn't parse '%s': %s", - address.c_str(), error.c_str())); - return HostRequestResult::Handled; - } - atransport* t = find_transport(serial.c_str()); - if (t == nullptr) { - SendFail(reply_fd, android::base::StringPrintf("no such device '%s'", serial.c_str())); - return HostRequestResult::Handled; - } - kick_transport(t); - SendOkay(reply_fd, android::base::StringPrintf("disconnected %s", address.c_str())); - return HostRequestResult::Handled; - } - - // Returns our value for ADB_SERVER_VERSION. - if (service == "version") { - SendOkay(reply_fd, android::base::StringPrintf("%04x", ADB_SERVER_VERSION)); - return HostRequestResult::Handled; - } - - // These always report "unknown" rather than the actual error, for scripts. - if (service == "get-serialno") { - std::string error; - atransport* t = - s->transport ? s->transport - : acquire_one_transport(type, serial, transport_id, nullptr, &error); - if (t) { - SendOkay(reply_fd, !t->serial.empty() ? t->serial : "unknown"); - } else { - SendFail(reply_fd, error); - } - return HostRequestResult::Handled; - } - if (service == "get-devpath") { - std::string error; - atransport* t = - s->transport ? s->transport - : acquire_one_transport(type, serial, transport_id, nullptr, &error); - if (t) { - SendOkay(reply_fd, !t->devpath.empty() ? t->devpath : "unknown"); - } else { - SendFail(reply_fd, error); - } - return HostRequestResult::Handled; - } - if (service == "get-state") { - std::string error; - atransport* t = - s->transport ? s->transport - : acquire_one_transport(type, serial, transport_id, nullptr, &error); - if (t) { - SendOkay(reply_fd, t->connection_state_name()); - } else { - SendFail(reply_fd, error); - } - return HostRequestResult::Handled; - } - - // Indicates a new emulator instance has started. - if (android::base::ConsumePrefix(&service, "emulator:")) { - unsigned int port; - if (!ParseUint(&port, service)) { - LOG(ERROR) << "received invalid port for emulator: " << service; - } else { - local_connect(port); - } - - /* we don't even need to send a reply */ - return HostRequestResult::Handled; - } - - if (service == "reconnect") { - std::string response; - atransport* t = s->transport ? s->transport - : acquire_one_transport(type, serial, transport_id, nullptr, - &response, true); - if (t != nullptr) { - kick_transport(t, true); - response = - "reconnecting " + t->serial_name() + " [" + t->connection_state_name() + "]\n"; - } - SendOkay(reply_fd, response); - return HostRequestResult::Handled; - } - - // TODO: Switch handle_forward_request to string_view. - std::string service_str(service); - auto transport_acquirer = [=](std::string* error) { - if (s->transport) { - return s->transport; - } else { - std::string error; - return acquire_one_transport(type, serial, transport_id, nullptr, &error); - } - }; - if (handle_forward_request(service_str.c_str(), transport_acquirer, reply_fd)) { - return HostRequestResult::Handled; - } - - return HostRequestResult::Unhandled; -} - -static auto& init_mutex = *new std::mutex(); -static auto& init_cv = *new std::condition_variable(); -static bool device_scan_complete = false; -static bool transports_ready = false; - -void update_transport_status() { - bool result = iterate_transports([](const atransport* t) { - if (t->type == kTransportUsb && t->online != 1) { - return false; - } - return true; - }); - - bool ready; - { - std::lock_guard lock(init_mutex); - transports_ready = result; - ready = transports_ready && device_scan_complete; - } - - if (ready) { - init_cv.notify_all(); - } -} - -void adb_notify_device_scan_complete() { - { - std::lock_guard lock(init_mutex); - if (device_scan_complete) { - return; - } - - device_scan_complete = true; - } - - update_transport_status(); -} - -void adb_wait_for_device_initialization() { - std::unique_lock lock(init_mutex); - init_cv.wait_for(lock, 3s, []() { return device_scan_complete && transports_ready; }); -} - -#endif // ADB_HOST diff --git a/adb/adb.h b/adb/adb.h deleted file mode 100644 index ce12a55f96d0d7b719917dc21de4c33f436f9474..0000000000000000000000000000000000000000 --- a/adb/adb.h +++ /dev/null @@ -1,254 +0,0 @@ -/* - * 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 -#include - -#include - -#include - -#include "adb_trace.h" -#include "fdevent/fdevent.h" -#include "socket.h" -#include "types.h" - -constexpr size_t MAX_PAYLOAD_V1 = 4 * 1024; -constexpr size_t MAX_PAYLOAD = 1024 * 1024; -constexpr size_t MAX_FRAMEWORK_PAYLOAD = 64 * 1024; - -constexpr size_t LINUX_MAX_SOCKET_SIZE = 4194304; - -#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_STLS 0x534C5453 - -// ADB protocol version. -// Version revision: -// 0x01000000: original -// 0x01000001: skip checksum (Dec 2017) -#define A_VERSION_MIN 0x01000000 -#define A_VERSION_SKIP_CHECKSUM 0x01000001 -#define A_VERSION 0x01000001 - -// Stream-based TLS protocol version -#define A_STLS_VERSION_MIN 0x01000000 -#define A_STLS_VERSION 0x01000000 - -// Used for help/version information. -#define ADB_VERSION_MAJOR 1 -#define ADB_VERSION_MINOR 0 - -std::string adb_version(); - -// Increment this when we want to force users to start a new adb server. -#define ADB_SERVER_VERSION 41 - -using TransportId = uint64_t; -class atransport; - -uint32_t calculate_apacket_checksum(const apacket* packet); - -/* 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; -}; - -// 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. -enum TransportType { - kTransportUsb, - kTransportLocal, - kTransportAny, - kTransportHost, -}; - -#define TOKEN_SIZE 20 - -enum ConnectionState { - kCsAny = -1, - - kCsConnecting = 0, // Haven't received a response from the device yet. - kCsAuthorizing, // Authorizing with keys from ADB_VENDOR_KEYS. - kCsUnauthorized, // ADB_VENDOR_KEYS exhausted, fell back to user prompt. - kCsNoPerm, // Insufficient permissions to communicate with the device. - kCsOffline, - - kCsBootloader, - kCsDevice, - kCsHost, - kCsRecovery, - kCsSideload, - kCsRescue, -}; - -inline bool ConnectionStateIsOnline(ConnectionState state) { - switch (state) { - case kCsBootloader: - case kCsDevice: - case kCsHost: - case kCsRecovery: - case kCsSideload: - case kCsRescue: - return true; - default: - return false; - } -} - -void print_packet(const char* label, apacket* p); - -void handle_packet(apacket* p, atransport* t); - -int launch_server(const std::string& socket_spec); -int adb_server_main(int is_daemon, const std::string& socket_spec, int ack_reply_fd); - -/* initialize a transport object's func pointers and state */ -int init_socket_transport(atransport* t, unique_fd s, int port, int local); - -std::string getEmulatorSerialString(int console_port); -#if ADB_HOST -atransport* find_emulator_transport_by_adb_port(int adb_port); -atransport* find_emulator_transport_by_console_port(int console_port); -#endif - -unique_fd service_to_fd(std::string_view name, atransport* transport); -#if !ADB_HOST -unique_fd daemon_service_to_fd(std::string_view name, atransport* transport); -#endif - -#if ADB_HOST -asocket* host_service_to_socket(std::string_view name, std::string_view serial, - TransportId transport_id); -#endif - -#if !ADB_HOST -asocket* daemon_service_to_socket(std::string_view name); -#endif - -#if !ADB_HOST -unique_fd execute_abb_command(std::string_view command); -#endif - -#if !ADB_HOST -int init_jdwp(void); -asocket* create_jdwp_service_socket(); -asocket* create_jdwp_tracker_service_socket(); -unique_fd create_jdwp_connection_fd(int jdwp_pid); -#endif - -bool handle_forward_request(const char* service, atransport* transport, int reply_fd); -bool handle_forward_request(const char* service, - std::function transport_acquirer, - int reply_fd); - -/* packet allocator */ -apacket* get_apacket(void); -void put_apacket(apacket* p); - -// Define it if you want to dump packets. -#define DEBUG_PACKETS 0 - -#if !DEBUG_PACKETS -#define print_packet(tag, p) \ - do { \ - } while (0) -#endif - -#define DEFAULT_ADB_PORT 5037 - -#define DEFAULT_ADB_LOCAL_TRANSPORT_PORT 5555 - -#define ADB_CLASS 0xff -#define ADB_SUBCLASS 0x42 -#define ADB_PROTOCOL 0x1 - -void local_init(const std::string& addr); -bool local_connect(int port); -int local_connect_arbitrary_ports(int console_port, int adb_port, std::string* error); - -ConnectionState connection_state(atransport* t); - -extern const char* adb_device_banner; - -#define CHUNK_SIZE (64 * 1024) - -// Argument delimeter for adb abb command. -#define ABB_ARG_DELIMETER ('\0') - -#if !ADB_HOST -#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 - -enum class HostRequestResult { - Handled, - SwitchedTransport, - Unhandled, -}; - -HostRequestResult handle_host_request(std::string_view service, TransportType type, - const char* serial, TransportId transport_id, int reply_fd, - asocket* s); - -void handle_online(atransport* t); -void handle_offline(atransport* t); - -void send_connect(atransport* t); -void send_tls_request(atransport* t); - -void parse_banner(const std::string&, atransport* t); - -// On startup, the adb server needs to wait until all of the connected devices are ready. -// To do this, we need to know when the scan has identified all of the potential new transports, and -// when each transport becomes ready. -// TODO: Do this for mDNS as well, instead of just USB? - -// We've found all of the transports we potentially care about. -void adb_notify_device_scan_complete(); - -// One or more transports have changed status, check to see if we're ready. -void update_transport_status(); - -// Wait until device scan has completed and every transport is ready, or a timeout elapses. -void adb_wait_for_device_initialization(); - -void usb_init(); -#endif diff --git a/adb/adb_auth.h b/adb/adb_auth.h deleted file mode 100644 index 7e858dce4fcbaea75ec0b6914ab2139a10f27148..0000000000000000000000000000000000000000 --- a/adb/adb_auth.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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 - -#include "adb.h" - -#include -#include - -#include - -/* AUTH packets first argument */ -/* Request */ -#define ADB_AUTH_TOKEN 1 -/* Response */ -#define ADB_AUTH_SIGNATURE 2 -#define ADB_AUTH_RSAPUBLICKEY 3 - -#if ADB_HOST - -void adb_auth_init(); - -int adb_auth_keygen(const char* filename); -int adb_auth_pubkey(const char* filename); -std::string adb_auth_get_userkey(); -bssl::UniquePtr adb_auth_get_user_privkey(); -std::deque> adb_auth_get_private_keys(); - -void send_auth_response(const char* token, size_t token_size, atransport* t); - -int adb_tls_set_certificate(SSL* ssl); -void adb_auth_tls_handshake(atransport* t); - -#else // !ADB_HOST - -extern bool auth_required; - -void adbd_auth_init(void); -void adbd_auth_verified(atransport *t); - -void adbd_cloexec_auth_socket(); -bool adbd_auth_verify(const char* token, size_t token_size, const std::string& sig, - std::string* auth_key); -void adbd_auth_confirm_key(atransport* t); -void adbd_notify_framework_connected_key(atransport* t); - -void send_auth_request(atransport *t); - -void adbd_auth_tls_handshake(atransport* t); -int adbd_tls_verify_cert(X509_STORE_CTX* ctx, std::string* auth_key); -bssl::UniquePtr adbd_tls_client_ca_list(); - -#endif // ADB_HOST - -#endif // __ADB_AUTH_H diff --git a/adb/adb_integration_test_adb.xml b/adb/adb_integration_test_adb.xml deleted file mode 100644 index e722956b8d8915b7e54b2d3df5cddfd56ebf6d64..0000000000000000000000000000000000000000 --- a/adb/adb_integration_test_adb.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - diff --git a/adb/adb_integration_test_device.xml b/adb/adb_integration_test_device.xml deleted file mode 100644 index b89237734dbd9200f9c2ac2dc0bd0583d9281e75..0000000000000000000000000000000000000000 --- a/adb/adb_integration_test_device.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - diff --git a/adb/adb_io.cpp b/adb/adb_io.cpp deleted file mode 100644 index bdb8efa5cee2f0e88483659c825268dff2dbe5e7..0000000000000000000000000000000000000000 --- a/adb/adb_io.cpp +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright (C) 2015 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 RWX - -#include "adb_io.h" - -#include - -#if !ADB_HOST -#include -#include -#endif - -#include - -#include - -#include "adb.h" -#include "adb_trace.h" -#include "adb_utils.h" -#include "sysdeps.h" - -bool SendProtocolString(borrowed_fd fd, std::string_view s) { - unsigned int length = s.size(); - if (length > MAX_PAYLOAD - 4) { - errno = EMSGSIZE; - return false; - } - - // The cost of sending two strings outweighs the cost of formatting. - // "adb sync" performance is affected by this. - auto str = android::base::StringPrintf("%04x", length).append(s); - return WriteFdExactly(fd, str); -} - -bool ReadProtocolString(borrowed_fd fd, std::string* s, std::string* error) { - char buf[5]; - if (!ReadFdExactly(fd, buf, 4)) { - *error = perror_str("protocol fault (couldn't read status length)"); - return false; - } - buf[4] = 0; - - unsigned long len = strtoul(buf, nullptr, 16); - s->resize(len, '\0'); - if (!ReadFdExactly(fd, &(*s)[0], len)) { - *error = perror_str("protocol fault (couldn't read status message)"); - return false; - } - - return true; -} - -bool SendOkay(borrowed_fd fd) { - return WriteFdExactly(fd, "OKAY", 4); -} - -bool SendFail(borrowed_fd fd, std::string_view reason) { - return WriteFdExactly(fd, "FAIL", 4) && SendProtocolString(fd, reason); -} - -bool ReadFdExactly(borrowed_fd fd, void* buf, size_t len) { - char* p = reinterpret_cast(buf); - - size_t len0 = len; - - D("readx: fd=%d wanted=%zu", fd.get(), len); - while (len > 0) { - int r = adb_read(fd, p, len); - if (r > 0) { - len -= r; - p += r; - } else if (r == -1) { - D("readx: fd=%d error %d: %s", fd.get(), errno, strerror(errno)); - return false; - } else { - D("readx: fd=%d disconnected", fd.get()); - errno = 0; - return false; - } - } - - VLOG(RWX) << "readx: fd=" << fd.get() << " wanted=" << len0 << " got=" << (len0 - len) << " " - << dump_hex(reinterpret_cast(buf), len0); - - return true; -} - -bool WriteFdExactly(borrowed_fd fd, const void* buf, size_t len) { - const char* p = reinterpret_cast(buf); - int r; - - VLOG(RWX) << "writex: fd=" << fd.get() << " len=" << len << " " - << dump_hex(reinterpret_cast(buf), len); - - while (len > 0) { - r = adb_write(fd, p, len); - if (r == -1) { - D("writex: fd=%d error %d: %s", fd.get(), errno, strerror(errno)); - if (errno == EAGAIN) { - std::this_thread::yield(); - continue; - } else if (errno == EPIPE) { - D("writex: fd=%d disconnected", fd.get()); - errno = 0; - return false; - } else { - return false; - } - } else { - len -= r; - p += r; - } - } - return true; -} - -bool WriteFdExactly(borrowed_fd fd, const char* str) { - return WriteFdExactly(fd, str, strlen(str)); -} - -bool WriteFdExactly(borrowed_fd fd, const std::string& str) { - return WriteFdExactly(fd, str.c_str(), str.size()); -} - -bool WriteFdFmt(borrowed_fd fd, const char* fmt, ...) { - std::string str; - - va_list ap; - va_start(ap, fmt); - android::base::StringAppendV(&str, fmt, ap); - va_end(ap); - - return WriteFdExactly(fd, str); -} - -bool ReadOrderlyShutdown(borrowed_fd fd) { - char buf[16]; - - // Only call this function if you're sure that the peer does - // orderly/graceful shutdown of the socket, closing the socket so that - // adb_read() will return 0. If the peer keeps the socket open, adb_read() - // will never return. - int result = adb_read(fd, buf, sizeof(buf)); - if (result == -1) { - // If errno is EAGAIN, that means this function was called on a - // nonblocking socket and it would have blocked (which would be bad - // because we'd probably block the main thread where nonblocking IO is - // done). Don't do that. If you have a nonblocking socket, use the - // fdevent APIs to get called on FDE_READ, and then call this function - // if you really need to, but it shouldn't be needed for server sockets. - CHECK_NE(errno, EAGAIN); - - // Note that on Windows, orderly shutdown sometimes causes - // recv() == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET. That - // can be ignored. - return false; - } else if (result == 0) { - // Peer has performed an orderly/graceful shutdown. - return true; - } else { - // Unexpectedly received data. This is essentially a protocol error - // because you should not call this function unless you expect no more - // data. We don't repeatedly call adb_read() until we get zero because - // we don't know how long that would take, but we do know that the - // caller wants to close the socket soon. - VLOG(RWX) << "ReadOrderlyShutdown(" << fd.get() << ") unexpectedly read " - << dump_hex(buf, result); - // Shutdown the socket to prevent the caller from reading or writing to - // it which doesn't make sense if we just read and discarded some data. - adb_shutdown(fd); - errno = EINVAL; - return false; - } -} diff --git a/adb/adb_io.h b/adb/adb_io.h deleted file mode 100644 index 96289461078b106bdb1141c946161d9047fc2d1f..0000000000000000000000000000000000000000 --- a/adb/adb_io.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2015 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_IO_H -#define ADB_IO_H - -#include - -#include -#include - -#include "adb_unique_fd.h" - -// Sends the protocol "OKAY" message. -bool SendOkay(borrowed_fd fd); - -// Sends the protocol "FAIL" message, with the given failure reason. -bool SendFail(borrowed_fd fd, std::string_view reason); - -// Writes a protocol-format string; a four hex digit length followed by the string data. -bool SendProtocolString(borrowed_fd fd, std::string_view s); - -// Reads a protocol-format string; a four hex digit length followed by the string data. -bool ReadProtocolString(borrowed_fd fd, std::string* s, std::string* error); - -// Reads exactly len bytes from fd into buf. -// -// Returns false if there is an error or if EOF was reached before len bytes -// were read. If EOF was found, errno will be set to 0. -// -// If this function fails, the contents of buf are undefined. -bool ReadFdExactly(borrowed_fd fd, void* buf, size_t len); - -// Given a client socket, wait for orderly/graceful shutdown. Call this: -// -// * Before closing a client socket. -// * Only when no more data is expected to come in. -// * Only when the server is not waiting for data from the client (because then -// the client and server will deadlock waiting for each other). -// * Only when the server is expected to close its socket right now. -// * Don't call shutdown(SHUT_WR) before calling this because that will shutdown -// the client socket early, defeating the purpose of calling this. -// -// Waiting for orderly/graceful shutdown of the server socket will cause the -// server socket to close before the client socket. That prevents the client -// socket from staying in TIME_WAIT which eventually causes subsequent -// connect()s from the client to fail with WSAEADDRINUSE on Windows. -// Returns true if it is sure that orderly/graceful shutdown has occurred with -// no additional data read from the server. -bool ReadOrderlyShutdown(borrowed_fd fd); - -// Writes exactly len bytes from buf to fd. -// -// Returns false if there is an error or if the fd was closed before the write -// completed. If the other end of the fd (such as in a socket, pipe, or fifo), -// is closed, errno will be set to 0. -bool WriteFdExactly(borrowed_fd fd, const void* buf, size_t len); - -// Same as above, but for strings. -bool WriteFdExactly(borrowed_fd fd, const char* s); -bool WriteFdExactly(borrowed_fd fd, const std::string& s); - -// Same as above, but formats the string to send. -bool WriteFdFmt(borrowed_fd fd, const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))); -#endif /* ADB_IO_H */ diff --git a/adb/adb_io_test.cpp b/adb/adb_io_test.cpp deleted file mode 100644 index 91b73a9a4735b328853d6bede6b522fd33ee2877..0000000000000000000000000000000000000000 --- a/adb/adb_io_test.cpp +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (C) 2015 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 "adb_io.h" - -#include - -#include -#include -#include -#include -#include -#include - -#include - -#include - -// All of these tests fail on Windows because they use the C Runtime open(), -// but the adb_io APIs expect file descriptors from adb_open(). This could -// theoretically be fixed by making adb_read()/adb_write() fallback to using -// read()/write() if an unrecognized fd is used, and by making adb_open() return -// fds far from the range that open() returns. But all of that might defeat the -// purpose of the tests. - -#if defined(_WIN32) -#define POSIX_TEST(x,y) TEST(DISABLED_ ## x,y) -#else -#define POSIX_TEST TEST -#endif - -POSIX_TEST(io, ReadFdExactly_whole) { - const char expected[] = "Foobar"; - TemporaryFile tf; - ASSERT_NE(-1, tf.fd); - - ASSERT_TRUE(android::base::WriteStringToFd(expected, tf.fd)) << strerror(errno); - ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)); - - // Test reading the whole file. - char buf[sizeof(expected)] = {}; - ASSERT_TRUE(ReadFdExactly(tf.fd, buf, sizeof(buf) - 1)) << strerror(errno); - EXPECT_STREQ(expected, buf); -} - -POSIX_TEST(io, ReadFdExactly_eof) { - const char expected[] = "Foobar"; - TemporaryFile tf; - ASSERT_NE(-1, tf.fd); - - ASSERT_TRUE(android::base::WriteStringToFd(expected, tf.fd)) << strerror(errno); - ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)); - - // Test that not having enough data will fail. - char buf[sizeof(expected) + 1] = {}; - ASSERT_FALSE(ReadFdExactly(tf.fd, buf, sizeof(buf))); - EXPECT_EQ(0, errno) << strerror(errno); -} - -POSIX_TEST(io, ReadFdExactly_partial) { - const char input[] = "Foobar"; - TemporaryFile tf; - ASSERT_NE(-1, tf.fd); - - ASSERT_TRUE(android::base::WriteStringToFd(input, tf.fd)) << strerror(errno); - ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)); - - // Test reading a partial file. - char buf[sizeof(input) - 1] = {}; - ASSERT_TRUE(ReadFdExactly(tf.fd, buf, sizeof(buf) - 1)); - - std::string expected(input); - expected.pop_back(); - EXPECT_STREQ(expected.c_str(), buf); -} - -POSIX_TEST(io, WriteFdExactly_whole) { - const char expected[] = "Foobar"; - TemporaryFile tf; - ASSERT_NE(-1, tf.fd); - - // Test writing the whole string to the file. - ASSERT_TRUE(WriteFdExactly(tf.fd, expected, sizeof(expected))) - << strerror(errno); - ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)); - - std::string s; - ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s)); - EXPECT_STREQ(expected, s.c_str()); -} - -POSIX_TEST(io, WriteFdExactly_partial) { - const char buf[] = "Foobar"; - TemporaryFile tf; - ASSERT_NE(-1, tf.fd); - - // Test writing a partial string to the file. - ASSERT_TRUE(WriteFdExactly(tf.fd, buf, sizeof(buf) - 2)) << strerror(errno); - ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)); - - std::string expected(buf); - expected.pop_back(); - - std::string s; - ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s)); - EXPECT_EQ(expected, s); -} - -POSIX_TEST(io, WriteFdExactly_ENOSPC) { - int fd = open("/dev/full", O_WRONLY); - ASSERT_NE(-1, fd); - - char buf[] = "foo"; - ASSERT_FALSE(WriteFdExactly(fd, buf, sizeof(buf))); - ASSERT_EQ(ENOSPC, errno); -} - -POSIX_TEST(io, WriteFdExactly_string) { - const char str[] = "Foobar"; - TemporaryFile tf; - ASSERT_NE(-1, tf.fd); - - // Test writing a partial string to the file. - ASSERT_TRUE(WriteFdExactly(tf.fd, str)) << strerror(errno); - ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)); - - std::string s; - ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s)); - EXPECT_STREQ(str, s.c_str()); -} - -POSIX_TEST(io, WriteFdFmt) { - TemporaryFile tf; - ASSERT_NE(-1, tf.fd); - - // Test writing a partial string to the file. - ASSERT_TRUE(WriteFdFmt(tf.fd, "Foo%s%d", "bar", 123)) << strerror(errno); - ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)); - - std::string s; - ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s)); - EXPECT_STREQ("Foobar123", s.c_str()); -} diff --git a/adb/adb_listeners.cpp b/adb/adb_listeners.cpp deleted file mode 100644 index 29909a555c9e589090228956a3a62a0070db1d62..0000000000000000000000000000000000000000 --- a/adb/adb_listeners.cpp +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright (C) 2015 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 "adb_listeners.h" - -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include "socket_spec.h" -#include "sysdeps.h" -#include "transport.h" - -// 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. -class alistener { - public: - alistener(const std::string& _local_name, const std::string& _connect_to); - ~alistener(); - - fdevent* fde = nullptr; - int fd = -1; - - std::string local_name; - std::string connect_to; - atransport* transport = nullptr; - adisconnect disconnect; - - private: - DISALLOW_COPY_AND_ASSIGN(alistener); -}; - -alistener::alistener(const std::string& _local_name, const std::string& _connect_to) - : local_name(_local_name), connect_to(_connect_to) { -} - -alistener::~alistener() { - // Closes the corresponding fd. - fdevent_destroy(fde); - - if (transport) { - transport->RemoveDisconnect(&disconnect); - } -} - -// listener_list retains ownership of all created alistener objects. Removing an alistener from -// this list will cause it to be deleted. -static auto& listener_list_mutex = *new std::mutex(); -typedef std::list> ListenerList; -static ListenerList& listener_list GUARDED_BY(listener_list_mutex) = *new ListenerList(); - -static void ss_listener_event_func(int _fd, unsigned ev, void *_l) { - if (ev & FDE_READ) { - unique_fd fd(adb_socket_accept(_fd, nullptr, nullptr)); - if (fd < 0) return; - - int rcv_buf_size = CHUNK_SIZE; - adb_setsockopt(fd.get(), SOL_SOCKET, SO_RCVBUF, &rcv_buf_size, sizeof(rcv_buf_size)); - - asocket* s = create_local_socket(std::move(fd)); - if (s) { - connect_to_smartsocket(s); - return; - } - } -} - -static void listener_event_func(int _fd, unsigned ev, void* _l) -{ - alistener* listener = reinterpret_cast(_l); - - if (ev & FDE_READ) { - unique_fd fd(adb_socket_accept(_fd, nullptr, nullptr)); - if (fd < 0) { - return; - } - - asocket* s = create_local_socket(std::move(fd)); - if (s) { - s->transport = listener->transport; - connect_to_remote(s, listener->connect_to); - return; - } - } -} - -// Called as a transport disconnect function. |arg| is the raw alistener*. -static void listener_disconnect(void* arg, atransport*) EXCLUDES(listener_list_mutex) { - std::lock_guard lock(listener_list_mutex); - for (auto iter = listener_list.begin(); iter != listener_list.end(); ++iter) { - if (iter->get() == arg) { - (*iter)->transport = nullptr; - listener_list.erase(iter); - return; - } - } -} - -// Write the list of current listeners (network redirections) into a string. -std::string format_listeners() EXCLUDES(listener_list_mutex) { - std::lock_guard lock(listener_list_mutex); - std::string result; - for (auto& l : listener_list) { - // Ignore special listeners like those for *smartsocket* - if (l->connect_to[0] == '*') { - continue; - } - // " " " " "\n" - // Entries from "adb reverse" have no serial. - android::base::StringAppendF( - &result, "%s %s %s\n", - !l->transport->serial.empty() ? l->transport->serial.c_str() : "(reverse)", - l->local_name.c_str(), l->connect_to.c_str()); - } - return result; -} - -InstallStatus remove_listener(const char* local_name, atransport* transport) - EXCLUDES(listener_list_mutex) { - std::lock_guard lock(listener_list_mutex); - for (auto iter = listener_list.begin(); iter != listener_list.end(); ++iter) { - if (local_name == (*iter)->local_name) { - listener_list.erase(iter); - return INSTALL_STATUS_OK; - } - } - return INSTALL_STATUS_LISTENER_NOT_FOUND; -} - -void remove_all_listeners() EXCLUDES(listener_list_mutex) { - std::lock_guard lock(listener_list_mutex); - auto iter = listener_list.begin(); - while (iter != listener_list.end()) { - // Never remove smart sockets. - if ((*iter)->connect_to[0] == '*') { - ++iter; - } else { - iter = listener_list.erase(iter); - } - } -} - -void close_smartsockets() EXCLUDES(listener_list_mutex) { - std::lock_guard lock(listener_list_mutex); - auto pred = [](const std::unique_ptr& listener) { - return listener->local_name == "*smartsocket*"; - }; - listener_list.remove_if(pred); -} - -InstallStatus install_listener(const std::string& local_name, const char* connect_to, - atransport* transport, int no_rebind, int* resolved_tcp_port, - std::string* error) EXCLUDES(listener_list_mutex) { - std::lock_guard lock(listener_list_mutex); - for (auto& l : listener_list) { - if (local_name == l->local_name) { - // Can't repurpose a smartsocket. - if(l->connect_to[0] == '*') { - *error = "cannot repurpose smartsocket"; - return INSTALL_STATUS_INTERNAL_ERROR; - } - - // Can't repurpose a listener if 'no_rebind' is true. - if (no_rebind) { - *error = "cannot rebind"; - return INSTALL_STATUS_CANNOT_REBIND; - } - - l->connect_to = connect_to; - if (l->transport != transport) { - l->transport->RemoveDisconnect(&l->disconnect); - l->transport = transport; - l->transport->AddDisconnect(&l->disconnect); - } - return INSTALL_STATUS_OK; - } - } - - auto listener = std::make_unique(local_name, connect_to); - - int resolved = 0; - listener->fd = socket_spec_listen(listener->local_name, error, &resolved); - if (listener->fd < 0) { - return INSTALL_STATUS_CANNOT_BIND; - } - - // If the caller requested port 0, update the listener name with the resolved port. - if (resolved != 0) { - listener->local_name = android::base::StringPrintf("tcp:%d", resolved); - if (resolved_tcp_port) { - *resolved_tcp_port = resolved; - } - } - - close_on_exec(listener->fd); - if (listener->connect_to == "*smartsocket*") { - listener->fde = fdevent_create(listener->fd, ss_listener_event_func, listener.get()); - } else { - listener->fde = fdevent_create(listener->fd, listener_event_func, listener.get()); - } - fdevent_set(listener->fde, FDE_READ); - - listener->transport = transport; - - if (transport) { - listener->disconnect.opaque = listener.get(); - listener->disconnect.func = listener_disconnect; - transport->AddDisconnect(&listener->disconnect); - } - - listener_list.push_back(std::move(listener)); - return INSTALL_STATUS_OK; -} diff --git a/adb/adb_listeners.h b/adb/adb_listeners.h deleted file mode 100644 index 70a2ee1210a69b18d54cdc5ef9acef16c16e836b..0000000000000000000000000000000000000000 --- a/adb/adb_listeners.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2015 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_LISTENERS_H -#define __ADB_LISTENERS_H - -#include "adb.h" - -#include - -#include - -// error/status codes for install_listener. -enum InstallStatus { - INSTALL_STATUS_OK = 0, - INSTALL_STATUS_INTERNAL_ERROR = -1, - INSTALL_STATUS_CANNOT_BIND = -2, - INSTALL_STATUS_CANNOT_REBIND = -3, - INSTALL_STATUS_LISTENER_NOT_FOUND = -4, -}; - -InstallStatus install_listener(const std::string& local_name, const char* connect_to, - atransport* transport, int no_rebind, int* resolved_tcp_port, - std::string* error); - -std::string format_listeners(); - -InstallStatus remove_listener(const char* local_name, atransport* transport); -void remove_all_listeners(void); - -void close_smartsockets(); - -#endif /* __ADB_LISTENERS_H */ diff --git a/adb/adb_listeners_test.cpp b/adb/adb_listeners_test.cpp deleted file mode 100644 index a7e2deaf63765b5e68e14c6890251b6d7df6e382..0000000000000000000000000000000000000000 --- a/adb/adb_listeners_test.cpp +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (C) 2016 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 "adb_listeners.h" - -#include - -#include -#include - -#include "fdevent/fdevent.h" -#include "sysdeps.h" -#include "transport.h" - -// Returns true if the given listener is present in format_listeners(). Empty parameters will -// be ignored. -static bool listener_is_installed(const std::string& serial, const std::string& source, - const std::string& dest) { - // format_listeners() gives lines of " \n". - for (const std::string& line : android::base::Split(format_listeners(), "\n")) { - std::vector info = android::base::Split(line, " "); - if (info.size() == 3 && - (serial.empty() || info[0] == serial) && - (source.empty() || info[1] == source) && - (dest.empty() || info[2] == dest)) { - return true; - } - } - - return false; -} - -class AdbListenersTest : public ::testing::Test { - public: - void SetUp() override { - // We don't need an fdevent loop, but adding/removing listeners must be done from the - // fdevent thread if one exists. Since previously run tests may have created an fdevent - // thread, we need to reset to prevent the thread check. - fdevent_reset(); - } - - void TearDown() override { - // Clean up any listeners that may have been installed. - remove_all_listeners(); - - // Make sure we didn't leave any dangling events. - ASSERT_EQ(0u, fdevent_installed_count()); - } - - protected: - atransport transport_; -}; - -TEST_F(AdbListenersTest, test_install_listener) { - std::string error; - - ASSERT_EQ(INSTALL_STATUS_OK, - install_listener("tcp:9000", "tcp:9000", &transport_, false, nullptr, &error)); - ASSERT_TRUE(error.empty()); - - ASSERT_TRUE(listener_is_installed("", "tcp:9000", "tcp:9000")); -} - -TEST_F(AdbListenersTest, test_install_listener_rebind) { - std::string error; - - ASSERT_EQ(INSTALL_STATUS_OK, - install_listener("tcp:9000", "tcp:9000", &transport_, false, nullptr, &error)); - ASSERT_TRUE(error.empty()); - - ASSERT_EQ(INSTALL_STATUS_OK, - install_listener("tcp:9000", "tcp:9001", &transport_, false, nullptr, &error)); - ASSERT_TRUE(error.empty()); - - ASSERT_TRUE(listener_is_installed("", "tcp:9000", "tcp:9001")); -} - -TEST_F(AdbListenersTest, test_install_listener_no_rebind) { - std::string error; - - ASSERT_EQ(INSTALL_STATUS_OK, - install_listener("tcp:9000", "tcp:9000", &transport_, true, nullptr, &error)); - ASSERT_TRUE(error.empty()); - - ASSERT_EQ(INSTALL_STATUS_CANNOT_REBIND, - install_listener("tcp:9000", "tcp:9001", &transport_, true, nullptr, &error)); - ASSERT_FALSE(error.empty()); - - ASSERT_TRUE(listener_is_installed("", "tcp:9000", "tcp:9000")); -} - -TEST_F(AdbListenersTest, test_install_listener_tcp_port_0) { - int port = 0; - std::string error; - - ASSERT_EQ(INSTALL_STATUS_OK, - install_listener("tcp:0", "tcp:9000", &transport_, true, &port, &error)); - ASSERT_TRUE(error.empty()); - - ASSERT_TRUE(listener_is_installed("", android::base::StringPrintf("tcp:%d", port), "tcp:9000")); -} - -TEST_F(AdbListenersTest, test_remove_listener) { - std::string error; - - ASSERT_EQ(INSTALL_STATUS_OK, - install_listener("tcp:9000", "tcp:9000", &transport_, false, nullptr, &error)); - ASSERT_TRUE(error.empty()); - - ASSERT_EQ(INSTALL_STATUS_OK, remove_listener("tcp:9000", &transport_)); - ASSERT_TRUE(format_listeners().empty()); -} - -TEST_F(AdbListenersTest, test_remove_nonexistent_listener) { - std::string error; - - ASSERT_EQ(INSTALL_STATUS_OK, - install_listener("tcp:9000", "tcp:9000", &transport_, false, nullptr, &error)); - ASSERT_TRUE(error.empty()); - - ASSERT_EQ(INSTALL_STATUS_LISTENER_NOT_FOUND, remove_listener("tcp:1", &transport_)); - ASSERT_TRUE(listener_is_installed("", "tcp:9000", "tcp:9000")); -} - -TEST_F(AdbListenersTest, test_remove_all_listeners) { - std::string error; - - ASSERT_EQ(INSTALL_STATUS_OK, - install_listener("tcp:9000", "tcp:9000", &transport_, false, nullptr, &error)); - ASSERT_TRUE(error.empty()); - - ASSERT_EQ(INSTALL_STATUS_OK, - install_listener("tcp:9001", "tcp:9001", &transport_, false, nullptr, &error)); - ASSERT_TRUE(error.empty()); - - remove_all_listeners(); - ASSERT_TRUE(format_listeners().empty()); -} - -TEST_F(AdbListenersTest, test_transport_disconnect) { - std::string error; - - ASSERT_EQ(INSTALL_STATUS_OK, - install_listener("tcp:9000", "tcp:9000", &transport_, false, nullptr, &error)); - ASSERT_TRUE(error.empty()); - - ASSERT_EQ(INSTALL_STATUS_OK, - install_listener("tcp:9001", "tcp:9001", &transport_, false, nullptr, &error)); - ASSERT_TRUE(error.empty()); - - transport_.RunDisconnects(); - ASSERT_TRUE(format_listeners().empty()); -} diff --git a/adb/adb_mdns.h b/adb/adb_mdns.h deleted file mode 100644 index 31112485b1eb22da8c951c3b70cd89cfc464b7ec..0000000000000000000000000000000000000000 --- a/adb/adb_mdns.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2016 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_MDNS_H_ -#define _ADB_MDNS_H_ - -#include - -// The rules for Service Names [RFC6335] state that they may be no more -// than fifteen characters long (not counting the mandatory underscore), -// consisting of only letters, digits, and hyphens, must begin and end -// with a letter or digit, must not contain consecutive hyphens, and -// must contain at least one letter. -#define ADB_MDNS_SERVICE_TYPE "adb" -#define ADB_MDNS_TLS_PAIRING_TYPE "adb-tls-pairing" -#define ADB_MDNS_TLS_CONNECT_TYPE "adb-tls-connect" - -const int kADBTransportServiceRefIndex = 0; -const int kADBSecurePairingServiceRefIndex = 1; -const int kADBSecureConnectServiceRefIndex = 2; - -// Each ADB Secure service advertises with a TXT record indicating the version -// using a key/value pair per RFC 6763 (https://tools.ietf.org/html/rfc6763). -// -// The first key/value pair is always the version of the protocol. -// There may be more key/value pairs added after. -// -// The version is purposely represented as the single letter "v" due to the -// need to minimize DNS traffic. The version starts at 1. With each breaking -// protocol change, the version is incremented by 1. -// -// Newer adb clients/daemons need to recognize and either reject -// or be backward-compatible with older verseions if there is a mismatch. -// -// Relevant sections: -// -// """ -// 6.4. Rules for Keys in DNS-SD Key/Value Pairs -// -// The key MUST be at least one character. DNS-SD TXT record strings -// beginning with an '=' character (i.e., the key is missing) MUST be -// silently ignored. -// -// ... -// -// 6.5. Rules for Values in DNS-SD Key/Value Pairs -// -// If there is an '=' in a DNS-SD TXT record string, then everything -// after the first '=' to the end of the string is the value. The value -// can contain any eight-bit values including '='. -// """ - -#define ADB_SECURE_SERVICE_VERSION_TXT_RECORD(ver) ("v=" #ver) - -// Client/service versions are initially defined to be matching, -// but may go out of sync as different clients and services -// try to talk to each other. -#define ADB_SECURE_SERVICE_VERSION 1 -#define ADB_SECURE_CLIENT_VERSION ADB_SECURE_SERVICE_VERSION - -const char* kADBSecurePairingServiceTxtRecord = - ADB_SECURE_SERVICE_VERSION_TXT_RECORD(ADB_SECURE_SERVICE_VERSION); -const char* kADBSecureConnectServiceTxtRecord = - ADB_SECURE_SERVICE_VERSION_TXT_RECORD(ADB_SECURE_SERVICE_VERSION); - -#define ADB_FULL_MDNS_SERVICE_TYPE(atype) ("_" atype "._tcp") -const char* kADBDNSServices[] = {ADB_FULL_MDNS_SERVICE_TYPE(ADB_MDNS_SERVICE_TYPE), - ADB_FULL_MDNS_SERVICE_TYPE(ADB_MDNS_TLS_PAIRING_TYPE), - ADB_FULL_MDNS_SERVICE_TYPE(ADB_MDNS_TLS_CONNECT_TYPE)}; - -const char* kADBDNSServiceTxtRecords[] = { - nullptr, - kADBSecurePairingServiceTxtRecord, - kADBSecureConnectServiceTxtRecord, -}; - -const int kNumADBDNSServices = arraysize(kADBDNSServices); - -#endif diff --git a/adb/adb_test.xml b/adb/adb_test.xml deleted file mode 100644 index cc3302d7bebf647cb3a529568dae10a23cd8f23a..0000000000000000000000000000000000000000 --- a/adb/adb_test.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - diff --git a/adb/adb_trace.cpp b/adb/adb_trace.cpp deleted file mode 100644 index cea24fe2f42bdf29303f9d328544f9943b7f7807..0000000000000000000000000000000000000000 --- a/adb/adb_trace.cpp +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright (C) 2015 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 "adb_trace.h" - -#include -#include -#include - -#include -#include - -#include "adb.h" - -#if !ADB_HOST -#include -#endif - -#if !ADB_HOST -const char* adb_device_banner = "device"; -#if defined(__ANDROID__) -static android::base::LogdLogger gLogdLogger; -#endif -#else -const char* adb_device_banner = "host"; -#endif - -void AdbLogger(android::base::LogId id, android::base::LogSeverity severity, - const char* tag, const char* file, unsigned int line, - const char* message) { - android::base::StderrLogger(id, severity, tag, file, line, message); -#if defined(_WIN32) - // stderr can be buffered on Windows (and setvbuf doesn't seem to work), so explicitly flush. - fflush(stderr); -#endif - -#if !ADB_HOST && defined(__ANDROID__) - // Only print logs of INFO or higher to logcat, so that `adb logcat` with adbd tracing on - // doesn't result in exponential logging. - if (severity >= android::base::INFO) { - gLogdLogger(id, severity, tag, file, line, message); - } -#endif -} - - -#if !ADB_HOST -static std::string get_log_file_name() { - struct tm now; - time_t t; - tzset(); - time(&t); - localtime_r(&t, &now); - - char timestamp[PATH_MAX]; - strftime(timestamp, sizeof(timestamp), "%Y-%m-%d-%H-%M-%S", &now); - - return android::base::StringPrintf("/data/adb/adb-%s-%d", timestamp, - getpid()); -} - -void start_device_log(void) { - int fd = unix_open(get_log_file_name(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0640); - if (fd == -1) { - return; - } - - // Redirect stdout and stderr to the log file. - dup2(fd, STDOUT_FILENO); - dup2(fd, STDERR_FILENO); - fprintf(stderr, "--- adb starting (pid %d) ---\n", getpid()); - unix_close(fd); -} -#endif - -int adb_trace_mask; - -std::string get_trace_setting_from_env() { - const char* setting = getenv("ADB_TRACE"); - if (setting == nullptr) { - setting = ""; - } - - return std::string(setting); -} - -std::string get_trace_setting() { -#if ADB_HOST - return get_trace_setting_from_env(); -#else - return android::base::GetProperty("persist.adb.trace_mask", ""); -#endif -} - -// Split the space separated list of tags from the trace setting and build the -// trace mask from it. note that '1' and 'all' are special cases to enable all -// tracing. -// -// adb's trace setting comes from the ADB_TRACE environment variable, whereas -// adbd's comes from the system property persist.adb.trace_mask. -static void setup_trace_mask() { - const std::string trace_setting = get_trace_setting(); - if (trace_setting.empty()) { - return; - } - - std::unordered_map trace_flags = {{"1", -1}, - {"all", -1}, - {"adb", ADB}, - {"sockets", SOCKETS}, - {"packets", PACKETS}, - {"rwx", RWX}, - {"usb", USB}, - {"sync", SYNC}, - {"sysdeps", SYSDEPS}, - {"transport", TRANSPORT}, - {"jdwp", JDWP}, - {"services", SERVICES}, - {"auth", AUTH}, - {"fdevent", FDEVENT}, - {"shell", SHELL}, - {"incremental", INCREMENTAL}}; - - std::vector elements = android::base::Split(trace_setting, " "); - for (const auto& elem : elements) { - const auto& flag = trace_flags.find(elem); - if (flag == trace_flags.end()) { - LOG(ERROR) << "Unknown trace flag: " << elem; - continue; - } - - if (flag->second == -1) { - // -1 is used for the special values "1" and "all" that enable all - // tracing. - adb_trace_mask = ~0; - break; - } else { - adb_trace_mask |= 1 << flag->second; - } - } - - if (adb_trace_mask != 0) { - android::base::SetMinimumLogSeverity(android::base::VERBOSE); - } -} - -void adb_trace_init(char** argv) { -#if !ADB_HOST - // Don't open log file if no tracing, since this will block - // the crypto unmount of /data - if (!get_trace_setting().empty()) { - if (unix_isatty(STDOUT_FILENO) == 0) { - start_device_log(); - } - } -#endif - -#if ADB_HOST && !defined(_WIN32) - // adb historically ignored $ANDROID_LOG_TAGS but passed it through to logcat. - // If set, move it out of the way so that libbase logging doesn't try to parse it. - std::string log_tags; - char* ANDROID_LOG_TAGS = getenv("ANDROID_LOG_TAGS"); - if (ANDROID_LOG_TAGS) { - log_tags = ANDROID_LOG_TAGS; - unsetenv("ANDROID_LOG_TAGS"); - } -#endif - - android::base::InitLogging(argv, &AdbLogger); - -#if ADB_HOST && !defined(_WIN32) - // Put $ANDROID_LOG_TAGS back so we can pass it to logcat. - if (!log_tags.empty()) setenv("ANDROID_LOG_TAGS", log_tags.c_str(), 1); -#endif - - setup_trace_mask(); - - VLOG(ADB) << adb_version(); -} - -void adb_trace_enable(AdbTrace trace_tag) { - adb_trace_mask |= (1 << trace_tag); -} diff --git a/adb/adb_trace.h b/adb/adb_trace.h deleted file mode 100644 index 3421a029650a8087d1e99e63ee3f4411a48e92f1..0000000000000000000000000000000000000000 --- a/adb/adb_trace.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __ADB_TRACE_H -#define __ADB_TRACE_H - -#include -#include - -/* 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_trace.cpp. - */ -enum AdbTrace { - ADB = 0, /* 0x001 */ - SOCKETS, - PACKETS, - TRANSPORT, - RWX, /* 0x010 */ - USB, - SYNC, - SYSDEPS, - JDWP, /* 0x100 */ - SERVICES, - AUTH, - FDEVENT, - SHELL, - INCREMENTAL, -}; - -#define VLOG_IS_ON(TAG) \ - ((adb_trace_mask & (1 << (TAG))) != 0) - -#define VLOG(TAG) \ - if (LIKELY(!VLOG_IS_ON(TAG))) \ - ; \ - else \ - LOG(DEBUG) - -// You must define TRACE_TAG before using this macro. -#define D(...) \ - VLOG(TRACE_TAG) << android::base::StringPrintf(__VA_ARGS__) - - -extern int adb_trace_mask; -void adb_trace_init(char**); -void adb_trace_enable(AdbTrace trace_tag); - -#endif /* __ADB_TRACE_H */ diff --git a/adb/adb_unique_fd.cpp b/adb/adb_unique_fd.cpp deleted file mode 100644 index dec73bc2e64c1cf38eb17c058d8d812e251583fb..0000000000000000000000000000000000000000 --- a/adb/adb_unique_fd.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2018 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 "adb_unique_fd.h" - -#include -#include - -#include "sysdeps.h" - -#if defined(_WIN32) -void AdbCloser::Close(int fd) { - adb_close(fd); -} -#endif diff --git a/adb/adb_unique_fd.h b/adb/adb_unique_fd.h deleted file mode 100644 index b6c910a9484a8a370c52d5bb7645e3704bc982ae..0000000000000000000000000000000000000000 --- a/adb/adb_unique_fd.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2016 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. - */ - -#pragma once - -#include -#include - -#include - -#if defined(_WIN32) -// Helper to automatically close an FD when it goes out of scope. -struct AdbCloser { - static void Close(int fd); -}; - -using unique_fd = android::base::unique_fd_impl; -#else -using unique_fd = android::base::unique_fd; -#endif - -using android::base::borrowed_fd; - -template -int adb_close(const android::base::unique_fd_impl&) - __attribute__((__unavailable__("adb_close called on unique_fd"))); diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp deleted file mode 100644 index d1910f1c3f938c57ab0e1b3b43a4e4754af5a82d..0000000000000000000000000000000000000000 --- a/adb/adb_utils.cpp +++ /dev/null @@ -1,380 +0,0 @@ -/* - * Copyright (C) 2015 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 ADB - -#include "adb_utils.h" -#include "adb_unique_fd.h" - -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include - -#include "adb.h" -#include "adb_trace.h" -#include "sysdeps.h" - -#ifdef _WIN32 -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -# endif -# include "windows.h" -# include "shlobj.h" -#else -#include -#endif - - -#if defined(_WIN32) -static constexpr char kNullFileName[] = "NUL"; -#else -static constexpr char kNullFileName[] = "/dev/null"; -#endif - -void close_stdin() { - int fd = unix_open(kNullFileName, O_RDONLY); - if (fd == -1) { - PLOG(FATAL) << "failed to open " << kNullFileName; - } - - if (TEMP_FAILURE_RETRY(dup2(fd, STDIN_FILENO)) == -1) { - PLOG(FATAL) << "failed to redirect stdin to " << kNullFileName; - } - unix_close(fd); -} - -bool getcwd(std::string* s) { - char* cwd = getcwd(nullptr, 0); - if (cwd != nullptr) *s = cwd; - free(cwd); - return (cwd != nullptr); -} - -bool directory_exists(const std::string& path) { - struct stat sb; - return stat(path.c_str(), &sb) != -1 && S_ISDIR(sb.st_mode); -} - -std::string escape_arg(const std::string& s) { - // Escape any ' in the string (before we single-quote the whole thing). - // The correct way to do this for the shell is to replace ' with '\'' --- that is, - // close the existing single-quoted string, escape a single single-quote, and start - // a new single-quoted string. Like the C preprocessor, the shell will concatenate - // these pieces into one string. - - std::string result; - result.push_back('\''); - - size_t base = 0; - while (true) { - size_t found = s.find('\'', base); - result.append(s, base, found - base); - if (found == s.npos) break; - result.append("'\\''"); - base = found + 1; - } - - result.push_back('\''); - return result; -} - -// Given a relative or absolute filepath, create the directory hierarchy -// as needed. Returns true if the hierarchy is/was setup. -bool mkdirs(const std::string& path) { - // TODO: all the callers do unlink && mkdirs && adb_creat --- - // that's probably the operation we should expose. - - // Implementation Notes: - // - // Pros: - // - Uses dirname, so does not need to deal with OS_PATH_SEPARATOR. - // - On Windows, uses mingw dirname which accepts '/' and '\\', drive letters - // (C:\foo), UNC paths (\\server\share\dir\dir\file), and Unicode (when - // combined with our adb_mkdir() which takes UTF-8). - // - Is optimistic wrt thinking that a deep directory hierarchy will exist. - // So it does as few stat()s as possible before doing mkdir()s. - // Cons: - // - Recursive, so it uses stack space relative to number of directory - // components. - - // If path points to a symlink to a directory, that's fine. - struct stat sb; - if (stat(path.c_str(), &sb) != -1 && S_ISDIR(sb.st_mode)) { - return true; - } - - const std::string parent(android::base::Dirname(path)); - - // If dirname returned the same path as what we passed in, don't go recursive. - // This can happen on Windows when walking up the directory hierarchy and not - // finding anything that already exists (unlike POSIX that will eventually - // find . or /). - if (parent == path) { - errno = ENOENT; - return false; - } - - // Recursively make parent directories of 'path'. - if (!mkdirs(parent)) { - return false; - } - - // Now that the parent directory hierarchy of 'path' has been ensured, - // create path itself. - if (adb_mkdir(path, 0775) == -1) { - const int saved_errno = errno; - // If someone else created the directory, that is ok. - if (directory_exists(path)) { - return true; - } - // There might be a pre-existing file at 'path', or there might have been some other error. - errno = saved_errno; - return false; - } - - return true; -} - -std::string dump_hex(const void* data, size_t byte_count) { - size_t truncate_len = 16; - bool truncated = false; - if (byte_count > truncate_len) { - byte_count = truncate_len; - truncated = true; - } - - const uint8_t* p = reinterpret_cast(data); - - std::string line; - for (size_t i = 0; i < byte_count; ++i) { - android::base::StringAppendF(&line, "%02x", p[i]); - } - line.push_back(' '); - - for (size_t i = 0; i < byte_count; ++i) { - int ch = p[i]; - line.push_back(isprint(ch) ? ch : '.'); - } - - if (truncated) { - line += " [truncated]"; - } - - return line; -} - -std::string dump_header(const amessage* msg) { - unsigned command = msg->command; - int len = 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 (msg->arg0 < 256U) - snprintf(arg0, sizeof arg0, "%d", msg->arg0); - else - snprintf(arg0, sizeof arg0, "0x%x", msg->arg0); - - if (msg->arg1 < 256U) - snprintf(arg1, sizeof arg1, "%d", msg->arg1); - else - snprintf(arg1, sizeof arg1, "0x%x", msg->arg1); - - return android::base::StringPrintf("[%s] arg0=%s arg1=%s (len=%d) ", cmd, arg0, arg1, len); -} - -std::string dump_packet(const char* name, const char* func, const apacket* p) { - std::string result = name; - result += ": "; - result += func; - result += ": "; - result += dump_header(&p->msg); - result += dump_hex(p->payload.data(), p->payload.size()); - return result; -} - -std::string perror_str(const char* msg) { - return android::base::StringPrintf("%s: %s", msg, strerror(errno)); -} - -#if !defined(_WIN32) -// Windows version provided in sysdeps_win32.cpp -bool set_file_block_mode(borrowed_fd fd, bool block) { - int flags = fcntl(fd.get(), F_GETFL, 0); - if (flags == -1) { - PLOG(ERROR) << "failed to fcntl(F_GETFL) for fd " << fd.get(); - return false; - } - flags = block ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK); - if (fcntl(fd.get(), F_SETFL, flags) != 0) { - PLOG(ERROR) << "failed to fcntl(F_SETFL) for fd " << fd.get() << ", flags " << flags; - return false; - } - return true; -} -#endif - -bool forward_targets_are_valid(const std::string& source, const std::string& dest, - std::string* error) { - if (android::base::StartsWith(source, "tcp:")) { - // The source port may be 0 to allow the system to select an open port. - int port; - if (!android::base::ParseInt(&source[4], &port) || port < 0) { - *error = android::base::StringPrintf("Invalid source port: '%s'", &source[4]); - return false; - } - } - - if (android::base::StartsWith(dest, "tcp:")) { - // The destination port must be > 0. - int port; - if (!android::base::ParseInt(&dest[4], &port) || port <= 0) { - *error = android::base::StringPrintf("Invalid destination port: '%s'", &dest[4]); - return false; - } - } - - return true; -} - -std::string adb_get_homedir_path() { -#ifdef _WIN32 - WCHAR path[MAX_PATH]; - const HRESULT hr = SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, 0, path); - if (FAILED(hr)) { - D("SHGetFolderPathW failed: %s", android::base::SystemErrorCodeToString(hr).c_str()); - return {}; - } - std::string home_str; - if (!android::base::WideToUTF8(path, &home_str)) { - return {}; - } - return home_str; -#else - if (const char* const home = getenv("HOME")) { - return home; - } - - struct passwd pwent; - struct passwd* result; - int pwent_max = sysconf(_SC_GETPW_R_SIZE_MAX); - if (pwent_max == -1) { - pwent_max = 16384; - } - std::vector buf(pwent_max); - int rc = getpwuid_r(getuid(), &pwent, buf.data(), buf.size(), &result); - if (rc == 0 && result) { - return result->pw_dir; - } - - LOG(FATAL) << "failed to get user home directory"; - return {}; -#endif -} - -std::string adb_get_android_dir_path() { - std::string user_dir = adb_get_homedir_path(); - std::string android_dir = user_dir + OS_PATH_SEPARATOR + ".android"; - struct stat buf; - if (stat(android_dir.c_str(), &buf) == -1) { - if (adb_mkdir(android_dir, 0750) == -1) { - PLOG(FATAL) << "Cannot mkdir '" << android_dir << "'"; - } - } - return android_dir; -} - -std::string GetLogFilePath() { - // https://issuetracker.google.com/112588493 - const char* path = getenv("ANDROID_ADB_LOG_PATH"); - if (path) return path; - -#if defined(_WIN32) - const char log_name[] = "adb.log"; - WCHAR temp_path[MAX_PATH]; - - // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364992%28v=vs.85%29.aspx - DWORD nchars = GetTempPathW(arraysize(temp_path), temp_path); - if (nchars >= arraysize(temp_path) || nchars == 0) { - // If string truncation or some other error. - LOG(FATAL) << "cannot retrieve temporary file path: " - << android::base::SystemErrorCodeToString(GetLastError()); - } - - std::string temp_path_utf8; - if (!android::base::WideToUTF8(temp_path, &temp_path_utf8)) { - PLOG(FATAL) << "cannot convert temporary file path from UTF-16 to UTF-8"; - } - - return temp_path_utf8 + log_name; -#else - const char* tmp_dir = getenv("TMPDIR"); - if (tmp_dir == nullptr) tmp_dir = "/tmp"; - return android::base::StringPrintf("%s/adb.%u.log", tmp_dir, getuid()); -#endif -} - -[[noreturn]] static void error_exit_va(int error, const char* fmt, va_list va) { - fflush(stdout); - fprintf(stderr, "%s: ", android::base::Basename(android::base::GetExecutablePath()).c_str()); - - vfprintf(stderr, fmt, va); - - if (error != 0) { - fprintf(stderr, ": %s", strerror(error)); - } - - putc('\n', stderr); - fflush(stderr); - - exit(EXIT_FAILURE); -} - -void error_exit(const char* fmt, ...) { - va_list va; - va_start(va, fmt); - error_exit_va(0, fmt, va); - va_end(va); -} - -void perror_exit(const char* fmt, ...) { - va_list va; - va_start(va, fmt); - error_exit_va(errno, fmt, va); - va_end(va); -} diff --git a/adb/adb_utils.h b/adb/adb_utils.h deleted file mode 100644 index 66cba121b2ac70bce52aeaa491602ddc8a8d4609..0000000000000000000000000000000000000000 --- a/adb/adb_utils.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "adb.h" -#include "adb_unique_fd.h" - -void close_stdin(); - -bool getcwd(std::string* cwd); -bool directory_exists(const std::string& path); - -// Return the user's home directory. -std::string adb_get_homedir_path(); - -// Return the adb user directory. -std::string adb_get_android_dir_path(); - -bool mkdirs(const std::string& path); - -std::string escape_arg(const std::string& s); - -std::string dump_hex(const void* ptr, size_t byte_count); -std::string dump_header(const amessage* msg); -std::string dump_packet(const char* name, const char* func, const apacket* p); - -std::string perror_str(const char* msg); - -[[noreturn]] void error_exit(const char* fmt, ...) __attribute__((__format__(__printf__, 1, 2))); -[[noreturn]] void perror_exit(const char* fmt, ...) __attribute__((__format__(__printf__, 1, 2))); - -bool set_file_block_mode(borrowed_fd fd, bool block); - -// Given forward/reverse targets, returns true if they look sane. If an error is found, fills -// |error| and returns false. -// Currently this only checks "tcp:" targets. Additional checking could be added for other targets -// if needed. -bool forward_targets_are_valid(const std::string& source, const std::string& dest, - std::string* error); - -// A thread-safe blocking queue. -template -class BlockingQueue { - std::mutex mutex; - std::condition_variable cv; - std::vector queue; - - public: - void Push(const T& t) { - { - std::unique_lock lock(mutex); - queue.push_back(t); - } - cv.notify_one(); - } - - template - void PopAll(Fn fn) { - std::vector popped; - - { - std::unique_lock lock(mutex); - cv.wait(lock, [this]() { return !queue.empty(); }); - popped = std::move(queue); - queue.clear(); - } - - for (const T& t : popped) { - fn(t); - } - } -}; - -std::string GetLogFilePath(); - -inline std::string_view StripTrailingNulls(std::string_view str) { - size_t n = 0; - for (auto it = str.rbegin(); it != str.rend(); ++it) { - if (*it != '\0') { - break; - } - ++n; - } - - str.remove_suffix(n); - return str; -} - -// Base-10 stroll on a string_view. -template -inline bool ParseUint(T* result, std::string_view str, std::string_view* remaining = nullptr) { - T value; - const auto res = std::from_chars(str.begin(), str.end(), value); - if (res.ec != std::errc{}) { - return false; - } - if (res.ptr != str.end() && !remaining) { - return false; - } - if (remaining) { - *remaining = std::string_view(res.ptr, str.end() - res.ptr); - } - *result = value; - return true; -} diff --git a/adb/adb_utils_test.cpp b/adb/adb_utils_test.cpp deleted file mode 100644 index cdca3aa321c10ba409fc20795b3d0c09f0fe5a34..0000000000000000000000000000000000000000 --- a/adb/adb_utils_test.cpp +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright (C) 2015 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 "adb_utils.h" - -#ifdef _WIN32 -#include -#include -#endif - -#include - -#include - -#include -#include - -#include "sysdeps.h" - -#include -#include - -#ifdef _WIN32 -static std::string subdir(const char* parent, const char* child) { - std::string str(parent); - str += OS_PATH_SEPARATOR; - str += child; - return str; -} -#endif - -TEST(adb_utils, directory_exists) { -#ifdef _WIN32 - char profiles_dir[MAX_PATH]; - DWORD cch = arraysize(profiles_dir); - - // On typical Windows 7, returns C:\Users - ASSERT_TRUE(GetProfilesDirectoryA(profiles_dir, &cch)); - - ASSERT_TRUE(directory_exists(profiles_dir)); - - ASSERT_FALSE(directory_exists(subdir(profiles_dir, "does-not-exist"))); -#else - ASSERT_TRUE(directory_exists("/proc")); - ASSERT_FALSE(directory_exists("/proc/does-not-exist")); -#endif -} - -#if defined(_WIN32) -TEST(adb_utils, directory_exists_win32_symlink_junction) { - char profiles_dir[MAX_PATH]; - DWORD cch = arraysize(profiles_dir); - - // On typical Windows 7, returns C:\Users - ASSERT_TRUE(GetProfilesDirectoryA(profiles_dir, &cch)); - - // On modern (English?) Windows, this is a directory symbolic link to - // C:\ProgramData. Symbolic links are rare on Windows and the user requires - // a special permission (by default granted to Administrative users) to - // create symbolic links. - EXPECT_FALSE(directory_exists(subdir(profiles_dir, "All Users"))); - - // On modern (English?) Windows, this is a directory junction to - // C:\Users\Default. Junctions are used throughout user profile directories - // for backwards compatibility and they don't require any special permissions - // to create. - EXPECT_FALSE(directory_exists(subdir(profiles_dir, "Default User"))); -} -#endif - -TEST(adb_utils, escape_arg) { - EXPECT_EQ(R"('')", escape_arg("")); - - EXPECT_EQ(R"('abc')", escape_arg("abc")); - - auto wrap = [](const std::string& x) { return '\'' + x + '\''; }; - const std::string q = R"('\'')"; - EXPECT_EQ(wrap(q), escape_arg("'")); - EXPECT_EQ(wrap(q + q), escape_arg("''")); - EXPECT_EQ(wrap(q + "abc" + q), escape_arg("'abc'")); - EXPECT_EQ(wrap(q + "abc"), escape_arg("'abc")); - EXPECT_EQ(wrap("abc" + q), escape_arg("abc'")); - EXPECT_EQ(wrap("abc" + q + "def"), escape_arg("abc'def")); - EXPECT_EQ(wrap("a" + q + "b" + q + "c"), escape_arg("a'b'c")); - EXPECT_EQ(wrap("a" + q + "bcde" + q + "f"), escape_arg("a'bcde'f")); - - EXPECT_EQ(R"(' abc')", escape_arg(" abc")); - EXPECT_EQ(R"('"abc')", escape_arg("\"abc")); - EXPECT_EQ(R"('\abc')", escape_arg("\\abc")); - EXPECT_EQ(R"('(abc')", escape_arg("(abc")); - EXPECT_EQ(R"(')abc')", escape_arg(")abc")); - - EXPECT_EQ(R"('abc abc')", escape_arg("abc abc")); - EXPECT_EQ(R"('abc"abc')", escape_arg("abc\"abc")); - EXPECT_EQ(R"('abc\abc')", escape_arg("abc\\abc")); - EXPECT_EQ(R"('abc(abc')", escape_arg("abc(abc")); - EXPECT_EQ(R"('abc)abc')", escape_arg("abc)abc")); - - EXPECT_EQ(R"('abc ')", escape_arg("abc ")); - EXPECT_EQ(R"('abc"')", escape_arg("abc\"")); - EXPECT_EQ(R"('abc\')", escape_arg("abc\\")); - EXPECT_EQ(R"('abc(')", escape_arg("abc(")); - EXPECT_EQ(R"('abc)')", escape_arg("abc)")); -} - -void test_mkdirs(const std::string& basepath) { - // Test creating a directory hierarchy. - ASSERT_TRUE(mkdirs(basepath)); - // Test finding an existing directory hierarchy. - ASSERT_TRUE(mkdirs(basepath)); - // Test mkdirs on an existing hierarchy with a trailing slash. - ASSERT_TRUE(mkdirs(basepath + '/')); -#if defined(_WIN32) - ASSERT_TRUE(mkdirs(basepath + '\\')); -#endif - - const std::string filepath = basepath + "/file"; - // Verify that the hierarchy was created by trying to create a file in it. - ASSERT_NE(-1, adb_creat(filepath.c_str(), 0600)); - // If a file exists where we want a directory, the operation should fail. - ASSERT_FALSE(mkdirs(filepath)); -} - -TEST(adb_utils, mkdirs) { - TemporaryDir td; - - // Absolute paths. - test_mkdirs(std::string(td.path) + "/dir/subdir"); - - // Relative paths. - ASSERT_EQ(0, chdir(td.path)) << strerror(errno); - test_mkdirs(std::string("relative/subrel")); -} - -#if !defined(_WIN32) -TEST(adb_utils, set_file_block_mode) { - unique_fd fd(adb_open("/dev/null", O_RDWR | O_APPEND)); - ASSERT_GE(fd, 0); - int flags = fcntl(fd.get(), F_GETFL, 0); - ASSERT_EQ(O_RDWR | O_APPEND, (flags & (O_RDWR | O_APPEND))); - ASSERT_TRUE(set_file_block_mode(fd, false)); - int new_flags = fcntl(fd.get(), F_GETFL, 0); - ASSERT_EQ(flags | O_NONBLOCK, new_flags); - ASSERT_TRUE(set_file_block_mode(fd, true)); - new_flags = fcntl(fd.get(), F_GETFL, 0); - ASSERT_EQ(flags, new_flags); -} -#endif - -TEST(adb_utils, test_forward_targets_are_valid) { - std::string error; - - // Source port can be >= 0. - EXPECT_FALSE(forward_targets_are_valid("tcp:-1", "tcp:9000", &error)); - EXPECT_TRUE(forward_targets_are_valid("tcp:0", "tcp:9000", &error)); - EXPECT_TRUE(forward_targets_are_valid("tcp:8000", "tcp:9000", &error)); - - // Destination port must be >0. - EXPECT_FALSE(forward_targets_are_valid("tcp:8000", "tcp:-1", &error)); - EXPECT_FALSE(forward_targets_are_valid("tcp:8000", "tcp:0", &error)); - - // Port must be a number. - EXPECT_FALSE(forward_targets_are_valid("tcp:", "tcp:9000", &error)); - EXPECT_FALSE(forward_targets_are_valid("tcp:a", "tcp:9000", &error)); - EXPECT_FALSE(forward_targets_are_valid("tcp:22x", "tcp:9000", &error)); - EXPECT_FALSE(forward_targets_are_valid("tcp:8000", "tcp:", &error)); - EXPECT_FALSE(forward_targets_are_valid("tcp:8000", "tcp:a", &error)); - EXPECT_FALSE(forward_targets_are_valid("tcp:8000", "tcp:22x", &error)); -} - -void TestParseUint(std::string_view string, bool expected_success, uint32_t expected_value = 0) { - // Standalone. - { - uint32_t value; - std::string_view remaining; - bool success = ParseUint(&value, string, &remaining); - EXPECT_EQ(success, expected_success); - if (expected_success) { - EXPECT_EQ(value, expected_value); - } - EXPECT_TRUE(remaining.empty()); - } - - // With trailing text. - { - std::string text = std::string(string) + "foo"; - uint32_t value; - std::string_view remaining; - bool success = ParseUint(&value, text, &remaining); - EXPECT_EQ(success, expected_success); - if (expected_success) { - EXPECT_EQ(value, expected_value); - EXPECT_EQ(remaining, "foo"); - } - } - - // With trailing text, without remaining. - { - std::string text = std::string(string) + "foo"; - uint32_t value; - bool success = ParseUint(&value, text, nullptr); - EXPECT_EQ(success, false); - } -} - -TEST(adb_utils, ParseUint) { - TestParseUint("", false); - TestParseUint("foo", false); - TestParseUint("foo123", false); - TestParseUint("-1", false); - - TestParseUint("123", true, 123); - TestParseUint("9999999999999999999999999", false); - TestParseUint(std::to_string(UINT32_MAX), true, UINT32_MAX); - TestParseUint("0" + std::to_string(UINT32_MAX), true, UINT32_MAX); - TestParseUint(std::to_string(static_cast(UINT32_MAX) + 1), false); - TestParseUint("0" + std::to_string(static_cast(UINT32_MAX) + 1), false); - - std::string x = std::to_string(UINT32_MAX) + "123"; - std::string_view substr = std::string_view(x).substr(0, std::to_string(UINT32_MAX).size()); - TestParseUint(substr, true, UINT32_MAX); -} diff --git a/adb/adb_wifi.h b/adb/adb_wifi.h deleted file mode 100644 index 585748c911a2e3ca4a86146c416b9eb05c957502..0000000000000000000000000000000000000000 --- a/adb/adb_wifi.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2019 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. - */ - -#pragma once - -#include - -#include "adb.h" - -#if ADB_HOST - -void adb_wifi_init(void); -void adb_wifi_pair_device(const std::string& host, const std::string& password, - std::string& response); -bool adb_wifi_is_known_host(const std::string& host); - -#else // !ADB_HOST - -struct AdbdAuthContext; - -void adbd_wifi_init(AdbdAuthContext* ctx); -void adbd_wifi_secure_connect(atransport* t); - -#endif diff --git a/adb/apex/Android.bp b/adb/apex/Android.bp deleted file mode 100644 index ddb17dac1d96073ba436d9b53dbc843d65061e10..0000000000000000000000000000000000000000 --- a/adb/apex/Android.bp +++ /dev/null @@ -1,55 +0,0 @@ -apex_defaults { - name: "com.android.adbd-defaults", - updatable: true, - min_sdk_version: "R", - - binaries: ["adbd"], - compile_multilib: "both", - multilib: { - both: { - native_shared_libs: [ - "libadb_pairing_auth", - "libadb_pairing_connection", - "libadb_pairing_server", - "libadbconnection_client", - ], - }, - }, - prebuilts: ["com.android.adbd.init.rc"], - - key: "com.android.adbd.key", - certificate: ":com.android.adbd.certificate", -} - -apex { - name: "com.android.adbd", - defaults: ["com.android.adbd-defaults"], - manifest: "apex_manifest.json", -} - -// adbd apex with INT_MAX version code, to allow for upgrade/rollback testing. -apex_test { - name: "test_com.android.adbd", - defaults: ["com.android.adbd-defaults"], - manifest: "test_apex_manifest.json", - file_contexts: ":com.android.adbd-file_contexts", - installable: false, -} - -prebuilt_etc { - name: "com.android.adbd.init.rc", - src: "adbd.rc", - filename: "init.rc", - installable: false, -} - -apex_key { - name: "com.android.adbd.key", - public_key: "com.android.adbd.avbpubkey", - private_key: "com.android.adbd.pem", -} - -android_app_certificate { - name: "com.android.adbd.certificate", - certificate: "com.android.adbd", -} diff --git a/adb/apex/adbd.rc b/adb/apex/adbd.rc deleted file mode 100644 index 9cb072bccf6d6ec6f194c74c37a24f1257de983a..0000000000000000000000000000000000000000 --- a/adb/apex/adbd.rc +++ /dev/null @@ -1,6 +0,0 @@ -service adbd /apex/com.android.adbd/bin/adbd --root_seclabel=u:r:su:s0 - class core - socket adbd seqpacket 660 system system - disabled - override - seclabel u:r:adbd:s0 diff --git a/adb/apex/apex_manifest.json b/adb/apex/apex_manifest.json deleted file mode 100644 index c825b044a9685fac7efb76b41a173017c73e9c7c..0000000000000000000000000000000000000000 --- a/adb/apex/apex_manifest.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "com.android.adbd", - "version": 309999900 -} diff --git a/adb/apex/com.android.adbd.avbpubkey b/adb/apex/com.android.adbd.avbpubkey deleted file mode 100644 index 06235bd1f61cc259fef6414d31ed779ffc2e24af..0000000000000000000000000000000000000000 Binary files a/adb/apex/com.android.adbd.avbpubkey and /dev/null differ diff --git a/adb/apex/com.android.adbd.pem b/adb/apex/com.android.adbd.pem deleted file mode 100644 index 2c9a86079010601d8d52f54bbc29a0975b7b09d3..0000000000000000000000000000000000000000 --- a/adb/apex/com.android.adbd.pem +++ /dev/null @@ -1,51 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIJKQIBAAKCAgEAwUmO4l/ZdLhmBcBtpwDjih6z6bC7iZDPAVgnFVnYuYDRlVDA -9OCDwv02Wwc/YCNzON7vt7JBk3o9wyJZpqY9HR1PUjk2DJa/wHtxbskmLcqsvcoh -wZxmMkgx1mFyni/vQ0tCjjxYmDcnpoVmSntoPG4LBTZRwbgE2roYSuEi7q88Z9+t -cFiQ5x7MqVTzUFsi1E+rpsxRaTt6Ly9DO71yR1gMTqONsSgmFm8f2HhUCiQzRh7H -qLwk8eN5ZLPLVc1JBqo8swuH5pR9whR8HaYyQtK1VANRR9oVj3JpRXmyFUk8QjEn -91I3sFV1lErdP1uh6xi6ewMBp+mQ+ccNFiNJs8PHVprzbEgX2ah45Tnge95ZwnkR -V/5G/EwGBsggk/BcZjQyj0PExG6LmygR7lq8q4m9ODJj3cmNLZsZu8ukMBxf4Fim -4/Y7lyaelW0FL+x3CR27wlIxLyIf/JfUNv/cFO/O2MHrDHYdHtCbvg8vpq1MZtDN -+gJIkYQNUfBEtGS4SkH3WWfNet3bcL5yFx5IVdwCY+n635jPA1fvr1vcIiKnyGUm -zNE+jMOZkgk6lPPuDwllAX0D8nYTm1eBMCTAWCePO0QlcFHCT9j1/xKbFbjt/xYI -0pXuOc8/1n61F5ybzH/91cS66gqmYUAekUiP0osTIZ7idVFJMoqpc9m7+rECAwEA -AQKCAgEAkjg9WU89SCk/NNavnQj1GUXEwOKr3JOppdC0MFi5tQuYgSaH8jfuNZIs -joxbCzWGMt2j5wl4xkJRes7/lyxnSyEjIoaZNsjL4qb/1tlggn+yUhkZlEfmn98x -pIYvmS+WBwhmHwfT1cLTwgtkqK/W2PA+cgD3tF6rfXQOcIcEUCBMyB/UKws1A0Kv -fOIA9ycaoBZtOk+SvtL5ybwtVoIoc4ROOydLR1uiBJKoOrA8kzdzenZKgIFkSYDW -ErJY/l3AAsTCCoiMlIh84ldw1VUm7JpOBnJECOEYMl5Q+PfpGmU+qqxZGaYe7syX -mElSOl3tjdY1LF3H4Oi2fd5xLfAgDgQjXcawKRYpImEgbqNfEUHW4BE/uVp0hHn+ -W0tCq9hvWoizhjxVq7oEfpdCXJBH0bTg9h3Ho2nuJMHTrUVbSWPTqNJn1xOi4Oxl -vWsD5qjOOVw1e0P1dtxQ+6a8+rCL8LDvIthQC9Wpt0yXduEi/vUWiMFx2VbcSpNn -5PB9HK7vvCpR/k0IocaTKt80D3m2svJCnfrekRx/7n//x8imrvtvaYNpoToTSN0q -hPOpTNc77R4aARJNXm4sVHzGs6HUXsJfODJdjFtTuaDHjLvRoXZi2wFUVWBvIaFg -/4+PHXjsfMkY15KULKn3f7Xs7K6rmINAb853zti3Qkllv1EeYoECggEBAP9t1Jxe -hLKnVrJ5jJ0zCT0/ez6qM5cQG8YvXbVICmoAOQ+/NV6qjPABg5j8FuNhpyr45OuJ -m1oISLgZPVCbIvYx3oZS4ekWUp9Z7jlDGzsWiBCkEUFLRzDLQRUl4bQMI2SWM+vD -RL9AAM+NHJQ8LJN7ASNdSQw9ZinNCSByCZ52QjPCfRON0OPY4l1FJKHHymzBNXpe -R5e9a1o9KEIhd7j+3YX9y8SOVrbUe6U8me5LZ6RY+pLB+cA/UHcSQK23hYAkMcvL -MQny6B57P6rquzFZDG/OUOZWzWub2FSYTTmiYSHPAuB15FyWShs7h7+wK8y2xrSM -Lq3FWHxzR1OK2HkCggEBAMG4KsAU/lp9rQhNpdw2NQXqbDLgHy09BFMOOWhyp2/Z -2lbDo9aP746Q56HAfRRgx5oAAtr3SxeN/R/uEJLYzzDU+SrG4TQO/TZ3DPZOAVYM -oESWG/HXLN4Hw6j4iWt2NvqpnSVJrvYr6zar/QxRHOMwnUoUV3ugmzUkqFC/Nwmm -nMGJbTQbEha8OyatfwejmhrCkbQMBiCk0AQmgLybUxs2ckGs5jibau7VqXVxly0f -WkAsWE/qfybQl4oyBhGCFNObr3Co/PHTaD4ACFQQvaEEF4bTuh6wP+MIgJKxL8IB -SkrKWO5PFbJWY5lacnNMe7ITrWy60HukLlJe5or5lfkCggEBAP3Rwghw1CRDrR9F -Mbm0UWYPgwTOVN20ICVcRB40LEURW6KOOxaLG+oTVxXay1PAYkGNes2jvEBHIxvt -2MQUpTVIcPvBuMPKbufykYtNZ+3bgfInVw4vI9sU3uOI9TPZLAJ0T7vkGpiBnUyh -yNh0w0b6YDMoK8KB8Ndw67TWHUDd+wM8LNYVgpInnylX4ALzae+QPvgOX84laFwP -kcXFRBcNDExt2uLDHuAnXYbhJYVqYN8rnDPhlbC4OdlYxfTZ/UtMrD769wwP2SER -ED9jagirmHQx7Ko3b4GTJ/FINtUiyqqx7wXloLtwjMtq6IZPJfcTWXloI6qCBGAG -ncYinuECggEAfZeiF8BEm3RpTz3QL3HxdHFkTqOhctnhSNuq+n2C8nBCLwhN21ic -DkkB84txTFnmboBdWYsEYzQKDL5yflIUGeup00L3VKH3Jm2OuM0f7qLm8TCE04kW -rKhKAO2JYmNVB7QZjsgzp6QXre1ZdLfNy7mD8Dg584vPtGecvCUMULR1YsBvTV3T -n2vPyaan+dLmoTzN6/XzrwxLVLWFt0HYYoctEkk/RSn17PwXDm5jfbya7YoSg1Vb -tFV+Oflul8FHMV35I0hcHYhbR/8LZz0nRBH8EsyIGUdZVB76BKDdfqEJgm2ntHEP -dvytPAo4s2m9tFkvkZOYgOCTq5GdVDK2OQKCAQAsz+y9rDcqFciCESu4IHzmtckT -0kwP2W5ds5hzUjbY0Y2AKTx2oHNOFak6WW5vxN0+OIn37SNK3RBStPWJiigut4R4 -rGrZM4pijm53s3cWzd0h8XyLGisl2zORu8gD2IQLkQf79F3lEZHGA+J0mkSHB85N -IuqReFzL6cfOToNd+8WYjMgJcXmVuKiCV1FRK3jrqNpXO2cLtnhFvQMxRUAYU4j+ -2MIdBFVeMq5ftMMOBS21hM9cNLlOzoSN2HmK+ZkmrlTCK0G9lmF427/lqXTmWLed -sspOUbOLfBOwxdCCc9JUxz5KggKWcDcTqX25M0mv09rpuCxIEg8lez1Ax0if ------END RSA PRIVATE KEY----- diff --git a/adb/apex/com.android.adbd.pk8 b/adb/apex/com.android.adbd.pk8 deleted file mode 100644 index cdddc3fdfb96490fda8cc5fa7a992642cb78bd4d..0000000000000000000000000000000000000000 Binary files a/adb/apex/com.android.adbd.pk8 and /dev/null differ diff --git a/adb/apex/com.android.adbd.x509.pem b/adb/apex/com.android.adbd.x509.pem deleted file mode 100644 index bb85c1d115556d53ef0cfa52439a6d054476c67b..0000000000000000000000000000000000000000 --- a/adb/apex/com.android.adbd.x509.pem +++ /dev/null @@ -1,35 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIGHzCCBAegAwIBAgIUW8npFHXBP+wsEAesGMBxaV7TScAwDQYJKoZIhvcNAQEL -BQAwgZ0xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH -DA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYDVQQLDAdBbmRy -b2lkMRkwFwYDVQQDDBBjb20uYW5kcm9pZC5hZGJkMSIwIAYJKoZIhvcNAQkBFhNh -bmRyb2lkQGFuZHJvaWQuY29tMCAXDTE5MDgxNTE5MzkxM1oYDzQ3NTcwNzExMTkz -OTEzWjCBnTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNV -BAcMDU1vdW50YWluIFZpZXcxEDAOBgNVBAoMB0FuZHJvaWQxEDAOBgNVBAsMB0Fu -ZHJvaWQxGTAXBgNVBAMMEGNvbS5hbmRyb2lkLmFkYmQxIjAgBgkqhkiG9w0BCQEW -E2FuZHJvaWRAYW5kcm9pZC5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK -AoICAQC6zbUeWi5vNA6vCC4FBrJQ9re4UexP6TabsDYvWpFBoCluvMkT2ZRmpXMF -W7EzQ5VmuUvZgLYVHuJmnvHIV3uaRc2VE1SV+spjWTRt+6DtsAN7irR5K66POWMp -+tr5hASdQBVOJdebimsepy0pH6sXREvanrrFzkSM/2Ho0unlwWJ5Y4jcnvdkVHI5 -Ks0vifLmX4y5mYgv1dcXYWzyYx39f8HyePv0cjRhYXiIEYZ49KWU4MjryvQe/mAu -MQuMp901BLps2W1+oKyPPA4DV69KUXgF66RFfsjjkJJ/CSeQGzTuez+UWzFk3Duc -6MmbiL1LTki3vyyVtjW1rYFO2s+M6Pa5NZWHgA55uUxiJ987WPyK9lWnMsY6YeKa -FDBfS1JUzXGPzVncgM7LLvzAEibLdhjII88NsJvzPoHK0SluSn+E7t7iGO1fTjkD -Js94iUJAp8OQ4GwkcTVgtEAR+NXzownNjHJ6qpiq6tXRqXdBqSat/glf01AgNDtz -9AGeW7Mz6FqTdOzg3U4lu77+CGd3SZTuQk8C8PUDNhqhQX5H2qhr90bakGaXuYfE -rWFzIjrVdJIznV1BimOCay5HyyHab4FWlVhAvslEQb2BpHRyi2lhe0laupOpmN44 -LzfjFM18bi2GashIi2OQuYDyAeT5mGtR2g8mC7g44H6dH+wTfQIDAQABo1MwUTAd -BgNVHQ4EFgQU7lyyxPO5SOOh9a5O0l4+RjckcgcwHwYDVR0jBBgwFoAU7lyyxPO5 -SOOh9a5O0l4+RjckcgcwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC -AgEAStsOy8bkbZg/Ygx47bPkLSz0cJIvATxTChUGOabkz+brLis88ABVWVP0IXps -tlLlZR5cjXBJguE7GJXzKPWzQZuB8+YwcGHG6QDFpfdMeGrxPDhwNfGy236ArVnx -K0v1IIxoZRZ0P7aubk3xwUAPgsmT5ayZCKu+dqlEy5B6ioKEsr7Y2RRT/8ifERNm -cjS9AhcyWrp4R3cjy2iA/RpdsPFwE5ac3I+GtUB4D2up5aDMsy85i9t2/1kuTUaA -9UHwGXCpcqP8f8BqeLzuxDzYkAvkntlNxbXn1cbn+dTRIOCBoDbtSeqtxhWooOUH -RQROeRsB7iicdYJJRge0+WyR+216AKUSQPE6/rT0Ifr06ZRwi22/YyySpwuO3SNA -+yWffh+f4h31Dz+p6pu8wjbMDkq4LnCWyjLwfF/yhvWhwwm5+KPAEhvJABeHQc+3 -cslOC9dlXJm9sPoUC7ghmUiFsCmN2hIzQrr2QoK0Obh0AGexOvOAw9cqtOdZQncB -bqC8c4sVYScVxwDWkg0lNfRMC5boPjBsl7+M2CC1ukgVpXTyDOEjMWILrBXfYCDX -unBH3kbKQOfL5RT0nE1Lkt1rn5qAWMJg4mvS4QuIurbRtEoj3QYQadF9md4qJXs0 -TvqvY8iEC4xrWU2SQn1K3PutXgaLP9/b6Cy1SBrhBX+AC5s= ------END CERTIFICATE----- diff --git a/adb/apex/test_apex_manifest.json b/adb/apex/test_apex_manifest.json deleted file mode 100644 index 7131977062ffad094386a4b5a546fb25fdc28593..0000000000000000000000000000000000000000 --- a/adb/apex/test_apex_manifest.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "com.android.adbd", - "version": 2147483647 -} diff --git a/adb/benchmark_device.py b/adb/benchmark_device.py deleted file mode 100755 index 4d0cf49a05227764333c1264557900b9748f0231..0000000000000000000000000000000000000000 --- a/adb/benchmark_device.py +++ /dev/null @@ -1,156 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (C) 2018 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 os -import statistics -import subprocess -import tempfile -import time - -import adb - -def lock_min(device): - device.shell_nocheck([""" - for x in /sys/devices/system/cpu/cpu?/cpufreq; do - echo userspace > $x/scaling_governor - cat $x/scaling_min_freq > $x/scaling_setspeed - done - """]) - -def lock_max(device): - device.shell_nocheck([""" - for x in /sys/devices/system/cpu/cpu?/cpufreq; do - echo userspace > $x/scaling_governor - cat $x/scaling_max_freq > $x/scaling_setspeed - done - """]) - -def unlock(device): - device.shell_nocheck([""" - for x in /sys/devices/system/cpu/cpu?/cpufreq; do - echo ondemand > $x/scaling_governor - echo sched > $x/scaling_governor - echo schedutil > $x/scaling_governor - done - """]) - -def harmonic_mean(xs): - return 1.0 / statistics.mean([1.0 / x for x in xs]) - -def analyze(name, speeds): - median = statistics.median(speeds) - mean = harmonic_mean(speeds) - stddev = statistics.stdev(speeds) - msg = "%s: %d runs: median %.2f MiB/s, mean %.2f MiB/s, stddev: %.2f MiB/s" - print(msg % (name, len(speeds), median, mean, stddev)) - -def benchmark_sink(device=None, size_mb=100): - if device == None: - device = adb.get_device() - - speeds = list() - cmd = device.adb_cmd + ["raw", "sink:%d" % (size_mb * 1024 * 1024)] - - with tempfile.TemporaryFile() as tmpfile: - tmpfile.truncate(size_mb * 1024 * 1024) - - for _ in range(0, 10): - tmpfile.seek(0) - begin = time.time() - subprocess.check_call(cmd, stdin=tmpfile) - end = time.time() - speeds.append(size_mb / float(end - begin)) - - analyze("sink %dMiB" % size_mb, speeds) - -def benchmark_source(device=None, size_mb=100): - if device == None: - device = adb.get_device() - - speeds = list() - cmd = device.adb_cmd + ["raw", "source:%d" % (size_mb * 1024 * 1024)] - - with open(os.devnull, 'w') as devnull: - for _ in range(0, 10): - begin = time.time() - subprocess.check_call(cmd, stdout=devnull) - end = time.time() - speeds.append(size_mb / float(end - begin)) - - analyze("source %dMiB" % size_mb, speeds) - -def benchmark_push(device=None, file_size_mb=100): - if device == None: - device = adb.get_device() - - remote_path = "/dev/null" - local_path = "/tmp/adb_benchmark_temp" - - with open(local_path, "wb") as f: - f.truncate(file_size_mb * 1024 * 1024) - - speeds = list() - for _ in range(0, 10): - begin = time.time() - device.push(local=local_path, remote=remote_path) - end = time.time() - speeds.append(file_size_mb / float(end - begin)) - - analyze("push %dMiB" % file_size_mb, speeds) - -def benchmark_pull(device=None, file_size_mb=100): - if device == None: - device = adb.get_device() - - remote_path = "/data/local/tmp/adb_benchmark_temp" - local_path = "/tmp/adb_benchmark_temp" - - device.shell(["dd", "if=/dev/zero", "of=" + remote_path, "bs=1m", - "count=" + str(file_size_mb)]) - speeds = list() - for _ in range(0, 10): - begin = time.time() - device.pull(remote=remote_path, local=local_path) - end = time.time() - speeds.append(file_size_mb / float(end - begin)) - - analyze("pull %dMiB" % file_size_mb, speeds) - -def benchmark_shell(device=None, file_size_mb=100): - if device == None: - device = adb.get_device() - - speeds = list() - for _ in range(0, 10): - begin = time.time() - device.shell(["dd", "if=/dev/zero", "bs=1m", - "count=" + str(file_size_mb)]) - end = time.time() - speeds.append(file_size_mb / float(end - begin)) - - analyze("shell %dMiB" % file_size_mb, speeds) - -def main(): - device = adb.get_device() - unlock(device) - benchmark_sink(device) - benchmark_source(device) - benchmark_push(device) - benchmark_pull(device) - -if __name__ == "__main__": - main() diff --git a/adb/brotli_utils.h b/adb/brotli_utils.h deleted file mode 100644 index c5be73d0ceb837858eabab96d4c2a9511a8e13ae..0000000000000000000000000000000000000000 --- a/adb/brotli_utils.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2020 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. - */ - -#pragma once - -#include - -#include -#include - -#include "types.h" - -enum class BrotliDecodeResult { - Error, - Done, - NeedInput, - MoreOutput, -}; - -struct BrotliDecoder { - explicit BrotliDecoder(std::span output_buffer) - : output_buffer_(output_buffer), - decoder_(BrotliDecoderCreateInstance(nullptr, nullptr, nullptr), - BrotliDecoderDestroyInstance) {} - - void Append(Block&& block) { input_buffer_.append(std::move(block)); } - - BrotliDecodeResult Decode(std::span* output) { - size_t available_in = input_buffer_.front_size(); - const uint8_t* next_in = reinterpret_cast(input_buffer_.front_data()); - - size_t available_out = output_buffer_.size(); - uint8_t* next_out = reinterpret_cast(output_buffer_.data()); - - BrotliDecoderResult r = BrotliDecoderDecompressStream( - decoder_.get(), &available_in, &next_in, &available_out, &next_out, nullptr); - - size_t bytes_consumed = input_buffer_.front_size() - available_in; - input_buffer_.drop_front(bytes_consumed); - - size_t bytes_emitted = output_buffer_.size() - available_out; - *output = std::span(output_buffer_.data(), bytes_emitted); - - switch (r) { - case BROTLI_DECODER_RESULT_SUCCESS: - return BrotliDecodeResult::Done; - case BROTLI_DECODER_RESULT_ERROR: - return BrotliDecodeResult::Error; - case BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT: - // Brotli guarantees as one of its invariants that if it returns NEEDS_MORE_INPUT, - // it will consume the entire input buffer passed in, so we don't have to worry - // about bytes left over in the front block with more input remaining. - return BrotliDecodeResult::NeedInput; - case BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT: - return BrotliDecodeResult::MoreOutput; - } - } - - private: - IOVector input_buffer_; - std::span output_buffer_; - std::unique_ptr decoder_; -}; - -enum class BrotliEncodeResult { - Error, - Done, - NeedInput, - MoreOutput, -}; - -template -struct BrotliEncoder { - explicit BrotliEncoder() - : output_block_(OutputBlockSize), - output_bytes_left_(OutputBlockSize), - encoder_(BrotliEncoderCreateInstance(nullptr, nullptr, nullptr), - BrotliEncoderDestroyInstance) { - BrotliEncoderSetParameter(encoder_.get(), BROTLI_PARAM_QUALITY, 1); - } - - void Append(Block input) { input_buffer_.append(std::move(input)); } - void Finish() { finished_ = true; } - - BrotliEncodeResult Encode(Block* output) { - output->clear(); - while (true) { - size_t available_in = input_buffer_.front_size(); - const uint8_t* next_in = reinterpret_cast(input_buffer_.front_data()); - - size_t available_out = output_bytes_left_; - uint8_t* next_out = reinterpret_cast(output_block_.data() + - (OutputBlockSize - output_bytes_left_)); - - BrotliEncoderOperation op = BROTLI_OPERATION_PROCESS; - if (finished_) { - op = BROTLI_OPERATION_FINISH; - } - - if (!BrotliEncoderCompressStream(encoder_.get(), op, &available_in, &next_in, - &available_out, &next_out, nullptr)) { - return BrotliEncodeResult::Error; - } - - size_t bytes_consumed = input_buffer_.front_size() - available_in; - input_buffer_.drop_front(bytes_consumed); - - output_bytes_left_ = available_out; - - if (BrotliEncoderIsFinished(encoder_.get())) { - output_block_.resize(OutputBlockSize - output_bytes_left_); - *output = std::move(output_block_); - return BrotliEncodeResult::Done; - } else if (output_bytes_left_ == 0) { - *output = std::move(output_block_); - output_block_.resize(OutputBlockSize); - output_bytes_left_ = OutputBlockSize; - return BrotliEncodeResult::MoreOutput; - } else if (input_buffer_.empty()) { - return BrotliEncodeResult::NeedInput; - } - } - } - - private: - bool finished_ = false; - IOVector input_buffer_; - Block output_block_; - size_t output_bytes_left_; - std::unique_ptr encoder_; -}; diff --git a/adb/bugreport_test.cpp b/adb/bugreport_test.cpp deleted file mode 100644 index a6be203685d0b5fa2a84336c2fc348479d8f3bed..0000000000000000000000000000000000000000 --- a/adb/bugreport_test.cpp +++ /dev/null @@ -1,466 +0,0 @@ -/* - * Copyright (C) 2016 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 "bugreport.h" - -#include -#include - -#include -#include - -#include "sysdeps.h" -#include "adb_utils.h" - -using ::testing::_; -using ::testing::Action; -using ::testing::ActionInterface; -using ::testing::DoAll; -using ::testing::ElementsAre; -using ::testing::HasSubstr; -using ::testing::MakeAction; -using ::testing::Return; -using ::testing::StrEq; -using ::testing::WithArg; -using ::testing::internal::CaptureStderr; -using ::testing::internal::CaptureStdout; -using ::testing::internal::GetCapturedStderr; -using ::testing::internal::GetCapturedStdout; - -// Empty function so tests don't need to be linked against file_sync_service.cpp, which requires -// SELinux and its transitive dependencies... -bool do_sync_pull(const std::vector& srcs, const char* dst, bool copy_attrs, - const char* name) { - ADD_FAILURE() << "do_sync_pull() should have been mocked"; - return false; -} - -// Empty functions so tests don't need to be linked against commandline.cpp -DefaultStandardStreamsCallback DEFAULT_STANDARD_STREAMS_CALLBACK(nullptr, nullptr); - -int send_shell_command(const std::string& command, bool disable_shell_protocol, - StandardStreamsCallbackInterface* callback) { - ADD_FAILURE() << "send_shell_command() should have been mocked"; - return -42; -} - -enum StreamType { - kStreamStdout, - kStreamStderr, -}; - -// gmock black magic to provide a WithArg<2>(WriteOnStdout(output)) matcher -typedef void OnStandardStreamsCallbackFunction(StandardStreamsCallbackInterface*); - -class OnStandardStreamsCallbackAction : public ActionInterface { - public: - explicit OnStandardStreamsCallbackAction(StreamType type, const std::string& output) - : type_(type), output_(output) { - } - virtual Result Perform(const ArgumentTuple& args) { - if (type_ == kStreamStdout) { - ::std::tr1::get<0>(args)->OnStdout(output_.c_str(), output_.size()); - } - if (type_ == kStreamStderr) { - ::std::tr1::get<0>(args)->OnStderr(output_.c_str(), output_.size()); - } - } - - private: - StreamType type_; - std::string output_; -}; - -// Matcher used to emulated StandardStreamsCallbackInterface.OnStdout(buffer, -// length) -Action WriteOnStdout(const std::string& output) { - return MakeAction(new OnStandardStreamsCallbackAction(kStreamStdout, output)); -} - -// Matcher used to emulated StandardStreamsCallbackInterface.OnStderr(buffer, -// length) -Action WriteOnStderr(const std::string& output) { - return MakeAction(new OnStandardStreamsCallbackAction(kStreamStderr, output)); -} - -typedef int CallbackDoneFunction(StandardStreamsCallbackInterface*); - -class CallbackDoneAction : public ActionInterface { - public: - explicit CallbackDoneAction(int status) : status_(status) { - } - virtual Result Perform(const ArgumentTuple& args) { - int status = ::std::tr1::get<0>(args)->Done(status_); - return status; - } - - private: - int status_; -}; - -// Matcher used to emulated StandardStreamsCallbackInterface.Done(status) -Action ReturnCallbackDone(int status = -1337) { - return MakeAction(new CallbackDoneAction(status)); -} - -class BugreportMock : public Bugreport { - public: - MOCK_METHOD3(SendShellCommand, int(const std::string& command, bool disable_shell_protocol, - StandardStreamsCallbackInterface* callback)); - MOCK_METHOD4(DoSyncPull, bool(const std::vector& srcs, const char* dst, - bool copy_attrs, const char* name)); - MOCK_METHOD2(UpdateProgress, void(const std::string&, int)); -}; - -class BugreportTest : public ::testing::Test { - public: - void SetUp() { - if (!getcwd(&cwd_)) { - ADD_FAILURE() << "getcwd failed: " << strerror(errno); - return; - } - } - - void ExpectBugreportzVersion(const std::string& version) { - EXPECT_CALL(br_, SendShellCommand("bugreportz -v", false, _)) - .WillOnce(DoAll(WithArg<2>(WriteOnStderr(version)), - WithArg<2>(ReturnCallbackDone(0)))); - } - - void ExpectProgress(int progress_percentage, const std::string& file = "file.zip") { - EXPECT_CALL(br_, UpdateProgress(StrEq("generating " + file), progress_percentage)); - } - - BugreportMock br_; - std::string cwd_; // TODO: make it static -}; - -// Tests when called with invalid number of arguments -TEST_F(BugreportTest, InvalidNumberArgs) { - const char* args[] = {"bugreport", "to", "principal"}; - ASSERT_EQ(1, br_.DoIt(3, args)); -} - -// Tests the 'adb bugreport' option when the device does not support 'bugreportz' - it falls back -// to the flat-file format ('bugreport' binary on device) -TEST_F(BugreportTest, NoArgumentsPreNDevice) { - // clang-format off - EXPECT_CALL(br_, SendShellCommand("bugreportz -v", false, _)) - .WillOnce(DoAll(WithArg<2>(WriteOnStderr("")), - // Write some bogus output on stdout to make sure it's ignored - WithArg<2>(WriteOnStdout("Dude, where is my bugreportz?")), - WithArg<2>(ReturnCallbackDone(0)))); - // clang-format on - std::string bugreport = "Reported the bug was."; - CaptureStdout(); - EXPECT_CALL(br_, SendShellCommand("bugreport", false, _)) - .WillOnce(DoAll(WithArg<2>(WriteOnStdout(bugreport)), Return(0))); - - const char* args[] = {"bugreport"}; - ASSERT_EQ(0, br_.DoIt(1, args)); - ASSERT_THAT(GetCapturedStdout(), StrEq(bugreport)); -} - -// Tests the 'adb bugreport' option when the device supports 'bugreportz' version 1.0 - it will -// save the bugreport in the current directory with the name provided by the device. -TEST_F(BugreportTest, NoArgumentsNDevice) { - ExpectBugreportzVersion("1.0"); - - std::string dest_file = - android::base::StringPrintf("%s%cda_bugreport.zip", cwd_.c_str(), OS_PATH_SEPARATOR); - EXPECT_CALL(br_, SendShellCommand("bugreportz", false, _)) - .WillOnce(DoAll(WithArg<2>(WriteOnStdout("OK:/device/da_bugreport.zip")), - WithArg<2>(ReturnCallbackDone()))); - EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file), - false, StrEq("pulling da_bugreport.zip"))) - .WillOnce(Return(true)); - - const char* args[] = {"bugreport"}; - ASSERT_EQ(0, br_.DoIt(1, args)); -} - -// Tests the 'adb bugreport' option when the device supports 'bugreportz' version 1.1 - it will -// save the bugreport in the current directory with the name provided by the device. -TEST_F(BugreportTest, NoArgumentsPostNDevice) { - ExpectBugreportzVersion("1.1"); - std::string dest_file = - android::base::StringPrintf("%s%cda_bugreport.zip", cwd_.c_str(), OS_PATH_SEPARATOR); - ExpectProgress(50, "da_bugreport.zip"); - EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _)) - .WillOnce(DoAll(WithArg<2>(WriteOnStdout("BEGIN:/device/da_bugreport.zip\n")), - WithArg<2>(WriteOnStdout("PROGRESS:50/100\n")), - WithArg<2>(WriteOnStdout("OK:/device/da_bugreport.zip\n")), - WithArg<2>(ReturnCallbackDone()))); - EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file), - false, StrEq("pulling da_bugreport.zip"))) - .WillOnce(Return(true)); - - const char* args[] = {"bugreport"}; - ASSERT_EQ(0, br_.DoIt(1, args)); -} - -// Tests 'adb bugreport file.zip' when it succeeds and device does not support progress. -TEST_F(BugreportTest, OkNDevice) { - ExpectBugreportzVersion("1.0"); - EXPECT_CALL(br_, SendShellCommand("bugreportz", false, _)) - .WillOnce(DoAll(WithArg<2>(WriteOnStdout("OK:/device/bugreport.zip")), - WithArg<2>(ReturnCallbackDone()))); - EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"), - false, StrEq("pulling file.zip"))) - .WillOnce(Return(true)); - - const char* args[] = {"bugreport", "file.zip"}; - ASSERT_EQ(0, br_.DoIt(2, args)); -} - -// Tests 'adb bugreport file.zip' when it succeeds but response was sent in -// multiple buffer writers and without progress updates. -TEST_F(BugreportTest, OkNDeviceSplitBuffer) { - ExpectBugreportzVersion("1.0"); - EXPECT_CALL(br_, SendShellCommand("bugreportz", false, _)) - .WillOnce(DoAll(WithArg<2>(WriteOnStdout("OK:/device")), - WithArg<2>(WriteOnStdout("/bugreport.zip")), - WithArg<2>(ReturnCallbackDone()))); - EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"), - false, StrEq("pulling file.zip"))) - .WillOnce(Return(true)); - - const char* args[] = {"bugreport", "file.zip"}; - ASSERT_EQ(0, br_.DoIt(2, args)); -} - -// Tests 'adb bugreport file.zip' when it succeeds and displays progress. -TEST_F(BugreportTest, OkProgress) { - ExpectBugreportzVersion("1.1"); - ExpectProgress(1); - ExpectProgress(10); - ExpectProgress(50); - ExpectProgress(99); - // clang-format off - EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _)) - // NOTE: DoAll accepts at most 10 arguments, and we're almost reached that limit... - .WillOnce(DoAll( - // Name might change on OK, so make sure the right one is picked. - WithArg<2>(WriteOnStdout("BEGIN:/device/bugreport___NOT.zip\n")), - // Progress line in one write - WithArg<2>(WriteOnStdout("PROGRESS:1/100\n")), - // Add some bogus lines - WithArg<2>(WriteOnStdout("\nDUDE:SWEET\n\nBLA\n\nBLA\nBLA\n\n")), - // Multiple progress lines in one write - WithArg<2>(WriteOnStdout("PROGRESS:10/100\nPROGRESS:50/100\n")), - // Progress line in multiple writes - WithArg<2>(WriteOnStdout("PROG")), - WithArg<2>(WriteOnStdout("RESS:99")), - WithArg<2>(WriteOnStdout("/100\n")), - // Split last message as well, just in case - WithArg<2>(WriteOnStdout("OK:/device/bugreport")), - WithArg<2>(WriteOnStdout(".zip")), - WithArg<2>(ReturnCallbackDone()))); - // clang-format on - EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"), - false, StrEq("pulling file.zip"))) - .WillOnce(Return(true)); - - const char* args[] = {"bugreport", "file.zip"}; - ASSERT_EQ(0, br_.DoIt(2, args)); -} - -// Tests 'adb bugreport file.zip' when it succeeds and displays progress, even if progress recedes. -TEST_F(BugreportTest, OkProgressAlwaysForward) { - ExpectBugreportzVersion("1.1"); - ExpectProgress(1); - ExpectProgress(50); - ExpectProgress(75); - // clang-format off - EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _)) - // NOTE: DoAll accepts at most 10 arguments, and we're almost reached that limit... - .WillOnce(DoAll( - WithArg<2>(WriteOnStdout("BEGIN:/device/bugreport.zip\n")), - WithArg<2>(WriteOnStdout("PROGRESS:1/100\n")), // 1% - WithArg<2>(WriteOnStdout("PROGRESS:50/100\n")), // 50% - // 25% should be ignored becaused it receded. - WithArg<2>(WriteOnStdout("PROGRESS:25/100\n")), // 25% - WithArg<2>(WriteOnStdout("PROGRESS:75/100\n")), // 75% - // 75% should be ignored becaused it didn't change. - WithArg<2>(WriteOnStdout("PROGRESS:75/100\n")), // 75% - // Try a receeding percentage with a different max progress - WithArg<2>(WriteOnStdout("PROGRESS:700/1000\n")), // 70% - WithArg<2>(WriteOnStdout("OK:/device/bugreport.zip")), - WithArg<2>(ReturnCallbackDone()))); - // clang-format on - EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"), - false, StrEq("pulling file.zip"))) - .WillOnce(Return(true)); - - const char* args[] = {"bugreport", "file.zip"}; - ASSERT_EQ(0, br_.DoIt(2, args)); -} - -// Tests 'adb bugreport file.zip' when it succeeds and displays the initial progress of 0% -TEST_F(BugreportTest, OkProgressZeroPercentIsNotIgnored) { - ExpectBugreportzVersion("1.1"); - ExpectProgress(0); - ExpectProgress(1); - // clang-format off - EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _)) - // NOTE: DoAll accepts at most 10 arguments, and we're almost reached that limit... - .WillOnce(DoAll( - WithArg<2>(WriteOnStdout("BEGIN:/device/bugreport.zip\n")), - WithArg<2>(WriteOnStdout("PROGRESS:1/100000\n")), - WithArg<2>(WriteOnStdout("PROGRESS:1/100\n")), // 1% - WithArg<2>(WriteOnStdout("OK:/device/bugreport.zip")), - WithArg<2>(ReturnCallbackDone()))); - // clang-format on - EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"), - false, StrEq("pulling file.zip"))) - .WillOnce(Return(true)); - - const char* args[] = {"bugreport", "file.zip"}; - ASSERT_EQ(0, br_.DoIt(2, args)); -} - -// Tests 'adb bugreport dir' when it succeeds and destination is a directory. -TEST_F(BugreportTest, OkDirectory) { - ExpectBugreportzVersion("1.1"); - TemporaryDir td; - std::string dest_file = - android::base::StringPrintf("%s%cda_bugreport.zip", td.path, OS_PATH_SEPARATOR); - - EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _)) - .WillOnce(DoAll(WithArg<2>(WriteOnStdout("BEGIN:/device/da_bugreport.zip\n")), - WithArg<2>(WriteOnStdout("OK:/device/da_bugreport.zip")), - WithArg<2>(ReturnCallbackDone()))); - EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file), - false, StrEq("pulling da_bugreport.zip"))) - .WillOnce(Return(true)); - - const char* args[] = {"bugreport", td.path}; - ASSERT_EQ(0, br_.DoIt(2, args)); -} - -// Tests 'adb bugreport file' when it succeeds -TEST_F(BugreportTest, OkNoExtension) { - ExpectBugreportzVersion("1.1"); - EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _)) - .WillOnce(DoAll(WithArg<2>(WriteOnStdout("OK:/device/bugreport.zip\n")), - WithArg<2>(ReturnCallbackDone()))); - EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"), - false, StrEq("pulling file.zip"))) - .WillOnce(Return(true)); - - const char* args[] = {"bugreport", "file"}; - ASSERT_EQ(0, br_.DoIt(2, args)); -} - -// Tests 'adb bugreport dir' when it succeeds and destination is a directory and device runs N. -TEST_F(BugreportTest, OkNDeviceDirectory) { - ExpectBugreportzVersion("1.0"); - TemporaryDir td; - std::string dest_file = - android::base::StringPrintf("%s%cda_bugreport.zip", td.path, OS_PATH_SEPARATOR); - - EXPECT_CALL(br_, SendShellCommand("bugreportz", false, _)) - .WillOnce(DoAll(WithArg<2>(WriteOnStdout("BEGIN:/device/da_bugreport.zip\n")), - WithArg<2>(WriteOnStdout("OK:/device/da_bugreport.zip")), - WithArg<2>(ReturnCallbackDone()))); - EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file), - false, StrEq("pulling da_bugreport.zip"))) - .WillOnce(Return(true)); - - const char* args[] = {"bugreport", td.path}; - ASSERT_EQ(0, br_.DoIt(2, args)); -} - -// Tests 'adb bugreport file.zip' when the bugreport itself failed -TEST_F(BugreportTest, BugreportzReturnedFail) { - ExpectBugreportzVersion("1.1"); - EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _)) - .WillOnce( - DoAll(WithArg<2>(WriteOnStdout("FAIL:D'OH!\n")), WithArg<2>(ReturnCallbackDone()))); - - CaptureStderr(); - const char* args[] = {"bugreport", "file.zip"}; - ASSERT_EQ(-1, br_.DoIt(2, args)); - ASSERT_THAT(GetCapturedStderr(), HasSubstr("D'OH!")); -} - -// Tests 'adb bugreport file.zip' when the bugreport itself failed but response -// was sent in -// multiple buffer writes -TEST_F(BugreportTest, BugreportzReturnedFailSplitBuffer) { - ExpectBugreportzVersion("1.1"); - EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _)) - .WillOnce(DoAll(WithArg<2>(WriteOnStdout("FAIL")), WithArg<2>(WriteOnStdout(":D'OH!\n")), - WithArg<2>(ReturnCallbackDone()))); - - CaptureStderr(); - const char* args[] = {"bugreport", "file.zip"}; - ASSERT_EQ(-1, br_.DoIt(2, args)); - ASSERT_THAT(GetCapturedStderr(), HasSubstr("D'OH!")); -} - -// Tests 'adb bugreport file.zip' when the bugreportz returned an unsupported -// response. -TEST_F(BugreportTest, BugreportzReturnedUnsupported) { - ExpectBugreportzVersion("1.1"); - EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _)) - .WillOnce(DoAll(WithArg<2>(WriteOnStdout("bugreportz? What am I, a zombie?")), - WithArg<2>(ReturnCallbackDone()))); - - CaptureStderr(); - const char* args[] = {"bugreport", "file.zip"}; - ASSERT_EQ(-1, br_.DoIt(2, args)); - ASSERT_THAT(GetCapturedStderr(), HasSubstr("bugreportz? What am I, a zombie?")); -} - -// Tests 'adb bugreport file.zip' when the bugreportz -v command failed -TEST_F(BugreportTest, BugreportzVersionFailed) { - EXPECT_CALL(br_, SendShellCommand("bugreportz -v", false, _)).WillOnce(Return(666)); - - const char* args[] = {"bugreport", "file.zip"}; - ASSERT_EQ(666, br_.DoIt(2, args)); -} - -// Tests 'adb bugreport file.zip' when the bugreportz -v returns status 0 but with no output. -TEST_F(BugreportTest, BugreportzVersionEmpty) { - ExpectBugreportzVersion(""); - - const char* args[] = {"bugreport", "file.zip"}; - ASSERT_EQ(-1, br_.DoIt(2, args)); -} - -// Tests 'adb bugreport file.zip' when the main bugreportz command failed -TEST_F(BugreportTest, BugreportzFailed) { - ExpectBugreportzVersion("1.1"); - EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _)).WillOnce(Return(666)); - - const char* args[] = {"bugreport", "file.zip"}; - ASSERT_EQ(666, br_.DoIt(2, args)); -} - -// Tests 'adb bugreport file.zip' when the bugreport could not be pulled -TEST_F(BugreportTest, PullFails) { - ExpectBugreportzVersion("1.1"); - EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _)) - .WillOnce(DoAll(WithArg<2>(WriteOnStdout("OK:/device/bugreport.zip")), - WithArg<2>(ReturnCallbackDone()))); - EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"), - false, HasSubstr("file.zip"))) - .WillOnce(Return(false)); - - const char* args[] = {"bugreport", "file.zip"}; - ASSERT_EQ(1, br_.DoIt(2, args)); -} diff --git a/adb/client/adb_client.cpp b/adb/client/adb_client.cpp deleted file mode 100644 index f724cb5221f926284a2750b7bb3d165db44b3b6c..0000000000000000000000000000000000000000 --- a/adb/client/adb_client.cpp +++ /dev/null @@ -1,416 +0,0 @@ -/* - * Copyright (C) 2015 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 ADB - -#include "sysdeps.h" -#include "adb_client.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "adb_io.h" -#include "adb_utils.h" -#include "socket_spec.h" -#include "sysdeps/chrono.h" - -static TransportType __adb_transport = kTransportAny; -static const char* __adb_serial = nullptr; -static TransportId __adb_transport_id = 0; - -static const char* __adb_server_socket_spec; - -void adb_set_transport(TransportType type, const char* serial, TransportId transport_id) { - __adb_transport = type; - __adb_serial = serial; - __adb_transport_id = transport_id; -} - -void adb_get_transport(TransportType* type, const char** serial, TransportId* transport_id) { - if (type) *type = __adb_transport; - if (serial) *serial = __adb_serial; - if (transport_id) *transport_id = __adb_transport_id; -} - -void adb_set_socket_spec(const char* socket_spec) { - if (__adb_server_socket_spec) { - LOG(FATAL) << "attempted to reinitialize adb_server_socket_spec " << socket_spec << " (was " << __adb_server_socket_spec << ")"; - } - __adb_server_socket_spec = socket_spec; -} - -static std::optional switch_socket_transport(int fd, std::string* error) { - TransportId result; - bool read_transport = true; - - std::string service; - if (__adb_transport_id) { - read_transport = false; - service += "host:transport-id:"; - service += std::to_string(__adb_transport_id); - result = __adb_transport_id; - } else if (__adb_serial) { - service += "host:tport:serial:"; - service += __adb_serial; - } else { - const char* transport_type = "???"; - switch (__adb_transport) { - case kTransportUsb: - transport_type = "usb"; - break; - case kTransportLocal: - transport_type = "local"; - break; - case kTransportAny: - transport_type = "any"; - break; - case kTransportHost: - // no switch necessary - return 0; - } - service += "host:tport:"; - service += transport_type; - } - - if (!SendProtocolString(fd, service)) { - *error = perror_str("write failure during connection"); - return std::nullopt; - } - - LOG(DEBUG) << "Switch transport in progress: " << service; - - if (!adb_status(fd, error)) { - D("Switch transport failed: %s", error->c_str()); - return std::nullopt; - } - - if (read_transport) { - if (!ReadFdExactly(fd, &result, sizeof(result))) { - *error = "failed to read transport id from server"; - return std::nullopt; - } - } - - D("Switch transport success"); - return result; -} - -bool adb_status(borrowed_fd fd, std::string* error) { - char buf[5]; - if (!ReadFdExactly(fd, buf, 4)) { - *error = perror_str("protocol fault (couldn't read status)"); - return false; - } - - if (!memcmp(buf, "OKAY", 4)) { - return true; - } - - if (memcmp(buf, "FAIL", 4)) { - *error = android::base::StringPrintf("protocol fault (status %02x %02x %02x %02x?!)", - buf[0], buf[1], buf[2], buf[3]); - return false; - } - - ReadProtocolString(fd, error, error); - return false; -} - -static int _adb_connect(std::string_view service, TransportId* transport, std::string* error, - bool force_switch = false) { - LOG(DEBUG) << "_adb_connect: " << service; - if (service.empty() || service.size() > MAX_PAYLOAD) { - *error = android::base::StringPrintf("bad service name length (%zd)", service.size()); - return -1; - } - - std::string reason; - unique_fd fd; - if (!socket_spec_connect(&fd, __adb_server_socket_spec, nullptr, nullptr, &reason)) { - *error = android::base::StringPrintf("cannot connect to daemon at %s: %s", - __adb_server_socket_spec, reason.c_str()); - return -2; - } - - if (!service.starts_with("host") || force_switch) { - std::optional transport_result = switch_socket_transport(fd.get(), error); - if (!transport_result) { - return -1; - } - - if (transport) { - *transport = *transport_result; - } - } - - if (!SendProtocolString(fd.get(), service)) { - *error = perror_str("write failure during connection"); - return -1; - } - - if (!adb_status(fd.get(), error)) { - return -1; - } - - D("_adb_connect: return fd %d", fd.get()); - return fd.release(); -} - -bool adb_kill_server() { - D("adb_kill_server"); - std::string reason; - unique_fd fd; - if (!socket_spec_connect(&fd, __adb_server_socket_spec, nullptr, nullptr, &reason)) { - fprintf(stderr, "cannot connect to daemon at %s: %s\n", __adb_server_socket_spec, - reason.c_str()); - return true; - } - - if (!SendProtocolString(fd.get(), "host:kill")) { - fprintf(stderr, "error: write failure during connection: %s\n", strerror(errno)); - return false; - } - - // The server might send OKAY, so consume that. - char buf[4]; - ReadFdExactly(fd.get(), buf, 4); - // Now that no more data is expected, wait for socket orderly shutdown or error, indicating - // server death. - ReadOrderlyShutdown(fd.get()); - return true; -} - -int adb_connect(std::string_view service, std::string* error) { - return adb_connect(nullptr, service, error); -} - -#if defined(__linux__) -std::optional adb_get_server_executable_path() { - int port; - std::string error; - if (!parse_tcp_socket_spec(__adb_server_socket_spec, nullptr, &port, nullptr, &error)) { - return {}; - } - - return adb_get_android_dir_path() + OS_PATH_SEPARATOR + "adb." + std::to_string(port); -} -#endif - -static bool __adb_check_server_version(std::string* error) { - unique_fd fd(_adb_connect("host:version", nullptr, error)); - - bool local = is_local_socket_spec(__adb_server_socket_spec); - if (fd == -2 && !local) { - fprintf(stderr, "* cannot start server on remote host\n"); - // error is the original network connection error - return false; - } else if (fd == -2) { - fprintf(stderr, "* daemon not running; starting now at %s\n", __adb_server_socket_spec); - start_server: - if (launch_server(__adb_server_socket_spec)) { - fprintf(stderr, "* failed to start daemon\n"); - // launch_server() has already printed detailed error info, so just - // return a generic error string about the overall adb_connect() - // that the caller requested. - *error = "cannot connect to daemon"; - return false; - } else { - fprintf(stderr, "* daemon started successfully\n"); - } - // The server will wait until it detects all of its connected devices before acking. - // Fall through to _adb_connect. - } else { - // If a server is already running, check its version matches. - int version = 0; - - // If we have a file descriptor, then parse version result. - if (fd >= 0) { - std::string version_string; - if (!ReadProtocolString(fd, &version_string, error)) { - return false; - } - - ReadOrderlyShutdown(fd); - - if (sscanf(&version_string[0], "%04x", &version) != 1) { - *error = android::base::StringPrintf("cannot parse version string: %s", - version_string.c_str()); - return false; - } - } else { - // If fd is -1 check for "unknown host service" which would - // indicate a version of adb that does not support the - // version command, in which case we should fall-through to kill it. - if (*error != "unknown host service") { - return false; - } - } - - if (version != ADB_SERVER_VERSION) { -#if defined(__linux__) - if (version > ADB_SERVER_VERSION && local) { - // Try to re-exec the existing adb server's binary. - constexpr const char* adb_reexeced = "adb (re-execed)"; - if (strcmp(adb_reexeced, *__adb_argv) != 0) { - __adb_argv[0] = adb_reexeced; - std::optional server_path_path = adb_get_server_executable_path(); - std::string server_path; - if (server_path_path && - android::base::ReadFileToString(*server_path_path, &server_path)) { - if (execve(server_path.c_str(), const_cast(__adb_argv), - const_cast(__adb_envp)) == -1) { - LOG(ERROR) << "failed to exec newer version at " << server_path; - } - - // Fall-through to restarting the server. - } - } - } -#endif - - fprintf(stderr, "adb server version (%d) doesn't match this client (%d); killing...\n", - version, ADB_SERVER_VERSION); - adb_kill_server(); - goto start_server; - } - } - - return true; -} - -bool adb_check_server_version(std::string* error) { - // Only check the version once per process, since this isn't atomic anyway. - static std::once_flag once; - static bool result; - static std::string* err; - std::call_once(once, []() { - err = new std::string(); - result = __adb_check_server_version(err); - }); - *error = *err; - return result; -} - -int adb_connect(TransportId* transport, std::string_view service, std::string* error, - bool force_switch_device) { - LOG(DEBUG) << "adb_connect: service: " << service; - - // Query the adb server's version. - if (!adb_check_server_version(error)) { - return -1; - } - - // if the command is start-server, we are done. - if (service == "host:start-server") { - return 0; - } - - unique_fd fd(_adb_connect(service, transport, error, force_switch_device)); - if (fd == -1) { - D("_adb_connect error: %s", error->c_str()); - } else if(fd == -2) { - fprintf(stderr, "* daemon still not running\n"); - } - D("adb_connect: return fd %d", fd.get()); - - return fd.release(); -} - -bool adb_command(const std::string& service) { - std::string error; - unique_fd fd(adb_connect(service, &error)); - if (fd < 0) { - fprintf(stderr, "error: %s\n", error.c_str()); - return false; - } - - if (!adb_status(fd.get(), &error)) { - fprintf(stderr, "error: %s\n", error.c_str()); - return false; - } - - ReadOrderlyShutdown(fd.get()); - return true; -} - -bool adb_query(const std::string& service, std::string* result, std::string* error) { - D("adb_query: %s", service.c_str()); - unique_fd fd(adb_connect(service, error)); - if (fd < 0) { - return false; - } - - result->clear(); - if (!ReadProtocolString(fd.get(), result, error)) { - return false; - } - - ReadOrderlyShutdown(fd.get()); - return true; -} - -std::string format_host_command(const char* command) { - if (__adb_transport_id) { - return android::base::StringPrintf("host-transport-id:%" PRIu64 ":%s", __adb_transport_id, - command); - } else if (__adb_serial) { - return android::base::StringPrintf("host-serial:%s:%s", __adb_serial, command); - } - - const char* prefix = "host"; - if (__adb_transport == kTransportUsb) { - prefix = "host-usb"; - } else if (__adb_transport == kTransportLocal) { - prefix = "host-local"; - } - return android::base::StringPrintf("%s:%s", prefix, command); -} - -bool adb_get_feature_set(FeatureSet* feature_set, std::string* error) { - static FeatureSet* features = nullptr; - if (!features) { - std::string result; - if (adb_query(format_host_command("features"), &result, error)) { - features = new FeatureSet(StringToFeatureSet(result)); - } - } - if (features) { - *feature_set = *features; - return true; - } - feature_set->clear(); - return false; -} diff --git a/adb/client/adb_client.h b/adb/client/adb_client.h deleted file mode 100644 index 1c6cde77dc25d161c0a20a9f149e331f880a72ca..0000000000000000000000000000000000000000 --- a/adb/client/adb_client.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -#pragma once - -#include -#include -#include - -#include "adb.h" -#include "adb_unique_fd.h" -#include "sysdeps.h" -#include "transport.h" - -// Explicitly check the adb server version. -// All of the commands below do this implicitly. -// Only the first invocation of this function will check the server version. -bool adb_check_server_version(std::string* _Nonnull error); - -// 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(std::string_view service, std::string* _Nonnull error); - -// Same as above, except returning the TransportId for the service that we've connected to. -// force_switch_device forces the function to attempt to select a device, even if the service -// string appears to be a host: service (for use with host services that are device specific, like -// forward). -int adb_connect(TransportId* _Nullable id, std::string_view service, std::string* _Nonnull error, - bool force_switch_device = false); - -// Kill the currently running adb server, if it exists. -bool adb_kill_server(); - -// Connect to adb, connect to the named service, returns true if the connection -// succeeded AND the service returned OKAY. Outputs any returned error otherwise. -bool adb_command(const std::string& service); - -// Connects to the named adb service and fills 'result' with the response. -// Returns true on success; returns false and fills 'error' on failure. -bool adb_query(const std::string& service, std::string* _Nonnull result, - std::string* _Nonnull error); - -// Set the preferred transport to connect to. -void adb_set_transport(TransportType type, const char* _Nullable serial, TransportId transport_id); -void adb_get_transport(TransportType* _Nullable type, const char* _Nullable* _Nullable serial, - TransportId* _Nullable transport_id); - -// Set the socket specification for the adb server. -// This function can only be called once, and the argument must live to the end of the process. -void adb_set_socket_spec(const char* _Nonnull socket_spec); - -// Send commands to the current emulator instance. Will fail if there is not -// exactly one emulator connected (or if you use -s with a -// that does not designate an emulator). -int adb_send_emulator_command(int argc, const char* _Nonnull* _Nonnull argv, - const char* _Nullable serial); - -// Reads a standard adb status response (OKAY|FAIL) and returns true in the -// event of OKAY, false in the event of FAIL or protocol error. -bool adb_status(borrowed_fd fd, std::string* _Nonnull error); - -// Create a host command corresponding to selected transport type/serial. -std::string format_host_command(const char* _Nonnull command); - -// Get the feature set of the current preferred transport. -bool adb_get_feature_set(FeatureSet* _Nonnull feature_set, std::string* _Nonnull error); - -#if defined(__linux__) -// Get the path of a file containing the path to the server executable, if the socket spec set via -// adb_set_socket_spec is a local one. -std::optional adb_get_server_executable_path(); -#endif - -// Globally acccesible argv/envp, for the purpose of re-execing adb. -extern const char* _Nullable * _Nullable __adb_argv; -extern const char* _Nullable * _Nullable __adb_envp; - -// ADB Secure DNS service interface. Used to query what ADB Secure DNS services have been -// resolved, and to run some kind of callback for each one. -using adb_secure_foreach_service_callback = std::function; - -// Queries pairing/connect services that have been discovered and resolved. -// If |host_name| is not null, run |cb| only for services -// matching |host_name|. Otherwise, run for all services. -void adb_secure_foreach_pairing_service(const char* _Nullable service_name, - adb_secure_foreach_service_callback cb); -void adb_secure_foreach_connect_service(const char* _Nullable service_name, - adb_secure_foreach_service_callback cb); -// Tries to connect to a |service_name| if found. Returns true if found and -// connected, false otherwise. -bool adb_secure_connect_by_service_name(const char* _Nonnull service_name); diff --git a/adb/client/adb_install.cpp b/adb/client/adb_install.cpp deleted file mode 100644 index f2de0d23da27a65ef81a3b20d62d3d71aa8fd90a..0000000000000000000000000000000000000000 --- a/adb/client/adb_install.cpp +++ /dev/null @@ -1,995 +0,0 @@ -/* - * Copyright (C) 2018 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 "adb_install.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "adb.h" -#include "adb_client.h" -#include "adb_unique_fd.h" -#include "adb_utils.h" -#include "client/file_sync_client.h" -#include "commandline.h" -#include "fastdeploy.h" -#include "incremental.h" - -using namespace std::literals; - -static constexpr int kFastDeployMinApi = 24; - -namespace { - -enum InstallMode { - INSTALL_DEFAULT, - INSTALL_PUSH, - INSTALL_STREAM, - INSTALL_INCREMENTAL, -}; - -enum class CmdlineOption { None, Enable, Disable }; -} - -static bool can_use_feature(const char* feature) { - FeatureSet features; - std::string error; - if (!adb_get_feature_set(&features, &error)) { - fprintf(stderr, "error: %s\n", error.c_str()); - return false; - } - return CanUseFeature(features, feature); -} - -static InstallMode best_install_mode() { - if (can_use_feature(kFeatureCmd)) { - return INSTALL_STREAM; - } - return INSTALL_PUSH; -} - -static bool is_apex_supported() { - return can_use_feature(kFeatureApex); -} - -static bool is_abb_exec_supported() { - return can_use_feature(kFeatureAbbExec); -} - -static int pm_command(int argc, const char** argv) { - std::string cmd = "pm"; - - while (argc-- > 0) { - cmd += " " + escape_arg(*argv++); - } - - return send_shell_command(cmd); -} - -static int uninstall_app_streamed(int argc, const char** argv) { - // 'adb uninstall' takes the same arguments as 'cmd package uninstall' on device - std::string cmd = "cmd package"; - while (argc-- > 0) { - // deny the '-k' option until the remaining data/cache can be removed with adb/UI - if (strcmp(*argv, "-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 cmd package " - "uninstall -k'.\n"); - return EXIT_FAILURE; - } - cmd += " " + escape_arg(*argv++); - } - - return send_shell_command(cmd); -} - -static int uninstall_app_legacy(int argc, const 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) */ - for (int i = 1; i < argc; i++) { - if (!strcmp(argv[i], "-k")) { - 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'\n."); - return EXIT_FAILURE; - } - } - - /* 'adb uninstall' takes the same arguments as 'pm uninstall' on device */ - return pm_command(argc, argv); -} - -int uninstall_app(int argc, const char** argv) { - if (best_install_mode() == INSTALL_PUSH) { - return uninstall_app_legacy(argc, argv); - } - return uninstall_app_streamed(argc, argv); -} - -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; - } - - buf += len; - count -= len; - } - *buf = '\0'; -} - -static unique_fd send_command(const std::vector& cmd_args, std::string* error) { - if (is_abb_exec_supported()) { - return send_abb_exec_command(cmd_args, error); - } else { - return unique_fd(adb_connect(android::base::Join(cmd_args, " "), error)); - } -} - -static int install_app_streamed(int argc, const char** argv, bool use_fastdeploy) { - printf("Performing Streamed Install\n"); - - // The last argument must be the APK file - const char* file = argv[argc - 1]; - if (!android::base::EndsWithIgnoreCase(file, ".apk") && - !android::base::EndsWithIgnoreCase(file, ".apex")) { - error_exit("filename doesn't end .apk or .apex: %s", file); - } - - bool is_apex = false; - if (android::base::EndsWithIgnoreCase(file, ".apex")) { - is_apex = true; - } - if (is_apex && !is_apex_supported()) { - error_exit(".apex is not supported on the target device"); - } - - if (is_apex && use_fastdeploy) { - error_exit("--fastdeploy doesn't support .apex files"); - } - - if (use_fastdeploy) { - auto metadata = extract_metadata(file); - if (metadata.has_value()) { - // pass all but 1st (command) and last (apk path) parameters through to pm for - // session creation - std::vector pm_args{argv + 1, argv + argc - 1}; - auto patchFd = install_patch(pm_args.size(), pm_args.data()); - return stream_patch(file, std::move(metadata.value()), std::move(patchFd)); - } - } - - struct stat sb; - if (stat(file, &sb) == -1) { - fprintf(stderr, "adb: failed to stat %s: %s\n", file, strerror(errno)); - return 1; - } - - unique_fd local_fd(adb_open(file, O_RDONLY | O_CLOEXEC)); - if (local_fd < 0) { - fprintf(stderr, "adb: failed to open %s: %s\n", file, strerror(errno)); - return 1; - } - -#ifdef __linux__ - posix_fadvise(local_fd.get(), 0, 0, POSIX_FADV_SEQUENTIAL | POSIX_FADV_NOREUSE); -#endif - - const bool use_abb_exec = is_abb_exec_supported(); - std::string error; - std::vector cmd_args = {use_abb_exec ? "package" : "exec:cmd package"}; - cmd_args.reserve(argc + 3); - - // don't copy the APK name, but, copy the rest of the arguments as-is - while (argc-- > 1) { - if (use_abb_exec) { - cmd_args.push_back(*argv++); - } else { - cmd_args.push_back(escape_arg(*argv++)); - } - } - - // add size parameter [required for streaming installs] - // do last to override any user specified value - cmd_args.push_back("-S"); - cmd_args.push_back(android::base::StringPrintf("%" PRIu64, static_cast(sb.st_size))); - - if (is_apex) { - cmd_args.push_back("--apex"); - } - - unique_fd remote_fd = send_command(cmd_args, &error); - if (remote_fd < 0) { - fprintf(stderr, "adb: connect error for write: %s\n", error.c_str()); - return 1; - } - - if (!copy_to_file(local_fd.get(), remote_fd.get())) { - fprintf(stderr, "adb: failed to install: copy_to_file: %s: %s", file, strerror(errno)); - return 1; - } - - char buf[BUFSIZ]; - read_status_line(remote_fd.get(), buf, sizeof(buf)); - if (strncmp("Success", buf, 7) != 0) { - fprintf(stderr, "adb: failed to install %s: %s", file, buf); - return 1; - } - - fputs(buf, stdout); - return 0; -} - -static int install_app_legacy(int argc, const char** argv, bool use_fastdeploy) { - printf("Performing Push Install\n"); - - // Find last APK argument. - // All other arguments passed through verbatim. - int last_apk = -1; - for (int i = argc - 1; i >= 0; i--) { - if (android::base::EndsWithIgnoreCase(argv[i], ".apex")) { - error_exit("APEX packages are only compatible with Streamed Install"); - } - if (android::base::EndsWithIgnoreCase(argv[i], ".apk")) { - last_apk = i; - break; - } - } - - if (last_apk == -1) error_exit("need APK file on command line"); - - int result = -1; - std::vector apk_file = {argv[last_apk]}; - std::string apk_dest = "/data/local/tmp/" + android::base::Basename(argv[last_apk]); - argv[last_apk] = apk_dest.c_str(); /* destination name, not source location */ - - if (use_fastdeploy) { - auto metadata = extract_metadata(apk_file[0]); - if (metadata.has_value()) { - auto patchFd = apply_patch_on_device(apk_dest.c_str()); - int status = stream_patch(apk_file[0], std::move(metadata.value()), std::move(patchFd)); - - result = pm_command(argc, argv); - delete_device_file(apk_dest); - - return status; - } - } - - if (do_sync_push(apk_file, apk_dest.c_str(), false, true)) { - result = pm_command(argc, argv); - delete_device_file(apk_dest); - } - - return result; -} - -template -static int ms_between(TimePoint start, TimePoint end) { - return std::chrono::duration_cast(end - start).count(); -} - -static int install_app_incremental(int argc, const char** argv, bool wait, bool silent) { - using clock = std::chrono::high_resolution_clock; - const auto start = clock::now(); - int first_apk = -1; - int last_apk = -1; - incremental::Args passthrough_args = {}; - for (int i = 0; i < argc; ++i) { - const auto arg = std::string_view(argv[i]); - if (android::base::EndsWithIgnoreCase(arg, ".apk"sv)) { - last_apk = i; - if (first_apk == -1) { - first_apk = i; - } - } else if (arg.starts_with("install"sv)) { - // incremental installation command on the device is the same for all its variations in - // the adb, e.g. install-multiple or install-multi-package - } else { - passthrough_args.push_back(arg); - } - } - - if (first_apk == -1) { - if (!silent) { - fprintf(stderr, "error: need at least one APK file on command line\n"); - } - return -1; - } - - auto files = incremental::Files{argv + first_apk, argv + last_apk + 1}; - if (silent) { - // For a silent installation we want to do the lightweight check first and bail early and - // quietly if it fails. - if (!incremental::can_install(files)) { - return -1; - } - } - - printf("Performing Incremental Install\n"); - auto server_process = incremental::install(files, passthrough_args, silent); - if (!server_process) { - return -1; - } - - const auto end = clock::now(); - printf("Install command complete in %d ms\n", ms_between(start, end)); - - if (wait) { - (*server_process).wait(); - } - - return 0; -} - -static std::pair> calculate_install_mode( - InstallMode modeFromArgs, bool fastdeploy, CmdlineOption incremental_request) { - if (incremental_request == CmdlineOption::Enable) { - if (fastdeploy) { - error_exit( - "--incremental and --fast-deploy options are incompatible. " - "Please choose one"); - } - } - - if (modeFromArgs != INSTALL_DEFAULT) { - if (incremental_request == CmdlineOption::Enable) { - error_exit("--incremental is not compatible with other installation modes"); - } - return {modeFromArgs, std::nullopt}; - } - - if (incremental_request != CmdlineOption::Disable && !is_abb_exec_supported()) { - if (incremental_request == CmdlineOption::None) { - incremental_request = CmdlineOption::Disable; - } else { - error_exit("Device doesn't support incremental installations"); - } - } - if (incremental_request == CmdlineOption::None) { - // check if the host is ok with incremental by default - if (const char* incrementalFromEnv = getenv("ADB_INSTALL_DEFAULT_INCREMENTAL")) { - using namespace android::base; - auto val = ParseBool(incrementalFromEnv); - if (val == ParseBoolResult::kFalse) { - incremental_request = CmdlineOption::Disable; - } - } - } - if (incremental_request == CmdlineOption::None) { - // still ok: let's see if the device allows using incremental by default - // it starts feeling like we're looking for an excuse to not to use incremental... - std::string error; - std::vector args = {"settings", "get", - "enable_adb_incremental_install_default"}; - auto fd = send_abb_exec_command(args, &error); - if (!fd.ok()) { - fprintf(stderr, "adb: retrieving the default device installation mode failed: %s", - error.c_str()); - } else { - char buf[BUFSIZ] = {}; - read_status_line(fd.get(), buf, sizeof(buf)); - using namespace android::base; - auto val = ParseBool(buf); - if (val == ParseBoolResult::kFalse) { - incremental_request = CmdlineOption::Disable; - } - } - } - - if (incremental_request == CmdlineOption::Enable) { - // explicitly requested - no fallback - return {INSTALL_INCREMENTAL, std::nullopt}; - } - const auto bestMode = best_install_mode(); - if (incremental_request == CmdlineOption::None) { - // no opinion - use incremental, fallback to regular on a failure. - return {INSTALL_INCREMENTAL, bestMode}; - } - // incremental turned off - use the regular best mode without a fallback. - return {bestMode, std::nullopt}; -} - -static std::vector parse_install_mode(std::vector argv, - InstallMode* install_mode, - CmdlineOption* incremental_request, - bool* incremental_wait) { - *install_mode = INSTALL_DEFAULT; - *incremental_request = CmdlineOption::None; - *incremental_wait = false; - - std::vector passthrough; - for (auto&& arg : argv) { - if (arg == "--streaming"sv) { - *install_mode = INSTALL_STREAM; - } else if (arg == "--no-streaming"sv) { - *install_mode = INSTALL_PUSH; - } else if (strlen(arg) >= "--incr"sv.size() && "--incremental"sv.starts_with(arg)) { - *incremental_request = CmdlineOption::Enable; - } else if (strlen(arg) >= "--no-incr"sv.size() && "--no-incremental"sv.starts_with(arg)) { - *incremental_request = CmdlineOption::Disable; - } else if (arg == "--wait"sv) { - *incremental_wait = true; - } else { - passthrough.push_back(arg); - } - } - return passthrough; -} - -static std::vector parse_fast_deploy_mode( - std::vector argv, bool* use_fastdeploy, - FastDeploy_AgentUpdateStrategy* agent_update_strategy) { - *use_fastdeploy = false; - *agent_update_strategy = FastDeploy_AgentUpdateDifferentVersion; - - std::vector passthrough; - for (auto&& arg : argv) { - if (arg == "--fastdeploy"sv) { - *use_fastdeploy = true; - } else if (arg == "--no-fastdeploy"sv) { - *use_fastdeploy = false; - } else if (arg == "--force-agent"sv) { - *agent_update_strategy = FastDeploy_AgentUpdateAlways; - } else if (arg == "--date-check-agent"sv) { - *agent_update_strategy = FastDeploy_AgentUpdateNewerTimeStamp; - } else if (arg == "--version-check-agent"sv) { - *agent_update_strategy = FastDeploy_AgentUpdateDifferentVersion; - } else { - passthrough.push_back(arg); - } - } - return passthrough; -} - -int install_app(int argc, const char** argv) { - InstallMode install_mode = INSTALL_DEFAULT; - auto incremental_request = CmdlineOption::None; - bool incremental_wait = false; - - bool use_fastdeploy = false; - FastDeploy_AgentUpdateStrategy agent_update_strategy = FastDeploy_AgentUpdateDifferentVersion; - - auto unused_argv = parse_install_mode({argv, argv + argc}, &install_mode, &incremental_request, - &incremental_wait); - auto passthrough_argv = - parse_fast_deploy_mode(std::move(unused_argv), &use_fastdeploy, &agent_update_strategy); - - auto [primary_mode, fallback_mode] = - calculate_install_mode(install_mode, use_fastdeploy, incremental_request); - if ((primary_mode == INSTALL_STREAM || - fallback_mode.value_or(INSTALL_PUSH) == INSTALL_STREAM) && - best_install_mode() == INSTALL_PUSH) { - error_exit("Attempting to use streaming install on unsupported device"); - } - - if (use_fastdeploy && get_device_api_level() < kFastDeployMinApi) { - fprintf(stderr, - "Fast Deploy is only compatible with devices of API version %d or higher, " - "ignoring.\n", - kFastDeployMinApi); - use_fastdeploy = false; - } - fastdeploy_set_agent_update_strategy(agent_update_strategy); - - if (passthrough_argv.size() < 2) { - error_exit("install requires an apk argument"); - } - - auto run_install_mode = [&](InstallMode install_mode, bool silent) { - switch (install_mode) { - case INSTALL_PUSH: - return install_app_legacy(passthrough_argv.size(), passthrough_argv.data(), - use_fastdeploy); - case INSTALL_STREAM: - return install_app_streamed(passthrough_argv.size(), passthrough_argv.data(), - use_fastdeploy); - case INSTALL_INCREMENTAL: - return install_app_incremental(passthrough_argv.size(), passthrough_argv.data(), - incremental_wait, silent); - case INSTALL_DEFAULT: - default: - error_exit("invalid install mode"); - } - }; - auto res = run_install_mode(primary_mode, fallback_mode.has_value()); - if (res && fallback_mode.value_or(primary_mode) != primary_mode) { - res = run_install_mode(*fallback_mode, false); - } - return res; -} - -static int install_multiple_app_streamed(int argc, const char** argv) { - // Find all APK arguments starting at end. - // All other arguments passed through verbatim. - int first_apk = -1; - uint64_t total_size = 0; - for (int i = argc - 1; i >= 0; i--) { - const char* file = argv[i]; - if (android::base::EndsWithIgnoreCase(argv[i], ".apex")) { - error_exit("APEX packages are not compatible with install-multiple"); - } - - if (android::base::EndsWithIgnoreCase(file, ".apk") || - android::base::EndsWithIgnoreCase(file, ".dm") || - android::base::EndsWithIgnoreCase(file, ".fsv_sig")) { - struct stat sb; - if (stat(file, &sb) == -1) perror_exit("failed to stat \"%s\"", file); - total_size += sb.st_size; - first_apk = i; - } else { - break; - } - } - - if (first_apk == -1) error_exit("need APK file on command line"); - - const bool use_abb_exec = is_abb_exec_supported(); - const std::string install_cmd = - use_abb_exec ? "package" - : best_install_mode() == INSTALL_PUSH ? "exec:pm" : "exec:cmd package"; - - std::vector cmd_args = {install_cmd, "install-create", "-S", - std::to_string(total_size)}; - cmd_args.reserve(first_apk + 4); - for (int i = 1; i < first_apk; i++) { - if (use_abb_exec) { - cmd_args.push_back(argv[i]); - } else { - cmd_args.push_back(escape_arg(argv[i])); - } - } - - // Create install session - std::string error; - char buf[BUFSIZ]; - { - unique_fd fd = send_command(cmd_args, &error); - if (fd < 0) { - fprintf(stderr, "adb: connect error for create: %s\n", error.c_str()); - return EXIT_FAILURE; - } - read_status_line(fd.get(), buf, sizeof(buf)); - } - - 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, nullptr, 10); - } - } - if (session_id < 0) { - fprintf(stderr, "adb: failed to create session\n"); - fputs(buf, stderr); - return EXIT_FAILURE; - } - const auto session_id_str = std::to_string(session_id); - - // Valid session, now stream the APKs - bool success = true; - for (int i = first_apk; i < argc; i++) { - const char* file = argv[i]; - struct stat sb; - if (stat(file, &sb) == -1) { - fprintf(stderr, "adb: failed to stat \"%s\": %s\n", file, strerror(errno)); - success = false; - goto finalize_session; - } - - std::vector cmd_args = { - install_cmd, - "install-write", - "-S", - std::to_string(sb.st_size), - session_id_str, - android::base::Basename(file), - "-", - }; - - unique_fd local_fd(adb_open(file, O_RDONLY | O_CLOEXEC)); - if (local_fd < 0) { - fprintf(stderr, "adb: failed to open \"%s\": %s\n", file, strerror(errno)); - success = false; - goto finalize_session; - } - - std::string error; - unique_fd remote_fd = send_command(cmd_args, &error); - if (remote_fd < 0) { - fprintf(stderr, "adb: connect error for write: %s\n", error.c_str()); - success = false; - goto finalize_session; - } - - if (!copy_to_file(local_fd.get(), remote_fd.get())) { - fprintf(stderr, "adb: failed to write \"%s\": %s\n", file, strerror(errno)); - success = false; - goto finalize_session; - } - - read_status_line(remote_fd.get(), buf, sizeof(buf)); - - if (strncmp("Success", buf, 7)) { - fprintf(stderr, "adb: failed to write \"%s\"\n", file); - fputs(buf, stderr); - success = false; - goto finalize_session; - } - } - -finalize_session: - // Commit session if we streamed everything okay; otherwise abandon. - std::vector service_args = { - install_cmd, - success ? "install-commit" : "install-abandon", - session_id_str, - }; - { - unique_fd fd = send_command(service_args, &error); - if (fd < 0) { - fprintf(stderr, "adb: connect error for finalize: %s\n", error.c_str()); - return EXIT_FAILURE; - } - read_status_line(fd.get(), buf, sizeof(buf)); - } - if (!success) return EXIT_FAILURE; - - if (strncmp("Success", buf, 7)) { - fprintf(stderr, "adb: failed to finalize session\n"); - fputs(buf, stderr); - return EXIT_FAILURE; - } - - fputs(buf, stdout); - return EXIT_SUCCESS; -} - -int install_multiple_app(int argc, const char** argv) { - InstallMode install_mode = INSTALL_DEFAULT; - auto incremental_request = CmdlineOption::None; - bool incremental_wait = false; - bool use_fastdeploy = false; - - auto passthrough_argv = parse_install_mode({argv + 1, argv + argc}, &install_mode, - &incremental_request, &incremental_wait); - - auto [primary_mode, fallback_mode] = - calculate_install_mode(install_mode, use_fastdeploy, incremental_request); - if ((primary_mode == INSTALL_STREAM || - fallback_mode.value_or(INSTALL_PUSH) == INSTALL_STREAM) && - best_install_mode() == INSTALL_PUSH) { - error_exit("Attempting to use streaming install on unsupported device"); - } - - auto run_install_mode = [&](InstallMode install_mode, bool silent) { - switch (install_mode) { - case INSTALL_PUSH: - case INSTALL_STREAM: - return install_multiple_app_streamed(passthrough_argv.size(), - passthrough_argv.data()); - case INSTALL_INCREMENTAL: - return install_app_incremental(passthrough_argv.size(), passthrough_argv.data(), - incremental_wait, silent); - case INSTALL_DEFAULT: - default: - error_exit("invalid install mode"); - } - }; - auto res = run_install_mode(primary_mode, fallback_mode.has_value()); - if (res && fallback_mode.value_or(primary_mode) != primary_mode) { - res = run_install_mode(*fallback_mode, false); - } - return res; -} - -int install_multi_package(int argc, const char** argv) { - // Find all APK arguments starting at end. - // All other arguments passed through verbatim. - bool apex_found = false; - int first_package = -1; - for (int i = argc - 1; i >= 0; i--) { - const char* file = argv[i]; - if (android::base::EndsWithIgnoreCase(file, ".apk") || - android::base::EndsWithIgnoreCase(file, ".apex")) { - first_package = i; - if (android::base::EndsWithIgnoreCase(file, ".apex")) { - apex_found = true; - } - } else { - break; - } - } - - if (first_package == -1) error_exit("need APK or APEX files on command line"); - - if (best_install_mode() == INSTALL_PUSH) { - fprintf(stderr, "adb: multi-package install is not supported on this device\n"); - return EXIT_FAILURE; - } - - const bool use_abb_exec = is_abb_exec_supported(); - const std::string install_cmd = use_abb_exec ? "package" : "exec:cmd package"; - - std::vector multi_package_cmd_args = {install_cmd, "install-create", - "--multi-package"}; - - multi_package_cmd_args.reserve(first_package + 4); - for (int i = 1; i < first_package; i++) { - if (use_abb_exec) { - multi_package_cmd_args.push_back(argv[i]); - } else { - multi_package_cmd_args.push_back(escape_arg(argv[i])); - } - } - - if (apex_found) { - multi_package_cmd_args.emplace_back("--staged"); - } - - // Create multi-package install session - std::string error; - char buf[BUFSIZ]; - { - unique_fd fd = send_command(multi_package_cmd_args, &error); - if (fd < 0) { - fprintf(stderr, "adb: connect error for create multi-package: %s\n", error.c_str()); - return EXIT_FAILURE; - } - read_status_line(fd.get(), buf, sizeof(buf)); - } - - int parent_session_id = -1; - if (!strncmp("Success", buf, 7)) { - char* start = strrchr(buf, '['); - char* end = strrchr(buf, ']'); - if (start && end) { - *end = '\0'; - parent_session_id = strtol(start + 1, nullptr, 10); - } - } - if (parent_session_id < 0) { - fprintf(stderr, "adb: failed to create multi-package session\n"); - fputs(buf, stderr); - return EXIT_FAILURE; - } - const auto parent_session_id_str = std::to_string(parent_session_id); - - fprintf(stdout, "Created parent session ID %d.\n", parent_session_id); - - std::vector session_ids; - - // Valid session, now create the individual sessions and stream the APKs - int success = EXIT_FAILURE; - std::vector individual_cmd_args = {install_cmd, "install-create"}; - for (int i = 1; i < first_package; i++) { - if (use_abb_exec) { - individual_cmd_args.push_back(argv[i]); - } else { - individual_cmd_args.push_back(escape_arg(argv[i])); - } - } - if (apex_found) { - individual_cmd_args.emplace_back("--staged"); - } - - std::vector individual_apex_cmd_args; - if (apex_found) { - individual_apex_cmd_args = individual_cmd_args; - individual_apex_cmd_args.emplace_back("--apex"); - } - - std::vector add_session_cmd_args = { - install_cmd, - "install-add-session", - parent_session_id_str, - }; - - for (int i = first_package; i < argc; i++) { - const char* file = argv[i]; - char buf[BUFSIZ]; - { - unique_fd fd; - // Create individual install session - if (android::base::EndsWithIgnoreCase(file, ".apex")) { - fd = send_command(individual_apex_cmd_args, &error); - } else { - fd = send_command(individual_cmd_args, &error); - } - if (fd < 0) { - fprintf(stderr, "adb: connect error for create: %s\n", error.c_str()); - goto finalize_multi_package_session; - } - read_status_line(fd.get(), buf, sizeof(buf)); - } - - 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, nullptr, 10); - } - } - if (session_id < 0) { - fprintf(stderr, "adb: failed to create multi-package session\n"); - fputs(buf, stderr); - goto finalize_multi_package_session; - } - const auto session_id_str = std::to_string(session_id); - - fprintf(stdout, "Created child session ID %d.\n", session_id); - session_ids.push_back(session_id); - - // Support splitAPKs by allowing the notation split1.apk:split2.apk:split3.apk as argument. - std::vector splits = android::base::Split(file, ":"); - - for (const std::string& split : splits) { - struct stat sb; - if (stat(split.c_str(), &sb) == -1) { - fprintf(stderr, "adb: failed to stat %s: %s\n", split.c_str(), strerror(errno)); - goto finalize_multi_package_session; - } - - std::vector cmd_args = { - install_cmd, - "install-write", - "-S", - std::to_string(sb.st_size), - session_id_str, - android::base::StringPrintf("%d_%s", i, android::base::Basename(file).c_str()), - "-", - }; - - unique_fd local_fd(adb_open(split.c_str(), O_RDONLY | O_CLOEXEC)); - if (local_fd < 0) { - fprintf(stderr, "adb: failed to open %s: %s\n", split.c_str(), strerror(errno)); - goto finalize_multi_package_session; - } - - std::string error; - unique_fd remote_fd = send_command(cmd_args, &error); - if (remote_fd < 0) { - fprintf(stderr, "adb: connect error for write: %s\n", error.c_str()); - goto finalize_multi_package_session; - } - - if (!copy_to_file(local_fd.get(), remote_fd.get())) { - fprintf(stderr, "adb: failed to write %s: %s\n", split.c_str(), strerror(errno)); - goto finalize_multi_package_session; - } - - read_status_line(remote_fd.get(), buf, sizeof(buf)); - - if (strncmp("Success", buf, 7)) { - fprintf(stderr, "adb: failed to write %s\n", split.c_str()); - fputs(buf, stderr); - goto finalize_multi_package_session; - } - } - add_session_cmd_args.push_back(std::to_string(session_id)); - } - - { - unique_fd fd = send_command(add_session_cmd_args, &error); - if (fd < 0) { - fprintf(stderr, "adb: connect error for install-add-session: %s\n", error.c_str()); - goto finalize_multi_package_session; - } - read_status_line(fd.get(), buf, sizeof(buf)); - } - - if (strncmp("Success", buf, 7)) { - fprintf(stderr, "adb: failed to link sessions (%s)\n", - android::base::Join(add_session_cmd_args, " ").c_str()); - fputs(buf, stderr); - goto finalize_multi_package_session; - } - - // no failures means we can proceed with the assumption of success - success = 0; - -finalize_multi_package_session: - // Commit session if we streamed everything okay; otherwise abandon - std::vector service_args = { - install_cmd, - success == 0 ? "install-commit" : "install-abandon", - parent_session_id_str, - }; - - { - unique_fd fd = send_command(service_args, &error); - if (fd < 0) { - fprintf(stderr, "adb: connect error for finalize: %s\n", error.c_str()); - return EXIT_FAILURE; - } - read_status_line(fd.get(), buf, sizeof(buf)); - } - - if (!strncmp("Success", buf, 7)) { - fputs(buf, stdout); - if (success == 0) { - return 0; - } - } else { - fprintf(stderr, "adb: failed to finalize session\n"); - fputs(buf, stderr); - } - - session_ids.push_back(parent_session_id); - // try to abandon all remaining sessions - for (std::size_t i = 0; i < session_ids.size(); i++) { - std::vector service_args = { - install_cmd, - "install-abandon", - std::to_string(session_ids[i]), - }; - fprintf(stderr, "Attempting to abandon session ID %d\n", session_ids[i]); - unique_fd fd = send_command(service_args, &error); - if (fd < 0) { - fprintf(stderr, "adb: connect error for finalize: %s\n", error.c_str()); - continue; - } - read_status_line(fd.get(), buf, sizeof(buf)); - } - return EXIT_FAILURE; -} - -int delete_device_file(const std::string& filename) { - // http://b/17339227 "Sideloading a Readonly File Results in a Prompt to - // Delete" caused us to add `-f` here, to avoid the equivalent of the `-i` - // prompt that you get from BSD rm (used in Android 5) if you have a - // non-writable file and stdin is a tty (which is true for old versions of - // adbd). - // - // Unfortunately, `rm -f` requires Android 4.3, so that workaround broke - // earlier Android releases. This was reported as http://b/37704384 "adb - // install -r passes invalid argument to rm on Android 4.1" and - // http://b/37035817 "ADB Fails: rm failed for -f, No such file or - // directory". - // - // Testing on a variety of devices and emulators shows that redirecting - // stdin is sufficient to avoid the pseudo-`-i`, and works on toolbox, - // BSD, and toybox versions of rm. - return send_shell_command("rm " + escape_arg(filename) + " - -int install_app(int argc, const char** argv); -int install_multiple_app(int argc, const char** argv); -int install_multi_package(int argc, const char** argv); -int uninstall_app(int argc, const char** argv); - -int delete_device_file(const std::string& filename); -int delete_host_file(const std::string& filename); - diff --git a/adb/client/adb_wifi.cpp b/adb/client/adb_wifi.cpp deleted file mode 100644 index fa71028115bea85b32db3e01051d012388c6ee6b..0000000000000000000000000000000000000000 --- a/adb/client/adb_wifi.cpp +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright (C) 2019 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 "adb_wifi.h" - -#include -#include -#include - -#include -#include -#include -#include -#include "client/pairing/pairing_client.h" - -#include "adb_auth.h" -#include "adb_known_hosts.pb.h" -#include "adb_utils.h" -#include "client/adb_client.h" -#include "sysdeps.h" - -using adbwifi::pairing::PairingClient; -using namespace adb::crypto; - -struct PairingResultWaiter { - std::mutex mutex_; - std::condition_variable cv_; - std::optional is_valid_; - PeerInfo peer_info_; - - static void OnResult(const PeerInfo* peer_info, void* opaque) { - CHECK(opaque); - auto* p = reinterpret_cast(opaque); - { - std::lock_guard lock(p->mutex_); - if (peer_info) { - memcpy(&(p->peer_info_), peer_info, sizeof(PeerInfo)); - } - p->is_valid_ = (peer_info != nullptr); - } - p->cv_.notify_one(); - } -}; // PairingResultWaiter - -void adb_wifi_init() {} - -static std::vector stringToUint8(const std::string& str) { - auto* p8 = reinterpret_cast(str.data()); - return std::vector(p8, p8 + str.length()); -} - -// Tries to replace the |old_file| with |new_file|. -// On success, then |old_file| has been removed and replaced with the -// contents of |new_file|, |new_file| will be removed, and only |old_file| will -// remain. -// On failure, both files will be unchanged. -// |new_file| must exist, but |old_file| does not need to exist. -bool SafeReplaceFile(std::string_view old_file, std::string_view new_file) { - std::string to_be_deleted(old_file); - to_be_deleted += ".tbd"; - - bool old_renamed = true; - if (adb_rename(old_file.data(), to_be_deleted.c_str()) != 0) { - // Don't exit here. This is not necessarily an error, because |old_file| - // may not exist. - PLOG(INFO) << "Failed to rename " << old_file; - old_renamed = false; - } - - if (adb_rename(new_file.data(), old_file.data()) != 0) { - PLOG(ERROR) << "Unable to rename file (" << new_file << " => " << old_file << ")"; - if (old_renamed) { - // Rename the .tbd file back to it's original name - adb_rename(to_be_deleted.c_str(), old_file.data()); - } - return false; - } - - adb_unlink(to_be_deleted.c_str()); - return true; -} - -static std::string get_user_known_hosts_path() { - return adb_get_android_dir_path() + OS_PATH_SEPARATOR + "adb_known_hosts.pb"; -} - -bool load_known_hosts_from_file(const std::string& path, adb::proto::AdbKnownHosts& known_hosts) { - // Check for file existence. - struct stat buf; - if (stat(path.c_str(), &buf) == -1) { - LOG(INFO) << "Known hosts file [" << path << "] does not exist..."; - return false; - } - - std::ifstream file(path, std::ios::binary); - if (!file) { - PLOG(ERROR) << "Unable to open [" << path << "]."; - return false; - } - - if (!known_hosts.ParseFromIstream(&file)) { - PLOG(ERROR) << "Failed to parse [" << path << "]. Deleting it as it may be corrupted."; - adb_unlink(path.c_str()); - return false; - } - - return true; -} - -static bool write_known_host_to_file(std::string& known_host) { - std::string path = get_user_known_hosts_path(); - if (path.empty()) { - PLOG(ERROR) << "Error getting user known hosts filename"; - return false; - } - - adb::proto::AdbKnownHosts known_hosts; - load_known_hosts_from_file(path, known_hosts); - auto* host_info = known_hosts.add_host_infos(); - host_info->set_guid(known_host); - - std::unique_ptr temp_file(new TemporaryFile(adb_get_android_dir_path())); - if (temp_file->fd == -1) { - PLOG(ERROR) << "Failed to open [" << temp_file->path << "] for writing"; - return false; - } - - if (!known_hosts.SerializeToFileDescriptor(temp_file->fd)) { - LOG(ERROR) << "Unable to write out adb_knowns_hosts"; - return false; - } - temp_file->DoNotRemove(); - std::string temp_file_name(temp_file->path); - temp_file.reset(); - - // Replace the existing adb_known_hosts with the new one - if (!SafeReplaceFile(path, temp_file_name.c_str())) { - LOG(ERROR) << "Failed to replace old adb_known_hosts"; - adb_unlink(temp_file_name.c_str()); - return false; - } - chmod(path.c_str(), S_IRUSR | S_IWUSR | S_IRGRP); - - return true; -} - -bool adb_wifi_is_known_host(const std::string& host) { - std::string path = get_user_known_hosts_path(); - if (path.empty()) { - PLOG(ERROR) << "Error getting user known hosts filename"; - return false; - } - - adb::proto::AdbKnownHosts known_hosts; - if (!load_known_hosts_from_file(path, known_hosts)) { - return false; - } - - for (const auto& host_info : known_hosts.host_infos()) { - if (host == host_info.guid()) { - return true; - } - } - return false; -} - -void adb_wifi_pair_device(const std::string& host, const std::string& password, - std::string& response) { - // Check the address for a valid address and port. - std::string parsed_host; - std::string err; - int port = -1; - if (!android::base::ParseNetAddress(host, &parsed_host, &port, nullptr, &err)) { - response = "Failed to parse address for pairing: " + err; - return; - } - if (port <= 0 || port > 65535) { - response = "Invalid port while parsing address [" + host + "]"; - return; - } - - auto priv_key = adb_auth_get_user_privkey(); - auto x509_cert = GenerateX509Certificate(priv_key.get()); - if (!x509_cert) { - LOG(ERROR) << "Unable to create X509 certificate for pairing"; - return; - } - auto cert_str = X509ToPEMString(x509_cert.get()); - auto priv_str = Key::ToPEMString(priv_key.get()); - - // Send our public key on pairing success - PeerInfo system_info = {}; - system_info.type = ADB_RSA_PUB_KEY; - std::string public_key = adb_auth_get_userkey(); - CHECK_LE(public_key.size(), sizeof(system_info.data) - 1); // -1 for null byte - memcpy(system_info.data, public_key.data(), public_key.size()); - - auto pswd8 = stringToUint8(password); - auto cert8 = stringToUint8(cert_str); - auto priv8 = stringToUint8(priv_str); - - auto client = PairingClient::Create(pswd8, system_info, cert8, priv8); - if (client == nullptr) { - response = "Failed: unable to create pairing client."; - return; - } - - PairingResultWaiter waiter; - std::unique_lock lock(waiter.mutex_); - if (!client->Start(host, waiter.OnResult, &waiter)) { - response = "Failed: Unable to start pairing client."; - return; - } - waiter.cv_.wait(lock, [&]() { return waiter.is_valid_.has_value(); }); - if (!*(waiter.is_valid_)) { - response = "Failed: Wrong password or connection was dropped."; - return; - } - - if (waiter.peer_info_.type != ADB_DEVICE_GUID) { - response = "Failed: Successfully paired but server returned unknown response="; - response += waiter.peer_info_.type; - return; - } - - std::string device_guid = reinterpret_cast(waiter.peer_info_.data); - response = "Successfully paired to " + host + " [guid=" + device_guid + "]"; - - // Write to adb_known_hosts - write_known_host_to_file(device_guid); - // Try to auto-connect. - adb_secure_connect_by_service_name(device_guid.c_str()); -} diff --git a/adb/client/auth.cpp b/adb/client/auth.cpp deleted file mode 100644 index 35264c76f02e8c0a667fa5b8d42669a85270de82..0000000000000000000000000000000000000000 --- a/adb/client/auth.cpp +++ /dev/null @@ -1,557 +0,0 @@ -/* - * 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. - */ - -#define TRACE_TAG AUTH - -#include -#include -#include -#include -#if defined(__linux__) -#include -#endif - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "adb.h" -#include "adb_auth.h" -#include "adb_io.h" -#include "adb_utils.h" -#include "sysdeps.h" -#include "transport.h" - -static std::mutex& g_keys_mutex = *new std::mutex; -static std::map>& g_keys = - *new std::map>; -static std::map& g_monitored_paths = *new std::map; - -using namespace adb::crypto; -using namespace adb::tls; - -static bool generate_key(const std::string& file) { - LOG(INFO) << "generate_key(" << file << ")..."; - - auto rsa_2048 = CreateRSA2048Key(); - if (!rsa_2048) { - LOG(ERROR) << "Unable to create key"; - return false; - } - std::string pubkey; - - RSA* rsa = EVP_PKEY_get0_RSA(rsa_2048->GetEvpPkey()); - CHECK(rsa); - - if (!CalculatePublicKey(&pubkey, rsa)) { - LOG(ERROR) << "failed to calculate public key"; - return false; - } - - mode_t old_mask = umask(077); - - std::unique_ptr f(nullptr, &fclose); - f.reset(fopen(file.c_str(), "w")); - if (!f) { - PLOG(ERROR) << "Failed to open " << file; - umask(old_mask); - return false; - } - - umask(old_mask); - - if (!PEM_write_PrivateKey(f.get(), rsa_2048->GetEvpPkey(), nullptr, nullptr, 0, nullptr, - nullptr)) { - LOG(ERROR) << "Failed to write key"; - return false; - } - - if (!android::base::WriteStringToFile(pubkey, file + ".pub")) { - PLOG(ERROR) << "failed to write public key"; - return false; - } - - return true; -} - -static std::string hash_key(RSA* key) { - unsigned char* pubkey = nullptr; - int len = i2d_RSA_PUBKEY(key, &pubkey); - if (len < 0) { - LOG(ERROR) << "failed to encode RSA public key"; - return std::string(); - } - - std::string result; - result.resize(SHA256_DIGEST_LENGTH); - SHA256(pubkey, len, reinterpret_cast(&result[0])); - OPENSSL_free(pubkey); - return result; -} - -static std::shared_ptr read_key_file(const std::string& file) { - std::unique_ptr fp(fopen(file.c_str(), "r"), fclose); - if (!fp) { - PLOG(ERROR) << "Failed to open '" << file << "'"; - return nullptr; - } - - RSA* key = RSA_new(); - if (!PEM_read_RSAPrivateKey(fp.get(), &key, nullptr, nullptr)) { - LOG(ERROR) << "Failed to read key from '" << file << "'"; - ERR_print_errors_fp(stderr); - RSA_free(key); - return nullptr; - } - - return std::shared_ptr(key, RSA_free); -} - -static bool load_key(const std::string& file) { - std::shared_ptr key = read_key_file(file); - if (!key) { - return false; - } - - std::lock_guard lock(g_keys_mutex); - std::string fingerprint = hash_key(key.get()); - if (g_keys.find(fingerprint) != g_keys.end()) { - LOG(INFO) << "ignoring already-loaded key: " << file; - } else { - LOG(INFO) << "Loaded fingerprint=[" << SHA256BitsToHexString(fingerprint) << "]"; - g_keys[fingerprint] = std::move(key); - } - return true; -} - -static bool load_keys(const std::string& path, bool allow_dir = true) { - LOG(INFO) << "load_keys '" << path << "'..."; - - struct stat st; - if (stat(path.c_str(), &st) != 0) { - PLOG(ERROR) << "failed to stat '" << path << "'"; - return false; - } - - if (S_ISREG(st.st_mode)) { - return load_key(path); - } else if (S_ISDIR(st.st_mode)) { - if (!allow_dir) { - // inotify isn't recursive. It would break expectations to load keys in nested - // directories but not monitor them for new keys. - LOG(WARNING) << "refusing to recurse into directory '" << path << "'"; - return false; - } - - std::unique_ptr dir(opendir(path.c_str()), closedir); - if (!dir) { - PLOG(ERROR) << "failed to open directory '" << path << "'"; - return false; - } - - bool result = false; - while (struct dirent* dent = readdir(dir.get())) { - std::string name = dent->d_name; - - // We can't use dent->d_type here because it's not available on Windows. - if (name == "." || name == "..") { - continue; - } - - if (!android::base::EndsWith(name, ".adb_key")) { - LOG(INFO) << "skipping non-adb_key '" << path << "/" << name << "'"; - continue; - } - - result |= load_key((path + OS_PATH_SEPARATOR + name)); - } - return result; - } - - LOG(ERROR) << "unexpected type for '" << path << "': 0x" << std::hex << st.st_mode; - return false; -} - -static std::string get_user_key_path() { - return adb_get_android_dir_path() + OS_PATH_SEPARATOR + "adbkey"; -} - -static bool load_userkey() { - std::string path = get_user_key_path(); - if (path.empty()) { - PLOG(ERROR) << "Error getting user key filename"; - return false; - } - - struct stat buf; - if (stat(path.c_str(), &buf) == -1) { - LOG(INFO) << "User key '" << path << "' does not exist..."; - if (!generate_key(path)) { - LOG(ERROR) << "Failed to generate new key"; - return false; - } - } - - return load_key(path); -} - -static std::set get_vendor_keys() { - const char* adb_keys_path = getenv("ADB_VENDOR_KEYS"); - if (adb_keys_path == nullptr) { - return std::set(); - } - - std::set result; - for (const auto& path : android::base::Split(adb_keys_path, ENV_PATH_SEPARATOR_STR)) { - result.emplace(path); - } - return result; -} - -std::deque> adb_auth_get_private_keys() { - std::deque> result; - - // Copy all the currently known keys. - std::lock_guard lock(g_keys_mutex); - for (const auto& it : g_keys) { - result.push_back(it.second); - } - - // Add a sentinel to the list. Our caller uses this to mean "out of private keys, - // but try using the public key" (the empty deque could otherwise mean this _or_ - // that this function hasn't been called yet to request the keys). - result.push_back(nullptr); - - return result; -} - -static std::string adb_auth_sign(RSA* key, const char* token, size_t token_size) { - if (token_size != TOKEN_SIZE) { - D("Unexpected token size %zd", token_size); - return nullptr; - } - - std::string result; - result.resize(MAX_PAYLOAD); - - unsigned int len; - if (!RSA_sign(NID_sha1, reinterpret_cast(token), token_size, - reinterpret_cast(&result[0]), &len, key)) { - return std::string(); - } - - result.resize(len); - - D("adb_auth_sign len=%d", len); - return result; -} - -static bool pubkey_from_privkey(std::string* out, const std::string& path) { - std::shared_ptr privkey = read_key_file(path); - if (!privkey) { - return false; - } - return CalculatePublicKey(out, privkey.get()); -} - -bssl::UniquePtr adb_auth_get_user_privkey() { - std::string path = get_user_key_path(); - if (path.empty()) { - PLOG(ERROR) << "Error getting user key filename"; - return nullptr; - } - - std::shared_ptr rsa_privkey = read_key_file(path); - if (!rsa_privkey) { - return nullptr; - } - - bssl::UniquePtr pkey(EVP_PKEY_new()); - if (!pkey) { - LOG(ERROR) << "Failed to allocate key"; - return nullptr; - } - - EVP_PKEY_set1_RSA(pkey.get(), rsa_privkey.get()); - return pkey; -} - -std::string adb_auth_get_userkey() { - std::string path = get_user_key_path(); - if (path.empty()) { - PLOG(ERROR) << "Error getting user key filename"; - return ""; - } - - std::string result; - if (!pubkey_from_privkey(&result, path)) { - return ""; - } - return result; -} - -int adb_auth_keygen(const char* filename) { - return !generate_key(filename); -} - -int adb_auth_pubkey(const char* filename) { - std::string pubkey; - if (!pubkey_from_privkey(&pubkey, filename)) { - return 1; - } - pubkey.push_back('\n'); - - return WriteFdExactly(STDOUT_FILENO, pubkey.data(), pubkey.size()) ? 0 : 1; -} - -#if defined(__linux__) -static void adb_auth_inotify_update(int fd, unsigned fd_event, void*) { - LOG(INFO) << "adb_auth_inotify_update called"; - if (!(fd_event & FDE_READ)) { - return; - } - - char buf[sizeof(struct inotify_event) + NAME_MAX + 1]; - while (true) { - ssize_t rc = TEMP_FAILURE_RETRY(unix_read(fd, buf, sizeof(buf))); - if (rc == -1) { - if (errno == EAGAIN) { - LOG(INFO) << "done reading inotify fd"; - break; - } - PLOG(FATAL) << "read of inotify event failed"; - } - - // The read potentially returned multiple events. - char* start = buf; - char* end = buf + rc; - - while (start < end) { - inotify_event* event = reinterpret_cast(start); - auto root_it = g_monitored_paths.find(event->wd); - if (root_it == g_monitored_paths.end()) { - LOG(FATAL) << "observed inotify event for unmonitored path, wd = " << event->wd; - } - - std::string path = root_it->second; - if (event->len > 0) { - path += '/'; - path += event->name; - } - - if (event->mask & (IN_CREATE | IN_MOVED_TO)) { - if (event->mask & IN_ISDIR) { - LOG(INFO) << "ignoring new directory at '" << path << "'"; - } else { - LOG(INFO) << "observed new file at '" << path << "'"; - load_keys(path, false); - } - } else { - LOG(WARNING) << "unmonitored event for " << path << ": 0x" << std::hex - << event->mask; - } - - start += sizeof(struct inotify_event) + event->len; - } - } -} - -static void adb_auth_inotify_init(const std::set& paths) { - LOG(INFO) << "adb_auth_inotify_init..."; - - int infd = inotify_init1(IN_CLOEXEC | IN_NONBLOCK); - if (infd < 0) { - PLOG(ERROR) << "failed to create inotify fd"; - return; - } - - for (const std::string& path : paths) { - int wd = inotify_add_watch(infd, path.c_str(), IN_CREATE | IN_MOVED_TO); - if (wd < 0) { - PLOG(ERROR) << "failed to inotify_add_watch on path '" << path; - continue; - } - - g_monitored_paths[wd] = path; - LOG(INFO) << "watch descriptor " << wd << " registered for " << path; - } - - fdevent* event = fdevent_create(infd, adb_auth_inotify_update, nullptr); - fdevent_add(event, FDE_READ); -} -#endif - -void adb_auth_init() { - LOG(INFO) << "adb_auth_init..."; - - if (!load_userkey()) { - LOG(ERROR) << "Failed to load (or generate) user key"; - return; - } - - const auto& key_paths = get_vendor_keys(); - -#if defined(__linux__) - adb_auth_inotify_init(key_paths); -#endif - - for (const std::string& path : key_paths) { - load_keys(path); - } -} - -static void send_auth_publickey(atransport* t) { - LOG(INFO) << "Calling send_auth_publickey"; - - std::string key = adb_auth_get_userkey(); - if (key.empty()) { - D("Failed to get user public key"); - return; - } - - if (key.size() >= MAX_PAYLOAD_V1) { - D("User public key too large (%zu B)", key.size()); - return; - } - - apacket* p = get_apacket(); - p->msg.command = A_AUTH; - p->msg.arg0 = ADB_AUTH_RSAPUBLICKEY; - - // adbd expects a null-terminated string. - p->payload.assign(key.data(), key.data() + key.size() + 1); - p->msg.data_length = p->payload.size(); - send_packet(p, t); -} - -void send_auth_response(const char* token, size_t token_size, atransport* t) { - std::shared_ptr key = t->NextKey(); - if (key == nullptr) { - // No more private keys to try, send the public key. - t->SetConnectionState(kCsUnauthorized); - t->SetConnectionEstablished(true); - send_auth_publickey(t); - return; - } - - LOG(INFO) << "Calling send_auth_response"; - apacket* p = get_apacket(); - - std::string result = adb_auth_sign(key.get(), token, token_size); - if (result.empty()) { - D("Error signing the token"); - put_apacket(p); - return; - } - - p->msg.command = A_AUTH; - p->msg.arg0 = ADB_AUTH_SIGNATURE; - p->payload.assign(result.begin(), result.end()); - p->msg.data_length = p->payload.size(); - send_packet(p, t); -} - -void adb_auth_tls_handshake(atransport* t) { - std::thread([t]() { - std::shared_ptr key = t->Key(); - if (key == nullptr) { - // Can happen if !auth_required - LOG(INFO) << "t->auth_key not set before handshake"; - key = t->NextKey(); - CHECK(key); - } - - LOG(INFO) << "Attempting to TLS handshake"; - bool success = t->connection()->DoTlsHandshake(key.get()); - if (success) { - LOG(INFO) << "Handshake succeeded. Waiting for CNXN packet..."; - } else { - LOG(INFO) << "Handshake failed. Kicking transport"; - t->Kick(); - } - }).detach(); -} - -// Callback given to SSL_set_cert_cb to select a certificate when server requests -// for a certificate. This is where the server will give us a CA-issuer list, and -// figure out if the server knows any of our public keys. We currently always return -// 1 here to indicate success, since we always try a key here (in the case of no auth). -// See https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_set_cert_cb -// for more details. -int adb_tls_set_certificate(SSL* ssl) { - LOG(INFO) << __func__; - - const STACK_OF(X509_NAME)* ca_list = SSL_get_client_CA_list(ssl); - if (ca_list == nullptr) { - // Either the device doesn't know any keys, or !auth_required. - // So let's just try with the default certificate and see what happens. - LOG(INFO) << "No client CA list. Trying with default certificate."; - return 1; - } - - const size_t num_cas = sk_X509_NAME_num(ca_list); - for (size_t i = 0; i < num_cas; ++i) { - auto* x509_name = sk_X509_NAME_value(ca_list, i); - auto adbFingerprint = ParseEncodedKeyFromCAIssuer(x509_name); - if (!adbFingerprint.has_value()) { - // This could be a real CA issuer. Unfortunately, we don't support - // it ATM. - continue; - } - - LOG(INFO) << "Checking for fingerprint match [" << *adbFingerprint << "]"; - auto encoded_key = SHA256HexStringToBits(*adbFingerprint); - if (!encoded_key.has_value()) { - continue; - } - // Check against our list of encoded keys for a match - std::lock_guard lock(g_keys_mutex); - auto rsa_priv_key = g_keys.find(*encoded_key); - if (rsa_priv_key != g_keys.end()) { - LOG(INFO) << "Got SHA256 match on a key"; - bssl::UniquePtr evp_pkey(EVP_PKEY_new()); - CHECK(EVP_PKEY_set1_RSA(evp_pkey.get(), rsa_priv_key->second.get())); - auto x509 = GenerateX509Certificate(evp_pkey.get()); - auto x509_str = X509ToPEMString(x509.get()); - auto evp_str = Key::ToPEMString(evp_pkey.get()); - TlsConnection::SetCertAndKey(ssl, x509_str, evp_str); - return 1; - } else { - LOG(INFO) << "No match for [" << *adbFingerprint << "]"; - } - } - - // Let's just try with the default certificate anyways, because daemon might - // not require auth, even though it has a list of keys. - return 1; -} diff --git a/adb/client/bugreport.cpp b/adb/client/bugreport.cpp deleted file mode 100644 index 8ca44e8b58a50e5c2166e52742e4bd44c4ffb205..0000000000000000000000000000000000000000 --- a/adb/client/bugreport.cpp +++ /dev/null @@ -1,286 +0,0 @@ -/* - * Copyright (C) 2016 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 ADB - -#include "sysdeps.h" - -#include "bugreport.h" - -#include -#include - -#include -#include - -#include "adb_utils.h" -#include "client/file_sync_client.h" - -static constexpr char BUGZ_BEGIN_PREFIX[] = "BEGIN:"; -static constexpr char BUGZ_PROGRESS_PREFIX[] = "PROGRESS:"; -static constexpr char BUGZ_PROGRESS_SEPARATOR[] = "/"; -static constexpr char BUGZ_OK_PREFIX[] = "OK:"; -static constexpr char BUGZ_FAIL_PREFIX[] = "FAIL:"; - -// Custom callback used to handle the output of zipped bugreports. -class BugreportStandardStreamsCallback : public StandardStreamsCallbackInterface { - public: - BugreportStandardStreamsCallback(const std::string& dest_dir, const std::string& dest_file, - bool show_progress, Bugreport* br) - : br_(br), - src_file_(), - dest_dir_(dest_dir), - dest_file_(dest_file), - line_message_(), - invalid_lines_(), - show_progress_(show_progress), - status_(0), - line_(), - last_progress_percentage_(0) { - SetLineMessage("generating"); - } - - void OnStdout(const char* buffer, int length) { - for (int i = 0; i < length; i++) { - char c = buffer[i]; - if (c == '\n') { - ProcessLine(line_); - line_.clear(); - } else { - line_.append(1, c); - } - } - } - - void OnStderr(const char* buffer, int length) { - OnStream(nullptr, stderr, buffer, length); - } - - int Done(int unused_) { - // Process remaining line, if any. - ProcessLine(line_); - - // Warn about invalid lines, if any. - if (!invalid_lines_.empty()) { - fprintf(stderr, - "WARNING: bugreportz generated %zu line(s) with unknown commands, " - "device might not support zipped bugreports:\n", - invalid_lines_.size()); - for (const auto& line : invalid_lines_) { - fprintf(stderr, "\t%s\n", line.c_str()); - } - fprintf(stderr, - "If the zipped bugreport was not generated, try 'adb bugreport' instead.\n"); - } - - // Pull the generated bug report. - if (status_ == 0) { - if (src_file_.empty()) { - fprintf(stderr, "bugreportz did not return a '%s' or '%s' line\n", BUGZ_OK_PREFIX, - BUGZ_FAIL_PREFIX); - return -1; - } - std::string destination; - if (dest_dir_.empty()) { - destination = dest_file_; - } else { - destination = android::base::StringPrintf("%s%c%s", dest_dir_.c_str(), - OS_PATH_SEPARATOR, dest_file_.c_str()); - } - std::vector srcs{src_file_.c_str()}; - SetLineMessage("pulling"); - status_ = - br_->DoSyncPull(srcs, destination.c_str(), false, line_message_.c_str()) ? 0 : 1; - if (status_ != 0) { - fprintf(stderr, - "Bug report finished but could not be copied to '%s'.\n" - "Try to run 'adb pull %s '\n" - "to copy it to a directory that can be written.\n", - destination.c_str(), src_file_.c_str()); - } - } - return status_; - } - - private: - void SetLineMessage(const std::string& action) { - line_message_ = action + " " + android::base::Basename(dest_file_); - } - - void SetSrcFile(const std::string path) { - src_file_ = path; - if (!dest_dir_.empty()) { - // Only uses device-provided name when user passed a directory. - dest_file_ = android::base::Basename(path); - SetLineMessage("generating"); - } - } - - void ProcessLine(const std::string& line) { - if (line.empty()) return; - - if (android::base::StartsWith(line, BUGZ_BEGIN_PREFIX)) { - SetSrcFile(&line[strlen(BUGZ_BEGIN_PREFIX)]); - } else if (android::base::StartsWith(line, BUGZ_OK_PREFIX)) { - SetSrcFile(&line[strlen(BUGZ_OK_PREFIX)]); - } else if (android::base::StartsWith(line, BUGZ_FAIL_PREFIX)) { - const char* error_message = &line[strlen(BUGZ_FAIL_PREFIX)]; - fprintf(stderr, "adb: device failed to take a zipped bugreport: %s\n", error_message); - status_ = -1; - } else if (show_progress_ && android::base::StartsWith(line, BUGZ_PROGRESS_PREFIX)) { - // progress_line should have the following format: - // - // BUGZ_PROGRESS_PREFIX:PROGRESS/TOTAL - // - size_t idx1 = line.rfind(BUGZ_PROGRESS_PREFIX) + strlen(BUGZ_PROGRESS_PREFIX); - size_t idx2 = line.rfind(BUGZ_PROGRESS_SEPARATOR); - int progress = std::stoi(line.substr(idx1, (idx2 - idx1))); - int total = std::stoi(line.substr(idx2 + 1)); - int progress_percentage = (progress * 100 / total); - if (progress_percentage != 0 && progress_percentage <= last_progress_percentage_) { - // Ignore. - return; - } - last_progress_percentage_ = progress_percentage; - br_->UpdateProgress(line_message_, progress_percentage); - } else { - invalid_lines_.push_back(line); - } - } - - Bugreport* br_; - - // Path of bugreport on device. - std::string src_file_; - - // Bugreport destination on host, depending on argument passed on constructor: - // - if argument is a directory, dest_dir_ is set with it and dest_file_ will be the name - // of the bugreport reported by the device. - // - if argument is empty, dest_dir is set as the current directory and dest_file_ will be the - // name of the bugreport reported by the device. - // - otherwise, dest_dir_ is not set and dest_file_ is set with the value passed on constructor. - std::string dest_dir_, dest_file_; - - // Message displayed on LinePrinter, it's updated every time the destination above change. - std::string line_message_; - - // Lines sent by bugreportz that contain invalid commands; will be displayed at the end. - std::vector invalid_lines_; - - // Whether PROGRESS_LINES should be interpreted as progress. - bool show_progress_; - - // Overall process of the operation, as returned by Done(). - int status_; - - // Temporary buffer containing the characters read since the last newline (\n). - std::string line_; - - // Last displayed progress. - // Since dumpstate progress can recede, only forward progress should be displayed - int last_progress_percentage_; - - DISALLOW_COPY_AND_ASSIGN(BugreportStandardStreamsCallback); -}; - -int Bugreport::DoIt(int argc, const char** argv) { - if (argc > 2) error_exit("usage: adb bugreport [PATH]"); - - // Gets bugreportz version. - std::string bugz_stdout, bugz_stderr; - DefaultStandardStreamsCallback version_callback(&bugz_stdout, &bugz_stderr); - int status = SendShellCommand("bugreportz -v", false, &version_callback); - std::string bugz_version = android::base::Trim(bugz_stderr); - std::string bugz_output = android::base::Trim(bugz_stdout); - - if (status != 0 || bugz_version.empty()) { - D("'bugreportz' -v results: status=%d, stdout='%s', stderr='%s'", status, - bugz_output.c_str(), bugz_version.c_str()); - if (argc == 1) { - // Device does not support bugreportz: if called as 'adb bugreport', just falls out to - // the flat-file version. - fprintf(stderr, - "Failed to get bugreportz version, which is only available on devices " - "running Android 7.0 or later.\nTrying a plain-text bug report instead.\n"); - return SendShellCommand("bugreport", false); - } - - // But if user explicitly asked for a zipped bug report, fails instead (otherwise calling - // 'bugreport' would generate a lot of output the user might not be prepared to handle). - fprintf(stderr, - "Failed to get bugreportz version: 'bugreportz -v' returned '%s' (code %d).\n" - "If the device does not run Android 7.0 or above, try 'adb bugreport' instead.\n", - bugz_output.c_str(), status); - return status != 0 ? status : -1; - } - - std::string dest_file, dest_dir; - - if (argc == 1) { - // No args - use current directory - if (!getcwd(&dest_dir)) { - perror("adb: getcwd failed"); - return 1; - } - } else { - // Check whether argument is a directory or file - if (directory_exists(argv[1])) { - dest_dir = argv[1]; - } else { - dest_file = argv[1]; - } - } - - if (dest_file.empty()) { - // Uses a default value until device provides the proper name - dest_file = "bugreport.zip"; - } else { - if (!android::base::EndsWithIgnoreCase(dest_file, ".zip")) { - dest_file += ".zip"; - } - } - - bool show_progress = true; - std::string bugz_command = "bugreportz -p"; - if (bugz_version == "1.0") { - // 1.0 does not support progress notifications, so print a disclaimer - // message instead. - fprintf(stderr, - "Bugreport is in progress and it could take minutes to complete.\n" - "Please be patient and do not cancel or disconnect your device " - "until it completes.\n"); - show_progress = false; - bugz_command = "bugreportz"; - } - BugreportStandardStreamsCallback bugz_callback(dest_dir, dest_file, show_progress, this); - return SendShellCommand(bugz_command, false, &bugz_callback); -} - -void Bugreport::UpdateProgress(const std::string& message, int progress_percentage) { - line_printer_.Print( - android::base::StringPrintf("[%3d%%] %s", progress_percentage, message.c_str()), - LinePrinter::INFO); -} - -int Bugreport::SendShellCommand(const std::string& command, bool disable_shell_protocol, - StandardStreamsCallbackInterface* callback) { - return send_shell_command(command, disable_shell_protocol, callback); -} - -bool Bugreport::DoSyncPull(const std::vector& srcs, const char* dst, bool copy_attrs, - const char* name) { - return do_sync_pull(srcs, dst, copy_attrs, name); -} diff --git a/adb/client/bugreport.h b/adb/client/bugreport.h deleted file mode 100644 index 413439b749862a062558191fb51a6a8dced55120..0000000000000000000000000000000000000000 --- a/adb/client/bugreport.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2016 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 BUGREPORT_H -#define BUGREPORT_H - -#include - -#include "adb.h" -#include "commandline.h" -#include "line_printer.h" - -class Bugreport { - friend class BugreportStandardStreamsCallback; - - public: - Bugreport() : line_printer_() { - } - int DoIt(int argc, const char** argv); - - protected: - // Functions below are abstractions of external functions so they can be - // mocked on tests. - virtual int SendShellCommand( - const std::string& command, bool disable_shell_protocol, - StandardStreamsCallbackInterface* callback = &DEFAULT_STANDARD_STREAMS_CALLBACK); - - virtual bool DoSyncPull(const std::vector& srcs, const char* dst, bool copy_attrs, - const char* name); - - private: - virtual void UpdateProgress(const std::string& file_name, int progress_percentage); - LinePrinter line_printer_; - DISALLOW_COPY_AND_ASSIGN(Bugreport); -}; - -#endif // BUGREPORT_H diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp deleted file mode 100644 index ad4e21c4d493b7e749508a9de2f2934e3c470831..0000000000000000000000000000000000000000 --- a/adb/client/commandline.cpp +++ /dev/null @@ -1,2066 +0,0 @@ -/* - * 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 ADB - -#include "sysdeps.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#if !defined(_WIN32) -#include -#include -#include -#include -#endif - -#include "adb.h" -#include "adb_auth.h" -#include "adb_client.h" -#include "adb_install.h" -#include "adb_io.h" -#include "adb_unique_fd.h" -#include "adb_utils.h" -#include "bugreport.h" -#include "client/file_sync_client.h" -#include "commandline.h" -#include "fastdeploy.h" -#include "incremental_server.h" -#include "services.h" -#include "shell_protocol.h" -#include "sysdeps/chrono.h" - -extern int gListenAll; - -DefaultStandardStreamsCallback DEFAULT_STANDARD_STREAMS_CALLBACK(nullptr, nullptr); - -static std::string product_file(const std::string& file) { - const char* ANDROID_PRODUCT_OUT = getenv("ANDROID_PRODUCT_OUT"); - if (ANDROID_PRODUCT_OUT == nullptr) { - error_exit("product directory not specified; set $ANDROID_PRODUCT_OUT"); - } - return std::string{ANDROID_PRODUCT_OUT} + OS_PATH_SEPARATOR_STR + file; -} - -static void help() { - fprintf(stdout, "%s\n", adb_version().c_str()); - // clang-format off - fprintf(stdout, - "global options:\n" - " -a listen on all network interfaces, not just localhost\n" - " -d use USB device (error if multiple devices connected)\n" - " -e use TCP/IP device (error if multiple TCP/IP devices available)\n" - " -s SERIAL use device with given serial (overrides $ANDROID_SERIAL)\n" - " -t ID use device with given transport id\n" - " -H name of adb server host [default=localhost]\n" - " -P port of adb server [default=5037]\n" - " -L SOCKET listen on given socket for adb server [default=tcp:localhost:5037]\n" - "\n" - "general commands:\n" - " devices [-l] list connected devices (-l for long output)\n" - " help show this help message\n" - " version show version num\n" - "\n" - "networking:\n" - " connect HOST[:PORT] connect to a device via TCP/IP [default port=5555]\n" - " disconnect [HOST[:PORT]]\n" - " disconnect from given TCP/IP device [default port=5555], or all\n" - " pair HOST[:PORT] pair with a device for secure TCP/IP communication\n" - " forward --list list all forward socket connections\n" - " forward [--no-rebind] LOCAL REMOTE\n" - " forward socket connection using:\n" - " tcp: ( may be \"tcp:0\" to pick any open port)\n" - " localabstract:\n" - " localreserved:\n" - " localfilesystem:\n" - " dev:\n" - " jdwp: (remote only)\n" - " acceptfd: (listen only)\n" - " forward --remove LOCAL remove specific forward socket connection\n" - " forward --remove-all remove all forward socket connections\n" - " ppp TTY [PARAMETER...] run PPP over USB\n" - " reverse --list list all reverse socket connections from device\n" - " reverse [--no-rebind] REMOTE LOCAL\n" - " reverse socket connection using:\n" - " tcp: ( may be \"tcp:0\" to pick any open port)\n" - " localabstract:\n" - " localreserved:\n" - " localfilesystem:\n" - " reverse --remove REMOTE remove specific reverse socket connection\n" - " reverse --remove-all remove all reverse socket connections from device\n" - "\n" - "file transfer:\n" - " push [--sync] [-zZ] LOCAL... REMOTE\n" - " copy local files/directories to device\n" - " --sync: only push files that are newer on the host than the device\n" - " -z: enable compression\n" - " -Z: disable compression\n" - " pull [-azZ] REMOTE... LOCAL\n" - " copy files/dirs from device\n" - " -a: preserve file timestamp and mode\n" - " -z: enable compression\n" - " -Z: disable compression\n" - " sync [-lzZ] [all|data|odm|oem|product|system|system_ext|vendor]\n" - " sync a local build from $ANDROID_PRODUCT_OUT to the device (default all)\n" - " -l: list files that would be copied, but don't copy them\n" - " -z: enable compression\n" - " -Z: disable compression\n" - "\n" - "shell:\n" - " shell [-e ESCAPE] [-n] [-Tt] [-x] [COMMAND...]\n" - " run remote shell command (interactive shell if no command given)\n" - " -e: choose escape character, or \"none\"; default '~'\n" - " -n: don't read from stdin\n" - " -T: disable pty allocation\n" - " -t: allocate a pty if on a tty (-tt: force pty allocation)\n" - " -x: disable remote exit codes and stdout/stderr separation\n" - " emu COMMAND run emulator console command\n" - "\n" - "app installation (see also `adb shell cmd package help`):\n" - " install [-lrtsdg] [--instant] PACKAGE\n" - " push a single package to the device and install it\n" - " install-multiple [-lrtsdpg] [--instant] PACKAGE...\n" - " push multiple APKs to the device for a single package and install them\n" - " install-multi-package [-lrtsdpg] [--instant] PACKAGE...\n" - " push one or more packages to the device and install them atomically\n" - " -r: replace existing application\n" - " -t: allow test packages\n" - " -d: allow version code downgrade (debuggable packages only)\n" - " -p: partial application install (install-multiple only)\n" - " -g: grant all runtime permissions\n" - " --abi ABI: override platform's default ABI\n" - " --instant: cause the app to be installed as an ephemeral install app\n" - " --no-streaming: always push APK to device and invoke Package Manager as separate steps\n" - " --streaming: force streaming APK directly into Package Manager\n" - " --fastdeploy: use fast deploy\n" - " --no-fastdeploy: prevent use of fast deploy\n" - " --force-agent: force update of deployment agent when using fast deploy\n" - " --date-check-agent: update deployment agent when local version is newer and using fast deploy\n" - " --version-check-agent: update deployment agent when local version has different version code and using fast deploy\n" -#ifndef _WIN32 - " --local-agent: locate agent files from local source build (instead of SDK location)\n" -#endif - " (See also `adb shell pm help` for more options.)\n" - //TODO--installlog - " uninstall [-k] PACKAGE\n" - " remove this app package from the device\n" - " '-k': keep the data and cache directories\n" - "\n" - "debugging:\n" - " bugreport [PATH]\n" - " write bugreport to given PATH [default=bugreport.zip];\n" - " if PATH is a directory, the bug report is saved in that directory.\n" - " devices that don't support zipped bug reports output to stdout.\n" - " jdwp list pids of processes hosting a JDWP transport\n" - " logcat show device log (logcat --help for more)\n" - "\n" - "security:\n" - " disable-verity disable dm-verity checking on userdebug builds\n" - " enable-verity re-enable dm-verity checking on userdebug builds\n" - " keygen FILE\n" - " generate adb public/private key; private key stored in FILE,\n" - "\n" - "scripting:\n" - " wait-for[-TRANSPORT]-STATE\n" - " wait for device to be in the given state\n" - " STATE: device, recovery, rescue, sideload, bootloader, or disconnect\n" - " TRANSPORT: usb, local, or any [default=any]\n" - " get-state print offline | bootloader | device\n" - " get-serialno print \n" - " get-devpath print \n" - " remount [-R]\n" - " remount partitions read-write. if a reboot is required, -R will\n" - " will automatically reboot the device.\n" - " reboot [bootloader|recovery|sideload|sideload-auto-reboot]\n" - " reboot the device; defaults to booting system image but\n" - " supports bootloader and recovery too. sideload reboots\n" - " into recovery and automatically starts sideload mode,\n" - " sideload-auto-reboot is the same but reboots after sideloading.\n" - " sideload OTAPACKAGE sideload the given full OTA package\n" - " root restart adbd with root permissions\n" - " unroot restart adbd without root permissions\n" - " usb restart adbd listening on USB\n" - " tcpip PORT restart adbd listening on TCP on PORT\n" - "\n" - "internal debugging:\n" - " start-server ensure that there is a server running\n" - " kill-server kill the server if it is running\n" - " reconnect kick connection from host side to force reconnect\n" - " reconnect device kick connection from device side to force reconnect\n" - " reconnect offline reset offline/unauthorized devices to force reconnect\n" - "\n" - "environment variables:\n" - " $ADB_TRACE\n" - " comma-separated list of debug info to log:\n" - " all,adb,sockets,packets,rwx,usb,sync,sysdeps,transport,jdwp\n" - " $ADB_VENDOR_KEYS colon-separated list of keys (files or directories)\n" - " $ANDROID_SERIAL serial number to connect to (see -s)\n" - " $ANDROID_LOG_TAGS tags to be used by logcat (see logcat --help)\n" - " $ADB_LOCAL_TRANSPORT_MAX_PORT max emulator scan port (default 5585, 16 emus)\n" - ); - // clang-format on -} - -#if defined(_WIN32) - -// Implemented in sysdeps_win32.cpp. -void stdin_raw_init(); -void stdin_raw_restore(); - -#else -static termios g_saved_terminal_state; - -static void stdin_raw_init() { - if (tcgetattr(STDIN_FILENO, &g_saved_terminal_state)) return; - - termios tio; - if (tcgetattr(STDIN_FILENO, &tio)) return; - - cfmakeraw(&tio); - - // No timeout but request at least one character per read. - tio.c_cc[VTIME] = 0; - tio.c_cc[VMIN] = 1; - - tcsetattr(STDIN_FILENO, TCSAFLUSH, &tio); -} - -static void stdin_raw_restore() { - tcsetattr(STDIN_FILENO, TCSAFLUSH, &g_saved_terminal_state); -} -#endif - -int read_and_dump(borrowed_fd fd, bool use_shell_protocol, - StandardStreamsCallbackInterface* callback) { - int exit_code = 0; - if (fd < 0) return exit_code; - - std::unique_ptr protocol; - int length = 0; - - char raw_buffer[BUFSIZ]; - char* buffer_ptr = raw_buffer; - if (use_shell_protocol) { - protocol = std::make_unique(fd); - if (!protocol) { - LOG(ERROR) << "failed to allocate memory for ShellProtocol object"; - return 1; - } - buffer_ptr = protocol->data(); - } - - while (true) { - if (use_shell_protocol) { - if (!protocol->Read()) { - break; - } - length = protocol->data_length(); - switch (protocol->id()) { - case ShellProtocol::kIdStdout: - callback->OnStdout(buffer_ptr, length); - break; - case ShellProtocol::kIdStderr: - callback->OnStderr(buffer_ptr, length); - break; - case ShellProtocol::kIdExit: - // data() returns a char* which doesn't have defined signedness. - // Cast to uint8_t to prevent 255 from being sign extended to INT_MIN, - // which doesn't get truncated on Windows. - exit_code = static_cast(protocol->data()[0]); - continue; - default: - continue; - } - length = protocol->data_length(); - } else { - D("read_and_dump(): pre adb_read(fd=%d)", fd.get()); - length = adb_read(fd, raw_buffer, sizeof(raw_buffer)); - D("read_and_dump(): post adb_read(fd=%d): length=%d", fd.get(), length); - if (length <= 0) { - break; - } - callback->OnStdout(buffer_ptr, length); - } - } - - return callback->Done(exit_code); -} - -static void stdinout_raw_prologue(int inFd, int outFd, int& old_stdin_mode, int& old_stdout_mode) { - if (inFd == STDIN_FILENO) { - stdin_raw_init(); -#ifdef _WIN32 - old_stdin_mode = _setmode(STDIN_FILENO, _O_BINARY); - if (old_stdin_mode == -1) { - PLOG(FATAL) << "could not set stdin to binary"; - } -#endif - } - -#ifdef _WIN32 - if (outFd == STDOUT_FILENO) { - old_stdout_mode = _setmode(STDOUT_FILENO, _O_BINARY); - if (old_stdout_mode == -1) { - PLOG(FATAL) << "could not set stdout to binary"; - } - } -#endif -} - -static void stdinout_raw_epilogue(int inFd, int outFd, int old_stdin_mode, int old_stdout_mode) { - if (inFd == STDIN_FILENO) { - stdin_raw_restore(); -#ifdef _WIN32 - if (_setmode(STDIN_FILENO, old_stdin_mode) == -1) { - PLOG(FATAL) << "could not restore stdin mode"; - } -#endif - } - -#ifdef _WIN32 - if (outFd == STDOUT_FILENO) { - if (_setmode(STDOUT_FILENO, old_stdout_mode) == -1) { - PLOG(FATAL) << "could not restore stdout mode"; - } - } -#endif -} - -bool copy_to_file(int inFd, int outFd) { - bool result = true; - std::vector buf(64 * 1024); - int len; - long total = 0; - int old_stdin_mode = -1; - int old_stdout_mode = -1; - - D("copy_to_file(%d -> %d)", inFd, outFd); - - stdinout_raw_prologue(inFd, outFd, old_stdin_mode, old_stdout_mode); - - while (true) { - if (inFd == STDIN_FILENO) { - len = unix_read(inFd, buf.data(), buf.size()); - } else { - len = adb_read(inFd, buf.data(), buf.size()); - } - if (len == 0) { - D("copy_to_file() : read 0 bytes; exiting"); - break; - } - if (len < 0) { - D("copy_to_file(): read failed: %s", strerror(errno)); - result = false; - break; - } - if (outFd == STDOUT_FILENO) { - fwrite(buf.data(), 1, len, stdout); - fflush(stdout); - } else { - adb_write(outFd, buf.data(), len); - } - total += len; - } - - stdinout_raw_epilogue(inFd, outFd, old_stdin_mode, old_stdout_mode); - - D("copy_to_file() finished with %s after %lu bytes", result ? "success" : "failure", total); - return result; -} - -static void send_window_size_change(int fd, std::unique_ptr& shell) { - // Old devices can't handle window size changes. - if (shell == nullptr) return; - -#if defined(_WIN32) - struct winsize { - unsigned short ws_row; - unsigned short ws_col; - unsigned short ws_xpixel; - unsigned short ws_ypixel; - }; -#endif - - winsize ws; - -#if defined(_WIN32) - // If stdout is redirected to a non-console, we won't be able to get the - // console size, but that makes sense. - const intptr_t intptr_handle = _get_osfhandle(STDOUT_FILENO); - if (intptr_handle == -1) return; - - const HANDLE handle = reinterpret_cast(intptr_handle); - - CONSOLE_SCREEN_BUFFER_INFO info; - memset(&info, 0, sizeof(info)); - if (!GetConsoleScreenBufferInfo(handle, &info)) return; - - memset(&ws, 0, sizeof(ws)); - // The number of visible rows, excluding offscreen scroll-back rows which are in info.dwSize.Y. - ws.ws_row = info.srWindow.Bottom - info.srWindow.Top + 1; - // If the user has disabled "Wrap text output on resize", they can make the screen buffer wider - // than the window, in which case we should use the width of the buffer. - ws.ws_col = info.dwSize.X; -#else - if (ioctl(fd, TIOCGWINSZ, &ws) == -1) return; -#endif - - // Send the new window size as human-readable ASCII for debugging convenience. - size_t l = snprintf(shell->data(), shell->data_capacity(), "%dx%d,%dx%d", - ws.ws_row, ws.ws_col, ws.ws_xpixel, ws.ws_ypixel); - shell->Write(ShellProtocol::kIdWindowSizeChange, l + 1); -} - -// Used to pass multiple values to the stdin read thread. -struct StdinReadArgs { - int stdin_fd, write_fd; - bool raw_stdin; - std::unique_ptr protocol; - char escape_char; -}; - -// Loops to read from stdin and push the data to the given FD. -// The argument should be a pointer to a StdinReadArgs object. This function -// will take ownership of the object and delete it when finished. -static void stdin_read_thread_loop(void* x) { - std::unique_ptr args(reinterpret_cast(x)); - -#if !defined(_WIN32) - // Mask SIGTTIN in case we're in a backgrounded process. - sigset_t sigset; - sigemptyset(&sigset); - sigaddset(&sigset, SIGTTIN); - pthread_sigmask(SIG_BLOCK, &sigset, nullptr); -#endif - -#if defined(_WIN32) - // _get_interesting_input_record_uncached() causes unix_read_interruptible() - // to return -1 with errno == EINTR if the window size changes. -#else - // Unblock SIGWINCH for this thread, so our read(2) below will be - // interrupted if the window size changes. - sigset_t mask; - sigemptyset(&mask); - sigaddset(&mask, SIGWINCH); - pthread_sigmask(SIG_UNBLOCK, &mask, nullptr); -#endif - - // Set up the initial window size. - send_window_size_change(args->stdin_fd, args->protocol); - - char raw_buffer[BUFSIZ]; - char* buffer_ptr = raw_buffer; - size_t buffer_size = sizeof(raw_buffer); - if (args->protocol != nullptr) { - buffer_ptr = args->protocol->data(); - buffer_size = args->protocol->data_capacity(); - } - - // If we need to parse escape sequences, make life easy. - if (args->raw_stdin && args->escape_char != '\0') { - buffer_size = 1; - } - - enum EscapeState { kMidFlow, kStartOfLine, kInEscape }; - EscapeState state = kStartOfLine; - - while (true) { - // Use unix_read_interruptible() rather than adb_read() for stdin. - D("stdin_read_thread_loop(): pre unix_read_interruptible(fdi=%d,...)", args->stdin_fd); - int r = unix_read_interruptible(args->stdin_fd, buffer_ptr, - buffer_size); - if (r == -1 && errno == EINTR) { - send_window_size_change(args->stdin_fd, args->protocol); - continue; - } - D("stdin_read_thread_loop(): post unix_read_interruptible(fdi=%d,...)", args->stdin_fd); - if (r <= 0) { - // Only devices using the shell protocol know to close subprocess - // stdin. For older devices we want to just leave the connection - // open, otherwise an unpredictable amount of return data could - // be lost due to the FD closing before all data has been received. - if (args->protocol) { - args->protocol->Write(ShellProtocol::kIdCloseStdin, 0); - } - break; - } - // If we made stdin raw, check input for escape sequences. In - // this situation signals like Ctrl+C are sent remotely rather than - // interpreted locally so this provides an emergency out if the remote - // process starts ignoring the signal. SSH also does this, see the - // "escape characters" section on the ssh man page for more info. - if (args->raw_stdin && args->escape_char != '\0') { - char ch = buffer_ptr[0]; - if (ch == args->escape_char) { - if (state == kStartOfLine) { - state = kInEscape; - // Swallow the escape character. - continue; - } else { - state = kMidFlow; - } - } else { - if (state == kInEscape) { - if (ch == '.') { - fprintf(stderr,"\r\n[ disconnected ]\r\n"); - stdin_raw_restore(); - exit(0); - } else { - // We swallowed an escape character that wasn't part of - // a valid escape sequence; time to cough it up. - buffer_ptr[0] = args->escape_char; - buffer_ptr[1] = ch; - ++r; - } - } - state = (ch == '\n' || ch == '\r') ? kStartOfLine : kMidFlow; - } - } - if (args->protocol) { - if (!args->protocol->Write(ShellProtocol::kIdStdin, r)) { - break; - } - } else { - if (!WriteFdExactly(args->write_fd, buffer_ptr, r)) { - break; - } - } - } -} - -// Returns a shell service string with the indicated arguments and command. -static std::string ShellServiceString(bool use_shell_protocol, - const std::string& type_arg, - const std::string& command) { - std::vector args; - if (use_shell_protocol) { - args.push_back(kShellServiceArgShellProtocol); - - const char* terminal_type = getenv("TERM"); - if (terminal_type != nullptr) { - args.push_back(std::string("TERM=") + terminal_type); - } - } - if (!type_arg.empty()) { - args.push_back(type_arg); - } - - // Shell service string can look like: shell[,arg1,arg2,...]:[command]. - return android::base::StringPrintf("shell%s%s:%s", - args.empty() ? "" : ",", - android::base::Join(args, ',').c_str(), - command.c_str()); -} - -// Connects to a shell on the device and read/writes data. -// -// Note: currently this function doesn't properly clean up resources; the -// FD connected to the adb server is never closed and the stdin read thread -// may never exit. -// -// On success returns the remote exit code if |use_shell_protocol| is true, -// 0 otherwise. On failure returns 1. -static int RemoteShell(bool use_shell_protocol, const std::string& type_arg, char escape_char, - bool empty_command, const std::string& service_string) { - // Old devices can't handle a service string that's longer than MAX_PAYLOAD_V1. - // Use |use_shell_protocol| to determine whether to allow a command longer than that. - if (service_string.size() > MAX_PAYLOAD_V1 && !use_shell_protocol) { - fprintf(stderr, "error: shell command too long\n"); - return 1; - } - - // Make local stdin raw if the device allocates a PTY, which happens if: - // 1. We are explicitly asking for a PTY shell, or - // 2. We don't specify shell type and are starting an interactive session. - bool raw_stdin = (type_arg == kShellServiceArgPty || (type_arg.empty() && empty_command)); - - std::string error; - int fd = adb_connect(service_string, &error); - if (fd < 0) { - fprintf(stderr,"error: %s\n", error.c_str()); - return 1; - } - - StdinReadArgs* args = new StdinReadArgs; - if (!args) { - LOG(ERROR) << "couldn't allocate StdinReadArgs object"; - return 1; - } - args->stdin_fd = STDIN_FILENO; - args->write_fd = fd; - args->raw_stdin = raw_stdin; - args->escape_char = escape_char; - if (use_shell_protocol) { - args->protocol = std::make_unique(args->write_fd); - } - - if (raw_stdin) stdin_raw_init(); - -#if !defined(_WIN32) - // Ensure our process is notified if the local window size changes. - // We use sigaction(2) to ensure that the SA_RESTART flag is not set, - // because the whole reason we're sending signals is to unblock the read(2)! - // That also means we don't need to do anything in the signal handler: - // the side effect of delivering the signal is all we need. - struct sigaction sa; - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = [](int) {}; - sa.sa_flags = 0; - sigaction(SIGWINCH, &sa, nullptr); - - // Now block SIGWINCH in this thread (the main thread) and all threads spawned - // from it. The stdin read thread will unblock this signal to ensure that it's - // the thread that receives the signal. - sigset_t mask; - sigemptyset(&mask); - sigaddset(&mask, SIGWINCH); - pthread_sigmask(SIG_BLOCK, &mask, nullptr); -#endif - - // TODO: combine read_and_dump with stdin_read_thread to make life simpler? - std::thread(stdin_read_thread_loop, args).detach(); - int exit_code = read_and_dump(fd, use_shell_protocol); - - // TODO: properly exit stdin_read_thread_loop and close |fd|. - - // TODO: we should probably install signal handlers for this. - // TODO: can we use atexit? even on Windows? - if (raw_stdin) stdin_raw_restore(); - - return exit_code; -} - -static int adb_shell(int argc, const char** argv) { - FeatureSet features; - std::string error_message; - if (!adb_get_feature_set(&features, &error_message)) { - fprintf(stderr, "error: %s\n", error_message.c_str()); - return 1; - } - - enum PtyAllocationMode { kPtyAuto, kPtyNo, kPtyYes, kPtyDefinitely }; - - // Defaults. - char escape_char = '~'; // -e - bool use_shell_protocol = CanUseFeature(features, kFeatureShell2); // -x - PtyAllocationMode tty = use_shell_protocol ? kPtyAuto : kPtyDefinitely; // -t/-T - - // Parse shell-specific command-line options. - argv[0] = "adb shell"; // So getopt(3) error messages start "adb shell". -#ifdef _WIN32 - // fixes "adb shell -l" crash on Windows, b/37284906 - __argv = const_cast(argv); -#endif - optind = 1; // argv[0] is always "shell", so set `optind` appropriately. - int opt; - while ((opt = getopt(argc, const_cast(argv), "+e:ntTx")) != -1) { - switch (opt) { - case 'e': - if (!(strlen(optarg) == 1 || strcmp(optarg, "none") == 0)) { - error_exit("-e requires a single-character argument or 'none'"); - } - escape_char = (strcmp(optarg, "none") == 0) ? 0 : optarg[0]; - break; - case 'n': - close_stdin(); - break; - case 'x': - // This option basically asks for historical behavior, so set options that - // correspond to the historical defaults. This is slightly weird in that -Tx - // is fine (because we'll undo the -T) but -xT isn't, but that does seem to - // be our least worst choice... - use_shell_protocol = false; - tty = kPtyDefinitely; - escape_char = '~'; - break; - case 't': - // Like ssh, -t arguments are cumulative so that multiple -t's - // are needed to force a PTY. - tty = (tty >= kPtyYes) ? kPtyDefinitely : kPtyYes; - break; - case 'T': - tty = kPtyNo; - break; - default: - // getopt(3) already printed an error message for us. - return 1; - } - } - - bool is_interactive = (optind == argc); - - std::string shell_type_arg = kShellServiceArgPty; - if (tty == kPtyNo) { - shell_type_arg = kShellServiceArgRaw; - } else if (tty == kPtyAuto) { - // If stdin isn't a TTY, default to a raw shell; this lets - // things like `adb shell < my_script.sh` work as expected. - // Non-interactive shells should also not have a pty. - if (!unix_isatty(STDIN_FILENO) || !is_interactive) { - shell_type_arg = kShellServiceArgRaw; - } - } else if (tty == kPtyYes) { - // A single -t arg isn't enough to override implicit -T. - if (!unix_isatty(STDIN_FILENO)) { - fprintf(stderr, - "Remote PTY will not be allocated because stdin is not a terminal.\n" - "Use multiple -t options to force remote PTY allocation.\n"); - shell_type_arg = kShellServiceArgRaw; - } - } - - D("shell -e 0x%x t=%d use_shell_protocol=%s shell_type_arg=%s\n", - escape_char, tty, - use_shell_protocol ? "true" : "false", - (shell_type_arg == kShellServiceArgPty) ? "pty" : "raw"); - - // Raw mode is only supported when talking to a new device *and* using the shell protocol. - if (!use_shell_protocol) { - if (shell_type_arg != kShellServiceArgPty) { - fprintf(stderr, "error: %s only supports allocating a pty\n", - !CanUseFeature(features, kFeatureShell2) ? "device" : "-x"); - return 1; - } else { - // If we're not using the shell protocol, the type argument must be empty. - shell_type_arg = ""; - } - } - - std::string command; - if (optind < argc) { - // We don't escape here, just like ssh(1). http://b/20564385. - command = android::base::Join(std::vector(argv + optind, argv + argc), ' '); - } - - std::string service_string = ShellServiceString(use_shell_protocol, shell_type_arg, command); - return RemoteShell(use_shell_protocol, shell_type_arg, escape_char, command.empty(), - service_string); -} - -static int adb_abb(int argc, const char** argv) { - FeatureSet features; - std::string error_message; - if (!adb_get_feature_set(&features, &error_message)) { - fprintf(stderr, "error: %s\n", error_message.c_str()); - return 1; - } - - if (!CanUseFeature(features, kFeatureAbb)) { - error_exit("abb is not supported by the device"); - } - - optind = 1; // argv[0] is always "abb", so set `optind` appropriately. - - // Defaults. - constexpr char escape_char = '~'; // -e - constexpr bool use_shell_protocol = true; - constexpr auto shell_type_arg = kShellServiceArgRaw; - constexpr bool empty_command = false; - - std::vector args(argv + optind, argv + argc); - std::string service_string = "abb:" + android::base::Join(args, ABB_ARG_DELIMETER); - - D("abb -e 0x%x [%*.s]\n", escape_char, static_cast(service_string.size()), - service_string.data()); - - return RemoteShell(use_shell_protocol, shell_type_arg, escape_char, empty_command, - service_string); -} - -static int adb_shell_noinput(int argc, const char** argv) { -#if !defined(_WIN32) - unique_fd fd(adb_open("/dev/null", O_RDONLY)); - CHECK_NE(STDIN_FILENO, fd.get()); - dup2(fd.get(), STDIN_FILENO); -#endif - return adb_shell(argc, argv); -} - -static int adb_sideload_legacy(const char* filename, int in_fd, int size) { - std::string error; - unique_fd out_fd(adb_connect(android::base::StringPrintf("sideload:%d", size), &error)); - if (out_fd < 0) { - fprintf(stderr, "adb: pre-KitKat sideload connection failed: %s\n", error.c_str()); - return -1; - } - - int opt = CHUNK_SIZE; - opt = adb_setsockopt(out_fd, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)); - - char buf[CHUNK_SIZE]; - int total = size; - while (size > 0) { - unsigned xfer = (size > CHUNK_SIZE) ? CHUNK_SIZE : size; - if (!ReadFdExactly(in_fd, buf, xfer)) { - fprintf(stderr, "adb: failed to read data from %s: %s\n", filename, strerror(errno)); - return -1; - } - if (!WriteFdExactly(out_fd, buf, xfer)) { - std::string error; - adb_status(out_fd, &error); - fprintf(stderr, "adb: failed to write data: %s\n", error.c_str()); - return -1; - } - size -= xfer; - printf("sending: '%s' %4d%% \r", filename, (int)(100LL - ((100LL * size) / (total)))); - fflush(stdout); - } - printf("\n"); - - if (!adb_status(out_fd, &error)) { - fprintf(stderr, "adb: error response: %s\n", error.c_str()); - return -1; - } - - return 0; -} - -#define SIDELOAD_HOST_BLOCK_SIZE (CHUNK_SIZE) - -// Connects to the sideload / rescue service on the device (served by minadbd) and sends over the -// data in an OTA package. -// -// It uses a simple protocol as follows. -// -// - 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 (e.g. "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" or "FAILFAIL" instead of a block number, we have done all -// the data transfer. -// -static int adb_sideload_install(const char* filename, bool rescue_mode) { - // TODO: use a LinePrinter instead... - struct stat sb; - if (stat(filename, &sb) == -1) { - fprintf(stderr, "adb: failed to stat file %s: %s\n", filename, strerror(errno)); - return -1; - } - unique_fd package_fd(adb_open(filename, O_RDONLY)); - if (package_fd == -1) { - fprintf(stderr, "adb: failed to open file %s: %s\n", filename, strerror(errno)); - return -1; - } - - std::string service = android::base::StringPrintf( - "%s:%" PRId64 ":%d", rescue_mode ? "rescue-install" : "sideload-host", - static_cast(sb.st_size), SIDELOAD_HOST_BLOCK_SIZE); - std::string error; - unique_fd device_fd(adb_connect(service, &error)); - if (device_fd < 0) { - fprintf(stderr, "adb: sideload connection failed: %s\n", error.c_str()); - - if (rescue_mode) { - return -1; - } - - // If this is a small enough package, maybe this is an older device that doesn't - // support sideload-host. Try falling back to the older (<= K) sideload method. - if (sb.st_size > INT_MAX) { - return -1; - } - fprintf(stderr, "adb: trying pre-KitKat sideload method...\n"); - return adb_sideload_legacy(filename, package_fd.get(), static_cast(sb.st_size)); - } - - int opt = SIDELOAD_HOST_BLOCK_SIZE; - adb_setsockopt(device_fd, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)); - - char buf[SIDELOAD_HOST_BLOCK_SIZE]; - - int64_t xfer = 0; - int last_percent = -1; - while (true) { - if (!ReadFdExactly(device_fd, buf, 8)) { - fprintf(stderr, "adb: failed to read command: %s\n", strerror(errno)); - return -1; - } - buf[8] = '\0'; - - if (strcmp(kMinadbdServicesExitSuccess, buf) == 0 || - strcmp(kMinadbdServicesExitFailure, buf) == 0) { - printf("\rTotal xfer: %.2fx%*s\n", - static_cast(xfer) / (sb.st_size ? sb.st_size : 1), - static_cast(strlen(filename) + 10), ""); - if (strcmp(kMinadbdServicesExitFailure, buf) == 0) { - return 1; - } - return 0; - } - - int64_t block = strtoll(buf, nullptr, 10); - int64_t offset = block * SIDELOAD_HOST_BLOCK_SIZE; - if (offset >= static_cast(sb.st_size)) { - fprintf(stderr, - "adb: failed to read block %" PRId64 " at offset %" PRId64 ", past end %" PRId64 - "\n", - block, offset, static_cast(sb.st_size)); - return -1; - } - - size_t to_write = SIDELOAD_HOST_BLOCK_SIZE; - if ((offset + SIDELOAD_HOST_BLOCK_SIZE) > static_cast(sb.st_size)) { - to_write = sb.st_size - offset; - } - - if (adb_lseek(package_fd, offset, SEEK_SET) != offset) { - fprintf(stderr, "adb: failed to seek to package block: %s\n", strerror(errno)); - return -1; - } - if (!ReadFdExactly(package_fd, buf, to_write)) { - fprintf(stderr, "adb: failed to read package block: %s\n", strerror(errno)); - return -1; - } - - if (!WriteFdExactly(device_fd, buf, to_write)) { - adb_status(device_fd, &error); - fprintf(stderr, "adb: failed to write data '%s' *\n", error.c_str()); - return -1; - } - 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 = static_cast(xfer * 47LL / (sb.st_size ? sb.st_size : 1)); - if (percent != last_percent) { - printf("\rserving: '%s' (~%d%%) ", filename, percent); - fflush(stdout); - last_percent = percent; - } - } -} - -static int adb_wipe_devices() { - auto wipe_devices_message_size = strlen(kMinadbdServicesExitSuccess); - std::string error; - unique_fd fd(adb_connect( - android::base::StringPrintf("rescue-wipe:userdata:%zu", wipe_devices_message_size), - &error)); - if (fd < 0) { - fprintf(stderr, "adb: wipe device connection failed: %s\n", error.c_str()); - return 1; - } - - std::string message(wipe_devices_message_size, '\0'); - if (!ReadFdExactly(fd, message.data(), wipe_devices_message_size)) { - fprintf(stderr, "adb: failed to read wipe result: %s\n", strerror(errno)); - return 1; - } - - if (message == kMinadbdServicesExitSuccess) { - return 0; - } - - if (message != kMinadbdServicesExitFailure) { - fprintf(stderr, "adb: got unexpected message from rescue wipe %s\n", message.c_str()); - } - return 1; -} - -/** - * Run ppp in "notty" mode against a resource listed as the first parameter - * eg: - * - * ppp dev:/dev/omap_csmi_tty0 - * - */ -static int ppp(int argc, const char** argv) { -#if defined(_WIN32) - error_exit("adb %s not implemented on Win32", argv[0]); - __builtin_unreachable(); -#else - if (argc < 2) error_exit("usage: adb %s [ppp opts]", argv[0]); - - const char* adb_service_name = argv[1]; - std::string error_message; - int fd = adb_connect(adb_service_name, &error_message); - if (fd < 0) { - error_exit("could not open adb service %s: %s", adb_service_name, error_message.c_str()); - } - - pid_t pid = fork(); - if (pid == -1) { - perror_exit("fork failed"); - } - - if (pid == 0) { - // child side - int i; - - // copy args - const char** 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] = nullptr; - - dup2(fd, STDIN_FILENO); - dup2(fd, STDOUT_FILENO); - adb_close(STDERR_FILENO); - adb_close(fd); - - execvp("pppd", (char* const*)ppp_args); - perror_exit("exec pppd failed"); - } - - // parent side - adb_close(fd); - return 0; -#endif /* !defined(_WIN32) */ -} - -static bool wait_for_device(const char* service, - std::optional timeout = std::nullopt) { - std::vector components = android::base::Split(service, "-"); - if (components.size() < 3 || components.size() > 4) { - fprintf(stderr, "adb: couldn't parse 'wait-for' command: %s\n", service); - return false; - } - - TransportType t; - adb_get_transport(&t, nullptr, nullptr); - - // Was the caller vague about what they'd like us to wait for? - // If so, check they weren't more specific in their choice of transport type. - if (components.size() == 3) { - auto it = components.begin() + 2; - if (t == kTransportUsb) { - components.insert(it, "usb"); - } else if (t == kTransportLocal) { - components.insert(it, "local"); - } else { - components.insert(it, "any"); - } - } else if (components[2] != "any" && components[2] != "local" && components[2] != "usb") { - fprintf(stderr, "adb: unknown type %s; expected 'any', 'local', or 'usb'\n", - components[2].c_str()); - return false; - } - - if (components[3] != "any" && components[3] != "bootloader" && components[3] != "device" && - components[3] != "recovery" && components[3] != "rescue" && components[3] != "sideload" && - components[3] != "disconnect") { - fprintf(stderr, - "adb: unknown state %s; " - "expected 'any', 'bootloader', 'device', 'recovery', 'rescue', 'sideload', or " - "'disconnect'\n", - components[3].c_str()); - return false; - } - - std::string cmd = format_host_command(android::base::Join(components, "-").c_str()); - if (timeout) { - std::thread([timeout]() { - std::this_thread::sleep_for(*timeout); - fprintf(stderr, "timeout expired while waiting for device\n"); - _exit(1); - }).detach(); - } - return adb_command(cmd); -} - -static bool adb_root(const char* command) { - std::string error; - - TransportId transport_id; - unique_fd fd(adb_connect(&transport_id, android::base::StringPrintf("%s:", command), &error)); - if (fd < 0) { - fprintf(stderr, "adb: unable to connect for %s: %s\n", command, error.c_str()); - return false; - } - - // Figure out whether we actually did anything. - char buf[256]; - char* cur = buf; - ssize_t bytes_left = sizeof(buf); - while (bytes_left > 0) { - ssize_t bytes_read = adb_read(fd, cur, bytes_left); - if (bytes_read == 0) { - break; - } else if (bytes_read < 0) { - fprintf(stderr, "adb: error while reading for %s: %s\n", command, strerror(errno)); - return false; - } - cur += bytes_read; - bytes_left -= bytes_read; - } - - if (bytes_left == 0) { - fprintf(stderr, "adb: unexpected output length for %s\n", command); - return false; - } - - fwrite(buf, 1, sizeof(buf) - bytes_left, stdout); - fflush(stdout); - if (cur != buf && strstr(buf, "restarting") == nullptr) { - return true; - } - - // Wait for the device to go away. - TransportType previous_type; - const char* previous_serial; - TransportId previous_id; - adb_get_transport(&previous_type, &previous_serial, &previous_id); - - adb_set_transport(kTransportAny, nullptr, transport_id); - wait_for_device("wait-for-disconnect"); - - // Wait for the device to come back. - // If we were using a specific transport ID, there's nothing we can wait for. - if (previous_id == 0) { - adb_set_transport(previous_type, previous_serial, 0); - wait_for_device("wait-for-device", 6000ms); - } - - return true; -} - -int send_shell_command(const std::string& command, bool disable_shell_protocol, - StandardStreamsCallbackInterface* callback) { - unique_fd fd; - bool use_shell_protocol = false; - - while (true) { - bool attempt_connection = true; - - // Use shell protocol if it's supported and the caller doesn't explicitly - // disable it. - if (!disable_shell_protocol) { - FeatureSet features; - std::string error; - if (adb_get_feature_set(&features, &error)) { - use_shell_protocol = CanUseFeature(features, kFeatureShell2); - } else { - // Device was unreachable. - attempt_connection = false; - } - } - - if (attempt_connection) { - std::string error; - std::string service_string = ShellServiceString(use_shell_protocol, "", command); - - fd.reset(adb_connect(service_string, &error)); - if (fd >= 0) { - break; - } - } - - fprintf(stderr, "- waiting for device -\n"); - if (!wait_for_device("wait-for-device")) { - return 1; - } - } - - return read_and_dump(fd.get(), use_shell_protocol, callback); -} - -static int logcat(int argc, const char** argv) { - char* log_tags = getenv("ANDROID_LOG_TAGS"); - std::string quoted = escape_arg(log_tags == nullptr ? "" : log_tags); - - std::string cmd = "export ANDROID_LOG_TAGS=\"" + quoted + "\"; exec logcat"; - - if (!strcmp(argv[0], "longcat")) { - cmd += " -v long"; - } - - --argc; - ++argv; - while (argc-- > 0) { - cmd += " " + escape_arg(*argv++); - } - - return send_shell_command(cmd); -} - -static void write_zeros(int bytes, borrowed_fd fd) { - int old_stdin_mode = -1; - int old_stdout_mode = -1; - std::vector buf(bytes); - - D("write_zeros(%d) -> %d", bytes, fd.get()); - - stdinout_raw_prologue(-1, fd.get(), old_stdin_mode, old_stdout_mode); - - if (fd == STDOUT_FILENO) { - fwrite(buf.data(), 1, bytes, stdout); - fflush(stdout); - } else { - adb_write(fd, buf.data(), bytes); - } - - stdinout_raw_prologue(-1, fd.get(), old_stdin_mode, old_stdout_mode); - - D("write_zeros() finished"); -} - -static int backup(int argc, const char** argv) { - fprintf(stdout, "WARNING: adb backup is deprecated and may be removed in a future release\n"); - - const char* filename = "backup.ab"; - - /* find, extract, and use any -f argument */ - for (int i = 1; i < argc; i++) { - if (!strcmp("-f", argv[i])) { - if (i == argc - 1) error_exit("backup -f passed with no filename"); - filename = argv[i+1]; - for (int j = i+2; j <= argc; ) { - argv[i++] = argv[j++]; - } - argc -= 2; - argv[argc] = nullptr; - } - } - - // Bare "adb backup" or "adb backup -f filename" are not valid invocations --- - // a list of packages is required. - if (argc < 2) error_exit("backup either needs a list of packages or -all/-shared"); - - adb_unlink(filename); - unique_fd outFd(adb_creat(filename, 0640)); - if (outFd < 0) { - fprintf(stderr, "adb: backup unable to create file '%s': %s\n", filename, strerror(errno)); - return EXIT_FAILURE; - } - - std::string cmd = "backup:"; - --argc; - ++argv; - while (argc-- > 0) { - cmd += " " + escape_arg(*argv++); - } - - D("backup. filename=%s cmd=%s", filename, cmd.c_str()); - std::string error; - unique_fd fd(adb_connect(cmd, &error)); - if (fd < 0) { - fprintf(stderr, "adb: unable to connect for backup: %s\n", error.c_str()); - return EXIT_FAILURE; - } - - fprintf(stdout, "Now unlock your device and confirm the backup operation...\n"); - fflush(stdout); - - copy_to_file(fd.get(), outFd.get()); - return EXIT_SUCCESS; -} - -static int restore(int argc, const char** argv) { - fprintf(stdout, "WARNING: adb restore is deprecated and may be removed in a future release\n"); - - if (argc != 2) error_exit("restore requires an argument"); - - const char* filename = argv[1]; - unique_fd tarFd(adb_open(filename, O_RDONLY)); - if (tarFd < 0) { - fprintf(stderr, "adb: unable to open file %s: %s\n", filename, strerror(errno)); - return -1; - } - - std::string error; - unique_fd fd(adb_connect("restore:", &error)); - if (fd < 0) { - fprintf(stderr, "adb: unable to connect for restore: %s\n", error.c_str()); - return -1; - } - - fprintf(stdout, "Now unlock your device and confirm the restore operation.\n"); - fflush(stdout); - - copy_to_file(tarFd.get(), fd.get()); - - // Provide an in-band EOD marker in case the archive file is malformed - write_zeros(512 * 2, fd); - - // Wait until the other side finishes, or it'll get sent SIGHUP. - copy_to_file(fd.get(), STDOUT_FILENO); - return 0; -} - -static void parse_push_pull_args(const char** arg, int narg, std::vector* srcs, - const char** dst, bool* copy_attrs, bool* sync, bool* compressed) { - *copy_attrs = false; - const char* adb_compression = getenv("ADB_COMPRESSION"); - if (adb_compression && strcmp(adb_compression, "0") == 0) { - *compressed = false; - } - - srcs->clear(); - bool ignore_flags = false; - while (narg > 0) { - if (ignore_flags || *arg[0] != '-') { - srcs->push_back(*arg); - } else { - if (!strcmp(*arg, "-p")) { - // Silently ignore for backwards compatibility. - } else if (!strcmp(*arg, "-a")) { - *copy_attrs = true; - } else if (!strcmp(*arg, "-z")) { - if (compressed != nullptr) { - *compressed = true; - } - } else if (!strcmp(*arg, "-Z")) { - if (compressed != nullptr) { - *compressed = false; - } - } else if (!strcmp(*arg, "--sync")) { - if (sync != nullptr) { - *sync = true; - } - } else if (!strcmp(*arg, "--")) { - ignore_flags = true; - } else { - error_exit("unrecognized option '%s'", *arg); - } - } - ++arg; - --narg; - } - - if (srcs->size() > 1) { - *dst = srcs->back(); - srcs->pop_back(); - } -} - -static int adb_connect_command(const std::string& command, TransportId* transport = nullptr) { - std::string error; - unique_fd fd(adb_connect(transport, command, &error)); - if (fd < 0) { - fprintf(stderr, "error: %s\n", error.c_str()); - return 1; - } - read_and_dump(fd); - return 0; -} - -static int adb_connect_command_bidirectional(const std::string& command) { - std::string error; - unique_fd fd(adb_connect(command, &error)); - if (fd < 0) { - fprintf(stderr, "error: %s\n", error.c_str()); - return 1; - } - - static constexpr auto forward = [](int src, int sink, bool exit_on_end) { - char buf[4096]; - while (true) { - int rc = adb_read(src, buf, sizeof(buf)); - if (rc == 0) { - if (exit_on_end) { - exit(0); - } else { - adb_shutdown(sink, SHUT_WR); - } - return; - } else if (rc < 0) { - perror_exit("read failed"); - } - if (!WriteFdExactly(sink, buf, rc)) { - perror_exit("write failed"); - } - } - }; - - std::thread read(forward, fd.get(), STDOUT_FILENO, true); - std::thread write(forward, STDIN_FILENO, fd.get(), false); - read.join(); - write.join(); - return 0; -} - -static int adb_query_command(const std::string& command) { - std::string result; - std::string error; - if (!adb_query(command, &result, &error)) { - fprintf(stderr, "error: %s\n", error.c_str()); - return 1; - } - printf("%s\n", result.c_str()); - return 0; -} - -// Disallow stdin, stdout, and stderr. -static bool _is_valid_ack_reply_fd(const int ack_reply_fd) { -#ifdef _WIN32 - const HANDLE ack_reply_handle = cast_int_to_handle(ack_reply_fd); - return (GetStdHandle(STD_INPUT_HANDLE) != ack_reply_handle) && - (GetStdHandle(STD_OUTPUT_HANDLE) != ack_reply_handle) && - (GetStdHandle(STD_ERROR_HANDLE) != ack_reply_handle); -#else - return ack_reply_fd > 2; -#endif -} - -static bool _is_valid_os_fd(int fd) { - // Disallow invalid FDs and stdin/out/err as well. - if (fd < 3) { - return false; - } -#ifdef _WIN32 - auto handle = (HANDLE)fd; - DWORD info = 0; - if (GetHandleInformation(handle, &info) == 0) { - return false; - } -#else - int flags = fcntl(fd, F_GETFD); - if (flags == -1) { - return false; - } -#endif - return true; -} - -int adb_commandline(int argc, const char** argv) { - bool no_daemon = false; - bool is_daemon = false; - bool is_server = false; - int r; - TransportType transport_type = kTransportAny; - int ack_reply_fd = -1; - -#if !defined(_WIN32) - // We'd rather have EPIPE than SIGPIPE. - signal(SIGPIPE, SIG_IGN); -#endif - - const char* server_host_str = nullptr; - const char* server_port_str = nullptr; - const char* server_socket_str = nullptr; - - // We need to check for -d and -e before we look at $ANDROID_SERIAL. - const char* serial = nullptr; - TransportId transport_id = 0; - - while (argc > 0) { - if (!strcmp(argv[0], "server")) { - is_server = true; - } else if (!strcmp(argv[0], "nodaemon")) { - no_daemon = true; - } else if (!strcmp(argv[0], "fork-server")) { - /* this is a special flag used only when the ADB client launches the ADB Server */ - is_daemon = true; - } else if (!strcmp(argv[0], "--reply-fd")) { - if (argc < 2) error_exit("--reply-fd requires an argument"); - const char* reply_fd_str = argv[1]; - argc--; - argv++; - ack_reply_fd = strtol(reply_fd_str, nullptr, 10); - if (!_is_valid_ack_reply_fd(ack_reply_fd)) { - fprintf(stderr, "adb: invalid reply fd \"%s\"\n", reply_fd_str); - return 1; - } - } else if (!strncmp(argv[0], "-s", 2)) { - if (isdigit(argv[0][2])) { - serial = argv[0] + 2; - } else { - if (argc < 2 || argv[0][2] != '\0') error_exit("-s requires an argument"); - serial = argv[1]; - argc--; - argv++; - } - } else if (!strncmp(argv[0], "-t", 2)) { - const char* id; - if (isdigit(argv[0][2])) { - id = argv[0] + 2; - } else { - id = argv[1]; - argc--; - argv++; - } - transport_id = strtoll(id, const_cast(&id), 10); - if (*id != '\0') { - error_exit("invalid transport id"); - } - } else if (!strcmp(argv[0], "-d")) { - transport_type = kTransportUsb; - } else if (!strcmp(argv[0], "-e")) { - transport_type = kTransportLocal; - } else if (!strcmp(argv[0], "-a")) { - gListenAll = 1; - } else if (!strncmp(argv[0], "-H", 2)) { - if (argv[0][2] == '\0') { - if (argc < 2) error_exit("-H requires an argument"); - server_host_str = argv[1]; - argc--; - argv++; - } else { - server_host_str = argv[0] + 2; - } - } else if (!strncmp(argv[0], "-P", 2)) { - if (argv[0][2] == '\0') { - if (argc < 2) error_exit("-P requires an argument"); - server_port_str = argv[1]; - argc--; - argv++; - } else { - server_port_str = argv[0] + 2; - } - } else if (!strcmp(argv[0], "-L")) { - if (argc < 2) error_exit("-L requires an argument"); - server_socket_str = argv[1]; - argc--; - argv++; - } else { - /* out of recognized modifiers and flags */ - break; - } - argc--; - argv++; - } - - if ((server_host_str || server_port_str) && server_socket_str) { - error_exit("-L is incompatible with -H or -P"); - } - - // If -L, -H, or -P are specified, ignore environment variables. - // Otherwise, prefer ADB_SERVER_SOCKET over ANDROID_ADB_SERVER_ADDRESS/PORT. - if (!server_host_str && !server_port_str && !server_socket_str) { - server_socket_str = getenv("ADB_SERVER_SOCKET"); - } - - if (!server_socket_str) { - // tcp:1234 and tcp:localhost:1234 are different with -a, so don't default to localhost - server_host_str = server_host_str ? server_host_str : getenv("ANDROID_ADB_SERVER_ADDRESS"); - - int server_port = DEFAULT_ADB_PORT; - server_port_str = server_port_str ? server_port_str : getenv("ANDROID_ADB_SERVER_PORT"); - if (server_port_str && strlen(server_port_str) > 0) { - if (!android::base::ParseInt(server_port_str, &server_port, 1, 65535)) { - error_exit( - "$ANDROID_ADB_SERVER_PORT must be a positive number less than 65535: " - "got \"%s\"", - server_port_str); - } - } - - int rc; - char* temp; - if (server_host_str) { - rc = asprintf(&temp, "tcp:%s:%d", server_host_str, server_port); - } else { - rc = asprintf(&temp, "tcp:%d", server_port); - } - if (rc < 0) { - LOG(FATAL) << "failed to allocate server socket specification"; - } - server_socket_str = temp; - } - - adb_set_socket_spec(server_socket_str); - - // If none of -d, -e, or -s were specified, try $ANDROID_SERIAL. - if (transport_type == kTransportAny && serial == nullptr) { - serial = getenv("ANDROID_SERIAL"); - } - - adb_set_transport(transport_type, serial, transport_id); - - if (is_server) { - if (no_daemon || is_daemon) { - if (is_daemon && (ack_reply_fd == -1)) { - fprintf(stderr, "reply fd for adb server to client communication not specified.\n"); - return 1; - } - r = adb_server_main(is_daemon, server_socket_str, ack_reply_fd); - } else { - r = launch_server(server_socket_str); - } - if (r) { - fprintf(stderr,"* could not start server *\n"); - } - return r; - } - - if (argc == 0) { - help(); - return 1; - } - - /* handle wait-for-* prefix */ - if (!strncmp(argv[0], "wait-for-", strlen("wait-for-"))) { - const char* service = argv[0]; - - if (!wait_for_device(service)) { - return 1; - } - - // Allow a command to be run after wait-for-device, - // e.g. 'adb wait-for-device shell'. - if (argc == 1) { - return 0; - } - - /* Fall through */ - argc--; - argv++; - } - - /* adb_connect() commands */ - if (!strcmp(argv[0], "devices")) { - const char *listopt; - if (argc < 2) { - listopt = ""; - } else if (argc == 2 && !strcmp(argv[1], "-l")) { - listopt = argv[1]; - } else { - error_exit("adb devices [-l]"); - } - - std::string query = android::base::StringPrintf("host:%s%s", argv[0], listopt); - std::string error; - if (!adb_check_server_version(&error)) { - error_exit("failed to check server version: %s", error.c_str()); - } - printf("List of devices attached\n"); - return adb_query_command(query); - } - else if (!strcmp(argv[0], "connect")) { - if (argc != 2) error_exit("usage: adb connect HOST[:PORT]"); - - std::string query = android::base::StringPrintf("host:connect:%s", argv[1]); - return adb_query_command(query); - } - else if (!strcmp(argv[0], "disconnect")) { - if (argc > 2) error_exit("usage: adb disconnect [HOST[:PORT]]"); - - std::string query = android::base::StringPrintf("host:disconnect:%s", - (argc == 2) ? argv[1] : ""); - return adb_query_command(query); - } else if (!strcmp(argv[0], "abb")) { - return adb_abb(argc, argv); - } else if (!strcmp(argv[0], "pair")) { - if (argc != 2) error_exit("usage: adb pair [:]"); - - std::string password; - printf("Enter pairing code: "); - fflush(stdout); - if (!std::getline(std::cin, password) || password.empty()) { - error_exit("No pairing code provided"); - } - std::string query = - android::base::StringPrintf("host:pair:%s:%s", password.c_str(), argv[1]); - - return adb_query_command(query); - } else if (!strcmp(argv[0], "emu")) { - return adb_send_emulator_command(argc, argv, serial); - } else if (!strcmp(argv[0], "shell")) { - return adb_shell(argc, argv); - } else if (!strcmp(argv[0], "exec-in") || !strcmp(argv[0], "exec-out")) { - int exec_in = !strcmp(argv[0], "exec-in"); - - if (argc < 2) error_exit("usage: adb %s command", argv[0]); - - std::string cmd = "exec:"; - cmd += argv[1]; - argc -= 2; - argv += 2; - while (argc-- > 0) { - cmd += " " + escape_arg(*argv++); - } - - std::string error; - unique_fd fd(adb_connect(cmd, &error)); - if (fd < 0) { - fprintf(stderr, "error: %s\n", error.c_str()); - return -1; - } - - if (exec_in) { - copy_to_file(STDIN_FILENO, fd.get()); - } else { - copy_to_file(fd.get(), STDOUT_FILENO); - } - return 0; - } else if (!strcmp(argv[0], "kill-server")) { - return adb_kill_server() ? 0 : 1; - } else if (!strcmp(argv[0], "sideload")) { - if (argc != 2) error_exit("sideload requires an argument"); - if (adb_sideload_install(argv[1], false /* rescue_mode */)) { - return 1; - } else { - return 0; - } - } else if (!strcmp(argv[0], "rescue")) { - // adb rescue getprop - // adb rescue getprop - // adb rescue install - // adb rescue wipe userdata - if (argc < 2) error_exit("rescue requires at least one argument"); - if (!strcmp(argv[1], "getprop")) { - if (argc == 2) { - return adb_connect_command("rescue-getprop:"); - } - if (argc == 3) { - return adb_connect_command( - android::base::StringPrintf("rescue-getprop:%s", argv[2])); - } - error_exit("invalid rescue getprop arguments"); - } else if (!strcmp(argv[1], "install")) { - if (argc != 3) error_exit("rescue install requires two arguments"); - if (adb_sideload_install(argv[2], true /* rescue_mode */) != 0) { - return 1; - } - } else if (!strcmp(argv[1], "wipe")) { - if (argc != 3 || strcmp(argv[2], "userdata") != 0) { - error_exit("invalid rescue wipe arguments"); - } - return adb_wipe_devices(); - } else { - error_exit("invalid rescue argument"); - } - return 0; - } else if (!strcmp(argv[0], "tcpip")) { - if (argc != 2) error_exit("tcpip requires an argument"); - int port; - if (!android::base::ParseInt(argv[1], &port, 1, 65535)) { - error_exit("tcpip: invalid port: %s", argv[1]); - } - return adb_connect_command(android::base::StringPrintf("tcpip:%d", port)); - } else if (!strcmp(argv[0], "remount")) { - FeatureSet features; - std::string error; - if (!adb_get_feature_set(&features, &error)) { - fprintf(stderr, "error: %s\n", error.c_str()); - return 1; - } - - if (CanUseFeature(features, kFeatureRemountShell)) { - std::vector args = {"shell"}; - args.insert(args.cend(), argv, argv + argc); - return adb_shell_noinput(args.size(), args.data()); - } else if (argc > 1) { - auto command = android::base::StringPrintf("%s:%s", argv[0], argv[1]); - return adb_connect_command(command); - } else { - return adb_connect_command("remount:"); - } - } - // clang-format off - else if (!strcmp(argv[0], "reboot") || - !strcmp(argv[0], "reboot-bootloader") || - !strcmp(argv[0], "reboot-fastboot") || - !strcmp(argv[0], "usb") || - !strcmp(argv[0], "disable-verity") || - !strcmp(argv[0], "enable-verity")) { - // clang-format on - std::string command; - if (!strcmp(argv[0], "reboot-bootloader")) { - command = "reboot:bootloader"; - } else if (!strcmp(argv[0], "reboot-fastboot")) { - command = "reboot:fastboot"; - } else if (argc > 1) { - command = android::base::StringPrintf("%s:%s", argv[0], argv[1]); - } else { - command = android::base::StringPrintf("%s:", argv[0]); - } - return adb_connect_command(command); - } else if (!strcmp(argv[0], "root") || !strcmp(argv[0], "unroot")) { - return adb_root(argv[0]) ? 0 : 1; - } else if (!strcmp(argv[0], "bugreport")) { - Bugreport bugreport; - return bugreport.DoIt(argc, argv); - } else if (!strcmp(argv[0], "forward") || !strcmp(argv[0], "reverse")) { - bool reverse = !strcmp(argv[0], "reverse"); - --argc; - if (argc < 1) error_exit("%s requires an argument", argv[0]); - ++argv; - - // Determine the for this command. - std::string host_prefix; - if (reverse) { - host_prefix = "reverse:"; - } else { - host_prefix = "host:"; - } - - std::string cmd, error_message; - if (strcmp(argv[0], "--list") == 0) { - if (argc != 1) error_exit("--list doesn't take any arguments"); - return adb_query_command(host_prefix + "list-forward"); - } else if (strcmp(argv[0], "--remove-all") == 0) { - if (argc != 1) error_exit("--remove-all doesn't take any arguments"); - cmd = "killforward-all"; - } else if (strcmp(argv[0], "--remove") == 0) { - // forward --remove - if (argc != 2) error_exit("--remove requires an argument"); - cmd = std::string("killforward:") + argv[1]; - } else if (strcmp(argv[0], "--no-rebind") == 0) { - // forward --no-rebind - if (argc != 3) error_exit("--no-rebind takes two arguments"); - if (forward_targets_are_valid(argv[1], argv[2], &error_message)) { - cmd = std::string("forward:norebind:") + argv[1] + ";" + argv[2]; - } - } else { - // forward - if (argc != 2) error_exit("forward takes two arguments"); - if (forward_targets_are_valid(argv[0], argv[1], &error_message)) { - cmd = std::string("forward:") + argv[0] + ";" + argv[1]; - } - } - - if (!error_message.empty()) { - error_exit("error: %s", error_message.c_str()); - } - - unique_fd fd(adb_connect(nullptr, host_prefix + cmd, &error_message, true)); - if (fd < 0 || !adb_status(fd.get(), &error_message)) { - error_exit("error: %s", error_message.c_str()); - } - - // Server or device may optionally return a resolved TCP port number. - std::string resolved_port; - if (ReadProtocolString(fd, &resolved_port, &error_message) && !resolved_port.empty()) { - printf("%s\n", resolved_port.c_str()); - } - - ReadOrderlyShutdown(fd); - return 0; - } - /* do_sync_*() commands */ - else if (!strcmp(argv[0], "ls")) { - if (argc != 2) error_exit("ls requires an argument"); - return do_sync_ls(argv[1]) ? 0 : 1; - } else if (!strcmp(argv[0], "push")) { - bool copy_attrs = false; - bool sync = false; - bool compressed = true; - std::vector srcs; - const char* dst = nullptr; - - parse_push_pull_args(&argv[1], argc - 1, &srcs, &dst, ©_attrs, &sync, &compressed); - if (srcs.empty() || !dst) error_exit("push requires an argument"); - return do_sync_push(srcs, dst, sync, compressed) ? 0 : 1; - } else if (!strcmp(argv[0], "pull")) { - bool copy_attrs = false; - bool compressed = true; - std::vector srcs; - const char* dst = "."; - - parse_push_pull_args(&argv[1], argc - 1, &srcs, &dst, ©_attrs, nullptr, &compressed); - if (srcs.empty()) error_exit("pull requires an argument"); - return do_sync_pull(srcs, dst, copy_attrs, compressed) ? 0 : 1; - } else if (!strcmp(argv[0], "install")) { - if (argc < 2) error_exit("install requires an argument"); - return install_app(argc, argv); - } else if (!strcmp(argv[0], "install-multiple")) { - if (argc < 2) error_exit("install-multiple requires an argument"); - return install_multiple_app(argc, argv); - } else if (!strcmp(argv[0], "install-multi-package")) { - if (argc < 2) error_exit("install-multi-package requires an argument"); - return install_multi_package(argc, argv); - } else if (!strcmp(argv[0], "uninstall")) { - if (argc < 2) error_exit("uninstall requires an argument"); - return uninstall_app(argc, argv); - } else if (!strcmp(argv[0], "sync")) { - std::string src; - bool list_only = false; - bool compressed = true; - - const char* adb_compression = getenv("ADB_COMPRESSION"); - if (adb_compression && strcmp(adb_compression, "0") == 0) { - compressed = false; - } - - int opt; - while ((opt = getopt(argc, const_cast(argv), "lzZ")) != -1) { - switch (opt) { - case 'l': - list_only = true; - break; - case 'z': - compressed = true; - break; - case 'Z': - compressed = false; - break; - default: - error_exit("usage: adb sync [-lzZ] [PARTITION]"); - } - } - - if (optind == argc) { - src = "all"; - } else if (optind + 1 == argc) { - src = argv[optind]; - } else { - error_exit("usage: adb sync [-lzZ] [PARTITION]"); - } - - std::vector partitions{"data", "odm", "oem", "product", - "system", "system_ext", "vendor"}; - bool found = false; - for (const auto& partition : partitions) { - if (src == "all" || src == partition) { - std::string src_dir{product_file(partition)}; - if (!directory_exists(src_dir)) continue; - found = true; - if (!do_sync_sync(src_dir, "/" + partition, list_only, compressed)) return 1; - } - } - if (!found) error_exit("don't know how to sync %s partition", src.c_str()); - return 0; - } - /* passthrough commands */ - else if (!strcmp(argv[0], "get-state") || !strcmp(argv[0], "get-serialno") || - !strcmp(argv[0], "get-devpath")) { - return adb_query_command(format_host_command(argv[0])); - } - /* other commands */ - else if (!strcmp(argv[0], "logcat") || !strcmp(argv[0], "lolcat") || - !strcmp(argv[0], "longcat")) { - return logcat(argc, argv); - } else if (!strcmp(argv[0], "ppp")) { - return ppp(argc, argv); - } else if (!strcmp(argv[0], "start-server")) { - std::string error; - const int result = adb_connect("host:start-server", &error); - if (result < 0) { - fprintf(stderr, "error: %s\n", error.c_str()); - } - return result; - } else if (!strcmp(argv[0], "backup")) { - return backup(argc, argv); - } else if (!strcmp(argv[0], "restore")) { - return restore(argc, argv); - } else if (!strcmp(argv[0], "keygen")) { - if (argc != 2) error_exit("keygen requires an argument"); - // Always print key generation information for keygen command. - adb_trace_enable(AUTH); - return adb_auth_keygen(argv[1]); - } else if (!strcmp(argv[0], "pubkey")) { - if (argc != 2) error_exit("pubkey requires an argument"); - return adb_auth_pubkey(argv[1]); - } else if (!strcmp(argv[0], "jdwp")) { - return adb_connect_command("jdwp"); - } else if (!strcmp(argv[0], "track-jdwp")) { - return adb_connect_command("track-jdwp"); - } else if (!strcmp(argv[0], "track-devices")) { - if (argc > 2 || (argc == 2 && strcmp(argv[1], "-l"))) { - error_exit("usage: adb track-devices [-l]"); - } - return adb_connect_command(argc == 2 ? "host:track-devices-l" : "host:track-devices"); - } else if (!strcmp(argv[0], "raw")) { - if (argc != 2) { - error_exit("usage: adb raw SERVICE"); - } - return adb_connect_command_bidirectional(argv[1]); - } - - /* "adb /?" is a common idiom under Windows */ - else if (!strcmp(argv[0], "--help") || !strcmp(argv[0], "help") || !strcmp(argv[0], "/?")) { - help(); - return 0; - } else if (!strcmp(argv[0], "--version") || !strcmp(argv[0], "version")) { - fprintf(stdout, "%s", adb_version().c_str()); - return 0; - } else if (!strcmp(argv[0], "features")) { - // Only list the features common to both the adb client and the device. - FeatureSet features; - std::string error; - if (!adb_get_feature_set(&features, &error)) { - fprintf(stderr, "error: %s\n", error.c_str()); - return 1; - } - - for (const std::string& name : features) { - if (CanUseFeature(features, name)) { - printf("%s\n", name.c_str()); - } - } - return 0; - } else if (!strcmp(argv[0], "host-features")) { - return adb_query_command("host:host-features"); - } else if (!strcmp(argv[0], "reconnect")) { - if (argc == 1) { - return adb_query_command(format_host_command(argv[0])); - } else if (argc == 2) { - if (!strcmp(argv[1], "device")) { - std::string err; - adb_connect("reconnect", &err); - return 0; - } else if (!strcmp(argv[1], "offline")) { - std::string err; - return adb_query_command("host:reconnect-offline"); - } else { - error_exit("usage: adb reconnect [device|offline]"); - } - } - } else if (!strcmp(argv[0], "inc-server")) { - if (argc < 4) { -#ifdef _WIN32 - error_exit("usage: adb inc-server CONNECTION_HANDLE OUTPUT_HANDLE FILE1 FILE2 ..."); -#else - error_exit("usage: adb inc-server CONNECTION_FD OUTPUT_FD FILE1 FILE2 ..."); -#endif - } - int connection_fd = atoi(argv[1]); - if (!_is_valid_os_fd(connection_fd)) { - error_exit("Invalid connection_fd number given: %d", connection_fd); - } - - connection_fd = adb_register_socket(connection_fd); - close_on_exec(connection_fd); - - int output_fd = atoi(argv[2]); - if (!_is_valid_os_fd(output_fd)) { - error_exit("Invalid output_fd number given: %d", output_fd); - } - output_fd = adb_register_socket(output_fd); - close_on_exec(output_fd); - return incremental::serve(connection_fd, output_fd, argc - 3, argv + 3); - } - - error_exit("unknown command %s", argv[0]); - __builtin_unreachable(); -} diff --git a/adb/client/commandline.h b/adb/client/commandline.h deleted file mode 100644 index b9dee5625938cd1beeca8968aea034a26a6ee1e7..0000000000000000000000000000000000000000 --- a/adb/client/commandline.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (C) 2016 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 COMMANDLINE_H -#define COMMANDLINE_H - -#include - -#include "adb.h" -#include "adb_client.h" -#include "adb_unique_fd.h" - -// Callback used to handle the standard streams (stdout and stderr) sent by the -// device's upon receiving a command. -// -class StandardStreamsCallbackInterface { - public: - StandardStreamsCallbackInterface() { - } - // Handles the stdout output from devices supporting the Shell protocol. - virtual void OnStdout(const char* buffer, int length) = 0; - - // Handles the stderr output from devices supporting the Shell protocol. - virtual void OnStderr(const char* buffer, int length) = 0; - - // Indicates the communication is finished and returns the appropriate error - // code. - // - // |status| has the status code returning by the underlying communication - // channels - virtual int Done(int status) = 0; - - protected: - static void OnStream(std::string* string, FILE* stream, const char* buffer, int length) { - if (string != nullptr) { - string->append(buffer, length); - } else { - fwrite(buffer, 1, length, stream); - fflush(stream); - } - } - - private: - DISALLOW_COPY_AND_ASSIGN(StandardStreamsCallbackInterface); -}; - -// Default implementation that redirects the streams to the equilavent host -// stream or to a string -// passed to the constructor. -class DefaultStandardStreamsCallback : public StandardStreamsCallbackInterface { - public: - // If |stdout_str| is non-null, OnStdout will append to it. - // If |stderr_str| is non-null, OnStderr will append to it. - DefaultStandardStreamsCallback(std::string* stdout_str, std::string* stderr_str) - : stdout_str_(stdout_str), stderr_str_(stderr_str) { - } - - void OnStdout(const char* buffer, int length) { - OnStream(stdout_str_, stdout, buffer, length); - } - - void OnStderr(const char* buffer, int length) { - OnStream(stderr_str_, stderr, buffer, length); - } - - int Done(int status) { - return status; - } - - private: - std::string* stdout_str_; - std::string* stderr_str_; - - DISALLOW_COPY_AND_ASSIGN(DefaultStandardStreamsCallback); -}; - -class SilentStandardStreamsCallbackInterface : public StandardStreamsCallbackInterface { - public: - SilentStandardStreamsCallbackInterface() = default; - void OnStdout(const char*, int) override final {} - void OnStderr(const char*, int) override final {} - int Done(int status) override final { return status; } -}; - -// Singleton. -extern DefaultStandardStreamsCallback DEFAULT_STANDARD_STREAMS_CALLBACK; - -int adb_commandline(int argc, const char** argv); - -bool copy_to_file(int inFd, int outFd); - -// Connects to the device "shell" service with |command| and prints the -// resulting output. -// if |callback| is non-null, stdout/stderr output will be handled by it. -int send_shell_command( - const std::string& command, bool disable_shell_protocol = false, - StandardStreamsCallbackInterface* callback = &DEFAULT_STANDARD_STREAMS_CALLBACK); - -// Reads from |fd| and prints received data. If |use_shell_protocol| is true -// this expects that incoming data will use the shell protocol, in which case -// stdout/stderr are routed independently and the remote exit code will be -// returned. -// if |callback| is non-null, stdout/stderr output will be handled by it. -int read_and_dump(borrowed_fd fd, bool use_shell_protocol = false, - StandardStreamsCallbackInterface* callback = &DEFAULT_STANDARD_STREAMS_CALLBACK); - -// Connects to the device "abb" service with |command| and returns the fd. -template -unique_fd send_abb_exec_command(const ContainerT& command_args, std::string* error) { - std::string service_string = "abb_exec:" + android::base::Join(command_args, ABB_ARG_DELIMETER); - - unique_fd fd(adb_connect(service_string, error)); - if (fd < 0) { - fprintf(stderr, "adb: failed to run abb_exec. Error: %s\n", error->c_str()); - return unique_fd{}; - } - return fd; -} - -#endif // COMMANDLINE_H diff --git a/adb/client/console.cpp b/adb/client/console.cpp deleted file mode 100644 index d10f4deec5f7964ba28c5ff1a8b1d63419761d9b..0000000000000000000000000000000000000000 --- a/adb/client/console.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (C) 2015 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 "adb.h" -#include "adb_client.h" -#include "adb_io.h" -#include "adb_utils.h" - -// Return the console authentication command for the emulator, if needed -static std::string adb_construct_auth_command() { - static const char auth_token_filename[] = ".emulator_console_auth_token"; - - std::string auth_token_path = adb_get_homedir_path(); - auth_token_path += OS_PATH_SEPARATOR; - auth_token_path += auth_token_filename; - - // read the token - std::string token; - if (!android::base::ReadFileToString(auth_token_path, &token) - || token.empty()) { - // we either can't read the file, or it doesn't exist, or it's empty - - // either way we won't add any authentication command. - return {}; - } - - // now construct and return the actual command: "auth \n" - std::string command = "auth "; - command += token; - command += '\n'; - return command; -} - -// Return the console port of the currently connected emulator (if any) or -1 if -// there is no emulator, and -2 if there is more than one. -static int adb_get_emulator_console_port(const char* serial) { - if (serial) { - // The user specified a serial number; is it an emulator? - int port; - return (sscanf(serial, "emulator-%d", &port) == 1) ? port : -1; - } - - // No specific device was given, so get the list of connected devices and - // search for emulators. If there's one, we'll take it. If there are more - // than one, that's an error. - std::string devices; - std::string error; - if (!adb_query("host:devices", &devices, &error)) { - fprintf(stderr, "error: no emulator connected: %s\n", error.c_str()); - return -1; - } - - int port = -1; - size_t emulator_count = 0; - for (const auto& device : android::base::Split(devices, "\n")) { - if (sscanf(device.c_str(), "emulator-%d", &port) == 1) { - if (++emulator_count > 1) { - fprintf( - stderr, "error: more than one emulator detected; use -s\n"); - return -1; - } - } - } - - if (emulator_count == 0) { - fprintf(stderr, "error: no emulator detected\n"); - return -1; - } - - return port; -} - -static int connect_to_console(const char* serial) { - int port = adb_get_emulator_console_port(serial); - if (port == -1) { - return -1; - } - - std::string error; - int fd = network_loopback_client(port, SOCK_STREAM, &error); - if (fd == -1) { - fprintf(stderr, "error: could not connect to TCP port %d: %s\n", port, - error.c_str()); - return -1; - } - return fd; -} - -int adb_send_emulator_command(int argc, const char** argv, const char* serial) { - unique_fd fd(connect_to_console(serial)); - if (fd == -1) { - return 1; - } - - std::string commands = adb_construct_auth_command(); - - for (int i = 1; i < argc; i++) { - commands.append(argv[i]); - commands.push_back(i == argc - 1 ? '\n' : ' '); - } - - commands.append("quit\n"); - - if (!WriteFdExactly(fd, commands)) { - fprintf(stderr, "error: cannot write to emulator: %s\n", - strerror(errno)); - return 1; - } - - // Drain output that the emulator console has sent us to prevent a problem - // on Windows where if adb closes the socket without reading all the data, - // the emulator's next call to recv() will have an ECONNABORTED error, - // preventing the emulator from reading the command that adb has sent. - // https://code.google.com/p/android/issues/detail?id=21021 - int result; - std::string emulator_output; - do { - char buf[BUFSIZ]; - result = adb_read(fd, buf, sizeof(buf)); - // Keep reading until zero bytes (orderly/graceful shutdown) or an - // error. If 'adb emu kill' is executed, the emulator calls exit() with - // the socket open (and shutdown(SD_SEND) was not called), which causes - // Windows to send a TCP RST segment which causes adb to get ECONNRESET. - // Any other emu command is followed by the quit command that we - // appended above, and that causes the emulator to close the socket - // which should cause zero bytes (orderly/graceful shutdown) to be - // returned. - if (result > 0) emulator_output.append(buf, result); - } while (result > 0); - - // Note: the following messages are expected to be quite stable from emulator. - // - // Emulator console will send the following message upon connection: - // - // Android Console: Authentication required - // Android Console: type 'auth ' to authenticate - // Android Console: you can find your in - // '//.emulator_console_auth_token' - // OK\r\n - // - // and the following after authentication: - // Android Console: type 'help' for a list of commands - // OK\r\n - // - // So try search and skip first two "OK\r\n", print the rest. - // - const std::string delims = "OK\r\n"; - size_t found = 0; - for (int i = 0; i < 2; ++i) { - const size_t result = emulator_output.find(delims, found); - if (result == std::string::npos) { - break; - } else { - found = result + delims.size(); - } - } - - printf("%s", emulator_output.c_str() + found); - return 0; -} diff --git a/adb/client/fastdeploy.cpp b/adb/client/fastdeploy.cpp deleted file mode 100644 index de82e14e53e630e342bf7cd3ab822ca16710abca..0000000000000000000000000000000000000000 --- a/adb/client/fastdeploy.cpp +++ /dev/null @@ -1,357 +0,0 @@ -/* - * Copyright (C) 2018 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 "fastdeploy.h" - -#include -#include -#include -#include - -#include "android-base/file.h" -#include "android-base/strings.h" -#include "androidfw/ResourceTypes.h" -#include "androidfw/ZipFileRO.h" -#include "client/file_sync_client.h" -#include "commandline.h" -#include "deployagent.inc" // Generated include via build rule. -#include "deployagentscript.inc" // Generated include via build rule. -#include "fastdeploy/deploypatchgenerator/deploy_patch_generator.h" -#include "fastdeploy/deploypatchgenerator/patch_utils.h" -#include "fastdeploy/proto/ApkEntry.pb.h" -#include "fastdeploycallbacks.h" -#include "sysdeps.h" - -#include "adb_utils.h" - -static constexpr long kRequiredAgentVersion = 0x00000003; - -static constexpr int kPackageMissing = 3; -static constexpr int kInvalidAgentVersion = 4; - -static constexpr const char* kDeviceAgentFile = "/data/local/tmp/deployagent.jar"; -static constexpr const char* kDeviceAgentScript = "/data/local/tmp/deployagent"; - -static constexpr bool g_verbose_timings = false; -static FastDeploy_AgentUpdateStrategy g_agent_update_strategy = - FastDeploy_AgentUpdateDifferentVersion; - -using APKMetaData = com::android::fastdeploy::APKMetaData; - -namespace { - -struct TimeReporter { - TimeReporter(const char* label) : label_(label) {} - ~TimeReporter() { - if (g_verbose_timings) { - auto duration = std::chrono::duration_cast( - std::chrono::steady_clock::now() - start_); - fprintf(stderr, "%s finished in %lldms\n", label_, - static_cast(duration.count())); - } - } - - private: - const char* label_; - std::chrono::steady_clock::time_point start_ = std::chrono::steady_clock::now(); -}; -#define REPORT_FUNC_TIME() TimeReporter reporter(__func__) - -struct FileDeleter { - FileDeleter(const char* path) : path_(path) {} - ~FileDeleter() { adb_unlink(path_); } - - private: - const char* const path_; -}; - -} // namespace - -int get_device_api_level() { - static const int api_level = [] { - REPORT_FUNC_TIME(); - std::vector sdk_version_output_buffer; - std::vector sdk_version_error_buffer; - int api_level = -1; - - int status_code = - capture_shell_command("getprop ro.build.version.sdk", &sdk_version_output_buffer, - &sdk_version_error_buffer); - if (status_code == 0 && sdk_version_output_buffer.size() > 0) { - api_level = strtol((char*)sdk_version_output_buffer.data(), nullptr, 10); - } - - return api_level; - }(); - return api_level; -} - -void fastdeploy_set_agent_update_strategy(FastDeploy_AgentUpdateStrategy agent_update_strategy) { - g_agent_update_strategy = agent_update_strategy; -} - -static void push_to_device(const void* data, size_t byte_count, const char* dst, bool sync) { - std::vector srcs; - TemporaryFile tf; - android::base::WriteFully(tf.fd, data, byte_count); - srcs.push_back(tf.path); - // On Windows, the file needs to be flushed before pushing to device, - // but can't be removed until after the push. - unix_close(tf.release()); - - if (!do_sync_push(srcs, dst, sync, true)) { - error_exit("Failed to push fastdeploy agent to device."); - } -} - -static bool deploy_agent(bool check_time_stamps) { - REPORT_FUNC_TIME(); - - push_to_device(kDeployAgent, sizeof(kDeployAgent), kDeviceAgentFile, check_time_stamps); - push_to_device(kDeployAgentScript, sizeof(kDeployAgentScript), kDeviceAgentScript, - check_time_stamps); - - // on windows the shell script might have lost execute permission - // so need to set this explicitly - const char* kChmodCommandPattern = "chmod 777 %s"; - std::string chmod_command = - android::base::StringPrintf(kChmodCommandPattern, kDeviceAgentScript); - int ret = send_shell_command(chmod_command); - if (ret != 0) { - error_exit("Error executing %s returncode: %d", chmod_command.c_str(), ret); - } - - return true; -} - -static std::string get_string_from_utf16(const char16_t* input, int input_len) { - ssize_t utf8_length = utf16_to_utf8_length(input, input_len); - if (utf8_length <= 0) { - return {}; - } - std::string utf8; - utf8.resize(utf8_length); - utf16_to_utf8(input, input_len, &*utf8.begin(), utf8_length + 1); - return utf8; -} - -static std::string get_package_name_from_apk(const char* apk_path) { -#undef open - std::unique_ptr zip_file((android::ZipFileRO::open)(apk_path)); -#define open ___xxx_unix_open - if (zip_file == nullptr) { - perror_exit("Could not open %s", apk_path); - } - android::ZipEntryRO entry = zip_file->findEntryByName("AndroidManifest.xml"); - if (entry == nullptr) { - error_exit("Could not find AndroidManifest.xml inside %s", apk_path); - } - uint32_t manifest_len = 0; - if (!zip_file->getEntryInfo(entry, NULL, &manifest_len, NULL, NULL, NULL, NULL)) { - error_exit("Could not read AndroidManifest.xml inside %s", apk_path); - } - std::vector manifest_data(manifest_len); - if (!zip_file->uncompressEntry(entry, manifest_data.data(), manifest_len)) { - error_exit("Could not uncompress AndroidManifest.xml inside %s", apk_path); - } - android::ResXMLTree tree; - android::status_t setto_status = tree.setTo(manifest_data.data(), manifest_len, true); - if (setto_status != android::OK) { - error_exit("Could not parse AndroidManifest.xml inside %s", apk_path); - } - android::ResXMLParser::event_code_t code; - while ((code = tree.next()) != android::ResXMLParser::BAD_DOCUMENT && - code != android::ResXMLParser::END_DOCUMENT) { - switch (code) { - case android::ResXMLParser::START_TAG: { - size_t element_name_length; - const char16_t* element_name = tree.getElementName(&element_name_length); - if (element_name == nullptr) { - continue; - } - std::u16string element_name_string(element_name, element_name_length); - if (element_name_string == u"manifest") { - for (size_t i = 0; i < tree.getAttributeCount(); i++) { - size_t attribute_name_length; - const char16_t* attribute_name_text = - tree.getAttributeName(i, &attribute_name_length); - if (attribute_name_text == nullptr) { - continue; - } - std::u16string attribute_name_string(attribute_name_text, - attribute_name_length); - if (attribute_name_string == u"package") { - size_t attribute_value_length; - const char16_t* attribute_value_text = - tree.getAttributeStringValue(i, &attribute_value_length); - if (attribute_value_text == nullptr) { - continue; - } - return get_string_from_utf16(attribute_value_text, - attribute_value_length); - } - } - } - break; - } - default: - break; - } - } - error_exit("Could not find package name tag in AndroidManifest.xml inside %s", apk_path); -} - -static long parse_agent_version(const std::vector& version_buffer) { - long version = -1; - if (!version_buffer.empty()) { - version = strtol((char*)version_buffer.data(), NULL, 16); - } - return version; -} - -static void update_agent_if_necessary() { - switch (g_agent_update_strategy) { - case FastDeploy_AgentUpdateAlways: - deploy_agent(/*check_time_stamps=*/false); - break; - case FastDeploy_AgentUpdateNewerTimeStamp: - deploy_agent(/*check_time_stamps=*/true); - break; - default: - break; - } -} - -std::optional extract_metadata(const char* apk_path) { - // Update agent if there is a command line argument forcing to do so. - update_agent_if_necessary(); - - REPORT_FUNC_TIME(); - - std::string package_name = get_package_name_from_apk(apk_path); - - // Dump apk command checks the required vs current agent version and if they match then returns - // the APK dump for package. Doing this in a single call saves round-trip and agent launch time. - constexpr const char* kAgentDumpCommandPattern = "/data/local/tmp/deployagent dump %ld %s"; - std::string dump_command = android::base::StringPrintf( - kAgentDumpCommandPattern, kRequiredAgentVersion, package_name.c_str()); - - std::vector dump_out_buffer; - std::vector dump_error_buffer; - int returnCode = - capture_shell_command(dump_command.c_str(), &dump_out_buffer, &dump_error_buffer); - if (returnCode >= kInvalidAgentVersion) { - // Agent has wrong version or missing. - long agent_version = parse_agent_version(dump_out_buffer); - if (agent_version < 0) { - printf("Could not detect agent on device, deploying\n"); - } else { - printf("Device agent version is (%ld), (%ld) is required, re-deploying\n", - agent_version, kRequiredAgentVersion); - } - deploy_agent(/*check_time_stamps=*/false); - - // Retry with new agent. - dump_out_buffer.clear(); - dump_error_buffer.clear(); - returnCode = - capture_shell_command(dump_command.c_str(), &dump_out_buffer, &dump_error_buffer); - } - if (returnCode != 0) { - if (returnCode == kInvalidAgentVersion) { - long agent_version = parse_agent_version(dump_out_buffer); - error_exit( - "After update agent version remains incorrect! Expected %ld but version is %ld", - kRequiredAgentVersion, agent_version); - } - if (returnCode == kPackageMissing) { - fprintf(stderr, "Package %s not found, falling back to install\n", - package_name.c_str()); - return {}; - } - fprintf(stderr, "Executing %s returned %d\n", dump_command.c_str(), returnCode); - fprintf(stderr, "%*s\n", int(dump_error_buffer.size()), dump_error_buffer.data()); - error_exit("Aborting"); - } - - com::android::fastdeploy::APKDump dump; - if (!dump.ParseFromArray(dump_out_buffer.data(), dump_out_buffer.size())) { - fprintf(stderr, "Can't parse output of %s\n", dump_command.c_str()); - error_exit("Aborting"); - } - - return PatchUtils::GetDeviceAPKMetaData(dump); -} - -unique_fd install_patch(int argc, const char** argv) { - REPORT_FUNC_TIME(); - constexpr char kAgentApplyServicePattern[] = "shell:/data/local/tmp/deployagent apply - -pm %s"; - - std::vector apply_output_buffer; - std::vector apply_error_buffer; - std::string argsString; - - bool rSwitchPresent = false; - for (int i = 0; i < argc; i++) { - argsString.append(argv[i]); - argsString.append(" "); - if (!strcmp(argv[i], "-r")) { - rSwitchPresent = true; - } - } - if (!rSwitchPresent) { - argsString.append("-r"); - } - - std::string error; - std::string apply_patch_service_string = - android::base::StringPrintf(kAgentApplyServicePattern, argsString.c_str()); - unique_fd fd{adb_connect(apply_patch_service_string, &error)}; - if (fd < 0) { - error_exit("Executing %s returned %s", apply_patch_service_string.c_str(), error.c_str()); - } - return fd; -} - -unique_fd apply_patch_on_device(const char* output_path) { - REPORT_FUNC_TIME(); - constexpr char kAgentApplyServicePattern[] = "shell:/data/local/tmp/deployagent apply - -o %s"; - - std::string error; - std::string apply_patch_service_string = - android::base::StringPrintf(kAgentApplyServicePattern, output_path); - unique_fd fd{adb_connect(apply_patch_service_string, &error)}; - if (fd < 0) { - error_exit("Executing %s returned %s", apply_patch_service_string.c_str(), error.c_str()); - } - return fd; -} - -static void create_patch(const char* apk_path, APKMetaData metadata, borrowed_fd patch_fd) { - REPORT_FUNC_TIME(); - DeployPatchGenerator generator(/*is_verbose=*/false); - bool success = generator.CreatePatch(apk_path, std::move(metadata), patch_fd); - if (!success) { - error_exit("Failed to create patch for %s", apk_path); - } -} - -int stream_patch(const char* apk_path, APKMetaData metadata, unique_fd patch_fd) { - create_patch(apk_path, std::move(metadata), patch_fd); - - REPORT_FUNC_TIME(); - return read_and_dump(patch_fd.get()); -} diff --git a/adb/client/fastdeploy.h b/adb/client/fastdeploy.h deleted file mode 100644 index 830aeb2ca957f03053b3c023deed16eda366f5d4..0000000000000000000000000000000000000000 --- a/adb/client/fastdeploy.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2018 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. - */ - -#pragma once - -#include "adb_unique_fd.h" - -#include "fastdeploy/proto/ApkEntry.pb.h" - -#include -#include - -enum FastDeploy_AgentUpdateStrategy { - FastDeploy_AgentUpdateAlways, - FastDeploy_AgentUpdateNewerTimeStamp, - FastDeploy_AgentUpdateDifferentVersion -}; - -void fastdeploy_set_agent_update_strategy(FastDeploy_AgentUpdateStrategy agent_update_strategy); -int get_device_api_level(); - -std::optional extract_metadata(const char* apk_path); -unique_fd install_patch(int argc, const char** argv); -unique_fd apply_patch_on_device(const char* output_path); -int stream_patch(const char* apk_path, com::android::fastdeploy::APKMetaData metadata, - unique_fd patch_fd); diff --git a/adb/client/fastdeploycallbacks.cpp b/adb/client/fastdeploycallbacks.cpp deleted file mode 100644 index 86ceaa1378992e28d82156ac7d82a951ce389dac..0000000000000000000000000000000000000000 --- a/adb/client/fastdeploycallbacks.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2018 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 ADB - -#include -#include -#include -#include - -#include "client/file_sync_client.h" -#include "commandline.h" -#include "sysdeps.h" - -#include "fastdeploycallbacks.h" - -static void appendBuffer(std::vector* buffer, const char* input, int length) { - if (buffer != NULL) { - buffer->insert(buffer->end(), input, input + length); - } -} - -class DeployAgentBufferCallback : public StandardStreamsCallbackInterface { - public: - DeployAgentBufferCallback(std::vector* outBuffer, std::vector* errBuffer); - - virtual void OnStdout(const char* buffer, int length); - virtual void OnStderr(const char* buffer, int length); - virtual int Done(int status); - - private: - std::vector* mpOutBuffer; - std::vector* mpErrBuffer; -}; - -int capture_shell_command(const char* command, std::vector* outBuffer, - std::vector* errBuffer) { - DeployAgentBufferCallback cb(outBuffer, errBuffer); - return send_shell_command(command, /*disable_shell_protocol=*/false, &cb); -} - -DeployAgentBufferCallback::DeployAgentBufferCallback(std::vector* outBuffer, - std::vector* errBuffer) { - mpOutBuffer = outBuffer; - mpErrBuffer = errBuffer; -} - -void DeployAgentBufferCallback::OnStdout(const char* buffer, int length) { - appendBuffer(mpOutBuffer, buffer, length); -} - -void DeployAgentBufferCallback::OnStderr(const char* buffer, int length) { - appendBuffer(mpErrBuffer, buffer, length); -} - -int DeployAgentBufferCallback::Done(int status) { - return status; -} diff --git a/adb/client/fastdeploycallbacks.h b/adb/client/fastdeploycallbacks.h deleted file mode 100644 index 4a6fb991520fbdf51d824b92f8a9697c7347042c..0000000000000000000000000000000000000000 --- a/adb/client/fastdeploycallbacks.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2018 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. - */ - -#pragma once - -#include - -int capture_shell_command(const char* command, std::vector* outBuffer, - std::vector* errBuffer); diff --git a/adb/client/file_sync_client.cpp b/adb/client/file_sync_client.cpp deleted file mode 100644 index e686973db4ea4b54dd4f7ccb1cb34fff6f97fb25..0000000000000000000000000000000000000000 --- a/adb/client/file_sync_client.cpp +++ /dev/null @@ -1,1650 +0,0 @@ -/* - * 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 "client/file_sync_client.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "sysdeps.h" - -#include "adb.h" -#include "adb_client.h" -#include "adb_io.h" -#include "adb_utils.h" -#include "brotli_utils.h" -#include "file_sync_protocol.h" -#include "line_printer.h" -#include "sysdeps/errno.h" -#include "sysdeps/stat.h" - -#include "client/commandline.h" - -#include -#include -#include - -using namespace std::literals; - -typedef void(sync_ls_cb)(unsigned mode, uint64_t size, uint64_t time, const char* name); - -struct syncsendbuf { - unsigned id; - unsigned size; - char data[SYNC_DATA_MAX]; -}; - -static void ensure_trailing_separators(std::string& local_path, std::string& remote_path) { - if (!adb_is_separator(local_path.back())) { - local_path.push_back(OS_PATH_SEPARATOR); - } - if (remote_path.back() != '/') { - remote_path.push_back('/'); - } -} - -static bool should_pull_file(mode_t mode) { - return S_ISREG(mode) || S_ISBLK(mode) || S_ISCHR(mode); -} - -static bool should_push_file(mode_t mode) { - return S_ISREG(mode) || S_ISLNK(mode); -} - -struct copyinfo { - std::string lpath; - std::string rpath; - int64_t time = 0; - uint32_t mode; - uint64_t size = 0; - bool skip = false; - - copyinfo(const std::string& local_path, - const std::string& remote_path, - const std::string& name, - unsigned int mode) - : lpath(local_path), rpath(remote_path), mode(mode) { - ensure_trailing_separators(lpath, rpath); - lpath.append(name); - rpath.append(name); - if (S_ISDIR(mode)) { - ensure_trailing_separators(lpath, rpath); - } - } -}; - -enum class TransferDirection { - push, - pull, -}; - -struct TransferLedger { - std::chrono::steady_clock::time_point start_time; - uint64_t files_transferred; - uint64_t files_skipped; - uint64_t bytes_transferred; - uint64_t bytes_expected; - bool expect_multiple_files; - - private: - std::string last_progress_str; - std::chrono::steady_clock::time_point last_progress_time; - - public: - TransferLedger() { - Reset(); - } - - bool operator==(const TransferLedger& other) const { - return files_transferred == other.files_transferred && - files_skipped == other.files_skipped && bytes_transferred == other.bytes_transferred; - } - - bool operator!=(const TransferLedger& other) const { - return !(*this == other); - } - - void Reset() { - start_time = std::chrono::steady_clock::now(); - files_transferred = 0; - files_skipped = 0; - bytes_transferred = 0; - bytes_expected = 0; - last_progress_str.clear(); - last_progress_time = {}; - } - - std::string TransferRate() { - if (bytes_transferred == 0) return ""; - - std::chrono::duration duration; - duration = std::chrono::steady_clock::now() - start_time; - - double s = duration.count(); - if (s == 0) { - return ""; - } - double rate = (static_cast(bytes_transferred) / s) / (1024 * 1024); - return android::base::StringPrintf(" %.1f MB/s (%" PRIu64 " bytes in %.3fs)", rate, - bytes_transferred, s); - } - - void ReportProgress(LinePrinter& lp, const std::string& file, uint64_t file_copied_bytes, - uint64_t file_total_bytes) { - static constexpr auto kProgressReportInterval = 100ms; - - auto now = std::chrono::steady_clock::now(); - if (now < last_progress_time + kProgressReportInterval) { - return; - } - char overall_percentage_str[5] = "?"; - if (bytes_expected != 0 && bytes_transferred <= bytes_expected) { - int overall_percentage = static_cast(bytes_transferred * 100 / bytes_expected); - // If we're pulling symbolic links, we'll pull the target of the link rather than - // just create a local link, and that will cause us to go over 100%. - if (overall_percentage <= 100) { - snprintf(overall_percentage_str, sizeof(overall_percentage_str), "%d%%", - overall_percentage); - } - } - - std::string output; - if (file_copied_bytes > file_total_bytes || file_total_bytes == 0) { - // This case can happen if we're racing against something that wrote to the file - // between our stat and our read, or if we're reading a magic file that lies about - // its size. Just show how much we've copied. - output = android::base::StringPrintf("[%4s] %s: %" PRId64 "/?", overall_percentage_str, - file.c_str(), file_copied_bytes); - } else { - // If we're transferring multiple files, we want to know how far through the current - // file we are, as well as the overall percentage. - if (expect_multiple_files) { - int file_percentage = static_cast(file_copied_bytes * 100 / file_total_bytes); - output = android::base::StringPrintf("[%4s] %s: %d%%", overall_percentage_str, - file.c_str(), file_percentage); - } else { - output = - android::base::StringPrintf("[%4s] %s", overall_percentage_str, file.c_str()); - } - } - if (output != last_progress_str) { - lp.Print(output, LinePrinter::LineType::INFO); - last_progress_str = std::move(output); - last_progress_time = now; - } - } - - void ReportTransferRate(LinePrinter& lp, const std::string& name, TransferDirection direction) { - const char* direction_str = (direction == TransferDirection::push) ? "pushed" : "pulled"; - std::stringstream ss; - if (!name.empty()) { - std::string_view display_name(name); - char* out = getenv("ANDROID_PRODUCT_OUT"); - if (out) android::base::ConsumePrefix(&display_name, out); - ss << display_name << ": "; - } - ss << files_transferred << " file" << ((files_transferred == 1) ? "" : "s") << " " - << direction_str << ", " << files_skipped << " skipped."; - ss << TransferRate(); - - lp.Print(ss.str(), LinePrinter::LineType::INFO); - lp.KeepInfoLine(); - } -}; - -class SyncConnection { - public: - SyncConnection() : acknowledgement_buffer_(sizeof(sync_status) + SYNC_DATA_MAX) { - acknowledgement_buffer_.resize(0); - max = SYNC_DATA_MAX; // TODO: decide at runtime. - - std::string error; - if (!adb_get_feature_set(&features_, &error)) { - Error("failed to get feature set: %s", error.c_str()); - } else { - have_stat_v2_ = CanUseFeature(features_, kFeatureStat2); - have_ls_v2_ = CanUseFeature(features_, kFeatureLs2); - have_sendrecv_v2_ = CanUseFeature(features_, kFeatureSendRecv2); - have_sendrecv_v2_brotli_ = CanUseFeature(features_, kFeatureSendRecv2Brotli); - fd.reset(adb_connect("sync:", &error)); - if (fd < 0) { - Error("connect failed: %s", error.c_str()); - } - } - } - - ~SyncConnection() { - if (!IsValid()) return; - - if (SendQuit()) { - // We sent a quit command, so the server should be doing orderly - // shutdown soon. But if we encountered an error while we were using - // the connection, the server might still be sending data (before - // doing orderly shutdown), in which case we won't wait for all of - // the data nor the coming orderly shutdown. In the common success - // case, this will wait for the server to do orderly shutdown. - ReadOrderlyShutdown(fd); - } - - line_printer_.KeepInfoLine(); - } - - bool HaveSendRecv2() const { return have_sendrecv_v2_; } - bool HaveSendRecv2Brotli() const { return have_sendrecv_v2_brotli_; } - - const FeatureSet& Features() const { return features_; } - - bool IsValid() { return fd >= 0; } - - void NewTransfer() { - current_ledger_.Reset(); - } - - void RecordBytesTransferred(size_t bytes) { - current_ledger_.bytes_transferred += bytes; - global_ledger_.bytes_transferred += bytes; - } - - void RecordFileSent(std::string from, std::string to) { - RecordFilesTransferred(1); - deferred_acknowledgements_.emplace_back(std::move(from), std::move(to)); - } - - void RecordFilesTransferred(size_t files) { - current_ledger_.files_transferred += files; - global_ledger_.files_transferred += files; - } - - void RecordFilesSkipped(size_t files) { - current_ledger_.files_skipped += files; - global_ledger_.files_skipped += files; - } - - void ReportProgress(const std::string& file, uint64_t file_copied_bytes, - uint64_t file_total_bytes) { - current_ledger_.ReportProgress(line_printer_, file, file_copied_bytes, file_total_bytes); - } - - void ReportTransferRate(const std::string& file, TransferDirection direction) { - current_ledger_.ReportTransferRate(line_printer_, file, direction); - } - - void ReportOverallTransferRate(TransferDirection direction) { - if (current_ledger_ != global_ledger_) { - global_ledger_.ReportTransferRate(line_printer_, "", direction); - } - } - - bool SendRequest(int id, const std::string& path) { - if (path.length() > 1024) { - Error("SendRequest failed: path too long: %zu", path.length()); - errno = ENAMETOOLONG; - return false; - } - - // Sending header and payload in a single write makes a noticeable - // difference to "adb sync" performance. - std::vector buf(sizeof(SyncRequest) + path.length()); - SyncRequest* req = reinterpret_cast(&buf[0]); - req->id = id; - req->path_length = path.length(); - char* data = reinterpret_cast(req + 1); - memcpy(data, path.data(), path.length()); - return WriteFdExactly(fd, buf.data(), buf.size()); - } - - bool SendSend2(std::string_view path, mode_t mode, bool compressed) { - if (path.length() > 1024) { - Error("SendRequest failed: path too long: %zu", path.length()); - errno = ENAMETOOLONG; - return false; - } - - Block buf; - - SyncRequest req; - req.id = ID_SEND_V2; - req.path_length = path.length(); - - syncmsg msg; - msg.send_v2_setup.id = ID_SEND_V2; - msg.send_v2_setup.mode = mode; - msg.send_v2_setup.flags = compressed ? kSyncFlagBrotli : kSyncFlagNone; - - buf.resize(sizeof(SyncRequest) + path.length() + sizeof(msg.send_v2_setup)); - - void* p = buf.data(); - - p = mempcpy(p, &req, sizeof(SyncRequest)); - p = mempcpy(p, path.data(), path.length()); - p = mempcpy(p, &msg.send_v2_setup, sizeof(msg.send_v2_setup)); - - return WriteFdExactly(fd, buf.data(), buf.size()); - } - - bool SendRecv2(const std::string& path) { - if (path.length() > 1024) { - Error("SendRequest failed: path too long: %zu", path.length()); - errno = ENAMETOOLONG; - return false; - } - - Block buf; - - SyncRequest req; - req.id = ID_RECV_V2; - req.path_length = path.length(); - - syncmsg msg; - msg.recv_v2_setup.id = ID_RECV_V2; - msg.recv_v2_setup.flags = kSyncFlagBrotli; - - buf.resize(sizeof(SyncRequest) + path.length() + sizeof(msg.recv_v2_setup)); - - void* p = buf.data(); - - p = mempcpy(p, &req, sizeof(SyncRequest)); - p = mempcpy(p, path.data(), path.length()); - p = mempcpy(p, &msg.recv_v2_setup, sizeof(msg.recv_v2_setup)); - - return WriteFdExactly(fd, buf.data(), buf.size()); - } - - bool SendStat(const std::string& path) { - if (!have_stat_v2_) { - errno = ENOTSUP; - return false; - } - return SendRequest(ID_STAT_V2, path); - } - - bool SendLstat(const std::string& path) { - if (have_stat_v2_) { - return SendRequest(ID_LSTAT_V2, path); - } else { - return SendRequest(ID_LSTAT_V1, path); - } - } - - bool FinishStat(struct stat* st) { - syncmsg msg; - - memset(st, 0, sizeof(*st)); - if (have_stat_v2_) { - if (!ReadFdExactly(fd.get(), &msg.stat_v2, sizeof(msg.stat_v2))) { - PLOG(FATAL) << "protocol fault: failed to read stat response"; - } - - if (msg.stat_v2.id != ID_LSTAT_V2 && msg.stat_v2.id != ID_STAT_V2) { - PLOG(FATAL) << "protocol fault: stat response has wrong message id: " - << msg.stat_v2.id; - } - - if (msg.stat_v2.error != 0) { - errno = errno_from_wire(msg.stat_v2.error); - return false; - } - - st->st_dev = msg.stat_v2.dev; - st->st_ino = msg.stat_v2.ino; - st->st_mode = msg.stat_v2.mode; - st->st_nlink = msg.stat_v2.nlink; - st->st_uid = msg.stat_v2.uid; - st->st_gid = msg.stat_v2.gid; - st->st_size = msg.stat_v2.size; - st->st_atime = msg.stat_v2.atime; - st->st_mtime = msg.stat_v2.mtime; - st->st_ctime = msg.stat_v2.ctime; - return true; - } else { - if (!ReadFdExactly(fd.get(), &msg.stat_v1, sizeof(msg.stat_v1))) { - PLOG(FATAL) << "protocol fault: failed to read stat response"; - } - - if (msg.stat_v1.id != ID_LSTAT_V1) { - LOG(FATAL) << "protocol fault: stat response has wrong message id: " - << msg.stat_v1.id; - } - - if (msg.stat_v1.mode == 0 && msg.stat_v1.size == 0 && msg.stat_v1.mtime == 0) { - // There's no way for us to know what the error was. - errno = ENOPROTOOPT; - return false; - } - - st->st_mode = msg.stat_v1.mode; - st->st_size = msg.stat_v1.size; - st->st_ctime = msg.stat_v1.mtime; - st->st_mtime = msg.stat_v1.mtime; - } - - return true; - } - - bool SendLs(const std::string& path) { - return SendRequest(have_ls_v2_ ? ID_LIST_V2 : ID_LIST_V1, path); - } - - private: - template - static bool FinishLsImpl(borrowed_fd fd, const std::function& callback) { - using dent_type = - std::conditional_t; - - while (true) { - dent_type dent; - if (!ReadFdExactly(fd, &dent, sizeof(dent))) return false; - - uint32_t expected_id = v2 ? ID_DENT_V2 : ID_DENT_V1; - if (dent.id == ID_DONE) return true; - if (dent.id != expected_id) return false; - - // Maximum length of a file name excluding null terminator (NAME_MAX) on Linux is 255. - char buf[256]; - size_t len = dent.namelen; - if (len > 255) return false; - - if (!ReadFdExactly(fd, buf, len)) return false; - buf[len] = 0; - - callback(dent.mode, dent.size, dent.mtime, buf); - } - } - - public: - bool FinishLs(const std::function& callback) { - if (have_ls_v2_) { - return FinishLsImpl(this->fd, callback); - } else { - return FinishLsImpl(this->fd, callback); - } - } - - // Sending header, payload, and footer in a single write makes a huge - // difference to "adb sync" performance. - bool SendSmallFile(const std::string& path, mode_t mode, const std::string& lpath, - const std::string& rpath, unsigned mtime, const char* data, - size_t data_length) { - std::string path_and_mode = android::base::StringPrintf("%s,%d", path.c_str(), mode); - if (path_and_mode.length() > 1024) { - Error("SendSmallFile failed: path too long: %zu", path_and_mode.length()); - errno = ENAMETOOLONG; - return false; - } - - std::vector buf(sizeof(SyncRequest) + path_and_mode.length() + sizeof(SyncRequest) + - data_length + sizeof(SyncRequest)); - char* p = &buf[0]; - - SyncRequest* req_send = reinterpret_cast(p); - req_send->id = ID_SEND_V1; - req_send->path_length = path_and_mode.length(); - p += sizeof(SyncRequest); - memcpy(p, path_and_mode.data(), path_and_mode.size()); - p += path_and_mode.length(); - - SyncRequest* req_data = reinterpret_cast(p); - req_data->id = ID_DATA; - req_data->path_length = data_length; - p += sizeof(SyncRequest); - memcpy(p, data, data_length); - p += data_length; - - SyncRequest* req_done = reinterpret_cast(p); - req_done->id = ID_DONE; - req_done->path_length = mtime; - p += sizeof(SyncRequest); - - WriteOrDie(lpath, rpath, &buf[0], (p - &buf[0])); - - RecordFileSent(lpath, rpath); - RecordBytesTransferred(data_length); - ReportProgress(rpath, data_length, data_length); - return true; - } - - bool SendLargeFileCompressed(const std::string& path, mode_t mode, const std::string& lpath, - const std::string& rpath, unsigned mtime) { - if (!SendSend2(path, mode, true)) { - Error("failed to send ID_SEND_V2 message '%s': %s", path.c_str(), strerror(errno)); - return false; - } - - struct stat st; - if (stat(lpath.c_str(), &st) == -1) { - Error("cannot stat '%s': %s", lpath.c_str(), strerror(errno)); - return false; - } - - uint64_t total_size = st.st_size; - uint64_t bytes_copied = 0; - - unique_fd lfd(adb_open(lpath.c_str(), O_RDONLY | O_CLOEXEC)); - if (lfd < 0) { - Error("opening '%s' locally failed: %s", lpath.c_str(), strerror(errno)); - return false; - } - - syncsendbuf sbuf; - sbuf.id = ID_DATA; - - BrotliEncoder encoder; - bool sending = true; - while (sending) { - Block input(SYNC_DATA_MAX); - int r = adb_read(lfd.get(), input.data(), input.size()); - if (r < 0) { - Error("reading '%s' locally failed: %s", lpath.c_str(), strerror(errno)); - return false; - } - - if (r == 0) { - encoder.Finish(); - } else { - input.resize(r); - encoder.Append(std::move(input)); - RecordBytesTransferred(r); - bytes_copied += r; - ReportProgress(rpath, bytes_copied, total_size); - } - - while (true) { - Block output; - BrotliEncodeResult result = encoder.Encode(&output); - if (result == BrotliEncodeResult::Error) { - Error("compressing '%s' locally failed", lpath.c_str()); - return false; - } - - if (!output.empty()) { - sbuf.size = output.size(); - memcpy(sbuf.data, output.data(), output.size()); - WriteOrDie(lpath, rpath, &sbuf, sizeof(SyncRequest) + output.size()); - } - - if (result == BrotliEncodeResult::Done) { - sending = false; - break; - } else if (result == BrotliEncodeResult::NeedInput) { - break; - } else if (result == BrotliEncodeResult::MoreOutput) { - continue; - } - } - } - - syncmsg msg; - msg.data.id = ID_DONE; - msg.data.size = mtime; - RecordFileSent(lpath, rpath); - return WriteOrDie(lpath, rpath, &msg.data, sizeof(msg.data)); - } - - bool SendLargeFile(const std::string& path, mode_t mode, const std::string& lpath, - const std::string& rpath, unsigned mtime, bool compressed) { - if (compressed && HaveSendRecv2Brotli()) { - return SendLargeFileCompressed(path, mode, lpath, rpath, mtime); - } - - std::string path_and_mode = android::base::StringPrintf("%s,%d", path.c_str(), mode); - if (!SendRequest(ID_SEND_V1, path_and_mode)) { - Error("failed to send ID_SEND_V1 message '%s': %s", path_and_mode.c_str(), - strerror(errno)); - return false; - } - - struct stat st; - if (stat(lpath.c_str(), &st) == -1) { - Error("cannot stat '%s': %s", lpath.c_str(), strerror(errno)); - return false; - } - - uint64_t total_size = st.st_size; - uint64_t bytes_copied = 0; - - unique_fd lfd(adb_open(lpath.c_str(), O_RDONLY | O_CLOEXEC)); - if (lfd < 0) { - Error("opening '%s' locally failed: %s", lpath.c_str(), strerror(errno)); - return false; - } - - syncsendbuf sbuf; - sbuf.id = ID_DATA; - - while (true) { - int bytes_read = adb_read(lfd, sbuf.data, max); - if (bytes_read == -1) { - Error("reading '%s' locally failed: %s", lpath.c_str(), strerror(errno)); - return false; - } else if (bytes_read == 0) { - break; - } - - sbuf.size = bytes_read; - WriteOrDie(lpath, rpath, &sbuf, sizeof(SyncRequest) + bytes_read); - - RecordBytesTransferred(bytes_read); - bytes_copied += bytes_read; - ReportProgress(rpath, bytes_copied, total_size); - } - - syncmsg msg; - msg.data.id = ID_DONE; - msg.data.size = mtime; - RecordFileSent(lpath, rpath); - return WriteOrDie(lpath, rpath, &msg.data, sizeof(msg.data)); - } - - bool ReportCopyFailure(const std::string& from, const std::string& to, const syncmsg& msg) { - std::vector buf(msg.status.msglen + 1); - if (!ReadFdExactly(fd, &buf[0], msg.status.msglen)) { - Error("failed to copy '%s' to '%s'; failed to read reason (!): %s", from.c_str(), - to.c_str(), strerror(errno)); - return false; - } - buf[msg.status.msglen] = 0; - Error("failed to copy '%s' to '%s': remote %s", from.c_str(), to.c_str(), &buf[0]); - return false; - } - - void CopyDone() { deferred_acknowledgements_.pop_front(); } - - void ReportDeferredCopyFailure(const std::string& msg) { - auto& [from, to] = deferred_acknowledgements_.front(); - Error("failed to copy '%s' to '%s': remote %s", from.c_str(), to.c_str(), msg.c_str()); - deferred_acknowledgements_.pop_front(); - } - - bool ReadAcknowledgements(bool read_all = false) { - // We need to read enough such that adbd's intermediate socket's write buffer can't be - // full. The default buffer on Linux is 212992 bytes, but there's 576 bytes of bookkeeping - // overhead per write. The worst case scenario is a continuous string of failures, since - // each logical packet is divided into two writes. If our packet size if conservatively 512 - // bytes long, this leaves us with space for 128 responses. - constexpr size_t max_deferred_acks = 128; - auto& buf = acknowledgement_buffer_; - adb_pollfd pfd = {.fd = fd.get(), .events = POLLIN}; - while (!deferred_acknowledgements_.empty()) { - bool should_block = read_all || deferred_acknowledgements_.size() >= max_deferred_acks; - - ssize_t rc = adb_poll(&pfd, 1, should_block ? -1 : 0); - if (rc == 0) { - CHECK(!should_block); - return true; - } - - if (acknowledgement_buffer_.size() < sizeof(sync_status)) { - const ssize_t header_bytes_left = sizeof(sync_status) - buf.size(); - ssize_t rc = adb_read(fd, buf.end(), header_bytes_left); - if (rc <= 0) { - Error("failed to read copy response"); - return false; - } - - buf.resize(buf.size() + rc); - if (rc != header_bytes_left) { - // Early exit if we run out of data in the socket. - return true; - } - - if (!should_block) { - // We don't want to read again yet, because the socket might be empty. - continue; - } - } - - auto* hdr = reinterpret_cast(buf.data()); - if (hdr->id == ID_OKAY) { - buf.resize(0); - if (hdr->msglen != 0) { - Error("received ID_OKAY with msg_len (%" PRIu32 " != 0", hdr->msglen); - return false; - } - CopyDone(); - continue; - } else if (hdr->id != ID_FAIL) { - Error("unexpected response from daemon: id = %#" PRIx32, hdr->id); - return false; - } else if (hdr->msglen > SYNC_DATA_MAX) { - Error("too-long message length from daemon: msglen = %" PRIu32, hdr->msglen); - return false; - } - - const ssize_t msg_bytes_left = hdr->msglen + sizeof(sync_status) - buf.size(); - CHECK_GE(msg_bytes_left, 0); - if (msg_bytes_left > 0) { - ssize_t rc = adb_read(fd, buf.end(), msg_bytes_left); - if (rc <= 0) { - Error("failed to read copy failure message"); - return false; - } - - buf.resize(buf.size() + rc); - if (rc != msg_bytes_left) { - if (should_block) { - continue; - } else { - return true; - } - } - - std::string msg(buf.begin() + sizeof(sync_status), buf.end()); - ReportDeferredCopyFailure(msg); - buf.resize(0); - return false; - } - } - - return true; - } - - void Printf(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) { - std::string s; - - va_list ap; - va_start(ap, fmt); - android::base::StringAppendV(&s, fmt, ap); - va_end(ap); - - line_printer_.Print(s, LinePrinter::INFO); - } - - void Println(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) { - std::string s; - - va_list ap; - va_start(ap, fmt); - android::base::StringAppendV(&s, fmt, ap); - va_end(ap); - - line_printer_.Print(s, LinePrinter::INFO); - line_printer_.KeepInfoLine(); - } - - void Error(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) { - std::string s = "adb: error: "; - - va_list ap; - va_start(ap, fmt); - android::base::StringAppendV(&s, fmt, ap); - va_end(ap); - - line_printer_.Print(s, LinePrinter::ERROR); - } - - void Warning(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) { - std::string s = "adb: warning: "; - - va_list ap; - va_start(ap, fmt); - android::base::StringAppendV(&s, fmt, ap); - va_end(ap); - - line_printer_.Print(s, LinePrinter::WARNING); - } - - void ComputeExpectedTotalBytes(const std::vector& file_list) { - current_ledger_.bytes_expected = 0; - for (const copyinfo& ci : file_list) { - // Unfortunately, this doesn't work for symbolic links, because we'll copy the - // target of the link rather than just creating a link. (But ci.size is the link size.) - if (!ci.skip) current_ledger_.bytes_expected += ci.size; - } - current_ledger_.expect_multiple_files = true; - } - - void SetExpectedTotalBytes(uint64_t expected_total_bytes) { - current_ledger_.bytes_expected = expected_total_bytes; - current_ledger_.expect_multiple_files = false; - } - - // TODO: add a char[max] buffer here, to replace syncsendbuf... - unique_fd fd; - size_t max; - - private: - std::deque> deferred_acknowledgements_; - Block acknowledgement_buffer_; - FeatureSet features_; - bool have_stat_v2_; - bool have_ls_v2_; - bool have_sendrecv_v2_; - bool have_sendrecv_v2_brotli_; - - TransferLedger global_ledger_; - TransferLedger current_ledger_; - LinePrinter line_printer_; - - bool SendQuit() { - return SendRequest(ID_QUIT, ""); // TODO: add a SendResponse? - } - - bool WriteOrDie(const std::string& from, const std::string& to, const void* data, - size_t data_length) { - if (!WriteFdExactly(fd, data, data_length)) { - if (errno == ECONNRESET) { - // Assume adbd told us why it was closing the connection, and - // try to read failure reason from adbd. - syncmsg msg; - if (!ReadFdExactly(fd, &msg.status, sizeof(msg.status))) { - Error("failed to copy '%s' to '%s': no response: %s", from.c_str(), to.c_str(), - strerror(errno)); - } else if (msg.status.id != ID_FAIL) { - Error("failed to copy '%s' to '%s': not ID_FAIL: %d", from.c_str(), to.c_str(), - msg.status.id); - } else { - ReportCopyFailure(from, to, msg); - } - } else { - Error("%zu-byte write failed: %s", data_length, strerror(errno)); - } - _exit(1); - } - return true; - } -}; - -static bool sync_ls(SyncConnection& sc, const std::string& path, - const std::function& func) { - return sc.SendLs(path) && sc.FinishLs(func); -} - -static bool sync_stat(SyncConnection& sc, const std::string& path, struct stat* st) { - return sc.SendStat(path) && sc.FinishStat(st); -} - -static bool sync_lstat(SyncConnection& sc, const std::string& path, struct stat* st) { - return sc.SendLstat(path) && sc.FinishStat(st); -} - -static bool sync_stat_fallback(SyncConnection& sc, const std::string& path, struct stat* st) { - if (sync_stat(sc, path, st)) { - return true; - } - - if (errno != ENOTSUP) { - return false; - } - - // Try to emulate the parts we can when talking to older adbds. - bool lstat_result = sync_lstat(sc, path, st); - if (!lstat_result) { - return false; - } - - if (S_ISLNK(st->st_mode)) { - // If the target is a symlink, figure out whether it's a file or a directory. - // Also, zero out the st_size field, since no one actually cares what the path length is. - st->st_size = 0; - std::string dir_path = path; - dir_path.push_back('/'); - struct stat tmp_st; - - st->st_mode &= ~S_IFMT; - if (sync_lstat(sc, dir_path, &tmp_st)) { - st->st_mode |= S_IFDIR; - } else { - st->st_mode |= S_IFREG; - } - } - return true; -} - -static bool sync_send(SyncConnection& sc, const std::string& lpath, const std::string& rpath, - unsigned mtime, mode_t mode, bool sync, bool compressed) { - if (sync) { - struct stat st; - if (sync_lstat(sc, rpath, &st)) { - if (st.st_mtime == static_cast(mtime)) { - sc.RecordFilesSkipped(1); - return true; - } - } - } - - if (S_ISLNK(mode)) { -#if !defined(_WIN32) - char buf[PATH_MAX]; - ssize_t data_length = readlink(lpath.c_str(), buf, PATH_MAX - 1); - if (data_length == -1) { - sc.Error("readlink '%s' failed: %s", lpath.c_str(), strerror(errno)); - return false; - } - buf[data_length++] = '\0'; - - if (!sc.SendSmallFile(rpath, mode, lpath, rpath, mtime, buf, data_length)) { - return false; - } - return sc.ReadAcknowledgements(); -#endif - } - - struct stat st; - if (stat(lpath.c_str(), &st) == -1) { - sc.Error("failed to stat local file '%s': %s", lpath.c_str(), strerror(errno)); - return false; - } - if (st.st_size < SYNC_DATA_MAX) { - std::string data; - if (!android::base::ReadFileToString(lpath, &data, true)) { - sc.Error("failed to read all of '%s': %s", lpath.c_str(), strerror(errno)); - return false; - } - if (!sc.SendSmallFile(rpath, mode, lpath, rpath, mtime, data.data(), data.size())) { - return false; - } - } else { - if (!sc.SendLargeFile(rpath, mode, lpath, rpath, mtime, compressed)) { - return false; - } - } - return sc.ReadAcknowledgements(); -} - -static bool sync_recv_v1(SyncConnection& sc, const char* rpath, const char* lpath, const char* name, - uint64_t expected_size) { - if (!sc.SendRequest(ID_RECV_V1, rpath)) return false; - - adb_unlink(lpath); - unique_fd lfd(adb_creat(lpath, 0644)); - if (lfd < 0) { - sc.Error("cannot create '%s': %s", lpath, strerror(errno)); - return false; - } - - uint64_t bytes_copied = 0; - while (true) { - syncmsg msg; - if (!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) { - adb_unlink(lpath); - return false; - } - - if (msg.data.id == ID_DONE) break; - - if (msg.data.id != ID_DATA) { - adb_unlink(lpath); - sc.ReportCopyFailure(rpath, lpath, msg); - return false; - } - - if (msg.data.size > sc.max) { - sc.Error("msg.data.size too large: %u (max %zu)", msg.data.size, sc.max); - adb_unlink(lpath); - return false; - } - - char buffer[SYNC_DATA_MAX]; - if (!ReadFdExactly(sc.fd, buffer, msg.data.size)) { - adb_unlink(lpath); - return false; - } - - if (!WriteFdExactly(lfd, buffer, msg.data.size)) { - sc.Error("cannot write '%s': %s", lpath, strerror(errno)); - adb_unlink(lpath); - return false; - } - - bytes_copied += msg.data.size; - - sc.RecordBytesTransferred(msg.data.size); - sc.ReportProgress(name != nullptr ? name : rpath, bytes_copied, expected_size); - } - - sc.RecordFilesTransferred(1); - return true; -} - -static bool sync_recv_v2(SyncConnection& sc, const char* rpath, const char* lpath, const char* name, - uint64_t expected_size) { - if (!sc.SendRecv2(rpath)) return false; - - adb_unlink(lpath); - unique_fd lfd(adb_creat(lpath, 0644)); - if (lfd < 0) { - sc.Error("cannot create '%s': %s", lpath, strerror(errno)); - return false; - } - - uint64_t bytes_copied = 0; - - Block buffer(SYNC_DATA_MAX); - BrotliDecoder decoder(std::span(buffer.data(), buffer.size())); - bool reading = true; - while (reading) { - syncmsg msg; - if (!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) { - adb_unlink(lpath); - return false; - } - - if (msg.data.id == ID_DONE) { - adb_unlink(lpath); - sc.Error("unexpected ID_DONE"); - return false; - } - - if (msg.data.id != ID_DATA) { - adb_unlink(lpath); - sc.ReportCopyFailure(rpath, lpath, msg); - return false; - } - - if (msg.data.size > sc.max) { - sc.Error("msg.data.size too large: %u (max %zu)", msg.data.size, sc.max); - adb_unlink(lpath); - return false; - } - - Block block(msg.data.size); - if (!ReadFdExactly(sc.fd, block.data(), msg.data.size)) { - adb_unlink(lpath); - return false; - } - decoder.Append(std::move(block)); - - while (true) { - std::span output; - BrotliDecodeResult result = decoder.Decode(&output); - - if (result == BrotliDecodeResult::Error) { - sc.Error("decompress failed"); - adb_unlink(lpath); - return false; - } - - if (!output.empty()) { - if (!WriteFdExactly(lfd, output.data(), output.size())) { - sc.Error("cannot write '%s': %s", lpath, strerror(errno)); - adb_unlink(lpath); - return false; - } - } - - bytes_copied += output.size(); - - sc.RecordBytesTransferred(msg.data.size); - sc.ReportProgress(name != nullptr ? name : rpath, bytes_copied, expected_size); - - if (result == BrotliDecodeResult::NeedInput) { - break; - } else if (result == BrotliDecodeResult::MoreOutput) { - continue; - } else if (result == BrotliDecodeResult::Done) { - reading = false; - break; - } else { - LOG(FATAL) << "invalid BrotliDecodeResult: " << static_cast(result); - } - } - } - - syncmsg msg; - if (!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) { - sc.Error("failed to read ID_DONE"); - return false; - } - - if (msg.data.id != ID_DONE) { - sc.Error("unexpected message after transfer: id = %d (expected ID_DONE)", msg.data.id); - return false; - } - - sc.RecordFilesTransferred(1); - return true; -} - -static bool sync_recv(SyncConnection& sc, const char* rpath, const char* lpath, const char* name, - uint64_t expected_size, bool compressed) { - if (sc.HaveSendRecv2() && compressed) { - return sync_recv_v2(sc, rpath, lpath, name, expected_size); - } else { - return sync_recv_v1(sc, rpath, lpath, name, expected_size); - } -} - -bool do_sync_ls(const char* path) { - SyncConnection sc; - if (!sc.IsValid()) return false; - - return sync_ls(sc, path, [](unsigned mode, uint64_t size, uint64_t time, const char* name) { - printf("%08x %08" PRIx64 " %08" PRIx64 " %s\n", mode, size, time, name); - }); -} - -static bool IsDotOrDotDot(const char* name) { - return name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')); -} - -static bool local_build_list(SyncConnection& sc, std::vector* file_list, - std::vector* directory_list, const std::string& lpath, - const std::string& rpath) { - std::vector dirlist; - std::unique_ptr dir(opendir(lpath.c_str()), closedir); - if (!dir) { - sc.Error("cannot open '%s': %s", lpath.c_str(), strerror(errno)); - return false; - } - - bool empty_dir = true; - dirent* de; - while ((de = readdir(dir.get()))) { - if (IsDotOrDotDot(de->d_name)) { - continue; - } - - empty_dir = false; - std::string stat_path = lpath + de->d_name; - - struct stat st; - if (lstat(stat_path.c_str(), &st) == -1) { - sc.Error("cannot lstat '%s': %s", stat_path.c_str(), - strerror(errno)); - continue; - } - - copyinfo ci(lpath, rpath, de->d_name, st.st_mode); - if (S_ISDIR(st.st_mode)) { - dirlist.push_back(ci); - } else { - if (!should_push_file(st.st_mode)) { - sc.Warning("skipping special file '%s' (mode = 0o%o)", lpath.c_str(), st.st_mode); - ci.skip = true; - } - ci.time = st.st_mtime; - ci.size = st.st_size; - file_list->push_back(ci); - } - } - - // Close this directory and recurse. - dir.reset(); - - for (const copyinfo& ci : dirlist) { - directory_list->push_back(ci.rpath); - local_build_list(sc, file_list, directory_list, ci.lpath, ci.rpath); - } - - return true; -} - -// dirname("//foo") returns "//", so we can't do the obvious `path == "/"`. -static bool is_root_dir(std::string_view path) { - for (char c : path) { - if (c != '/') { - return false; - } - } - return true; -} - -static bool copy_local_dir_remote(SyncConnection& sc, std::string lpath, std::string rpath, - bool check_timestamps, bool list_only, bool compressed) { - sc.NewTransfer(); - - // Make sure that both directory paths end in a slash. - // Both paths are known to be nonempty, so we don't need to check. - ensure_trailing_separators(lpath, rpath); - - // Recursively build the list of files to copy. - std::vector file_list; - std::vector directory_list; - - for (std::string path = rpath; !is_root_dir(path); path = android::base::Dirname(path)) { - directory_list.push_back(path); - } - std::reverse(directory_list.begin(), directory_list.end()); - - int skipped = 0; - if (!local_build_list(sc, &file_list, &directory_list, lpath, rpath)) { - return false; - } - - // b/110953234: - // P shipped with a bug that causes directory creation as a side-effect of a push to fail. - // Work around this by explicitly doing a mkdir via shell. - // - // Devices that don't support shell_v2 are unhappy if we try to send a too-long packet to them, - // but they're not affected by this bug, so only apply the workaround if we have shell_v2. - // - // TODO(b/25457350): We don't preserve permissions on directories. - // TODO: Find all of the leaves and `mkdir -p` them instead? - if (!CanUseFeature(sc.Features(), kFeatureFixedPushMkdir) && - CanUseFeature(sc.Features(), kFeatureShell2)) { - SilentStandardStreamsCallbackInterface cb; - std::string cmd = "mkdir"; - for (const auto& dir : directory_list) { - std::string escaped_path = escape_arg(dir); - if (escaped_path.size() > 16384) { - // Somewhat arbitrarily limit that probably won't ever happen. - sc.Error("path too long: %s", escaped_path.c_str()); - return false; - } - - // The maximum should be 64kiB, but that's not including other stuff that gets tacked - // onto the command line, so let's be a bit conservative. - if (cmd.size() + escaped_path.size() > 32768) { - // Dispatch the command, ignoring failure (since the directory might already exist). - send_shell_command(cmd, false, &cb); - cmd = "mkdir"; - } - cmd += " "; - cmd += escaped_path; - } - - if (cmd != "mkdir") { - send_shell_command(cmd, false, &cb); - } - } - - if (check_timestamps) { - for (const copyinfo& ci : file_list) { - if (!sc.SendLstat(ci.rpath)) { - sc.Error("failed to send lstat"); - return false; - } - } - for (copyinfo& ci : file_list) { - struct stat st; - if (sc.FinishStat(&st)) { - if (st.st_size == static_cast(ci.size) && st.st_mtime == ci.time) { - ci.skip = true; - } - } - } - } - - sc.ComputeExpectedTotalBytes(file_list); - - for (const copyinfo& ci : file_list) { - if (!ci.skip) { - if (list_only) { - sc.Println("would push: %s -> %s", ci.lpath.c_str(), ci.rpath.c_str()); - } else { - if (!sync_send(sc, ci.lpath, ci.rpath, ci.time, ci.mode, false, compressed)) { - return false; - } - } - } else { - skipped++; - } - } - - sc.RecordFilesSkipped(skipped); - bool success = sc.ReadAcknowledgements(true); - sc.ReportTransferRate(lpath, TransferDirection::push); - return success; -} - -bool do_sync_push(const std::vector& srcs, const char* dst, bool sync, - bool compressed) { - SyncConnection sc; - if (!sc.IsValid()) return false; - - bool success = true; - bool dst_exists; - bool dst_isdir; - - struct stat st; - if (sync_stat_fallback(sc, dst, &st)) { - dst_exists = true; - dst_isdir = S_ISDIR(st.st_mode); - } else { - if (errno == ENOENT || errno == ENOPROTOOPT) { - dst_exists = false; - dst_isdir = false; - } else { - sc.Error("stat failed when trying to push to %s: %s", dst, strerror(errno)); - return false; - } - } - - if (!dst_isdir) { - if (srcs.size() > 1) { - sc.Error("target '%s' is not a directory", dst); - return false; - } else { - size_t dst_len = strlen(dst); - - // A path that ends with a slash doesn't have to be a directory if - // it doesn't exist yet. - if (dst[dst_len - 1] == '/' && dst_exists) { - sc.Error("failed to access '%s': Not a directory", dst); - return false; - } - } - } - - for (const char* src_path : srcs) { - const char* dst_path = dst; - struct stat st; - if (stat(src_path, &st) == -1) { - sc.Error("cannot stat '%s': %s", src_path, strerror(errno)); - success = false; - continue; - } - - if (S_ISDIR(st.st_mode)) { - std::string dst_dir = dst; - - // If the destination path existed originally, the source directory - // should be copied as a child of the destination. - if (dst_exists) { - if (!dst_isdir) { - sc.Error("target '%s' is not a directory", dst); - return false; - } - // dst is a POSIX path, so we don't want to use the sysdeps - // helpers here. - if (dst_dir.back() != '/') { - dst_dir.push_back('/'); - } - dst_dir.append(android::base::Basename(src_path)); - } - - success &= copy_local_dir_remote(sc, src_path, dst_dir, sync, false, compressed); - continue; - } else if (!should_push_file(st.st_mode)) { - sc.Warning("skipping special file '%s' (mode = 0o%o)", src_path, st.st_mode); - continue; - } - - std::string path_holder; - if (dst_isdir) { - // If we're copying a local file to a remote directory, - // we really want to copy to remote_dir + "/" + local_filename. - path_holder = dst_path; - if (path_holder.back() != '/') { - path_holder.push_back('/'); - } - path_holder += android::base::Basename(src_path); - dst_path = path_holder.c_str(); - } - - sc.NewTransfer(); - sc.SetExpectedTotalBytes(st.st_size); - success &= sync_send(sc, src_path, dst_path, st.st_mtime, st.st_mode, sync, compressed); - sc.ReportTransferRate(src_path, TransferDirection::push); - } - - success &= sc.ReadAcknowledgements(true); - sc.ReportOverallTransferRate(TransferDirection::push); - return success; -} - -static bool remote_build_list(SyncConnection& sc, std::vector* file_list, - const std::string& rpath, const std::string& lpath) { - std::vector dirlist; - std::vector linklist; - - // Add an entry for the current directory to ensure it gets created before pulling its contents. - copyinfo ci(android::base::Dirname(lpath), android::base::Dirname(rpath), - android::base::Basename(lpath), S_IFDIR); - file_list->push_back(ci); - - // Put the files/dirs in rpath on the lists. - auto callback = [&](unsigned mode, uint64_t size, uint64_t time, const char* name) { - if (IsDotOrDotDot(name)) { - return; - } - - copyinfo ci(lpath, rpath, name, mode); - if (S_ISDIR(mode)) { - dirlist.push_back(ci); - } else if (S_ISLNK(mode)) { - linklist.push_back(ci); - } else { - if (!should_pull_file(ci.mode)) { - sc.Warning("skipping special file '%s' (mode = 0o%o)", ci.rpath.c_str(), ci.mode); - ci.skip = true; - } - ci.time = time; - ci.size = size; - file_list->push_back(ci); - } - }; - - if (!sync_ls(sc, rpath.c_str(), callback)) { - return false; - } - - // Check each symlink we found to see whether it's a file or directory. - for (copyinfo& link_ci : linklist) { - struct stat st; - if (!sync_stat_fallback(sc, link_ci.rpath.c_str(), &st)) { - sc.Warning("stat failed for path %s: %s", link_ci.rpath.c_str(), strerror(errno)); - continue; - } - - if (S_ISDIR(st.st_mode)) { - dirlist.emplace_back(std::move(link_ci)); - } else { - file_list->emplace_back(std::move(link_ci)); - } - } - - // Recurse into each directory we found. - while (!dirlist.empty()) { - copyinfo current = dirlist.back(); - dirlist.pop_back(); - if (!remote_build_list(sc, file_list, current.rpath, current.lpath)) { - return false; - } - } - - return true; -} - -static int set_time_and_mode(const std::string& lpath, time_t time, - unsigned int mode) { - struct utimbuf times = { time, time }; - int r1 = utime(lpath.c_str(), ×); - - /* use umask for permissions */ - mode_t mask = umask(0000); - umask(mask); - int r2 = chmod(lpath.c_str(), mode & ~mask); - - return r1 ? r1 : r2; -} - -static bool copy_remote_dir_local(SyncConnection& sc, std::string rpath, std::string lpath, - bool copy_attrs, bool compressed) { - sc.NewTransfer(); - - // Make sure that both directory paths end in a slash. - // Both paths are known to be nonempty, so we don't need to check. - ensure_trailing_separators(lpath, rpath); - - // Recursively build the list of files to copy. - sc.Printf("pull: building file list..."); - std::vector file_list; - if (!remote_build_list(sc, &file_list, rpath, lpath)) { - return false; - } - - sc.ComputeExpectedTotalBytes(file_list); - - int skipped = 0; - for (const copyinfo &ci : file_list) { - if (!ci.skip) { - if (S_ISDIR(ci.mode)) { - // Entry is for an empty directory, create it and continue. - // TODO(b/25457350): We don't preserve permissions on directories. - if (!mkdirs(ci.lpath)) { - sc.Error("failed to create directory '%s': %s", - ci.lpath.c_str(), strerror(errno)); - return false; - } - continue; - } - - if (!sync_recv(sc, ci.rpath.c_str(), ci.lpath.c_str(), nullptr, ci.size, compressed)) { - return false; - } - - if (copy_attrs && set_time_and_mode(ci.lpath, ci.time, ci.mode)) { - return false; - } - } else { - skipped++; - } - } - - sc.RecordFilesSkipped(skipped); - sc.ReportTransferRate(rpath, TransferDirection::pull); - return true; -} - -bool do_sync_pull(const std::vector& srcs, const char* dst, bool copy_attrs, - bool compressed, const char* name) { - SyncConnection sc; - if (!sc.IsValid()) return false; - - bool success = true; - struct stat st; - bool dst_exists = true; - - if (stat(dst, &st) == -1) { - dst_exists = false; - - // If we're only pulling one path, the destination path might point to - // a path that doesn't exist yet. - if (srcs.size() == 1 && errno == ENOENT) { - // However, its parent must exist. - struct stat parent_st; - if (stat(android::base::Dirname(dst).c_str(), &parent_st) == -1) { - sc.Error("cannot create file/directory '%s': %s", dst, strerror(errno)); - return false; - } - } else { - sc.Error("failed to access '%s': %s", dst, strerror(errno)); - return false; - } - } - - bool dst_isdir = dst_exists && S_ISDIR(st.st_mode); - if (!dst_isdir) { - if (srcs.size() > 1) { - sc.Error("target '%s' is not a directory", dst); - return false; - } else { - size_t dst_len = strlen(dst); - - // A path that ends with a slash doesn't have to be a directory if - // it doesn't exist yet. - if (adb_is_separator(dst[dst_len - 1]) && dst_exists) { - sc.Error("failed to access '%s': Not a directory", dst); - return false; - } - } - } - - for (const char* src_path : srcs) { - const char* dst_path = dst; - struct stat src_st; - if (!sync_stat_fallback(sc, src_path, &src_st)) { - if (errno == ENOPROTOOPT) { - sc.Error("remote object '%s' does not exist", src_path); - } else { - sc.Error("failed to stat remote object '%s': %s", src_path, strerror(errno)); - } - - success = false; - continue; - } - - bool src_isdir = S_ISDIR(src_st.st_mode); - if (src_isdir) { - std::string dst_dir = dst; - - // If the destination path existed originally, the source directory - // should be copied as a child of the destination. - if (dst_exists) { - if (!dst_isdir) { - sc.Error("target '%s' is not a directory", dst); - return false; - } - if (!adb_is_separator(dst_dir.back())) { - dst_dir.push_back(OS_PATH_SEPARATOR); - } - dst_dir.append(android::base::Basename(src_path)); - } - - success &= copy_remote_dir_local(sc, src_path, dst_dir, copy_attrs, compressed); - continue; - } else if (!should_pull_file(src_st.st_mode)) { - sc.Warning("skipping special file '%s' (mode = 0o%o)", src_path, src_st.st_mode); - continue; - } - - std::string path_holder; - if (dst_isdir) { - // If we're copying a remote file to a local directory, we - // really want to copy to local_dir + OS_PATH_SEPARATOR + - // basename(remote). - path_holder = android::base::StringPrintf("%s%c%s", dst_path, OS_PATH_SEPARATOR, - android::base::Basename(src_path).c_str()); - dst_path = path_holder.c_str(); - } - - sc.NewTransfer(); - sc.SetExpectedTotalBytes(src_st.st_size); - if (!sync_recv(sc, src_path, dst_path, name, src_st.st_size, compressed)) { - success = false; - continue; - } - - if (copy_attrs && set_time_and_mode(dst_path, src_st.st_mtime, src_st.st_mode) != 0) { - success = false; - continue; - } - sc.ReportTransferRate(src_path, TransferDirection::pull); - } - - sc.ReportOverallTransferRate(TransferDirection::pull); - return success; -} - -bool do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only, - bool compressed) { - SyncConnection sc; - if (!sc.IsValid()) return false; - - bool success = copy_local_dir_remote(sc, lpath, rpath, true, list_only, compressed); - if (!list_only) { - sc.ReportOverallTransferRate(TransferDirection::push); - } - return success; -} diff --git a/adb/client/file_sync_client.h b/adb/client/file_sync_client.h deleted file mode 100644 index de3f1924569425ca9045f0e0df8e6855ccecfa55..0000000000000000000000000000000000000000 --- a/adb/client/file_sync_client.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2018 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. - */ - -#pragma once - -#include -#include - -bool do_sync_ls(const char* path); -bool do_sync_push(const std::vector& srcs, const char* dst, bool sync, - bool compressed); -bool do_sync_pull(const std::vector& srcs, const char* dst, bool copy_attrs, - bool compressed, const char* name = nullptr); - -bool do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only, - bool compressed); diff --git a/adb/client/incremental.cpp b/adb/client/incremental.cpp deleted file mode 100644 index c8f69c381245c466ac326dfcbac5ee0cbffb5512..0000000000000000000000000000000000000000 --- a/adb/client/incremental.cpp +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright (C) 2020 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 "incremental.h" - -#include "incremental_utils.h" - -#include -#include -#include - -#include "adb_client.h" -#include "adb_utils.h" -#include "commandline.h" -#include "sysdeps.h" - -using namespace std::literals; - -namespace incremental { - -using android::base::StringPrintf; - -// Read, verify and return the signature bytes. Keeping fd at the position of start of verity tree. -static std::pair> read_signature(Size file_size, - std::string signature_file, - bool silent) { - signature_file += IDSIG; - - struct stat st; - if (stat(signature_file.c_str(), &st)) { - if (!silent) { - fprintf(stderr, "Failed to stat signature file %s. Abort.\n", signature_file.c_str()); - } - return {}; - } - - unique_fd fd(adb_open(signature_file.c_str(), O_RDONLY)); - if (fd < 0) { - if (!silent) { - fprintf(stderr, "Failed to open signature file: %s. Abort.\n", signature_file.c_str()); - } - return {}; - } - - auto [signature, tree_size] = read_id_sig_headers(fd); - if (auto expected = verity_tree_size_for_file(file_size); tree_size != expected) { - if (!silent) { - fprintf(stderr, - "Verity tree size mismatch in signature file: %s [was %lld, expected %lld].\n", - signature_file.c_str(), (long long)tree_size, (long long)expected); - } - return {}; - } - - return {std::move(fd), std::move(signature)}; -} - -// Base64-encode signature bytes. Keeping fd at the position of start of verity tree. -static std::pair read_and_encode_signature(Size file_size, - std::string signature_file, - bool silent) { - auto [fd, signature] = read_signature(file_size, std::move(signature_file), silent); - if (!fd.ok()) { - return {}; - } - - size_t base64_len = 0; - if (!EVP_EncodedLength(&base64_len, signature.size())) { - if (!silent) { - fprintf(stderr, "Fail to estimate base64 encoded length. Abort.\n"); - } - return {}; - } - std::string encoded_signature(base64_len, '\0'); - encoded_signature.resize(EVP_EncodeBlock((uint8_t*)encoded_signature.data(), - (const uint8_t*)signature.data(), signature.size())); - - return {std::move(fd), std::move(encoded_signature)}; -} - -// Send install-incremental to the device along with properly configured file descriptors in -// streaming format. Once connection established, send all fs-verity tree bytes. -static unique_fd start_install(const Files& files, const Args& passthrough_args, bool silent) { - std::vector command_args{"package", "install-incremental"}; - command_args.insert(command_args.end(), passthrough_args.begin(), passthrough_args.end()); - - for (int i = 0, size = files.size(); i < size; ++i) { - const auto& file = files[i]; - - struct stat st; - if (stat(file.c_str(), &st)) { - if (!silent) { - fprintf(stderr, "Failed to stat input file %s. Abort.\n", file.c_str()); - } - return {}; - } - - auto [signature_fd, signature] = read_and_encode_signature(st.st_size, file, silent); - if (!signature_fd.ok()) { - return {}; - } - - auto file_desc = StringPrintf("%s:%lld:%d:%s:1", android::base::Basename(file).c_str(), - (long long)st.st_size, i, signature.c_str()); - command_args.push_back(std::move(file_desc)); - } - - std::string error; - auto connection_fd = unique_fd(send_abb_exec_command(command_args, &error)); - if (connection_fd < 0) { - if (!silent) { - fprintf(stderr, "Failed to run: %s, error: %s\n", - android::base::Join(command_args, " ").c_str(), error.c_str()); - } - return {}; - } - - return connection_fd; -} - -bool can_install(const Files& files) { - for (const auto& file : files) { - struct stat st; - if (stat(file.c_str(), &st)) { - return false; - } - - auto [fd, _] = read_signature(st.st_size, file, true); - if (!fd.ok()) { - return false; - } - } - return true; -} - -std::optional install(const Files& files, const Args& passthrough_args, bool silent) { - auto connection_fd = start_install(files, passthrough_args, silent); - if (connection_fd < 0) { - if (!silent) { - fprintf(stderr, "adb: failed to initiate installation on device.\n"); - } - return {}; - } - - std::string adb_path = android::base::GetExecutablePath(); - - auto osh = adb_get_os_handle(connection_fd.get()); -#ifdef _WIN32 - auto fd_param = std::to_string(reinterpret_cast(osh)); -#else /* !_WIN32 a.k.a. Unix */ - auto fd_param = std::to_string(osh); -#endif - - // pipe for child process to write output - int print_fds[2]; - if (adb_socketpair(print_fds) != 0) { - if (!silent) { - fprintf(stderr, "Failed to create socket pair for child to print to parent\n"); - } - return {}; - } - auto [pipe_read_fd, pipe_write_fd] = print_fds; - auto pipe_write_fd_param = std::to_string(intptr_t(adb_get_os_handle(pipe_write_fd))); - close_on_exec(pipe_read_fd); - - std::vector args(std::move(files)); - args.insert(args.begin(), {"inc-server", fd_param, pipe_write_fd_param}); - auto child = - adb_launch_process(adb_path, std::move(args), {connection_fd.get(), pipe_write_fd}); - if (!child) { - if (!silent) { - fprintf(stderr, "adb: failed to fork: %s\n", strerror(errno)); - } - return {}; - } - - adb_close(pipe_write_fd); - - auto killOnExit = [](Process* p) { p->kill(); }; - std::unique_ptr serverKiller(&child, killOnExit); - - Result result = wait_for_installation(pipe_read_fd); - adb_close(pipe_read_fd); - - if (result == Result::Success) { - // adb client exits now but inc-server can continue - serverKiller.release(); - } - return child; -} - -Result wait_for_installation(int read_fd) { - static constexpr int maxMessageSize = 256; - std::vector child_stdout(CHUNK_SIZE); - int bytes_read; - int buf_size = 0; - // TODO(b/150865433): optimize child's output parsing - while ((bytes_read = adb_read(read_fd, child_stdout.data() + buf_size, - child_stdout.size() - buf_size)) > 0) { - // print to parent's stdout - fprintf(stdout, "%.*s", bytes_read, child_stdout.data() + buf_size); - - buf_size += bytes_read; - const std::string_view stdout_str(child_stdout.data(), buf_size); - // wait till installation either succeeds or fails - if (stdout_str.find("Success") != std::string::npos) { - return Result::Success; - } - // on failure, wait for full message - static constexpr auto failure_msg_head = "Failure ["sv; - if (const auto begin_itr = stdout_str.find(failure_msg_head); - begin_itr != std::string::npos) { - if (buf_size >= maxMessageSize) { - return Result::Failure; - } - const auto end_itr = stdout_str.rfind("]"); - if (end_itr != std::string::npos && end_itr >= begin_itr + failure_msg_head.size()) { - return Result::Failure; - } - } - child_stdout.resize(buf_size + CHUNK_SIZE); - } - return Result::None; -} - -} // namespace incremental diff --git a/adb/client/incremental.h b/adb/client/incremental.h deleted file mode 100644 index 40e928aea4db5480abe2c8350bb10ab60d7416c0..0000000000000000000000000000000000000000 --- a/adb/client/incremental.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2020 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. - */ - -#pragma once - -#include "adb_unique_fd.h" - -#include -#include - -#include "sysdeps.h" - -namespace incremental { - -using Files = std::vector; -using Args = std::vector; - -bool can_install(const Files& files); -std::optional install(const Files& files, const Args& passthrough_args, bool silent); - -enum class Result { Success, Failure, None }; -Result wait_for_installation(int read_fd); - -} // namespace incremental diff --git a/adb/client/incremental_server.cpp b/adb/client/incremental_server.cpp deleted file mode 100644 index bfe18c0b29454f76ef4f7d94ee6ca7e871107020..0000000000000000000000000000000000000000 --- a/adb/client/incremental_server.cpp +++ /dev/null @@ -1,716 +0,0 @@ -/* - * Copyright (C) 2020 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 INCREMENTAL - -#include "incremental_server.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "adb.h" -#include "adb_io.h" -#include "adb_trace.h" -#include "adb_unique_fd.h" -#include "adb_utils.h" -#include "incremental_utils.h" -#include "sysdeps.h" - -namespace incremental { - -static constexpr int kHashesPerBlock = kBlockSize / kDigestSize; -static constexpr int kCompressedSizeMax = kBlockSize * 0.95; -static constexpr int8_t kTypeData = 0; -static constexpr int8_t kTypeHash = 1; -static constexpr int8_t kCompressionNone = 0; -static constexpr int8_t kCompressionLZ4 = 1; -static constexpr int kCompressBound = std::max(kBlockSize, LZ4_COMPRESSBOUND(kBlockSize)); -static constexpr auto kReadBufferSize = 128 * 1024; -static constexpr int kPollTimeoutMillis = 300000; // 5 minutes - -using BlockSize = int16_t; -using FileId = int16_t; -using BlockIdx = int32_t; -using NumBlocks = int32_t; -using BlockType = int8_t; -using CompressionType = int8_t; -using RequestType = int16_t; -using ChunkHeader = int32_t; -using MagicType = uint32_t; - -static constexpr MagicType INCR = 0x494e4352; // LE INCR - -static constexpr RequestType SERVING_COMPLETE = 0; -static constexpr RequestType BLOCK_MISSING = 1; -static constexpr RequestType PREFETCH = 2; -static constexpr RequestType DESTROY = 3; - -static constexpr inline int64_t roundDownToBlockOffset(int64_t val) { - return val & ~(kBlockSize - 1); -} - -static constexpr inline int64_t roundUpToBlockOffset(int64_t val) { - return roundDownToBlockOffset(val + kBlockSize - 1); -} - -static constexpr inline NumBlocks numBytesToNumBlocks(int64_t bytes) { - return roundUpToBlockOffset(bytes) / kBlockSize; -} - -static constexpr inline off64_t blockIndexToOffset(BlockIdx blockIdx) { - return static_cast(blockIdx) * kBlockSize; -} - -template -static inline constexpr T toBigEndian(T t) { - using unsigned_type = std::make_unsigned_t; - if constexpr (std::is_same_v) { - return htobe16(static_cast(t)); - } else if constexpr (std::is_same_v) { - return htobe32(static_cast(t)); - } else if constexpr (std::is_same_v) { - return htobe64(static_cast(t)); - } else { - return t; - } -} - -template -static inline constexpr T readBigEndian(void* data) { - using unsigned_type = std::make_unsigned_t; - if constexpr (std::is_same_v) { - return static_cast(be16toh(*reinterpret_cast(data))); - } else if constexpr (std::is_same_v) { - return static_cast(be32toh(*reinterpret_cast(data))); - } else if constexpr (std::is_same_v) { - return static_cast(be64toh(*reinterpret_cast(data))); - } else { - return T(); - } -} - -// Received from device -// !Does not include magic! -struct RequestCommand { - RequestType request_type; // 2 bytes - FileId file_id; // 2 bytes - union { - BlockIdx block_idx; - NumBlocks num_blocks; - }; // 4 bytes -} __attribute__((packed)); - -// Placed before actual data bytes of each block -struct ResponseHeader { - FileId file_id; // 2 bytes - BlockType block_type; // 1 byte - CompressionType compression_type; // 1 byte - BlockIdx block_idx; // 4 bytes - BlockSize block_size; // 2 bytes - - static constexpr size_t responseSizeFor(size_t dataSize) { - return dataSize + sizeof(ResponseHeader); - } -} __attribute__((packed)); - -template -struct BlockBuffer { - ResponseHeader header; - char data[Size]; -} __attribute__((packed)); - -// Holds streaming state for a file -class File { - public: - // Plain file - File(const char* filepath, FileId id, int64_t size, unique_fd fd, int64_t tree_offset, - unique_fd tree_fd) - : File(filepath, id, size, tree_offset) { - this->fd_ = std::move(fd); - this->tree_fd_ = std::move(tree_fd); - priority_blocks_ = PriorityBlocksForFile(filepath, fd_.get(), size); - } - int64_t ReadDataBlock(BlockIdx block_idx, void* buf, bool* is_zip_compressed) const { - int64_t bytes_read = -1; - const off64_t offsetStart = blockIndexToOffset(block_idx); - bytes_read = adb_pread(fd_, buf, kBlockSize, offsetStart); - return bytes_read; - } - int64_t ReadTreeBlock(BlockIdx block_idx, void* buf) const { - int64_t bytes_read = -1; - const off64_t offsetStart = tree_offset_ + blockIndexToOffset(block_idx); - bytes_read = adb_pread(tree_fd_, buf, kBlockSize, offsetStart); - return bytes_read; - } - - const std::vector& PriorityBlocks() const { return priority_blocks_; } - - std::vector sentBlocks; - NumBlocks sentBlocksCount = 0; - - std::vector sentTreeBlocks; - - const char* const filepath; - const FileId id; - const int64_t size; - - private: - File(const char* filepath, FileId id, int64_t size, int64_t tree_offset) - : filepath(filepath), id(id), size(size), tree_offset_(tree_offset) { - sentBlocks.resize(numBytesToNumBlocks(size)); - sentTreeBlocks.resize(verity_tree_blocks_for_file(size)); - } - unique_fd fd_; - std::vector priority_blocks_; - - unique_fd tree_fd_; - const int64_t tree_offset_; -}; - -class IncrementalServer { - public: - IncrementalServer(unique_fd adb_fd, unique_fd output_fd, std::vector files) - : adb_fd_(std::move(adb_fd)), output_fd_(std::move(output_fd)), files_(std::move(files)) { - buffer_.reserve(kReadBufferSize); - pendingBlocksBuffer_.resize(kChunkFlushSize + 2 * kBlockSize); - pendingBlocks_ = pendingBlocksBuffer_.data() + sizeof(ChunkHeader); - } - - bool Serve(); - - private: - struct PrefetchState { - const File* file; - BlockIdx overallIndex = 0; - BlockIdx overallEnd = 0; - BlockIdx priorityIndex = 0; - - explicit PrefetchState(const File& f, BlockIdx start, int count) - : file(&f), - overallIndex(start), - overallEnd(std::min(start + count, f.sentBlocks.size())) {} - - explicit PrefetchState(const File& f) - : PrefetchState(f, 0, (BlockIdx)f.sentBlocks.size()) {} - - bool done() const { - const bool overallSent = (overallIndex >= overallEnd); - if (file->PriorityBlocks().empty()) { - return overallSent; - } - return overallSent && (priorityIndex >= (BlockIdx)file->PriorityBlocks().size()); - } - }; - - bool SkipToRequest(void* buffer, size_t* size, bool blocking); - std::optional ReadRequest(bool blocking); - - void erase_buffer_head(int count) { buffer_.erase(buffer_.begin(), buffer_.begin() + count); } - - enum class SendResult { Sent, Skipped, Error }; - SendResult SendDataBlock(FileId fileId, BlockIdx blockIdx, bool flush = false); - - bool SendTreeBlock(FileId fileId, int32_t fileBlockIdx, BlockIdx blockIdx); - bool SendTreeBlocksForDataBlock(FileId fileId, BlockIdx blockIdx); - - bool SendDone(); - void RunPrefetching(); - - void Send(const void* data, size_t size, bool flush); - void Flush(); - using TimePoint = decltype(std::chrono::high_resolution_clock::now()); - bool ServingComplete(std::optional startTime, int missesCount, int missesSent); - - unique_fd const adb_fd_; - unique_fd const output_fd_; - std::vector files_; - - // Incoming data buffer. - std::vector buffer_; - - std::deque prefetches_; - int compressed_ = 0, uncompressed_ = 0; - long long sentSize_ = 0; - - static constexpr auto kChunkFlushSize = 31 * kBlockSize; - - std::vector pendingBlocksBuffer_; - char* pendingBlocks_ = nullptr; - - // True when client notifies that all the data has been received - bool servingComplete_ = false; -}; - -bool IncrementalServer::SkipToRequest(void* buffer, size_t* size, bool blocking) { - while (true) { - // Looking for INCR magic. - bool magic_found = false; - int bcur = 0; - int bsize = buffer_.size(); - for (bcur = 0; bcur + 4 < bsize; ++bcur) { - uint32_t magic = be32toh(*(uint32_t*)(buffer_.data() + bcur)); - if (magic == INCR) { - magic_found = true; - break; - } - } - - if (bcur > 0) { - // output the rest. - (void)WriteFdExactly(output_fd_, buffer_.data(), bcur); - erase_buffer_head(bcur); - } - - if (magic_found && buffer_.size() >= *size + sizeof(INCR)) { - // fine, return - memcpy(buffer, buffer_.data() + sizeof(INCR), *size); - erase_buffer_head(*size + sizeof(INCR)); - return true; - } - - adb_pollfd pfd = {adb_fd_.get(), POLLIN, 0}; - auto res = adb_poll(&pfd, 1, blocking ? kPollTimeoutMillis : 0); - - if (res != 1) { - auto err = errno; - (void)WriteFdExactly(output_fd_, buffer_.data(), buffer_.size()); - if (res < 0) { - D("Failed to poll: %s", strerror(err)); - return false; - } - if (blocking) { - fprintf(stderr, "Timed out waiting for data from device.\n"); - } - if (blocking && servingComplete_) { - // timeout waiting from client. Serving is complete, so quit. - return false; - } - *size = 0; - return true; - } - - bsize = buffer_.size(); - buffer_.resize(kReadBufferSize); - int r = adb_read(adb_fd_, buffer_.data() + bsize, kReadBufferSize - bsize); - if (r > 0) { - buffer_.resize(bsize + r); - continue; - } - - D("Failed to read from fd %d: %d. Exit", adb_fd_.get(), errno); - break; - } - // socket is closed. print remaining messages - WriteFdExactly(output_fd_, buffer_.data(), buffer_.size()); - return false; -} - -std::optional IncrementalServer::ReadRequest(bool blocking) { - uint8_t commandBuf[sizeof(RequestCommand)]; - auto size = sizeof(commandBuf); - if (!SkipToRequest(&commandBuf, &size, blocking)) { - return {{DESTROY}}; - } - if (size < sizeof(RequestCommand)) { - return {}; - } - RequestCommand request; - request.request_type = readBigEndian(&commandBuf[0]); - request.file_id = readBigEndian(&commandBuf[2]); - request.block_idx = readBigEndian(&commandBuf[4]); - return request; -} - -bool IncrementalServer::SendTreeBlocksForDataBlock(const FileId fileId, const BlockIdx blockIdx) { - auto& file = files_[fileId]; - const int32_t data_block_count = numBytesToNumBlocks(file.size); - - const int32_t total_nodes_count(file.sentTreeBlocks.size()); - const int32_t leaf_nodes_count = (data_block_count + kHashesPerBlock - 1) / kHashesPerBlock; - - const int32_t leaf_nodes_offset = total_nodes_count - leaf_nodes_count; - - // Leaf level, sending only 1 block. - const int32_t leaf_idx = leaf_nodes_offset + blockIdx / kHashesPerBlock; - if (file.sentTreeBlocks[leaf_idx]) { - return true; - } - if (!SendTreeBlock(fileId, blockIdx, leaf_idx)) { - return false; - } - file.sentTreeBlocks[leaf_idx] = true; - - // Non-leaf, sending EVERYTHING. This should be done only once. - if (leaf_nodes_offset == 0 || file.sentTreeBlocks[0]) { - return true; - } - - for (int32_t i = 0; i < leaf_nodes_offset; ++i) { - if (!SendTreeBlock(fileId, blockIdx, i)) { - return false; - } - file.sentTreeBlocks[i] = true; - } - return true; -} - -bool IncrementalServer::SendTreeBlock(FileId fileId, int32_t fileBlockIdx, BlockIdx blockIdx) { - const auto& file = files_[fileId]; - - BlockBuffer buffer; - const int64_t bytesRead = file.ReadTreeBlock(blockIdx, buffer.data); - if (bytesRead <= 0) { - fprintf(stderr, "Failed to get data for %s.idsig at blockIdx=%d.\n", file.filepath, - blockIdx); - return false; - } - - buffer.header.compression_type = kCompressionNone; - buffer.header.block_type = kTypeHash; - buffer.header.file_id = toBigEndian(fileId); - buffer.header.block_size = toBigEndian(int16_t(bytesRead)); - buffer.header.block_idx = toBigEndian(blockIdx); - - Send(&buffer, ResponseHeader::responseSizeFor(bytesRead), /*flush=*/false); - - return true; -} - -auto IncrementalServer::SendDataBlock(FileId fileId, BlockIdx blockIdx, bool flush) -> SendResult { - auto& file = files_[fileId]; - if (blockIdx >= static_cast(file.sentBlocks.size())) { - // may happen as we schedule some extra blocks for reported page misses - D("Skipped reading file %s at block %" PRId32 " (past end).", file.filepath, blockIdx); - return SendResult::Skipped; - } - if (file.sentBlocks[blockIdx]) { - return SendResult::Skipped; - } - - if (!SendTreeBlocksForDataBlock(fileId, blockIdx)) { - return SendResult::Error; - } - - BlockBuffer raw; - bool isZipCompressed = false; - const int64_t bytesRead = file.ReadDataBlock(blockIdx, raw.data, &isZipCompressed); - if (bytesRead < 0) { - fprintf(stderr, "Failed to get data for %s at blockIdx=%d (%d).\n", file.filepath, blockIdx, - errno); - return SendResult::Error; - } - - BlockBuffer compressed; - int16_t compressedSize = 0; - if (!isZipCompressed) { - compressedSize = LZ4_compress_default(raw.data, compressed.data, bytesRead, kCompressBound); - } - int16_t blockSize; - ResponseHeader* header; - if (compressedSize > 0 && compressedSize < kCompressedSizeMax) { - ++compressed_; - blockSize = compressedSize; - header = &compressed.header; - header->compression_type = kCompressionLZ4; - } else { - ++uncompressed_; - blockSize = bytesRead; - header = &raw.header; - header->compression_type = kCompressionNone; - } - - header->block_type = kTypeData; - header->file_id = toBigEndian(fileId); - header->block_size = toBigEndian(blockSize); - header->block_idx = toBigEndian(blockIdx); - - file.sentBlocks[blockIdx] = true; - file.sentBlocksCount += 1; - Send(header, ResponseHeader::responseSizeFor(blockSize), flush); - - return SendResult::Sent; -} - -bool IncrementalServer::SendDone() { - ResponseHeader header; - header.file_id = -1; - header.block_type = 0; - header.compression_type = 0; - header.block_idx = 0; - header.block_size = 0; - Send(&header, sizeof(header), true); - return true; -} - -void IncrementalServer::RunPrefetching() { - constexpr auto kPrefetchBlocksPerIteration = 128; - - int blocksToSend = kPrefetchBlocksPerIteration; - while (!prefetches_.empty() && blocksToSend > 0) { - auto& prefetch = prefetches_.front(); - const auto& file = *prefetch.file; - const auto& priority_blocks = file.PriorityBlocks(); - if (!priority_blocks.empty()) { - for (auto& i = prefetch.priorityIndex; - blocksToSend > 0 && i < (BlockIdx)priority_blocks.size(); ++i) { - if (auto res = SendDataBlock(file.id, priority_blocks[i]); - res == SendResult::Sent) { - --blocksToSend; - } else if (res == SendResult::Error) { - fprintf(stderr, "Failed to send priority block %" PRId32 "\n", i); - } - } - } - for (auto& i = prefetch.overallIndex; blocksToSend > 0 && i < prefetch.overallEnd; ++i) { - if (auto res = SendDataBlock(file.id, i); res == SendResult::Sent) { - --blocksToSend; - } else if (res == SendResult::Error) { - fprintf(stderr, "Failed to send block %" PRId32 "\n", i); - } - } - if (prefetch.done()) { - prefetches_.pop_front(); - } - } -} - -void IncrementalServer::Send(const void* data, size_t size, bool flush) { - pendingBlocks_ = std::copy_n(static_cast(data), size, pendingBlocks_); - if (flush || pendingBlocks_ - pendingBlocksBuffer_.data() > kChunkFlushSize) { - Flush(); - } -} - -void IncrementalServer::Flush() { - auto dataBytes = pendingBlocks_ - (pendingBlocksBuffer_.data() + sizeof(ChunkHeader)); - if (dataBytes == 0) { - return; - } - - *(ChunkHeader*)pendingBlocksBuffer_.data() = toBigEndian(dataBytes); - auto totalBytes = sizeof(ChunkHeader) + dataBytes; - if (!WriteFdExactly(adb_fd_, pendingBlocksBuffer_.data(), totalBytes)) { - fprintf(stderr, "Failed to write %d bytes\n", int(totalBytes)); - } - sentSize_ += totalBytes; - pendingBlocks_ = pendingBlocksBuffer_.data() + sizeof(ChunkHeader); -} - -bool IncrementalServer::ServingComplete(std::optional startTime, int missesCount, - int missesSent) { - servingComplete_ = true; - using namespace std::chrono; - auto endTime = high_resolution_clock::now(); - D("Streaming completed.\n" - "Misses: %d, of those unique: %d; sent compressed: %d, uncompressed: " - "%d, mb: %.3f\n" - "Total time taken: %.3fms", - missesCount, missesSent, compressed_, uncompressed_, sentSize_ / 1024.0 / 1024.0, - duration_cast(endTime - (startTime ? *startTime : endTime)).count() / 1000.0); - return true; -} - -bool IncrementalServer::Serve() { - // Initial handshake to verify connection is still alive - if (!SendOkay(adb_fd_)) { - fprintf(stderr, "Connection is dead. Abort.\n"); - return false; - } - - std::unordered_set prefetchedFiles; - bool doneSent = false; - int missesCount = 0; - int missesSent = 0; - - using namespace std::chrono; - std::optional startTime; - - while (true) { - if (!doneSent && prefetches_.empty() && - std::all_of(files_.begin(), files_.end(), [](const File& f) { - return f.sentBlocksCount == NumBlocks(f.sentBlocks.size()); - })) { - fprintf(stderr, "All files should be loaded. Notifying the device.\n"); - SendDone(); - doneSent = true; - } - - const bool blocking = prefetches_.empty(); - if (blocking) { - // We've no idea how long the blocking call is, so let's flush whatever is still unsent. - Flush(); - } - auto request = ReadRequest(blocking); - - if (!startTime) { - startTime = high_resolution_clock::now(); - } - - if (request) { - FileId fileId = request->file_id; - BlockIdx blockIdx = request->block_idx; - - switch (request->request_type) { - case DESTROY: { - // Stop everything. - return true; - } - case SERVING_COMPLETE: { - // Not stopping the server here. - ServingComplete(startTime, missesCount, missesSent); - break; - } - case BLOCK_MISSING: { - ++missesCount; - // Sends one single block ASAP. - if (fileId < 0 || fileId >= (FileId)files_.size() || blockIdx < 0 || - blockIdx >= (BlockIdx)files_[fileId].sentBlocks.size()) { - fprintf(stderr, - "Received invalid data request for file_id %" PRId16 - " block_idx %" PRId32 ".\n", - fileId, blockIdx); - break; - } - - if (VLOG_IS_ON(INCREMENTAL)) { - auto& file = files_[fileId]; - auto posP = std::find(file.PriorityBlocks().begin(), - file.PriorityBlocks().end(), blockIdx); - D("\tMISSING BLOCK: reading file %d block %04d (in priority: %d of %d)", - (int)fileId, (int)blockIdx, - posP == file.PriorityBlocks().end() - ? -1 - : int(posP - file.PriorityBlocks().begin()), - int(file.PriorityBlocks().size())); - } - - if (auto res = SendDataBlock(fileId, blockIdx, true); - res == SendResult::Error) { - fprintf(stderr, "Failed to send block %" PRId32 ".\n", blockIdx); - } else if (res == SendResult::Sent) { - ++missesSent; - // Make sure we send more pages from this place onward, in case if the OS is - // reading a bigger block. - prefetches_.emplace_front(files_[fileId], blockIdx + 1, 7); - } - break; - } - case PREFETCH: { - // Start prefetching for a file - if (fileId < 0) { - fprintf(stderr, - "Received invalid prefetch request for file_id %" PRId16 "\n", - fileId); - break; - } - if (!prefetchedFiles.insert(fileId).second) { - fprintf(stderr, - "Received duplicate prefetch request for file_id %" PRId16 "\n", - fileId); - break; - } - D("Received prefetch request for file_id %" PRId16 ".", fileId); - prefetches_.emplace_back(files_[fileId]); - break; - } - default: - fprintf(stderr, "Invalid request %" PRId16 ",%" PRId16 ",%" PRId32 ".\n", - request->request_type, fileId, blockIdx); - break; - } - } - - RunPrefetching(); - } -} - -static std::pair open_fd(const char* filepath) { - struct stat st; - if (stat(filepath, &st)) { - error_exit("inc-server: failed to stat input file '%s'.", filepath); - } - - unique_fd fd(adb_open(filepath, O_RDONLY)); - if (fd < 0) { - error_exit("inc-server: failed to open file '%s'.", filepath); - } - - return {std::move(fd), st.st_size}; -} - -static std::pair open_signature(int64_t file_size, const char* filepath) { - std::string signature_file(filepath); - signature_file += IDSIG; - - unique_fd fd(adb_open(signature_file.c_str(), O_RDONLY)); - if (fd < 0) { - error_exit("inc-server: failed to open file '%s'.", signature_file.c_str()); - } - - auto [tree_offset, tree_size] = skip_id_sig_headers(fd); - if (auto expected = verity_tree_size_for_file(file_size); tree_size != expected) { - error_exit("Verity tree size mismatch in signature file: %s [was %lld, expected %lld].\n", - signature_file.c_str(), (long long)tree_size, (long long)expected); - } - - int32_t data_block_count = numBytesToNumBlocks(file_size); - int32_t leaf_nodes_count = (data_block_count + kHashesPerBlock - 1) / kHashesPerBlock; - D("Verity tree loaded: %s, tree size: %d (%d blocks, %d leafs)", signature_file.c_str(), - int(tree_size), int(numBytesToNumBlocks(tree_size)), int(leaf_nodes_count)); - - return {std::move(fd), tree_offset}; -} - -bool serve(int connection_fd, int output_fd, int argc, const char** argv) { - auto connection_ufd = unique_fd(connection_fd); - auto output_ufd = unique_fd(output_fd); - if (argc <= 0) { - error_exit("inc-server: must specify at least one file."); - } - - std::vector files; - files.reserve(argc); - for (int i = 0; i < argc; ++i) { - auto filepath = argv[i]; - - auto [file_fd, file_size] = open_fd(filepath); - auto [sign_fd, sign_offset] = open_signature(file_size, filepath); - - files.emplace_back(filepath, i, file_size, std::move(file_fd), sign_offset, - std::move(sign_fd)); - } - - IncrementalServer server(std::move(connection_ufd), std::move(output_ufd), std::move(files)); - printf("Serving...\n"); - fclose(stdin); - fclose(stdout); - return server.Serve(); -} - -} // namespace incremental diff --git a/adb/client/incremental_server.h b/adb/client/incremental_server.h deleted file mode 100644 index 55b8215b8869ee85d76a8e57f7c1a29851e4c135..0000000000000000000000000000000000000000 --- a/adb/client/incremental_server.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2020 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. - */ - -#pragma once - -namespace incremental { - -// Expecting arguments like: -// {FILE1 FILE2 ...} -// Where FILE* are files to serve. -bool serve(int connection_fd, int output_fd, int argc, const char** argv); - -} // namespace incremental diff --git a/adb/client/incremental_utils.cpp b/adb/client/incremental_utils.cpp deleted file mode 100644 index 076b7665ec4806e5aad64e988870b8f3ccff0863..0000000000000000000000000000000000000000 --- a/adb/client/incremental_utils.cpp +++ /dev/null @@ -1,366 +0,0 @@ -/* - * Copyright (C) 2020 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 INCREMENTAL - -#include "incremental_utils.h" - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "adb_io.h" -#include "adb_trace.h" -#include "sysdeps.h" - -namespace incremental { - -static constexpr inline int32_t offsetToBlockIndex(int64_t offset) { - return (offset & ~(kBlockSize - 1)) >> 12; -} - -Size verity_tree_blocks_for_file(Size fileSize) { - if (fileSize == 0) { - return 0; - } - - constexpr int hash_per_block = kBlockSize / kDigestSize; - - Size total_tree_block_count = 0; - - auto block_count = 1 + (fileSize - 1) / kBlockSize; - auto hash_block_count = block_count; - for (auto i = 0; hash_block_count > 1; i++) { - hash_block_count = (hash_block_count + hash_per_block - 1) / hash_per_block; - total_tree_block_count += hash_block_count; - } - return total_tree_block_count; -} - -Size verity_tree_size_for_file(Size fileSize) { - return verity_tree_blocks_for_file(fileSize) * kBlockSize; -} - -static inline int32_t read_int32(borrowed_fd fd) { - int32_t result; - return ReadFdExactly(fd, &result, sizeof(result)) ? result : -1; -} - -static inline int32_t skip_int(borrowed_fd fd) { - return adb_lseek(fd, 4, SEEK_CUR); -} - -static inline void append_int(borrowed_fd fd, std::vector* bytes) { - int32_t le_val = read_int32(fd); - auto old_size = bytes->size(); - bytes->resize(old_size + sizeof(le_val)); - memcpy(bytes->data() + old_size, &le_val, sizeof(le_val)); -} - -static inline void append_bytes_with_size(borrowed_fd fd, std::vector* bytes) { - int32_t le_size = read_int32(fd); - if (le_size < 0) { - return; - } - int32_t size = int32_t(le32toh(le_size)); - auto old_size = bytes->size(); - bytes->resize(old_size + sizeof(le_size) + size); - memcpy(bytes->data() + old_size, &le_size, sizeof(le_size)); - ReadFdExactly(fd, bytes->data() + old_size + sizeof(le_size), size); -} - -static inline int32_t skip_bytes_with_size(borrowed_fd fd) { - int32_t le_size = read_int32(fd); - if (le_size < 0) { - return -1; - } - int32_t size = int32_t(le32toh(le_size)); - return (int32_t)adb_lseek(fd, size, SEEK_CUR); -} - -std::pair, int32_t> read_id_sig_headers(borrowed_fd fd) { - std::vector result; - append_int(fd, &result); // version - append_bytes_with_size(fd, &result); // hashingInfo - append_bytes_with_size(fd, &result); // signingInfo - auto le_tree_size = read_int32(fd); - auto tree_size = int32_t(le32toh(le_tree_size)); // size of the verity tree - return {std::move(result), tree_size}; -} - -std::pair skip_id_sig_headers(borrowed_fd fd) { - skip_int(fd); // version - skip_bytes_with_size(fd); // hashingInfo - auto offset = skip_bytes_with_size(fd); // signingInfo - auto le_tree_size = read_int32(fd); - auto tree_size = int32_t(le32toh(le_tree_size)); // size of the verity tree - return {offset + sizeof(le_tree_size), tree_size}; -} - -template -static T valueAt(borrowed_fd fd, off64_t offset) { - T t; - memset(&t, 0, sizeof(T)); - if (adb_pread(fd, &t, sizeof(T), offset) != sizeof(T)) { - memset(&t, -1, sizeof(T)); - } - - return t; -} - -static void appendBlocks(int32_t start, int count, std::vector* blocks) { - if (count == 1) { - blocks->push_back(start); - } else { - auto oldSize = blocks->size(); - blocks->resize(oldSize + count); - std::iota(blocks->begin() + oldSize, blocks->end(), start); - } -} - -template -static void unduplicate(std::vector& v) { - std::unordered_set uniques(v.size()); - v.erase(std::remove_if(v.begin(), v.end(), - [&uniques](T t) { return !uniques.insert(t).second; }), - v.end()); -} - -static off64_t CentralDirOffset(borrowed_fd fd, Size fileSize) { - static constexpr int kZipEocdRecMinSize = 22; - static constexpr int32_t kZipEocdRecSig = 0x06054b50; - static constexpr int kZipEocdCentralDirSizeFieldOffset = 12; - static constexpr int kZipEocdCommentLengthFieldOffset = 20; - - int32_t sigBuf = 0; - off64_t eocdOffset = -1; - off64_t maxEocdOffset = fileSize - kZipEocdRecMinSize; - int16_t commentLenBuf = 0; - - // Search from the end of zip, backward to find beginning of EOCD - for (int16_t commentLen = 0; commentLen < fileSize; ++commentLen) { - sigBuf = valueAt(fd, maxEocdOffset - commentLen); - if (sigBuf == kZipEocdRecSig) { - commentLenBuf = valueAt( - fd, maxEocdOffset - commentLen + kZipEocdCommentLengthFieldOffset); - if (commentLenBuf == commentLen) { - eocdOffset = maxEocdOffset - commentLen; - break; - } - } - } - - if (eocdOffset < 0) { - return -1; - } - - off64_t cdLen = static_cast( - valueAt(fd, eocdOffset + kZipEocdCentralDirSizeFieldOffset)); - - return eocdOffset - cdLen; -} - -// Does not support APKs larger than 4GB -static off64_t SignerBlockOffset(borrowed_fd fd, Size fileSize) { - static constexpr int kApkSigBlockMinSize = 32; - static constexpr int kApkSigBlockFooterSize = 24; - static constexpr int64_t APK_SIG_BLOCK_MAGIC_HI = 0x3234206b636f6c42l; - static constexpr int64_t APK_SIG_BLOCK_MAGIC_LO = 0x20676953204b5041l; - - off64_t cdOffset = CentralDirOffset(fd, fileSize); - if (cdOffset < 0) { - return -1; - } - // CD offset is where original signer block ends. Search backwards for magic and footer. - if (cdOffset < kApkSigBlockMinSize || - valueAt(fd, cdOffset - 2 * sizeof(int64_t)) != APK_SIG_BLOCK_MAGIC_LO || - valueAt(fd, cdOffset - sizeof(int64_t)) != APK_SIG_BLOCK_MAGIC_HI) { - return -1; - } - int32_t signerSizeInFooter = valueAt(fd, cdOffset - kApkSigBlockFooterSize); - off64_t signerBlockOffset = cdOffset - signerSizeInFooter - sizeof(int64_t); - if (signerBlockOffset < 0) { - return -1; - } - int32_t signerSizeInHeader = valueAt(fd, signerBlockOffset); - if (signerSizeInFooter != signerSizeInHeader) { - return -1; - } - - return signerBlockOffset; -} - -static std::vector ZipPriorityBlocks(off64_t signerBlockOffset, Size fileSize) { - int32_t signerBlockIndex = offsetToBlockIndex(signerBlockOffset); - int32_t lastBlockIndex = offsetToBlockIndex(fileSize); - const auto numPriorityBlocks = lastBlockIndex - signerBlockIndex + 1; - - std::vector zipPriorityBlocks; - - // Some magic here: most of zip libraries perform a scan for EOCD record starting at the offset - // of a maximum comment size from the end of the file. This means the last 65-ish KBs will be - // accessed first, followed by the rest of the central directory blocks. Make sure we - // send the data in the proper order, as central directory can be quite big by itself. - static constexpr auto kMaxZipCommentSize = 64 * 1024; - static constexpr auto kNumBlocksInEocdSearch = kMaxZipCommentSize / kBlockSize + 1; - if (numPriorityBlocks > kNumBlocksInEocdSearch) { - appendBlocks(lastBlockIndex - kNumBlocksInEocdSearch + 1, kNumBlocksInEocdSearch, - &zipPriorityBlocks); - appendBlocks(signerBlockIndex, numPriorityBlocks - kNumBlocksInEocdSearch, - &zipPriorityBlocks); - } else { - appendBlocks(signerBlockIndex, numPriorityBlocks, &zipPriorityBlocks); - } - - // Somehow someone keeps accessing the start of the archive, even if there's nothing really - // interesting there... - appendBlocks(0, 1, &zipPriorityBlocks); - return zipPriorityBlocks; -} - -[[maybe_unused]] static ZipArchiveHandle openZipArchiveFd(borrowed_fd fd) { - bool transferFdOwnership = false; -#ifdef _WIN32 - // - // Need to create a special CRT FD here as the current one is not compatible with - // normal read()/write() calls that libziparchive uses. - // To make this work we have to create a copy of the file handle, as CRT doesn't care - // and closes it together with the new descriptor. - // - // Note: don't move this into a helper function, it's better to be hard to reuse because - // the code is ugly and won't work unless it's a last resort. - // - auto handle = adb_get_os_handle(fd); - HANDLE dupedHandle; - if (!::DuplicateHandle(::GetCurrentProcess(), handle, ::GetCurrentProcess(), &dupedHandle, 0, - false, DUPLICATE_SAME_ACCESS)) { - D("%s failed at DuplicateHandle: %d", __func__, (int)::GetLastError()); - return {}; - } - int osfd = _open_osfhandle((intptr_t)dupedHandle, _O_RDONLY | _O_BINARY); - if (osfd < 0) { - D("%s failed at _open_osfhandle: %d", __func__, errno); - ::CloseHandle(handle); - return {}; - } - transferFdOwnership = true; -#else - int osfd = fd.get(); -#endif - ZipArchiveHandle zip; - if (OpenArchiveFd(osfd, "apk_fd", &zip, transferFdOwnership) != 0) { - D("%s failed at OpenArchiveFd: %d", __func__, errno); -#ifdef _WIN32 - // "_close()" is a secret WinCRT name for the regular close() function. - _close(osfd); -#endif - return {}; - } - return zip; -} - -static std::pair> openZipArchive( - borrowed_fd fd, Size fileSize) { -#ifndef __LP64__ - if (fileSize >= INT_MAX) { - return {openZipArchiveFd(fd), nullptr}; - } -#endif - auto mapping = - android::base::MappedFile::FromOsHandle(adb_get_os_handle(fd), 0, fileSize, PROT_READ); - if (!mapping) { - D("%s failed at FromOsHandle: %d", __func__, errno); - return {}; - } - ZipArchiveHandle zip; - if (OpenArchiveFromMemory(mapping->data(), mapping->size(), "apk_mapping", &zip) != 0) { - D("%s failed at OpenArchiveFromMemory: %d", __func__, errno); - return {}; - } - return {zip, std::move(mapping)}; -} - -// TODO(b/151676293): avoid using libziparchive as it reads local file headers -// which causes additional performance cost. Instead, only read from central directory. -static std::vector InstallationPriorityBlocks(borrowed_fd fd, Size fileSize) { - auto [zip, _] = openZipArchive(fd, fileSize); - if (!zip) { - return {}; - } - - void* cookie = nullptr; - if (StartIteration(zip, &cookie) != 0) { - D("%s failed at StartIteration: %d", __func__, errno); - return {}; - } - - std::vector installationPriorityBlocks; - ZipEntry entry; - std::string_view entryName; - while (Next(cookie, &entry, &entryName) == 0) { - if (entryName == "resources.arsc" || entryName == "AndroidManifest.xml" || - entryName.starts_with("lib/")) { - // Full entries are needed for installation - off64_t entryStartOffset = entry.offset; - off64_t entryEndOffset = - entryStartOffset + - (entry.method == kCompressStored ? entry.uncompressed_length - : entry.compressed_length) + - (entry.has_data_descriptor ? 16 /* sizeof(DataDescriptor) */ : 0); - int32_t startBlockIndex = offsetToBlockIndex(entryStartOffset); - int32_t endBlockIndex = offsetToBlockIndex(entryEndOffset); - int32_t numNewBlocks = endBlockIndex - startBlockIndex + 1; - appendBlocks(startBlockIndex, numNewBlocks, &installationPriorityBlocks); - D("\tadding to priority blocks: '%.*s'", (int)entryName.size(), entryName.data()); - } else if (entryName == "classes.dex") { - // Only the head is needed for installation - int32_t startBlockIndex = offsetToBlockIndex(entry.offset); - appendBlocks(startBlockIndex, 2, &installationPriorityBlocks); - D("\tadding to priority blocks: '%.*s'", (int)entryName.size(), entryName.data()); - } - } - - EndIteration(cookie); - CloseArchive(zip); - return installationPriorityBlocks; -} - -std::vector PriorityBlocksForFile(const std::string& filepath, borrowed_fd fd, - Size fileSize) { - if (!android::base::EndsWithIgnoreCase(filepath, ".apk")) { - return {}; - } - off64_t signerOffset = SignerBlockOffset(fd, fileSize); - if (signerOffset < 0) { - // No signer block? not a valid APK - return {}; - } - std::vector priorityBlocks = ZipPriorityBlocks(signerOffset, fileSize); - std::vector installationPriorityBlocks = InstallationPriorityBlocks(fd, fileSize); - - priorityBlocks.insert(priorityBlocks.end(), installationPriorityBlocks.begin(), - installationPriorityBlocks.end()); - unduplicate(priorityBlocks); - return priorityBlocks; -} - -} // namespace incremental diff --git a/adb/client/incremental_utils.h b/adb/client/incremental_utils.h deleted file mode 100644 index fe2914ddea6dc42d07ec299bb681fa72664f0bcb..0000000000000000000000000000000000000000 --- a/adb/client/incremental_utils.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2020 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. - */ - -#pragma once - -#include "adb_unique_fd.h" - -#include -#include -#include -#include - -#include - -#include - -namespace incremental { - -using Size = int64_t; -constexpr int kBlockSize = 4096; -constexpr int kSha256DigestSize = 32; -constexpr int kDigestSize = kSha256DigestSize; - -constexpr std::string_view IDSIG = ".idsig"; - -std::vector PriorityBlocksForFile(const std::string& filepath, borrowed_fd fd, - Size fileSize); - -Size verity_tree_blocks_for_file(Size fileSize); -Size verity_tree_size_for_file(Size fileSize); - -std::pair, int32_t> read_id_sig_headers(borrowed_fd fd); -std::pair skip_id_sig_headers(borrowed_fd fd); - -} // namespace incremental diff --git a/adb/client/line_printer.cpp b/adb/client/line_printer.cpp deleted file mode 100644 index 50c03e81b3362f5e7904870683e28dc5e7b102b0..0000000000000000000000000000000000000000 --- a/adb/client/line_printer.cpp +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright 2013 Google Inc. All Rights Reserved. -// -// 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 "line_printer.h" - -#include -#include -#ifdef _WIN32 -#include -#else -#include -#include -#include -#include -#endif - -// Make sure printf is really adb_printf which works for UTF-8 on Windows. -#include - -// Stuff from ninja's util.h that's needed below. -#include -using namespace std; -// This does not account for multiple UTF-8 bytes corresponding to a single Unicode code point, or -// multiple code points corresponding to a single grapheme cluster (user-perceived character). -string ElideMiddle(const string& str, size_t width) { - const int kMargin = 3; // Space for "...". - string result = str; - if (result.size() + kMargin > width) { - size_t elide_size = (width - kMargin) / 2; - result = result.substr(0, elide_size) - + "..." - + result.substr(result.size() - elide_size, elide_size); - } - return result; -} - -LinePrinter::LinePrinter() : have_blank_line_(true) { -#ifndef _WIN32 - const char* term = getenv("TERM"); - smart_terminal_ = unix_isatty(1) && term && string(term) != "dumb"; -#else - // Disable output buffer. It'd be nice to use line buffering but - // MSDN says: "For some systems, [_IOLBF] provides line - // buffering. However, for Win32, the behavior is the same as _IOFBF - // - Full Buffering." - setvbuf(stdout, nullptr, _IONBF, 0); - console_ = GetStdHandle(STD_OUTPUT_HANDLE); - CONSOLE_SCREEN_BUFFER_INFO csbi; - smart_terminal_ = GetConsoleScreenBufferInfo(console_, &csbi); -#endif -} - -static void Out(const std::string& s) { - // Avoid printf and C strings, since the actual output might contain null - // bytes like UTF-16 does (yuck). - fwrite(s.data(), 1, s.size(), stdout); -} - -void LinePrinter::Print(string to_print, LineType type) { - if (!smart_terminal_) { - if (type == LineType::INFO) { - info_line_ = to_print + "\n"; - } else { - Out(to_print + "\n"); - } - return; - } - - // Print over previous line, if any. - // On Windows, calling a C library function writing to stdout also handles - // pausing the executable when the "Pause" key or Ctrl-S is pressed. - printf("\r"); - - if (type == INFO) { -#ifdef _WIN32 - CONSOLE_SCREEN_BUFFER_INFO csbi; - GetConsoleScreenBufferInfo(console_, &csbi); - - to_print = ElideMiddle(to_print, static_cast(csbi.dwSize.X)); - std::wstring to_print_wide; - // ElideMiddle may create invalid UTF-8, so ignore conversion errors. - (void)android::base::UTF8ToWide(to_print, &to_print_wide); - // We don't want to have the cursor spamming back and forth, so instead of - // printf use WriteConsoleOutput which updates the contents of the buffer, - // but doesn't move the cursor position. - COORD buf_size = { csbi.dwSize.X, 1 }; - COORD zero_zero = { 0, 0 }; - SMALL_RECT target = { - csbi.dwCursorPosition.X, csbi.dwCursorPosition.Y, - static_cast(csbi.dwCursorPosition.X + csbi.dwSize.X - 1), - csbi.dwCursorPosition.Y - }; - vector char_data(csbi.dwSize.X); - for (size_t i = 0; i < static_cast(csbi.dwSize.X); ++i) { - char_data[i].Char.UnicodeChar = i < to_print_wide.size() ? to_print_wide[i] : L' '; - char_data[i].Attributes = csbi.wAttributes; - } - WriteConsoleOutputW(console_, &char_data[0], buf_size, zero_zero, &target); -#else - // Limit output to width of the terminal if provided so we don't cause - // line-wrapping. - winsize size; - if ((ioctl(0, TIOCGWINSZ, &size) == 0) && size.ws_col) { - to_print = ElideMiddle(to_print, size.ws_col); - } - Out(to_print); - printf("\x1B[K"); // Clear to end of line. - fflush(stdout); -#endif - - have_blank_line_ = false; - } else { - Out(to_print); - Out("\n"); - have_blank_line_ = true; - } -} - -void LinePrinter::KeepInfoLine() { - if (smart_terminal_) { - if (!have_blank_line_) Out("\n"); - have_blank_line_ = true; - } else { - Out(info_line_); - info_line_.clear(); - } -} diff --git a/adb/client/line_printer.h b/adb/client/line_printer.h deleted file mode 100644 index 4c4c7c6fa2fbc7268a4b375b29ff518773854eb0..0000000000000000000000000000000000000000 --- a/adb/client/line_printer.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2013 Google Inc. All Rights Reserved. -// -// 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 NINJA_LINE_PRINTER_H_ -#define NINJA_LINE_PRINTER_H_ - -#include -#include - -/// Prints lines of text, possibly overprinting previously printed lines -/// if the terminal supports it. -struct LinePrinter { - LinePrinter(); - - bool is_smart_terminal() const { return smart_terminal_; } - void set_smart_terminal(bool smart) { smart_terminal_ = smart; } - - enum LineType { INFO, WARNING, ERROR }; - - /// Outputs the given line. INFO output will be overwritten. - /// WARNING and ERROR appear on a line to themselves. - void Print(std::string to_print, LineType type); - - /// If there's an INFO line, keep it. If not, do nothing. - void KeepInfoLine(); - - private: - /// Whether we can do fancy terminal control codes. - bool smart_terminal_; - - /// Whether the caret is at the beginning of a blank line. - bool have_blank_line_; - - /// The last printed info line when printing to a dumb terminal. - std::string info_line_; - -#ifdef _WIN32 - void* console_; -#endif -}; - -#endif // NINJA_LINE_PRINTER_H_ diff --git a/adb/client/main.cpp b/adb/client/main.cpp deleted file mode 100644 index 78f7b8f204bb6c08fb8c8e6536631f41774856a8..0000000000000000000000000000000000000000 --- a/adb/client/main.cpp +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright (C) 2015 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 ADB - -#include "sysdeps.h" - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include "adb.h" -#include "adb_auth.h" -#include "adb_client.h" -#include "adb_listeners.h" -#include "adb_utils.h" -#include "adb_wifi.h" -#include "client/usb.h" -#include "commandline.h" -#include "sysdeps/chrono.h" -#include "transport.h" - -const char** __adb_argv; -const char** __adb_envp; - -static void setup_daemon_logging() { - const std::string log_file_path(GetLogFilePath()); - int fd = unix_open(log_file_path, O_WRONLY | O_CREAT | O_APPEND, 0640); - if (fd == -1) { - PLOG(FATAL) << "cannot open " << log_file_path; - } - if (dup2(fd, STDOUT_FILENO) == -1) { - PLOG(FATAL) << "cannot redirect stdout"; - } - if (dup2(fd, STDERR_FILENO) == -1) { - PLOG(FATAL) << "cannot redirect stderr"; - } - unix_close(fd); - - fprintf(stderr, "--- adb starting (pid %d) ---\n", getpid()); - LOG(INFO) << adb_version(); -} - -void adb_server_cleanup() { - // Upon exit, we want to clean up in the following order: - // 1. close_smartsockets, so that we don't get any new clients - // 2. kick_all_transports, to avoid writing only part of a packet to a transport. - // 3. usb_cleanup, to tear down the USB stack. - close_smartsockets(); - kick_all_transports(); - usb_cleanup(); -} - -static void intentionally_leak() { - void* p = ::operator new(1); - // The analyzer is upset about this leaking. NOLINTNEXTLINE - LOG(INFO) << "leaking pointer " << p; -} - -int adb_server_main(int is_daemon, const std::string& socket_spec, int ack_reply_fd) { -#if defined(_WIN32) - // adb start-server starts us up with stdout and stderr hooked up to - // anonymous pipes. When the C Runtime sees this, it makes stderr and - // stdout buffered, but to improve the chance that error output is seen, - // unbuffer stdout and stderr just like if we were run at the console. - // This also keeps stderr unbuffered when it is redirected to adb.log. - if (is_daemon) { - if (setvbuf(stdout, nullptr, _IONBF, 0) == -1) { - PLOG(FATAL) << "cannot make stdout unbuffered"; - } - if (setvbuf(stderr, nullptr, _IONBF, 0) == -1) { - PLOG(FATAL) << "cannot make stderr unbuffered"; - } - } - - // TODO: On Ctrl-C, consider trying to kill a starting up adb server (if we're in - // launch_server) by calling GenerateConsoleCtrlEvent(). - - // On Windows, SIGBREAK is when Ctrl-Break is pressed or the console window is closed. It should - // act like Ctrl-C. - signal(SIGBREAK, [](int) { raise(SIGINT); }); -#endif - signal(SIGINT, [](int) { - fdevent_run_on_main_thread([]() { exit(0); }); - }); - - char* leak = getenv("ADB_LEAK"); - if (leak && strcmp(leak, "1") == 0) { - intentionally_leak(); - } - - if (is_daemon) { - close_stdin(); - setup_daemon_logging(); - } - - atexit(adb_server_cleanup); - - init_transport_registration(); - init_reconnect_handler(); - - adb_wifi_init(); - if (!getenv("ADB_MDNS") || strcmp(getenv("ADB_MDNS"), "0") != 0) { - init_mdns_transport_discovery(); - } - - if (!getenv("ADB_USB") || strcmp(getenv("ADB_USB"), "0") != 0) { - usb_init(); - } else { - adb_notify_device_scan_complete(); - } - - if (!getenv("ADB_EMU") || strcmp(getenv("ADB_EMU"), "0") != 0) { - local_init(android::base::StringPrintf("tcp:%d", DEFAULT_ADB_LOCAL_TRANSPORT_PORT)); - } - - std::string error; - - auto start = std::chrono::steady_clock::now(); - - // If we told a previous adb server to quit because of version mismatch, we can get to this - // point before it's finished exiting. Retry for a while to give it some time. - while (install_listener(socket_spec, "*smartsocket*", nullptr, 0, nullptr, &error) != - INSTALL_STATUS_OK) { - if (std::chrono::steady_clock::now() - start > 0.5s) { - LOG(FATAL) << "could not install *smartsocket* listener: " << error; - } - - std::this_thread::sleep_for(100ms); - } - - adb_auth_init(); - - if (is_daemon) { -#if !defined(_WIN32) - // Start a new session for the daemon. Do this here instead of after the fork so - // that a ctrl-c between the "starting server" and "done starting server" messages - // gets a chance to terminate the server. - // setsid will fail with EPERM if it's already been a lead process of new session. - // Ignore such error. - if (setsid() == -1 && errno != EPERM) { - PLOG(FATAL) << "setsid() failed"; - } -#endif - - // Wait for the USB scan to complete before notifying the parent that we're up. - // We need to perform this in a thread, because we would otherwise block the event loop. - std::thread notify_thread([ack_reply_fd]() { - adb_wait_for_device_initialization(); - - // Any error output written to stderr now goes to adb.log. We could - // keep around a copy of the stderr fd and use that to write any errors - // encountered by the following code, but that is probably overkill. -#if defined(_WIN32) - const HANDLE ack_reply_handle = cast_int_to_handle(ack_reply_fd); - const CHAR ack[] = "OK\n"; - const DWORD bytes_to_write = arraysize(ack) - 1; - DWORD written = 0; - if (!WriteFile(ack_reply_handle, ack, bytes_to_write, &written, NULL)) { - LOG(FATAL) << "cannot write ACK to handle " << ack_reply_handle - << android::base::SystemErrorCodeToString(GetLastError()); - } - if (written != bytes_to_write) { - LOG(FATAL) << "cannot write " << bytes_to_write << " bytes of ACK: only wrote " - << written << " bytes"; - } - CloseHandle(ack_reply_handle); -#else - // TODO(danalbert): Can't use SendOkay because we're sending "OK\n", not - // "OKAY". - if (!android::base::WriteStringToFd("OK\n", ack_reply_fd)) { - PLOG(FATAL) << "error writing ACK to fd " << ack_reply_fd; - } - unix_close(ack_reply_fd); -#endif - }); - notify_thread.detach(); - } - -#if defined(__linux__) - // Write our location to .android/adb.$PORT, so that older clients can exec us. - std::string path; - if (!android::base::Readlink("/proc/self/exe", &path)) { - PLOG(ERROR) << "failed to readlink /proc/self/exe"; - } - - std::optional server_executable_path = adb_get_server_executable_path(); - if (server_executable_path) { - if (!android::base::WriteStringToFile(path, *server_executable_path)) { - PLOG(ERROR) << "failed to write server path to " << path; - } - } -#endif - - D("Event loop starting"); - fdevent_loop(); - return 0; -} - -int main(int argc, char* argv[], char* envp[]) { - __adb_argv = const_cast(argv); - __adb_envp = const_cast(envp); - adb_trace_init(argv); - return adb_commandline(argc - 1, const_cast(argv + 1)); -} diff --git a/adb/client/pairing/pairing_client.cpp b/adb/client/pairing/pairing_client.cpp deleted file mode 100644 index 04bbcebd41a1b72fcf18c87a9261d73004a3c2e7..0000000000000000000000000000000000000000 --- a/adb/client/pairing/pairing_client.cpp +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (C) 2019 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 "client/pairing/pairing_client.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include "sysdeps.h" - -namespace adbwifi { -namespace pairing { - -using android::base::unique_fd; - -namespace { - -struct ConnectionDeleter { - void operator()(PairingConnectionCtx* p) { pairing_connection_destroy(p); } -}; // ConnectionDeleter -using ConnectionPtr = std::unique_ptr; - -class PairingClientImpl : public PairingClient { - public: - virtual ~PairingClientImpl(); - - explicit PairingClientImpl(const Data& pswd, const PeerInfo& peer_info, const Data& cert, - const Data& priv_key); - - // Starts the pairing client. This call is non-blocking. Upon pairing - // completion, |cb| will be called with the PeerInfo on success, - // or an empty value on failure. - // - // Returns true if PairingClient was successfully started. Otherwise, - // return false. - virtual bool Start(std::string_view ip_addr, pairing_client_result_cb cb, - void* opaque) override; - - static void OnPairingResult(const PeerInfo* peer_info, int fd, void* opaque); - - private: - // Setup and start the PairingConnection - bool StartConnection(); - - enum class State { - Ready, - Running, - Stopped, - }; - - State state_ = State::Ready; - Data pswd_; - PeerInfo peer_info_; - Data cert_; - Data priv_key_; - std::string host_; - int port_; - - ConnectionPtr connection_; - pairing_client_result_cb cb_; - void* opaque_ = nullptr; -}; // PairingClientImpl - -PairingClientImpl::PairingClientImpl(const Data& pswd, const PeerInfo& peer_info, const Data& cert, - const Data& priv_key) - : pswd_(pswd), peer_info_(peer_info), cert_(cert), priv_key_(priv_key) { - CHECK(!pswd_.empty() && !cert_.empty() && !priv_key_.empty()); - - state_ = State::Ready; -} - -PairingClientImpl::~PairingClientImpl() { - // Make sure to kill the PairingConnection before terminating the fdevent - // looper. - if (connection_ != nullptr) { - connection_.reset(); - } -} - -bool PairingClientImpl::Start(std::string_view ip_addr, pairing_client_result_cb cb, void* opaque) { - CHECK(!ip_addr.empty()); - cb_ = cb; - opaque_ = opaque; - - if (state_ != State::Ready) { - LOG(ERROR) << "PairingClient already running or finished"; - return false; - } - - // Try to parse the host address - std::string err; - CHECK(android::base::ParseNetAddress(std::string(ip_addr), &host_, &port_, nullptr, &err)); - CHECK(port_ > 0 && port_ <= 65535); - - if (!StartConnection()) { - LOG(ERROR) << "Unable to start PairingClient connection"; - state_ = State::Stopped; - return false; - } - - state_ = State::Running; - return true; -} - -bool PairingClientImpl::StartConnection() { - std::string err; - const int timeout = 10; // seconds - unique_fd fd(network_connect(host_, port_, SOCK_STREAM, timeout, &err)); - if (fd.get() == -1) { - LOG(ERROR) << "Failed to start pairing connection client [" << err << "]"; - return false; - } - int off = 1; - adb_setsockopt(fd.get(), IPPROTO_TCP, TCP_NODELAY, &off, sizeof(off)); - - connection_ = ConnectionPtr( - pairing_connection_client_new(pswd_.data(), pswd_.size(), &peer_info_, cert_.data(), - cert_.size(), priv_key_.data(), priv_key_.size())); - CHECK(connection_); - -#ifdef _WIN32 - int osh = cast_handle_to_int(adb_get_os_handle(fd.release())); -#else - int osh = adb_get_os_handle(fd.release()); -#endif - if (!pairing_connection_start(connection_.get(), osh, OnPairingResult, this)) { - LOG(ERROR) << "PairingClient failed to start the PairingConnection"; - state_ = State::Stopped; - return false; - } - - return true; -} - -// static -void PairingClientImpl::OnPairingResult(const PeerInfo* peer_info, int /* fd */, void* opaque) { - auto* p = reinterpret_cast(opaque); - p->cb_(peer_info, p->opaque_); -} - -} // namespace - -// static -std::unique_ptr PairingClient::Create(const Data& pswd, const PeerInfo& peer_info, - const Data& cert, const Data& priv_key) { - CHECK(!pswd.empty()); - CHECK(!cert.empty()); - CHECK(!priv_key.empty()); - - return std::unique_ptr(new PairingClientImpl(pswd, peer_info, cert, priv_key)); -} - -} // namespace pairing -} // namespace adbwifi diff --git a/adb/client/pairing/pairing_client.h b/adb/client/pairing/pairing_client.h deleted file mode 100644 index dbd72a54961da8a24b57679939c1c17ee882fa1a..0000000000000000000000000000000000000000 --- a/adb/client/pairing/pairing_client.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2019 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. - */ - -#pragma once - -#include -#include - -#include -#include -#include -#include - -#include "adb/pairing/pairing_connection.h" - -namespace adbwifi { -namespace pairing { - -typedef void (*pairing_client_result_cb)(const PeerInfo*, void*); - -// PairingClient is the client side of the PairingConnection protocol. It will -// attempt to connect to a PairingServer specified at |host| and |port|, and -// allocate a new PairingConnection for processing. -// -// See pairing_connection_test.cpp for example usage. -// -class PairingClient { - public: - using Data = std::vector; - - virtual ~PairingClient() = default; - - // Starts the pairing client. This call is non-blocking. Upon completion, - // if the pairing was successful, then |cb| will be called with the PeerInfo - // containing the info of the trusted peer. Otherwise, |cb| will be - // called with an empty value. Start can only be called once in the lifetime - // of this object. - // - // Returns true if PairingClient was successfully started. Otherwise, - // returns false. - virtual bool Start(std::string_view ip_addr, pairing_client_result_cb cb, void* opaque) = 0; - - // Creates a new PairingClient instance. May return null if unable - // to create an instance. |pswd|, |certificate|, |priv_key| and - // |ip_addr| cannot be empty. |peer_info| must contain non-empty strings for - // the guid and name fields. - static std::unique_ptr Create(const Data& pswd, const PeerInfo& peer_info, - const Data& certificate, const Data& priv_key); - - protected: - PairingClient() = default; -}; // class PairingClient - -} // namespace pairing -} // namespace adbwifi diff --git a/adb/client/pairing/tests/pairing_connection_test.cpp b/adb/client/pairing/tests/pairing_connection_test.cpp deleted file mode 100644 index c69c1c2bebd57f81b14cd99ea581726bfbbe7fed..0000000000000000000000000000000000000000 --- a/adb/client/pairing/tests/pairing_connection_test.cpp +++ /dev/null @@ -1,473 +0,0 @@ -/* - * Copyright 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "AdbWifiPairingConnectionTest" - -#include -#include -#include - -#include -#include -#include - -#include "adb/client/pairing/tests/pairing_client.h" - -namespace adbwifi { -namespace pairing { - -static const std::string kTestServerCert = - "-----BEGIN CERTIFICATE-----\n" - "MIIBljCCAT2gAwIBAgIBATAKBggqhkjOPQQDAjAzMQswCQYDVQQGEwJVUzEQMA4G\n" - "A1UECgwHQW5kcm9pZDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTE5MTEwNzAyMDkx\n" - "NVoXDTI5MTEwNDAyMDkxNVowMzELMAkGA1UEBhMCVVMxEDAOBgNVBAoMB0FuZHJv\n" - "aWQxEjAQBgNVBAMMCWxvY2FsaG9zdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA\n" - "BCXRovy3RhtK0Khle48vUmkcuI0OF7K8o9sVPE4oVnp24l+cCYr3BtrgifoHPgj4\n" - "vq7n105qzK7ngBHH+LBmYIijQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/\n" - "BAQDAgGGMB0GA1UdDgQWBBQi4eskzqVG3SCX2CwJF/aTZqUcuTAKBggqhkjOPQQD\n" - "AgNHADBEAiBPYvLOCIvPDtq3vMF7A2z7t7JfcCmbC7g8ftEVJucJBwIgepf+XjTb\n" - "L7RCE16p7iVkpHUrWAOl7zDxqD+jaji5MkQ=\n" - "-----END CERTIFICATE-----\n"; - -static const std::string kTestServerPrivKey = - "-----BEGIN PRIVATE KEY-----\n" - "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgSCaskWPtutIgh8uQ\n" - "UBH6ZIea5Kxm7m6kkGNkd8FYPSOhRANCAAQl0aL8t0YbStCoZXuPL1JpHLiNDhey\n" - "vKPbFTxOKFZ6duJfnAmK9wba4In6Bz4I+L6u59dOasyu54ARx/iwZmCI\n" - "-----END PRIVATE KEY-----\n"; - -static const std::string kTestClientCert = - "-----BEGIN CERTIFICATE-----\n" - "MIIBlzCCAT2gAwIBAgIBATAKBggqhkjOPQQDAjAzMQswCQYDVQQGEwJVUzEQMA4G\n" - "A1UECgwHQW5kcm9pZDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTE5MTEwOTAxNTAy\n" - "OFoXDTI5MTEwNjAxNTAyOFowMzELMAkGA1UEBhMCVVMxEDAOBgNVBAoMB0FuZHJv\n" - "aWQxEjAQBgNVBAMMCWxvY2FsaG9zdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA\n" - "BGW+RuoEIzbt42zAuZzbXaC0bvh8n4OLFDnqkkW6kWA43GYg/mUMVc9vg/nuxyuM\n" - "aT0KqbTaLhm+NjCXVRnxBrajQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/\n" - "BAQDAgGGMB0GA1UdDgQWBBTjCaC8/NXgdBz9WlMVCNwhx7jn0jAKBggqhkjOPQQD\n" - "AgNIADBFAiB/xp2boj7b1KK2saS6BL59deo/TvfgZ+u8HPq4k4VP3gIhAMXswp9W\n" - "XdlziccQdj+0KpbUojDKeHOr4fIj/+LxsWPa\n" - "-----END CERTIFICATE-----\n"; - -static const std::string kTestClientPrivKey = - "-----BEGIN PRIVATE KEY-----\n" - "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgFw/CWY1f6TSB70AF\n" - "yVe8n6QdYFu8HW5t/tij2SrXx42hRANCAARlvkbqBCM27eNswLmc212gtG74fJ+D\n" - "ixQ56pJFupFgONxmIP5lDFXPb4P57scrjGk9Cqm02i4ZvjYwl1UZ8Qa2\n" - "-----END PRIVATE KEY-----\n"; - -class AdbWifiPairingConnectionTest : public testing::Test { - protected: - virtual void SetUp() override {} - - virtual void TearDown() override {} - - void initPairing(const std::vector server_pswd, - const std::vector client_pswd) { - std::vector cert; - std::vector key; - // Include the null-byte as well. - cert.assign(reinterpret_cast(kTestServerCert.data()), - reinterpret_cast(kTestServerCert.data()) + - kTestServerCert.size() + 1); - key.assign(reinterpret_cast(kTestServerPrivKey.data()), - reinterpret_cast(kTestServerPrivKey.data()) + - kTestServerPrivKey.size() + 1); - server_ = PairingServer::create(server_pswd, server_info_, cert, key, kDefaultPairingPort); - cert.assign(reinterpret_cast(kTestClientCert.data()), - reinterpret_cast(kTestClientCert.data()) + - kTestClientCert.size() + 1); - key.assign(reinterpret_cast(kTestClientPrivKey.data()), - reinterpret_cast(kTestClientPrivKey.data()) + - kTestClientPrivKey.size() + 1); - client_ = PairingClient::create(client_pswd, client_info_, cert, key, "127.0.0.1"); - } - - std::unique_ptr createServer(const std::vector pswd) { - std::vector cert; - std::vector key; - // Include the null-byte as well. - cert.assign(reinterpret_cast(kTestServerCert.data()), - reinterpret_cast(kTestServerCert.data()) + - kTestServerCert.size() + 1); - key.assign(reinterpret_cast(kTestServerPrivKey.data()), - reinterpret_cast(kTestServerPrivKey.data()) + - kTestServerPrivKey.size() + 1); - return PairingServer::create(pswd, server_info_, cert, key, kDefaultPairingPort); - } - - std::unique_ptr createClient(const std::vector pswd) { - std::vector cert; - std::vector key; - // Include the null-byte as well. - cert.assign(reinterpret_cast(kTestClientCert.data()), - reinterpret_cast(kTestClientCert.data()) + - kTestClientCert.size() + 1); - key.assign(reinterpret_cast(kTestClientPrivKey.data()), - reinterpret_cast(kTestClientPrivKey.data()) + - kTestClientPrivKey.size() + 1); - return PairingClient::create(pswd, client_info_, cert, key, "127.0.0.1"); - } - - std::unique_ptr server_; - const PeerInfo server_info_ = { - .name = "my_server_name", - .guid = "my_server_guid", - }; - std::unique_ptr client_; - const PeerInfo client_info_ = { - .name = "my_client_name", - .guid = "my_client_guid", - }; -}; - -TEST_F(AdbWifiPairingConnectionTest, ServerCreation) { - // All parameters bad - auto server = PairingServer::create({}, {}, {}, {}, -1); - EXPECT_EQ(nullptr, server); - // Bad password - server = PairingServer::create({}, server_info_, {0x01}, {0x01}, -1); - EXPECT_EQ(nullptr, server); - // Bad peer_info - server = PairingServer::create({0x01}, {}, {0x01}, {0x01}, -1); - EXPECT_EQ(nullptr, server); - // Bad certificate - server = PairingServer::create({0x01}, server_info_, {}, {0x01}, -1); - EXPECT_EQ(nullptr, server); - // Bad private key - server = PairingServer::create({0x01}, server_info_, {0x01}, {}, -1); - EXPECT_EQ(nullptr, server); - // Bad port - server = PairingServer::create({0x01}, server_info_, {0x01}, {0x01}, -1); - EXPECT_EQ(nullptr, server); - // Valid params - server = PairingServer::create({0x01}, server_info_, {0x01}, {0x01}, 7776); - EXPECT_NE(nullptr, server); -} - -TEST_F(AdbWifiPairingConnectionTest, ClientCreation) { - // All parameters bad - auto client = PairingClient::create({}, client_info_, {}, {}, ""); - EXPECT_EQ(nullptr, client); - // Bad password - client = PairingClient::create({}, client_info_, {0x01}, {0x01}, "127.0.0.1"); - EXPECT_EQ(nullptr, client); - // Bad peer_info - client = PairingClient::create({0x01}, {}, {0x01}, {0x01}, "127.0.0.1"); - EXPECT_EQ(nullptr, client); - // Bad certificate - client = PairingClient::create({0x01}, client_info_, {}, {0x01}, "127.0.0.1"); - EXPECT_EQ(nullptr, client); - // Bad private key - client = PairingClient::create({0x01}, client_info_, {0x01}, {}, "127.0.0.1"); - EXPECT_EQ(nullptr, client); - // Bad ip address - client = PairingClient::create({0x01}, client_info_, {0x01}, {0x01}, ""); - EXPECT_EQ(nullptr, client); - // Valid params - client = PairingClient::create({0x01}, client_info_, {0x01}, {0x01}, "127.0.0.1"); - EXPECT_NE(nullptr, client); -} - -TEST_F(AdbWifiPairingConnectionTest, SmokeValidPairing) { - std::vector pswd{0x01, 0x03, 0x05, 0x07}; - initPairing(pswd, pswd); - - // Start the server first, to open the port for connections - std::mutex server_mutex; - std::condition_variable server_cv; - std::unique_lock server_lock(server_mutex); - - auto server_callback = [&](const PeerInfo* peer_info, const std::vector* cert, - void* opaque) { - ASSERT_NE(nullptr, peer_info); - ASSERT_NE(nullptr, cert); - EXPECT_FALSE(cert->empty()); - EXPECT_EQ(nullptr, opaque); - - // Verify the peer_info and cert - ASSERT_EQ(strlen(peer_info->name), strlen(client_info_.name)); - EXPECT_EQ(::memcmp(peer_info->name, client_info_.name, strlen(client_info_.name)), 0); - ASSERT_EQ(strlen(peer_info->guid), strlen(client_info_.guid)); - EXPECT_EQ(::memcmp(peer_info->guid, client_info_.guid, strlen(client_info_.guid)), 0); - ASSERT_EQ(cert->size(), kTestClientCert.size() + 1); - EXPECT_EQ(::memcmp(cert->data(), kTestClientCert.data(), kTestClientCert.size() + 1), 0); - - std::lock_guard lock(server_mutex); - server_cv.notify_one(); - }; - ASSERT_TRUE(server_->start(server_callback, nullptr)); - - // Start the client - bool got_valid_pairing = false; - std::mutex client_mutex; - std::condition_variable client_cv; - std::unique_lock client_lock(client_mutex); - auto client_callback = [&](const PeerInfo* peer_info, const std::vector* cert, - void* opaque) { - ASSERT_NE(nullptr, peer_info); - ASSERT_NE(nullptr, cert); - EXPECT_FALSE(cert->empty()); - EXPECT_EQ(nullptr, opaque); - - // Verify the peer_info and cert - ASSERT_EQ(strlen(peer_info->name), strlen(server_info_.name)); - EXPECT_EQ(::memcmp(peer_info->name, server_info_.name, strlen(server_info_.name)), 0); - ASSERT_EQ(strlen(peer_info->guid), strlen(server_info_.guid)); - EXPECT_EQ(::memcmp(peer_info->guid, server_info_.guid, strlen(server_info_.guid)), 0); - ASSERT_EQ(cert->size(), kTestServerCert.size() + 1); - EXPECT_EQ(::memcmp(cert->data(), kTestServerCert.data(), kTestServerCert.size() + 1), 0); - - got_valid_pairing = (peer_info != nullptr && cert != nullptr && !cert->empty()); - std::lock_guard lock(client_mutex); - client_cv.notify_one(); - }; - ASSERT_TRUE(client_->start(client_callback, nullptr)); - client_cv.wait(client_lock); - - // Kill server if the pairing failed, since server only shuts down when - // it gets a valid pairing. - if (!got_valid_pairing) { - server_lock.unlock(); - server_.reset(); - } else { - server_cv.wait(server_lock); - } -} - -TEST_F(AdbWifiPairingConnectionTest, CancelPairing) { - std::vector pswd{0x01, 0x03, 0x05, 0x07}; - std::vector pswd2{0x01, 0x03, 0x05, 0x06}; - initPairing(pswd, pswd2); - - // Start the server first, to open the port for connections - std::mutex server_mutex; - std::condition_variable server_cv; - std::unique_lock server_lock(server_mutex); - - bool server_got_valid_pairing = true; - auto server_callback = [&](const PeerInfo* peer_info, const std::vector* cert, - void* opaque) { - // Pairing will be cancelled, which should initiate this callback with - // empty values. - ASSERT_EQ(nullptr, peer_info); - ASSERT_EQ(nullptr, cert); - EXPECT_EQ(nullptr, opaque); - std::lock_guard lock(server_mutex); - server_cv.notify_one(); - server_got_valid_pairing = false; - }; - ASSERT_TRUE(server_->start(server_callback, nullptr)); - - // Start the client (should fail because of different passwords). - bool got_valid_pairing = false; - std::mutex client_mutex; - std::condition_variable client_cv; - std::unique_lock client_lock(client_mutex); - auto client_callback = [&](const PeerInfo* peer_info, const std::vector* cert, - void* opaque) { - ASSERT_EQ(nullptr, peer_info); - ASSERT_EQ(nullptr, cert); - EXPECT_EQ(nullptr, opaque); - - got_valid_pairing = (peer_info != nullptr && cert != nullptr && !cert->empty()); - std::lock_guard lock(client_mutex); - client_cv.notify_one(); - }; - ASSERT_TRUE(client_->start(client_callback, nullptr)); - client_cv.wait(client_lock); - - server_lock.unlock(); - // This should trigger the callback to be on the same thread. - server_.reset(); - EXPECT_FALSE(server_got_valid_pairing); -} - -TEST_F(AdbWifiPairingConnectionTest, MultipleClientsAllFail) { - std::vector pswd{0x01, 0x03, 0x05, 0x07}; - std::vector pswd2{0x01, 0x03, 0x05, 0x06}; - - auto server = createServer(pswd); - ASSERT_NE(nullptr, server); - // Start the server first, to open the port for connections - std::mutex server_mutex; - std::condition_variable server_cv; - std::unique_lock server_lock(server_mutex); - - bool server_got_valid_pairing = true; - auto server_callback = [&](const PeerInfo* peer_info, const std::vector* cert, - void* opaque) { - // Pairing will be cancelled, which should initiate this callback with - // empty values. - ASSERT_EQ(nullptr, peer_info); - ASSERT_EQ(nullptr, cert); - EXPECT_EQ(nullptr, opaque); - std::lock_guard lock(server_mutex); - server_cv.notify_one(); - server_got_valid_pairing = false; - }; - ASSERT_TRUE(server->start(server_callback, nullptr)); - - // Start multiple clients, all with bad passwords - std::vector> clients; - int num_clients_done = 0; - int test_num_clients = 5; - std::mutex client_mutex; - std::condition_variable client_cv; - std::unique_lock client_lock(client_mutex); - while (clients.size() < test_num_clients) { - auto client = createClient(pswd2); - ASSERT_NE(nullptr, client); - auto callback = [&](const PeerInfo* peer_info, const std::vector* cert, - void* opaque) { - ASSERT_EQ(nullptr, peer_info); - ASSERT_EQ(nullptr, cert); - EXPECT_EQ(nullptr, opaque); - - { - std::lock_guard lock(client_mutex); - num_clients_done++; - } - client_cv.notify_one(); - }; - ASSERT_TRUE(client->start(callback, nullptr)); - clients.push_back(std::move(client)); - } - - client_cv.wait(client_lock, [&]() { return (num_clients_done == test_num_clients); }); - EXPECT_EQ(num_clients_done, test_num_clients); - - server_lock.unlock(); - // This should trigger the callback to be on the same thread. - server.reset(); - EXPECT_FALSE(server_got_valid_pairing); -} - -TEST_F(AdbWifiPairingConnectionTest, MultipleClientsOnePass) { - // Send multiple clients with bad passwords, but send the last one with the - // correct password. - std::vector pswd{0x01, 0x03, 0x05, 0x07}; - std::vector pswd2{0x01, 0x03, 0x05, 0x06}; - - auto server = createServer(pswd); - ASSERT_NE(nullptr, server); - // Start the server first, to open the port for connections - std::mutex server_mutex; - std::condition_variable server_cv; - std::unique_lock server_lock(server_mutex); - - bool server_got_valid_pairing = false; - auto server_callback = [&](const PeerInfo* peer_info, const std::vector* cert, - void* opaque) { - // Pairing will be cancelled, which should initiate this callback with - // empty values. - - ASSERT_NE(nullptr, peer_info); - ASSERT_NE(nullptr, cert); - EXPECT_FALSE(cert->empty()); - EXPECT_EQ(nullptr, opaque); - - // Verify the peer_info and cert - ASSERT_EQ(strlen(peer_info->name), strlen(client_info_.name)); - EXPECT_EQ(::memcmp(peer_info->name, client_info_.name, strlen(client_info_.name)), 0); - ASSERT_EQ(strlen(peer_info->guid), strlen(client_info_.guid)); - EXPECT_EQ(::memcmp(peer_info->guid, client_info_.guid, strlen(client_info_.guid)), 0); - ASSERT_EQ(cert->size(), kTestClientCert.size() + 1); - EXPECT_EQ(::memcmp(cert->data(), kTestClientCert.data(), kTestClientCert.size() + 1), 0); - - std::lock_guard lock(server_mutex); - server_got_valid_pairing = true; - server_cv.notify_one(); - }; - ASSERT_TRUE(server->start(server_callback, nullptr)); - - // Start multiple clients, all with bad passwords (except for the last one) - std::vector> clients; - int num_clients_done = 0; - int test_num_clients = 5; - std::mutex client_mutex; - std::condition_variable client_cv; - std::unique_lock client_lock(client_mutex); - bool got_valid_pairing = false; - while (clients.size() < test_num_clients) { - std::unique_ptr client; - if (clients.size() == test_num_clients - 1) { - // Make this one have the valid password - client = createClient(pswd); - ASSERT_NE(nullptr, client); - auto callback = [&](const PeerInfo* peer_info, const std::vector* cert, - void* opaque) { - ASSERT_NE(nullptr, peer_info); - ASSERT_NE(nullptr, cert); - EXPECT_FALSE(cert->empty()); - EXPECT_EQ(nullptr, opaque); - - // Verify the peer_info and cert - ASSERT_EQ(strlen(peer_info->name), strlen(server_info_.name)); - EXPECT_EQ(::memcmp(peer_info->name, server_info_.name, strlen(server_info_.name)), - 0); - ASSERT_EQ(strlen(peer_info->guid), strlen(server_info_.guid)); - EXPECT_EQ(::memcmp(peer_info->guid, server_info_.guid, strlen(server_info_.guid)), - 0); - ASSERT_EQ(cert->size(), kTestServerCert.size() + 1); - EXPECT_EQ( - ::memcmp(cert->data(), kTestServerCert.data(), kTestServerCert.size() + 1), - 0); - got_valid_pairing = (peer_info != nullptr && cert != nullptr && !cert->empty()); - - { - std::lock_guard lock(client_mutex); - num_clients_done++; - } - client_cv.notify_one(); - }; - ASSERT_TRUE(client->start(callback, nullptr)); - } else { - client = createClient(pswd2); - ASSERT_NE(nullptr, client); - auto callback = [&](const PeerInfo* peer_info, const std::vector* cert, - void* opaque) { - ASSERT_EQ(nullptr, peer_info); - ASSERT_EQ(nullptr, cert); - EXPECT_EQ(nullptr, opaque); - - { - std::lock_guard lock(client_mutex); - num_clients_done++; - } - client_cv.notify_one(); - }; - ASSERT_TRUE(client->start(callback, nullptr)); - } - clients.push_back(std::move(client)); - } - - client_cv.wait(client_lock, [&]() { return (num_clients_done == test_num_clients); }); - EXPECT_EQ(num_clients_done, test_num_clients); - - // Kill server if the pairing failed, since server only shuts down when - // it gets a valid pairing. - if (!got_valid_pairing) { - server_lock.unlock(); - server_.reset(); - } else { - server_cv.wait(server_lock); - } - EXPECT_TRUE(server_got_valid_pairing); -} - -} // namespace pairing -} // namespace adbwifi diff --git a/adb/client/pairing/tests/pairing_server.cpp b/adb/client/pairing/tests/pairing_server.cpp deleted file mode 100644 index 9201e7a0e8e84e0606bd52c6117d9252cab19ee3..0000000000000000000000000000000000000000 --- a/adb/client/pairing/tests/pairing_server.cpp +++ /dev/null @@ -1,426 +0,0 @@ -/* - * Copyright (C) 2019 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 "adbwifi/pairing/pairing_server.h" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -namespace adbwifi { -namespace pairing { - -using android::base::ScopedLockAssertion; -using android::base::unique_fd; - -namespace { - -// The implimentation has two background threads running: one to handle and -// accept any new pairing connection requests (socket accept), and the other to -// handle connection events (connection started, connection finished). -class PairingServerImpl : public PairingServer { - public: - virtual ~PairingServerImpl(); - - // All parameters must be non-empty. - explicit PairingServerImpl(const Data& pswd, const PeerInfo& peer_info, const Data& cert, - const Data& priv_key, int port); - - // Starts the pairing server. This call is non-blocking. Upon completion, - // if the pairing was successful, then |cb| will be called with the PublicKeyHeader - // containing the info of the trusted peer. Otherwise, |cb| will be - // called with an empty value. Start can only be called once in the lifetime - // of this object. - // - // Returns true if PairingServer was successfully started. Otherwise, - // returns false. - virtual bool start(PairingConnection::ResultCallback cb, void* opaque) override; - - private: - // Setup the server socket to accept incoming connections - bool setupServer(); - // Force stop the server thread. - void stopServer(); - - // handles a new pairing client connection - bool handleNewClientConnection(int fd) EXCLUDES(conn_mutex_); - - // ======== connection events thread ============= - std::mutex conn_mutex_; - std::condition_variable conn_cv_; - - using FdVal = int; - using ConnectionPtr = std::unique_ptr; - using NewConnectionEvent = std::tuple; - // - using ConnectionFinishedEvent = std::tuple, - std::optional, std::optional>; - using ConnectionEvent = std::variant; - // Queue for connections to write into. We have a separate queue to read - // from, in order to minimize the time the server thread is blocked. - std::deque conn_write_queue_ GUARDED_BY(conn_mutex_); - std::deque conn_read_queue_; - // Map of fds to their PairingConnections currently running. - std::unordered_map connections_; - - // Two threads launched when starting the pairing server: - // 1) A server thread that waits for incoming client connections, and - // 2) A connection events thread that synchonizes events from all of the - // clients, since each PairingConnection is running in it's own thread. - void startConnectionEventsThread(); - void startServerThread(); - - std::thread conn_events_thread_; - void connectionEventsWorker(); - std::thread server_thread_; - void serverWorker(); - bool is_terminate_ GUARDED_BY(conn_mutex_) = false; - - enum class State { - Ready, - Running, - Stopped, - }; - State state_ = State::Ready; - Data pswd_; - PeerInfo peer_info_; - Data cert_; - Data priv_key_; - int port_ = -1; - - PairingConnection::ResultCallback cb_; - void* opaque_ = nullptr; - bool got_valid_pairing_ = false; - - static const int kEpollConstSocket = 0; - // Used to break the server thread from epoll_wait - static const int kEpollConstEventFd = 1; - unique_fd epoll_fd_; - unique_fd server_fd_; - unique_fd event_fd_; -}; // PairingServerImpl - -PairingServerImpl::PairingServerImpl(const Data& pswd, const PeerInfo& peer_info, const Data& cert, - const Data& priv_key, int port) - : pswd_(pswd), peer_info_(peer_info), cert_(cert), priv_key_(priv_key), port_(port) { - CHECK(!pswd_.empty() && !cert_.empty() && !priv_key_.empty() && port_ > 0); - CHECK('\0' == peer_info.name[kPeerNameLength - 1] && - '\0' == peer_info.guid[kPeerGuidLength - 1] && strlen(peer_info.name) > 0 && - strlen(peer_info.guid) > 0); -} - -PairingServerImpl::~PairingServerImpl() { - // Since these connections have references to us, let's make sure they - // destruct before us. - if (server_thread_.joinable()) { - stopServer(); - server_thread_.join(); - } - - { - std::lock_guard lock(conn_mutex_); - is_terminate_ = true; - } - conn_cv_.notify_one(); - if (conn_events_thread_.joinable()) { - conn_events_thread_.join(); - } - - // Notify the cb_ if it hasn't already. - if (!got_valid_pairing_ && cb_ != nullptr) { - cb_(nullptr, nullptr, opaque_); - } -} - -bool PairingServerImpl::start(PairingConnection::ResultCallback cb, void* opaque) { - cb_ = cb; - opaque_ = opaque; - - if (state_ != State::Ready) { - LOG(ERROR) << "PairingServer already running or stopped"; - return false; - } - - if (!setupServer()) { - LOG(ERROR) << "Unable to start PairingServer"; - state_ = State::Stopped; - return false; - } - - state_ = State::Running; - return true; -} - -void PairingServerImpl::stopServer() { - if (event_fd_.get() == -1) { - return; - } - uint64_t value = 1; - ssize_t rc = write(event_fd_.get(), &value, sizeof(value)); - if (rc == -1) { - // This can happen if the server didn't start. - PLOG(ERROR) << "write to eventfd failed"; - } else if (rc != sizeof(value)) { - LOG(FATAL) << "write to event returned short (" << rc << ")"; - } -} - -bool PairingServerImpl::setupServer() { - epoll_fd_.reset(epoll_create1(EPOLL_CLOEXEC)); - if (epoll_fd_ == -1) { - PLOG(ERROR) << "failed to create epoll fd"; - return false; - } - - event_fd_.reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); - if (event_fd_ == -1) { - PLOG(ERROR) << "failed to create eventfd"; - return false; - } - - server_fd_.reset(socket_inaddr_any_server(port_, SOCK_STREAM)); - if (server_fd_.get() == -1) { - PLOG(ERROR) << "Failed to start pairing connection server"; - return false; - } else if (fcntl(server_fd_.get(), F_SETFD, FD_CLOEXEC) != 0) { - PLOG(ERROR) << "Failed to make server socket cloexec"; - return false; - } else if (fcntl(server_fd_.get(), F_SETFD, O_NONBLOCK) != 0) { - PLOG(ERROR) << "Failed to make server socket nonblocking"; - return false; - } - - startConnectionEventsThread(); - startServerThread(); - return true; -} - -void PairingServerImpl::startServerThread() { - server_thread_ = std::thread([this]() { serverWorker(); }); -} - -void PairingServerImpl::startConnectionEventsThread() { - conn_events_thread_ = std::thread([this]() { connectionEventsWorker(); }); -} - -void PairingServerImpl::serverWorker() { - { - struct epoll_event event; - event.events = EPOLLIN; - event.data.u64 = kEpollConstSocket; - CHECK_EQ(0, epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, server_fd_.get(), &event)); - } - - { - struct epoll_event event; - event.events = EPOLLIN; - event.data.u64 = kEpollConstEventFd; - CHECK_EQ(0, epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, event_fd_.get(), &event)); - } - - while (true) { - struct epoll_event events[2]; - int rc = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd_.get(), events, 2, -1)); - if (rc == -1) { - PLOG(ERROR) << "epoll_wait failed"; - return; - } else if (rc == 0) { - LOG(ERROR) << "epoll_wait returned 0"; - return; - } - - for (int i = 0; i < rc; ++i) { - struct epoll_event& event = events[i]; - switch (event.data.u64) { - case kEpollConstSocket: - handleNewClientConnection(server_fd_.get()); - break; - case kEpollConstEventFd: - uint64_t dummy; - int rc = TEMP_FAILURE_RETRY(read(event_fd_.get(), &dummy, sizeof(dummy))); - if (rc != sizeof(dummy)) { - PLOG(FATAL) << "failed to read from eventfd (rc=" << rc << ")"; - } - return; - } - } - } -} - -void PairingServerImpl::connectionEventsWorker() { - for (;;) { - // Transfer the write queue to the read queue. - { - std::unique_lock lock(conn_mutex_); - ScopedLockAssertion assume_locked(conn_mutex_); - - if (is_terminate_) { - // We check |is_terminate_| twice because condition_variable's - // notify() only wakes up a thread if it is in the wait state - // prior to notify(). Furthermore, we aren't holding the mutex - // when processing the events in |conn_read_queue_|. - return; - } - if (conn_write_queue_.empty()) { - // We need to wait for new events, or the termination signal. - conn_cv_.wait(lock, [this]() REQUIRES(conn_mutex_) { - return (is_terminate_ || !conn_write_queue_.empty()); - }); - } - if (is_terminate_) { - // We're done. - return; - } - // Move all events into the read queue. - conn_read_queue_ = std::move(conn_write_queue_); - conn_write_queue_.clear(); - } - - // Process all events in the read queue. - while (conn_read_queue_.size() > 0) { - auto& event = conn_read_queue_.front(); - if (auto* p = std::get_if(&event)) { - // Ignore if we are already at the max number of connections - if (connections_.size() >= internal::kMaxConnections) { - conn_read_queue_.pop_front(); - continue; - } - auto [ufd, connection] = std::move(*p); - int fd = ufd.release(); - bool started = connection->start( - fd, - [fd](const PeerInfo* peer_info, const Data* cert, void* opaque) { - auto* p = reinterpret_cast(opaque); - - ConnectionFinishedEvent event; - if (peer_info != nullptr && cert != nullptr) { - event = std::make_tuple(fd, std::string(peer_info->name), - std::string(peer_info->guid), Data(*cert)); - } else { - event = std::make_tuple(fd, std::nullopt, std::nullopt, - std::nullopt); - } - { - std::lock_guard lock(p->conn_mutex_); - p->conn_write_queue_.push_back(std::move(event)); - } - p->conn_cv_.notify_one(); - }, - this); - if (!started) { - LOG(ERROR) << "PairingServer unable to start a PairingConnection fd=" << fd; - ufd.reset(fd); - } else { - connections_[fd] = std::move(connection); - } - } else if (auto* p = std::get_if(&event)) { - auto [fd, name, guid, cert] = std::move(*p); - if (name.has_value() && guid.has_value() && cert.has_value() && !name->empty() && - !guid->empty() && !cert->empty()) { - // Valid pairing. Let's shutdown the server and close any - // pairing connections in progress. - stopServer(); - connections_.clear(); - - CHECK_LE(name->size(), kPeerNameLength); - CHECK_LE(guid->size(), kPeerGuidLength); - PeerInfo info = {}; - strncpy(info.name, name->data(), name->size()); - strncpy(info.guid, guid->data(), guid->size()); - - cb_(&info, &*cert, opaque_); - - got_valid_pairing_ = true; - return; - } - // Invalid pairing. Close the invalid connection. - if (connections_.find(fd) != connections_.end()) { - connections_.erase(fd); - } - } - conn_read_queue_.pop_front(); - } - } -} - -bool PairingServerImpl::handleNewClientConnection(int fd) { - unique_fd ufd(TEMP_FAILURE_RETRY(accept4(fd, nullptr, nullptr, SOCK_CLOEXEC))); - if (ufd == -1) { - PLOG(WARNING) << "adb_socket_accept failed fd=" << fd; - return false; - } - auto connection = PairingConnection::create(PairingConnection::Role::Server, pswd_, peer_info_, - cert_, priv_key_); - if (connection == nullptr) { - LOG(ERROR) << "PairingServer unable to create a PairingConnection fd=" << fd; - return false; - } - // send the new connection to the connection thread for further processing - NewConnectionEvent event = std::make_tuple(std::move(ufd), std::move(connection)); - { - std::lock_guard lock(conn_mutex_); - conn_write_queue_.push_back(std::move(event)); - } - conn_cv_.notify_one(); - - return true; -} - -} // namespace - -// static -std::unique_ptr PairingServer::create(const Data& pswd, const PeerInfo& peer_info, - const Data& cert, const Data& priv_key, - int port) { - if (pswd.empty() || cert.empty() || priv_key.empty() || port <= 0) { - return nullptr; - } - // Make sure peer_info has a non-empty, null-terminated string for guid and - // name. - if ('\0' != peer_info.name[kPeerNameLength - 1] || - '\0' != peer_info.guid[kPeerGuidLength - 1] || strlen(peer_info.name) == 0 || - strlen(peer_info.guid) == 0) { - LOG(ERROR) << "The GUID/short name fields are empty or not null-terminated"; - return nullptr; - } - - if (port != kDefaultPairingPort) { - LOG(WARNING) << "Starting server with non-default pairing port=" << port; - } - - return std::unique_ptr( - new PairingServerImpl(pswd, peer_info, cert, priv_key, port)); -} - -} // namespace pairing -} // namespace adbwifi diff --git a/adb/client/pairing/tests/pairing_server.h b/adb/client/pairing/tests/pairing_server.h deleted file mode 100644 index 6fb51ccf1687c0c6b4ef7eb5c1c012926cf5d859..0000000000000000000000000000000000000000 --- a/adb/client/pairing/tests/pairing_server.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2019 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. - */ - -#pragma once - -#include -#include - -#include -#include -#include -#include - -#include - -namespace adbwifi { -namespace pairing { - -// PairingServer is the server side of the PairingConnection protocol. It will -// listen for incoming PairingClient connections, and allocate a new -// PairingConnection per client for processing. PairingServer can handle multiple -// connections, but the first one to establish the pairing will be the only one -// to succeed. All others will be disconnected. -// -// See pairing_connection_test.cpp for example usage. -// -class PairingServer { - public: - using Data = std::vector; - - virtual ~PairingServer() = default; - - // Starts the pairing server. This call is non-blocking. Upon completion, - // if the pairing was successful, then |cb| will be called with the PeerInfo - // containing the info of the trusted peer. Otherwise, |cb| will be - // called with an empty value. Start can only be called once in the lifetime - // of this object. - // - // Returns true if PairingServer was successfully started. Otherwise, - // returns false. - virtual bool start(PairingConnection::ResultCallback cb, void* opaque) = 0; - - // Creates a new PairingServer instance. May return null if unable - // to create an instance. |pswd|, |certificate| and |priv_key| cannot - // be empty. |port| is the port PairingServer will listen to PairingClient - // connections on. |peer_info| must contain non-empty strings for the guid - // and name fields. - static std::unique_ptr create(const Data& pswd, const PeerInfo& peer_info, - const Data& certificate, const Data& priv_key, - int port); - - protected: - PairingServer() = default; -}; // class PairingServer - -} // namespace pairing -} // namespace adbwifi diff --git a/adb/client/transport_mdns.cpp b/adb/client/transport_mdns.cpp deleted file mode 100644 index 22b9b18080225fdf408717eafbe3fe0b6de65b8d..0000000000000000000000000000000000000000 --- a/adb/client/transport_mdns.cpp +++ /dev/null @@ -1,547 +0,0 @@ -/* - * Copyright (C) 2016 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 TRANSPORT - -#include "transport.h" - -#ifdef _WIN32 -#include -#else -#include -#endif - -#include -#include -#include - -#include -#include -#include - -#include "adb_client.h" -#include "adb_mdns.h" -#include "adb_trace.h" -#include "adb_utils.h" -#include "adb_wifi.h" -#include "fdevent/fdevent.h" -#include "sysdeps.h" - -static DNSServiceRef service_refs[kNumADBDNSServices]; -static fdevent* service_ref_fdes[kNumADBDNSServices]; - -static int adb_DNSServiceIndexByName(const char* regType) { - for (int i = 0; i < kNumADBDNSServices; ++i) { - if (!strncmp(regType, kADBDNSServices[i], strlen(kADBDNSServices[i]))) { - return i; - } - } - return -1; -} - -static bool adb_DNSServiceShouldConnect(const char* regType, const char* serviceName) { - int index = adb_DNSServiceIndexByName(regType); - if (index == kADBTransportServiceRefIndex) { - // Ignore adb-EMULATOR* service names, as it interferes with the - // emulator ports that are already connected. - if (android::base::StartsWith(serviceName, "adb-EMULATOR")) { - LOG(INFO) << "Ignoring emulator transport service [" << serviceName << "]"; - return false; - } - } - return (index == kADBTransportServiceRefIndex || index == kADBSecureConnectServiceRefIndex); -} - -// Use adb_DNSServiceRefSockFD() instead of calling DNSServiceRefSockFD() -// directly so that the socket is put through the appropriate compatibility -// layers to work with the rest of ADB's internal APIs. -static inline int adb_DNSServiceRefSockFD(DNSServiceRef ref) { - return adb_register_socket(DNSServiceRefSockFD(ref)); -} -#define DNSServiceRefSockFD ___xxx_DNSServiceRefSockFD - -static void DNSSD_API register_service_ip(DNSServiceRef sdRef, - DNSServiceFlags flags, - uint32_t interfaceIndex, - DNSServiceErrorType errorCode, - const char* hostname, - const sockaddr* address, - uint32_t ttl, - void* context); - -static void pump_service_ref(int /*fd*/, unsigned ev, void* data) { - DNSServiceRef* ref = reinterpret_cast(data); - - if (ev & FDE_READ) - DNSServiceProcessResult(*ref); -} - -class AsyncServiceRef { - public: - bool Initialized() { - return initialized_; - } - - virtual ~AsyncServiceRef() { - if (!initialized_) { - return; - } - - // Order matters here! Must destroy the fdevent first since it has a - // reference to |sdRef_|. - fdevent_destroy(fde_); - DNSServiceRefDeallocate(sdRef_); - } - - protected: - DNSServiceRef sdRef_; - - void Initialize() { - fde_ = fdevent_create(adb_DNSServiceRefSockFD(sdRef_), pump_service_ref, &sdRef_); - if (fde_ == nullptr) { - D("Unable to create fdevent"); - return; - } - fdevent_set(fde_, FDE_READ); - initialized_ = true; - } - - private: - bool initialized_ = false; - fdevent* fde_; -}; - -class ResolvedService : public AsyncServiceRef { - public: - virtual ~ResolvedService() = default; - - ResolvedService(std::string serviceName, std::string regType, uint32_t interfaceIndex, - const char* hosttarget, uint16_t port, int version) - : serviceName_(serviceName), - regType_(regType), - hosttarget_(hosttarget), - port_(port), - sa_family_(0), - ip_addr_data_(NULL), - serviceVersion_(version) { - memset(ip_addr_, 0, sizeof(ip_addr_)); - - /* TODO: We should be able to get IPv6 support by adding - * kDNSServiceProtocol_IPv6 to the flags below. However, when we do - * this, we get served link-local addresses that are usually useless to - * connect to. What's more, we seem to /only/ get those and nothing else. - * If we want IPv6 in the future we'll have to figure out why. - */ - DNSServiceErrorType ret = - DNSServiceGetAddrInfo( - &sdRef_, 0, interfaceIndex, - kDNSServiceProtocol_IPv4, hosttarget, - register_service_ip, reinterpret_cast(this)); - - if (ret != kDNSServiceErr_NoError) { - D("Got %d from DNSServiceGetAddrInfo.", ret); - } else { - Initialize(); - } - - D("Client version: %d Service version: %d\n", clientVersion_, serviceVersion_); - } - - bool ConnectSecureWifiDevice() { - if (!adb_wifi_is_known_host(serviceName_)) { - LOG(INFO) << "serviceName=" << serviceName_ << " not in keystore"; - return false; - } - - std::string response; - connect_device(android::base::StringPrintf(addr_format_.c_str(), ip_addr_, port_), - &response); - D("Secure connect to %s regtype %s (%s:%hu) : %s", serviceName_.c_str(), regType_.c_str(), - ip_addr_, port_, response.c_str()); - return true; - } - - void Connect(const sockaddr* address) { - sa_family_ = address->sa_family; - - if (sa_family_ == AF_INET) { - ip_addr_data_ = &reinterpret_cast(address)->sin_addr; - addr_format_ = "%s:%hu"; - } else if (sa_family_ == AF_INET6) { - ip_addr_data_ = &reinterpret_cast(address)->sin6_addr; - addr_format_ = "[%s]:%hu"; - } else { // Should be impossible - D("mDNS resolved non-IP address."); - return; - } - - // Winsock version requires the const cast Because Microsoft. - if (!inet_ntop(sa_family_, const_cast(ip_addr_data_), ip_addr_, sizeof(ip_addr_))) { - D("Could not convert IP address to string."); - return; - } - - // adb secure service needs to do something different from just - // connecting here. - if (adb_DNSServiceShouldConnect(regType_.c_str(), serviceName_.c_str())) { - std::string response; - D("Attempting to serviceName=[%s], regtype=[%s] ipaddr=(%s:%hu)", serviceName_.c_str(), - regType_.c_str(), ip_addr_, port_); - int index = adb_DNSServiceIndexByName(regType_.c_str()); - if (index == kADBSecureConnectServiceRefIndex) { - ConnectSecureWifiDevice(); - } else { - connect_device(android::base::StringPrintf(addr_format_.c_str(), ip_addr_, port_), - &response); - D("Connect to %s regtype %s (%s:%hu) : %s", serviceName_.c_str(), regType_.c_str(), - ip_addr_, port_, response.c_str()); - } - } else { - D("Not immediately connecting to serviceName=[%s], regtype=[%s] ipaddr=(%s:%hu)", - serviceName_.c_str(), regType_.c_str(), ip_addr_, port_); - } - - int adbSecureServiceType = serviceIndex(); - switch (adbSecureServiceType) { - case kADBSecurePairingServiceRefIndex: - sAdbSecurePairingServices->push_back(this); - break; - case kADBSecureConnectServiceRefIndex: - sAdbSecureConnectServices->push_back(this); - break; - default: - break; - } - } - - int serviceIndex() const { return adb_DNSServiceIndexByName(regType_.c_str()); } - - std::string hostTarget() const { return hosttarget_; } - - std::string serviceName() const { return serviceName_; } - - std::string ipAddress() const { return ip_addr_; } - - uint16_t port() const { return port_; } - - using ServiceRegistry = std::vector; - - static ServiceRegistry* sAdbSecurePairingServices; - static ServiceRegistry* sAdbSecureConnectServices; - - static void initAdbSecure(); - - static void forEachService(const ServiceRegistry& services, const std::string& hostname, - adb_secure_foreach_service_callback cb); - - static bool connectByServiceName(const ServiceRegistry& services, - const std::string& service_name); - - private: - int clientVersion_ = ADB_SECURE_CLIENT_VERSION; - std::string addr_format_; - std::string serviceName_; - std::string regType_; - std::string hosttarget_; - const uint16_t port_; - int sa_family_; - const void* ip_addr_data_; - char ip_addr_[INET6_ADDRSTRLEN]; - int serviceVersion_; -}; - -// static -std::vector* ResolvedService::sAdbSecurePairingServices = NULL; - -// static -std::vector* ResolvedService::sAdbSecureConnectServices = NULL; - -// static -void ResolvedService::initAdbSecure() { - if (!sAdbSecurePairingServices) { - sAdbSecurePairingServices = new ServiceRegistry; - } - if (!sAdbSecureConnectServices) { - sAdbSecureConnectServices = new ServiceRegistry; - } -} - -// static -void ResolvedService::forEachService(const ServiceRegistry& services, - const std::string& wanted_service_name, - adb_secure_foreach_service_callback cb) { - initAdbSecure(); - - for (auto service : services) { - auto service_name = service->serviceName(); - auto ip = service->ipAddress(); - auto port = service->port(); - - if (wanted_service_name == "") { - cb(service_name.c_str(), ip.c_str(), port); - } else if (service_name == wanted_service_name) { - cb(service_name.c_str(), ip.c_str(), port); - } - } -} - -// static -bool ResolvedService::connectByServiceName(const ServiceRegistry& services, - const std::string& service_name) { - initAdbSecure(); - for (auto service : services) { - if (service_name == service->serviceName()) { - D("Got service_name match [%s]", service->serviceName().c_str()); - return service->ConnectSecureWifiDevice(); - } - } - D("No registered serviceNames matched [%s]", service_name.c_str()); - return false; -} - -void adb_secure_foreach_pairing_service(const char* service_name, - adb_secure_foreach_service_callback cb) { - ResolvedService::forEachService(*ResolvedService::sAdbSecurePairingServices, - service_name ? service_name : "", cb); -} - -void adb_secure_foreach_connect_service(const char* service_name, - adb_secure_foreach_service_callback cb) { - ResolvedService::forEachService(*ResolvedService::sAdbSecureConnectServices, - service_name ? service_name : "", cb); -} - -bool adb_secure_connect_by_service_name(const char* service_name) { - return ResolvedService::connectByServiceName(*ResolvedService::sAdbSecureConnectServices, - service_name); -} - -static void DNSSD_API register_service_ip(DNSServiceRef /*sdRef*/, - DNSServiceFlags /*flags*/, - uint32_t /*interfaceIndex*/, - DNSServiceErrorType /*errorCode*/, - const char* /*hostname*/, - const sockaddr* address, - uint32_t /*ttl*/, - void* context) { - D("Got IP for service."); - std::unique_ptr data( - reinterpret_cast(context)); - data->Connect(address); - - // For ADB Secure services, keep those ResolvedService's around - // for later processing with secure connection establishment. - if (data->serviceIndex() != kADBTransportServiceRefIndex) { - data.release(); - } -} - -static void DNSSD_API register_resolved_mdns_service(DNSServiceRef sdRef, - DNSServiceFlags flags, - uint32_t interfaceIndex, - DNSServiceErrorType errorCode, - const char* fullname, - const char* hosttarget, - uint16_t port, - uint16_t txtLen, - const unsigned char* txtRecord, - void* context); - -class DiscoveredService : public AsyncServiceRef { - public: - DiscoveredService(uint32_t interfaceIndex, const char* serviceName, const char* regtype, - const char* domain) - : serviceName_(serviceName), regType_(regtype) { - DNSServiceErrorType ret = - DNSServiceResolve(&sdRef_, 0, interfaceIndex, serviceName, regtype, - domain, register_resolved_mdns_service, - reinterpret_cast(this)); - - D("DNSServiceResolve for " - "interfaceIndex %u " - "serviceName %s " - "regtype %s " - "domain %s " - ": %d", - interfaceIndex, serviceName, regtype, domain, ret); - - if (ret == kDNSServiceErr_NoError) { - Initialize(); - } - } - - const char* ServiceName() { - return serviceName_.c_str(); - } - - const char* RegType() { return regType_.c_str(); } - - private: - std::string serviceName_; - std::string regType_; -}; - -static void adb_RemoveDNSService(const char* regType, const char* serviceName) { - int index = adb_DNSServiceIndexByName(regType); - ResolvedService::ServiceRegistry* services; - switch (index) { - case kADBSecurePairingServiceRefIndex: - services = ResolvedService::sAdbSecurePairingServices; - break; - case kADBSecureConnectServiceRefIndex: - services = ResolvedService::sAdbSecureConnectServices; - break; - default: - return; - } - - std::string sName(serviceName); - services->erase(std::remove_if( - services->begin(), services->end(), - [&sName](ResolvedService* service) { return (sName == service->serviceName()); })); -} - -// Returns the version the device wanted to advertise, -// or -1 if parsing fails. -static int parse_version_from_txt_record(uint16_t txtLen, const unsigned char* txtRecord) { - if (!txtLen) return -1; - if (!txtRecord) return -1; - - // https://tools.ietf.org/html/rfc6763 - // """ - // 6.1. General Format Rules for DNS TXT Records - // - // A DNS TXT record can be up to 65535 (0xFFFF) bytes long. The total - // length is indicated by the length given in the resource record header - // in the DNS message. There is no way to tell directly from the data - // alone how long it is (e.g., there is no length count at the start, or - // terminating NULL byte at the end). - // """ - - // Let's trust the TXT record's length byte - // Worst case, it wastes 255 bytes - std::vector recordAsString(txtLen + 1, '\0'); - char* str = recordAsString.data(); - - memcpy(str, txtRecord + 1 /* skip the length byte */, txtLen); - - // Check if it's the version key - static const char* versionKey = "v="; - size_t versionKeyLen = strlen(versionKey); - - if (strncmp(versionKey, str, versionKeyLen)) return -1; - - auto valueStart = str + versionKeyLen; - - long parsedNumber = strtol(valueStart, 0, 10); - - // No valid conversion. Also, 0 - // is not a valid version. - if (!parsedNumber) return -1; - - // Outside bounds of long. - if (parsedNumber == LONG_MIN || parsedNumber == LONG_MAX) return -1; - - // Possibly valid version - return static_cast(parsedNumber); -} - -static void DNSSD_API register_resolved_mdns_service( - DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, - DNSServiceErrorType errorCode, const char* fullname, const char* hosttarget, uint16_t port, - uint16_t txtLen, const unsigned char* txtRecord, void* context) { - D("Resolved a service."); - std::unique_ptr discovered( - reinterpret_cast(context)); - - if (errorCode != kDNSServiceErr_NoError) { - D("Got error %d resolving service.", errorCode); - return; - } - - // TODO: Reject certain combinations of invalid or mismatched client and - // service versions here before creating anything. - // At the moment, there is nothing to reject, so accept everything - // as an optimistic default. - auto serviceVersion = parse_version_from_txt_record(txtLen, txtRecord); - - auto resolved = new ResolvedService(discovered->ServiceName(), discovered->RegType(), - interfaceIndex, hosttarget, ntohs(port), serviceVersion); - - if (! resolved->Initialized()) { - D("Unable to init resolved service"); - delete resolved; - } - - if (flags) { /* Only ever equals MoreComing or 0 */ - D("releasing discovered service"); - discovered.release(); - } -} - -static void DNSSD_API on_service_browsed(DNSServiceRef sdRef, DNSServiceFlags flags, - uint32_t interfaceIndex, DNSServiceErrorType errorCode, - const char* serviceName, const char* regtype, - const char* domain, void* /*context*/) { - if (errorCode != kDNSServiceErr_NoError) { - D("Got error %d during mDNS browse.", errorCode); - DNSServiceRefDeallocate(sdRef); - int serviceIndex = adb_DNSServiceIndexByName(regtype); - if (serviceIndex != -1) { - fdevent_destroy(service_ref_fdes[serviceIndex]); - } - return; - } - - if (flags & kDNSServiceFlagsAdd) { - D("%s: Discover found new serviceName=[%s] regtype=[%s] domain=[%s]", __func__, serviceName, - regtype, domain); - auto discovered = new DiscoveredService(interfaceIndex, serviceName, regtype, domain); - if (!discovered->Initialized()) { - delete discovered; - } - } else { - D("%s: Discover lost serviceName=[%s] regtype=[%s] domain=[%s]", __func__, serviceName, - regtype, domain); - adb_RemoveDNSService(regtype, serviceName); - } -} - -void init_mdns_transport_discovery_thread(void) { - int errorCodes[kNumADBDNSServices]; - - for (int i = 0; i < kNumADBDNSServices; ++i) { - errorCodes[i] = DNSServiceBrowse(&service_refs[i], 0, 0, kADBDNSServices[i], nullptr, - on_service_browsed, nullptr); - - if (errorCodes[i] != kDNSServiceErr_NoError) { - D("Got %d browsing for mDNS service %s.", errorCodes[i], kADBDNSServices[i]); - } - - if (errorCodes[i] == kDNSServiceErr_NoError) { - fdevent_run_on_main_thread([i]() { - service_ref_fdes[i] = fdevent_create(adb_DNSServiceRefSockFD(service_refs[i]), - pump_service_ref, &service_refs[i]); - fdevent_set(service_ref_fdes[i], FDE_READ); - }); - } - } -} - -void init_mdns_transport_discovery(void) { - ResolvedService::initAdbSecure(); - std::thread(init_mdns_transport_discovery_thread).detach(); -} diff --git a/adb/client/transport_usb.cpp b/adb/client/transport_usb.cpp deleted file mode 100644 index 777edde0b3e2789d1e5b1d2e870a81c2259cd6c1..0000000000000000000000000000000000000000 --- a/adb/client/transport_usb.cpp +++ /dev/null @@ -1,212 +0,0 @@ -/* - * 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 TRANSPORT - -#include "sysdeps.h" - -#include "client/usb.h" - -#include - -#include "sysdeps.h" -#include "transport.h" - -#include -#include -#include - -#include "adb.h" - -#if ADB_HOST - -#if defined(__APPLE__) -#define CHECK_PACKET_OVERFLOW 0 -#else -#define CHECK_PACKET_OVERFLOW 1 -#endif - -// Call usb_read using a buffer having a multiple of usb_get_max_packet_size() bytes -// to avoid overflow. See http://libusb.sourceforge.net/api-1.0/packetoverflow.html. -static int UsbReadMessage(usb_handle* h, amessage* msg) { - D("UsbReadMessage"); - -#if CHECK_PACKET_OVERFLOW - size_t usb_packet_size = usb_get_max_packet_size(h); - CHECK_GE(usb_packet_size, sizeof(*msg)); - CHECK_LT(usb_packet_size, 4096ULL); - - char buffer[4096]; - int n = usb_read(h, buffer, usb_packet_size); - if (n != sizeof(*msg)) { - D("usb_read returned unexpected length %d (expected %zu)", n, sizeof(*msg)); - return -1; - } - memcpy(msg, buffer, sizeof(*msg)); - return n; -#else - return usb_read(h, msg, sizeof(*msg)); -#endif -} - -// Call usb_read using a buffer having a multiple of usb_get_max_packet_size() bytes -// to avoid overflow. See http://libusb.sourceforge.net/api-1.0/packetoverflow.html. -static int UsbReadPayload(usb_handle* h, apacket* p) { - D("UsbReadPayload(%d)", p->msg.data_length); - - if (p->msg.data_length > MAX_PAYLOAD) { - return -1; - } - -#if CHECK_PACKET_OVERFLOW - size_t usb_packet_size = usb_get_max_packet_size(h); - - // Round the data length up to the nearest packet size boundary. - // The device won't send a zero packet for packet size aligned payloads, - // so don't read any more packets than needed. - size_t len = p->msg.data_length; - size_t rem_size = len % usb_packet_size; - if (rem_size) { - len += usb_packet_size - rem_size; - } - - p->payload.resize(len); - int rc = usb_read(h, &p->payload[0], p->payload.size()); - if (rc != static_cast(p->msg.data_length)) { - return -1; - } - - p->payload.resize(rc); - return rc; -#else - p->payload.resize(p->msg.data_length); - return usb_read(h, &p->payload[0], p->payload.size()); -#endif -} - -static int remote_read(apacket* p, usb_handle* usb) { - int n = UsbReadMessage(usb, &p->msg); - if (n < 0) { - D("remote usb: read terminated (message)"); - return -1; - } - if (static_cast(n) != sizeof(p->msg)) { - D("remote usb: read received unexpected header length %d", n); - return -1; - } - if (p->msg.data_length) { - n = UsbReadPayload(usb, p); - if (n < 0) { - D("remote usb: terminated (data)"); - return -1; - } - if (static_cast(n) != p->msg.data_length) { - D("remote usb: read payload failed (need %u bytes, give %d bytes), skip it", - p->msg.data_length, n); - return -1; - } - } - return 0; -} - -#else - -// On Android devices, we rely on the kernel to provide buffered read. -// So we can recover automatically from EOVERFLOW. -static int remote_read(apacket* p, usb_handle* usb) { - if (usb_read(usb, &p->msg, sizeof(amessage)) != sizeof(amessage)) { - PLOG(ERROR) << "remote usb: read terminated (message)"; - return -1; - } - - if (p->msg.data_length) { - if (p->msg.data_length > MAX_PAYLOAD) { - PLOG(ERROR) << "remote usb: read overflow (data length = " << p->msg.data_length << ")"; - return -1; - } - - p->payload.resize(p->msg.data_length); - if (usb_read(usb, &p->payload[0], p->payload.size()) != - static_cast(p->payload.size())) { - PLOG(ERROR) << "remote usb: terminated (data)"; - return -1; - } - } - - return 0; -} -#endif - -UsbConnection::~UsbConnection() { - usb_close(handle_); -} - -bool UsbConnection::Read(apacket* packet) { - int rc = remote_read(packet, handle_); - return rc == 0; -} - -bool UsbConnection::Write(apacket* packet) { - int size = packet->msg.data_length; - - if (usb_write(handle_, &packet->msg, sizeof(packet->msg)) != sizeof(packet->msg)) { - PLOG(ERROR) << "remote usb: 1 - write terminated"; - return false; - } - - if (packet->msg.data_length != 0 && usb_write(handle_, packet->payload.data(), size) != size) { - PLOG(ERROR) << "remote usb: 2 - write terminated"; - return false; - } - - return true; -} - -bool UsbConnection::DoTlsHandshake(RSA* key, std::string* auth_key) { - // TODO: support TLS for usb connections - LOG(FATAL) << "Not supported yet."; - return false; -} - -void UsbConnection::Reset() { - usb_reset(handle_); - usb_kick(handle_); -} - -void UsbConnection::Close() { - usb_kick(handle_); -} - -void init_usb_transport(atransport* t, usb_handle* h) { - D("transport: usb"); - auto connection = std::make_unique(h); - t->SetConnection(std::make_unique(std::move(connection))); - t->type = kTransportUsb; - t->SetUsbHandle(h); -} - -int is_adb_interface(int usb_class, int usb_subclass, int usb_protocol) { - return (usb_class == ADB_CLASS && usb_subclass == ADB_SUBCLASS && usb_protocol == ADB_PROTOCOL); -} - -bool should_use_libusb() { -#if !ADB_HOST - return false; -#else - static bool enable = getenv("ADB_LIBUSB") && strcmp(getenv("ADB_LIBUSB"), "1") == 0; - return enable; -#endif -} diff --git a/adb/client/usb.h b/adb/client/usb.h deleted file mode 100644 index b371788cced2825a57404e957af671a71c532fb2..0000000000000000000000000000000000000000 --- a/adb/client/usb.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2016 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. - */ - -#pragma once - -#include - -#include "adb.h" -#include "transport.h" - -// USB host/client interface. - -#define ADB_USB_INTERFACE(handle_ref_type) \ - void usb_init(); \ - void usb_cleanup(); \ - int usb_write(handle_ref_type h, const void* data, int len); \ - int usb_read(handle_ref_type h, void* data, int len); \ - int usb_close(handle_ref_type h); \ - void usb_reset(handle_ref_type h); \ - void usb_kick(handle_ref_type h); \ - size_t usb_get_max_packet_size(handle_ref_type) - -// Linux and Darwin clients have native and libusb implementations. - -namespace libusb { -struct usb_handle; -ADB_USB_INTERFACE(libusb::usb_handle*); -} // namespace libusb - -namespace native { -struct usb_handle; -ADB_USB_INTERFACE(native::usb_handle*); -} // namespace native - -// Empty base that both implementations' opaque handles inherit from. -struct usb_handle {}; - -ADB_USB_INTERFACE(::usb_handle*); - -// USB device detection. -int is_adb_interface(int usb_class, int usb_subclass, int usb_protocol); - -bool should_use_libusb(); - -struct UsbConnection : public BlockingConnection { - explicit UsbConnection(usb_handle* handle) : handle_(handle) {} - ~UsbConnection(); - - bool Read(apacket* packet) override final; - bool Write(apacket* packet) override final; - bool DoTlsHandshake(RSA* key, std::string* auth_key) override final; - - void Close() override final; - virtual void Reset() override final; - - usb_handle* handle_; -}; diff --git a/adb/client/usb_dispatch.cpp b/adb/client/usb_dispatch.cpp deleted file mode 100644 index 7b97117de294f63b919d729c5af65cd72f88c5ff..0000000000000000000000000000000000000000 --- a/adb/client/usb_dispatch.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2017 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 "client/usb.h" - -void usb_init() { - if (should_use_libusb()) { - LOG(DEBUG) << "using libusb backend"; - libusb::usb_init(); - } else { - LOG(DEBUG) << "using native backend"; - native::usb_init(); - } -} - -void usb_cleanup() { - if (should_use_libusb()) { - libusb::usb_cleanup(); - } else { - native::usb_cleanup(); - } -} - -int usb_write(usb_handle* h, const void* data, int len) { - return should_use_libusb() - ? libusb::usb_write(reinterpret_cast(h), data, len) - : native::usb_write(reinterpret_cast(h), data, len); -} - -int usb_read(usb_handle* h, void* data, int len) { - return should_use_libusb() - ? libusb::usb_read(reinterpret_cast(h), data, len) - : native::usb_read(reinterpret_cast(h), data, len); -} - -int usb_close(usb_handle* h) { - return should_use_libusb() ? libusb::usb_close(reinterpret_cast(h)) - : native::usb_close(reinterpret_cast(h)); -} - -void usb_reset(usb_handle* h) { - should_use_libusb() ? libusb::usb_reset(reinterpret_cast(h)) - : native::usb_reset(reinterpret_cast(h)); -} - -void usb_kick(usb_handle* h) { - should_use_libusb() ? libusb::usb_kick(reinterpret_cast(h)) - : native::usb_kick(reinterpret_cast(h)); -} - -size_t usb_get_max_packet_size(usb_handle* h) { - return should_use_libusb() - ? libusb::usb_get_max_packet_size(reinterpret_cast(h)) - : native::usb_get_max_packet_size(reinterpret_cast(h)); -} diff --git a/adb/client/usb_libusb.cpp b/adb/client/usb_libusb.cpp deleted file mode 100644 index 07cbc9418ce1f569c2ce1d695488a3250247172d..0000000000000000000000000000000000000000 --- a/adb/client/usb_libusb.cpp +++ /dev/null @@ -1,638 +0,0 @@ -/* - * Copyright (C) 2016 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 "client/usb.h" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include "adb.h" -#include "adb_utils.h" -#include "transport.h" - -using android::base::StringPrintf; - -// RAII wrappers for libusb. -struct ConfigDescriptorDeleter { - void operator()(libusb_config_descriptor* desc) { - libusb_free_config_descriptor(desc); - } -}; - -using unique_config_descriptor = std::unique_ptr; - -struct DeviceHandleDeleter { - void operator()(libusb_device_handle* h) { - libusb_close(h); - } -}; - -using unique_device_handle = std::unique_ptr; - -struct transfer_info { - transfer_info(const char* name, uint16_t zero_mask, bool is_bulk_out) - : name(name), - transfer(libusb_alloc_transfer(0)), - is_bulk_out(is_bulk_out), - zero_mask(zero_mask) {} - - ~transfer_info() { - libusb_free_transfer(transfer); - } - - const char* name; - libusb_transfer* transfer; - bool is_bulk_out; - bool transfer_complete; - std::condition_variable cv; - std::mutex mutex; - uint16_t zero_mask; - - void Notify() { - LOG(DEBUG) << "notifying " << name << " transfer complete"; - transfer_complete = true; - cv.notify_one(); - } -}; - -namespace libusb { -struct usb_handle : public ::usb_handle { - usb_handle(const std::string& device_address, const std::string& serial, - unique_device_handle&& device_handle, uint8_t interface, uint8_t bulk_in, - uint8_t bulk_out, size_t zero_mask, size_t max_packet_size) - : device_address(device_address), - serial(serial), - closing(false), - device_handle(device_handle.release()), - read("read", zero_mask, false), - write("write", zero_mask, true), - interface(interface), - bulk_in(bulk_in), - bulk_out(bulk_out), - max_packet_size(max_packet_size) {} - - ~usb_handle() { - Close(); - } - - void Close() { - std::unique_lock lock(device_handle_mutex); - // Cancelling transfers will trigger more Closes, so make sure this only happens once. - if (closing) { - return; - } - closing = true; - - // Make sure that no new transfers come in. - libusb_device_handle* handle = device_handle; - if (!handle) { - return; - } - - device_handle = nullptr; - - // Cancel already dispatched transfers. - libusb_cancel_transfer(read.transfer); - libusb_cancel_transfer(write.transfer); - - libusb_release_interface(handle, interface); - libusb_close(handle); - } - - std::string device_address; - std::string serial; - - std::atomic closing; - std::mutex device_handle_mutex; - libusb_device_handle* device_handle; - - transfer_info read; - transfer_info write; - - uint8_t interface; - uint8_t bulk_in; - uint8_t bulk_out; - - size_t max_packet_size; -}; - -static auto& usb_handles = *new std::unordered_map>(); -static auto& usb_handles_mutex = *new std::mutex(); - -static libusb_hotplug_callback_handle hotplug_handle; - -static std::string get_device_address(libusb_device* device) { - return StringPrintf("usb:%d:%d", libusb_get_bus_number(device), - libusb_get_device_address(device)); -} - -#if defined(__linux__) -static std::string get_device_serial_path(libusb_device* device) { - uint8_t ports[7]; - int port_count = libusb_get_port_numbers(device, ports, 7); - if (port_count < 0) return ""; - - std::string path = - StringPrintf("/sys/bus/usb/devices/%d-%d", libusb_get_bus_number(device), ports[0]); - for (int port = 1; port < port_count; ++port) { - path += StringPrintf(".%d", ports[port]); - } - path += "/serial"; - return path; -} - -static std::string get_device_dev_path(libusb_device* device) { - uint8_t ports[7]; - int port_count = libusb_get_port_numbers(device, ports, 7); - if (port_count < 0) return ""; - return StringPrintf("/dev/bus/usb/%03u/%03u", libusb_get_bus_number(device), ports[0]); -} -#endif - -static bool endpoint_is_output(uint8_t endpoint) { - return (endpoint & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_OUT; -} - -static bool should_perform_zero_transfer(uint8_t endpoint, size_t write_length, uint16_t zero_mask) { - return endpoint_is_output(endpoint) && write_length != 0 && zero_mask != 0 && - (write_length & zero_mask) == 0; -} - -static void process_device(libusb_device* device) { - std::string device_address = get_device_address(device); - std::string device_serial; - - // Figure out if we want to open the device. - libusb_device_descriptor device_desc; - int rc = libusb_get_device_descriptor(device, &device_desc); - if (rc != 0) { - LOG(WARNING) << "failed to get device descriptor for device at " << device_address << ": " - << libusb_error_name(rc); - return; - } - - if (device_desc.bDeviceClass != LIBUSB_CLASS_PER_INTERFACE) { - // Assume that all Android devices have the device class set to per interface. - // TODO: Is this assumption valid? - LOG(VERBOSE) << "skipping device with incorrect class at " << device_address; - return; - } - - libusb_config_descriptor* config_raw; - rc = libusb_get_active_config_descriptor(device, &config_raw); - if (rc != 0) { - LOG(WARNING) << "failed to get active config descriptor for device at " << device_address - << ": " << libusb_error_name(rc); - return; - } - const unique_config_descriptor config(config_raw); - - // Use size_t for interface_num so s don't mangle it. - size_t interface_num; - uint16_t zero_mask = 0; - uint8_t bulk_in = 0, bulk_out = 0; - size_t packet_size = 0; - bool found_adb = false; - - for (interface_num = 0; interface_num < config->bNumInterfaces; ++interface_num) { - const libusb_interface& interface = config->interface[interface_num]; - if (interface.num_altsetting != 1) { - // Assume that interfaces with alternate settings aren't adb interfaces. - // TODO: Is this assumption valid? - LOG(VERBOSE) << "skipping interface with incorrect num_altsetting at " << device_address - << " (interface " << interface_num << ")"; - continue; - } - - const libusb_interface_descriptor& interface_desc = interface.altsetting[0]; - if (!is_adb_interface(interface_desc.bInterfaceClass, interface_desc.bInterfaceSubClass, - interface_desc.bInterfaceProtocol)) { - LOG(VERBOSE) << "skipping non-adb interface at " << device_address << " (interface " - << interface_num << ")"; - continue; - } - - LOG(VERBOSE) << "found potential adb interface at " << device_address << " (interface " - << interface_num << ")"; - - bool found_in = false; - bool found_out = false; - for (size_t endpoint_num = 0; endpoint_num < interface_desc.bNumEndpoints; ++endpoint_num) { - const auto& endpoint_desc = interface_desc.endpoint[endpoint_num]; - const uint8_t endpoint_addr = endpoint_desc.bEndpointAddress; - const uint8_t endpoint_attr = endpoint_desc.bmAttributes; - - const uint8_t transfer_type = endpoint_attr & LIBUSB_TRANSFER_TYPE_MASK; - - if (transfer_type != LIBUSB_TRANSFER_TYPE_BULK) { - continue; - } - - if (endpoint_is_output(endpoint_addr) && !found_out) { - found_out = true; - bulk_out = endpoint_addr; - zero_mask = endpoint_desc.wMaxPacketSize - 1; - } else if (!endpoint_is_output(endpoint_addr) && !found_in) { - found_in = true; - bulk_in = endpoint_addr; - } - - size_t endpoint_packet_size = endpoint_desc.wMaxPacketSize; - CHECK(endpoint_packet_size != 0); - if (packet_size == 0) { - packet_size = endpoint_packet_size; - } else { - CHECK(packet_size == endpoint_packet_size); - } - } - - if (found_in && found_out) { - found_adb = true; - break; - } else { - LOG(VERBOSE) << "rejecting potential adb interface at " << device_address - << "(interface " << interface_num << "): missing bulk endpoints " - << "(found_in = " << found_in << ", found_out = " << found_out << ")"; - } - } - - if (!found_adb) { - LOG(VERBOSE) << "skipping device with no adb interfaces at " << device_address; - return; - } - - { - std::unique_lock lock(usb_handles_mutex); - if (usb_handles.find(device_address) != usb_handles.end()) { - LOG(VERBOSE) << "device at " << device_address - << " has already been registered, skipping"; - return; - } - } - - bool writable = true; - libusb_device_handle* handle_raw = nullptr; - rc = libusb_open(device, &handle_raw); - unique_device_handle handle(handle_raw); - if (rc == 0) { - LOG(DEBUG) << "successfully opened adb device at " << device_address << ", " - << StringPrintf("bulk_in = %#x, bulk_out = %#x", bulk_in, bulk_out); - - device_serial.resize(255); - rc = libusb_get_string_descriptor_ascii(handle_raw, device_desc.iSerialNumber, - reinterpret_cast(&device_serial[0]), - device_serial.length()); - if (rc == 0) { - LOG(WARNING) << "received empty serial from device at " << device_address; - return; - } else if (rc < 0) { - LOG(WARNING) << "failed to get serial from device at " << device_address - << libusb_error_name(rc); - return; - } - device_serial.resize(rc); - - // WARNING: this isn't released via RAII. - rc = libusb_claim_interface(handle.get(), interface_num); - if (rc != 0) { - LOG(WARNING) << "failed to claim adb interface for device '" << device_serial << "'" - << libusb_error_name(rc); - return; - } - - for (uint8_t endpoint : {bulk_in, bulk_out}) { - rc = libusb_clear_halt(handle.get(), endpoint); - if (rc != 0) { - LOG(WARNING) << "failed to clear halt on device '" << device_serial - << "' endpoint 0x" << std::hex << endpoint << ": " - << libusb_error_name(rc); - libusb_release_interface(handle.get(), interface_num); - return; - } - } - } else { - LOG(WARNING) << "failed to open usb device at " << device_address << ": " - << libusb_error_name(rc); - writable = false; - -#if defined(__linux__) - // libusb doesn't think we should be messing around with devices we don't have - // write access to, but Linux at least lets us get the serial number anyway. - if (!android::base::ReadFileToString(get_device_serial_path(device), &device_serial)) { - // We don't actually want to treat an unknown serial as an error because - // devices aren't able to communicate a serial number in early bringup. - // http://b/20883914 - device_serial = "unknown"; - } - device_serial = android::base::Trim(device_serial); -#else - // On Mac OS and Windows, we're screwed. But I don't think this situation actually - // happens on those OSes. - return; -#endif - } - - std::unique_ptr result(new usb_handle(device_address, device_serial, - std::move(handle), interface_num, bulk_in, - bulk_out, zero_mask, packet_size)); - usb_handle* usb_handle_raw = result.get(); - - { - std::unique_lock lock(usb_handles_mutex); - usb_handles[device_address] = std::move(result); - - register_usb_transport(usb_handle_raw, device_serial.c_str(), device_address.c_str(), - writable); - } - LOG(INFO) << "registered new usb device '" << device_serial << "'"; -} - -static std::atomic connecting_devices(0); - -static void device_connected(libusb_device* device) { -#if defined(__linux__) - // Android's host linux libusb uses netlink instead of udev for device hotplug notification, - // which means we can get hotplug notifications before udev has updated ownership/perms on the - // device. Since we're not going to be able to link against the system's libudev any time soon, - // hack around this by inserting a sleep. - auto thread = std::thread([device]() { - std::string device_path = get_device_dev_path(device); - std::this_thread::sleep_for(std::chrono::seconds(1)); - - process_device(device); - if (--connecting_devices == 0) { - adb_notify_device_scan_complete(); - } - }); - thread.detach(); -#else - process_device(device); -#endif -} - -static void device_disconnected(libusb_device* device) { - std::string device_address = get_device_address(device); - - LOG(INFO) << "device disconnected: " << device_address; - std::unique_lock lock(usb_handles_mutex); - auto it = usb_handles.find(device_address); - if (it != usb_handles.end()) { - if (!it->second->device_handle) { - // If the handle is null, we were never able to open the device. - - // Temporarily release the usb handles mutex to avoid deadlock. - std::unique_ptr handle = std::move(it->second); - usb_handles.erase(it); - lock.unlock(); - unregister_usb_transport(handle.get()); - lock.lock(); - } else { - // Closure of the transport will erase the usb_handle. - } - } -} - -static auto& hotplug_queue = *new BlockingQueue>(); -static void hotplug_thread() { - adb_thread_setname("libusb hotplug"); - while (true) { - hotplug_queue.PopAll([](std::pair pair) { - libusb_hotplug_event event = pair.first; - libusb_device* device = pair.second; - if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) { - device_connected(device); - } else if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) { - device_disconnected(device); - } - }); - } -} - -static LIBUSB_CALL int hotplug_callback(libusb_context*, libusb_device* device, - libusb_hotplug_event event, void*) { - // We're called with the libusb lock taken. Call these on a separate thread outside of this - // function so that the usb_handle mutex is always taken before the libusb mutex. - static std::once_flag once; - std::call_once(once, []() { std::thread(hotplug_thread).detach(); }); - - if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) { - ++connecting_devices; - } - hotplug_queue.Push({event, device}); - return 0; -} - -void usb_init() { - LOG(DEBUG) << "initializing libusb..."; - int rc = libusb_init(nullptr); - if (rc != 0) { - LOG(FATAL) << "failed to initialize libusb: " << libusb_error_name(rc); - } - - // Register the hotplug callback. - rc = libusb_hotplug_register_callback( - nullptr, static_cast(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | - LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT), - LIBUSB_HOTPLUG_ENUMERATE, LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY, - LIBUSB_CLASS_PER_INTERFACE, hotplug_callback, nullptr, &hotplug_handle); - - if (rc != LIBUSB_SUCCESS) { - LOG(FATAL) << "failed to register libusb hotplug callback"; - } - - // Spawn a thread for libusb_handle_events. - std::thread([]() { - adb_thread_setname("libusb"); - while (true) { - libusb_handle_events(nullptr); - } - }).detach(); -} - -void usb_cleanup() { - libusb_hotplug_deregister_callback(nullptr, hotplug_handle); -} - -static LIBUSB_CALL void transfer_callback(libusb_transfer* transfer) { - transfer_info* info = static_cast(transfer->user_data); - - LOG(DEBUG) << info->name << " transfer callback entered"; - - // Make sure that the original submitter has made it to the condition_variable wait. - std::unique_lock lock(info->mutex); - - LOG(DEBUG) << info->name << " callback successfully acquired lock"; - - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { - LOG(WARNING) << info->name << " transfer failed: " << libusb_error_name(transfer->status); - info->Notify(); - return; - } - - // usb_read() can return when receiving some data. - if (info->is_bulk_out && transfer->actual_length != transfer->length) { - LOG(DEBUG) << info->name << " transfer incomplete, resubmitting"; - transfer->length -= transfer->actual_length; - transfer->buffer += transfer->actual_length; - int rc = libusb_submit_transfer(transfer); - if (rc != 0) { - LOG(WARNING) << "failed to submit " << info->name - << " transfer: " << libusb_error_name(rc); - transfer->status = LIBUSB_TRANSFER_ERROR; - info->Notify(); - } - return; - } - - if (should_perform_zero_transfer(transfer->endpoint, transfer->length, info->zero_mask)) { - LOG(DEBUG) << "submitting zero-length write"; - transfer->length = 0; - int rc = libusb_submit_transfer(transfer); - if (rc != 0) { - LOG(WARNING) << "failed to submit zero-length write: " << libusb_error_name(rc); - transfer->status = LIBUSB_TRANSFER_ERROR; - info->Notify(); - } - return; - } - - LOG(VERBOSE) << info->name << "transfer fully complete"; - info->Notify(); -} - -// Dispatch a libusb transfer, unlock |device_lock|, and then wait for the result. -static int perform_usb_transfer(usb_handle* h, transfer_info* info, - std::unique_lock device_lock) { - libusb_transfer* transfer = info->transfer; - - transfer->user_data = info; - transfer->callback = transfer_callback; - - LOG(DEBUG) << "locking " << info->name << " transfer_info mutex"; - std::unique_lock lock(info->mutex); - info->transfer_complete = false; - LOG(DEBUG) << "submitting " << info->name << " transfer"; - int rc = libusb_submit_transfer(transfer); - if (rc != 0) { - LOG(WARNING) << "failed to submit " << info->name << " transfer: " << libusb_error_name(rc); - errno = EIO; - return -1; - } - - LOG(DEBUG) << info->name << " transfer successfully submitted"; - device_lock.unlock(); - info->cv.wait(lock, [info]() { return info->transfer_complete; }); - if (transfer->status != 0) { - errno = EIO; - return -1; - } - - return 0; -} - -int usb_write(usb_handle* h, const void* d, int len) { - LOG(DEBUG) << "usb_write of length " << len; - - std::unique_lock lock(h->device_handle_mutex); - if (!h->device_handle) { - errno = EIO; - return -1; - } - - transfer_info* info = &h->write; - info->transfer->dev_handle = h->device_handle; - info->transfer->flags = 0; - info->transfer->endpoint = h->bulk_out; - info->transfer->type = LIBUSB_TRANSFER_TYPE_BULK; - info->transfer->length = len; - info->transfer->buffer = reinterpret_cast(const_cast(d)); - info->transfer->num_iso_packets = 0; - - int rc = perform_usb_transfer(h, info, std::move(lock)); - LOG(DEBUG) << "usb_write(" << len << ") = " << rc; - return info->transfer->actual_length; -} - -int usb_read(usb_handle* h, void* d, int len) { - LOG(DEBUG) << "usb_read of length " << len; - - std::unique_lock lock(h->device_handle_mutex); - if (!h->device_handle) { - errno = EIO; - return -1; - } - - transfer_info* info = &h->read; - info->transfer->dev_handle = h->device_handle; - info->transfer->flags = 0; - info->transfer->endpoint = h->bulk_in; - info->transfer->type = LIBUSB_TRANSFER_TYPE_BULK; - info->transfer->length = len; - info->transfer->buffer = reinterpret_cast(d); - info->transfer->num_iso_packets = 0; - - int rc = perform_usb_transfer(h, info, std::move(lock)); - LOG(DEBUG) << "usb_read(" << len << ") = " << rc << ", actual_length " - << info->transfer->actual_length; - if (rc < 0) { - return rc; - } - return info->transfer->actual_length; -} - -int usb_close(usb_handle* h) { - std::unique_lock lock(usb_handles_mutex); - auto it = usb_handles.find(h->device_address); - if (it == usb_handles.end()) { - LOG(FATAL) << "attempted to close unregistered usb_handle for '" << h->serial << "'"; - } - usb_handles.erase(h->device_address); - return 0; -} - -void usb_reset(usb_handle* h) { - libusb_reset_device(h->device_handle); - usb_kick(h); -} - -void usb_kick(usb_handle* h) { - h->Close(); -} - -size_t usb_get_max_packet_size(usb_handle* h) { - CHECK(h->max_packet_size != 0); - return h->max_packet_size; -} - -} // namespace libusb diff --git a/adb/client/usb_linux.cpp b/adb/client/usb_linux.cpp deleted file mode 100644 index 95b1817dcf9772d319a8958b4d986a740f67b9e5..0000000000000000000000000000000000000000 --- a/adb/client/usb_linux.cpp +++ /dev/null @@ -1,632 +0,0 @@ -/* - * 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 USB - -#include "sysdeps.h" - -#include "client/usb.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "adb.h" -#include "transport.h" - -using namespace std::chrono_literals; -using namespace std::literals; - -/* usb scan debugging is waaaay too verbose */ -#define DBGX(x...) - -namespace native { -struct usb_handle : public ::usb_handle { - ~usb_handle() { - if (fd != -1) unix_close(fd); - } - - std::string path; - int fd = -1; - unsigned char ep_in; - unsigned char ep_out; - - size_t max_packet_size; - unsigned zero_mask; - unsigned writeable = 1; - - usbdevfs_urb urb_in; - usbdevfs_urb urb_out; - - bool urb_in_busy = false; - bool urb_out_busy = false; - bool dead = false; - - std::condition_variable cv; - std::mutex mutex; - - // for garbage collecting disconnected devices - bool mark; - - // ID of thread currently in REAPURB - pthread_t reaper_thread = 0; -}; - -static auto& g_usb_handles_mutex = *new std::mutex(); -static auto& g_usb_handles = *new std::list(); - -static int is_known_device(std::string_view dev_name) { - std::lock_guard lock(g_usb_handles_mutex); - for (usb_handle* usb : g_usb_handles) { - if (usb->path == dev_name) { - // set mark flag to indicate this device is still alive - usb->mark = true; - return 1; - } - } - return 0; -} - -static void kick_disconnected_devices() { - std::lock_guard lock(g_usb_handles_mutex); - // kick any devices in the device list that were not found in the device scan - for (usb_handle* usb : g_usb_handles) { - if (!usb->mark) { - usb_kick(usb); - } else { - usb->mark = false; - } - } -} - -static inline bool contains_non_digit(const char* name) { - while (*name) { - if (!isdigit(*name++)) return true; - } - return false; -} - -static void find_usb_device(const std::string& base, - void (*register_device_callback)(const char*, const char*, - unsigned char, unsigned char, int, int, - unsigned, size_t)) { - std::unique_ptr bus_dir(opendir(base.c_str()), closedir); - if (!bus_dir) return; - - dirent* de; - while ((de = readdir(bus_dir.get())) != nullptr) { - if (contains_non_digit(de->d_name)) continue; - - std::string bus_name = base + "/" + de->d_name; - - std::unique_ptr dev_dir(opendir(bus_name.c_str()), closedir); - if (!dev_dir) continue; - - while ((de = readdir(dev_dir.get()))) { - 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; - size_t max_packet_size = 0; - unsigned vid, pid; - - if (contains_non_digit(de->d_name)) continue; - - std::string dev_name = bus_name + "/" + de->d_name; - if (is_known_device(dev_name)) { - continue; - } - - int fd = unix_open(dev_name, O_RDONLY | O_CLOEXEC); - if (fd == -1) { - continue; - } - - size_t desclength = unix_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", desclength); - unix_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)) { - unix_close(fd); - continue; - } - - vid = device->idVendor; - pid = device->idProduct; - DBGX("[ %s is V:%04x P:%04x ]\n", dev_name.c_str(), 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"); - unix_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"); - 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(interface->bInterfaceClass, interface->bInterfaceSubClass, - interface->bInterfaceProtocol)) { - struct stat st; - char pathbuf[128]; - char link[256]; - char *devpath = nullptr; - - DBGX("looking for bulk endpoints\n"); - // looks like ADB... - ep1 = (struct usb_endpoint_descriptor *)bufptr; - bufptr += USB_DT_ENDPOINT_SIZE; - // For USB 3.0 SuperSpeed devices, skip potential - // USB 3.0 SuperSpeed Endpoint Companion descriptor - if (bufptr+2 <= devdesc + desclength && - bufptr[0] == USB_DT_SS_EP_COMP_SIZE && - bufptr[1] == USB_DT_SS_ENDPOINT_COMP) { - bufptr += USB_DT_SS_EP_COMP_SIZE; - } - ep2 = (struct usb_endpoint_descriptor *)bufptr; - bufptr += USB_DT_ENDPOINT_SIZE; - if (bufptr+2 <= devdesc + desclength && - bufptr[0] == USB_DT_SS_EP_COMP_SIZE && - bufptr[1] == USB_DT_SS_ENDPOINT_COMP) { - bufptr += USB_DT_SS_EP_COMP_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"); - break; - } - - // both endpoints should be bulk - if (ep1->bmAttributes != USB_ENDPOINT_XFER_BULK || - ep2->bmAttributes != USB_ENDPOINT_XFER_BULK) { - D("bulk endpoints not found"); - continue; - } - /* aproto 01 needs 0 termination */ - if (interface->bInterfaceProtocol == ADB_PROTOCOL) { - max_packet_size = ep1->wMaxPacketSize; - zero_mask = ep1->wMaxPacketSize - 1; - } - - // we have a match. now we just need to figure out which is in and which is out. - unsigned char local_ep_in, local_ep_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)) { - snprintf(pathbuf, sizeof(pathbuf), "/sys/dev/char/%d:%d", - major(st.st_rdev), minor(st.st_rdev)); - ssize_t link_len = readlink(pathbuf, link, sizeof(link) - 1); - if (link_len > 0) { - link[link_len] = '\0'; - const char* slash = strrchr(link, '/'); - if (slash) { - snprintf(pathbuf, sizeof(pathbuf), - "usb:%s", slash + 1); - devpath = pathbuf; - } - } - } - - register_device_callback(dev_name.c_str(), devpath, local_ep_in, - local_ep_out, interface->bInterfaceNumber, - device->iSerialNumber, zero_mask, max_packet_size); - break; - } - } else { - bufptr += length; - } - } // end of while - - unix_close(fd); - } - } -} - -static int usb_bulk_write(usb_handle* h, const void* data, int len) { - std::unique_lock lock(h->mutex); - D("++ usb_bulk_write ++"); - - usbdevfs_urb* urb = &h->urb_out; - memset(urb, 0, sizeof(*urb)); - urb->type = USBDEVFS_URB_TYPE_BULK; - urb->endpoint = h->ep_out; - urb->status = -1; - urb->buffer = const_cast(data); - urb->buffer_length = len; - - if (h->dead) { - errno = EINVAL; - return -1; - } - - if (TEMP_FAILURE_RETRY(ioctl(h->fd, USBDEVFS_SUBMITURB, urb)) == -1) { - return -1; - } - - h->urb_out_busy = true; - while (true) { - auto now = std::chrono::steady_clock::now(); - if (h->cv.wait_until(lock, now + 5s) == std::cv_status::timeout || h->dead) { - // TODO: call USBDEVFS_DISCARDURB? - errno = ETIMEDOUT; - return -1; - } - if (!h->urb_out_busy) { - if (urb->status != 0) { - errno = -urb->status; - return -1; - } - return urb->actual_length; - } - } -} - -static int usb_bulk_read(usb_handle* h, void* data, int len) { - std::unique_lock lock(h->mutex); - D("++ usb_bulk_read ++"); - - usbdevfs_urb* urb = &h->urb_in; - 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; - - if (h->dead) { - errno = EINVAL; - return -1; - } - - if (TEMP_FAILURE_RETRY(ioctl(h->fd, USBDEVFS_SUBMITURB, urb)) == -1) { - return -1; - } - - h->urb_in_busy = true; - while (true) { - D("[ reap urb - wait ]"); - h->reaper_thread = pthread_self(); - int fd = h->fd; - lock.unlock(); - - // This ioctl must not have TEMP_FAILURE_RETRY because we send SIGALRM to break out. - usbdevfs_urb* out = nullptr; - int res = ioctl(fd, USBDEVFS_REAPURB, &out); - int saved_errno = errno; - - lock.lock(); - h->reaper_thread = 0; - if (h->dead) { - errno = EINVAL; - return -1; - } - if (res < 0) { - if (saved_errno == EINTR) { - continue; - } - D("[ reap urb - error ]"); - errno = saved_errno; - return -1; - } - D("[ urb @%p status = %d, actual = %d ]", out, out->status, out->actual_length); - - if (out == &h->urb_in) { - D("[ reap urb - IN complete ]"); - h->urb_in_busy = false; - if (urb->status != 0) { - errno = -urb->status; - return -1; - } - return urb->actual_length; - } - if (out == &h->urb_out) { - D("[ reap urb - OUT compelete ]"); - h->urb_out_busy = false; - h->cv.notify_all(); - } - } -} - -static int usb_write_split(usb_handle* h, unsigned char* data, int len) { - for (int i = 0; i < len; i += 16384) { - int chunk_size = (i + 16384 > len) ? len - i : 16384; - int n = usb_bulk_write(h, data + i, chunk_size); - if (n != chunk_size) { - D("ERROR: n = %d, errno = %d (%s)", n, errno, strerror(errno)); - return -1; - } - } - - return len; -} - -int usb_write(usb_handle* h, const void* _data, int len) { - D("++ usb_write ++"); - - unsigned char* data = (unsigned char*)_data; - - // The kernel will attempt to allocate a contiguous buffer for each write we submit. - // This might fail due to heap fragmentation, so attempt a contiguous write once, and if that - // fails, retry after having split the data into 16kB chunks to avoid allocation failure. - int n = usb_bulk_write(h, data, len); - if (n == -1 && errno == ENOMEM) { - n = usb_write_split(h, data, len); - } - - if (n == -1) { - return -1; - } - - if (h->zero_mask && !(len & h->zero_mask)) { - // If we need 0-markers and our transfer is an even multiple of the packet size, - // then send a zero marker. - return usb_bulk_write(h, _data, 0) == 0 ? len : -1; - } - - D("-- usb_write --"); - return len; -} - -int usb_read(usb_handle *h, void *_data, int len) -{ - unsigned char *data = (unsigned char*) _data; - int n; - - D("++ usb_read ++"); - int orig_len = len; - while (len == orig_len) { - int xfer = len; - - D("[ usb read %d fd = %d], path=%s", xfer, h->fd, h->path.c_str()); - n = usb_bulk_read(h, data, xfer); - D("[ usb read %d ] = %d, path=%s", xfer, n, h->path.c_str()); - if (n <= 0) { - if((errno == ETIMEDOUT) && (h->fd != -1)) { - D("[ timeout ]"); - continue; - } - D("ERROR: n = %d, errno = %d (%s)", - n, errno, strerror(errno)); - return -1; - } - - len -= n; - data += n; - } - - D("-- usb_read --"); - return orig_len - len; -} - -void usb_reset(usb_handle* h) { - ioctl(h->fd, USBDEVFS_RESET); - usb_kick(h); -} - -void usb_kick(usb_handle* h) { - std::lock_guard lock(h->mutex); - D("[ kicking %p (fd = %d) ]", h, h->fd); - if (!h->dead) { - h->dead = true; - - 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->fd, USBDEVFS_DISCARDURB, &h->urb_in); - ioctl(h->fd, USBDEVFS_DISCARDURB, &h->urb_out); - h->urb_in.status = -ENODEV; - h->urb_out.status = -ENODEV; - h->urb_in_busy = false; - h->urb_out_busy = false; - h->cv.notify_all(); - } else { - unregister_usb_transport(h); - } - } -} - -int usb_close(usb_handle* h) { - std::lock_guard lock(g_usb_handles_mutex); - g_usb_handles.remove(h); - - D("-- usb close %p (fd = %d) --", h, h->fd); - - delete h; - - return 0; -} - -size_t usb_get_max_packet_size(usb_handle* h) { - return h->max_packet_size; -} - -static void register_device(const char* dev_name, const char* dev_path, unsigned char ep_in, - unsigned char ep_out, int interface, int serial_index, - unsigned zero_mask, size_t max_packet_size) { - // 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 of handles with a matching name, we - // have no further work to do. - { - std::lock_guard lock(g_usb_handles_mutex); - for (usb_handle* usb: g_usb_handles) { - if (usb->path == dev_name) { - return; - } - } - } - - D("[ usb located new device %s (%d/%d/%d) ]", dev_name, ep_in, ep_out, interface); - std::unique_ptr usb(new usb_handle); - usb->path = dev_name; - usb->ep_in = ep_in; - usb->ep_out = ep_out; - usb->zero_mask = zero_mask; - usb->max_packet_size = max_packet_size; - - // Initialize mark so we don't get garbage collected after the device scan. - usb->mark = true; - - usb->fd = unix_open(usb->path, O_RDWR | O_CLOEXEC); - if (usb->fd == -1) { - // Opening RW failed, so see if we have RO access. - usb->fd = unix_open(usb->path, O_RDONLY | O_CLOEXEC); - if (usb->fd == -1) { - D("[ usb open %s failed: %s]", usb->path.c_str(), strerror(errno)); - return; - } - usb->writeable = 0; - } - - D("[ usb opened %s%s, fd=%d]", - usb->path.c_str(), (usb->writeable ? "" : " (read-only)"), usb->fd); - - if (usb->writeable) { - if (ioctl(usb->fd, USBDEVFS_CLAIMINTERFACE, &interface) != 0) { - D("[ usb ioctl(%d, USBDEVFS_CLAIMINTERFACE) failed: %s]", usb->fd, strerror(errno)); - return; - } - } - - // Read the device's serial number. - std::string serial_path = android::base::StringPrintf( - "/sys/bus/usb/devices/%s/serial", dev_path + 4); - std::string serial; - if (!android::base::ReadFileToString(serial_path, &serial)) { - D("[ usb read %s failed: %s ]", serial_path.c_str(), strerror(errno)); - // We don't actually want to treat an unknown serial as an error because - // devices aren't able to communicate a serial number in early bringup. - // http://b/20883914 - serial = ""; - } - serial = android::base::Trim(serial); - - // Add to the end of the active handles. - usb_handle* done_usb = usb.release(); - { - std::lock_guard lock(g_usb_handles_mutex); - g_usb_handles.push_back(done_usb); - } - register_usb_transport(done_usb, serial.c_str(), dev_path, done_usb->writeable); -} - -static void device_poll_thread() { - adb_thread_setname("device poll"); - D("Created device thread"); - while (true) { - // TODO: Use inotify. - find_usb_device("/dev/bus/usb", register_device); - adb_notify_device_scan_complete(); - kick_disconnected_devices(); - std::this_thread::sleep_for(1s); - } -} - -void usb_init() { - struct sigaction actions; - memset(&actions, 0, sizeof(actions)); - sigemptyset(&actions.sa_mask); - actions.sa_flags = 0; - actions.sa_handler = [](int) {}; - sigaction(SIGALRM, &actions, nullptr); - - std::thread(device_poll_thread).detach(); -} - -void usb_cleanup() {} - -} // namespace native diff --git a/adb/client/usb_osx.cpp b/adb/client/usb_osx.cpp deleted file mode 100644 index a93fa3a6bc44d3dafedd2c2c43e639729667e01a..0000000000000000000000000000000000000000 --- a/adb/client/usb_osx.cpp +++ /dev/null @@ -1,592 +0,0 @@ -/* - * 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 USB - -#include "sysdeps.h" - -#include "client/usb.h" - -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "adb.h" -#include "transport.h" - -using namespace std::chrono_literals; - -namespace native { -struct usb_handle -{ - UInt8 bulkIn; - UInt8 bulkOut; - IOUSBInterfaceInterface550** interface; - unsigned int zero_mask; - size_t max_packet_size; - - // For garbage collecting disconnected devices. - bool mark; - std::string devpath; - std::atomic dead; - - usb_handle() - : bulkIn(0), - bulkOut(0), - interface(nullptr), - zero_mask(0), - max_packet_size(0), - mark(false), - dead(false) {} -}; - -static std::atomic usb_inited_flag; - -static auto& g_usb_handles_mutex = *new std::mutex(); -static auto& g_usb_handles = *new std::vector>(); - -static bool IsKnownDevice(const std::string& devpath) { - std::lock_guard lock_guard(g_usb_handles_mutex); - for (auto& usb : g_usb_handles) { - if (usb->devpath == devpath) { - // Set mark flag to indicate this device is still alive. - usb->mark = true; - return true; - } - } - return false; -} - -static void usb_kick_locked(usb_handle* handle); - -static void KickDisconnectedDevices() { - std::lock_guard lock_guard(g_usb_handles_mutex); - for (auto& usb : g_usb_handles) { - if (!usb->mark) { - usb_kick_locked(usb.get()); - } else { - usb->mark = false; - } - } -} - -static void AddDevice(std::unique_ptr handle) { - handle->mark = true; - std::lock_guard lock(g_usb_handles_mutex); - g_usb_handles.push_back(std::move(handle)); -} - -static void AndroidInterfaceAdded(io_iterator_t iterator); -static std::unique_ptr CheckInterface(IOUSBInterfaceInterface550** iface, UInt16 vendor, - UInt16 product); - -static bool FindUSBDevices() { - // Create the matching dictionary to find the Android device's adb interface. - CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOUSBInterfaceClassName); - if (!matchingDict) { - LOG(ERROR) << "couldn't create USB matching dictionary"; - return false; - } - // Create an iterator for all I/O Registry objects that match the dictionary. - io_iterator_t iter = 0; - kern_return_t kr = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, &iter); - if (kr != KERN_SUCCESS) { - LOG(ERROR) << "failed to get matching services"; - return false; - } - // Iterate over all matching objects. - AndroidInterfaceAdded(iter); - IOObjectRelease(iter); - return true; -} - -static void -AndroidInterfaceAdded(io_iterator_t iterator) -{ - kern_return_t kr; - io_service_t usbDevice; - io_service_t usbInterface; - IOCFPlugInInterface **plugInInterface = NULL; - IOUSBInterfaceInterface500 **iface = NULL; - IOUSBDeviceInterface500 **dev = NULL; - HRESULT result; - SInt32 score; - uint32_t locationId; - UInt8 if_class, subclass, protocol; - UInt16 vendor; - UInt16 product; - UInt8 serialIndex; - char serial[256]; - std::string devpath; - - while ((usbInterface = IOIteratorNext(iterator))) { - //* Create an intermediate interface plugin - kr = IOCreatePlugInInterfaceForService(usbInterface, - kIOUSBInterfaceUserClientTypeID, - kIOCFPlugInInterfaceID, - &plugInInterface, &score); - IOObjectRelease(usbInterface); - if ((kIOReturnSuccess != kr) || (!plugInInterface)) { - LOG(ERROR) << "Unable to create an interface plug-in (" << std::hex << kr << ")"; - continue; - } - - //* This gets us the interface object - result = (*plugInInterface)->QueryInterface( - plugInInterface, - CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID500), (LPVOID*)&iface); - //* We only needed the plugin to get the interface, so discard it - (*plugInInterface)->Release(plugInInterface); - if (result || !iface) { - LOG(ERROR) << "Couldn't query the interface (" << std::hex << result << ")"; - continue; - } - - kr = (*iface)->GetInterfaceClass(iface, &if_class); - kr = (*iface)->GetInterfaceSubClass(iface, &subclass); - kr = (*iface)->GetInterfaceProtocol(iface, &protocol); - if (!is_adb_interface(if_class, subclass, protocol)) { - // Ignore non-ADB devices. - LOG(DEBUG) << "Ignoring interface with incorrect class/subclass/protocol - " << if_class - << ", " << subclass << ", " << protocol; - (*iface)->Release(iface); - continue; - } - - //* this gets us an ioservice, with which we will find the actual - //* device; after getting a plugin, and querying the interface, of - //* course. - //* Gotta love OS X - kr = (*iface)->GetDevice(iface, &usbDevice); - if (kIOReturnSuccess != kr || !usbDevice) { - LOG(ERROR) << "Couldn't grab device from interface (" << std::hex << kr << ")"; - (*iface)->Release(iface); - 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)) { - LOG(ERROR) << "Unable to create a device plug-in (" << std::hex << kr << ")"; - (*iface)->Release(iface); - continue; - } - - result = (*plugInInterface)->QueryInterface(plugInInterface, - CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID500), (LPVOID*)&dev); - //* only needed this to query the plugin - (*plugInInterface)->Release(plugInInterface); - if (result || !dev) { - LOG(ERROR) << "Couldn't create a device interface (" << std::hex << result << ")"; - (*iface)->Release(iface); - 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 == KERN_SUCCESS) { - devpath = android::base::StringPrintf("usb:%" PRIu32 "X", locationId); - if (IsKnownDevice(devpath)) { - (*dev)->Release(dev); - (*iface)->Release(iface); - continue; - } - } - 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); - - VLOG(USB) << android::base::StringPrintf("Found vid=%04x pid=%04x serial=%s\n", - vendor, product, serial); - if (devpath.empty()) { - devpath = serial; - } - if (IsKnownDevice(devpath)) { - (*iface)->USBInterfaceClose(iface); - (*iface)->Release(iface); - continue; - } - - std::unique_ptr handle = - CheckInterface((IOUSBInterfaceInterface550**)iface, vendor, product); - if (handle == nullptr) { - LOG(ERROR) << "Could not find device interface"; - (*iface)->Release(iface); - continue; - } - handle->devpath = devpath; - usb_handle* handle_p = handle.get(); - VLOG(USB) << "Add usb device " << serial; - LOG(INFO) << "reported max packet size for " << serial << " is " << handle->max_packet_size; - AddDevice(std::move(handle)); - register_usb_transport(reinterpret_cast<::usb_handle*>(handle_p), serial, devpath.c_str(), - 1); - } -} - -// Used to clear both the endpoints before starting. -// When adb quits, we might clear the host endpoint but not the device. -// So we make sure both sides are clear before starting up. -static bool ClearPipeStallBothEnds(IOUSBInterfaceInterface550** interface, UInt8 bulkEp) { - IOReturn rc = (*interface)->ClearPipeStallBothEnds(interface, bulkEp); - if (rc != kIOReturnSuccess) { - LOG(ERROR) << "Could not clear pipe stall both ends: " << std::hex << rc; - return false; - } - return true; -} - -//* TODO: simplify this further since we only register to get ADB interface -//* subclass+protocol events -static std::unique_ptr CheckInterface(IOUSBInterfaceInterface550** interface, - UInt16 vendor, UInt16 product) { - std::unique_ptr handle; - 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) { - LOG(ERROR) << "Could not open interface: " << std::hex << kr; - return NULL; - } - - //* Get the number of endpoints associated with this interface - kr = (*interface)->GetNumEndpoints(interface, &interfaceNumEndpoints); - if (kr != kIOReturnSuccess) { - LOG(ERROR) << "Unable to get number of endpoints: " << std::hex << 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) { - LOG(ERROR) << "Unable to get interface class, subclass and protocol"; - 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(interfaceClass, interfaceSubClass, interfaceProtocol)) { - goto err_bad_adb_interface; - } - - handle.reset(new usb_handle); - if (handle == nullptr) { - goto err_bad_adb_interface; - } - - //* 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 = 1; endpoint <= interfaceNumEndpoints; endpoint++) { - UInt8 transferType; - UInt16 maxPacketSize; - UInt8 interval; - UInt8 number; - UInt8 direction; - UInt8 maxBurst; - UInt8 mult; - UInt16 bytesPerInterval; - - kr = (*interface) - ->GetPipePropertiesV2(interface, endpoint, &direction, &number, &transferType, - &maxPacketSize, &interval, &maxBurst, &mult, - &bytesPerInterval); - if (kr != kIOReturnSuccess) { - LOG(ERROR) << "FindDeviceInterface - could not get pipe properties: " - << std::hex << kr; - goto err_get_pipe_props; - } - - if (kUSBBulk != transferType) continue; - - if (kUSBIn == direction) { - handle->bulkIn = endpoint; - if (!ClearPipeStallBothEnds(interface, handle->bulkIn)) goto err_get_pipe_props; - } - - if (kUSBOut == direction) { - handle->bulkOut = endpoint; - if (!ClearPipeStallBothEnds(interface, handle->bulkOut)) goto err_get_pipe_props; - } - - if (maxBurst != 0) - // bMaxBurst is the number of additional packets in the burst. - maxPacketSize /= (maxBurst + 1); - - // mult is only relevant for isochronous endpoints. - CHECK_EQ(0, mult); - - handle->zero_mask = maxPacketSize - 1; - handle->max_packet_size = maxPacketSize; - } - - handle->interface = interface; - return handle; - -err_get_pipe_props: -err_bad_adb_interface: -err_get_interface_class: -err_get_num_ep: - (*interface)->USBInterfaceClose(interface); - return nullptr; -} - -std::mutex& operate_device_lock = *new std::mutex(); - -static void RunLoopThread() { - adb_thread_setname("RunLoop"); - - VLOG(USB) << "RunLoopThread started"; - while (true) { - { - std::lock_guard lock_guard(operate_device_lock); - FindUSBDevices(); - KickDisconnectedDevices(); - } - // Signal the parent that we are running - usb_inited_flag = true; - std::this_thread::sleep_for(1s); - } - VLOG(USB) << "RunLoopThread done"; -} - -void usb_cleanup() NO_THREAD_SAFETY_ANALYSIS { - VLOG(USB) << "usb_cleanup"; - // Wait until usb operations in RunLoopThread finish, and prevent further operations. - operate_device_lock.lock(); - close_usb_devices(); -} - -void usb_init() { - static bool initialized = false; - if (!initialized) { - usb_inited_flag = false; - - std::thread(RunLoopThread).detach(); - - // Wait for initialization to finish - while (!usb_inited_flag) { - std::this_thread::sleep_for(100ms); - } - - adb_notify_device_scan_complete(); - initialized = true; - } -} - -int usb_write(usb_handle *handle, const void *buf, int len) -{ - IOReturn result; - - if (!len) - return 0; - - if (!handle || handle->dead) - return -1; - - if (NULL == handle->interface) { - LOG(ERROR) << "usb_write interface was null"; - return -1; - } - - if (0 == handle->bulkOut) { - LOG(ERROR) << "bulkOut endpoint not assigned"; - 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 (!result) - return len; - - LOG(ERROR) << "usb_write failed with status: " << std::hex << result; - return -1; -} - -int usb_read(usb_handle *handle, void *buf, int len) -{ - IOReturn result; - UInt32 numBytes = len; - - if (!len) { - return 0; - } - - if (!handle || handle->dead) { - return -1; - } - - if (NULL == handle->interface) { - LOG(ERROR) << "usb_read interface was null"; - return -1; - } - - if (0 == handle->bulkIn) { - LOG(ERROR) << "bulkIn endpoint not assigned"; - return -1; - } - - result = (*handle->interface)->ReadPipe(handle->interface, handle->bulkIn, buf, &numBytes); - - if (kIOUSBPipeStalled == result) { - LOG(ERROR) << "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 numBytes; - else { - LOG(ERROR) << "usb_read failed with status: " << std::hex << result; - } - - return -1; -} - -int usb_close(usb_handle *handle) -{ - std::lock_guard lock(g_usb_handles_mutex); - for (auto it = g_usb_handles.begin(); it != g_usb_handles.end(); ++it) { - if ((*it).get() == handle) { - g_usb_handles.erase(it); - break; - } - } - return 0; -} - -void usb_reset(usb_handle* handle) { - // Unimplemented on OS X. - usb_kick(handle); -} - -static void usb_kick_locked(usb_handle *handle) -{ - LOG(INFO) << "Kicking handle"; - /* release the interface */ - if (!handle) - return; - - if (!handle->dead) - { - handle->dead = true; - (*handle->interface)->USBInterfaceClose(handle->interface); - (*handle->interface)->Release(handle->interface); - } -} - -void usb_kick(usb_handle *handle) { - // Use the lock to avoid multiple thread kicking the device at the same time. - std::lock_guard lock_guard(g_usb_handles_mutex); - usb_kick_locked(handle); -} - -size_t usb_get_max_packet_size(usb_handle* handle) { - return handle->max_packet_size; -} - -} // namespace native diff --git a/adb/client/usb_windows.cpp b/adb/client/usb_windows.cpp deleted file mode 100644 index e209230c7c543416ba0b786955ff8b45586885fa..0000000000000000000000000000000000000000 --- a/adb/client/usb_windows.cpp +++ /dev/null @@ -1,621 +0,0 @@ -/* - * 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 USB - -#include "sysdeps.h" - -#include "client/usb.h" - -// clang-format off -#include // winsock.h *must* be included before windows.h. -#include -// clang-format on -#include -#include - -#include -#include -#include - -#include -#include -#include - -#include - -#include - -#include "adb.h" -#include "sysdeps/chrono.h" -#include "transport.h" - -namespace native { - -/** 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. - - Most members are protected by usb_lock, except for adb_{read,write}_pipe which - rely on AdbWinApi.dll's handle validation and AdbCloseHandle(endpoint)'s - ability to break a thread out of pipe IO. -*/ -struct usb_handle : public ::usb_handle { - /// 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 - wchar_t* interface_name; - - /// Maximum packet size. - unsigned max_packet_size; - - /// 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 std::vector& handle_list = *new std::vector(); - -/// Locker for the list of opened usb handles -static std::mutex& usb_lock = *new std::mutex(); - -/// Checks if there is opened usb handle in handle_list for this device. -int known_device(const wchar_t* 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 wchar_t* 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(); - -/// Kicks all USB devices -static void kick_devices(); - -/// Entry point for thread that polls (every second) for new usb interfaces. -/// This routine calls find_devices in infinite loop. -static void device_poll_thread(); - -/// Initializes this module -void usb_init(); - -/// 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); - -int known_device_locked(const wchar_t* dev_name) { - if (nullptr != dev_name) { - // Iterate through the list looking for the name match. - for (usb_handle* usb : handle_list) { - // In Windows names are not case sensetive! - if ((nullptr != usb->interface_name) && (0 == wcsicmp(usb->interface_name, dev_name))) { - return 1; - } - } - } - - return 0; -} - -int known_device(const wchar_t* dev_name) { - int ret = 0; - - if (nullptr != dev_name) { - std::lock_guard lock(usb_lock); - ret = known_device_locked(dev_name); - } - - return ret; -} - -int register_new_device(usb_handle* handle) { - if (nullptr == handle) return 0; - - std::lock_guard lock(usb_lock); - - // Check if device is already in the list - if (known_device_locked(handle->interface_name)) { - return 0; - } - - // Not in the list. Add this handle to the list. - handle_list.push_back(handle); - - return 1; -} - -void device_poll_thread() { - adb_thread_setname("Device Poll"); - D("Created device thread"); - - while (true) { - find_devices(); - adb_notify_device_scan_complete(); - std::this_thread::sleep_for(1s); - } -} - -static LRESULT CALLBACK _power_window_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { - switch (uMsg) { - case WM_POWERBROADCAST: - switch (wParam) { - case PBT_APMRESUMEAUTOMATIC: - // Resuming from sleep or hibernation, so kick all existing USB devices - // and then allow the device_poll_thread to redetect USB devices from - // scratch. If we don't do this, existing USB devices will never respond - // to us because they'll be waiting for the connect/auth handshake. - D("Received (WM_POWERBROADCAST, PBT_APMRESUMEAUTOMATIC) notification, " - "so kicking all USB devices\n"); - kick_devices(); - return TRUE; - } - } - return DefWindowProcW(hwnd, uMsg, wParam, lParam); -} - -static void _power_notification_thread() { - // This uses a thread with its own window message pump to get power - // notifications. If adb runs from a non-interactive service account, this - // might not work (not sure). If that happens to not work, we could use - // heavyweight WMI APIs to get power notifications. But for the common case - // of a developer's interactive session, a window message pump is more - // appropriate. - D("Created power notification thread"); - adb_thread_setname("Power Notifier"); - - // Window class names are process specific. - static const WCHAR kPowerNotificationWindowClassName[] = L"PowerNotificationWindow"; - - // Get the HINSTANCE corresponding to the module that _power_window_proc - // is in (the main module). - const HINSTANCE instance = GetModuleHandleW(nullptr); - if (!instance) { - // This is such a common API call that this should never fail. - LOG(FATAL) << "GetModuleHandleW failed: " - << android::base::SystemErrorCodeToString(GetLastError()); - } - - WNDCLASSEXW wndclass; - memset(&wndclass, 0, sizeof(wndclass)); - wndclass.cbSize = sizeof(wndclass); - wndclass.lpfnWndProc = _power_window_proc; - wndclass.hInstance = instance; - wndclass.lpszClassName = kPowerNotificationWindowClassName; - if (!RegisterClassExW(&wndclass)) { - LOG(FATAL) << "RegisterClassExW failed: " - << android::base::SystemErrorCodeToString(GetLastError()); - } - - if (!CreateWindowExW(WS_EX_NOACTIVATE, kPowerNotificationWindowClassName, - L"ADB Power Notification Window", WS_POPUP, 0, 0, 0, 0, nullptr, nullptr, - instance, nullptr)) { - LOG(FATAL) << "CreateWindowExW failed: " - << android::base::SystemErrorCodeToString(GetLastError()); - } - - MSG msg; - while (GetMessageW(&msg, nullptr, 0, 0)) { - TranslateMessage(&msg); - DispatchMessageW(&msg); - } - - // GetMessageW() will return false if a quit message is posted. We don't - // do that, but it might be possible for that to occur when logging off or - // shutting down. Not a big deal since the whole process will be going away - // soon anyway. - D("Power notification thread exiting"); -} - -void usb_init() { - std::thread(device_poll_thread).detach(); - std::thread(_power_notification_thread).detach(); -} - -void usb_cleanup() {} - -usb_handle* do_usb_open(const wchar_t* interface_name) { - unsigned long name_len = 0; - - // Allocate our handle - usb_handle* ret = (usb_handle*)calloc(1, sizeof(usb_handle)); - if (nullptr == ret) { - D("Could not allocate %u bytes for usb_handle: %s", sizeof(usb_handle), strerror(errno)); - goto fail; - } - - // Create interface. - ret->adb_interface = AdbCreateInterfaceByName(interface_name); - if (nullptr == ret->adb_interface) { - D("AdbCreateInterfaceByName failed: %s", - android::base::SystemErrorCodeToString(GetLastError()).c_str()); - goto fail; - } - - // Open read pipe (endpoint) - ret->adb_read_pipe = AdbOpenDefaultBulkReadEndpoint( - ret->adb_interface, AdbOpenAccessTypeReadWrite, AdbOpenSharingModeReadWrite); - if (nullptr == ret->adb_read_pipe) { - D("AdbOpenDefaultBulkReadEndpoint failed: %s", - android::base::SystemErrorCodeToString(GetLastError()).c_str()); - goto fail; - } - - // Open write pipe (endpoint) - ret->adb_write_pipe = AdbOpenDefaultBulkWriteEndpoint( - ret->adb_interface, AdbOpenAccessTypeReadWrite, AdbOpenSharingModeReadWrite); - if (nullptr == ret->adb_write_pipe) { - D("AdbOpenDefaultBulkWriteEndpoint failed: %s", - android::base::SystemErrorCodeToString(GetLastError()).c_str()); - goto fail; - } - - // Save interface name - // First get expected name length - AdbGetInterfaceName(ret->adb_interface, nullptr, &name_len, false); - if (0 == name_len) { - D("AdbGetInterfaceName returned name length of zero: %s", - android::base::SystemErrorCodeToString(GetLastError()).c_str()); - goto fail; - } - - ret->interface_name = (wchar_t*)malloc(name_len * sizeof(ret->interface_name[0])); - if (nullptr == ret->interface_name) { - D("Could not allocate %lu characters for interface_name: %s", name_len, strerror(errno)); - goto fail; - } - - // Now save the name - if (!AdbGetInterfaceName(ret->adb_interface, ret->interface_name, &name_len, false)) { - D("AdbGetInterfaceName failed: %s", - android::base::SystemErrorCodeToString(GetLastError()).c_str()); - goto fail; - } - - // We're done at this point - return ret; - -fail: - if (nullptr != ret) { - usb_cleanup_handle(ret); - free(ret); - } - - return nullptr; -} - -int usb_write(usb_handle* handle, const void* data, int len) { - unsigned long time_out = 5000; - unsigned long written = 0; - int err = 0; - - D("usb_write %d", len); - if (nullptr == handle) { - D("usb_write was passed NULL handle"); - err = EINVAL; - goto fail; - } - - // Perform write - if (!AdbWriteEndpointSync(handle->adb_write_pipe, (void*)data, (unsigned long)len, &written, - time_out)) { - D("AdbWriteEndpointSync failed: %s", - android::base::SystemErrorCodeToString(GetLastError()).c_str()); - err = EIO; - goto fail; - } - - // Make sure that we've written what we were asked to write - D("usb_write got: %ld, expected: %d", written, len); - if (written != (unsigned long)len) { - // If this occurs, this code should be changed to repeatedly call - // AdbWriteEndpointSync() until all bytes are written. - D("AdbWriteEndpointSync was supposed to write %d, but only wrote %ld", len, written); - err = EIO; - goto fail; - } - - if (handle->zero_mask && (len & handle->zero_mask) == 0) { - // Send a zero length packet - unsigned long dummy; - if (!AdbWriteEndpointSync(handle->adb_write_pipe, (void*)data, 0, &dummy, time_out)) { - D("AdbWriteEndpointSync of zero length packet failed: %s", - android::base::SystemErrorCodeToString(GetLastError()).c_str()); - err = EIO; - goto fail; - } - } - - return written; - -fail: - // Any failure should cause us to kick the device instead of leaving it a - // zombie state with potential to hang. - if (nullptr != handle) { - D("Kicking device due to error in usb_write"); - usb_kick(handle); - } - - D("usb_write failed"); - errno = err; - return -1; -} - -int usb_read(usb_handle* handle, void* data, int len) { - unsigned long time_out = 0; - unsigned long read = 0; - int err = 0; - int orig_len = len; - - D("usb_read %d", len); - if (nullptr == handle) { - D("usb_read was passed NULL handle"); - err = EINVAL; - goto fail; - } - - while (len == orig_len) { - if (!AdbReadEndpointSync(handle->adb_read_pipe, data, len, &read, time_out)) { - D("AdbReadEndpointSync failed: %s", - android::base::SystemErrorCodeToString(GetLastError()).c_str()); - err = EIO; - goto fail; - } - D("usb_read got: %ld, expected: %d", read, len); - - data = (char*)data + read; - len -= read; - } - - return orig_len - len; - -fail: - // Any failure should cause us to kick the device instead of leaving it a - // zombie state with potential to hang. - if (nullptr != handle) { - D("Kicking device due to error in usb_read"); - usb_kick(handle); - } - - D("usb_read failed"); - errno = err; - return -1; -} - -// Wrapper around AdbCloseHandle() that logs diagnostics. -static void _adb_close_handle(ADBAPIHANDLE adb_handle) { - if (!AdbCloseHandle(adb_handle)) { - D("AdbCloseHandle(%p) failed: %s", adb_handle, - android::base::SystemErrorCodeToString(GetLastError()).c_str()); - } -} - -void usb_cleanup_handle(usb_handle* handle) { - D("usb_cleanup_handle"); - if (nullptr != handle) { - if (nullptr != handle->interface_name) free(handle->interface_name); - // AdbCloseHandle(pipe) will break any threads out of pending IO calls and - // wait until the pipe no longer uses the interface. Then we can - // AdbCloseHandle() the interface. - if (nullptr != handle->adb_write_pipe) _adb_close_handle(handle->adb_write_pipe); - if (nullptr != handle->adb_read_pipe) _adb_close_handle(handle->adb_read_pipe); - if (nullptr != handle->adb_interface) _adb_close_handle(handle->adb_interface); - - handle->interface_name = nullptr; - handle->adb_write_pipe = nullptr; - handle->adb_read_pipe = nullptr; - handle->adb_interface = nullptr; - } -} - -void usb_reset(usb_handle* handle) { - // Unimplemented on Windows. - usb_kick(handle); -} - -static void usb_kick_locked(usb_handle* handle) { - // The reason the lock must be acquired before calling this function is in - // case multiple threads are trying to kick the same device at the same time. - usb_cleanup_handle(handle); -} - -void usb_kick(usb_handle* handle) { - D("usb_kick"); - if (nullptr != handle) { - std::lock_guard lock(usb_lock); - usb_kick_locked(handle); - } else { - errno = EINVAL; - } -} - -int usb_close(usb_handle* handle) { - D("usb_close"); - - if (nullptr != handle) { - // Remove handle from the list - { - std::lock_guard lock(usb_lock); - handle_list.erase(std::remove(handle_list.begin(), handle_list.end(), handle), - handle_list.end()); - } - - // Cleanup handle - usb_cleanup_handle(handle); - free(handle); - } - - return 0; -} - -size_t usb_get_max_packet_size(usb_handle* handle) { - return handle->max_packet_size; -} - -int recognized_device(usb_handle* handle) { - if (nullptr == handle) return 0; - - // Check vendor and product id first - USB_DEVICE_DESCRIPTOR device_desc; - - if (!AdbGetUsbDeviceDescriptor(handle->adb_interface, &device_desc)) { - D("AdbGetUsbDeviceDescriptor failed: %s", - android::base::SystemErrorCodeToString(GetLastError()).c_str()); - return 0; - } - - // Then check interface properties - USB_INTERFACE_DESCRIPTOR interf_desc; - - if (!AdbGetUsbInterfaceDescriptor(handle->adb_interface, &interf_desc)) { - D("AdbGetUsbInterfaceDescriptor failed: %s", - android::base::SystemErrorCodeToString(GetLastError()).c_str()); - return 0; - } - - // Must have two endpoints - if (2 != interf_desc.bNumEndpoints) { - return 0; - } - - if (!is_adb_interface(interf_desc.bInterfaceClass, interf_desc.bInterfaceSubClass, - interf_desc.bInterfaceProtocol)) { - return 0; - } - - AdbEndpointInformation endpoint_info; - // assuming zero is a valid bulk endpoint ID - if (AdbGetEndpointInformation(handle->adb_interface, 0, &endpoint_info)) { - handle->max_packet_size = endpoint_info.max_packet_size; - handle->zero_mask = endpoint_info.max_packet_size - 1; - D("device zero_mask: 0x%x", handle->zero_mask); - } else { - D("AdbGetEndpointInformation failed: %s", - android::base::SystemErrorCodeToString(GetLastError()).c_str()); - } - - return 1; -} - -void find_devices() { - usb_handle* handle = nullptr; - char entry_buffer[2048]; - AdbInterfaceInfo* next_interface = (AdbInterfaceInfo*)(&entry_buffer[0]); - unsigned long entry_buffer_size = sizeof(entry_buffer); - - // Enumerate all present and active interfaces. - ADBAPIHANDLE enum_handle = AdbEnumInterfaces(usb_class_id, true, true, true); - - if (nullptr == enum_handle) { - D("AdbEnumInterfaces failed: %s", - android::base::SystemErrorCodeToString(GetLastError()).c_str()); - return; - } - - while (AdbNextInterface(enum_handle, next_interface, &entry_buffer_size)) { - // Lets see if we already have this device in the list - if (!known_device(next_interface->device_name)) { - // This seems to be a new device. Open it! - handle = do_usb_open(next_interface->device_name); - if (nullptr != handle) { - // Lets see if this interface (device) belongs to us - if (recognized_device(handle)) { - D("adding a new device %ls", next_interface->device_name); - - // We don't request a wchar_t string from AdbGetSerialNumber() because of a bug - // in adb_winusb_interface.cpp:CopyMemory(buffer, ser_num->bString, - // bytes_written) where the last parameter should be (str_len * - // sizeof(wchar_t)). The bug reads 2 bytes past the end of a stack buffer in the - // best case, and in the unlikely case of a long serial number, it will read 2 - // bytes past the end of a heap allocation. This doesn't affect the resulting - // string, but we should avoid the bad reads in the first place. - 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, nullptr, 1); - } else { - D("register_new_device failed for %ls", next_interface->device_name); - usb_cleanup_handle(handle); - free(handle); - } - } else { - D("cannot get serial number: %s", - android::base::SystemErrorCodeToString(GetLastError()).c_str()); - usb_cleanup_handle(handle); - free(handle); - } - } else { - usb_cleanup_handle(handle); - free(handle); - } - } - } - - entry_buffer_size = sizeof(entry_buffer); - } - - if (GetLastError() != ERROR_NO_MORE_ITEMS) { - // Only ERROR_NO_MORE_ITEMS is expected at the end of enumeration. - D("AdbNextInterface failed: %s", - android::base::SystemErrorCodeToString(GetLastError()).c_str()); - } - - _adb_close_handle(enum_handle); -} - -static void kick_devices() { - // Need to acquire lock to safely walk the list which might be modified - // by another thread. - std::lock_guard lock(usb_lock); - for (usb_handle* usb : handle_list) { - usb_kick_locked(usb); - } -} - -} // namespace native diff --git a/adb/crypto/Android.bp b/adb/crypto/Android.bp deleted file mode 100644 index 9d14b030ac1e621be18ba3abd234bed857ed61ae..0000000000000000000000000000000000000000 --- a/adb/crypto/Android.bp +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (C) 2019 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. - -cc_defaults { - name: "libadb_crypto_defaults", - cflags: [ - "-Wall", - "-Wextra", - "-Wthread-safety", - "-Werror", - ], - - compile_multilib: "both", - - srcs: [ - "key.cpp", - "rsa_2048_key.cpp", - "x509_generator.cpp", - ], - - target: { - windows: { - compile_multilib: "first", - enabled: true, - }, - }, - - export_include_dirs: ["include"], - - visibility: [ - "//system/core/adb:__subpackages__", - "//bootable/recovery/minadbd:__subpackages__", - ], - - host_supported: true, - recovery_available: true, - - shared_libs: [ - "libadb_protos", - "libbase", - "liblog", - "libcrypto", - "libcrypto_utils", - ], -} - -cc_library { - name: "libadb_crypto", - defaults: ["libadb_crypto_defaults"], - - apex_available: [ - "com.android.adbd", - "test_com.android.adbd", - ], -} - -// For running atest (b/147158681) -cc_library_static { - name: "libadb_crypto_static", - defaults: ["libadb_crypto_defaults"], - - apex_available: [ - "//apex_available:platform", - ], - - static_libs: [ - "libadb_protos_static", - ], -} diff --git a/adb/crypto/include/adb/crypto/key.h b/adb/crypto/include/adb/crypto/key.h deleted file mode 100644 index d9ce69e0385e027e71527347a8cacf98d1724b5a..0000000000000000000000000000000000000000 --- a/adb/crypto/include/adb/crypto/key.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2019 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. - */ - -#pragma once - -#include - -#include - -#include "key_type.pb.h" - -namespace adb { -namespace crypto { - -// Class that represents a public/private key pair. -class Key { - public: - explicit Key(bssl::UniquePtr&& pkey, adb::proto::KeyType type) - : pkey_(std::move(pkey)), key_type_(type) {} - Key(Key&&) = default; - Key& operator=(Key&&) = default; - - EVP_PKEY* GetEvpPkey() const { return pkey_.get(); } - adb::proto::KeyType GetKeyType() const { return key_type_; } - static std::string ToPEMString(EVP_PKEY* pkey); - - private: - bssl::UniquePtr pkey_; - adb::proto::KeyType key_type_; -}; // Key - -} // namespace crypto -} // namespace adb diff --git a/adb/crypto/include/adb/crypto/rsa_2048_key.h b/adb/crypto/include/adb/crypto/rsa_2048_key.h deleted file mode 100644 index 2983a84c4778a8ae72523dff7722bdb5ce881f88..0000000000000000000000000000000000000000 --- a/adb/crypto/include/adb/crypto/rsa_2048_key.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2019 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. - */ - -#pragma once - -#include -#include - -#include "adb/crypto/key.h" - -namespace adb { -namespace crypto { - -// Create a new RSA2048 key pair. -std::optional CreateRSA2048Key(); - -// Generates the public key from the RSA private key. -bool CalculatePublicKey(std::string* out, RSA* private_key); - -} // namespace crypto -} // namespace adb diff --git a/adb/crypto/include/adb/crypto/x509_generator.h b/adb/crypto/include/adb/crypto/x509_generator.h deleted file mode 100644 index a269243125fa94a25a487c0ede3da99a93101cc1..0000000000000000000000000000000000000000 --- a/adb/crypto/include/adb/crypto/x509_generator.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2019 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. - */ - -#pragma once - -#include - -namespace adb { -namespace crypto { - -// Generate a X.509 certificate based on the key |pkey|. -bssl::UniquePtr GenerateX509Certificate(EVP_PKEY* pkey); - -// Convert X509* to PEM string format -std::string X509ToPEMString(X509* x509); - -} // namespace crypto -} // namespace adb diff --git a/adb/crypto/key.cpp b/adb/crypto/key.cpp deleted file mode 100644 index 4d870069c0d9e902103262f8f6b9be58ae8cee01..0000000000000000000000000000000000000000 --- a/adb/crypto/key.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2019 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 "adb/crypto/key.h" - -#include -#include -#include -#include - -namespace adb { -namespace crypto { - -// static -std::string Key::ToPEMString(EVP_PKEY* pkey) { - bssl::UniquePtr bio(BIO_new(BIO_s_mem())); - int rc = PEM_write_bio_PKCS8PrivateKey(bio.get(), pkey, nullptr, nullptr, 0, nullptr, nullptr); - if (rc != 1) { - LOG(ERROR) << "PEM_write_bio_PKCS8PrivateKey failed"; - return ""; - } - - BUF_MEM* mem = nullptr; - BIO_get_mem_ptr(bio.get(), &mem); - if (!mem || !mem->data || !mem->length) { - LOG(ERROR) << "BIO_get_mem_ptr failed"; - return ""; - } - - return std::string(mem->data, mem->length); -} - -} // namespace crypto -} // namespace adb diff --git a/adb/crypto/rsa_2048_key.cpp b/adb/crypto/rsa_2048_key.cpp deleted file mode 100644 index 7911af95fec585c0484a57f2abb6243058b3fa91..0000000000000000000000000000000000000000 --- a/adb/crypto/rsa_2048_key.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2019 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 "adb/crypto/rsa_2048_key.h" - -#include -#include -#include -#include - -namespace adb { -namespace crypto { - -namespace { -std::string get_user_info() { - std::string hostname; - if (getenv("HOSTNAME")) hostname = getenv("HOSTNAME"); -#if !defined(_WIN32) - char buf[64]; - if (hostname.empty() && gethostname(buf, sizeof(buf)) != -1) hostname = buf; -#endif - if (hostname.empty()) hostname = "unknown"; - - std::string username; - if (getenv("LOGNAME")) username = getenv("LOGNAME"); -#if !defined(_WIN32) - if (username.empty() && getlogin()) username = getlogin(); -#endif - if (username.empty()) hostname = "unknown"; - - return " " + username + "@" + hostname; -} - -} // namespace - -bool CalculatePublicKey(std::string* out, RSA* private_key) { - uint8_t binary_key_data[ANDROID_PUBKEY_ENCODED_SIZE]; - if (!android_pubkey_encode(private_key, binary_key_data, sizeof(binary_key_data))) { - LOG(ERROR) << "Failed to convert to public key"; - return false; - } - - size_t expected_length; - if (!EVP_EncodedLength(&expected_length, sizeof(binary_key_data))) { - LOG(ERROR) << "Public key too large to base64 encode"; - return false; - } - - out->resize(expected_length); - size_t actual_length = EVP_EncodeBlock(reinterpret_cast(out->data()), binary_key_data, - sizeof(binary_key_data)); - out->resize(actual_length); - out->append(get_user_info()); - return true; -} - -std::optional CreateRSA2048Key() { - bssl::UniquePtr pkey(EVP_PKEY_new()); - bssl::UniquePtr exponent(BN_new()); - bssl::UniquePtr rsa(RSA_new()); - if (!pkey || !exponent || !rsa) { - LOG(ERROR) << "Failed to allocate key"; - return std::nullopt; - } - - BN_set_word(exponent.get(), RSA_F4); - RSA_generate_key_ex(rsa.get(), 2048, exponent.get(), nullptr); - EVP_PKEY_set1_RSA(pkey.get(), rsa.get()); - - return std::optional{Key(std::move(pkey), adb::proto::KeyType::RSA_2048)}; -} - -} // namespace crypto -} // namespace adb diff --git a/adb/crypto/tests/Android.bp b/adb/crypto/tests/Android.bp deleted file mode 100644 index b32dcf731397b1d521297d816e74de5c8ea91d02..0000000000000000000000000000000000000000 --- a/adb/crypto/tests/Android.bp +++ /dev/null @@ -1,41 +0,0 @@ -// -// Copyright (C) 2019 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. -// - -cc_test { - name: "adb_crypto_test", - srcs: [ - "rsa_2048_key_test.cpp", - "x509_generator_test.cpp", - ], - - compile_multilib: "first", - - shared_libs: [ - "libbase", - "libcrypto", - "libcrypto_utils", - "libprotobuf-cpp-lite", - ], - - // Let's statically link them so we don't have to install it onto the - // system image for testing. - static_libs: [ - "libadb_crypto_static", - "libadb_protos_static", - ], - - test_suites: ["device-tests"], -} diff --git a/adb/crypto/tests/key_test.cpp b/adb/crypto/tests/key_test.cpp deleted file mode 100644 index 1feb6e8fbb95b0822e4612bcfe958b3e00a474dc..0000000000000000000000000000000000000000 --- a/adb/crypto/tests/key_test.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2019 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 - -namespace adb { -namespace crypto { - -TEST(RSA2048Key, Smoke) { - auto rsa_2048 = CreateRSA2048Key(); - EXPECT_NE(rsa_2048, std::nullopt); - EXPECT_EQ(rsa_2048->GetKeyType(), adb::proto::KeyType::RSA_2048); - ASSERT_NE(rsa_2048->GetEvpPkey(), nullptr); - - // The public key string format is expected to be: " " - std::string pub_key_plus_name; - auto* rsa = EVP_PKEY_get0_RSA(rsa_2048->GetEvpPkey()); - ASSERT_TRUE(CalculatePublicKey(&pub_key_plus_name, rsa)); - std::vector split = android::base::Split(std::string(pub_key_plus_name), " \t"); - EXPECT_EQ(split.size(), 2); - - LOG(INFO) << "pub_key=[" << pub_key_plus_name << "]"; - - // Try to sign something and decode it. - const char token[SHA_DIGEST_LENGTH] = "abcdefghij123456789"; - std::vector sig(RSA_size(rsa)); - unsigned sig_len; - EXPECT_EQ(RSA_sign(NID_sha1, reinterpret_cast(token), sizeof(token), sig.data(), - &sig_len, rsa), - 1); - sig.resize(sig_len); - - { - uint8_t keybuf[ANDROID_PUBKEY_ENCODED_SIZE + 1]; - const std::string& pubkey = split[0]; - ASSERT_EQ(b64_pton(pubkey.c_str(), keybuf, sizeof(keybuf)), ANDROID_PUBKEY_ENCODED_SIZE); - RSA* key = nullptr; - ASSERT_TRUE(android_pubkey_decode(keybuf, ANDROID_PUBKEY_ENCODED_SIZE, &key)); - EXPECT_EQ(RSA_verify(NID_sha1, reinterpret_cast(token), sizeof(token), - sig.data(), sig.size(), key), - 1); - RSA_free(key); - } -} - -} // namespace crypto -} // namespace adb diff --git a/adb/crypto/tests/rsa_2048_key_test.cpp b/adb/crypto/tests/rsa_2048_key_test.cpp deleted file mode 100644 index 1d8880e15c7e7ec40d3712b3bda07b90b6f72d50..0000000000000000000000000000000000000000 --- a/adb/crypto/tests/rsa_2048_key_test.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2019 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 - -namespace adb { -namespace crypto { - -TEST(RSA2048Key, Smoke) { - auto rsa_2048 = CreateRSA2048Key(); - EXPECT_NE(rsa_2048, std::nullopt); - EXPECT_EQ(rsa_2048->GetKeyType(), adb::proto::KeyType::RSA_2048); - ASSERT_NE(rsa_2048->GetEvpPkey(), nullptr); - - // The public key string format is expected to be: " " - std::string pub_key_plus_name; - auto* rsa = EVP_PKEY_get0_RSA(rsa_2048->GetEvpPkey()); - ASSERT_TRUE(CalculatePublicKey(&pub_key_plus_name, rsa)); - std::vector split = android::base::Split(std::string(pub_key_plus_name), " \t"); - EXPECT_EQ(split.size(), 2); - - LOG(INFO) << "pub_key=[" << pub_key_plus_name << "]"; - - std::string pemString = Key::ToPEMString(rsa_2048->GetEvpPkey()); - ASSERT_FALSE(pemString.empty()); - - // Try to sign something and decode it. - const char token[SHA_DIGEST_LENGTH] = "abcdefghij123456789"; - std::vector sig(RSA_size(rsa)); - unsigned sig_len; - EXPECT_EQ(RSA_sign(NID_sha1, reinterpret_cast(token), sizeof(token), sig.data(), - &sig_len, rsa), - 1); - sig.resize(sig_len); - - { - uint8_t keybuf[ANDROID_PUBKEY_ENCODED_SIZE + 1]; - const std::string& pubkey = split[0]; - ASSERT_EQ(b64_pton(pubkey.c_str(), keybuf, sizeof(keybuf)), ANDROID_PUBKEY_ENCODED_SIZE); - RSA* key = nullptr; - ASSERT_TRUE(android_pubkey_decode(keybuf, ANDROID_PUBKEY_ENCODED_SIZE, &key)); - EXPECT_EQ(RSA_verify(NID_sha1, reinterpret_cast(token), sizeof(token), - sig.data(), sig.size(), key), - 1); - RSA_free(key); - } -} - -} // namespace crypto -} // namespace adb diff --git a/adb/crypto/tests/x509_generator_test.cpp b/adb/crypto/tests/x509_generator_test.cpp deleted file mode 100644 index 281776bd4adddc67f55f14eada46e64d2fa2871d..0000000000000000000000000000000000000000 --- a/adb/crypto/tests/x509_generator_test.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2019 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 - -namespace adb { -namespace crypto { - -TEST(X509Generator, Smoke) { - auto rsa_2048 = CreateRSA2048Key(); - - std::string pub_key_plus_name; - auto* rsa = EVP_PKEY_get0_RSA(rsa_2048->GetEvpPkey()); - ASSERT_TRUE(CalculatePublicKey(&pub_key_plus_name, rsa)); - std::vector split = android::base::Split(std::string(pub_key_plus_name), " \t"); - EXPECT_EQ(split.size(), 2); - - LOG(INFO) << "pub_key=[" << pub_key_plus_name << "]"; - auto x509_cert = GenerateX509Certificate(rsa_2048->GetEvpPkey()); - ASSERT_NE(x509_cert.get(), nullptr); - - std::string x509_str = X509ToPEMString(x509_cert.get()); - ASSERT_FALSE(x509_str.empty()); -} - -} // namespace crypto -} // namespace adb diff --git a/adb/crypto/x509_generator.cpp b/adb/crypto/x509_generator.cpp deleted file mode 100644 index 43b81530483df8a9b4073a665f9b373b949bbcb2..0000000000000000000000000000000000000000 --- a/adb/crypto/x509_generator.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (C) 2019 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 "adb/crypto/x509_generator.h" - -#include - -#include -#include -#include -#include -#include - -namespace adb { -namespace crypto { - -namespace { - -const char kBasicConstraints[] = "critical,CA:TRUE"; -const char kKeyUsage[] = "critical,keyCertSign,cRLSign,digitalSignature"; -const char kSubjectKeyIdentifier[] = "hash"; -constexpr int kCertLifetimeSeconds = 10 * 365 * 24 * 60 * 60; - -bool add_ext(X509* cert, int nid, const char* value) { - size_t len = strlen(value) + 1; - std::vector mutableValue(value, value + len); - X509V3_CTX context; - - X509V3_set_ctx_nodb(&context); - - X509V3_set_ctx(&context, cert, cert, nullptr, nullptr, 0); - X509_EXTENSION* ex = X509V3_EXT_nconf_nid(nullptr, &context, nid, mutableValue.data()); - if (!ex) { - return false; - } - - X509_add_ext(cert, ex, -1); - X509_EXTENSION_free(ex); - return true; -} - -} // namespace - -bssl::UniquePtr GenerateX509Certificate(EVP_PKEY* pkey) { - CHECK(pkey); - bssl::UniquePtr x509(X509_new()); - if (!x509) { - LOG(ERROR) << "Unable to allocate x509 container"; - return nullptr; - } - X509_set_version(x509.get(), 2); - - ASN1_INTEGER_set(X509_get_serialNumber(x509.get()), 1); - X509_gmtime_adj(X509_get_notBefore(x509.get()), 0); - X509_gmtime_adj(X509_get_notAfter(x509.get()), kCertLifetimeSeconds); - - if (!X509_set_pubkey(x509.get(), pkey)) { - LOG(ERROR) << "Unable to set x509 public key"; - return nullptr; - } - - X509_NAME* name = X509_get_subject_name(x509.get()); - if (!name) { - LOG(ERROR) << "Unable to get x509 subject name"; - return nullptr; - } - X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, - reinterpret_cast("US"), -1, -1, 0); - X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, - reinterpret_cast("Android"), -1, -1, 0); - X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, - reinterpret_cast("Adb"), -1, -1, 0); - if (!X509_set_issuer_name(x509.get(), name)) { - LOG(ERROR) << "Unable to set x509 issuer name"; - return nullptr; - } - - add_ext(x509.get(), NID_basic_constraints, kBasicConstraints); - add_ext(x509.get(), NID_key_usage, kKeyUsage); - add_ext(x509.get(), NID_subject_key_identifier, kSubjectKeyIdentifier); - - int bytes = X509_sign(x509.get(), pkey, EVP_sha256()); - if (bytes <= 0) { - LOG(ERROR) << "Unable to sign x509 certificate"; - return nullptr; - } - - return x509; -} - -std::string X509ToPEMString(X509* x509) { - bssl::UniquePtr bio(BIO_new(BIO_s_mem())); - int rc = PEM_write_bio_X509(bio.get(), x509); - if (rc != 1) { - LOG(ERROR) << "PEM_write_bio_X509 failed"; - return ""; - } - - BUF_MEM* mem = nullptr; - BIO_get_mem_ptr(bio.get(), &mem); - if (!mem || !mem->data || !mem->length) { - LOG(ERROR) << "BIO_get_mem_ptr failed"; - return ""; - } - - return std::string(mem->data, mem->length); -} - -} // namespace crypto -} // namespace adb diff --git a/adb/daemon/abb.cpp b/adb/daemon/abb.cpp deleted file mode 100644 index 17c25e88b6f8d03d40fe8f34461391465a19315f..0000000000000000000000000000000000000000 --- a/adb/daemon/abb.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2018 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 "adb.h" -#include "adb_io.h" -#include "adb_utils.h" -#include "shell_service.h" -#include "sysdeps.h" - -namespace { - -class AdbFdTextOutput : public android::TextOutput { - public: - explicit AdbFdTextOutput(borrowed_fd fd) : fd_(fd) {} - - private: - android::status_t print(const char* txt, size_t len) override { - return WriteFdExactly(fd_, txt, len) ? android::OK : -errno; - } - void moveIndent(int delta) override { /*not implemented*/ - } - - void pushBundle() override { /*not implemented*/ - } - void popBundle() override { /*not implemented*/ - } - - private: - borrowed_fd fd_; -}; - -std::vector parseCmdArgs(std::string_view args) { - std::vector argv; - - char delim = ABB_ARG_DELIMETER; - size_t size = args.size(); - size_t base = 0; - while (base < size) { - size_t found; - for (found = base; found < size && args[found] && args[found] != delim; ++found) - ; - if (found > base) { - argv.emplace_back(args.substr(base, found - base)); - } - base = found + 1; - } - - return argv; -} - -} // namespace - -static int execCmd(std::string_view args, borrowed_fd in, borrowed_fd out, borrowed_fd err) { - int max_buf = LINUX_MAX_SOCKET_SIZE; - adb_setsockopt(in, SOL_SOCKET, SO_SNDBUF, &max_buf, sizeof(max_buf)); - adb_setsockopt(out, SOL_SOCKET, SO_SNDBUF, &max_buf, sizeof(max_buf)); - adb_setsockopt(err, SOL_SOCKET, SO_SNDBUF, &max_buf, sizeof(max_buf)); - - AdbFdTextOutput oin(out); - AdbFdTextOutput oerr(err); - return cmdMain(parseCmdArgs(args), oin, oerr, in.get(), out.get(), err.get(), - RunMode::kLibrary); -} - -int main(int argc, char* const argv[]) { - signal(SIGPIPE, SIG_IGN); - - int fd = STDIN_FILENO; - std::string data; - while (true) { - std::string error; - if (!ReadProtocolString(fd, &data, &error)) { - PLOG(ERROR) << "Failed to read message: " << error; - break; - } - - std::string_view name = data; - auto protocol = SubprocessProtocol::kShell; - if (android::base::ConsumePrefix(&name, "abb:")) { - protocol = SubprocessProtocol::kShell; - } else if (android::base::ConsumePrefix(&name, "abb_exec:")) { - protocol = SubprocessProtocol::kNone; - } else { - LOG(FATAL) << "Unknown command prefix for abb: " << data; - } - - unique_fd result = StartCommandInProcess(std::string(name), &execCmd, protocol); - int max_buf = LINUX_MAX_SOCKET_SIZE; - adb_setsockopt(result, SOL_SOCKET, SO_SNDBUF, &max_buf, sizeof(max_buf)); - if (android::base::SendFileDescriptors(fd, "", 1, result.get()) != 1) { - PLOG(ERROR) << "Failed to send an inprocess fd for command: " << data; - break; - } - } -} diff --git a/adb/daemon/abb_service.cpp b/adb/daemon/abb_service.cpp deleted file mode 100644 index e1df4a591c75f144a12ccf0cde0a09c2fc2f228c..0000000000000000000000000000000000000000 --- a/adb/daemon/abb_service.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2018 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 "adb.h" -#include "adb_io.h" -#include "adb_unique_fd.h" -#include "adb_utils.h" -#include "shell_service.h" - -#include - -namespace { - -struct AbbProcess; -static auto& abbp = *new std::unique_ptr(std::make_unique()); - -struct AbbProcess { - unique_fd sendCommand(std::string_view command); - - private: - static unique_fd startAbbProcess(unique_fd* error_fd); - - static constexpr auto kRetries = 2; - static constexpr auto kErrorProtocol = SubprocessProtocol::kShell; - - std::mutex locker_; - unique_fd socket_fd_; -}; - -unique_fd AbbProcess::sendCommand(std::string_view command) { - std::unique_lock lock{locker_}; - - for (int i = 0; i < kRetries; ++i) { - unique_fd error_fd; - if (socket_fd_ == -1) { - socket_fd_ = startAbbProcess(&error_fd); - } - if (socket_fd_ == -1) { - LOG(ERROR) << "failed to start abb process"; - return error_fd; - } - - if (!SendProtocolString(socket_fd_, command)) { - PLOG(ERROR) << "failed to send command to abb"; - socket_fd_.reset(); - continue; - } - - unique_fd fd; - char buf; - if (android::base::ReceiveFileDescriptors(socket_fd_, &buf, 1, &fd) != 1) { - PLOG(ERROR) << "failed to receive FD from abb"; - socket_fd_.reset(); - continue; - } - - return fd; - } - - LOG(ERROR) << "abb is unavailable"; - socket_fd_.reset(); - return ReportError(kErrorProtocol, "abb is unavailable"); -} - -unique_fd AbbProcess::startAbbProcess(unique_fd* error_fd) { - constexpr auto abb_process_type = SubprocessType::kRaw; - constexpr auto abb_protocol = SubprocessProtocol::kNone; - constexpr auto make_pty_raw = false; - return StartSubprocess("abb", "dumb", abb_process_type, abb_protocol, make_pty_raw, - kErrorProtocol, error_fd); -} - -} // namespace - -unique_fd execute_abb_command(std::string_view command) { - return abbp->sendCommand(command); -} diff --git a/adb/daemon/adb_wifi.cpp b/adb/daemon/adb_wifi.cpp deleted file mode 100644 index 2f9e9b4d039e323deac955c1d8e0893d9996f5c6..0000000000000000000000000000000000000000 --- a/adb/daemon/adb_wifi.cpp +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright (C) 2019 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. - */ - -#if !ADB_HOST - -#define TRACE_TAG ADB_WIRELESS - -#include "adb_wifi.h" - -#include -#include - -#include -#include - -#include "adb.h" -#include "daemon/mdns.h" -#include "sysdeps.h" -#include "transport.h" - -using namespace android::base; - -namespace { - -static AdbdAuthContext* auth_ctx; - -static void adb_disconnected(void* unused, atransport* t); -static struct adisconnect adb_disconnect = {adb_disconnected, nullptr}; - -static void adb_disconnected(void* unused, atransport* t) { - LOG(INFO) << "ADB wifi device disconnected"; - CHECK(t->auth_id.has_value()); - adbd_auth_tls_device_disconnected(auth_ctx, kAdbTransportTypeWifi, t->auth_id.value()); -} - -// TODO(b/31559095): need bionic host so that we can use 'prop_info' returned -// from WaitForProperty -#if defined(__ANDROID__) - -class TlsServer { - public: - explicit TlsServer(int port); - virtual ~TlsServer(); - bool Start(); - uint16_t port() { return port_; }; - - private: - void OnFdEvent(int fd, unsigned ev); - static void StaticOnFdEvent(int fd, unsigned ev, void* opaque); - - fdevent* fd_event_ = nullptr; - uint16_t port_; -}; // TlsServer - -TlsServer::TlsServer(int port) : port_(port) {} - -TlsServer::~TlsServer() { - fdevent* fde = fd_event_; - fdevent_run_on_main_thread([fde]() { - if (fde != nullptr) { - fdevent_destroy(fde); - } - }); -} - -bool TlsServer::Start() { - std::condition_variable cv; - std::mutex mutex; - std::optional success; - auto callback = [&](bool result) { - { - std::lock_guard lock(mutex); - success = result; - } - cv.notify_one(); - }; - - std::string err; - unique_fd fd(network_inaddr_any_server(port_, SOCK_STREAM, &err)); - if (fd.get() == -1) { - LOG(ERROR) << "Failed to start TLS server [" << err << "]"; - return false; - } - close_on_exec(fd.get()); - int port = socket_get_local_port(fd.get()); - if (port <= 0 || port > 65535) { - LOG(ERROR) << "Invalid port for tls server"; - return false; - } - port_ = static_cast(port); - LOG(INFO) << "adbwifi started on port " << port_; - - std::unique_lock lock(mutex); - fdevent_run_on_main_thread([&]() { - fd_event_ = fdevent_create(fd.release(), &TlsServer::StaticOnFdEvent, this); - if (fd_event_ == nullptr) { - LOG(ERROR) << "Failed to create fd event for TlsServer."; - callback(false); - return; - } - callback(true); - }); - - cv.wait(lock, [&]() { return success.has_value(); }); - if (!*success) { - LOG(INFO) << "TlsServer fdevent_create failed"; - return false; - } - fdevent_set(fd_event_, FDE_READ); - LOG(INFO) << "TlsServer running on port " << port_; - - return *success; -} - -// static -void TlsServer::StaticOnFdEvent(int fd, unsigned ev, void* opaque) { - auto server = reinterpret_cast(opaque); - server->OnFdEvent(fd, ev); -} - -void TlsServer::OnFdEvent(int fd, unsigned ev) { - if ((ev & FDE_READ) == 0 || fd != fd_event_->fd.get()) { - LOG(INFO) << __func__ << ": No read [ev=" << ev << " fd=" << fd << "]"; - return; - } - - unique_fd new_fd(adb_socket_accept(fd, nullptr, nullptr)); - if (new_fd >= 0) { - LOG(INFO) << "New TLS connection [fd=" << new_fd.get() << "]"; - close_on_exec(new_fd.get()); - disable_tcp_nagle(new_fd.get()); - std::string serial = android::base::StringPrintf("host-%d", new_fd.get()); - register_socket_transport( - std::move(new_fd), std::move(serial), port_, 1, - [](atransport*) { return ReconnectResult::Abort; }, true); - } -} - -TlsServer* sTlsServer = nullptr; -const char kWifiPortProp[] = "service.adb.tls.port"; - -const char kWifiEnabledProp[] = "persist.adb.tls_server.enable"; - -static void enable_wifi_debugging() { - start_mdnsd(); - - if (sTlsServer != nullptr) { - delete sTlsServer; - } - sTlsServer = new TlsServer(0); - if (!sTlsServer->Start()) { - LOG(ERROR) << "Failed to start TlsServer"; - delete sTlsServer; - sTlsServer = nullptr; - return; - } - - // Start mdns connect service for discovery - register_adb_secure_connect_service(sTlsServer->port()); - LOG(INFO) << "adb wifi started on port " << sTlsServer->port(); - SetProperty(kWifiPortProp, std::to_string(sTlsServer->port())); -} - -static void disable_wifi_debugging() { - if (sTlsServer != nullptr) { - delete sTlsServer; - sTlsServer = nullptr; - } - if (is_adb_secure_connect_service_registered()) { - unregister_adb_secure_connect_service(); - } - kick_all_tcp_tls_transports(); - LOG(INFO) << "adb wifi stopped"; - SetProperty(kWifiPortProp, ""); -} - -// Watches for the #kWifiEnabledProp property to toggle the TlsServer -static void start_wifi_enabled_observer() { - std::thread([]() { - bool wifi_enabled = false; - while (true) { - std::string toggled_val = wifi_enabled ? "0" : "1"; - LOG(INFO) << "Waiting for " << kWifiEnabledProp << "=" << toggled_val; - if (WaitForProperty(kWifiEnabledProp, toggled_val)) { - wifi_enabled = !wifi_enabled; - LOG(INFO) << kWifiEnabledProp << " changed to " << toggled_val; - if (wifi_enabled) { - enable_wifi_debugging(); - } else { - disable_wifi_debugging(); - } - } - } - }).detach(); -} -#endif //__ANDROID__ - -} // namespace - -void adbd_wifi_init(AdbdAuthContext* ctx) { - auth_ctx = ctx; -#if defined(__ANDROID__) - start_wifi_enabled_observer(); -#endif //__ANDROID__ -} - -void adbd_wifi_secure_connect(atransport* t) { - t->AddDisconnect(&adb_disconnect); - handle_online(t); - send_connect(t); - LOG(INFO) << __func__ << ": connected " << t->serial; - t->auth_id = adbd_auth_tls_device_connected(auth_ctx, kAdbTransportTypeWifi, t->auth_key.data(), - t->auth_key.size()); -} - -#endif /* !HOST */ diff --git a/adb/daemon/auth.cpp b/adb/daemon/auth.cpp deleted file mode 100644 index 1a1e4ad62d226424241363411135b5f00ce0fad9..0000000000000000000000000000000000000000 --- a/adb/daemon/auth.cpp +++ /dev/null @@ -1,382 +0,0 @@ -/* - * 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. - */ - -#define TRACE_TAG AUTH - -#include "sysdeps.h" - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "adb.h" -#include "adb_auth.h" -#include "adb_io.h" -#include "adb_wifi.h" -#include "fdevent/fdevent.h" -#include "transport.h" -#include "types.h" - -using namespace adb::crypto; -using namespace adb::tls; -using namespace std::chrono_literals; - -static AdbdAuthContext* auth_ctx; - -static RSA* rsa_pkey = nullptr; - -static void adb_disconnected(void* unused, atransport* t); -static struct adisconnect adb_disconnect = {adb_disconnected, nullptr}; - -static android::base::NoDestructor>> transports; -static uint32_t transport_auth_id = 0; - -bool auth_required = true; - -static void* transport_to_callback_arg(atransport* transport) { - uint32_t id = transport_auth_id++; - (*transports)[id] = transport->weak(); - return reinterpret_cast(id); -} - -static atransport* transport_from_callback_arg(void* id) { - uint64_t id_u64 = reinterpret_cast(id); - if (id_u64 > std::numeric_limits::max()) { - LOG(FATAL) << "transport_from_callback_arg called on out of range value: " << id_u64; - } - - uint32_t id_u32 = static_cast(id_u64); - auto it = transports->find(id_u32); - if (it == transports->end()) { - LOG(ERROR) << "transport_from_callback_arg failed to find transport for id " << id_u32; - return nullptr; - } - - atransport* t = it->second.get(); - if (!t) { - LOG(WARNING) << "transport_from_callback_arg found already destructed transport"; - return nullptr; - } - - transports->erase(it); - return t; -} - -static void IteratePublicKeys(std::function f) { - adbd_auth_get_public_keys( - auth_ctx, - [](void* opaque, const char* public_key, size_t len) { - return (*static_cast(opaque))(std::string_view(public_key, len)); - }, - &f); -} - -bssl::UniquePtr adbd_tls_client_ca_list() { - if (!auth_required) { - return nullptr; - } - - bssl::UniquePtr ca_list(sk_X509_NAME_new_null()); - - IteratePublicKeys([&](std::string_view public_key) { - // TODO: do we really have to support both ' ' and '\t'? - std::vector split = android::base::Split(std::string(public_key), " \t"); - uint8_t keybuf[ANDROID_PUBKEY_ENCODED_SIZE + 1]; - const std::string& pubkey = split[0]; - if (b64_pton(pubkey.c_str(), keybuf, sizeof(keybuf)) != ANDROID_PUBKEY_ENCODED_SIZE) { - LOG(ERROR) << "Invalid base64 key " << pubkey; - return true; - } - - RSA* key = nullptr; - if (!android_pubkey_decode(keybuf, ANDROID_PUBKEY_ENCODED_SIZE, &key)) { - LOG(ERROR) << "Failed to parse key " << pubkey; - return true; - } - bssl::UniquePtr rsa_key(key); - - unsigned char* dkey = nullptr; - int len = i2d_RSA_PUBKEY(rsa_key.get(), &dkey); - if (len <= 0 || dkey == nullptr) { - LOG(ERROR) << "Failed to encode RSA public key"; - return true; - } - - uint8_t digest[SHA256_DIGEST_LENGTH]; - // Put the encoded key in the commonName attribute of the issuer name. - // Note that the commonName has a max length of 64 bytes, which is less - // than the SHA256_DIGEST_LENGTH. - SHA256(dkey, len, digest); - OPENSSL_free(dkey); - - auto digest_str = SHA256BitsToHexString( - std::string_view(reinterpret_cast(&digest[0]), sizeof(digest))); - LOG(INFO) << "fingerprint=[" << digest_str << "]"; - auto issuer = CreateCAIssuerFromEncodedKey(digest_str); - CHECK(bssl::PushToStack(ca_list.get(), std::move(issuer))); - return true; - }); - - return ca_list; -} - -bool adbd_auth_verify(const char* token, size_t token_size, const std::string& sig, - std::string* auth_key) { - bool authorized = false; - auth_key->clear(); - - IteratePublicKeys([&](std::string_view public_key) { - // TODO: do we really have to support both ' ' and '\t'? - std::vector split = android::base::Split(std::string(public_key), " \t"); - uint8_t keybuf[ANDROID_PUBKEY_ENCODED_SIZE + 1]; - const std::string& pubkey = split[0]; - if (b64_pton(pubkey.c_str(), keybuf, sizeof(keybuf)) != ANDROID_PUBKEY_ENCODED_SIZE) { - LOG(ERROR) << "Invalid base64 key " << pubkey; - return true; - } - - RSA* key = nullptr; - if (!android_pubkey_decode(keybuf, ANDROID_PUBKEY_ENCODED_SIZE, &key)) { - LOG(ERROR) << "Failed to parse key " << pubkey; - return true; - } - - bool verified = - (RSA_verify(NID_sha1, reinterpret_cast(token), token_size, - reinterpret_cast(sig.c_str()), sig.size(), key) == 1); - RSA_free(key); - if (verified) { - *auth_key = public_key; - authorized = true; - return false; - } - - return true; - }); - - return authorized; -} - -static bool adbd_auth_generate_token(void* token, size_t token_size) { - FILE* fp = fopen("/dev/urandom", "re"); - if (!fp) return false; - bool okay = (fread(token, token_size, 1, fp) == 1); - fclose(fp); - return okay; -} - -void adbd_cloexec_auth_socket() { - int fd = android_get_control_socket("adbd"); - if (fd == -1) { - PLOG(ERROR) << "Failed to get adbd socket"; - return; - } - fcntl(fd, F_SETFD, FD_CLOEXEC); -} - -static void adbd_auth_key_authorized(void* arg, uint64_t id) { - LOG(INFO) << "adb client " << id << " authorized"; - fdevent_run_on_main_thread([=]() { - auto* transport = transport_from_callback_arg(arg); - if (!transport) { - LOG(ERROR) << "authorization received for deleted transport (" << id << "), ignoring"; - return; - } - - if (transport->auth_id.has_value()) { - if (transport->auth_id.value() != id) { - LOG(ERROR) - << "authorization received, but auth id doesn't match, ignoring (expected " - << transport->auth_id.value() << ", got " << id << ")"; - return; - } - } else { - // Older versions (i.e. dogfood/beta builds) of libadbd_auth didn't pass the initial - // auth id to us, so we'll just have to trust it until R ships and we can retcon this. - transport->auth_id = id; - } - - adbd_auth_verified(transport); - }); -} - -static void adbd_key_removed(const char* public_key, size_t len) { - // The framework removed the key from its keystore. We need to disconnect all - // devices using that key. Search by t->auth_key - std::string_view auth_key(public_key, len); - kick_all_transports_by_auth_key(auth_key); -} - -void adbd_auth_init(void) { - AdbdAuthCallbacksV1 cb; - cb.version = 1; - cb.key_authorized = adbd_auth_key_authorized; - cb.key_removed = adbd_key_removed; - auth_ctx = adbd_auth_new(&cb); - adbd_wifi_init(auth_ctx); - std::thread([]() { - adb_thread_setname("adbd auth"); - adbd_auth_run(auth_ctx); - LOG(FATAL) << "auth thread terminated"; - }).detach(); -} - -void send_auth_request(atransport* t) { - LOG(INFO) << "Calling send_auth_request..."; - - if (!adbd_auth_generate_token(t->token, sizeof(t->token))) { - PLOG(ERROR) << "Error generating token"; - return; - } - - apacket* p = get_apacket(); - p->msg.command = A_AUTH; - p->msg.arg0 = ADB_AUTH_TOKEN; - p->msg.data_length = sizeof(t->token); - p->payload.assign(t->token, t->token + sizeof(t->token)); - send_packet(p, t); -} - -void adbd_auth_verified(atransport* t) { - LOG(INFO) << "adb client authorized"; - handle_online(t); - send_connect(t); -} - -static void adb_disconnected(void* unused, atransport* t) { - LOG(INFO) << "ADB disconnect"; - CHECK(t->auth_id.has_value()); - adbd_auth_notify_disconnect(auth_ctx, t->auth_id.value()); -} - -void adbd_auth_confirm_key(atransport* t) { - LOG(INFO) << "prompting user to authorize key"; - t->AddDisconnect(&adb_disconnect); - if (adbd_auth_prompt_user_with_id) { - t->auth_id = adbd_auth_prompt_user_with_id(auth_ctx, t->auth_key.data(), t->auth_key.size(), - transport_to_callback_arg(t)); - } else { - adbd_auth_prompt_user(auth_ctx, t->auth_key.data(), t->auth_key.size(), - transport_to_callback_arg(t)); - } -} - -void adbd_notify_framework_connected_key(atransport* t) { - t->auth_id = adbd_auth_notify_auth(auth_ctx, t->auth_key.data(), t->auth_key.size()); -} - -int adbd_tls_verify_cert(X509_STORE_CTX* ctx, std::string* auth_key) { - if (!auth_required) { - // Any key will do. - LOG(INFO) << __func__ << ": auth not required"; - return 1; - } - - bool authorized = false; - X509* cert = X509_STORE_CTX_get0_cert(ctx); - if (cert == nullptr) { - LOG(INFO) << "got null x509 certificate"; - return 0; - } - bssl::UniquePtr evp_pkey(X509_get_pubkey(cert)); - if (evp_pkey == nullptr) { - LOG(INFO) << "got null evp_pkey from x509 certificate"; - return 0; - } - - IteratePublicKeys([&](std::string_view public_key) { - // TODO: do we really have to support both ' ' and '\t'? - std::vector split = android::base::Split(std::string(public_key), " \t"); - uint8_t keybuf[ANDROID_PUBKEY_ENCODED_SIZE + 1]; - const std::string& pubkey = split[0]; - if (b64_pton(pubkey.c_str(), keybuf, sizeof(keybuf)) != ANDROID_PUBKEY_ENCODED_SIZE) { - LOG(ERROR) << "Invalid base64 key " << pubkey; - return true; - } - - RSA* key = nullptr; - if (!android_pubkey_decode(keybuf, ANDROID_PUBKEY_ENCODED_SIZE, &key)) { - LOG(ERROR) << "Failed to parse key " << pubkey; - return true; - } - - bool verified = false; - bssl::UniquePtr known_evp(EVP_PKEY_new()); - EVP_PKEY_set1_RSA(known_evp.get(), key); - if (EVP_PKEY_cmp(known_evp.get(), evp_pkey.get())) { - LOG(INFO) << "Matched auth_key=" << public_key; - verified = true; - } else { - LOG(INFO) << "auth_key doesn't match [" << public_key << "]"; - } - RSA_free(key); - if (verified) { - *auth_key = public_key; - authorized = true; - return false; - } - - return true; - }); - - return authorized ? 1 : 0; -} - -void adbd_auth_tls_handshake(atransport* t) { - if (rsa_pkey == nullptr) { - // Generate a random RSA key to feed into the X509 certificate - auto rsa_2048 = CreateRSA2048Key(); - CHECK(rsa_2048.has_value()); - rsa_pkey = EVP_PKEY_get1_RSA(rsa_2048->GetEvpPkey()); - CHECK(rsa_pkey); - } - - std::thread([t]() { - std::string auth_key; - if (t->connection()->DoTlsHandshake(rsa_pkey, &auth_key)) { - LOG(INFO) << "auth_key=" << auth_key; - if (t->IsTcpDevice()) { - t->auth_key = auth_key; - adbd_wifi_secure_connect(t); - } else { - adbd_auth_verified(t); - adbd_notify_framework_connected_key(t); - } - } else { - // Only allow one attempt at the handshake. - t->Kick(); - } - }).detach(); -} diff --git a/adb/daemon/file_sync_service.cpp b/adb/daemon/file_sync_service.cpp deleted file mode 100644 index 07f6e65e8443f9ebc1fe1fbdbf200befc25c3060..0000000000000000000000000000000000000000 --- a/adb/daemon/file_sync_service.cpp +++ /dev/null @@ -1,816 +0,0 @@ -/* - * 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 SYNC - -#include "daemon/file_sync_service.h" - -#include "sysdeps.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -// Needed for __android_log_security_bswrite. -#include - -#if defined(__ANDROID__) -#include -#include -#include -#endif - -#include "adb.h" -#include "adb_io.h" -#include "adb_trace.h" -#include "adb_utils.h" -#include "brotli_utils.h" -#include "file_sync_protocol.h" -#include "security_log_tags.h" -#include "sysdeps/errno.h" - -using android::base::borrowed_fd; -using android::base::Dirname; -using android::base::StringPrintf; - -static bool should_use_fs_config(const std::string& path) { -#if defined(__ANDROID__) - // TODO: use fs_config to configure permissions on /data too. - return !android::base::StartsWith(path, "/data/"); -#else - UNUSED(path); - return false; -#endif -} - -static bool update_capabilities(const char* path, uint64_t capabilities) { -#if defined(__ANDROID__) - if (capabilities == 0) { - // Ensure we clean up in case the capabilities weren't 0 in the past. - removexattr(path, XATTR_NAME_CAPS); - return true; - } - - vfs_cap_data cap_data = {}; - cap_data.magic_etc = VFS_CAP_REVISION_2 | VFS_CAP_FLAGS_EFFECTIVE; - cap_data.data[0].permitted = (capabilities & 0xffffffff); - cap_data.data[0].inheritable = 0; - cap_data.data[1].permitted = (capabilities >> 32); - cap_data.data[1].inheritable = 0; - return setxattr(path, XATTR_NAME_CAPS, &cap_data, sizeof(cap_data), 0) != -1; -#else - UNUSED(path, capabilities); - return true; -#endif -} - -static bool secure_mkdirs(const std::string& path) { - if (path[0] != '/') return false; - - std::vector path_components = android::base::Split(path, "/"); - std::string partial_path; - for (const auto& path_component : path_components) { - uid_t uid = -1; - gid_t gid = -1; - mode_t mode = 0775; - uint64_t capabilities = 0; - - if (path_component.empty()) { - continue; - } - - if (partial_path.empty() || partial_path.back() != OS_PATH_SEPARATOR) { - partial_path += OS_PATH_SEPARATOR; - } - partial_path += path_component; - - if (should_use_fs_config(partial_path)) { - adbd_fs_config(partial_path.c_str(), 1, nullptr, &uid, &gid, &mode, &capabilities); - } - if (adb_mkdir(partial_path.c_str(), mode) == -1) { - if (errno != EEXIST) { - return false; - } - } else { - if (chown(partial_path.c_str(), uid, gid) == -1) return false; - -#if defined(__ANDROID__) - // Not all filesystems support setting SELinux labels. http://b/23530370. - selinux_android_restorecon(partial_path.c_str(), 0); -#endif - - if (!update_capabilities(partial_path.c_str(), capabilities)) return false; - } - } - return true; -} - -static bool do_lstat_v1(int s, const char* path) { - syncmsg msg = {}; - msg.stat_v1.id = ID_LSTAT_V1; - - struct stat st = {}; - lstat(path, &st); - msg.stat_v1.mode = st.st_mode; - msg.stat_v1.size = st.st_size; - msg.stat_v1.mtime = st.st_mtime; - return WriteFdExactly(s, &msg.stat_v1, sizeof(msg.stat_v1)); -} - -static bool do_stat_v2(int s, uint32_t id, const char* path) { - syncmsg msg = {}; - msg.stat_v2.id = id; - - decltype(&stat) stat_fn; - if (id == ID_STAT_V2) { - stat_fn = stat; - } else { - stat_fn = lstat; - } - - struct stat st = {}; - int rc = stat_fn(path, &st); - if (rc == -1) { - msg.stat_v2.error = errno_to_wire(errno); - } else { - msg.stat_v2.dev = st.st_dev; - msg.stat_v2.ino = st.st_ino; - msg.stat_v2.mode = st.st_mode; - msg.stat_v2.nlink = st.st_nlink; - msg.stat_v2.uid = st.st_uid; - msg.stat_v2.gid = st.st_gid; - msg.stat_v2.size = st.st_size; - msg.stat_v2.atime = st.st_atime; - msg.stat_v2.mtime = st.st_mtime; - msg.stat_v2.ctime = st.st_ctime; - } - - return WriteFdExactly(s, &msg.stat_v2, sizeof(msg.stat_v2)); -} - -template -static bool do_list(int s, const char* path) { - dirent* de; - - using MessageType = - std::conditional_t; - MessageType msg; - uint32_t msg_id; - if constexpr (v2) { - msg_id = ID_DENT_V2; - } else { - msg_id = ID_DENT_V1; - } - - std::unique_ptr d(opendir(path), closedir); - if (!d) goto done; - - while ((de = readdir(d.get()))) { - memset(&msg, 0, sizeof(msg)); - msg.id = msg_id; - - std::string filename(StringPrintf("%s/%s", path, de->d_name)); - - struct stat st; - if (lstat(filename.c_str(), &st) == 0) { - msg.mode = st.st_mode; - msg.size = st.st_size; - msg.mtime = st.st_mtime; - - if constexpr (v2) { - msg.dev = st.st_dev; - msg.ino = st.st_ino; - msg.nlink = st.st_nlink; - msg.uid = st.st_uid; - msg.gid = st.st_gid; - msg.atime = st.st_atime; - msg.ctime = st.st_ctime; - } - } else { - if constexpr (v2) { - msg.error = errno; - } else { - continue; - } - } - - size_t d_name_length = strlen(de->d_name); - msg.namelen = d_name_length; - - if (!WriteFdExactly(s, &msg, sizeof(msg)) || - !WriteFdExactly(s, de->d_name, d_name_length)) { - return false; - } - } - -done: - memset(&msg, 0, sizeof(msg)); - msg.id = ID_DONE; - return WriteFdExactly(s, &msg, sizeof(msg)); -} - -static bool do_list_v1(int s, const char* path) { - return do_list(s, path); -} - -static bool do_list_v2(int s, const char* path) { - return do_list(s, path); -} - -// Make sure that SendFail from adb_io.cpp isn't accidentally used in this file. -#pragma GCC poison SendFail - -static bool SendSyncFail(borrowed_fd fd, const std::string& reason) { - D("sync: failure: %s", reason.c_str()); - - syncmsg msg; - msg.data.id = ID_FAIL; - msg.data.size = reason.size(); - return WriteFdExactly(fd, &msg.data, sizeof(msg.data)) && WriteFdExactly(fd, reason); -} - -static bool SendSyncFailErrno(borrowed_fd fd, const std::string& reason) { - return SendSyncFail(fd, StringPrintf("%s: %s", reason.c_str(), strerror(errno))); -} - -static bool handle_send_file_compressed(borrowed_fd s, unique_fd fd, uint32_t* timestamp) { - syncmsg msg; - Block decode_buffer(SYNC_DATA_MAX); - BrotliDecoder decoder(std::span(decode_buffer.data(), decode_buffer.size())); - while (true) { - if (!ReadFdExactly(s, &msg.data, sizeof(msg.data))) return false; - - if (msg.data.id != ID_DATA) { - if (msg.data.id == ID_DONE) { - *timestamp = msg.data.size; - return true; - } - SendSyncFail(s, "invalid data message"); - return false; - } - - Block block(msg.data.size); - if (!ReadFdExactly(s, block.data(), msg.data.size)) return false; - decoder.Append(std::move(block)); - - while (true) { - std::span output; - BrotliDecodeResult result = decoder.Decode(&output); - if (result == BrotliDecodeResult::Error) { - SendSyncFailErrno(s, "decompress failed"); - return false; - } - - if (!WriteFdExactly(fd, output.data(), output.size())) { - SendSyncFailErrno(s, "write failed"); - return false; - } - - if (result == BrotliDecodeResult::NeedInput) { - break; - } else if (result == BrotliDecodeResult::MoreOutput) { - continue; - } else if (result == BrotliDecodeResult::Done) { - break; - } else { - LOG(FATAL) << "invalid BrotliDecodeResult: " << static_cast(result); - } - } - } - - __builtin_unreachable(); -} - -static bool handle_send_file_uncompressed(borrowed_fd s, unique_fd fd, uint32_t* timestamp, - std::vector& buffer) { - syncmsg msg; - - while (true) { - if (!ReadFdExactly(s, &msg.data, sizeof(msg.data))) return false; - - if (msg.data.id != ID_DATA) { - if (msg.data.id == ID_DONE) { - *timestamp = msg.data.size; - return true; - } - SendSyncFail(s, "invalid data message"); - return false; - } - - if (msg.data.size > buffer.size()) { // TODO: resize buffer? - SendSyncFail(s, "oversize data message"); - return false; - } - if (!ReadFdExactly(s, &buffer[0], msg.data.size)) return false; - if (!WriteFdExactly(fd, &buffer[0], msg.data.size)) { - SendSyncFailErrno(s, "write failed"); - return false; - } - } -} - -static bool handle_send_file(borrowed_fd s, const char* path, uint32_t* timestamp, uid_t uid, - gid_t gid, uint64_t capabilities, mode_t mode, bool compressed, - std::vector& buffer, bool do_unlink) { - int rc; - syncmsg msg; - - __android_log_security_bswrite(SEC_TAG_ADB_SEND_FILE, path); - - unique_fd fd(adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode)); - - if (fd < 0 && errno == ENOENT) { - if (!secure_mkdirs(Dirname(path))) { - SendSyncFailErrno(s, "secure_mkdirs failed"); - goto fail; - } - fd.reset(adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode)); - } - if (fd < 0 && errno == EEXIST) { - fd.reset(adb_open_mode(path, O_WRONLY | O_CLOEXEC, mode)); - } - if (fd < 0) { - SendSyncFailErrno(s, "couldn't create file"); - goto fail; - } else { - if (fchown(fd.get(), uid, gid) == -1) { - SendSyncFailErrno(s, "fchown failed"); - goto fail; - } - -#if defined(__ANDROID__) - // Not all filesystems support setting SELinux labels. http://b/23530370. - selinux_android_restorecon(path, 0); -#endif - - // fchown clears the setuid bit - restore it if present. - // Ignore the result of calling fchmod. It's not supported - // by all filesystems, so we don't check for success. b/12441485 - fchmod(fd.get(), mode); - } - - { - rc = posix_fadvise(fd.get(), 0, 0, - POSIX_FADV_SEQUENTIAL | POSIX_FADV_NOREUSE | POSIX_FADV_WILLNEED); - if (rc != 0) { - D("[ Failed to fadvise: %s ]", strerror(rc)); - } - - bool result; - if (compressed) { - result = handle_send_file_compressed(s, std::move(fd), timestamp); - } else { - result = handle_send_file_uncompressed(s, std::move(fd), timestamp, buffer); - } - - if (!result) { - goto fail; - } - - if (!update_capabilities(path, capabilities)) { - SendSyncFailErrno(s, "update_capabilities failed"); - goto fail; - } - - msg.status.id = ID_OKAY; - msg.status.msglen = 0; - return WriteFdExactly(s, &msg.status, sizeof(msg.status)); - } - -fail: - // If there's a problem on the device, we'll send an ID_FAIL message and - // close the socket. Unfortunately the kernel will sometimes throw that - // data away if the other end keeps writing without reading (which is - // the case with old versions of adb). To maintain compatibility, keep - // reading and throwing away ID_DATA packets until the other side notices - // that we've reported an error. - while (true) { - if (!ReadFdExactly(s, &msg.data, sizeof(msg.data))) break; - - if (msg.data.id == ID_DONE) { - break; - } else if (msg.data.id != ID_DATA) { - char id[5]; - memcpy(id, &msg.data.id, sizeof(msg.data.id)); - id[4] = '\0'; - D("handle_send_fail received unexpected id '%s' during failure", id); - break; - } - - if (msg.data.size > buffer.size()) { - D("handle_send_fail received oversized packet of length '%u' during failure", - msg.data.size); - break; - } - - if (!ReadFdExactly(s, &buffer[0], msg.data.size)) break; - } - - if (do_unlink) adb_unlink(path); - return false; -} - -#if defined(_WIN32) -extern bool handle_send_link(int s, const std::string& path, - uint32_t* timestamp, std::vector& buffer) - __attribute__((error("no symlinks on Windows"))); -#else -static bool handle_send_link(int s, const std::string& path, uint32_t* timestamp, - std::vector& buffer) { - syncmsg msg; - - if (!ReadFdExactly(s, &msg.data, sizeof(msg.data))) return false; - - if (msg.data.id != ID_DATA) { - SendSyncFail(s, "invalid data message: expected ID_DATA"); - return false; - } - - unsigned int len = msg.data.size; - if (len > buffer.size()) { // TODO: resize buffer? - SendSyncFail(s, "oversize data message"); - return false; - } - if (!ReadFdExactly(s, &buffer[0], len)) return false; - - std::string buf_link; - if (!android::base::Readlink(path, &buf_link) || (buf_link != &buffer[0])) { - adb_unlink(path.c_str()); - auto ret = symlink(&buffer[0], path.c_str()); - if (ret && errno == ENOENT) { - if (!secure_mkdirs(Dirname(path))) { - SendSyncFailErrno(s, "secure_mkdirs failed"); - return false; - } - ret = symlink(&buffer[0], path.c_str()); - } - if (ret) { - SendSyncFailErrno(s, "symlink failed"); - return false; - } - } - - if (!ReadFdExactly(s, &msg.data, sizeof(msg.data))) return false; - - if (msg.data.id == ID_DONE) { - *timestamp = msg.data.size; - msg.status.id = ID_OKAY; - msg.status.msglen = 0; - if (!WriteFdExactly(s, &msg.status, sizeof(msg.status))) return false; - } else { - SendSyncFail(s, "invalid data message: expected ID_DONE"); - return false; - } - - return true; -} -#endif - -static bool send_impl(int s, const std::string& path, mode_t mode, bool compressed, - std::vector& buffer) { - // Don't delete files before copying if they are not "regular" or symlinks. - struct stat st; - bool do_unlink = (lstat(path.c_str(), &st) == -1) || S_ISREG(st.st_mode) || - (S_ISLNK(st.st_mode) && !S_ISLNK(mode)); - if (do_unlink) { - adb_unlink(path.c_str()); - } - - bool result; - uint32_t timestamp; - if (S_ISLNK(mode)) { - result = handle_send_link(s, path, ×tamp, buffer); - } else { - // Copy user permission bits to "group" and "other" permissions. - mode &= 0777; - mode |= ((mode >> 3) & 0070); - mode |= ((mode >> 3) & 0007); - - uid_t uid = -1; - gid_t gid = -1; - uint64_t capabilities = 0; - if (should_use_fs_config(path)) { - adbd_fs_config(path.c_str(), 0, nullptr, &uid, &gid, &mode, &capabilities); - } - - result = handle_send_file(s, path.c_str(), ×tamp, uid, gid, capabilities, mode, - compressed, buffer, do_unlink); - } - - if (!result) { - return false; - } - - struct timeval tv[2]; - tv[0].tv_sec = timestamp; - tv[0].tv_usec = 0; - tv[1].tv_sec = timestamp; - tv[1].tv_usec = 0; - lutimes(path.c_str(), tv); - return true; -} - -static bool do_send_v1(int s, const std::string& spec, std::vector& buffer) { - // 'spec' is of the form "/some/path,0755". Break it up. - size_t comma = spec.find_last_of(','); - if (comma == std::string::npos) { - SendSyncFail(s, "missing , in ID_SEND_V1"); - return false; - } - - std::string path = spec.substr(0, comma); - - errno = 0; - mode_t mode = strtoul(spec.substr(comma + 1).c_str(), nullptr, 0); - if (errno != 0) { - SendSyncFail(s, "bad mode"); - return false; - } - - return send_impl(s, path, mode, false, buffer); -} - -static bool do_send_v2(int s, const std::string& path, std::vector& buffer) { - // Read the setup packet. - syncmsg msg; - int rc = ReadFdExactly(s, &msg.send_v2_setup, sizeof(msg.send_v2_setup)); - if (rc == 0) { - LOG(ERROR) << "failed to read send_v2 setup packet: EOF"; - return false; - } else if (rc < 0) { - PLOG(ERROR) << "failed to read send_v2 setup packet"; - } - - bool compressed = false; - if (msg.send_v2_setup.flags & kSyncFlagBrotli) { - msg.send_v2_setup.flags &= ~kSyncFlagBrotli; - compressed = true; - } - if (msg.send_v2_setup.flags) { - SendSyncFail(s, android::base::StringPrintf("unknown flags: %d", msg.send_v2_setup.flags)); - return false; - } - - errno = 0; - return send_impl(s, path, msg.send_v2_setup.mode, compressed, buffer); -} - -static bool recv_uncompressed(borrowed_fd s, unique_fd fd, std::vector& buffer) { - syncmsg msg; - msg.data.id = ID_DATA; - std::optional> encoder; - while (true) { - int r = adb_read(fd.get(), &buffer[0], buffer.size() - sizeof(msg.data)); - if (r <= 0) { - if (r == 0) break; - SendSyncFailErrno(s, "read failed"); - return false; - } - msg.data.size = r; - - if (!WriteFdExactly(s, &msg.data, sizeof(msg.data)) || !WriteFdExactly(s, &buffer[0], r)) { - return false; - } - } - - return true; -} - -static bool recv_compressed(borrowed_fd s, unique_fd fd) { - syncmsg msg; - msg.data.id = ID_DATA; - - BrotliEncoder encoder; - - bool sending = true; - while (sending) { - Block input(SYNC_DATA_MAX); - int r = adb_read(fd.get(), input.data(), input.size()); - if (r < 0) { - SendSyncFailErrno(s, "read failed"); - return false; - } - - if (r == 0) { - encoder.Finish(); - } else { - input.resize(r); - encoder.Append(std::move(input)); - } - - while (true) { - Block output; - BrotliEncodeResult result = encoder.Encode(&output); - if (result == BrotliEncodeResult::Error) { - SendSyncFailErrno(s, "compress failed"); - return false; - } - - if (!output.empty()) { - msg.data.size = output.size(); - if (!WriteFdExactly(s, &msg.data, sizeof(msg.data)) || - !WriteFdExactly(s, output.data(), output.size())) { - return false; - } - } - - if (result == BrotliEncodeResult::Done) { - sending = false; - break; - } else if (result == BrotliEncodeResult::NeedInput) { - break; - } else if (result == BrotliEncodeResult::MoreOutput) { - continue; - } - } - } - - return true; -} - -static bool recv_impl(borrowed_fd s, const char* path, bool compressed, std::vector& buffer) { - __android_log_security_bswrite(SEC_TAG_ADB_RECV_FILE, path); - - unique_fd fd(adb_open(path, O_RDONLY | O_CLOEXEC)); - if (fd < 0) { - SendSyncFailErrno(s, "open failed"); - return false; - } - - int rc = posix_fadvise(fd.get(), 0, 0, POSIX_FADV_SEQUENTIAL | POSIX_FADV_NOREUSE); - if (rc != 0) { - D("[ Failed to fadvise: %s ]", strerror(rc)); - } - - bool result; - if (compressed) { - result = recv_compressed(s, std::move(fd)); - } else { - result = recv_uncompressed(s, std::move(fd), buffer); - } - - if (!result) { - return false; - } - - syncmsg msg; - msg.data.id = ID_DONE; - msg.data.size = 0; - return WriteFdExactly(s, &msg.data, sizeof(msg.data)); -} - -static bool do_recv_v1(borrowed_fd s, const char* path, std::vector& buffer) { - return recv_impl(s, path, false, buffer); -} - -static bool do_recv_v2(borrowed_fd s, const char* path, std::vector& buffer) { - syncmsg msg; - // Read the setup packet. - int rc = ReadFdExactly(s, &msg.recv_v2_setup, sizeof(msg.recv_v2_setup)); - if (rc == 0) { - LOG(ERROR) << "failed to read recv_v2 setup packet: EOF"; - return false; - } else if (rc < 0) { - PLOG(ERROR) << "failed to read recv_v2 setup packet"; - } - - bool compressed = false; - if (msg.recv_v2_setup.flags & kSyncFlagBrotli) { - msg.recv_v2_setup.flags &= ~kSyncFlagBrotli; - compressed = true; - } - if (msg.recv_v2_setup.flags) { - SendSyncFail(s, android::base::StringPrintf("unknown flags: %d", msg.recv_v2_setup.flags)); - return false; - } - - return recv_impl(s, path, compressed, buffer); -} - -static const char* sync_id_to_name(uint32_t id) { - switch (id) { - case ID_LSTAT_V1: - return "lstat_v1"; - case ID_LSTAT_V2: - return "lstat_v2"; - case ID_STAT_V2: - return "stat_v2"; - case ID_LIST_V1: - return "list_v1"; - case ID_LIST_V2: - return "list_v2"; - case ID_SEND_V1: - return "send_v1"; - case ID_SEND_V2: - return "send_v2"; - case ID_RECV_V1: - return "recv_v1"; - case ID_RECV_V2: - return "recv_v2"; - case ID_QUIT: - return "quit"; - default: - return "???"; - } -} - -static bool handle_sync_command(int fd, std::vector& buffer) { - D("sync: waiting for request"); - - SyncRequest request; - if (!ReadFdExactly(fd, &request, sizeof(request))) { - SendSyncFail(fd, "command read failure"); - return false; - } - size_t path_length = request.path_length; - if (path_length > 1024) { - SendSyncFail(fd, "path too long"); - return false; - } - char name[1025]; - if (!ReadFdExactly(fd, name, path_length)) { - SendSyncFail(fd, "filename read failure"); - return false; - } - name[path_length] = 0; - - std::string id_name = sync_id_to_name(request.id); - - D("sync: %s('%s')", id_name.c_str(), name); - switch (request.id) { - case ID_LSTAT_V1: - if (!do_lstat_v1(fd, name)) return false; - break; - case ID_LSTAT_V2: - case ID_STAT_V2: - if (!do_stat_v2(fd, request.id, name)) return false; - break; - case ID_LIST_V1: - if (!do_list_v1(fd, name)) return false; - break; - case ID_LIST_V2: - if (!do_list_v2(fd, name)) return false; - break; - case ID_SEND_V1: - if (!do_send_v1(fd, name, buffer)) return false; - break; - case ID_SEND_V2: - if (!do_send_v2(fd, name, buffer)) return false; - break; - case ID_RECV_V1: - if (!do_recv_v1(fd, name, buffer)) return false; - break; - case ID_RECV_V2: - if (!do_recv_v2(fd, name, buffer)) return false; - break; - case ID_QUIT: - return false; - default: - SendSyncFail(fd, StringPrintf("unknown command %08x", request.id)); - return false; - } - - return true; -} - -void file_sync_service(unique_fd fd) { - std::vector buffer(SYNC_DATA_MAX); - - while (handle_sync_command(fd.get(), buffer)) { - } - - D("sync: done"); -} diff --git a/adb/daemon/file_sync_service.h b/adb/daemon/file_sync_service.h deleted file mode 100644 index f300e7b3a644c6670e4c31b5738af3122ede2408..0000000000000000000000000000000000000000 --- a/adb/daemon/file_sync_service.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2018 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. - */ - -#pragma once - -#include "adb_unique_fd.h" - -void file_sync_service(unique_fd fd); diff --git a/adb/daemon/framebuffer_service.cpp b/adb/daemon/framebuffer_service.cpp deleted file mode 100644 index 676f8e9db1914b8be089bf332993bd3f47f1a60f..0000000000000000000000000000000000000000 --- a/adb/daemon/framebuffer_service.cpp +++ /dev/null @@ -1,187 +0,0 @@ -/* - * 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 "framebuffer_service.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sysdeps.h" - -#include "adb.h" -#include "adb_io.h" -#include "adb_utils.h" - -/* TODO: -** - sync with vsync to avoid tearing -*/ -/* This version number defines the format of the fbinfo struct. - It must match versioning in ddms where this data is consumed. */ -#define DDMS_RAWIMAGE_VERSION 2 -struct fbinfo { - unsigned int version; - unsigned int bpp; - unsigned int colorSpace; - 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(unique_fd fd) { - struct fbinfo fbinfo; - unsigned int i, bsize; - char buf[640]; - int fd_screencap; - int w, h, f, c; - int fds[2]; - pid_t pid; - - if (pipe2(fds, O_CLOEXEC) < 0) return; - - pid = fork(); - if (pid < 0) goto done; - - if (pid == 0) { - dup2(fds[1], STDOUT_FILENO); - adb_close(fds[0]); - adb_close(fds[1]); - const char* command = "screencap"; - const char *args[2] = {command, nullptr}; - execvp(command, (char**)args); - perror_exit("exec screencap failed"); - } - - adb_close(fds[1]); - fd_screencap = fds[0]; - - /* read w, h, format & color space */ - if(!ReadFdExactly(fd_screencap, &w, 4)) goto done; - if(!ReadFdExactly(fd_screencap, &h, 4)) goto done; - if(!ReadFdExactly(fd_screencap, &f, 4)) goto done; - if(!ReadFdExactly(fd_screencap, &c, 4)) goto done; - - fbinfo.version = DDMS_RAWIMAGE_VERSION; - fbinfo.colorSpace = c; - /* 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 (!WriteFdExactly(fd.get(), &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(!ReadFdExactly(fd_screencap, buf, bsize)) goto done; - if (!WriteFdExactly(fd.get(), buf, bsize)) goto done; - } - -done: - adb_close(fds[0]); - - TEMP_FAILURE_RETRY(waitpid(pid, nullptr, 0)); -} diff --git a/adb/daemon/framebuffer_service.h b/adb/daemon/framebuffer_service.h deleted file mode 100644 index bab44be364a6b7718a1a4ac542b8132d2aadcedd..0000000000000000000000000000000000000000 --- a/adb/daemon/framebuffer_service.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (C) 2018 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. - */ - -#pragma once - -#include "adb_unique_fd.h" - -#if defined(__ANDROID__) -void framebuffer_service(unique_fd fd); -#endif diff --git a/adb/daemon/jdwp_service.cpp b/adb/daemon/jdwp_service.cpp deleted file mode 100644 index b92a7dec0e8125ce567cef3b5c2d3a48df168220..0000000000000000000000000000000000000000 --- a/adb/daemon/jdwp_service.cpp +++ /dev/null @@ -1,438 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -#if !ADB_HOST - -#define TRACE_TAG JDWP - -#include "sysdeps.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include "adb.h" -#include "adb_io.h" -#include "adb_unique_fd.h" -#include "adb_utils.h" - -using android::base::borrowed_fd; -using android::base::unique_fd; - -/* here's how these things work. - - when adbd starts, it creates a unix server socket - named @jdwp-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 @jdwp-control to announce its availability. - - - JDWP thread @jdwp-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 @jdwp-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 - **/ - -static void jdwp_process_event(int socket, unsigned events, void* _proc); -static void jdwp_process_list_updated(void); - -struct JdwpProcess; -static auto& _jdwp_list = *new std::list>(); - -struct JdwpProcess { - JdwpProcess(unique_fd socket, pid_t pid) { - CHECK(pid != 0); - - this->socket = socket; - this->pid = pid; - this->fde = fdevent_create(socket.release(), jdwp_process_event, this); - - if (!this->fde) { - LOG(FATAL) << "could not create fdevent for new JDWP process"; - } - } - - ~JdwpProcess() { - if (this->socket >= 0) { - adb_shutdown(this->socket); - this->socket = -1; - } - - if (this->fde) { - fdevent_destroy(this->fde); - this->fde = nullptr; - } - - out_fds.clear(); - } - - void RemoveFromList() { - auto pred = [this](const auto& proc) { return proc.get() == this; }; - _jdwp_list.remove_if(pred); - } - - borrowed_fd socket = -1; - int32_t pid = -1; - fdevent* fde = nullptr; - - std::vector out_fds; -}; - -static size_t jdwp_process_list(char* buffer, size_t bufferlen) { - std::string temp; - - for (auto& proc : _jdwp_list) { - std::string next = std::to_string(proc->pid) + "\n"; - if (temp.length() + next.length() > bufferlen) { - D("truncating JDWP process list (max len = %zu)", bufferlen); - break; - } - temp.append(next); - } - - memcpy(buffer, temp.data(), temp.length()); - return temp.length(); -} - -static size_t jdwp_process_list_msg(char* buffer, size_t bufferlen) { - // Message is length-prefixed with 4 hex digits in ASCII. - static constexpr size_t header_len = 4; - if (bufferlen < header_len) { - LOG(FATAL) << "invalid JDWP process list buffer size: " << bufferlen; - } - - char head[header_len + 1]; - size_t len = jdwp_process_list(buffer + header_len, bufferlen - header_len); - snprintf(head, sizeof head, "%04zx", len); - memcpy(buffer, head, header_len); - return len + header_len; -} - -static void jdwp_process_event(int socket, unsigned events, void* _proc) { - JdwpProcess* proc = reinterpret_cast(_proc); - CHECK_EQ(socket, proc->socket.get()); - - if (events & FDE_READ) { - // We already have the PID, if we can read from the socket, we've probably hit EOF. - D("terminating JDWP connection %d", proc->pid); - goto CloseProcess; - } - - if (events & FDE_WRITE) { - D("trying to send fd to JDWP process (count = %zu)", proc->out_fds.size()); - CHECK(!proc->out_fds.empty()); - - int fd = proc->out_fds.back().get(); - if (android::base::SendFileDescriptors(socket, "", 1, fd) != 1) { - D("sending new file descriptor to JDWP %d failed: %s", proc->pid, strerror(errno)); - goto CloseProcess; - } - - D("sent file descriptor %d to JDWP process %d", fd, proc->pid); - - proc->out_fds.pop_back(); - if (proc->out_fds.empty()) { - fdevent_del(proc->fde, FDE_WRITE); - } - } - - return; - -CloseProcess: - proc->RemoveFromList(); - jdwp_process_list_updated(); -} - -unique_fd create_jdwp_connection_fd(int pid) { - D("looking for pid %d in JDWP process list", pid); - - for (auto& proc : _jdwp_list) { - if (proc->pid == pid) { - int fds[2]; - - if (adb_socketpair(fds) < 0) { - D("%s: socket pair creation failed: %s", __FUNCTION__, strerror(errno)); - return unique_fd{}; - } - D("socketpair: (%d,%d)", fds[0], fds[1]); - - proc->out_fds.emplace_back(fds[1]); - if (proc->out_fds.size() == 1) { - fdevent_add(proc->fde, FDE_WRITE); - } - - return unique_fd{fds[0]}; - } - } - D("search failed !!"); - return unique_fd{}; -} - -/** "jdwp" local service implementation - ** this simply returns the list of known JDWP process pids - **/ - -struct JdwpSocket : public asocket { - bool pass = false; -}; - -static void jdwp_socket_close(asocket* s) { - D("LS(%d): closing jdwp socket", s->id); - - if (s->peer) { - D("LS(%d) peer->close()ing peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd); - s->peer->peer = nullptr; - s->peer->close(s->peer); - s->peer = nullptr; - } - - remove_socket(s); - delete s; -} - -static int jdwp_socket_enqueue(asocket* s, apacket::payload_type) { - /* you can't write to this asocket */ - D("LS(%d): JDWP socket received data?", s->id); - s->peer->close(s->peer); - return -1; -} - -static void jdwp_socket_ready(asocket* s) { - JdwpSocket* jdwp = (JdwpSocket*)s; - asocket* peer = jdwp->peer; - - /* on the first call, send the list of pids, - * on the second one, close the connection - */ - if (!jdwp->pass) { - apacket::payload_type data; - data.resize(s->get_max_payload()); - size_t len = jdwp_process_list(&data[0], data.size()); - data.resize(len); - peer->enqueue(peer, std::move(data)); - jdwp->pass = true; - } else { - peer->close(peer); - } -} - -asocket* create_jdwp_service_socket(void) { - JdwpSocket* s = new JdwpSocket(); - - if (!s) { - LOG(FATAL) << "failed to allocate JdwpSocket"; - } - - install_local_socket(s); - - s->ready = jdwp_socket_ready; - s->enqueue = jdwp_socket_enqueue; - s->close = jdwp_socket_close; - s->pass = false; - - return s; -} - -/** "track-jdwp" local service implementation - ** this periodically sends the list of known JDWP process pids - ** to the client... - **/ - -struct JdwpTracker : public asocket { - bool need_initial; -}; - -static auto& _jdwp_trackers = *new std::vector>(); - -static void jdwp_process_list_updated(void) { - std::string data; - data.resize(1024); - data.resize(jdwp_process_list_msg(&data[0], data.size())); - - for (auto& t : _jdwp_trackers) { - if (t->peer) { - // The tracker might not have been connected yet. - apacket::payload_type payload(data.begin(), data.end()); - t->peer->enqueue(t->peer, std::move(payload)); - } - } -} - -static void jdwp_tracker_close(asocket* s) { - D("LS(%d): destroying jdwp tracker service", s->id); - - if (s->peer) { - D("LS(%d) peer->close()ing peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd); - s->peer->peer = nullptr; - s->peer->close(s->peer); - s->peer = nullptr; - } - - remove_socket(s); - - auto pred = [s](const auto& tracker) { return tracker.get() == s; }; - _jdwp_trackers.erase(std::remove_if(_jdwp_trackers.begin(), _jdwp_trackers.end(), pred), - _jdwp_trackers.end()); -} - -static void jdwp_tracker_ready(asocket* s) { - JdwpTracker* t = (JdwpTracker*)s; - - if (t->need_initial) { - apacket::payload_type data; - data.resize(s->get_max_payload()); - data.resize(jdwp_process_list_msg(&data[0], data.size())); - t->need_initial = false; - s->peer->enqueue(s->peer, std::move(data)); - } -} - -static int jdwp_tracker_enqueue(asocket* s, apacket::payload_type) { - /* you can't write to this socket */ - D("LS(%d): JDWP tracker received data?", s->id); - s->peer->close(s->peer); - return -1; -} - -asocket* create_jdwp_tracker_service_socket(void) { - auto t = std::make_unique(); - if (!t) { - LOG(FATAL) << "failed to allocate JdwpTracker"; - } - - memset(t.get(), 0, sizeof(asocket)); - - install_local_socket(t.get()); - D("LS(%d): created new jdwp tracker service", t->id); - - t->ready = jdwp_tracker_ready; - t->enqueue = jdwp_tracker_enqueue; - t->close = jdwp_tracker_close; - t->need_initial = true; - - asocket* result = t.get(); - - _jdwp_trackers.emplace_back(std::move(t)); - - return result; -} - -int init_jdwp(void) { - std::thread([]() { - adb_thread_setname("jdwp control"); - adbconnection_listen([](int fd, pid_t pid) { - LOG(INFO) << "jdwp connection from " << pid; - fdevent_run_on_main_thread([fd, pid] { - unique_fd ufd(fd); - auto proc = std::make_unique(std::move(ufd), pid); - if (!proc) { - LOG(FATAL) << "failed to allocate JdwpProcess"; - } - _jdwp_list.emplace_back(std::move(proc)); - jdwp_process_list_updated(); - }); - }); - }).detach(); - return 0; -} - -#endif /* !ADB_HOST */ diff --git a/adb/daemon/logging.cpp b/adb/daemon/logging.cpp deleted file mode 100644 index 203c6c73d3cf3363427f927c08d5fec4daa353a9..0000000000000000000000000000000000000000 --- a/adb/daemon/logging.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2020 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 "daemon/logging.h" - -#include -#include -#include - -#include -#include -#include -#include - -#if defined(__ANDROID__) -struct LogStatus { - bool enabled[static_cast(adb::LogType::COUNT)]; - - bool& operator[](adb::LogType type) { return enabled[static_cast(type)]; } -}; - -using android::base::CachedProperty; -using android::base::NoDestructor; - -static NoDestructor log_mutex; -static NoDestructor log_property GUARDED_BY(log_mutex)("debug.adbd.logging"); -static std::optional cached_log_status GUARDED_BY(log_mutex); - -static NoDestructor persist_log_property - GUARDED_BY(log_mutex)("persist.debug.adbd.logging"); -static std::optional cached_persist_log_status GUARDED_BY(log_mutex); - -static LogStatus ParseLogStatus(std::string_view str) { - LogStatus result = {}; - for (const auto& part : android::base::Split(std::string(str), ",")) { - if (part == "cnxn") { - result[adb::LogType::Connection] = true; - } else if (part == "service") { - result[adb::LogType::Service] = true; - } else if (part == "shell") { - result[adb::LogType::Shell] = true; - } else if (part == "all") { - result[adb::LogType::Connection] = true; - result[adb::LogType::Service] = true; - result[adb::LogType::Shell] = true; - } - } - return result; -} - -static LogStatus GetLogStatus(android::base::CachedProperty* property, - std::optional* cached_status) REQUIRES(log_mutex) { - bool changed; - const char* value = property->Get(&changed); - if (changed || !*cached_status) { - **cached_status = ParseLogStatus(value); - } - return **cached_status; -} - -namespace adb { -bool is_logging_enabled(LogType type) { - std::lock_guard lock(*log_mutex); - return GetLogStatus(log_property.get(), &cached_log_status)[type] || - GetLogStatus(persist_log_property.get(), &cached_persist_log_status)[type]; -} -} // namespace adb - -#else - -namespace adb { -bool is_logging_enabled(LogType type) { - return false; -} -} // namespace adb -#endif diff --git a/adb/daemon/logging.h b/adb/daemon/logging.h deleted file mode 100644 index 3e28bef318ebda8b8a29312c71a96aac29953d95..0000000000000000000000000000000000000000 --- a/adb/daemon/logging.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include - -namespace adb { -enum class LogType { - Connection, - Service, - Shell, - COUNT, -}; - -bool is_logging_enabled(LogType type); - -#define ADB_LOG(type) ::adb::is_logging_enabled(::adb::LogType::type) && LOG(INFO) - -} // namespace adb diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp deleted file mode 100644 index 7a0f7ffcdbd51d2ff442499557e44f539a7f3aae..0000000000000000000000000000000000000000 --- a/adb/daemon/main.cpp +++ /dev/null @@ -1,344 +0,0 @@ -/* - * Copyright (C) 2015 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 ADB - -#include "sysdeps.h" - -#if defined(__BIONIC__) -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include - -#if defined(__ANDROID__) -#include -#include -#include - -#include -#include "selinux/android.h" -#endif - -#include "adb.h" -#include "adb_auth.h" -#include "adb_listeners.h" -#include "adb_utils.h" -#include "adb_wifi.h" -#include "socket_spec.h" -#include "transport.h" - -#include "mdns.h" - -#if defined(__ANDROID__) -static const char* root_seclabel = nullptr; - -static bool should_drop_privileges() { - // The properties that affect `adb root` and `adb unroot` are ro.secure and - // ro.debuggable. In this context the names don't make the expected behavior - // particularly obvious. - // - // ro.debuggable: - // Allowed to become root, but not necessarily the default. Set to 1 on - // eng and userdebug builds. - // - // ro.secure: - // Drop privileges by default. Set to 1 on userdebug and user builds. - bool ro_secure = android::base::GetBoolProperty("ro.secure", true); - bool ro_debuggable = __android_log_is_debuggable(); - - // Drop privileges if ro.secure is set... - bool drop = ro_secure; - - // ... except "adb root" lets you keep privileges in a debuggable build. - std::string prop = android::base::GetProperty("service.adb.root", ""); - bool adb_root = (prop == "1"); - bool adb_unroot = (prop == "0"); - if (ro_debuggable && adb_root) { - drop = false; - } - // ... and "adb unroot" lets you explicitly drop privileges. - if (adb_unroot) { - drop = true; - } - - return drop; -} - -static void drop_privileges(int server_port) { - ScopedMinijail jail(minijail_new()); - - // 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 (ping) - // AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump) - // AID_SDCARD_R to allow reading from the SD card - // AID_SDCARD_RW to allow writing to the SD card - // AID_NET_BW_STATS to read out qtaguid statistics - // AID_READPROC for reading /proc entries across UID boundaries - // AID_UHID for using 'hid' command to read/write to /dev/uhid - // AID_EXT_DATA_RW for writing to /sdcard/Android/data (devices without sdcardfs) - // AID_EXT_OBB_RW for writing to /sdcard/Android/obb (devices without sdcardfs) - gid_t groups[] = {AID_ADB, AID_LOG, AID_INPUT, AID_INET, - AID_NET_BT, AID_NET_BT_ADMIN, AID_SDCARD_R, AID_SDCARD_RW, - AID_NET_BW_STATS, AID_READPROC, AID_UHID, AID_EXT_DATA_RW, - AID_EXT_OBB_RW}; - minijail_set_supplementary_gids(jail.get(), arraysize(groups), groups); - - // Don't listen on a port (default 5037) if running in secure mode. - // Don't run as root if running in secure mode. - if (should_drop_privileges()) { - const bool should_drop_caps = !__android_log_is_debuggable(); - - if (should_drop_caps) { - minijail_use_caps(jail.get(), CAP_TO_MASK(CAP_SETUID) | CAP_TO_MASK(CAP_SETGID)); - } - - minijail_change_gid(jail.get(), AID_SHELL); - minijail_change_uid(jail.get(), AID_SHELL); - // minijail_enter() will abort if any priv-dropping step fails. - minijail_enter(jail.get()); - - // Whenever ambient capabilities are being used, minijail cannot - // simultaneously drop the bounding capability set to just - // CAP_SETUID|CAP_SETGID while clearing the inheritable, effective, - // and permitted sets. So we need to do that in two steps. - using ScopedCaps = - std::unique_ptr::type, std::function>; - ScopedCaps caps(cap_get_proc(), &cap_free); - if (cap_clear_flag(caps.get(), CAP_INHERITABLE) == -1) { - PLOG(FATAL) << "cap_clear_flag(INHERITABLE) failed"; - } - if (cap_clear_flag(caps.get(), CAP_EFFECTIVE) == -1) { - PLOG(FATAL) << "cap_clear_flag(PEMITTED) failed"; - } - if (cap_clear_flag(caps.get(), CAP_PERMITTED) == -1) { - PLOG(FATAL) << "cap_clear_flag(PEMITTED) failed"; - } - if (cap_set_proc(caps.get()) != 0) { - PLOG(FATAL) << "cap_set_proc() failed"; - } - - D("Local port disabled"); - } else { - // minijail_enter() will abort if any priv-dropping step fails. - minijail_enter(jail.get()); - - if (root_seclabel != nullptr) { - if (selinux_android_setcon(root_seclabel) < 0) { - LOG(FATAL) << "Could not set SELinux context"; - } - } - std::string error; - std::string local_name = - android::base::StringPrintf("tcp:%d", server_port); - if (install_listener(local_name, "*smartsocket*", nullptr, 0, nullptr, &error)) { - LOG(FATAL) << "Could not install *smartsocket* listener: " << error; - } - } -} -#endif - -static void setup_adb(const std::vector& addrs) { -#if defined(__ANDROID__) - // Get the first valid port from addrs and setup mDNS. - int port = -1; - std::string error; - for (const auto& addr : addrs) { - port = get_host_socket_spec_port(addr, &error); - if (port != -1) { - break; - } - } - if (port == -1) { - port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT; - } - LOG(INFO) << "Setup mdns on port= " << port; - setup_mdns(port); -#endif - for (const auto& addr : addrs) { - LOG(INFO) << "adbd listening on " << addr; - local_init(addr); - } -} - -int adbd_main(int server_port) { - umask(0); - - signal(SIGPIPE, SIG_IGN); - -#if defined(__BIONIC__) - auto fdsan_level = android_fdsan_get_error_level(); - if (fdsan_level == ANDROID_FDSAN_ERROR_LEVEL_DISABLED) { - android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE); - } -#endif - - init_transport_registration(); - - // We need to call this even if auth isn't enabled because the file - // descriptor will always be open. - adbd_cloexec_auth_socket(); - -#if defined(__ANDROID__) - // If we're on userdebug/eng or the device is unlocked, permit no-authentication. - bool device_unlocked = "orange" == android::base::GetProperty("ro.boot.verifiedbootstate", ""); - if (__android_log_is_debuggable() || device_unlocked) { - auth_required = android::base::GetBoolProperty("ro.adb.secure", false); - } -#endif - - // 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 (adb_external_storage != nullptr) { - setenv("EXTERNAL_STORAGE", adb_external_storage, 1); - } else { - D("Warning: ADB_EXTERNAL_STORAGE is not set. Leaving EXTERNAL_STORAGE" - " unchanged.\n"); - } - -#if defined(__ANDROID__) - drop_privileges(server_port); -#endif - - // adbd_auth_init will spawn a thread, so we need to defer it until after selinux transitions. - adbd_auth_init(); - - bool is_usb = false; - -#if defined(__ANDROID__) - if (access(USB_FFS_ADB_EP0, F_OK) == 0) { - // Listen on USB. - usb_init(); - is_usb = true; - } -#endif - - // If one of these properties is set, also listen on that port. - // If one of the properties isn't set and we couldn't listen on usb, listen - // on the default port. - std::vector addrs; - std::string prop_addr = android::base::GetProperty("service.adb.listen_addrs", ""); - if (prop_addr.empty()) { - std::string prop_port = android::base::GetProperty("service.adb.tcp.port", ""); - if (prop_port.empty()) { - prop_port = android::base::GetProperty("persist.adb.tcp.port", ""); - } - -#if !defined(__ANDROID__) - if (prop_port.empty() && getenv("ADBD_PORT")) { - prop_port = getenv("ADBD_PORT"); - } -#endif - - int port; - if (sscanf(prop_port.c_str(), "%d", &port) == 1 && port > 0) { - D("using tcp port=%d", port); - // Listen on TCP and VSOCK port specified by service.adb.tcp.port property. - addrs.push_back(android::base::StringPrintf("tcp:%d", port)); - addrs.push_back(android::base::StringPrintf("vsock:%d", port)); - setup_adb(addrs); - } else if (!is_usb) { - // Listen on default port. - addrs.push_back( - android::base::StringPrintf("tcp:%d", DEFAULT_ADB_LOCAL_TRANSPORT_PORT)); - addrs.push_back( - android::base::StringPrintf("vsock:%d", DEFAULT_ADB_LOCAL_TRANSPORT_PORT)); - setup_adb(addrs); - } - } else { - addrs = android::base::Split(prop_addr, ","); - setup_adb(addrs); - } - - D("adbd_main(): pre init_jdwp()"); - init_jdwp(); - D("adbd_main(): post init_jdwp()"); - - D("Event loop starting"); - fdevent_loop(); - - return 0; -} - -int main(int argc, char** argv) { -#if defined(__BIONIC__) - // Set M_DECAY_TIME so that our allocations aren't immediately purged on free. - mallopt(M_DECAY_TIME, 1); -#endif - - while (true) { - static struct option opts[] = { - {"root_seclabel", required_argument, nullptr, 's'}, - {"device_banner", required_argument, nullptr, 'b'}, - {"version", no_argument, nullptr, 'v'}, - {"logpostfsdata", no_argument, nullptr, 'l'}, - }; - - int option_index = 0; - int c = getopt_long(argc, argv, "", opts, &option_index); - if (c == -1) { - break; - } - - switch (c) { -#if defined(__ANDROID__) - case 's': - root_seclabel = optarg; - break; -#endif - case 'b': - adb_device_banner = optarg; - break; - case 'v': - printf("Android Debug Bridge Daemon version %d.%d.%d\n", ADB_VERSION_MAJOR, - ADB_VERSION_MINOR, ADB_SERVER_VERSION); - return 0; - case 'l': - LOG(ERROR) << "post-fs-data triggered"; - return 0; - default: - // getopt already prints "adbd: invalid option -- %c" for us. - return 1; - } - } - - close_stdin(); - - adb_trace_init(argv); - - D("Handling main()"); - return adbd_main(DEFAULT_ADB_PORT); -} diff --git a/adb/daemon/mdns.cpp b/adb/daemon/mdns.cpp deleted file mode 100644 index fa692c0396363548e73604b9e7a328afa614c7c7..0000000000000000000000000000000000000000 --- a/adb/daemon/mdns.cpp +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright (C) 2016 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 "mdns.h" -#include "adb_mdns.h" -#include "sysdeps.h" - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -using namespace std::chrono_literals; - -static std::mutex& mdns_lock = *new std::mutex(); -static int port; -static DNSServiceRef mdns_refs[kNumADBDNSServices]; -static bool mdns_registered[kNumADBDNSServices]; - -void start_mdnsd() { - if (android::base::GetProperty("init.svc.mdnsd", "") == "running") { - return; - } - - android::base::SetProperty("ctl.start", "mdnsd"); - - if (! android::base::WaitForProperty("init.svc.mdnsd", "running", 5s)) { - LOG(ERROR) << "Could not start mdnsd."; - } -} - -static void mdns_callback(DNSServiceRef /*ref*/, - DNSServiceFlags /*flags*/, - DNSServiceErrorType errorCode, - const char* /*name*/, - const char* /*regtype*/, - const char* /*domain*/, - void* /*context*/) { - if (errorCode != kDNSServiceErr_NoError) { - LOG(ERROR) << "Encountered mDNS registration error (" - << errorCode << ")."; - } -} - -static void register_mdns_service(int index, int port, const std::string service_name) { - std::lock_guard lock(mdns_lock); - - - // https://tools.ietf.org/html/rfc6763 - // """ - // The format of the data within a DNS TXT record is one or more - // strings, packed together in memory without any intervening gaps or - // padding bytes for word alignment. - // - // The format of each constituent string within the DNS TXT record is a - // single length byte, followed by 0-255 bytes of text data. - // """ - // - // Therefore: - // 1. Begin with the string length - // 2. No null termination - - std::vector txtRecord; - - if (kADBDNSServiceTxtRecords[index]) { - size_t txtRecordStringLength = strlen(kADBDNSServiceTxtRecords[index]); - - txtRecord.resize(1 + // length byte - txtRecordStringLength // string bytes - ); - - txtRecord[0] = (char)txtRecordStringLength; - memcpy(txtRecord.data() + 1, kADBDNSServiceTxtRecords[index], txtRecordStringLength); - } - - auto error = DNSServiceRegister( - &mdns_refs[index], 0, 0, service_name.c_str(), kADBDNSServices[index], nullptr, nullptr, - htobe16((uint16_t)port), (uint16_t)txtRecord.size(), - txtRecord.empty() ? nullptr : txtRecord.data(), mdns_callback, nullptr); - - if (error != kDNSServiceErr_NoError) { - LOG(ERROR) << "Could not register mDNS service " << kADBDNSServices[index] << ", error (" - << error << ")."; - mdns_registered[index] = false; - } - - mdns_registered[index] = true; - - LOG(INFO) << "adbd mDNS service " << kADBDNSServices[index] - << " registered: " << mdns_registered[index]; -} - -static void unregister_mdns_service(int index) { - std::lock_guard lock(mdns_lock); - - if (mdns_registered[index]) { - DNSServiceRefDeallocate(mdns_refs[index]); - } -} - -static void register_base_mdns_transport() { - std::string hostname = "adb-"; - hostname += android::base::GetProperty("ro.serialno", "unidentified"); - register_mdns_service(kADBTransportServiceRefIndex, port, hostname); -} - -static void setup_mdns_thread() { - start_mdnsd(); - - // We will now only set up the normal transport mDNS service - // instead of registering all the adb secure mDNS services - // in the beginning. This is to provide more privacy/security. - register_base_mdns_transport(); -} - -// This also tears down any adb secure mDNS services, if they exist. -static void teardown_mdns() { - for (int i = 0; i < kNumADBDNSServices; ++i) { - unregister_mdns_service(i); - } -} - -static std::string RandomAlphaNumString(size_t len) { - std::string ret; - std::random_device rd; - std::mt19937 mt(rd()); - // Generate values starting with zero and then up to enough to cover numeric - // digits, small letters and capital letters (26 each). - std::uniform_int_distribution dist(0, 61); - for (size_t i = 0; i < len; ++i) { - uint8_t val = dist(mt); - if (val < 10) { - ret += '0' + val; - } else if (val < 36) { - ret += 'A' + (val - 10); - } else { - ret += 'a' + (val - 36); - } - } - return ret; -} - -static std::string GenerateDeviceGuid() { - // The format is adb-- - std::string guid = "adb-"; - - std::string serial = android::base::GetProperty("ro.serialno", ""); - if (serial.empty()) { - // Generate 16-bytes of random alphanum string - serial = RandomAlphaNumString(16); - } - guid += serial + '-'; - // Random six-char suffix - guid += RandomAlphaNumString(6); - return guid; -} - -static std::string ReadDeviceGuid() { - std::string guid = android::base::GetProperty("persist.adb.wifi.guid", ""); - if (guid.empty()) { - guid = GenerateDeviceGuid(); - CHECK(!guid.empty()); - android::base::SetProperty("persist.adb.wifi.guid", guid); - } - return guid; -} - -// Public interface///////////////////////////////////////////////////////////// - -void setup_mdns(int port_in) { - // Make sure the adb wifi guid is generated. - std::string guid = ReadDeviceGuid(); - CHECK(!guid.empty()); - port = port_in; - std::thread(setup_mdns_thread).detach(); - - // TODO: Make this more robust against a hard kill. - atexit(teardown_mdns); -} - -void register_adb_secure_connect_service(int port) { - std::thread([port]() { - auto service_name = ReadDeviceGuid(); - if (service_name.empty()) { - return; - } - LOG(INFO) << "Registering secure_connect service (" << service_name << ")"; - register_mdns_service(kADBSecureConnectServiceRefIndex, port, service_name); - }).detach(); -} - -void unregister_adb_secure_connect_service() { - std::thread([]() { unregister_mdns_service(kADBSecureConnectServiceRefIndex); }).detach(); -} - -bool is_adb_secure_connect_service_registered() { - std::lock_guard lock(mdns_lock); - return mdns_registered[kADBSecureConnectServiceRefIndex]; -} diff --git a/adb/daemon/mdns.h b/adb/daemon/mdns.h deleted file mode 100644 index e7e7a62171856805dca474b7bc92ab006bc4fe08..0000000000000000000000000000000000000000 --- a/adb/daemon/mdns.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2016 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 _DAEMON_MDNS_H_ -#define _DAEMON_MDNS_H_ - -void setup_mdns(int port); - -void register_adb_secure_connect_service(int port); -void unregister_adb_secure_connect_service(); -bool is_adb_secure_connect_service_registered(); - -void start_mdnsd(); -#endif // _DAEMON_MDNS_H_ diff --git a/adb/daemon/restart_service.cpp b/adb/daemon/restart_service.cpp deleted file mode 100644 index 16d26279836d0978f2969b30de2e22bf0b0452d2..0000000000000000000000000000000000000000 --- a/adb/daemon/restart_service.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2019 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 SERVICES - -#include "sysdeps.h" - -#include - -#include -#include -#include -#include - -#include "adb_io.h" -#include "adb_unique_fd.h" - -void restart_root_service(unique_fd fd) { - if (getuid() == 0) { - WriteFdExactly(fd.get(), "adbd is already running as root\n"); - return; - } - if (!__android_log_is_debuggable()) { - WriteFdExactly(fd.get(), "adbd cannot run as root in production builds\n"); - return; - } - - LOG(INFO) << "adbd restarting as root"; - android::base::SetProperty("service.adb.root", "1"); - WriteFdExactly(fd.get(), "restarting adbd as root\n"); -} - -void restart_unroot_service(unique_fd fd) { - if (getuid() != 0) { - WriteFdExactly(fd.get(), "adbd not running as root\n"); - return; - } - - LOG(INFO) << "adbd restarting as nonroot"; - android::base::SetProperty("service.adb.root", "0"); - WriteFdExactly(fd.get(), "restarting adbd as non root\n"); -} - -void restart_tcp_service(unique_fd fd, int port) { - if (port <= 0) { - WriteFdFmt(fd.get(), "invalid port %d\n", port); - return; - } - - LOG(INFO) << "adbd restarting in TCP mode (port = " << port << ")"; - android::base::SetProperty("service.adb.tcp.port", android::base::StringPrintf("%d", port)); - WriteFdFmt(fd.get(), "restarting in TCP mode port: %d\n", port); -} - -void restart_usb_service(unique_fd fd) { - LOG(INFO) << "adbd restarting in USB mode"; - android::base::SetProperty("service.adb.tcp.port", "0"); - WriteFdExactly(fd.get(), "restarting in USB mode\n"); -} diff --git a/adb/daemon/restart_service.h b/adb/daemon/restart_service.h deleted file mode 100644 index 19840bd588ccba75c7aae3400abf82247bbd1567..0000000000000000000000000000000000000000 --- a/adb/daemon/restart_service.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2019 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. - */ - -#pragma once - -#include "adb_unique_fd.h" - -#if defined(__ANDROID__) -void restart_root_service(unique_fd fd); -void restart_unroot_service(unique_fd fd); -void restart_tcp_service(unique_fd fd, int port); -void restart_usb_service(unique_fd fd); -#endif diff --git a/adb/daemon/services.cpp b/adb/daemon/services.cpp deleted file mode 100644 index 6bbf66e8e35de5b57f73ad8779288fdcfc2e747d..0000000000000000000000000000000000000000 --- a/adb/daemon/services.cpp +++ /dev/null @@ -1,335 +0,0 @@ -/* - * Copyright (C) 2018 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 SERVICES - -#include "sysdeps.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "adb.h" -#include "adb_io.h" -#include "adb_unique_fd.h" -#include "adb_utils.h" -#include "services.h" -#include "socket_spec.h" -#include "sysdeps.h" -#include "transport.h" - -#include "daemon/file_sync_service.h" -#include "daemon/framebuffer_service.h" -#include "daemon/logging.h" -#include "daemon/restart_service.h" -#include "daemon/shell_service.h" - -void reconnect_service(unique_fd fd, atransport* t) { - WriteFdExactly(fd.get(), "done"); - kick_transport(t); -} - -unique_fd reverse_service(std::string_view command, atransport* transport) { - // TODO: Switch handle_forward_request to std::string_view. - std::string str(command); - - int s[2]; - if (adb_socketpair(s)) { - PLOG(ERROR) << "cannot create service socket pair."; - return unique_fd{}; - } - VLOG(SERVICES) << "service socketpair: " << s[0] << ", " << s[1]; - if (!handle_forward_request(str.c_str(), transport, s[1])) { - SendFail(s[1], "not a reverse forwarding command"); - } - adb_close(s[1]); - return unique_fd{s[0]}; -} - -// Shell service string can look like: -// shell[,arg1,arg2,...]:[command] -unique_fd ShellService(std::string_view args, const atransport* transport) { - size_t delimiter_index = args.find(':'); - if (delimiter_index == std::string::npos) { - LOG(ERROR) << "No ':' found in shell service arguments: " << args; - return unique_fd{}; - } - - // TODO: android::base::Split(const std::string_view&, ...) - std::string service_args(args.substr(0, delimiter_index)); - std::string command(args.substr(delimiter_index + 1)); - - // Defaults: - // PTY for interactive, raw for non-interactive. - // No protocol. - // $TERM set to "dumb". - SubprocessType type(command.empty() ? SubprocessType::kPty : SubprocessType::kRaw); - SubprocessProtocol protocol = SubprocessProtocol::kNone; - std::string terminal_type = "dumb"; - - for (const std::string& arg : android::base::Split(service_args, ",")) { - if (arg == kShellServiceArgRaw) { - type = SubprocessType::kRaw; - } else if (arg == kShellServiceArgPty) { - type = SubprocessType::kPty; - } else if (arg == kShellServiceArgShellProtocol) { - protocol = SubprocessProtocol::kShell; - } else if (arg.starts_with("TERM=")) { - terminal_type = arg.substr(strlen("TERM=")); - } else if (!arg.empty()) { - // This is not an error to allow for future expansion. - LOG(WARNING) << "Ignoring unknown shell service argument: " << arg; - } - } - - return StartSubprocess(command, terminal_type.c_str(), type, protocol); -} - -static void spin_service(unique_fd fd) { - if (!__android_log_is_debuggable()) { - WriteFdExactly(fd.get(), "refusing to spin on non-debuggable build\n"); - return; - } - - // A service that creates an fdevent that's always pending, and then ignores it. - unique_fd pipe_read, pipe_write; - if (!Pipe(&pipe_read, &pipe_write)) { - WriteFdExactly(fd.get(), "failed to create pipe\n"); - return; - } - - fdevent_run_on_main_thread([fd = pipe_read.release()]() { - fdevent* fde = fdevent_create( - fd, [](int, unsigned, void*) {}, nullptr); - fdevent_add(fde, FDE_READ); - }); - - WriteFdExactly(fd.get(), "spinning\n"); -} - -[[maybe_unused]] static unique_fd reboot_device(const std::string& name) { -#if defined(__ANDROID_RECOVERY__) - if (!__android_log_is_debuggable()) { - auto reboot_service = [name](unique_fd fd) { - std::string reboot_string = android::base::StringPrintf("reboot,%s", name.c_str()); - if (!android::base::SetProperty(ANDROID_RB_PROPERTY, reboot_string)) { - WriteFdFmt(fd.get(), "reboot (%s) failed\n", reboot_string.c_str()); - return; - } - while (true) pause(); - }; - return create_service_thread("reboot", reboot_service); - } -#endif - // Fall through - std::string cmd = "/system/bin/reboot "; - cmd += name; - return StartSubprocess(cmd, nullptr, SubprocessType::kRaw, SubprocessProtocol::kNone); -} - -struct ServiceSocket : public asocket { - ServiceSocket() { - install_local_socket(this); - this->enqueue = [](asocket* self, apacket::payload_type data) { - return static_cast(self)->Enqueue(std::move(data)); - }; - this->ready = [](asocket* self) { return static_cast(self)->Ready(); }; - this->close = [](asocket* self) { return static_cast(self)->Close(); }; - } - virtual ~ServiceSocket() = default; - - virtual int Enqueue(apacket::payload_type data) { return -1; } - virtual void Ready() {} - virtual void Close() { - if (peer) { - peer->peer = nullptr; - if (peer->shutdown) { - peer->shutdown(peer); - } - peer->close(peer); - } - - remove_socket(this); - delete this; - } -}; - -struct SinkSocket : public ServiceSocket { - explicit SinkSocket(size_t byte_count) { - LOG(INFO) << "Creating new SinkSocket with capacity " << byte_count; - bytes_left_ = byte_count; - } - - virtual ~SinkSocket() { LOG(INFO) << "SinkSocket destroyed"; } - - virtual int Enqueue(apacket::payload_type data) override final { - if (bytes_left_ <= data.size()) { - // Done reading. - Close(); - return -1; - } - - bytes_left_ -= data.size(); - return 0; - } - - size_t bytes_left_; -}; - -struct SourceSocket : public ServiceSocket { - explicit SourceSocket(size_t byte_count) { - LOG(INFO) << "Creating new SourceSocket with capacity " << byte_count; - bytes_left_ = byte_count; - } - - virtual ~SourceSocket() { LOG(INFO) << "SourceSocket destroyed"; } - - void Ready() { - size_t len = std::min(bytes_left_, get_max_payload()); - if (len == 0) { - Close(); - return; - } - - Block block(len); - memset(block.data(), 0, block.size()); - peer->enqueue(peer, std::move(block)); - bytes_left_ -= len; - } - - int Enqueue(apacket::payload_type data) { return -1; } - - size_t bytes_left_; -}; - -asocket* daemon_service_to_socket(std::string_view name) { - if (name == "jdwp") { - return create_jdwp_service_socket(); - } else if (name == "track-jdwp") { - return create_jdwp_tracker_service_socket(); - } else if (android::base::ConsumePrefix(&name, "sink:")) { - uint64_t byte_count = 0; - if (!ParseUint(&byte_count, name)) { - return nullptr; - } - return new SinkSocket(byte_count); - } else if (android::base::ConsumePrefix(&name, "source:")) { - uint64_t byte_count = 0; - if (!ParseUint(&byte_count, name)) { - return nullptr; - } - return new SourceSocket(byte_count); - } - - return nullptr; -} - -unique_fd daemon_service_to_fd(std::string_view name, atransport* transport) { - ADB_LOG(Service) << "transport " << transport->serial_name() << " opening service " << name; - -#if defined(__ANDROID__) && !defined(__ANDROID_RECOVERY__) - if (name.starts_with("abb:") || name.starts_with("abb_exec:")) { - return execute_abb_command(name); - } -#endif - -#if defined(__ANDROID__) - if (name.starts_with("framebuffer:")) { - return create_service_thread("fb", framebuffer_service); - } else if (android::base::ConsumePrefix(&name, "remount:")) { - std::string cmd = "/system/bin/remount "; - cmd += name; - return StartSubprocess(cmd, nullptr, SubprocessType::kRaw, SubprocessProtocol::kNone); - } else if (android::base::ConsumePrefix(&name, "reboot:")) { - return reboot_device(std::string(name)); - } else if (name.starts_with("root:")) { - return create_service_thread("root", restart_root_service); - } else if (name.starts_with("unroot:")) { - return create_service_thread("unroot", restart_unroot_service); - } else if (android::base::ConsumePrefix(&name, "backup:")) { - std::string cmd = "/system/bin/bu backup "; - cmd += name; - return StartSubprocess(cmd, nullptr, SubprocessType::kRaw, SubprocessProtocol::kNone); - } else if (name.starts_with("restore:")) { - return StartSubprocess("/system/bin/bu restore", nullptr, SubprocessType::kRaw, - SubprocessProtocol::kNone); - } else if (name.starts_with("disable-verity:")) { - return StartSubprocess("/system/bin/disable-verity", nullptr, SubprocessType::kRaw, - SubprocessProtocol::kNone); - } else if (name.starts_with("enable-verity:")) { - return StartSubprocess("/system/bin/enable-verity", nullptr, SubprocessType::kRaw, - SubprocessProtocol::kNone); - } else if (android::base::ConsumePrefix(&name, "tcpip:")) { - std::string str(name); - - int port; - if (sscanf(str.c_str(), "%d", &port) != 1) { - return unique_fd{}; - } - return create_service_thread("tcp", - std::bind(restart_tcp_service, std::placeholders::_1, port)); - } else if (name.starts_with("usb:")) { - return create_service_thread("usb", restart_usb_service); - } -#endif - - if (android::base::ConsumePrefix(&name, "dev:")) { - return unique_fd{unix_open(name, O_RDWR | O_CLOEXEC)}; - } else if (android::base::ConsumePrefix(&name, "jdwp:")) { - pid_t pid; - if (!ParseUint(&pid, name)) { - return unique_fd{}; - } - return create_jdwp_connection_fd(pid); - } else if (android::base::ConsumePrefix(&name, "shell")) { - return ShellService(name, transport); - } else if (android::base::ConsumePrefix(&name, "exec:")) { - return StartSubprocess(std::string(name), nullptr, SubprocessType::kRaw, - SubprocessProtocol::kNone); - } else if (name.starts_with("sync:")) { - return create_service_thread("sync", file_sync_service); - } else if (android::base::ConsumePrefix(&name, "reverse:")) { - return reverse_service(name, transport); - } else if (name == "reconnect") { - return create_service_thread( - "reconnect", std::bind(reconnect_service, std::placeholders::_1, transport)); - } else if (name == "spin") { - return create_service_thread("spin", spin_service); - } - - return unique_fd{}; -} diff --git a/adb/daemon/shell_service.cpp b/adb/daemon/shell_service.cpp deleted file mode 100644 index fbfae1e44f6e79f83636eac9f5c4c14d224269fe..0000000000000000000000000000000000000000 --- a/adb/daemon/shell_service.cpp +++ /dev/null @@ -1,911 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -// Functionality for launching and managing shell subprocesses. -// -// There are two types of subprocesses, PTY or raw. PTY is typically used for -// an interactive session, raw for non-interactive. There are also two methods -// of communication with the subprocess, passing raw data or using a simple -// protocol to wrap packets. The protocol allows separating stdout/stderr and -// passing the exit code back, but is not backwards compatible. -// ----------------+-------------------------------------- -// Type Protocol | Exit code? Separate stdout/stderr? -// ----------------+-------------------------------------- -// PTY No | No No -// Raw No | No No -// PTY Yes | Yes No -// Raw Yes | Yes Yes -// ----------------+-------------------------------------- -// -// Non-protocol subprocesses work by passing subprocess stdin/out/err through -// a single pipe which is registered with a local socket in adbd. The local -// socket uses the fdevent loop to pass raw data between this pipe and the -// transport, which then passes data back to the adb client. Cleanup is done by -// waiting in a separate thread for the subprocesses to exit and then signaling -// a separate fdevent to close out the local socket from the main loop. -// -// ------------------+-------------------------+------------------------------ -// Subprocess | adbd subprocess thread | adbd main fdevent loop -// ------------------+-------------------------+------------------------------ -// | | -// stdin/out/err <-----------------------------> LocalSocket -// | | | -// | | Block on exit | -// | | * | -// v | * | -// Exit ---> Unblock | -// | | | -// | v | -// | Notify shell exit FD ---> Close LocalSocket -// ------------------+-------------------------+------------------------------ -// -// The protocol requires the thread to intercept stdin/out/err in order to -// wrap/unwrap data with shell protocol packets. -// -// ------------------+-------------------------+------------------------------ -// Subprocess | adbd subprocess thread | adbd main fdevent loop -// ------------------+-------------------------+------------------------------ -// | | -// stdin/out <---> Protocol <---> LocalSocket -// stderr ---> Protocol ---> LocalSocket -// | | | -// v | | -// Exit ---> Exit code protocol ---> LocalSocket -// | | | -// | v | -// | Notify shell exit FD ---> Close LocalSocket -// ------------------+-------------------------+------------------------------ -// -// An alternate approach is to put the protocol wrapping/unwrapping in the main -// fdevent loop, which has the advantage of being able to re-use the existing -// select() code for handling data streams. However, implementation turned out -// to be more complex due to partial reads and non-blocking I/O so this model -// was chosen instead. - -#define TRACE_TAG SHELL - -#include "sysdeps.h" - -#include "shell_service.h" - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#if defined(__ANDROID__) -#include -#endif - -#include "adb.h" -#include "adb_io.h" -#include "adb_trace.h" -#include "adb_unique_fd.h" -#include "adb_utils.h" -#include "daemon/logging.h" -#include "security_log_tags.h" -#include "shell_protocol.h" - -namespace { - -// Reads from |fd| until close or failure. -std::string ReadAll(borrowed_fd fd) { - char buffer[512]; - std::string received; - - while (1) { - int bytes = adb_read(fd, buffer, sizeof(buffer)); - if (bytes <= 0) { - break; - } - received.append(buffer, bytes); - } - - return received; -} - -// Creates a socketpair and saves the endpoints to |fd1| and |fd2|. -bool CreateSocketpair(unique_fd* fd1, unique_fd* fd2) { - int sockets[2]; - if (adb_socketpair(sockets) < 0) { - PLOG(ERROR) << "cannot create socket pair"; - return false; - } - fd1->reset(sockets[0]); - fd2->reset(sockets[1]); - return true; -} - -struct SubprocessPollfds { - adb_pollfd pfds[3]; - - adb_pollfd* data() { return pfds; } - size_t size() { return 3; } - - adb_pollfd* begin() { return pfds; } - adb_pollfd* end() { return pfds + size(); } - - adb_pollfd& stdinout_pfd() { return pfds[0]; } - adb_pollfd& stderr_pfd() { return pfds[1]; } - adb_pollfd& protocol_pfd() { return pfds[2]; } -}; - -class Subprocess { - public: - Subprocess(std::string command, const char* terminal_type, SubprocessType type, - SubprocessProtocol protocol, bool make_pty_raw); - ~Subprocess(); - - const std::string& command() const { return command_; } - - int ReleaseLocalSocket() { return local_socket_sfd_.release(); } - - pid_t pid() const { return pid_; } - - // Sets up FDs, forks a subprocess, starts the subprocess manager thread, - // and exec's the child. Returns false and sets error on failure. - bool ForkAndExec(std::string* _Nonnull error); - - // Sets up FDs, starts a thread executing command and the manager thread, - // Returns false and sets error on failure. - bool ExecInProcess(Command command, std::string* _Nonnull error); - - // Start the subprocess manager thread. Consumes the subprocess, regardless of success. - // Returns false and sets error on failure. - static bool StartThread(std::unique_ptr subprocess, - std::string* _Nonnull error); - - private: - // Opens the file at |pts_name|. - int OpenPtyChildFd(const char* pts_name, unique_fd* error_sfd); - - bool ConnectProtocolEndpoints(std::string* _Nonnull error); - - static void ThreadHandler(void* userdata); - void PassDataStreams(); - void WaitForExit(); - - unique_fd* PollLoop(SubprocessPollfds* pfds); - - // Input/output stream handlers. Success returns nullptr, failure returns - // a pointer to the failed FD. - unique_fd* PassInput(); - unique_fd* PassOutput(unique_fd* sfd, ShellProtocol::Id id); - - const std::string command_; - const std::string terminal_type_; - SubprocessType type_; - SubprocessProtocol protocol_; - bool make_pty_raw_; - pid_t pid_ = -1; - unique_fd local_socket_sfd_; - - // Shell protocol variables. - unique_fd stdinout_sfd_, stderr_sfd_, protocol_sfd_; - std::unique_ptr input_, output_; - size_t input_bytes_left_ = 0; - - DISALLOW_COPY_AND_ASSIGN(Subprocess); -}; - -Subprocess::Subprocess(std::string command, const char* terminal_type, SubprocessType type, - SubprocessProtocol protocol, bool make_pty_raw) - : command_(std::move(command)), - terminal_type_(terminal_type ? terminal_type : ""), - type_(type), - protocol_(protocol), - make_pty_raw_(make_pty_raw) {} - -Subprocess::~Subprocess() { - WaitForExit(); -} - -static std::string GetHostName() { - char buf[HOST_NAME_MAX]; - if (gethostname(buf, sizeof(buf)) != -1 && strcmp(buf, "localhost") != 0) return buf; - - return android::base::GetProperty("ro.product.device", "android"); -} - -bool Subprocess::ForkAndExec(std::string* error) { - unique_fd child_stdinout_sfd, child_stderr_sfd; - unique_fd parent_error_sfd, child_error_sfd; - const char* pts_name = nullptr; - - if (command_.empty()) { - __android_log_security_bswrite(SEC_TAG_ADB_SHELL_INTERACTIVE, ""); - } else { - __android_log_security_bswrite(SEC_TAG_ADB_SHELL_CMD, command_.c_str()); - } - - // Create a socketpair for the fork() child to report any errors back to the parent. Since we - // use threads, logging directly from the child might deadlock due to locks held in another - // thread during the fork. - if (!CreateSocketpair(&parent_error_sfd, &child_error_sfd)) { - *error = android::base::StringPrintf( - "failed to create pipe for subprocess error reporting: %s", strerror(errno)); - return false; - } - - // Construct the environment for the child before we fork. - passwd* pw = getpwuid(getuid()); - std::unordered_map env; - if (environ) { - char** current = environ; - while (char* env_cstr = *current++) { - std::string env_string = env_cstr; - char* delimiter = strchr(&env_string[0], '='); - - // Drop any values that don't contain '='. - if (delimiter) { - *delimiter++ = '\0'; - env[env_string.c_str()] = delimiter; - } - } - } - - if (pw != nullptr) { - env["HOME"] = pw->pw_dir; - env["HOSTNAME"] = GetHostName(); - env["LOGNAME"] = pw->pw_name; - env["SHELL"] = pw->pw_shell; - env["TMPDIR"] = "/data/local/tmp"; - env["USER"] = pw->pw_name; - } - - if (!terminal_type_.empty()) { - env["TERM"] = terminal_type_; - } - - std::vector joined_env; - for (const auto& it : env) { - const char* key = it.first.c_str(); - const char* value = it.second.c_str(); - joined_env.push_back(android::base::StringPrintf("%s=%s", key, value)); - } - - std::vector cenv; - for (const std::string& str : joined_env) { - cenv.push_back(str.c_str()); - } - cenv.push_back(nullptr); - - if (type_ == SubprocessType::kPty) { - unique_fd pty_master(posix_openpt(O_RDWR | O_NOCTTY | O_CLOEXEC)); - if (pty_master == -1) { - *error = - android::base::StringPrintf("failed to create pty master: %s", strerror(errno)); - return false; - } - if (unlockpt(pty_master.get()) != 0) { - *error = android::base::StringPrintf("failed to unlockpt pty master: %s", - strerror(errno)); - return false; - } - - pid_ = fork(); - pts_name = ptsname(pty_master.get()); - if (pid_ > 0) { - stdinout_sfd_ = std::move(pty_master); - } - } else { - if (!CreateSocketpair(&stdinout_sfd_, &child_stdinout_sfd)) { - *error = android::base::StringPrintf("failed to create socketpair for stdin/out: %s", - strerror(errno)); - return false; - } - // Raw subprocess + shell protocol allows for splitting stderr. - if (protocol_ == SubprocessProtocol::kShell && - !CreateSocketpair(&stderr_sfd_, &child_stderr_sfd)) { - *error = android::base::StringPrintf("failed to create socketpair for stderr: %s", - strerror(errno)); - return false; - } - pid_ = fork(); - } - - if (pid_ == -1) { - *error = android::base::StringPrintf("fork failed: %s", strerror(errno)); - return false; - } - - if (pid_ == 0) { - // Subprocess child. - setsid(); - - if (type_ == SubprocessType::kPty) { - child_stdinout_sfd.reset(OpenPtyChildFd(pts_name, &child_error_sfd)); - } - - dup2(child_stdinout_sfd.get(), STDIN_FILENO); - dup2(child_stdinout_sfd.get(), STDOUT_FILENO); - dup2(child_stderr_sfd != -1 ? child_stderr_sfd.get() : child_stdinout_sfd.get(), - STDERR_FILENO); - - // exec doesn't trigger destructors, close the FDs manually. - stdinout_sfd_.reset(-1); - stderr_sfd_.reset(-1); - child_stdinout_sfd.reset(-1); - child_stderr_sfd.reset(-1); - parent_error_sfd.reset(-1); - close_on_exec(child_error_sfd); - - // adbd sets SIGPIPE to SIG_IGN to get EPIPE instead, and Linux propagates that to child - // processes, so we need to manually reset back to SIG_DFL here (http://b/35209888). - signal(SIGPIPE, SIG_DFL); - - // Increase oom_score_adj from -1000, so that the child is visible to the OOM-killer. - // Don't treat failure as an error, because old Android kernels explicitly disabled this. - int oom_score_adj_fd = adb_open("/proc/self/oom_score_adj", O_WRONLY | O_CLOEXEC); - if (oom_score_adj_fd != -1) { - const char* oom_score_adj_value = "-950"; - TEMP_FAILURE_RETRY( - adb_write(oom_score_adj_fd, oom_score_adj_value, strlen(oom_score_adj_value))); - } - -#ifdef __ANDROID_RECOVERY__ - // Special routine for recovery. Switch to shell domain when adbd is - // is running with dropped privileged (i.e. not running as root) and - // is built for the recovery mode. This is required because recovery - // rootfs is not labeled and everything is labeled just as rootfs. - char* con = nullptr; - if (getcon(&con) == 0) { - if (!strcmp(con, "u:r:adbd:s0")) { - if (selinux_android_setcon("u:r:shell:s0") < 0) { - LOG(FATAL) << "Could not set SELinux context for subprocess"; - } - } - freecon(con); - } else { - LOG(FATAL) << "Failed to get SELinux context"; - } -#endif - - if (command_.empty()) { - // Spawn a login shell if we don't have a command. - execle(_PATH_BSHELL, "-" _PATH_BSHELL, nullptr, cenv.data()); - } else { - execle(_PATH_BSHELL, _PATH_BSHELL, "-c", command_.c_str(), nullptr, cenv.data()); - } - WriteFdExactly(child_error_sfd, "exec '" _PATH_BSHELL "' failed: "); - WriteFdExactly(child_error_sfd, strerror(errno)); - child_error_sfd.reset(-1); - _Exit(1); - } - - // Subprocess parent. - D("subprocess parent: stdin/stdout FD = %d, stderr FD = %d", - stdinout_sfd_.get(), stderr_sfd_.get()); - - // Wait to make sure the subprocess exec'd without error. - child_error_sfd.reset(-1); - std::string error_message = ReadAll(parent_error_sfd); - if (!error_message.empty()) { - *error = error_message; - return false; - } - - D("subprocess parent: exec completed"); - if (!ConnectProtocolEndpoints(error)) { - kill(pid_, SIGKILL); - return false; - } - - D("subprocess parent: completed"); - return true; -} - -bool Subprocess::ExecInProcess(Command command, std::string* _Nonnull error) { - unique_fd child_stdinout_sfd, child_stderr_sfd; - - CHECK(type_ == SubprocessType::kRaw); - - __android_log_security_bswrite(SEC_TAG_ADB_SHELL_CMD, command_.c_str()); - - if (!CreateSocketpair(&stdinout_sfd_, &child_stdinout_sfd)) { - *error = android::base::StringPrintf("failed to create socketpair for stdin/out: %s", - strerror(errno)); - return false; - } - if (protocol_ == SubprocessProtocol::kShell) { - // Shell protocol allows for splitting stderr. - if (!CreateSocketpair(&stderr_sfd_, &child_stderr_sfd)) { - *error = android::base::StringPrintf("failed to create socketpair for stderr: %s", - strerror(errno)); - return false; - } - } else { - // Raw protocol doesn't support multiple output streams, so combine stdout and stderr. - child_stderr_sfd.reset(dup(child_stdinout_sfd.get())); - } - - D("execinprocess: stdin/stdout FD = %d, stderr FD = %d", stdinout_sfd_.get(), - stderr_sfd_.get()); - - if (!ConnectProtocolEndpoints(error)) { - return false; - } - - std::thread([inout_sfd = std::move(child_stdinout_sfd), err_sfd = std::move(child_stderr_sfd), - command = std::move(command), - args = command_]() { command(args, inout_sfd, inout_sfd, err_sfd); }) - .detach(); - - D("execinprocess: completed"); - return true; -} - -bool Subprocess::ConnectProtocolEndpoints(std::string* _Nonnull error) { - if (protocol_ == SubprocessProtocol::kNone) { - // No protocol: all streams pass through the stdinout FD and hook - // directly into the local socket for raw data transfer. - local_socket_sfd_.reset(stdinout_sfd_.release()); - } else { - // Required for shell protocol: create another socketpair to intercept data. - if (!CreateSocketpair(&protocol_sfd_, &local_socket_sfd_)) { - *error = android::base::StringPrintf( - "failed to create socketpair to intercept data: %s", strerror(errno)); - return false; - } - D("protocol FD = %d", protocol_sfd_.get()); - - input_ = std::make_unique(protocol_sfd_); - output_ = std::make_unique(protocol_sfd_); - if (!input_ || !output_) { - *error = "failed to allocate shell protocol objects"; - return false; - } - - // Don't let reads/writes to the subprocess block our thread. This isn't - // likely but could happen under unusual circumstances, such as if we - // write a ton of data to stdin but the subprocess never reads it and - // the pipe fills up. - for (int fd : {stdinout_sfd_.get(), stderr_sfd_.get()}) { - if (fd >= 0) { - if (!set_file_block_mode(fd, false)) { - *error = android::base::StringPrintf( - "failed to set non-blocking mode for fd %d", fd); - return false; - } - } - } - } - - return true; -} - -bool Subprocess::StartThread(std::unique_ptr subprocess, std::string* error) { - Subprocess* raw = subprocess.release(); - std::thread(ThreadHandler, raw).detach(); - - return true; -} - -int Subprocess::OpenPtyChildFd(const char* pts_name, unique_fd* error_sfd) { - int child_fd = adb_open(pts_name, O_RDWR | O_CLOEXEC); - if (child_fd == -1) { - // Don't use WriteFdFmt; since we're in the fork() child we don't want - // to allocate any heap memory to avoid race conditions. - const char* messages[] = {"child failed to open pseudo-term slave ", - pts_name, ": ", strerror(errno)}; - for (const char* message : messages) { - WriteFdExactly(*error_sfd, message); - } - abort(); - } - - if (make_pty_raw_) { - termios tattr; - if (tcgetattr(child_fd, &tattr) == -1) { - int saved_errno = errno; - WriteFdExactly(*error_sfd, "tcgetattr failed: "); - WriteFdExactly(*error_sfd, strerror(saved_errno)); - abort(); - } - - cfmakeraw(&tattr); - if (tcsetattr(child_fd, TCSADRAIN, &tattr) == -1) { - int saved_errno = errno; - WriteFdExactly(*error_sfd, "tcsetattr failed: "); - WriteFdExactly(*error_sfd, strerror(saved_errno)); - abort(); - } - } - - return child_fd; -} - -void Subprocess::ThreadHandler(void* userdata) { - Subprocess* subprocess = reinterpret_cast(userdata); - - adb_thread_setname(android::base::StringPrintf("shell svc %d", subprocess->pid())); - - D("passing data streams for PID %d", subprocess->pid()); - subprocess->PassDataStreams(); - - D("deleting Subprocess for PID %d", subprocess->pid()); - delete subprocess; -} - -void Subprocess::PassDataStreams() { - if (protocol_sfd_ == -1) { - return; - } - - // Start by trying to read from the protocol FD, stdout, and stderr. - SubprocessPollfds pfds; - pfds.stdinout_pfd() = {.fd = stdinout_sfd_.get(), .events = POLLIN}; - pfds.stderr_pfd() = {.fd = stderr_sfd_.get(), .events = POLLIN}; - pfds.protocol_pfd() = {.fd = protocol_sfd_.get(), .events = POLLIN}; - - // Pass data until the protocol FD or both the subprocess pipes die, at - // which point we can't pass any more data. - while (protocol_sfd_ != -1 && (stdinout_sfd_ != -1 || stderr_sfd_ != -1)) { - unique_fd* dead_sfd = PollLoop(&pfds); - if (dead_sfd) { - D("closing FD %d", dead_sfd->get()); - auto it = std::find_if(pfds.begin(), pfds.end(), [=](const adb_pollfd& pfd) { - return pfd.fd == dead_sfd->get(); - }); - CHECK(it != pfds.end()); - it->fd = -1; - it->events = 0; - if (dead_sfd == &protocol_sfd_) { - // Using SIGHUP is a decent general way to indicate that the - // controlling process is going away. If specific signals are - // needed (e.g. SIGINT), pass those through the shell protocol - // and only fall back on this for unexpected closures. - D("protocol FD died, sending SIGHUP to pid %d", pid_); - if (pid_ != -1) { - kill(pid_, SIGHUP); - } - - // We also need to close the pipes connected to the child process - // so that if it ignores SIGHUP and continues to write data it - // won't fill up the pipe and block. - stdinout_sfd_.reset(); - stderr_sfd_.reset(); - } - dead_sfd->reset(); - } - } -} - -unique_fd* Subprocess::PollLoop(SubprocessPollfds* pfds) { - unique_fd* dead_sfd = nullptr; - adb_pollfd& stdinout_pfd = pfds->stdinout_pfd(); - adb_pollfd& stderr_pfd = pfds->stderr_pfd(); - adb_pollfd& protocol_pfd = pfds->protocol_pfd(); - - // Keep calling poll() and passing data until an FD closes/errors. - while (!dead_sfd) { - if (adb_poll(pfds->data(), pfds->size(), -1) < 0) { - if (errno == EINTR) { - continue; - } else { - PLOG(ERROR) << "poll failed, closing subprocess pipes"; - stdinout_sfd_.reset(-1); - stderr_sfd_.reset(-1); - return nullptr; - } - } - - // Read stdout, write to protocol FD. - if (stdinout_pfd.fd != -1 && (stdinout_pfd.revents & POLLIN)) { - dead_sfd = PassOutput(&stdinout_sfd_, ShellProtocol::kIdStdout); - } - - // Read stderr, write to protocol FD. - if (!dead_sfd && stderr_pfd.fd != 1 && (stderr_pfd.revents & POLLIN)) { - dead_sfd = PassOutput(&stderr_sfd_, ShellProtocol::kIdStderr); - } - - // Read protocol FD, write to stdin. - if (!dead_sfd && protocol_pfd.fd != -1 && (protocol_pfd.revents & POLLIN)) { - dead_sfd = PassInput(); - // If we didn't finish writing, block on stdin write. - if (input_bytes_left_) { - protocol_pfd.events &= ~POLLIN; - stdinout_pfd.events |= POLLOUT; - } - } - - // Continue writing to stdin; only happens if a previous write blocked. - if (!dead_sfd && stdinout_pfd.fd != -1 && (stdinout_pfd.revents & POLLOUT)) { - dead_sfd = PassInput(); - // If we finished writing, go back to blocking on protocol read. - if (!input_bytes_left_) { - protocol_pfd.events |= POLLIN; - stdinout_pfd.events &= ~POLLOUT; - } - } - - // After handling all of the events we've received, check to see if any fds have died. - if (stdinout_pfd.revents & (POLLHUP | POLLRDHUP | POLLERR | POLLNVAL)) { - return &stdinout_sfd_; - } - - if (stderr_pfd.revents & (POLLHUP | POLLRDHUP | POLLERR | POLLNVAL)) { - return &stderr_sfd_; - } - - if (protocol_pfd.revents & (POLLHUP | POLLRDHUP | POLLERR | POLLNVAL)) { - return &protocol_sfd_; - } - } // while (!dead_sfd) - - return dead_sfd; -} - -unique_fd* Subprocess::PassInput() { - // Only read a new packet if we've finished writing the last one. - if (!input_bytes_left_) { - if (!input_->Read()) { - // Read() uses ReadFdExactly() which sets errno to 0 on EOF. - if (errno != 0) { - PLOG(ERROR) << "error reading protocol FD " << protocol_sfd_.get(); - } - return &protocol_sfd_; - } - - if (stdinout_sfd_ != -1) { - switch (input_->id()) { - case ShellProtocol::kIdWindowSizeChange: - int rows, cols, x_pixels, y_pixels; - if (sscanf(input_->data(), "%dx%d,%dx%d", - &rows, &cols, &x_pixels, &y_pixels) == 4) { - winsize ws; - ws.ws_row = rows; - ws.ws_col = cols; - ws.ws_xpixel = x_pixels; - ws.ws_ypixel = y_pixels; - ioctl(stdinout_sfd_.get(), TIOCSWINSZ, &ws); - } - break; - case ShellProtocol::kIdStdin: - input_bytes_left_ = input_->data_length(); - break; - case ShellProtocol::kIdCloseStdin: - if (type_ == SubprocessType::kRaw) { - if (adb_shutdown(stdinout_sfd_, SHUT_WR) == 0) { - return nullptr; - } - PLOG(ERROR) << "failed to shutdown writes to FD " << stdinout_sfd_.get(); - return &stdinout_sfd_; - } else { - // PTYs can't close just input, so rather than close the - // FD and risk losing subprocess output, leave it open. - // This only happens if the client starts a PTY shell - // non-interactively which is rare and unsupported. - // If necessary, the client can manually close the shell - // with `exit` or by killing the adb client process. - D("can't close input for PTY FD %d", stdinout_sfd_.get()); - } - break; - } - } - } - - if (input_bytes_left_ > 0) { - int index = input_->data_length() - input_bytes_left_; - int bytes = adb_write(stdinout_sfd_, input_->data() + index, input_bytes_left_); - if (bytes == 0 || (bytes < 0 && errno != EAGAIN)) { - if (bytes < 0) { - PLOG(ERROR) << "error reading stdin FD " << stdinout_sfd_.get(); - } - // stdin is done, mark this packet as finished and we'll just start - // dumping any further data received from the protocol FD. - input_bytes_left_ = 0; - return &stdinout_sfd_; - } else if (bytes > 0) { - input_bytes_left_ -= bytes; - } - } - - return nullptr; -} - -unique_fd* Subprocess::PassOutput(unique_fd* sfd, ShellProtocol::Id id) { - int bytes = adb_read(*sfd, output_->data(), output_->data_capacity()); - if (bytes == 0 || (bytes < 0 && errno != EAGAIN)) { - // read() returns EIO if a PTY closes; don't report this as an error, - // it just means the subprocess completed. - if (bytes < 0 && !(type_ == SubprocessType::kPty && errno == EIO)) { - PLOG(ERROR) << "error reading output FD " << sfd->get(); - } - return sfd; - } - - if (bytes > 0 && !output_->Write(id, bytes)) { - if (errno != 0) { - PLOG(ERROR) << "error reading protocol FD " << protocol_sfd_.get(); - } - return &protocol_sfd_; - } - - return nullptr; -} - -void Subprocess::WaitForExit() { - int exit_code = 1; - - D("waiting for pid %d", pid_); - while (pid_ != -1) { - int status; - if (pid_ == waitpid(pid_, &status, 0)) { - D("post waitpid (pid=%d) status=%04x", pid_, status); - if (WIFSIGNALED(status)) { - exit_code = 0x80 | WTERMSIG(status); - ADB_LOG(Shell) << "subprocess " << pid_ << " killed by signal " << WTERMSIG(status); - break; - } else if (!WIFEXITED(status)) { - D("subprocess didn't exit"); - break; - } else if (WEXITSTATUS(status) >= 0) { - exit_code = WEXITSTATUS(status); - ADB_LOG(Shell) << "subprocess " << pid_ << " exited with status " << exit_code; - break; - } - } - } - - // If we have an open protocol FD send an exit packet. - if (protocol_sfd_ != -1) { - output_->data()[0] = exit_code; - if (output_->Write(ShellProtocol::kIdExit, 1)) { - D("wrote the exit code packet: %d", exit_code); - } else { - PLOG(ERROR) << "failed to write the exit code packet"; - } - protocol_sfd_.reset(-1); - } -} - -} // namespace - -// Create a pipe containing the error. -unique_fd ReportError(SubprocessProtocol protocol, const std::string& message) { - unique_fd read, write; - if (!Pipe(&read, &write)) { - PLOG(ERROR) << "failed to create pipe to report error"; - return unique_fd{}; - } - - std::string buf = android::base::StringPrintf("error: %s\n", message.c_str()); - if (protocol == SubprocessProtocol::kShell) { - ShellProtocol::Id id = ShellProtocol::kIdStderr; - uint32_t length = buf.length(); - WriteFdExactly(write.get(), &id, sizeof(id)); - WriteFdExactly(write.get(), &length, sizeof(length)); - } - - WriteFdExactly(write.get(), buf.data(), buf.length()); - - if (protocol == SubprocessProtocol::kShell) { - ShellProtocol::Id id = ShellProtocol::kIdExit; - uint32_t length = 1; - char exit_code = 126; - WriteFdExactly(write.get(), &id, sizeof(id)); - WriteFdExactly(write.get(), &length, sizeof(length)); - WriteFdExactly(write.get(), &exit_code, sizeof(exit_code)); - } - - return read; -} - -unique_fd StartSubprocess(std::string name, const char* terminal_type, SubprocessType type, - SubprocessProtocol protocol) { - // If we aren't using the shell protocol we must allocate a PTY to properly close the - // subprocess. PTYs automatically send SIGHUP to the slave-side process when the master side - // of the PTY closes, which we rely on. If we use a raw pipe, processes that don't read/write, - // e.g. screenrecord, will never notice the broken pipe and terminate. - // The shell protocol doesn't require a PTY because it's always monitoring the local socket FD - // with select() and will send SIGHUP manually to the child process. - bool make_pty_raw = false; - if (protocol == SubprocessProtocol::kNone && type == SubprocessType::kRaw) { - // Disable PTY input/output processing since the client is expecting raw data. - D("Can't create raw subprocess without shell protocol, using PTY in raw mode instead"); - type = SubprocessType::kPty; - make_pty_raw = true; - } - - unique_fd error_fd; - unique_fd fd = StartSubprocess(std::move(name), terminal_type, type, protocol, make_pty_raw, - protocol, &error_fd); - if (fd == -1) { - return error_fd; - } - return fd; -} - -unique_fd StartSubprocess(std::string name, const char* terminal_type, SubprocessType type, - SubprocessProtocol protocol, bool make_pty_raw, - SubprocessProtocol error_protocol, unique_fd* error_fd) { - D("starting %s subprocess (protocol=%s, TERM=%s): '%s'", - type == SubprocessType::kRaw ? "raw" : "PTY", - protocol == SubprocessProtocol::kNone ? "none" : "shell", terminal_type, name.c_str()); - - auto subprocess = std::make_unique(std::move(name), terminal_type, type, protocol, - make_pty_raw); - if (!subprocess) { - LOG(ERROR) << "failed to allocate new subprocess"; - *error_fd = ReportError(error_protocol, "failed to allocate new subprocess"); - return {}; - } - - std::string error; - if (!subprocess->ForkAndExec(&error)) { - LOG(ERROR) << "failed to start subprocess: " << error; - *error_fd = ReportError(error_protocol, error); - return {}; - } - - unique_fd local_socket(subprocess->ReleaseLocalSocket()); - D("subprocess creation successful: local_socket_fd=%d, pid=%d", local_socket.get(), - subprocess->pid()); - - if (!Subprocess::StartThread(std::move(subprocess), &error)) { - LOG(ERROR) << "failed to start subprocess management thread: " << error; - *error_fd = ReportError(error_protocol, error); - return {}; - } - - return local_socket; -} - -unique_fd StartCommandInProcess(std::string name, Command command, SubprocessProtocol protocol) { - LOG(INFO) << "StartCommandInProcess(" << dump_hex(name.data(), name.size()) << ")"; - - constexpr auto terminal_type = ""; - constexpr auto type = SubprocessType::kRaw; - constexpr auto make_pty_raw = false; - - auto subprocess = std::make_unique(std::move(name), terminal_type, type, protocol, - make_pty_raw); - if (!subprocess) { - LOG(ERROR) << "failed to allocate new subprocess"; - return ReportError(protocol, "failed to allocate new subprocess"); - } - - std::string error; - if (!subprocess->ExecInProcess(std::move(command), &error)) { - LOG(ERROR) << "failed to start subprocess: " << error; - return ReportError(protocol, error); - } - - unique_fd local_socket(subprocess->ReleaseLocalSocket()); - D("inprocess creation successful: local_socket_fd=%d, pid=%d", local_socket.get(), - subprocess->pid()); - - if (!Subprocess::StartThread(std::move(subprocess), &error)) { - LOG(ERROR) << "failed to start inprocess management thread: " << error; - return ReportError(protocol, error); - } - - return local_socket; -} diff --git a/adb/daemon/shell_service.h b/adb/daemon/shell_service.h deleted file mode 100644 index 030228c7f7ee43f85e998793df28256c2bba6c69..0000000000000000000000000000000000000000 --- a/adb/daemon/shell_service.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2018 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. - */ - -#pragma once - -#include - -#include "adb_unique_fd.h" - -#include - -enum class SubprocessType { - kPty, - kRaw, -}; - -enum class SubprocessProtocol { - kNone, - kShell, -}; - -// Forks and starts a new shell subprocess. If |name| is empty an interactive -// shell is started, otherwise |name| is executed non-interactively. -// -// Returns an open FD connected to the subprocess or -1 on failure. -unique_fd StartSubprocess(std::string name, const char* terminal_type, SubprocessType type, - SubprocessProtocol protocol); - -// The same as above but with more fined grained control and custom error handling. -unique_fd StartSubprocess(std::string name, const char* terminal_type, SubprocessType type, - SubprocessProtocol protocol, bool make_pty_raw, - SubprocessProtocol error_protocol, unique_fd* error_fd); - -// Executes |command| in a separate thread. -// Sets up in/out and error streams to emulate shell-like behavior. -// -// Returns an open FD connected to the thread or -1 on failure. -using Command = int(std::string_view args, borrowed_fd in, borrowed_fd out, borrowed_fd err); -unique_fd StartCommandInProcess(std::string name, Command command, SubprocessProtocol protocol); - -// Create a pipe containing the error. -unique_fd ReportError(SubprocessProtocol protocol, const std::string& message); diff --git a/adb/daemon/shell_service_test.cpp b/adb/daemon/shell_service_test.cpp deleted file mode 100644 index cdd8dbede1193c6f72913de245886983a2a01017..0000000000000000000000000000000000000000 --- a/adb/daemon/shell_service_test.cpp +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Copyright (C) 2015 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 "shell_service.h" - -#include - -#include - -#include -#include - -#include - -#include "adb.h" -#include "adb_io.h" -#include "shell_protocol.h" -#include "sysdeps.h" - -class ShellServiceTest : public ::testing::Test { - public: - static void SetUpTestCase() { - // This is normally done in main.cpp. - saved_sigpipe_handler_ = signal(SIGPIPE, SIG_IGN); - } - - static void TearDownTestCase() { - signal(SIGPIPE, saved_sigpipe_handler_); - } - - // Helpers to start and cleanup a subprocess. Cleanup normally does not - // need to be called manually unless multiple subprocesses are run from - // a single test. - void StartTestSubprocess(const char* command, SubprocessType type, - SubprocessProtocol protocol); - void CleanupTestSubprocess(); - - void StartTestCommandInProcess(std::string name, Command command, SubprocessProtocol protocol); - - virtual void TearDown() override { CleanupTestSubprocess(); } - - static sighandler_t saved_sigpipe_handler_; - - unique_fd command_fd_; -}; - -sighandler_t ShellServiceTest::saved_sigpipe_handler_ = nullptr; - -void ShellServiceTest::StartTestSubprocess( - const char* command, SubprocessType type, SubprocessProtocol protocol) { - command_fd_ = StartSubprocess(command, nullptr, type, protocol); - ASSERT_TRUE(command_fd_ >= 0); -} - -void ShellServiceTest::CleanupTestSubprocess() { -} - -void ShellServiceTest::StartTestCommandInProcess(std::string name, Command command, - SubprocessProtocol protocol) { - command_fd_ = StartCommandInProcess(std::move(name), std::move(command), protocol); - ASSERT_TRUE(command_fd_ >= 0); -} - -namespace { - -// Reads raw data from |fd| until it closes or errors. -std::string ReadRaw(borrowed_fd fd) { - char buffer[1024]; - char *cur_ptr = buffer, *end_ptr = buffer + sizeof(buffer); - - while (1) { - int bytes = adb_read(fd, cur_ptr, end_ptr - cur_ptr); - if (bytes <= 0) { - return std::string(buffer, cur_ptr); - } - cur_ptr += bytes; - } -} - -// Reads shell protocol data from |fd| until it closes or errors. Fills -// |stdout| and |stderr| with their respective data, and returns the exit code -// read from the protocol or -1 if an exit code packet was not received. -int ReadShellProtocol(borrowed_fd fd, std::string* stdout, std::string* stderr) { - int exit_code = -1; - stdout->clear(); - stderr->clear(); - - auto protocol = std::make_unique(fd.get()); - while (protocol->Read()) { - switch (protocol->id()) { - case ShellProtocol::kIdStdout: - stdout->append(protocol->data(), protocol->data_length()); - break; - case ShellProtocol::kIdStderr: - stderr->append(protocol->data(), protocol->data_length()); - break; - case ShellProtocol::kIdExit: - EXPECT_EQ(-1, exit_code) << "Multiple exit packets received"; - EXPECT_EQ(1u, protocol->data_length()); - exit_code = protocol->data()[0]; - break; - default: - ADD_FAILURE() << "Unidentified packet ID: " << protocol->id(); - } - } - - return exit_code; -} - -// Checks if each line in |lines| exists in the same order in |output|. Blank -// lines in |output| are ignored for simplicity. -bool ExpectLinesEqual(const std::string& output, - const std::vector& lines) { - auto output_lines = android::base::Split(output, "\r\n"); - size_t i = 0; - - for (const std::string& line : lines) { - // Skip empty lines in output. - while (i < output_lines.size() && output_lines[i].empty()) { - ++i; - } - if (i >= output_lines.size()) { - ADD_FAILURE() << "Ran out of output lines"; - return false; - } - EXPECT_EQ(line, output_lines[i]); - ++i; - } - - while (i < output_lines.size() && output_lines[i].empty()) { - ++i; - } - EXPECT_EQ(i, output_lines.size()) << "Found unmatched output lines"; - return true; -} - -} // namespace - -// Tests a raw subprocess with no protocol. -TEST_F(ShellServiceTest, RawNoProtocolSubprocess) { - // [ -t 0 ] checks if stdin is connected to a terminal. - ASSERT_NO_FATAL_FAILURE(StartTestSubprocess( - "echo foo; echo bar >&2; [ -t 0 ]; echo $?", - SubprocessType::kRaw, SubprocessProtocol::kNone)); - - // [ -t 0 ] == 0 means we have a terminal (PTY). Even when requesting a raw subprocess, without - // the shell protocol we should always force a PTY to ensure proper cleanup. - ExpectLinesEqual(ReadRaw(command_fd_), {"foo", "bar", "0"}); -} - -// Tests a PTY subprocess with no protocol. -TEST_F(ShellServiceTest, PtyNoProtocolSubprocess) { - // [ -t 0 ] checks if stdin is connected to a terminal. - ASSERT_NO_FATAL_FAILURE(StartTestSubprocess( - "echo foo; echo bar >&2; [ -t 0 ]; echo $?", - SubprocessType::kPty, SubprocessProtocol::kNone)); - - // [ -t 0 ] == 0 means we have a terminal (PTY). - ExpectLinesEqual(ReadRaw(command_fd_), {"foo", "bar", "0"}); -} - -// Tests a raw subprocess with the shell protocol. -TEST_F(ShellServiceTest, RawShellProtocolSubprocess) { - ASSERT_NO_FATAL_FAILURE(StartTestSubprocess( - "echo foo; echo bar >&2; echo baz; exit 24", - SubprocessType::kRaw, SubprocessProtocol::kShell)); - - std::string stdout, stderr; - EXPECT_EQ(24, ReadShellProtocol(command_fd_, &stdout, &stderr)); - ExpectLinesEqual(stdout, {"foo", "baz"}); - ExpectLinesEqual(stderr, {"bar"}); -} - -// Tests a PTY subprocess with the shell protocol. -TEST_F(ShellServiceTest, PtyShellProtocolSubprocess) { - ASSERT_NO_FATAL_FAILURE(StartTestSubprocess( - "echo foo; echo bar >&2; echo baz; exit 50", - SubprocessType::kPty, SubprocessProtocol::kShell)); - - // PTY always combines stdout and stderr but the shell protocol should - // still give us an exit code. - std::string stdout, stderr; - EXPECT_EQ(50, ReadShellProtocol(command_fd_, &stdout, &stderr)); - ExpectLinesEqual(stdout, {"foo", "bar", "baz"}); - ExpectLinesEqual(stderr, {}); -} - -// Tests an interactive PTY session. -TEST_F(ShellServiceTest, InteractivePtySubprocess) { - ASSERT_NO_FATAL_FAILURE(StartTestSubprocess( - "", SubprocessType::kPty, SubprocessProtocol::kShell)); - - // Use variable substitution so echoed input is different from output. - const char* commands[] = {"TEST_STR=abc123", - "echo --${TEST_STR}--", - "exit"}; - - ShellProtocol* protocol = new ShellProtocol(command_fd_); - for (std::string command : commands) { - // Interactive shell requires a newline to complete each command. - command.push_back('\n'); - memcpy(protocol->data(), command.data(), command.length()); - ASSERT_TRUE(protocol->Write(ShellProtocol::kIdStdin, command.length())); - } - delete protocol; - - std::string stdout, stderr; - EXPECT_EQ(0, ReadShellProtocol(command_fd_, &stdout, &stderr)); - // An unpredictable command prompt makes parsing exact output difficult but - // it should at least contain echoed input and the expected output. - for (const char* command : commands) { - EXPECT_FALSE(stdout.find(command) == std::string::npos); - } - EXPECT_FALSE(stdout.find("--abc123--") == std::string::npos); -} - -// Tests closing raw subprocess stdin. -TEST_F(ShellServiceTest, CloseClientStdin) { - ASSERT_NO_FATAL_FAILURE(StartTestSubprocess( - "cat; echo TEST_DONE", - SubprocessType::kRaw, SubprocessProtocol::kShell)); - - std::string input = "foo\nbar"; - ShellProtocol* protocol = new ShellProtocol(command_fd_); - memcpy(protocol->data(), input.data(), input.length()); - ASSERT_TRUE(protocol->Write(ShellProtocol::kIdStdin, input.length())); - ASSERT_TRUE(protocol->Write(ShellProtocol::kIdCloseStdin, 0)); - delete protocol; - - std::string stdout, stderr; - EXPECT_EQ(0, ReadShellProtocol(command_fd_, &stdout, &stderr)); - ExpectLinesEqual(stdout, {"foo", "barTEST_DONE"}); - ExpectLinesEqual(stderr, {}); -} - -// Tests that nothing breaks when the stdin/stdout pipe closes. -TEST_F(ShellServiceTest, CloseStdinStdoutSubprocess) { - ASSERT_NO_FATAL_FAILURE(StartTestSubprocess( - "exec 0<&-; exec 1>&-; echo bar >&2", - SubprocessType::kRaw, SubprocessProtocol::kShell)); - - std::string stdout, stderr; - EXPECT_EQ(0, ReadShellProtocol(command_fd_, &stdout, &stderr)); - ExpectLinesEqual(stdout, {}); - ExpectLinesEqual(stderr, {"bar"}); -} - -// Tests that nothing breaks when the stderr pipe closes. -TEST_F(ShellServiceTest, CloseStderrSubprocess) { - ASSERT_NO_FATAL_FAILURE(StartTestSubprocess( - "exec 2>&-; echo foo", - SubprocessType::kRaw, SubprocessProtocol::kShell)); - - std::string stdout, stderr; - EXPECT_EQ(0, ReadShellProtocol(command_fd_, &stdout, &stderr)); - ExpectLinesEqual(stdout, {"foo"}); - ExpectLinesEqual(stderr, {}); -} - -// Tests an inprocess command with no protocol. -TEST_F(ShellServiceTest, RawNoProtocolInprocess) { - ASSERT_NO_FATAL_FAILURE( - StartTestCommandInProcess("123", - [](auto args, auto in, auto out, auto err) -> int { - EXPECT_EQ("123", args); - char input[10]; - EXPECT_TRUE(ReadFdExactly(in, input, 2)); - input[2] = 0; - EXPECT_STREQ("in", input); - WriteFdExactly(out, "out\n"); - WriteFdExactly(err, "err\n"); - return 0; - }, - SubprocessProtocol::kNone)); - - WriteFdExactly(command_fd_, "in"); - ExpectLinesEqual(ReadRaw(command_fd_), {"out", "err"}); -} - -// Tests an inprocess command with the shell protocol. -TEST_F(ShellServiceTest, RawShellProtocolInprocess) { - ASSERT_NO_FATAL_FAILURE( - StartTestCommandInProcess("321", - [](auto args, auto in, auto out, auto err) -> int { - EXPECT_EQ("321", args); - char input[10]; - EXPECT_TRUE(ReadFdExactly(in, input, 2)); - input[2] = 0; - EXPECT_STREQ("in", input); - WriteFdExactly(out, "out\n"); - WriteFdExactly(err, "err\n"); - return 0; - }, - SubprocessProtocol::kShell)); - - { - auto write_protocol = std::make_unique(command_fd_); - memcpy(write_protocol->data(), "in", 2); - write_protocol->Write(ShellProtocol::kIdStdin, 2); - } - - std::string stdout, stderr; - // For in-process commands the exit code is always the default (1). - EXPECT_EQ(1, ReadShellProtocol(command_fd_, &stdout, &stderr)); - ExpectLinesEqual(stdout, {"out"}); - ExpectLinesEqual(stderr, {"err"}); -} diff --git a/adb/daemon/transport_qemu.cpp b/adb/daemon/transport_qemu.cpp deleted file mode 100644 index e458cea7ea6cd1ba2055415f2c7e178dad62a992..0000000000000000000000000000000000000000 --- a/adb/daemon/transport_qemu.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2019 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 qemu_pipe.h before sysdeps, since it has inlined references to open, read, write. -#include - -#define TRACE_TAG TRANSPORT -#include "socket_spec.h" -#include "sysdeps.h" -#include "transport.h" - -#include - -#include "adb_io.h" -#include "adb_trace.h" -#include "adb_unique_fd.h" - -/* 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. - */ -void qemu_socket_thread(std::string_view addr) { - /* '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"; - - char tmp[256]; - char con_name[32]; - - adb_thread_setname("qemu socket"); - D("transport: qemu_socket_thread() starting"); - - std::string error; - int port = get_host_socket_spec_port(addr, &error); - if (port == -1) { - port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT; - } - - /* adb QEMUD service connection request. */ - snprintf(con_name, sizeof(con_name), "pipe:qemud:adb:%d", port); - - /* Connect to the adb QEMUD service. */ - unique_fd 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. */ - D("adb service is not available. Falling back to TCP socket."); - std::thread(server_socket_thread, adb_listen, addr).detach(); - return; - } - - while (true) { - /* - * Wait till the host creates a new connection. - */ - - /* Send the 'accept' request. */ - if (WriteFdExactly(fd.get(), _accept_req, strlen(_accept_req))) { - /* Wait for the response. In the response we expect 'ok' on success, - * or 'ko' on failure. */ - if (!ReadFdExactly(fd.get(), tmp, 2) || memcmp(tmp, _ok_resp, 2)) { - D("Accepting ADB host connection has failed."); - } else { - /* Host is connected. Register the transport, and start the - * exchange. */ - std::string serial = android::base::StringPrintf("host-%d", fd.get()); - WriteFdExactly(fd.get(), _start_req, strlen(_start_req)); - register_socket_transport( - std::move(fd), std::move(serial), port, 1, - [](atransport*) { return ReconnectResult::Abort; }, false); - } - - /* Prepare for accepting of the next ADB host connection. */ - fd.reset(qemu_pipe_open(con_name)); - if (fd < 0) { - D("adb service become unavailable."); - return; - } - } else { - D("Unable to send the '%s' request to ADB service.", _accept_req); - return; - } - } - D("transport: qemu_socket_thread() exiting"); - return; -} - -// If adbd is running inside the emulator, it will normally use QEMUD pipe (aka -// goldfish) as the transport. This can either be explicitly set by the -// service.adb.transport property, or be inferred from ro.kernel.qemu that is -// set to "1" for ranchu/goldfish. -bool use_qemu_goldfish() { - // Legacy way to detect if adbd should use the goldfish pipe is to check for - // ro.kernel.qemu, keep that behaviour for backward compatibility. - if (android::base::GetBoolProperty("ro.kernel.qemu", false)) { - return true; - } - // If service.adb.transport is present and is set to "goldfish", use the - // QEMUD pipe. - if (android::base::GetProperty("service.adb.transport", "") == "goldfish") { - return true; - } - return false; -} diff --git a/adb/daemon/usb.cpp b/adb/daemon/usb.cpp deleted file mode 100644 index 50d73644d4696cae3688f0337ddb4d82533a51c5..0000000000000000000000000000000000000000 --- a/adb/daemon/usb.cpp +++ /dev/null @@ -1,766 +0,0 @@ -/* - * Copyright (C) 2018 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 USB - -#include "sysdeps.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include "adb_unique_fd.h" -#include "adb_utils.h" -#include "daemon/usb_ffs.h" -#include "sysdeps/chrono.h" -#include "transport.h" -#include "types.h" - -using android::base::StringPrintf; - -// Not all USB controllers support operations larger than 16k, so don't go above that. -// Also, each submitted operation does an allocation in the kernel of that size, so we want to -// minimize our queue depth while still maintaining a deep enough queue to keep the USB stack fed. -static constexpr size_t kUsbReadQueueDepth = 8; -static constexpr size_t kUsbReadSize = 4 * PAGE_SIZE; - -static constexpr size_t kUsbWriteQueueDepth = 8; -static constexpr size_t kUsbWriteSize = 4 * PAGE_SIZE; - -static const char* to_string(enum usb_functionfs_event_type type) { - switch (type) { - case FUNCTIONFS_BIND: - return "FUNCTIONFS_BIND"; - case FUNCTIONFS_UNBIND: - return "FUNCTIONFS_UNBIND"; - case FUNCTIONFS_ENABLE: - return "FUNCTIONFS_ENABLE"; - case FUNCTIONFS_DISABLE: - return "FUNCTIONFS_DISABLE"; - case FUNCTIONFS_SETUP: - return "FUNCTIONFS_SETUP"; - case FUNCTIONFS_SUSPEND: - return "FUNCTIONFS_SUSPEND"; - case FUNCTIONFS_RESUME: - return "FUNCTIONFS_RESUME"; - } -} - -enum class TransferDirection : uint64_t { - READ = 0, - WRITE = 1, -}; - -struct TransferId { - TransferDirection direction : 1; - uint64_t id : 63; - - TransferId() : TransferId(TransferDirection::READ, 0) {} - - private: - TransferId(TransferDirection direction, uint64_t id) : direction(direction), id(id) {} - - public: - explicit operator uint64_t() const { - uint64_t result; - static_assert(sizeof(*this) == sizeof(result)); - memcpy(&result, this, sizeof(*this)); - return result; - } - - static TransferId read(uint64_t id) { return TransferId(TransferDirection::READ, id); } - static TransferId write(uint64_t id) { return TransferId(TransferDirection::WRITE, id); } - - static TransferId from_value(uint64_t value) { - TransferId result; - memcpy(&result, &value, sizeof(value)); - return result; - } -}; - -template -struct IoBlock { - bool pending = false; - struct iocb control = {}; - Payload payload; - - TransferId id() const { return TransferId::from_value(control.aio_data); } -}; - -using IoReadBlock = IoBlock; -using IoWriteBlock = IoBlock>; - -struct ScopedAioContext { - ScopedAioContext() = default; - ~ScopedAioContext() { reset(); } - - ScopedAioContext(ScopedAioContext&& move) { reset(move.release()); } - ScopedAioContext(const ScopedAioContext& copy) = delete; - - ScopedAioContext& operator=(ScopedAioContext&& move) { - reset(move.release()); - return *this; - } - ScopedAioContext& operator=(const ScopedAioContext& copy) = delete; - - static ScopedAioContext Create(size_t max_events) { - aio_context_t ctx = 0; - if (io_setup(max_events, &ctx) != 0) { - PLOG(FATAL) << "failed to create aio_context_t"; - } - ScopedAioContext result; - result.reset(ctx); - return result; - } - - aio_context_t release() { - aio_context_t result = context_; - context_ = 0; - return result; - } - - void reset(aio_context_t new_context = 0) { - if (context_ != 0) { - io_destroy(context_); - } - - context_ = new_context; - } - - aio_context_t get() { return context_; } - - private: - aio_context_t context_ = 0; -}; - -struct UsbFfsConnection : public Connection { - UsbFfsConnection(unique_fd control, unique_fd read, unique_fd write, - std::promise destruction_notifier) - : worker_started_(false), - stopped_(false), - destruction_notifier_(std::move(destruction_notifier)), - control_fd_(std::move(control)), - read_fd_(std::move(read)), - write_fd_(std::move(write)) { - LOG(INFO) << "UsbFfsConnection constructed"; - worker_event_fd_.reset(eventfd(0, EFD_CLOEXEC)); - if (worker_event_fd_ == -1) { - PLOG(FATAL) << "failed to create eventfd"; - } - - monitor_event_fd_.reset(eventfd(0, EFD_CLOEXEC)); - if (monitor_event_fd_ == -1) { - PLOG(FATAL) << "failed to create eventfd"; - } - - aio_context_ = ScopedAioContext::Create(kUsbReadQueueDepth + kUsbWriteQueueDepth); - } - - ~UsbFfsConnection() { - LOG(INFO) << "UsbFfsConnection being destroyed"; - Stop(); - monitor_thread_.join(); - - // We need to explicitly close our file descriptors before we notify our destruction, - // because the thread listening on the future will immediately try to reopen the endpoint. - aio_context_.reset(); - control_fd_.reset(); - read_fd_.reset(); - write_fd_.reset(); - - destruction_notifier_.set_value(); - } - - virtual bool Write(std::unique_ptr packet) override final { - LOG(DEBUG) << "USB write: " << dump_header(&packet->msg); - auto header = std::make_shared(sizeof(packet->msg)); - memcpy(header->data(), &packet->msg, sizeof(packet->msg)); - - std::lock_guard lock(write_mutex_); - write_requests_.push_back( - CreateWriteBlock(std::move(header), 0, sizeof(packet->msg), next_write_id_++)); - if (!packet->payload.empty()) { - // The kernel attempts to allocate a contiguous block of memory for each write, - // which can fail if the write is large and the kernel heap is fragmented. - // Split large writes into smaller chunks to avoid this. - auto payload = std::make_shared(std::move(packet->payload)); - size_t offset = 0; - size_t len = payload->size(); - - while (len > 0) { - size_t write_size = std::min(kUsbWriteSize, len); - write_requests_.push_back( - CreateWriteBlock(payload, offset, write_size, next_write_id_++)); - len -= write_size; - offset += write_size; - } - } - - // Wake up the worker thread to submit writes. - uint64_t notify = 1; - ssize_t rc = adb_write(worker_event_fd_.get(), ¬ify, sizeof(notify)); - if (rc < 0) { - PLOG(FATAL) << "failed to notify worker eventfd to submit writes"; - } - - return true; - } - - virtual void Start() override final { StartMonitor(); } - - virtual void Stop() override final { - if (stopped_.exchange(true)) { - return; - } - stopped_ = true; - uint64_t notify = 1; - ssize_t rc = adb_write(worker_event_fd_.get(), ¬ify, sizeof(notify)); - if (rc < 0) { - PLOG(FATAL) << "failed to notify worker eventfd to stop UsbFfsConnection"; - } - CHECK_EQ(static_cast(rc), sizeof(notify)); - - rc = adb_write(monitor_event_fd_.get(), ¬ify, sizeof(notify)); - if (rc < 0) { - PLOG(FATAL) << "failed to notify monitor eventfd to stop UsbFfsConnection"; - } - - CHECK_EQ(static_cast(rc), sizeof(notify)); - } - - virtual bool DoTlsHandshake(RSA* key, std::string* auth_key) override final { - // TODO: support TLS for usb connections. - LOG(FATAL) << "Not supported yet."; - return false; - } - - private: - void StartMonitor() { - // This is a bit of a mess. - // It's possible for io_submit to end up blocking, if we call it as the endpoint - // becomes disabled. Work around this by having a monitor thread to listen for functionfs - // lifecycle events. If we notice an error condition (either we've become disabled, or we - // were never enabled in the first place), we send interruption signals to the worker thread - // until it dies, and then report failure to the transport via HandleError, which will - // eventually result in the transport being destroyed, which will result in UsbFfsConnection - // being destroyed, which unblocks the open thread and restarts this entire process. - static std::once_flag handler_once; - std::call_once(handler_once, []() { signal(kInterruptionSignal, [](int) {}); }); - - monitor_thread_ = std::thread([this]() { - adb_thread_setname("UsbFfs-monitor"); - LOG(INFO) << "UsbFfs-monitor thread spawned"; - - bool bound = false; - bool enabled = false; - bool running = true; - while (running) { - adb_pollfd pfd[2] = { - { .fd = control_fd_.get(), .events = POLLIN, .revents = 0 }, - { .fd = monitor_event_fd_.get(), .events = POLLIN, .revents = 0 }, - }; - - // If we don't see our first bind within a second, try again. - int timeout_ms = bound ? -1 : 1000; - - int rc = TEMP_FAILURE_RETRY(adb_poll(pfd, 2, timeout_ms)); - if (rc == -1) { - PLOG(FATAL) << "poll on USB control fd failed"; - } else if (rc == 0) { - LOG(WARNING) << "timed out while waiting for FUNCTIONFS_BIND, trying again"; - break; - } - - if (pfd[1].revents) { - // We were told to die. - break; - } - - struct usb_functionfs_event event; - rc = TEMP_FAILURE_RETRY(adb_read(control_fd_.get(), &event, sizeof(event))); - if (rc == -1) { - PLOG(FATAL) << "failed to read functionfs event"; - } else if (rc == 0) { - LOG(WARNING) << "hit EOF on functionfs control fd"; - break; - } else if (rc != sizeof(event)) { - LOG(FATAL) << "read functionfs event of unexpected size, expected " - << sizeof(event) << ", got " << rc; - } - - LOG(INFO) << "USB event: " - << to_string(static_cast(event.type)); - - switch (event.type) { - case FUNCTIONFS_BIND: - if (bound) { - LOG(WARNING) << "received FUNCTIONFS_BIND while already bound?"; - running = false; - break; - } - - if (enabled) { - LOG(WARNING) << "received FUNCTIONFS_BIND while already enabled?"; - running = false; - break; - } - - bound = true; - break; - - case FUNCTIONFS_ENABLE: - if (!bound) { - LOG(WARNING) << "received FUNCTIONFS_ENABLE while not bound?"; - running = false; - break; - } - - if (enabled) { - LOG(WARNING) << "received FUNCTIONFS_ENABLE while already enabled?"; - running = false; - break; - } - - enabled = true; - StartWorker(); - break; - - case FUNCTIONFS_DISABLE: - if (!bound) { - LOG(WARNING) << "received FUNCTIONFS_DISABLE while not bound?"; - } - - if (!enabled) { - LOG(WARNING) << "received FUNCTIONFS_DISABLE while not enabled?"; - } - - enabled = false; - running = false; - break; - - case FUNCTIONFS_UNBIND: - if (enabled) { - LOG(WARNING) << "received FUNCTIONFS_UNBIND while still enabled?"; - } - - if (!bound) { - LOG(WARNING) << "received FUNCTIONFS_UNBIND when not bound?"; - } - - bound = false; - running = false; - break; - - case FUNCTIONFS_SETUP: { - LOG(INFO) << "received FUNCTIONFS_SETUP control transfer: bRequestType = " - << static_cast(event.u.setup.bRequestType) - << ", bRequest = " << static_cast(event.u.setup.bRequest) - << ", wValue = " << static_cast(event.u.setup.wValue) - << ", wIndex = " << static_cast(event.u.setup.wIndex) - << ", wLength = " << static_cast(event.u.setup.wLength); - - if ((event.u.setup.bRequestType & USB_DIR_IN)) { - LOG(INFO) << "acking device-to-host control transfer"; - ssize_t rc = adb_write(control_fd_.get(), "", 0); - if (rc != 0) { - PLOG(ERROR) << "failed to write empty packet to host"; - break; - } - } else { - std::string buf; - buf.resize(event.u.setup.wLength + 1); - - ssize_t rc = adb_read(control_fd_.get(), buf.data(), buf.size()); - if (rc != event.u.setup.wLength) { - LOG(ERROR) - << "read " << rc - << " bytes when trying to read control request, expected " - << event.u.setup.wLength; - } - - LOG(INFO) << "control request contents: " << buf; - break; - } - } - } - } - - StopWorker(); - HandleError("monitor thread finished"); - }); - } - - void StartWorker() { - CHECK(!worker_started_); - worker_started_ = true; - worker_thread_ = std::thread([this]() { - adb_thread_setname("UsbFfs-worker"); - LOG(INFO) << "UsbFfs-worker thread spawned"; - - for (size_t i = 0; i < kUsbReadQueueDepth; ++i) { - read_requests_[i] = CreateReadBlock(next_read_id_++); - if (!SubmitRead(&read_requests_[i])) { - return; - } - } - - while (!stopped_) { - uint64_t dummy; - ssize_t rc = adb_read(worker_event_fd_.get(), &dummy, sizeof(dummy)); - if (rc == -1) { - PLOG(FATAL) << "failed to read from eventfd"; - } else if (rc == 0) { - LOG(FATAL) << "hit EOF on eventfd"; - } - - ReadEvents(); - - std::lock_guard lock(write_mutex_); - SubmitWrites(); - } - }); - } - - void StopWorker() { - if (!worker_started_) { - return; - } - - pthread_t worker_thread_handle = worker_thread_.native_handle(); - while (true) { - int rc = pthread_kill(worker_thread_handle, kInterruptionSignal); - if (rc != 0) { - LOG(ERROR) << "failed to send interruption signal to worker: " << strerror(rc); - break; - } - - std::this_thread::sleep_for(100ms); - - rc = pthread_kill(worker_thread_handle, 0); - if (rc == 0) { - continue; - } else if (rc == ESRCH) { - break; - } else { - LOG(ERROR) << "failed to send interruption signal to worker: " << strerror(rc); - } - } - - worker_thread_.join(); - } - - void PrepareReadBlock(IoReadBlock* block, uint64_t id) { - block->pending = false; - if (block->payload.capacity() >= kUsbReadSize) { - block->payload.resize(kUsbReadSize); - } else { - block->payload = Block(kUsbReadSize); - } - block->control.aio_data = static_cast(TransferId::read(id)); - block->control.aio_buf = reinterpret_cast(block->payload.data()); - block->control.aio_nbytes = block->payload.size(); - } - - IoReadBlock CreateReadBlock(uint64_t id) { - IoReadBlock block; - PrepareReadBlock(&block, id); - block.control.aio_rw_flags = 0; - block.control.aio_lio_opcode = IOCB_CMD_PREAD; - block.control.aio_reqprio = 0; - block.control.aio_fildes = read_fd_.get(); - block.control.aio_offset = 0; - block.control.aio_flags = IOCB_FLAG_RESFD; - block.control.aio_resfd = worker_event_fd_.get(); - return block; - } - - void ReadEvents() { - static constexpr size_t kMaxEvents = kUsbReadQueueDepth + kUsbWriteQueueDepth; - struct io_event events[kMaxEvents]; - struct timespec timeout = {.tv_sec = 0, .tv_nsec = 0}; - int rc = io_getevents(aio_context_.get(), 0, kMaxEvents, events, &timeout); - if (rc == -1) { - HandleError(StringPrintf("io_getevents failed while reading: %s", strerror(errno))); - return; - } - - for (int event_idx = 0; event_idx < rc; ++event_idx) { - auto& event = events[event_idx]; - TransferId id = TransferId::from_value(event.data); - - if (event.res < 0) { - std::string error = - StringPrintf("%s %" PRIu64 " failed with error %s", - id.direction == TransferDirection::READ ? "read" : "write", - id.id, strerror(-event.res)); - HandleError(error); - return; - } - - if (id.direction == TransferDirection::READ) { - if (!HandleRead(id, event.res)) { - return; - } - } else { - HandleWrite(id); - } - } - } - - bool HandleRead(TransferId id, int64_t size) { - uint64_t read_idx = id.id % kUsbReadQueueDepth; - IoReadBlock* block = &read_requests_[read_idx]; - block->pending = false; - block->payload.resize(size); - - // Notification for completed reads can be received out of order. - if (block->id().id != needed_read_id_) { - LOG(VERBOSE) << "read " << block->id().id << " completed while waiting for " - << needed_read_id_; - return true; - } - - for (uint64_t id = needed_read_id_;; ++id) { - size_t read_idx = id % kUsbReadQueueDepth; - IoReadBlock* current_block = &read_requests_[read_idx]; - if (current_block->pending) { - break; - } - if (!ProcessRead(current_block)) { - return false; - } - ++needed_read_id_; - } - - return true; - } - - bool ProcessRead(IoReadBlock* block) { - if (!block->payload.empty()) { - if (!incoming_header_.has_value()) { - if (block->payload.size() != sizeof(amessage)) { - HandleError("received packet of unexpected length while reading header"); - return false; - } - amessage& msg = incoming_header_.emplace(); - memcpy(&msg, block->payload.data(), sizeof(msg)); - LOG(DEBUG) << "USB read:" << dump_header(&msg); - incoming_header_ = msg; - } else { - size_t bytes_left = incoming_header_->data_length - incoming_payload_.size(); - if (block->payload.size() > bytes_left) { - HandleError("received too many bytes while waiting for payload"); - return false; - } - incoming_payload_.append(std::move(block->payload)); - } - - if (incoming_header_->data_length == incoming_payload_.size()) { - auto packet = std::make_unique(); - packet->msg = *incoming_header_; - - // TODO: Make apacket contain an IOVector so we don't have to coalesce. - packet->payload = std::move(incoming_payload_).coalesce(); - read_callback_(this, std::move(packet)); - - incoming_header_.reset(); - // reuse the capacity of the incoming payload while we can. - auto free_block = incoming_payload_.clear(); - if (block->payload.capacity() == 0) { - block->payload = std::move(free_block); - } - } - } - - PrepareReadBlock(block, block->id().id + kUsbReadQueueDepth); - SubmitRead(block); - return true; - } - - bool SubmitRead(IoReadBlock* block) { - block->pending = true; - struct iocb* iocb = &block->control; - if (io_submit(aio_context_.get(), 1, &iocb) != 1) { - HandleError(StringPrintf("failed to submit read: %s", strerror(errno))); - return false; - } - - return true; - } - - void HandleWrite(TransferId id) { - std::lock_guard lock(write_mutex_); - auto it = - std::find_if(write_requests_.begin(), write_requests_.end(), [id](const auto& req) { - return static_cast(req.id()) == static_cast(id); - }); - CHECK(it != write_requests_.end()); - - write_requests_.erase(it); - size_t outstanding_writes = --writes_submitted_; - LOG(DEBUG) << "USB write: reaped, down to " << outstanding_writes; - } - - IoWriteBlock CreateWriteBlock(std::shared_ptr payload, size_t offset, size_t len, - uint64_t id) { - auto block = IoWriteBlock(); - block.payload = std::move(payload); - block.control.aio_data = static_cast(TransferId::write(id)); - block.control.aio_rw_flags = 0; - block.control.aio_lio_opcode = IOCB_CMD_PWRITE; - block.control.aio_reqprio = 0; - block.control.aio_fildes = write_fd_.get(); - block.control.aio_buf = reinterpret_cast(block.payload->data() + offset); - block.control.aio_nbytes = len; - block.control.aio_offset = 0; - block.control.aio_flags = IOCB_FLAG_RESFD; - block.control.aio_resfd = worker_event_fd_.get(); - return block; - } - - IoWriteBlock CreateWriteBlock(Block&& payload, uint64_t id) { - size_t len = payload.size(); - return CreateWriteBlock(std::make_shared(std::move(payload)), 0, len, id); - } - - void SubmitWrites() REQUIRES(write_mutex_) { - if (writes_submitted_ == kUsbWriteQueueDepth) { - return; - } - - ssize_t writes_to_submit = std::min(kUsbWriteQueueDepth - writes_submitted_, - write_requests_.size() - writes_submitted_); - CHECK_GE(writes_to_submit, 0); - if (writes_to_submit == 0) { - return; - } - - struct iocb* iocbs[kUsbWriteQueueDepth]; - for (int i = 0; i < writes_to_submit; ++i) { - CHECK(!write_requests_[writes_submitted_ + i].pending); - write_requests_[writes_submitted_ + i].pending = true; - iocbs[i] = &write_requests_[writes_submitted_ + i].control; - LOG(VERBOSE) << "submitting write_request " << static_cast(iocbs[i]); - } - - writes_submitted_ += writes_to_submit; - - int rc = io_submit(aio_context_.get(), writes_to_submit, iocbs); - if (rc == -1) { - HandleError(StringPrintf("failed to submit write requests: %s", strerror(errno))); - return; - } else if (rc != writes_to_submit) { - LOG(FATAL) << "failed to submit all writes: wanted to submit " << writes_to_submit - << ", actually submitted " << rc; - } - } - - void HandleError(const std::string& error) { - std::call_once(error_flag_, [&]() { - error_callback_(this, error); - if (!stopped_) { - Stop(); - } - }); - } - - std::thread monitor_thread_; - - bool worker_started_; - std::thread worker_thread_; - - std::atomic stopped_; - std::promise destruction_notifier_; - std::once_flag error_flag_; - - unique_fd worker_event_fd_; - unique_fd monitor_event_fd_; - - ScopedAioContext aio_context_; - unique_fd control_fd_; - unique_fd read_fd_; - unique_fd write_fd_; - - std::optional incoming_header_; - IOVector incoming_payload_; - - std::array read_requests_; - IOVector read_data_; - - // ID of the next request that we're going to send out. - size_t next_read_id_ = 0; - - // ID of the next packet we're waiting for. - size_t needed_read_id_ = 0; - - std::mutex write_mutex_; - std::deque write_requests_ GUARDED_BY(write_mutex_); - size_t next_write_id_ GUARDED_BY(write_mutex_) = 0; - size_t writes_submitted_ GUARDED_BY(write_mutex_) = 0; - - static constexpr int kInterruptionSignal = SIGUSR1; -}; - -static void usb_ffs_open_thread() { - adb_thread_setname("usb ffs open"); - - while (true) { - unique_fd control; - unique_fd bulk_out; - unique_fd bulk_in; - if (!open_functionfs(&control, &bulk_out, &bulk_in)) { - std::this_thread::sleep_for(1s); - continue; - } - - atransport* transport = new atransport(); - transport->serial = "UsbFfs"; - std::promise destruction_notifier; - std::future future = destruction_notifier.get_future(); - transport->SetConnection(std::make_unique( - std::move(control), std::move(bulk_out), std::move(bulk_in), - std::move(destruction_notifier))); - register_transport(transport); - future.wait(); - } -} - -void usb_init() { - std::thread(usb_ffs_open_thread).detach(); -} diff --git a/adb/daemon/usb_ffs.cpp b/adb/daemon/usb_ffs.cpp deleted file mode 100644 index e538ca8855e97d49d96b0d8179b559ccb677e45a..0000000000000000000000000000000000000000 --- a/adb/daemon/usb_ffs.cpp +++ /dev/null @@ -1,321 +0,0 @@ -/* - * Copyright (C) 2018 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 USB - -#include "sysdeps.h" - -#include "daemon/usb_ffs.h" - -#include -#include - -#include -#include -#include - -#include "adb.h" - -#define MAX_PACKET_SIZE_FS 64 -#define MAX_PACKET_SIZE_HS 512 -#define MAX_PACKET_SIZE_SS 1024 - -#define USB_FFS_BULK_SIZE 16384 - -// Number of buffers needed to fit MAX_PAYLOAD, with an extra for ZLPs. -#define USB_FFS_NUM_BUFS ((4 * MAX_PAYLOAD / USB_FFS_BULK_SIZE) + 1) - -#define USB_EXT_PROP_UNICODE 1 - -#define cpu_to_le16(x) htole16(x) -#define cpu_to_le32(x) htole32(x) - -// clang-format off -struct func_desc { - struct usb_interface_descriptor intf; - struct usb_endpoint_descriptor_no_audio source; - struct usb_endpoint_descriptor_no_audio sink; -} __attribute__((packed)); - -struct ss_func_desc { - struct usb_interface_descriptor intf; - struct usb_endpoint_descriptor_no_audio source; - struct usb_ss_ep_comp_descriptor source_comp; - struct usb_endpoint_descriptor_no_audio sink; - struct usb_ss_ep_comp_descriptor sink_comp; -} __attribute__((packed)); - -struct desc_v1 { - struct usb_functionfs_descs_head_v1 { - __le32 magic; - __le32 length; - __le32 fs_count; - __le32 hs_count; - } __attribute__((packed)) header; - struct func_desc fs_descs, hs_descs; -} __attribute__((packed)); - -template -struct usb_os_desc_ext_prop { - uint32_t dwSize = sizeof(*this); - uint32_t dwPropertyDataType = cpu_to_le32(USB_EXT_PROP_UNICODE); - - // Property name and value are transmitted as UTF-16, but the kernel only - // accepts ASCII values and performs the conversion for us. - uint16_t wPropertyNameLength = cpu_to_le16(PropertyNameLength); - char bPropertyName[PropertyNameLength]; - - uint32_t dwPropertyDataLength = cpu_to_le32(PropertyDataLength); - char bProperty[PropertyDataLength]; -} __attribute__((packed)); - -using usb_os_desc_guid_t = usb_os_desc_ext_prop<20, 39>; -usb_os_desc_guid_t os_desc_guid = { - .bPropertyName = "DeviceInterfaceGUID", - .bProperty = "{F72FE0D4-CBCB-407D-8814-9ED673D0DD6B}", -}; - -struct usb_ext_prop_values { - usb_os_desc_guid_t guid; -} __attribute__((packed)); - -usb_ext_prop_values os_prop_values = { - .guid = os_desc_guid, -}; - -struct desc_v2 { - struct usb_functionfs_descs_head_v2 header; - // The rest of the structure depends on the flags in the header. - __le32 fs_count; - __le32 hs_count; - __le32 ss_count; - __le32 os_count; - struct func_desc fs_descs, hs_descs; - struct ss_func_desc ss_descs; - struct usb_os_desc_header os_header; - struct usb_ext_compat_desc os_desc; - struct usb_os_desc_header os_prop_header; - struct usb_ext_prop_values os_prop_values; -} __attribute__((packed)); - -static struct func_desc fs_descriptors = { - .intf = { - .bLength = sizeof(fs_descriptors.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(fs_descriptors.source), - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 1 | USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = MAX_PACKET_SIZE_FS, - }, - .sink = { - .bLength = sizeof(fs_descriptors.sink), - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 2 | USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = MAX_PACKET_SIZE_FS, - }, -}; - -static struct func_desc hs_descriptors = { - .intf = { - .bLength = sizeof(hs_descriptors.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(hs_descriptors.source), - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 1 | USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = MAX_PACKET_SIZE_HS, - }, - .sink = { - .bLength = sizeof(hs_descriptors.sink), - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 2 | USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = MAX_PACKET_SIZE_HS, - }, -}; - -static struct ss_func_desc ss_descriptors = { - .intf = { - .bLength = sizeof(ss_descriptors.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(ss_descriptors.source), - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 1 | USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = MAX_PACKET_SIZE_SS, - }, - .source_comp = { - .bLength = sizeof(ss_descriptors.source_comp), - .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, - .bMaxBurst = 4, - }, - .sink = { - .bLength = sizeof(ss_descriptors.sink), - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 2 | USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = MAX_PACKET_SIZE_SS, - }, - .sink_comp = { - .bLength = sizeof(ss_descriptors.sink_comp), - .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, - .bMaxBurst = 4, - }, -}; - -struct usb_ext_compat_desc os_desc_compat = { - .bFirstInterfaceNumber = 0, - .Reserved1 = cpu_to_le32(1), - .CompatibleID = { 'W', 'I', 'N', 'U', 'S', 'B', '\0', '\0'}, - .SubCompatibleID = {0}, - .Reserved2 = {0}, -}; - -static struct usb_os_desc_header os_desc_header = { - .interface = cpu_to_le32(0), - .dwLength = cpu_to_le32(sizeof(os_desc_header) + sizeof(os_desc_compat)), - .bcdVersion = cpu_to_le32(1), - .wIndex = cpu_to_le32(4), - .bCount = cpu_to_le32(1), - .Reserved = cpu_to_le32(0), -}; - -static struct usb_os_desc_header os_prop_header = { - .interface = cpu_to_le32(0), - .dwLength = cpu_to_le32(sizeof(os_desc_header) + sizeof(os_prop_values)), - .bcdVersion = cpu_to_le32(1), - .wIndex = cpu_to_le32(5), - .wCount = cpu_to_le16(1), -}; - -#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_, - }, -}; -// clang-format on - -bool open_functionfs(android::base::unique_fd* out_control, android::base::unique_fd* out_bulk_out, - android::base::unique_fd* out_bulk_in) { - unique_fd control, bulk_out, bulk_in; - struct desc_v1 v1_descriptor = {}; - struct desc_v2 v2_descriptor = {}; - - v2_descriptor.header.magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2); - v2_descriptor.header.length = cpu_to_le32(sizeof(v2_descriptor)); - v2_descriptor.header.flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC | - FUNCTIONFS_HAS_SS_DESC | FUNCTIONFS_HAS_MS_OS_DESC; - v2_descriptor.fs_count = 3; - v2_descriptor.hs_count = 3; - v2_descriptor.ss_count = 5; - v2_descriptor.os_count = 2; - v2_descriptor.fs_descs = fs_descriptors; - v2_descriptor.hs_descs = hs_descriptors; - v2_descriptor.ss_descs = ss_descriptors; - v2_descriptor.os_header = os_desc_header; - v2_descriptor.os_desc = os_desc_compat; - v2_descriptor.os_prop_header = os_prop_header; - v2_descriptor.os_prop_values = os_prop_values; - - if (out_control->get() < 0) { // might have already done this before - LOG(INFO) << "opening control endpoint " << USB_FFS_ADB_EP0; - control.reset(adb_open(USB_FFS_ADB_EP0, O_RDWR)); - if (control < 0) { - PLOG(ERROR) << "cannot open control endpoint " << USB_FFS_ADB_EP0; - return false; - } - - if (adb_write(control.get(), &v2_descriptor, sizeof(v2_descriptor)) < 0) { - D("[ %s: Switching to V1_descriptor format errno=%s ]", USB_FFS_ADB_EP0, - strerror(errno)); - v1_descriptor.header.magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC); - v1_descriptor.header.length = cpu_to_le32(sizeof(v1_descriptor)); - v1_descriptor.header.fs_count = 3; - v1_descriptor.header.hs_count = 3; - v1_descriptor.fs_descs = fs_descriptors; - v1_descriptor.hs_descs = hs_descriptors; - if (adb_write(control.get(), &v1_descriptor, sizeof(v1_descriptor)) < 0) { - PLOG(ERROR) << "failed to write USB descriptors"; - return false; - } - } - - if (adb_write(control.get(), &strings, sizeof(strings)) < 0) { - PLOG(ERROR) << "failed to write USB strings"; - return false; - } - // Signal only when writing the descriptors to ffs - android::base::SetProperty("sys.usb.ffs.ready", "1"); - } - - bulk_out.reset(adb_open(USB_FFS_ADB_OUT, O_RDONLY)); - if (bulk_out < 0) { - PLOG(ERROR) << "cannot open bulk-out endpoint " << USB_FFS_ADB_OUT; - return false; - } - - bulk_in.reset(adb_open(USB_FFS_ADB_IN, O_WRONLY)); - if (bulk_in < 0) { - PLOG(ERROR) << "cannot open bulk-in endpoint " << USB_FFS_ADB_IN; - return false; - } - - *out_control = std::move(control); - *out_bulk_in = std::move(bulk_in); - *out_bulk_out = std::move(bulk_out); - return true; -} diff --git a/adb/daemon/usb_ffs.h b/adb/daemon/usb_ffs.h deleted file mode 100644 index a19d7ccce62473c29026235bb48542cfa15e55a1..0000000000000000000000000000000000000000 --- a/adb/daemon/usb_ffs.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2020 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. - */ - -#pragma once - -#include - -bool open_functionfs(android::base::unique_fd* control, android::base::unique_fd* bulk_out, - android::base::unique_fd* bulk_in); diff --git a/adb/fastdeploy/Android.bp b/adb/fastdeploy/Android.bp deleted file mode 100644 index f5893aa191b03b804d04cf60d3aa91f43000bcd7..0000000000000000000000000000000000000000 --- a/adb/fastdeploy/Android.bp +++ /dev/null @@ -1,89 +0,0 @@ -// -// Copyright (C) 2018 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. -// -java_library { - name: "deployagent_lib", - sdk_version: "24", - srcs: [ - "deployagent/src/**/*.java", - "proto/**/*.proto", - ], - proto: { - type: "lite", - }, -} - -java_binary { - name: "deployagent", - sdk_version: "24", - static_libs: [ - "deployagent_lib", - ], - dex_preopt: { - enabled: false, - } -} - -android_test { - name: "FastDeployTests", - - manifest: "AndroidManifest.xml", - - srcs: [ - "deployagent/test/com/android/fastdeploy/ApkArchiveTest.java", - ], - - static_libs: [ - "androidx.test.core", - "androidx.test.runner", - "androidx.test.rules", - "deployagent_lib", - "mockito-target-inline-minus-junit4", - ], - - libs: [ - "android.test.runner", - "android.test.base", - "android.test.mock", - ], - - data: [ - "testdata/sample.apk", - "testdata/sample.cd", - ], - - optimize: { - enabled: false, - }, -} - -java_test_host { - name: "FastDeployHostTests", - srcs: [ - "deployagent/test/com/android/fastdeploy/FastDeployTest.java", - ], - data: [ - "testdata/helloworld5.apk", - "testdata/helloworld7.apk", - ], - libs: [ - "compatibility-host-util", - "cts-tradefed", - "tradefed", - ], - test_suites: [ - "general-tests", - ], -} diff --git a/adb/fastdeploy/AndroidManifest.xml b/adb/fastdeploy/AndroidManifest.xml deleted file mode 100644 index 89dc7451bde41ce53a19937628e6024a8b15abae..0000000000000000000000000000000000000000 --- a/adb/fastdeploy/AndroidManifest.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/adb/fastdeploy/AndroidTest.xml b/adb/fastdeploy/AndroidTest.xml deleted file mode 100644 index 24a72bc85a09fc7c5b91a01f22576c9ea8361edd..0000000000000000000000000000000000000000 --- a/adb/fastdeploy/AndroidTest.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - diff --git a/adb/fastdeploy/OWNERS b/adb/fastdeploy/OWNERS deleted file mode 100644 index d1458348a2145d420c1c3e797f6c10695b060b96..0000000000000000000000000000000000000000 --- a/adb/fastdeploy/OWNERS +++ /dev/null @@ -1 +0,0 @@ -idries@google.com diff --git a/adb/fastdeploy/deployagent/deployagent.sh b/adb/fastdeploy/deployagent/deployagent.sh deleted file mode 100755 index 91576ca18c36164c49eba08c9194a91cadaa2ac1..0000000000000000000000000000000000000000 --- a/adb/fastdeploy/deployagent/deployagent.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/system/bin/sh -base=/data/local/tmp -export CLASSPATH=$base/deployagent.jar -exec app_process $base com.android.fastdeploy.DeployAgent "$@" diff --git a/adb/fastdeploy/deployagent/src/com/android/fastdeploy/ApkArchive.java b/adb/fastdeploy/deployagent/src/com/android/fastdeploy/ApkArchive.java deleted file mode 100644 index 31e05023ca1125e64782902ac3944e18e59ac005..0000000000000000000000000000000000000000 --- a/adb/fastdeploy/deployagent/src/com/android/fastdeploy/ApkArchive.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright (C) 2019 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. - */ - -package com.android.fastdeploy; - -import android.util.Log; - -import java.io.File; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.channels.FileChannel; - -/** - * Extremely light-weight APK parser class. - * Aware of Central Directory, Local File Headers and Signature. - * No Zip64 support yet. - */ -public final class ApkArchive { - private static final String TAG = "ApkArchive"; - - // Central Directory constants. - private static final int EOCD_SIGNATURE = 0x06054b50; - private static final int EOCD_MIN_SIZE = 22; - private static final long EOCD_MAX_SIZE = 65_535L + EOCD_MIN_SIZE; - - private static final int CD_ENTRY_HEADER_SIZE_BYTES = 22; - private static final int CD_LOCAL_FILE_HEADER_SIZE_OFFSET = 12; - - // Signature constants. - private static final int EOSIGNATURE_SIZE = 24; - - public final static class Dump { - final byte[] cd; - final byte[] signature; - - Dump(byte[] cd, byte[] signature) { - this.cd = cd; - this.signature = signature; - } - } - - final static class Location { - final long offset; - final long size; - - public Location(long offset, long size) { - this.offset = offset; - this.size = size; - } - } - - private final RandomAccessFile mFile; - private final FileChannel mChannel; - - public ApkArchive(File apk) throws IOException { - mFile = new RandomAccessFile(apk, "r"); - mChannel = mFile.getChannel(); - } - - /** - * Extract the APK metadata: content of Central Directory and Signature. - * - * @return raw content from APK representing CD and Signature data. - */ - public Dump extractMetadata() throws IOException { - Location cdLoc = getCDLocation(); - byte[] cd = readMetadata(cdLoc); - - byte[] signature = null; - Location sigLoc = getSignatureLocation(cdLoc.offset); - if (sigLoc != null) { - signature = readMetadata(sigLoc); - long size = ByteBuffer.wrap(signature).order(ByteOrder.LITTLE_ENDIAN).getLong(); - if (sigLoc.size != size) { - Log.e(TAG, "Mismatching signature sizes: " + sigLoc.size + " != " + size); - signature = null; - } - } - - return new Dump(cd, signature); - } - - private long findEndOfCDRecord() throws IOException { - final long fileSize = mChannel.size(); - int sizeToRead = Math.toIntExact(Math.min(fileSize, EOCD_MAX_SIZE)); - final long readOffset = fileSize - sizeToRead; - ByteBuffer buffer = mChannel.map(FileChannel.MapMode.READ_ONLY, readOffset, - sizeToRead).order(ByteOrder.LITTLE_ENDIAN); - - buffer.position(sizeToRead - EOCD_MIN_SIZE); - while (true) { - int signature = buffer.getInt(); // Read 4 bytes. - if (signature == EOCD_SIGNATURE) { - return readOffset + buffer.position() - 4; - } - if (buffer.position() == 4) { - break; - } - buffer.position(buffer.position() - Integer.BYTES - 1); // Backtrack 5 bytes. - } - - return -1L; - } - - private Location findCDRecord(ByteBuffer buf) { - if (buf.order() != ByteOrder.LITTLE_ENDIAN) { - throw new IllegalArgumentException("ByteBuffer byte order must be little endian"); - } - if (buf.remaining() < CD_ENTRY_HEADER_SIZE_BYTES) { - throw new IllegalArgumentException( - "Input too short. Need at least " + CD_ENTRY_HEADER_SIZE_BYTES - + " bytes, available: " + buf.remaining() + "bytes."); - } - - int originalPosition = buf.position(); - int recordSignature = buf.getInt(); - if (recordSignature != EOCD_SIGNATURE) { - throw new IllegalArgumentException( - "Not a Central Directory record. Signature: 0x" - + Long.toHexString(recordSignature & 0xffffffffL)); - } - - buf.position(originalPosition + CD_LOCAL_FILE_HEADER_SIZE_OFFSET); - long size = buf.getInt() & 0xffffffffL; - long offset = buf.getInt() & 0xffffffffL; - return new Location(offset, size); - } - - // Retrieve the location of the Central Directory Record. - Location getCDLocation() throws IOException { - long eocdRecord = findEndOfCDRecord(); - if (eocdRecord < 0) { - throw new IllegalArgumentException("Unable to find End of Central Directory record."); - } - - Location location = findCDRecord(mChannel.map(FileChannel.MapMode.READ_ONLY, eocdRecord, - CD_ENTRY_HEADER_SIZE_BYTES).order(ByteOrder.LITTLE_ENDIAN)); - if (location == null) { - throw new IllegalArgumentException("Unable to find Central Directory File Header."); - } - - return location; - } - - // Retrieve the location of the signature block starting from Central - // Directory Record or null if signature is not found. - Location getSignatureLocation(long cdRecordOffset) throws IOException { - long signatureOffset = cdRecordOffset - EOSIGNATURE_SIZE; - if (signatureOffset < 0) { - Log.e(TAG, "Unable to find Signature."); - return null; - } - - ByteBuffer signature = mChannel.map(FileChannel.MapMode.READ_ONLY, signatureOffset, - EOSIGNATURE_SIZE).order(ByteOrder.LITTLE_ENDIAN); - - long size = signature.getLong(); - - byte[] sign = new byte[16]; - signature.get(sign); - String signAsString = new String(sign); - if (!"APK Sig Block 42".equals(signAsString)) { - Log.e(TAG, "Signature magic does not match: " + signAsString); - return null; - } - - long offset = cdRecordOffset - size - 8; - - return new Location(offset, size); - } - - private byte[] readMetadata(Location loc) throws IOException { - byte[] payload = new byte[(int) loc.size]; - ByteBuffer buffer = mChannel.map(FileChannel.MapMode.READ_ONLY, loc.offset, loc.size); - buffer.get(payload); - return payload; - } -} diff --git a/adb/fastdeploy/deployagent/src/com/android/fastdeploy/DeployAgent.java b/adb/fastdeploy/deployagent/src/com/android/fastdeploy/DeployAgent.java deleted file mode 100644 index 3812307cca4f9dbcce570fa1560c260877b6f1b9..0000000000000000000000000000000000000000 --- a/adb/fastdeploy/deployagent/src/com/android/fastdeploy/DeployAgent.java +++ /dev/null @@ -1,337 +0,0 @@ -/* - * Copyright (C) 2018 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. - */ - -package com.android.fastdeploy; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.RandomAccessFile; -import java.nio.channels.Channels; -import java.nio.channels.FileChannel; -import java.nio.channels.WritableByteChannel; - -import com.android.fastdeploy.PatchFormatException; -import com.android.fastdeploy.ApkArchive; -import com.android.fastdeploy.APKDump; -import com.android.fastdeploy.APKMetaData; -import com.android.fastdeploy.PatchUtils; - -import com.google.protobuf.ByteString; - -public final class DeployAgent { - private static final int BUFFER_SIZE = 128 * 1024; - private static final int AGENT_VERSION = 0x00000003; - - public static void main(String[] args) { - int exitCode = 0; - try { - if (args.length < 1) { - showUsage(0); - } - - String commandString = args[0]; - switch (commandString) { - case "dump": { - if (args.length != 3) { - showUsage(1); - } - - String requiredVersion = args[1]; - if (AGENT_VERSION == Integer.parseInt(requiredVersion)) { - String packageName = args[2]; - String packagePath = getFilenameFromPackageName(packageName); - if (packagePath != null) { - dumpApk(packageName, packagePath); - } else { - exitCode = 3; - } - } else { - System.out.printf("0x%08X\n", AGENT_VERSION); - exitCode = 4; - } - break; - } - case "apply": { - if (args.length < 3) { - showUsage(1); - } - - String patchPath = args[1]; - String outputParam = args[2]; - - InputStream deltaInputStream = null; - if (patchPath.compareTo("-") == 0) { - deltaInputStream = System.in; - } else { - deltaInputStream = new FileInputStream(patchPath); - } - - if (outputParam.equals("-o")) { - OutputStream outputStream = null; - if (args.length > 3) { - String outputPath = args[3]; - if (!outputPath.equals("-")) { - outputStream = new FileOutputStream(outputPath); - } - } - if (outputStream == null) { - outputStream = System.out; - } - writePatchToStream(deltaInputStream, outputStream); - } else if (outputParam.equals("-pm")) { - String[] sessionArgs = null; - if (args.length > 3) { - int numSessionArgs = args.length - 3; - sessionArgs = new String[numSessionArgs]; - for (int i = 0; i < numSessionArgs; i++) { - sessionArgs[i] = args[i + 3]; - } - } - exitCode = applyPatch(deltaInputStream, sessionArgs); - } - break; - } - default: - showUsage(1); - break; - } - } catch (Exception e) { - System.err.println("Error: " + e); - e.printStackTrace(); - System.exit(2); - } - System.exit(exitCode); - } - - private static void showUsage(int exitCode) { - System.err.println( - "usage: deployagent []\n\n" + - "commands:\n" + - "dump VERSION PKGNAME dump info for an installed package given that " + - "VERSION equals current agent's version\n" + - "apply PATCHFILE [-o|-pm] apply a patch from PATCHFILE " + - "(- for stdin) to an installed package\n" + - " -o directs output to FILE, default or - for stdout\n" + - " -pm directs output to package manager, passes to " + - "'pm install-create'\n" - ); - System.exit(exitCode); - } - - private static Process executeCommand(String command) throws IOException { - try { - Process p; - p = Runtime.getRuntime().exec(command); - p.waitFor(); - return p; - } catch (InterruptedException e) { - e.printStackTrace(); - } - - return null; - } - - private static String getFilenameFromPackageName(String packageName) throws IOException { - StringBuilder commandBuilder = new StringBuilder(); - commandBuilder.append("pm list packages -f " + packageName); - - Process p = executeCommand(commandBuilder.toString()); - BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); - - String packagePrefix = "package:"; - String packageSuffix = "=" + packageName; - String line = ""; - while ((line = reader.readLine()) != null) { - if (line.endsWith(packageSuffix)) { - int packageIndex = line.indexOf(packagePrefix); - if (packageIndex == -1) { - throw new IOException("error reading package list"); - } - int equalsIndex = line.lastIndexOf(packageSuffix); - String fileName = - line.substring(packageIndex + packagePrefix.length(), equalsIndex); - return fileName; - } - } - return null; - } - - private static void dumpApk(String packageName, String packagePath) throws IOException { - File apk = new File(packagePath); - ApkArchive.Dump dump = new ApkArchive(apk).extractMetadata(); - - APKDump.Builder apkDumpBuilder = APKDump.newBuilder(); - apkDumpBuilder.setName(packageName); - if (dump.cd != null) { - apkDumpBuilder.setCd(ByteString.copyFrom(dump.cd)); - } - if (dump.signature != null) { - apkDumpBuilder.setSignature(ByteString.copyFrom(dump.signature)); - } - apkDumpBuilder.setAbsolutePath(apk.getAbsolutePath()); - - apkDumpBuilder.build().writeTo(System.out); - } - - private static int createInstallSession(String[] args) throws IOException { - StringBuilder commandBuilder = new StringBuilder(); - commandBuilder.append("pm install-create "); - for (int i = 0; args != null && i < args.length; i++) { - commandBuilder.append(args[i] + " "); - } - - Process p = executeCommand(commandBuilder.toString()); - - BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); - String line = ""; - String successLineStart = "Success: created install session ["; - String successLineEnd = "]"; - while ((line = reader.readLine()) != null) { - if (line.startsWith(successLineStart) && line.endsWith(successLineEnd)) { - return Integer.parseInt(line.substring(successLineStart.length(), - line.lastIndexOf(successLineEnd))); - } - } - - return -1; - } - - private static int commitInstallSession(int sessionId) throws IOException { - StringBuilder commandBuilder = new StringBuilder(); - commandBuilder.append(String.format("pm install-commit %d -- - ", sessionId)); - Process p = executeCommand(commandBuilder.toString()); - return p.exitValue(); - } - - private static int applyPatch(InputStream deltaStream, String[] sessionArgs) - throws IOException, PatchFormatException { - int sessionId = createInstallSession(sessionArgs); - if (sessionId < 0) { - System.err.println("PM Create Session Failed"); - return -1; - } - - int writeExitCode = writePatchedDataToSession(deltaStream, sessionId); - if (writeExitCode == 0) { - return commitInstallSession(sessionId); - } else { - return -1; - } - } - - private static long writePatchToStream(InputStream patchData, - OutputStream outputStream) throws IOException, PatchFormatException { - long newSize = readPatchHeader(patchData); - long bytesWritten = writePatchedDataToStream(newSize, patchData, outputStream); - outputStream.flush(); - if (bytesWritten != newSize) { - throw new PatchFormatException(String.format( - "output size mismatch (expected %ld but wrote %ld)", newSize, bytesWritten)); - } - return bytesWritten; - } - - private static long readPatchHeader(InputStream patchData) - throws IOException, PatchFormatException { - byte[] signatureBuffer = new byte[PatchUtils.SIGNATURE.length()]; - try { - PatchUtils.readFully(patchData, signatureBuffer); - } catch (IOException e) { - throw new PatchFormatException("truncated signature"); - } - - String signature = new String(signatureBuffer); - if (!PatchUtils.SIGNATURE.equals(signature)) { - throw new PatchFormatException("bad signature"); - } - - long newSize = PatchUtils.readLELong(patchData); - if (newSize < 0) { - throw new PatchFormatException("bad newSize: " + newSize); - } - - return newSize; - } - - // Note that this function assumes patchData has been seek'ed to the start of the delta stream - // (i.e. the signature has already been read by readPatchHeader). For a stream that points to - // the start of a patch file call writePatchToStream - private static long writePatchedDataToStream(long newSize, InputStream patchData, - OutputStream outputStream) throws IOException { - String deviceFile = PatchUtils.readString(patchData); - RandomAccessFile oldDataFile = new RandomAccessFile(deviceFile, "r"); - FileChannel oldData = oldDataFile.getChannel(); - - WritableByteChannel newData = Channels.newChannel(outputStream); - - long newDataBytesWritten = 0; - byte[] buffer = new byte[BUFFER_SIZE]; - - while (newDataBytesWritten < newSize) { - long newDataLen = PatchUtils.readLELong(patchData); - if (newDataLen > 0) { - PatchUtils.pipe(patchData, outputStream, buffer, newDataLen); - } - - long oldDataOffset = PatchUtils.readLELong(patchData); - long oldDataLen = PatchUtils.readLELong(patchData); - if (oldDataLen >= 0) { - long offset = oldDataOffset; - long len = oldDataLen; - while (len > 0) { - long chunkLen = Math.min(len, 1024*1024*1024); - oldData.transferTo(offset, chunkLen, newData); - offset += chunkLen; - len -= chunkLen; - } - } - newDataBytesWritten += newDataLen + oldDataLen; - } - - return newDataBytesWritten; - } - - private static int writePatchedDataToSession(InputStream patchData, int sessionId) - throws IOException, PatchFormatException { - try { - Process p; - long newSize = readPatchHeader(patchData); - String command = String.format("pm install-write -S %d %d -- -", newSize, sessionId); - p = Runtime.getRuntime().exec(command); - - OutputStream sessionOutputStream = p.getOutputStream(); - long bytesWritten = writePatchedDataToStream(newSize, patchData, sessionOutputStream); - sessionOutputStream.flush(); - p.waitFor(); - if (bytesWritten != newSize) { - throw new PatchFormatException( - String.format("output size mismatch (expected %d but wrote %)", newSize, - bytesWritten)); - } - return p.exitValue(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - return -1; - } -} diff --git a/adb/fastdeploy/deployagent/src/com/android/fastdeploy/PatchFormatException.java b/adb/fastdeploy/deployagent/src/com/android/fastdeploy/PatchFormatException.java deleted file mode 100644 index f0655f325cf59e65323c0e2bd9230ac692f77b0e..0000000000000000000000000000000000000000 --- a/adb/fastdeploy/deployagent/src/com/android/fastdeploy/PatchFormatException.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2018 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. - */ - -package com.android.fastdeploy; - -class PatchFormatException extends Exception { - /** - * Constructs a new exception with the specified message. - * @param message the message - */ - public PatchFormatException(String message) { super(message); } - - /** - * Constructs a new exception with the specified message and cause. - * @param message the message - * @param cause the cause of the error - */ - public PatchFormatException(String message, Throwable cause) { - super(message); - initCause(cause); - } -} diff --git a/adb/fastdeploy/deployagent/src/com/android/fastdeploy/PatchUtils.java b/adb/fastdeploy/deployagent/src/com/android/fastdeploy/PatchUtils.java deleted file mode 100644 index 54be26f651e41d307da964b5f6f1abfed344bbe7..0000000000000000000000000000000000000000 --- a/adb/fastdeploy/deployagent/src/com/android/fastdeploy/PatchUtils.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2018 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. - */ - -package com.android.fastdeploy; - -import java.io.DataInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -class PatchUtils { - public static final String SIGNATURE = "FASTDEPLOY"; - - /** - * Reads a 64-bit signed integer in Little Endian format from the specified {@link - * DataInputStream}. - * - * @param in the stream to read from. - */ - static long readLELong(InputStream in) throws IOException { - byte[] buffer = new byte[Long.BYTES]; - readFully(in, buffer); - ByteBuffer buf = ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN); - return buf.getLong(); - } - - static String readString(InputStream in) throws IOException { - int size = (int) readLELong(in); - byte[] buffer = new byte[size]; - readFully(in, buffer); - return new String(buffer); - } - - static void readFully(final InputStream in, final byte[] destination, final int startAt, - final int numBytes) throws IOException { - int numRead = 0; - while (numRead < numBytes) { - int readNow = in.read(destination, startAt + numRead, numBytes - numRead); - if (readNow == -1) { - throw new IOException("truncated input stream"); - } - numRead += readNow; - } - } - - static void readFully(final InputStream in, final byte[] destination) throws IOException { - readFully(in, destination, 0, destination.length); - } - - static void pipe(final InputStream in, final OutputStream out, final byte[] buffer, - long copyLength) throws IOException { - while (copyLength > 0) { - int maxCopy = (int) Math.min(buffer.length, copyLength); - readFully(in, buffer, 0, maxCopy); - out.write(buffer, 0, maxCopy); - copyLength -= maxCopy; - } - } -} diff --git a/adb/fastdeploy/deployagent/test/com/android/fastdeploy/ApkArchiveTest.java b/adb/fastdeploy/deployagent/test/com/android/fastdeploy/ApkArchiveTest.java deleted file mode 100644 index 7c2468f5242e8853ae5aae212c53405ee35027ad..0000000000000000000000000000000000000000 --- a/adb/fastdeploy/deployagent/test/com/android/fastdeploy/ApkArchiveTest.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2019 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. - */ - -package com.android.fastdeploy; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; - -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; - -import com.android.fastdeploy.ApkArchive; - -import java.io.File; -import java.io.IOException; - -@SmallTest -@RunWith(AndroidJUnit4.class) -public class ApkArchiveTest { - private static final File SAMPLE_APK = new File("/data/local/tmp/FastDeployTests/sample.apk"); - private static final File WRONG_APK = new File("/data/local/tmp/FastDeployTests/sample.cd"); - - @Test - public void testApkArchiveSizes() throws IOException { - ApkArchive archive = new ApkArchive(SAMPLE_APK); - - ApkArchive.Location cdLoc = archive.getCDLocation(); - assertNotEquals(cdLoc, null); - assertEquals(cdLoc.offset, 2044145); - assertEquals(cdLoc.size, 49390); - - // Check that block can be retrieved - ApkArchive.Location sigLoc = archive.getSignatureLocation(cdLoc.offset); - assertNotEquals(sigLoc, null); - assertEquals(sigLoc.offset, 2040049); - assertEquals(sigLoc.size, 4088); - } - - @Test - public void testApkArchiveDump() throws IOException { - ApkArchive archive = new ApkArchive(SAMPLE_APK); - - ApkArchive.Dump dump = archive.extractMetadata(); - assertNotEquals(dump, null); - assertNotEquals(dump.cd, null); - assertNotEquals(dump.signature, null); - assertEquals(dump.cd.length, 49390); - assertEquals(dump.signature.length, 4088); - } - - @Test(expected = IllegalArgumentException.class) - public void testApkArchiveDumpWrongApk() throws IOException { - ApkArchive archive = new ApkArchive(WRONG_APK); - - archive.extractMetadata(); - } -} diff --git a/adb/fastdeploy/deployagent/test/com/android/fastdeploy/FastDeployTest.java b/adb/fastdeploy/deployagent/test/com/android/fastdeploy/FastDeployTest.java deleted file mode 100644 index 4aa2f79bb8d8bef1fb336d8966b41c4cd45138cb..0000000000000000000000000000000000000000 --- a/adb/fastdeploy/deployagent/test/com/android/fastdeploy/FastDeployTest.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2018 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. - */ - -package com.android.fastdeploy; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper; -import com.android.ddmlib.Log.LogLevel; -import com.android.tradefed.device.DeviceNotAvailableException; -import com.android.tradefed.log.LogUtil.CLog; -import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; -import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.io.IOException; -import java.util.Arrays; - -@RunWith(DeviceJUnit4ClassRunner.class) -public class FastDeployTest extends BaseHostJUnit4Test { - - private static final String TEST_APP_PACKAGE = "com.example.helloworld"; - private static final String TEST_APK5_NAME = "helloworld5.apk"; - private static final String TEST_APK7_NAME = "helloworld7.apk"; - - private String mTestApk5Path; - private String mTestApk7Path; - - @Before - public void setUp() throws Exception { - CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(getBuild()); - getDevice().uninstallPackage(TEST_APP_PACKAGE); - mTestApk5Path = buildHelper.getTestFile(TEST_APK5_NAME).getAbsolutePath(); - mTestApk7Path = buildHelper.getTestFile(TEST_APK7_NAME).getAbsolutePath(); - } - - @Test - public void testAppInstalls() throws Exception { - fastInstallPackage(mTestApk5Path); - assertTrue(isAppInstalled(TEST_APP_PACKAGE)); - getDevice().uninstallPackage(TEST_APP_PACKAGE); - assertFalse(isAppInstalled(TEST_APP_PACKAGE)); - } - - @Test - public void testAppPatch() throws Exception { - fastInstallPackage(mTestApk5Path); - assertTrue(isAppInstalled(TEST_APP_PACKAGE)); - fastInstallPackage(mTestApk7Path); - assertTrue(isAppInstalled(TEST_APP_PACKAGE)); - getDevice().uninstallPackage(TEST_APP_PACKAGE); - assertFalse(isAppInstalled(TEST_APP_PACKAGE)); - } - - private boolean isAppInstalled(String packageName) throws DeviceNotAvailableException { - final String result = getDevice().executeShellCommand("pm list packages"); - CLog.logAndDisplay(LogLevel.INFO, result); - final int prefixLength = "package:".length(); - return Arrays.stream(result.split("\\r?\\n")) - .anyMatch(line -> line.substring(prefixLength).equals(packageName)); - } - - // Mostly copied from PkgInstallSignatureVerificationTest.java. - private void fastInstallPackage(String apkPath) - throws IOException, DeviceNotAvailableException { - String result = getDevice().executeAdbCommand("install", "-t", "--fastdeploy", "--force-agent", - apkPath); - CLog.logAndDisplay(LogLevel.INFO, result); - } -} - - diff --git a/adb/fastdeploy/deploypatchgenerator/apk_archive.cpp b/adb/fastdeploy/deploypatchgenerator/apk_archive.cpp deleted file mode 100644 index 9da256e240b79bd2decc912cecc3605e2f724d8c..0000000000000000000000000000000000000000 --- a/adb/fastdeploy/deploypatchgenerator/apk_archive.cpp +++ /dev/null @@ -1,417 +0,0 @@ -/* - * Copyright (C) 2019 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 ADB - -#include "apk_archive.h" - -#include - -#include "adb_trace.h" -#include "sysdeps.h" - -#include -#include - -#include - -constexpr uint16_t kCompressStored = 0; - -// mask value that signifies that the entry has a DD -static const uint32_t kGPBDDFlagMask = 0x0008; - -namespace { -struct FileRegion { - FileRegion(borrowed_fd fd, off64_t offset, size_t length) - : mapped_(android::base::MappedFile::FromOsHandle(adb_get_os_handle(fd), offset, length, - PROT_READ)) { - if (mapped_ != nullptr) { - return; - } - - // Mapped file failed, falling back to pread. - buffer_.resize(length); - if (auto err = adb_pread(fd.get(), buffer_.data(), length, offset); size_t(err) != length) { - fprintf(stderr, "Unable to read %lld bytes at offset %" PRId64 " \n", - static_cast(length), offset); - buffer_.clear(); - return; - } - } - - const char* data() const { return mapped_ ? mapped_->data() : buffer_.data(); } - size_t size() const { return mapped_ ? mapped_->size() : buffer_.size(); } - - private: - FileRegion() = default; - DISALLOW_COPY_AND_ASSIGN(FileRegion); - - std::unique_ptr mapped_; - std::string buffer_; -}; -} // namespace - -using com::android::fastdeploy::APKDump; - -ApkArchive::ApkArchive(const std::string& path) : path_(path), size_(0) { - fd_.reset(adb_open(path_.c_str(), O_RDONLY)); - if (fd_ == -1) { - fprintf(stderr, "Unable to open file '%s'\n", path_.c_str()); - return; - } - - struct stat st; - if (stat(path_.c_str(), &st) == -1) { - fprintf(stderr, "Unable to stat file '%s'\n", path_.c_str()); - return; - } - size_ = st.st_size; -} - -ApkArchive::~ApkArchive() {} - -APKDump ApkArchive::ExtractMetadata() { - D("ExtractMetadata"); - if (!ready()) { - return {}; - } - - Location cdLoc = GetCDLocation(); - if (!cdLoc.valid) { - return {}; - } - - APKDump dump; - dump.set_absolute_path(path_); - dump.set_cd(ReadMetadata(cdLoc)); - - Location sigLoc = GetSignatureLocation(cdLoc.offset); - if (sigLoc.valid) { - dump.set_signature(ReadMetadata(sigLoc)); - } - return dump; -} - -off_t ApkArchive::FindEndOfCDRecord() const { - constexpr int endOfCDSignature = 0x06054b50; - constexpr off_t endOfCDMinSize = 22; - constexpr off_t endOfCDMaxSize = 65535 + endOfCDMinSize; - - auto sizeToRead = std::min(size_, endOfCDMaxSize); - auto readOffset = size_ - sizeToRead; - FileRegion mapped(fd_, readOffset, sizeToRead); - - // Start scanning from the end - auto* start = mapped.data(); - auto* cursor = start + mapped.size() - sizeof(endOfCDSignature); - - // Search for End of Central Directory record signature. - while (cursor >= start) { - if (*(int32_t*)cursor == endOfCDSignature) { - return readOffset + (cursor - start); - } - cursor--; - } - return -1; -} - -ApkArchive::Location ApkArchive::FindCDRecord(const char* cursor) { - struct ecdr_t { - int32_t signature; - uint16_t diskNumber; - uint16_t numDisk; - uint16_t diskEntries; - uint16_t numEntries; - uint32_t crSize; - uint32_t offsetToCdHeader; - uint16_t commentSize; - uint8_t comment[0]; - } __attribute__((packed)); - ecdr_t* header = (ecdr_t*)cursor; - - Location location; - location.offset = header->offsetToCdHeader; - location.size = header->crSize; - location.valid = true; - return location; -} - -ApkArchive::Location ApkArchive::GetCDLocation() { - constexpr off_t cdEntryHeaderSizeBytes = 22; - Location location; - - // Find End of Central Directory Record - off_t eocdRecord = FindEndOfCDRecord(); - if (eocdRecord < 0) { - fprintf(stderr, "Unable to find End of Central Directory record in file '%s'\n", - path_.c_str()); - return location; - } - - // Find Central Directory Record - FileRegion mapped(fd_, eocdRecord, cdEntryHeaderSizeBytes); - location = FindCDRecord(mapped.data()); - if (!location.valid) { - fprintf(stderr, "Unable to find Central Directory File Header in file '%s'\n", - path_.c_str()); - return location; - } - - return location; -} - -ApkArchive::Location ApkArchive::GetSignatureLocation(off_t cdRecordOffset) { - Location location; - - // Signature constants. - constexpr off_t endOfSignatureSize = 24; - off_t signatureOffset = cdRecordOffset - endOfSignatureSize; - if (signatureOffset < 0) { - fprintf(stderr, "Unable to find signature in file '%s'\n", path_.c_str()); - return location; - } - - FileRegion mapped(fd_, signatureOffset, endOfSignatureSize); - - uint64_t signatureSize = *(uint64_t*)mapped.data(); - auto* signature = mapped.data() + sizeof(signatureSize); - // Check if there is a v2/v3 Signature block here. - if (memcmp(signature, "APK Sig Block 42", 16)) { - return location; - } - - // This is likely a signature block. - location.size = signatureSize; - location.offset = cdRecordOffset - location.size - 8; - location.valid = true; - - return location; -} - -std::string ApkArchive::ReadMetadata(Location loc) const { - FileRegion mapped(fd_, loc.offset, loc.size); - return {mapped.data(), mapped.size()}; -} - -size_t ApkArchive::ParseCentralDirectoryRecord(const char* input, size_t size, std::string* md5Hash, - int64_t* localFileHeaderOffset, int64_t* dataSize) { - // A structure representing the fixed length fields for a single - // record in the central directory of the archive. In addition to - // the fixed length fields listed here, each central directory - // record contains a variable length "file_name" and "extra_field" - // whose lengths are given by |file_name_length| and |extra_field_length| - // respectively. - static constexpr int kCDFileHeaderMagic = 0x02014b50; - struct CentralDirectoryRecord { - // The start of record signature. Must be |kSignature|. - uint32_t record_signature; - // Source tool version. Top byte gives source OS. - uint16_t version_made_by; - // Tool version. Ignored by this implementation. - uint16_t version_needed; - // The "general purpose bit flags" for this entry. The only - // flag value that we currently check for is the "data descriptor" - // flag. - uint16_t gpb_flags; - // The compression method for this entry, one of |kCompressStored| - // and |kCompressDeflated|. - uint16_t compression_method; - // The file modification time and date for this entry. - uint16_t last_mod_time; - uint16_t last_mod_date; - // The CRC-32 checksum for this entry. - uint32_t crc32; - // The compressed size (in bytes) of this entry. - uint32_t compressed_size; - // The uncompressed size (in bytes) of this entry. - uint32_t uncompressed_size; - // The length of the entry file name in bytes. The file name - // will appear immediately after this record. - uint16_t file_name_length; - // The length of the extra field info (in bytes). This data - // will appear immediately after the entry file name. - uint16_t extra_field_length; - // The length of the entry comment (in bytes). This data will - // appear immediately after the extra field. - uint16_t comment_length; - // The start disk for this entry. Ignored by this implementation). - uint16_t file_start_disk; - // File attributes. Ignored by this implementation. - uint16_t internal_file_attributes; - // File attributes. For archives created on Unix, the top bits are the - // mode. - uint32_t external_file_attributes; - // The offset to the local file header for this entry, from the - // beginning of this archive. - uint32_t local_file_header_offset; - - private: - CentralDirectoryRecord() = default; - DISALLOW_COPY_AND_ASSIGN(CentralDirectoryRecord); - } __attribute__((packed)); - - const CentralDirectoryRecord* cdr; - if (size < sizeof(*cdr)) { - return 0; - } - - auto begin = input; - cdr = reinterpret_cast(begin); - if (cdr->record_signature != kCDFileHeaderMagic) { - fprintf(stderr, "Invalid Central Directory Record signature\n"); - return 0; - } - auto end = begin + sizeof(*cdr) + cdr->file_name_length + cdr->extra_field_length + - cdr->comment_length; - - uint8_t md5Digest[MD5_DIGEST_LENGTH]; - MD5((const unsigned char*)begin, end - begin, md5Digest); - md5Hash->assign((const char*)md5Digest, sizeof(md5Digest)); - - *localFileHeaderOffset = cdr->local_file_header_offset; - *dataSize = (cdr->compression_method == kCompressStored) ? cdr->uncompressed_size - : cdr->compressed_size; - - return end - begin; -} - -size_t ApkArchive::CalculateLocalFileEntrySize(int64_t localFileHeaderOffset, - int64_t dataSize) const { - // The local file header for a given entry. This duplicates information - // present in the central directory of the archive. It is an error for - // the information here to be different from the central directory - // information for a given entry. - static constexpr int kLocalFileHeaderMagic = 0x04034b50; - struct LocalFileHeader { - // The local file header signature, must be |kSignature|. - uint32_t lfh_signature; - // Tool version. Ignored by this implementation. - uint16_t version_needed; - // The "general purpose bit flags" for this entry. The only - // flag value that we currently check for is the "data descriptor" - // flag. - uint16_t gpb_flags; - // The compression method for this entry, one of |kCompressStored| - // and |kCompressDeflated|. - uint16_t compression_method; - // The file modification time and date for this entry. - uint16_t last_mod_time; - uint16_t last_mod_date; - // The CRC-32 checksum for this entry. - uint32_t crc32; - // The compressed size (in bytes) of this entry. - uint32_t compressed_size; - // The uncompressed size (in bytes) of this entry. - uint32_t uncompressed_size; - // The length of the entry file name in bytes. The file name - // will appear immediately after this record. - uint16_t file_name_length; - // The length of the extra field info (in bytes). This data - // will appear immediately after the entry file name. - uint16_t extra_field_length; - - private: - LocalFileHeader() = default; - DISALLOW_COPY_AND_ASSIGN(LocalFileHeader); - } __attribute__((packed)); - static constexpr int kLocalFileHeaderSize = sizeof(LocalFileHeader); - CHECK(ready()) << path_; - - const LocalFileHeader* lfh; - if (localFileHeaderOffset + kLocalFileHeaderSize > size_) { - fprintf(stderr, - "Invalid Local File Header offset in file '%s' at offset %lld, file size %lld\n", - path_.c_str(), static_cast(localFileHeaderOffset), - static_cast(size_)); - return 0; - } - - FileRegion lfhMapped(fd_, localFileHeaderOffset, sizeof(LocalFileHeader)); - lfh = reinterpret_cast(lfhMapped.data()); - if (lfh->lfh_signature != kLocalFileHeaderMagic) { - fprintf(stderr, "Invalid Local File Header signature in file '%s' at offset %lld\n", - path_.c_str(), static_cast(localFileHeaderOffset)); - return 0; - } - - // The *optional* data descriptor start signature. - static constexpr int kOptionalDataDescriptorMagic = 0x08074b50; - struct DataDescriptor { - // CRC-32 checksum of the entry. - uint32_t crc32; - // Compressed size of the entry. - uint32_t compressed_size; - // Uncompressed size of the entry. - uint32_t uncompressed_size; - - private: - DataDescriptor() = default; - DISALLOW_COPY_AND_ASSIGN(DataDescriptor); - } __attribute__((packed)); - static constexpr int kDataDescriptorSize = sizeof(DataDescriptor); - - off_t ddOffset = localFileHeaderOffset + kLocalFileHeaderSize + lfh->file_name_length + - lfh->extra_field_length + dataSize; - int64_t ddSize = 0; - - int64_t localDataSize; - if (lfh->gpb_flags & kGPBDDFlagMask) { - // There is trailing data descriptor. - const DataDescriptor* dd; - - if (ddOffset + int(sizeof(uint32_t)) > size_) { - fprintf(stderr, - "Error reading trailing data descriptor signature in file '%s' at offset %lld, " - "file size %lld\n", - path_.c_str(), static_cast(ddOffset), static_cast(size_)); - return 0; - } - - FileRegion ddMapped(fd_, ddOffset, sizeof(uint32_t) + sizeof(DataDescriptor)); - - off_t localDDOffset = 0; - if (kOptionalDataDescriptorMagic == *(uint32_t*)ddMapped.data()) { - ddOffset += sizeof(uint32_t); - localDDOffset += sizeof(uint32_t); - ddSize += sizeof(uint32_t); - } - if (ddOffset + kDataDescriptorSize > size_) { - fprintf(stderr, - "Error reading trailing data descriptor in file '%s' at offset %lld, file size " - "%lld\n", - path_.c_str(), static_cast(ddOffset), static_cast(size_)); - return 0; - } - - dd = reinterpret_cast(ddMapped.data() + localDDOffset); - localDataSize = (lfh->compression_method == kCompressStored) ? dd->uncompressed_size - : dd->compressed_size; - ddSize += sizeof(*dd); - } else { - localDataSize = (lfh->compression_method == kCompressStored) ? lfh->uncompressed_size - : lfh->compressed_size; - } - if (localDataSize != dataSize) { - fprintf(stderr, - "Data sizes mismatch in file '%s' at offset %lld, CDr: %lld vs LHR/DD: %lld\n", - path_.c_str(), static_cast(localFileHeaderOffset), - static_cast(dataSize), static_cast(localDataSize)); - return 0; - } - - return kLocalFileHeaderSize + lfh->file_name_length + lfh->extra_field_length + dataSize + - ddSize; -} diff --git a/adb/fastdeploy/deploypatchgenerator/apk_archive.h b/adb/fastdeploy/deploypatchgenerator/apk_archive.h deleted file mode 100644 index 7127800a93d920447d0945c9e85f08bf71607c0f..0000000000000000000000000000000000000000 --- a/adb/fastdeploy/deploypatchgenerator/apk_archive.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2019 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. - */ - -#pragma once - -#include -#include -#include - -#include - -#include "fastdeploy/proto/ApkEntry.pb.h" - -class ApkArchiveTester; - -// Manipulates an APK archive. Process it by mmaping it in order to minimize -// I/Os. -class ApkArchive { - public: - friend ApkArchiveTester; - - // A convenience struct to store the result of search operation when - // locating the EoCDr, CDr, and Signature Block. - struct Location { - off_t offset = 0; - off_t size = 0; - bool valid = false; - }; - - ApkArchive(const std::string& path); - ~ApkArchive(); - - com::android::fastdeploy::APKDump ExtractMetadata(); - - // Parses the CDr starting from |input| and returns number of bytes consumed. - // Extracts local file header offset, data size and calculates MD5 hash of the record. - // 0 indicates invalid CDr. - static size_t ParseCentralDirectoryRecord(const char* input, size_t size, std::string* md5Hash, - int64_t* localFileHeaderOffset, int64_t* dataSize); - // Calculates Local File Entry size including header using offset and data size from CDr. - // 0 indicates invalid Local File Entry. - size_t CalculateLocalFileEntrySize(int64_t localFileHeaderOffset, int64_t dataSize) const; - - private: - std::string ReadMetadata(Location loc) const; - - // Retrieve the location of the Central Directory Record. - Location GetCDLocation(); - - // Retrieve the location of the signature block starting from Central - // Directory Record - Location GetSignatureLocation(off_t cdRecordOffset); - - // Find the End of Central Directory Record, starting from the end of the - // file. - off_t FindEndOfCDRecord() const; - - // Find Central Directory Record, starting from the end of the file. - Location FindCDRecord(const char* cursor); - - // Checks if the archive can be used. - bool ready() const { return fd_ >= 0; } - - std::string path_; - off_t size_; - unique_fd fd_; -}; diff --git a/adb/fastdeploy/deploypatchgenerator/apk_archive_test.cpp b/adb/fastdeploy/deploypatchgenerator/apk_archive_test.cpp deleted file mode 100644 index 554cb570eee81935246be718cac4f1587d75381f..0000000000000000000000000000000000000000 --- a/adb/fastdeploy/deploypatchgenerator/apk_archive_test.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2019 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 "apk_archive.h" - -// Friend test to get around private scope of ApkArchive private functions. -class ApkArchiveTester { - public: - ApkArchiveTester(const std::string& path) : archive_(path) {} - - bool ready() { return archive_.ready(); } - - auto ExtractMetadata() { return archive_.ExtractMetadata(); } - - ApkArchive::Location GetCDLocation() { return archive_.GetCDLocation(); } - ApkArchive::Location GetSignatureLocation(size_t start) { - return archive_.GetSignatureLocation(start); - } - - private: - ApkArchive archive_; -}; - -TEST(ApkArchiveTest, TestApkArchiveSizes) { - ApkArchiveTester archiveTester("fastdeploy/testdata/sample.apk"); - EXPECT_TRUE(archiveTester.ready()); - - ApkArchive::Location cdLoc = archiveTester.GetCDLocation(); - EXPECT_TRUE(cdLoc.valid); - ASSERT_EQ(cdLoc.offset, 2044145u); - ASSERT_EQ(cdLoc.size, 49390u); - - // Check that block can be retrieved - ApkArchive::Location sigLoc = archiveTester.GetSignatureLocation(cdLoc.offset); - EXPECT_TRUE(sigLoc.valid); - ASSERT_EQ(sigLoc.offset, 2040049u); - ASSERT_EQ(sigLoc.size, 4088u); -} - -TEST(ApkArchiveTest, TestApkArchiveDump) { - ApkArchiveTester archiveTester("fastdeploy/testdata/sample.apk"); - EXPECT_TRUE(archiveTester.ready()); - - auto dump = archiveTester.ExtractMetadata(); - ASSERT_EQ(dump.cd().size(), 49390u); - ASSERT_EQ(dump.signature().size(), 4088u); -} - -TEST(ApkArchiveTest, WrongApk) { - ApkArchiveTester archiveTester("fastdeploy/testdata/sample.cd"); - EXPECT_TRUE(archiveTester.ready()); - - auto dump = archiveTester.ExtractMetadata(); - ASSERT_EQ(dump.cd().size(), 0u); - ASSERT_EQ(dump.signature().size(), 0u); -} diff --git a/adb/fastdeploy/deploypatchgenerator/deploy_patch_generator.cpp b/adb/fastdeploy/deploypatchgenerator/deploy_patch_generator.cpp deleted file mode 100644 index 8aa7da72fcde74777f65d9a74dace814f30aeb6d..0000000000000000000000000000000000000000 --- a/adb/fastdeploy/deploypatchgenerator/deploy_patch_generator.cpp +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright (C) 2019 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 "deploy_patch_generator.h" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "adb_unique_fd.h" -#include "adb_utils.h" -#include "android-base/file.h" -#include "patch_utils.h" -#include "sysdeps.h" - -using namespace com::android::fastdeploy; - -void DeployPatchGenerator::Log(const char* fmt, ...) { - va_list ap; - va_start(ap, fmt); - vprintf(fmt, ap); - printf("\n"); - va_end(ap); -} - -static std::string HexEncode(const void* in_buffer, unsigned int size) { - static const char kHexChars[] = "0123456789ABCDEF"; - - // Each input byte creates two output hex characters. - std::string out_buffer(size * 2, '\0'); - - for (unsigned int i = 0; i < size; ++i) { - char byte = ((const uint8_t*)in_buffer)[i]; - out_buffer[(i << 1)] = kHexChars[(byte >> 4) & 0xf]; - out_buffer[(i << 1) + 1] = kHexChars[byte & 0xf]; - } - return out_buffer; -} - -void DeployPatchGenerator::APKEntryToLog(const APKEntry& entry) { - if (!is_verbose_) { - return; - } - Log("MD5: %s", HexEncode(entry.md5().data(), entry.md5().size()).c_str()); - Log("Data Offset: %" PRId64, entry.dataoffset()); - Log("Data Size: %" PRId64, entry.datasize()); -} - -void DeployPatchGenerator::APKMetaDataToLog(const APKMetaData& metadata) { - if (!is_verbose_) { - return; - } - Log("APK Metadata: %s", metadata.absolute_path().c_str()); - for (int i = 0; i < metadata.entries_size(); i++) { - const APKEntry& entry = metadata.entries(i); - APKEntryToLog(entry); - } -} - -void DeployPatchGenerator::ReportSavings(const std::vector& identicalEntries, - uint64_t totalSize) { - uint64_t totalEqualBytes = 0; - uint64_t totalEqualFiles = 0; - for (size_t i = 0; i < identicalEntries.size(); i++) { - if (identicalEntries[i].deviceEntry != nullptr) { - totalEqualBytes += identicalEntries[i].localEntry->datasize(); - totalEqualFiles++; - } - } - double savingPercent = (totalEqualBytes * 100.0f) / totalSize; - fprintf(stderr, "Detected %" PRIu64 " equal APK entries\n", totalEqualFiles); - fprintf(stderr, "%" PRIu64 " bytes are equal out of %" PRIu64 " (%.2f%%)\n", totalEqualBytes, - totalSize, savingPercent); -} - -struct PatchEntry { - int64_t deltaFromDeviceDataStart = 0; - int64_t deviceDataOffset = 0; - int64_t deviceDataLength = 0; -}; -static void WritePatchEntry(const PatchEntry& patchEntry, borrowed_fd input, borrowed_fd output, - size_t* realSizeOut) { - if (!(patchEntry.deltaFromDeviceDataStart | patchEntry.deviceDataOffset | - patchEntry.deviceDataLength)) { - return; - } - - PatchUtils::WriteLong(patchEntry.deltaFromDeviceDataStart, output); - if (patchEntry.deltaFromDeviceDataStart > 0) { - PatchUtils::Pipe(input, output, patchEntry.deltaFromDeviceDataStart); - } - auto hostDataLength = patchEntry.deviceDataLength; - adb_lseek(input, hostDataLength, SEEK_CUR); - - PatchUtils::WriteLong(patchEntry.deviceDataOffset, output); - PatchUtils::WriteLong(patchEntry.deviceDataLength, output); - - *realSizeOut += patchEntry.deltaFromDeviceDataStart + hostDataLength; -} - -void DeployPatchGenerator::GeneratePatch(const std::vector& entriesToUseOnDevice, - const std::string& localApkPath, - const std::string& deviceApkPath, borrowed_fd output) { - unique_fd input(adb_open(localApkPath.c_str(), O_RDONLY | O_CLOEXEC)); - size_t newApkSize = adb_lseek(input, 0L, SEEK_END); - adb_lseek(input, 0L, SEEK_SET); - - // Header. - PatchUtils::WriteSignature(output); - PatchUtils::WriteLong(newApkSize, output); - PatchUtils::WriteString(deviceApkPath, output); - - size_t currentSizeOut = 0; - size_t realSizeOut = 0; - // Write data from the host upto the first entry we have that matches a device entry. Then write - // the metadata about the device entry and repeat for all entries that match on device. Finally - // write out any data left. If the device and host APKs are exactly the same this ends up - // writing out zip metadata from the local APK followed by offsets to the data to use from the - // device APK. - PatchEntry patchEntry; - for (size_t i = 0, size = entriesToUseOnDevice.size(); i < size; ++i) { - auto&& entry = entriesToUseOnDevice[i]; - int64_t hostDataOffset = entry.localEntry->dataoffset(); - int64_t hostDataLength = entry.localEntry->datasize(); - int64_t deviceDataOffset = entry.deviceEntry->dataoffset(); - // Both entries are the same, using host data length. - int64_t deviceDataLength = hostDataLength; - - int64_t deltaFromDeviceDataStart = hostDataOffset - currentSizeOut; - if (deltaFromDeviceDataStart > 0) { - WritePatchEntry(patchEntry, input, output, &realSizeOut); - patchEntry.deltaFromDeviceDataStart = deltaFromDeviceDataStart; - patchEntry.deviceDataOffset = deviceDataOffset; - patchEntry.deviceDataLength = deviceDataLength; - } else { - patchEntry.deviceDataLength += deviceDataLength; - } - - currentSizeOut += deltaFromDeviceDataStart + hostDataLength; - } - WritePatchEntry(patchEntry, input, output, &realSizeOut); - if (realSizeOut != currentSizeOut) { - fprintf(stderr, "Size mismatch current %lld vs real %lld\n", - static_cast(currentSizeOut), static_cast(realSizeOut)); - error_exit("Aborting"); - } - - if (newApkSize > currentSizeOut) { - PatchUtils::WriteLong(newApkSize - currentSizeOut, output); - PatchUtils::Pipe(input, output, newApkSize - currentSizeOut); - PatchUtils::WriteLong(0, output); - PatchUtils::WriteLong(0, output); - } -} - -bool DeployPatchGenerator::CreatePatch(const char* localApkPath, APKMetaData deviceApkMetadata, - android::base::borrowed_fd output) { - return CreatePatch(PatchUtils::GetHostAPKMetaData(localApkPath), std::move(deviceApkMetadata), - output); -} - -bool DeployPatchGenerator::CreatePatch(APKMetaData localApkMetadata, APKMetaData deviceApkMetadata, - borrowed_fd output) { - // Log metadata info. - APKMetaDataToLog(deviceApkMetadata); - APKMetaDataToLog(localApkMetadata); - - const std::string localApkPath = localApkMetadata.absolute_path(); - const std::string deviceApkPath = deviceApkMetadata.absolute_path(); - - std::vector identicalEntries; - uint64_t totalSize = - BuildIdenticalEntries(identicalEntries, localApkMetadata, deviceApkMetadata); - ReportSavings(identicalEntries, totalSize); - GeneratePatch(identicalEntries, localApkPath, deviceApkPath, output); - - return true; -} - -uint64_t DeployPatchGenerator::BuildIdenticalEntries(std::vector& outIdenticalEntries, - const APKMetaData& localApkMetadata, - const APKMetaData& deviceApkMetadata) { - outIdenticalEntries.reserve( - std::min(localApkMetadata.entries_size(), deviceApkMetadata.entries_size())); - - using md5Digest = std::pair; - struct md5Hash { - size_t operator()(const md5Digest& digest) const { - std::hash hasher; - size_t seed = 0; - seed ^= hasher(digest.first) + 0x9e3779b9 + (seed << 6) + (seed >> 2); - seed ^= hasher(digest.second) + 0x9e3779b9 + (seed << 6) + (seed >> 2); - return seed; - } - }; - static_assert(sizeof(md5Digest) == MD5_DIGEST_LENGTH); - std::unordered_map, md5Hash> deviceEntries; - for (const auto& deviceEntry : deviceApkMetadata.entries()) { - md5Digest md5; - memcpy(&md5, deviceEntry.md5().data(), deviceEntry.md5().size()); - - deviceEntries[md5].push_back(&deviceEntry); - } - - uint64_t totalSize = 0; - for (const auto& localEntry : localApkMetadata.entries()) { - totalSize += localEntry.datasize(); - - md5Digest md5; - memcpy(&md5, localEntry.md5().data(), localEntry.md5().size()); - - auto deviceEntriesIt = deviceEntries.find(md5); - if (deviceEntriesIt == deviceEntries.end()) { - continue; - } - - for (const auto* deviceEntry : deviceEntriesIt->second) { - if (deviceEntry->md5() == localEntry.md5()) { - SimpleEntry simpleEntry; - simpleEntry.localEntry = &localEntry; - simpleEntry.deviceEntry = deviceEntry; - APKEntryToLog(localEntry); - outIdenticalEntries.push_back(simpleEntry); - break; - } - } - } - std::sort(outIdenticalEntries.begin(), outIdenticalEntries.end(), - [](const SimpleEntry& lhs, const SimpleEntry& rhs) { - return lhs.localEntry->dataoffset() < rhs.localEntry->dataoffset(); - }); - return totalSize; -} diff --git a/adb/fastdeploy/deploypatchgenerator/deploy_patch_generator.h b/adb/fastdeploy/deploypatchgenerator/deploy_patch_generator.h deleted file mode 100644 index fd7eaeee9b0e6f9d69df04d1bcf73120b458dbc8..0000000000000000000000000000000000000000 --- a/adb/fastdeploy/deploypatchgenerator/deploy_patch_generator.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2019 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. - */ - -#pragma once - -#include - -#include "adb_unique_fd.h" -#include "fastdeploy/proto/ApkEntry.pb.h" - -/** - * This class is responsible for creating a patch that can be accepted by the deployagent. The - * patch format is documented in GeneratePatch. - */ -class DeployPatchGenerator { - public: - using APKEntry = com::android::fastdeploy::APKEntry; - using APKMetaData = com::android::fastdeploy::APKMetaData; - - /** - * Simple struct to hold mapping between local metadata and device metadata. - */ - struct SimpleEntry { - const APKEntry* localEntry; - const APKEntry* deviceEntry; - }; - - /** - * If |is_verbose| is true ApkEntries that are similar between device and host are written to - * the console. - */ - explicit DeployPatchGenerator(bool is_verbose) : is_verbose_(is_verbose) {} - /** - * Given a |localApkPath|, and the |deviceApkMetadata| from an installed APK this function - * writes a patch to the given |output|. - */ - bool CreatePatch(const char* localApkPath, APKMetaData deviceApkMetadata, - android::base::borrowed_fd output); - - private: - bool is_verbose_; - - /** - * Log function only logs data to stdout when |is_verbose_| is true. - */ - void Log(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))); - - /** - * Helper function to log the APKMetaData structure. If |is_verbose_| is false this function - * early outs. This function is used for debugging / information. - */ - void APKMetaDataToLog(const APKMetaData& metadata); - /** - * Helper function to log APKEntry. - */ - void APKEntryToLog(const APKEntry& entry); - - /** - * Given the |localApkMetadata| metadata, and the |deviceApkMetadata| from an installed APK this - * function writes a patch to the given |output|. - */ - bool CreatePatch(APKMetaData localApkMetadata, APKMetaData deviceApkMetadata, - android::base::borrowed_fd output); - - /** - * Helper function to report savings by fastdeploy. This function prints out savings even with - * |is_verbose_| set to false. |totalSize| is used to show a percentage of savings. Note: - * |totalSize| is the size of the ZipEntries. Not the size of the entire file. The metadata of - * the zip data needs to be sent across with every iteration. - * [Patch format] - * |Fixed String| Signature - * |long| New Size of Apk - * |Packets[]| Array of Packets - * - * [Packet Format] - * |long| Size of data to use from patch - * |byte[]| Patch data - * |long| Offset of data to use already on device - * |long| Length of data to read from device APK - * TODO(b/138306784): Move the patch format to a proto. - */ - void ReportSavings(const std::vector& identicalEntries, uint64_t totalSize); - - /** - * This enumerates each entry in |entriesToUseOnDevice| and builds a patch file copying data - * from |localApkPath| where we are unable to use entries already on the device. The new patch - * is written to |output|. The entries are expected to be sorted by data offset from lowest to - * highest. - */ - void GeneratePatch(const std::vector& entriesToUseOnDevice, - const std::string& localApkPath, const std::string& deviceApkPath, - android::base::borrowed_fd output); - - protected: - uint64_t BuildIdenticalEntries(std::vector& outIdenticalEntries, - const APKMetaData& localApkMetadata, - const APKMetaData& deviceApkMetadata); -}; diff --git a/adb/fastdeploy/deploypatchgenerator/deploy_patch_generator_test.cpp b/adb/fastdeploy/deploypatchgenerator/deploy_patch_generator_test.cpp deleted file mode 100644 index e4c96eaffa17361cc38894e834a4c779c749ac12..0000000000000000000000000000000000000000 --- a/adb/fastdeploy/deploypatchgenerator/deploy_patch_generator_test.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2019 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 "deploy_patch_generator.h" -#include "apk_archive.h" -#include "patch_utils.h" - -#include -#include -#include -#include -#include - -#include "sysdeps.h" - -using namespace com::android::fastdeploy; - -static std::string GetTestFile(const std::string& name) { - return "fastdeploy/testdata/" + name; -} - -struct TestPatchGenerator : DeployPatchGenerator { - using DeployPatchGenerator::BuildIdenticalEntries; - using DeployPatchGenerator::DeployPatchGenerator; -}; - -TEST(DeployPatchGeneratorTest, IdenticalFileEntries) { - std::string apkPath = GetTestFile("rotating_cube-release.apk"); - APKMetaData metadataA = PatchUtils::GetHostAPKMetaData(apkPath.c_str()); - TestPatchGenerator generator(false); - std::vector entries; - generator.BuildIdenticalEntries(entries, metadataA, metadataA); - // Expect the entry count to match the number of entries in the metadata. - const uint32_t identicalCount = entries.size(); - const uint32_t entriesCount = metadataA.entries_size(); - EXPECT_EQ(identicalCount, entriesCount); -} - -TEST(DeployPatchGeneratorTest, NoDeviceMetadata) { - std::string apkPath = GetTestFile("rotating_cube-release.apk"); - // Get size of our test apk. - long apkSize = 0; - { - unique_fd apkFile(adb_open(apkPath.c_str(), O_RDWR)); - apkSize = adb_lseek(apkFile, 0L, SEEK_END); - } - - // Create a patch that is 100% different. - TemporaryFile output; - DeployPatchGenerator generator(true); - generator.CreatePatch(apkPath.c_str(), {}, output.fd); - - // Expect a patch file that has a size at least the size of our initial APK. - long patchSize = adb_lseek(output.fd, 0L, SEEK_END); - EXPECT_GT(patchSize, apkSize); -} - -TEST(DeployPatchGeneratorTest, ZeroSizePatch) { - std::string apkPath = GetTestFile("rotating_cube-release.apk"); - ApkArchive archive(apkPath); - auto dump = archive.ExtractMetadata(); - EXPECT_NE(dump.cd().size(), 0u); - - APKMetaData metadata = PatchUtils::GetDeviceAPKMetaData(dump); - - // Create a patch that is 100% the same. - TemporaryFile output; - output.DoNotRemove(); - DeployPatchGenerator generator(true); - generator.CreatePatch(apkPath.c_str(), metadata, output.fd); - - // Expect a patch file that is smaller than 0.5K. - int64_t patchSize = adb_lseek(output.fd, 0L, SEEK_END); - EXPECT_LE(patchSize, 512); -} diff --git a/adb/fastdeploy/deploypatchgenerator/patch_utils.cpp b/adb/fastdeploy/deploypatchgenerator/patch_utils.cpp deleted file mode 100644 index 2b00c80164dc092d7055515fd7cdbc777f42d8a0..0000000000000000000000000000000000000000 --- a/adb/fastdeploy/deploypatchgenerator/patch_utils.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (C) 2019 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 "patch_utils.h" - -#include - -#include "adb_io.h" -#include "adb_utils.h" -#include "android-base/endian.h" -#include "sysdeps.h" - -#include "apk_archive.h" - -using namespace com::android; -using namespace com::android::fastdeploy; -using namespace android::base; - -static constexpr char kSignature[] = "FASTDEPLOY"; - -APKMetaData PatchUtils::GetDeviceAPKMetaData(const APKDump& apk_dump) { - APKMetaData apkMetaData; - apkMetaData.set_absolute_path(apk_dump.absolute_path()); - - std::string md5Hash; - int64_t localFileHeaderOffset; - int64_t dataSize; - - const auto& cd = apk_dump.cd(); - auto cur = cd.data(); - int64_t size = cd.size(); - while (auto consumed = ApkArchive::ParseCentralDirectoryRecord( - cur, size, &md5Hash, &localFileHeaderOffset, &dataSize)) { - cur += consumed; - size -= consumed; - - auto apkEntry = apkMetaData.add_entries(); - apkEntry->set_md5(md5Hash); - apkEntry->set_dataoffset(localFileHeaderOffset); - apkEntry->set_datasize(dataSize); - } - return apkMetaData; -} - -APKMetaData PatchUtils::GetHostAPKMetaData(const char* apkPath) { - ApkArchive archive(apkPath); - auto dump = archive.ExtractMetadata(); - if (dump.cd().empty()) { - fprintf(stderr, "adb: Could not extract Central Directory from %s\n", apkPath); - error_exit("Aborting"); - } - - auto apkMetaData = GetDeviceAPKMetaData(dump); - - // Now let's set data sizes. - for (auto& apkEntry : *apkMetaData.mutable_entries()) { - auto dataSize = - archive.CalculateLocalFileEntrySize(apkEntry.dataoffset(), apkEntry.datasize()); - if (dataSize == 0) { - error_exit("Aborting"); - } - apkEntry.set_datasize(dataSize); - } - - return apkMetaData; -} - -void PatchUtils::WriteSignature(borrowed_fd output) { - WriteFdExactly(output, kSignature, sizeof(kSignature) - 1); -} - -void PatchUtils::WriteLong(int64_t value, borrowed_fd output) { - int64_t littleEndian = htole64(value); - WriteFdExactly(output, &littleEndian, sizeof(littleEndian)); -} - -void PatchUtils::WriteString(const std::string& value, android::base::borrowed_fd output) { - WriteLong(value.size(), output); - WriteFdExactly(output, value); -} - -void PatchUtils::Pipe(borrowed_fd input, borrowed_fd output, size_t amount) { - constexpr static size_t BUFFER_SIZE = 128 * 1024; - char buffer[BUFFER_SIZE]; - size_t transferAmount = 0; - while (transferAmount != amount) { - auto chunkAmount = std::min(amount - transferAmount, BUFFER_SIZE); - auto readAmount = adb_read(input, buffer, chunkAmount); - if (readAmount < 0) { - fprintf(stderr, "adb: failed to read from input: %s\n", strerror(errno)); - error_exit("Aborting"); - } - WriteFdExactly(output, buffer, readAmount); - transferAmount += readAmount; - } -} diff --git a/adb/fastdeploy/deploypatchgenerator/patch_utils.h b/adb/fastdeploy/deploypatchgenerator/patch_utils.h deleted file mode 100644 index 8dc9b9cb2a617bca0fa184835e1c753ccb0c8ff3..0000000000000000000000000000000000000000 --- a/adb/fastdeploy/deploypatchgenerator/patch_utils.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2019 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. - */ - -#pragma once - -#include "adb_unique_fd.h" -#include "fastdeploy/proto/ApkEntry.pb.h" - -/** - * Helper class that mirrors the PatchUtils from deploy agent. - */ -class PatchUtils { - public: - /** - * This function takes the dump of Central Directly and builds the APKMetaData required by the - * patching algorithm. The if this function has an error a string is printed to the terminal and - * exit(1) is called. - */ - static com::android::fastdeploy::APKMetaData GetDeviceAPKMetaData( - const com::android::fastdeploy::APKDump& apk_dump); - /** - * This function takes a local APK file and builds the APKMetaData required by the patching - * algorithm. The if this function has an error a string is printed to the terminal and exit(1) - * is called. - */ - static com::android::fastdeploy::APKMetaData GetHostAPKMetaData(const char* file); - /** - * Writes a fixed signature string to the header of the patch. - */ - static void WriteSignature(android::base::borrowed_fd output); - /** - * Writes an int64 to the |output| reversing the bytes. - */ - static void WriteLong(int64_t value, android::base::borrowed_fd output); - /** - * Writes string to the |output|. - */ - static void WriteString(const std::string& value, android::base::borrowed_fd output); - /** - * Copy |amount| of data from |input| to |output|. - */ - static void Pipe(android::base::borrowed_fd input, android::base::borrowed_fd output, - size_t amount); -}; diff --git a/adb/fastdeploy/deploypatchgenerator/patch_utils_test.cpp b/adb/fastdeploy/deploypatchgenerator/patch_utils_test.cpp deleted file mode 100644 index 3ec5ab3e0cdb16576fc0e4115b73da5ae4dce0c7..0000000000000000000000000000000000000000 --- a/adb/fastdeploy/deploypatchgenerator/patch_utils_test.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2019 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 "patch_utils.h" - -#include -#include -#include -#include -#include -#include - -#include - -#include "adb_io.h" -#include "sysdeps.h" - -using namespace com::android::fastdeploy; -using google::protobuf::util::MessageDifferencer; - -static std::string GetTestFile(const std::string& name) { - return "fastdeploy/testdata/" + name; -} - -bool FileMatchesContent(android::base::borrowed_fd input, const char* contents, - ssize_t contentsSize) { - adb_lseek(input, 0, SEEK_SET); - // Use a temp buffer larger than any test contents. - constexpr int BUFFER_SIZE = 2048; - char buffer[BUFFER_SIZE]; - bool result = true; - // Validate size of files is equal. - ssize_t readAmount = adb_read(input, buffer, BUFFER_SIZE); - EXPECT_EQ(readAmount, contentsSize); - result = memcmp(buffer, contents, readAmount) == 0; - for (int i = 0; i < readAmount; i++) { - printf("%x", buffer[i]); - } - printf(" == "); - for (int i = 0; i < contentsSize; i++) { - printf("%x", contents[i]); - } - printf("\n"); - - return result; -} - -TEST(PatchUtilsTest, SwapLongWrites) { - TemporaryFile output; - PatchUtils::WriteLong(0x0011223344556677, output.fd); - adb_lseek(output.fd, 0, SEEK_SET); - const char expected[] = {0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00}; - EXPECT_TRUE(FileMatchesContent(output.fd, expected, 8)); -} - -TEST(PatchUtilsTest, PipeWritesAmountToOutput) { - std::string expected("Some Data"); - TemporaryFile input; - TemporaryFile output; - // Populate input file. - WriteFdExactly(input.fd, expected); - adb_lseek(input.fd, 0, SEEK_SET); - // Open input file for read, and output file for write. - PatchUtils::Pipe(input.fd, output.fd, expected.size()); - // Validate pipe worked - EXPECT_TRUE(FileMatchesContent(output.fd, expected.c_str(), expected.size())); -} - -TEST(PatchUtilsTest, SignatureConstMatches) { - std::string apkFile = GetTestFile("rotating_cube-release.apk"); - TemporaryFile output; - PatchUtils::WriteSignature(output.fd); - std::string contents("FASTDEPLOY"); - EXPECT_TRUE(FileMatchesContent(output.fd, contents.c_str(), contents.size())); -} - -TEST(PatchUtilsTest, GatherMetadata) { - std::string apkFile = GetTestFile("rotating_cube-release.apk"); - APKMetaData actual = PatchUtils::GetHostAPKMetaData(apkFile.c_str()); - - std::string expectedMetadata; - android::base::ReadFileToString(GetTestFile("rotating_cube-metadata-release.data"), - &expectedMetadata); - APKMetaData expected; - EXPECT_TRUE(expected.ParseFromString(expectedMetadata)); - - // Test paths might vary. - expected.set_absolute_path(actual.absolute_path()); - - std::string actualMetadata; - actual.SerializeToString(&actualMetadata); - - expected.SerializeToString(&expectedMetadata); - - EXPECT_EQ(expectedMetadata, actualMetadata); -} - -static inline void sanitize(APKMetaData& metadata) { - metadata.clear_absolute_path(); - for (auto&& entry : *metadata.mutable_entries()) { - entry.clear_datasize(); - } -} - -TEST(PatchUtilsTest, GatherDumpMetadata) { - APKMetaData hostMetadata; - APKMetaData deviceMetadata; - - hostMetadata = PatchUtils::GetHostAPKMetaData(GetTestFile("sample.apk").c_str()); - - { - std::string cd; - android::base::ReadFileToString(GetTestFile("sample.cd"), &cd); - - APKDump dump; - dump.set_cd(std::move(cd)); - - deviceMetadata = PatchUtils::GetDeviceAPKMetaData(dump); - } - - sanitize(hostMetadata); - sanitize(deviceMetadata); - - std::string expectedMetadata; - hostMetadata.SerializeToString(&expectedMetadata); - - std::string actualMetadata; - deviceMetadata.SerializeToString(&actualMetadata); - - EXPECT_EQ(expectedMetadata, actualMetadata); -} diff --git a/adb/fastdeploy/proto/ApkEntry.proto b/adb/fastdeploy/proto/ApkEntry.proto deleted file mode 100644 index d84c5a54e0a510301704e0de860d8bf9f5f713d3..0000000000000000000000000000000000000000 --- a/adb/fastdeploy/proto/ApkEntry.proto +++ /dev/null @@ -1,26 +0,0 @@ -syntax = "proto3"; - -package com.android.fastdeploy; - -option java_package = "com.android.fastdeploy"; -option java_outer_classname = "ApkEntryProto"; -option java_multiple_files = true; -option optimize_for = LITE_RUNTIME; - -message APKDump { - string name = 1; - bytes cd = 2; - bytes signature = 3; - string absolute_path = 4; -} - -message APKEntry { - bytes md5 = 1; - int64 dataOffset = 2; - int64 dataSize = 3; -} - -message APKMetaData { - string absolute_path = 1; - repeated APKEntry entries = 2; -} diff --git a/adb/fastdeploy/testdata/helloworld5.apk b/adb/fastdeploy/testdata/helloworld5.apk deleted file mode 100644 index 4a1539ecdc4ef0408a14ea2aa40d4aef3ba4f50f..0000000000000000000000000000000000000000 Binary files a/adb/fastdeploy/testdata/helloworld5.apk and /dev/null differ diff --git a/adb/fastdeploy/testdata/helloworld7.apk b/adb/fastdeploy/testdata/helloworld7.apk deleted file mode 100644 index 82c46df80e6840564ffc8e69588289a388271465..0000000000000000000000000000000000000000 Binary files a/adb/fastdeploy/testdata/helloworld7.apk and /dev/null differ diff --git a/adb/fastdeploy/testdata/rotating_cube-metadata-release.data b/adb/fastdeploy/testdata/rotating_cube-metadata-release.data deleted file mode 100644 index 52352ff71287154a77a861bcc7ee7238fcd863c3..0000000000000000000000000000000000000000 --- a/adb/fastdeploy/testdata/rotating_cube-metadata-release.data +++ /dev/null @@ -1,8 +0,0 @@ - --fastdeploy/testdata/rotating_cube-release.apk -ìv4@obO#&kýn• -K›• 3Qcp^<Ð̽sF0•ƒ -xB ™a­©–2áÒ_O'˜¨ -¶ÅhsêÃDÍY -ª^"cvÀ ÓQ -qžp¶Îó{2ÐÄÒÙ«ÂÁàQç \ No newline at end of file diff --git a/adb/fastdeploy/testdata/rotating_cube-release.apk b/adb/fastdeploy/testdata/rotating_cube-release.apk deleted file mode 100644 index d47e0ea07f695398c937efab4a86b6857cddc657..0000000000000000000000000000000000000000 Binary files a/adb/fastdeploy/testdata/rotating_cube-release.apk and /dev/null differ diff --git a/adb/fastdeploy/testdata/sample.apk b/adb/fastdeploy/testdata/sample.apk deleted file mode 100644 index c31620572b89dde0c761d9c14c06431fa9b94d52..0000000000000000000000000000000000000000 Binary files a/adb/fastdeploy/testdata/sample.apk and /dev/null differ diff --git a/adb/fastdeploy/testdata/sample.cd b/adb/fastdeploy/testdata/sample.cd deleted file mode 100644 index 5e5b4d4c83f6e6781bca696503a0762caa860e85..0000000000000000000000000000000000000000 Binary files a/adb/fastdeploy/testdata/sample.cd and /dev/null differ diff --git a/adb/fdevent/fdevent.cpp b/adb/fdevent/fdevent.cpp deleted file mode 100644 index fd550200f3671affaedbef7e8835b6bd4c1e77b0..0000000000000000000000000000000000000000 --- a/adb/fdevent/fdevent.cpp +++ /dev/null @@ -1,262 +0,0 @@ -/* - * 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. - */ - -#define TRACE_TAG FDEVENT - -#include "sysdeps.h" - -#include - -#include -#include -#include - -#include "adb_utils.h" -#include "fdevent.h" -#include "fdevent_epoll.h" -#include "fdevent_poll.h" - -using namespace std::chrono_literals; -using std::chrono::duration_cast; - -void invoke_fde(struct fdevent* fde, unsigned events) { - if (auto f = std::get_if(&fde->func)) { - (*f)(fde->fd.get(), events, fde->arg); - } else if (auto f = std::get_if(&fde->func)) { - (*f)(fde, events, fde->arg); - } else { - __builtin_unreachable(); - } -} - -std::string dump_fde(const fdevent* fde) { - std::string state; - if (fde->state & FDE_READ) { - state += "R"; - } - if (fde->state & FDE_WRITE) { - state += "W"; - } - if (fde->state & FDE_ERROR) { - state += "E"; - } - return android::base::StringPrintf("(fdevent %" PRIu64 ": fd %d %s)", fde->id, fde->fd.get(), - state.c_str()); -} - -fdevent* fdevent_context::Create(unique_fd fd, std::variant func, void* arg) { - CheckMainThread(); - CHECK_GE(fd.get(), 0); - - int fd_num = fd.get(); - - auto [it, inserted] = this->installed_fdevents_.emplace(fd_num, fdevent{}); - CHECK(inserted); - - fdevent* fde = &it->second; - fde->id = fdevent_id_++; - fde->state = 0; - fde->fd = std::move(fd); - fde->func = func; - fde->arg = arg; - if (!set_file_block_mode(fde->fd, false)) { - // Here is not proper to handle the error. If it fails here, some error is - // likely to be detected by poll(), then we can let the callback function - // to handle it. - LOG(ERROR) << "failed to set non-blocking mode for fd " << fde->fd.get(); - } - - this->Register(fde); - return fde; -} - -unique_fd fdevent_context::Destroy(fdevent* fde) { - CheckMainThread(); - if (!fde) { - return {}; - } - - this->Unregister(fde); - - unique_fd fd = std::move(fde->fd); - - auto erased = this->installed_fdevents_.erase(fd.get()); - CHECK_EQ(1UL, erased); - - return fd; -} - -void fdevent_context::Add(fdevent* fde, unsigned events) { - CHECK(!(events & FDE_TIMEOUT)); - Set(fde, fde->state | events); -} - -void fdevent_context::Del(fdevent* fde, unsigned events) { - CHECK(!(events & FDE_TIMEOUT)); - Set(fde, fde->state & ~events); -} - -void fdevent_context::SetTimeout(fdevent* fde, std::optional timeout) { - CheckMainThread(); - fde->timeout = timeout; - fde->last_active = std::chrono::steady_clock::now(); -} - -std::optional fdevent_context::CalculatePollDuration() { - std::optional result = std::nullopt; - auto now = std::chrono::steady_clock::now(); - CheckMainThread(); - - for (const auto& [fd, fde] : this->installed_fdevents_) { - UNUSED(fd); - auto timeout_opt = fde.timeout; - if (timeout_opt) { - auto deadline = fde.last_active + *timeout_opt; - auto time_left = duration_cast(deadline - now); - if (time_left < 0ms) { - time_left = 0ms; - } - - if (!result) { - result = time_left; - } else { - result = std::min(*result, time_left); - } - } - } - - return result; -} - -void fdevent_context::HandleEvents(const std::vector& events) { - for (const auto& event : events) { - invoke_fde(event.fde, event.events); - } - FlushRunQueue(); -} - -void fdevent_context::FlushRunQueue() { - // We need to be careful around reentrancy here, since a function we call can queue up another - // function. - while (true) { - std::function fn; - { - std::lock_guard lock(this->run_queue_mutex_); - if (this->run_queue_.empty()) { - break; - } - fn = std::move(this->run_queue_.front()); - this->run_queue_.pop_front(); - } - fn(); - } -} - -void fdevent_context::CheckMainThread() { - if (main_thread_id_) { - CHECK_EQ(*main_thread_id_, android::base::GetThreadId()); - } -} - -void fdevent_context::Run(std::function fn) { - { - std::lock_guard lock(run_queue_mutex_); - run_queue_.push_back(std::move(fn)); - } - - Interrupt(); -} - -void fdevent_context::TerminateLoop() { - terminate_loop_ = true; - Interrupt(); -} - -static std::unique_ptr fdevent_create_context() { -#if defined(__linux__) - return std::make_unique(); -#else - return std::make_unique(); -#endif -} - -static auto& g_ambient_fdevent_context() { - static auto context = fdevent_create_context().release(); - return context; -} - -static fdevent_context* fdevent_get_ambient() { - return g_ambient_fdevent_context(); -} - -fdevent* fdevent_create(int fd, fd_func func, void* arg) { - unique_fd ufd(fd); - return fdevent_get_ambient()->Create(std::move(ufd), func, arg); -} - -fdevent* fdevent_create(int fd, fd_func2 func, void* arg) { - unique_fd ufd(fd); - return fdevent_get_ambient()->Create(std::move(ufd), func, arg); -} - -unique_fd fdevent_release(fdevent* fde) { - return fdevent_get_ambient()->Destroy(fde); -} - -void fdevent_destroy(fdevent* fde) { - fdevent_get_ambient()->Destroy(fde); -} - -void fdevent_set(fdevent* fde, unsigned events) { - fdevent_get_ambient()->Set(fde, events); -} - -void fdevent_add(fdevent* fde, unsigned events) { - fdevent_get_ambient()->Add(fde, events); -} - -void fdevent_del(fdevent* fde, unsigned events) { - fdevent_get_ambient()->Del(fde, events); -} - -void fdevent_set_timeout(fdevent* fde, std::optional timeout) { - fdevent_get_ambient()->SetTimeout(fde, timeout); -} - -void fdevent_run_on_main_thread(std::function fn) { - fdevent_get_ambient()->Run(std::move(fn)); -} - -void fdevent_loop() { - fdevent_get_ambient()->Loop(); -} - -void check_main_thread() { - fdevent_get_ambient()->CheckMainThread(); -} - -void fdevent_terminate_loop() { - fdevent_get_ambient()->TerminateLoop(); -} - -size_t fdevent_installed_count() { - return fdevent_get_ambient()->InstalledCount(); -} - -void fdevent_reset() { - auto old = std::exchange(g_ambient_fdevent_context(), fdevent_create_context().release()); - delete old; -} diff --git a/adb/fdevent/fdevent.h b/adb/fdevent/fdevent.h deleted file mode 100644 index 9fc3b2c0c7d7452983a21a6103e8ea03fdac12f3..0000000000000000000000000000000000000000 --- a/adb/fdevent/fdevent.h +++ /dev/null @@ -1,160 +0,0 @@ -/* - * 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 -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "adb_unique_fd.h" - -// Events that may be observed -#define FDE_READ 0x0001 -#define FDE_WRITE 0x0002 -#define FDE_ERROR 0x0004 -#define FDE_TIMEOUT 0x0008 - -struct fdevent; - -typedef void (*fd_func)(int fd, unsigned events, void *userdata); -typedef void (*fd_func2)(struct fdevent* fde, unsigned events, void* userdata); - -void invoke_fde(struct fdevent* fde, unsigned events); -std::string dump_fde(const fdevent* fde); - -struct fdevent_event { - fdevent* fde; - unsigned events; -}; - -struct fdevent final { - uint64_t id; - - unique_fd fd; - int force_eof = 0; - - uint16_t state = 0; - std::optional timeout; - std::chrono::steady_clock::time_point last_active; - - std::variant func; - void* arg = nullptr; -}; - -struct fdevent_context { - public: - virtual ~fdevent_context() = default; - - // Allocate and initialize a new fdevent object. - fdevent* Create(unique_fd fd, std::variant func, void* arg); - - // Deallocate an fdevent object, returning the file descriptor that was owned by it. - // Note that this calls Set, which is a virtual method, so destructors that call this must be - // final. - unique_fd Destroy(fdevent* fde); - - protected: - virtual void Register(fdevent*) {} - virtual void Unregister(fdevent*) {} - - public: - // Change which events should cause notifications. - virtual void Set(fdevent* fde, unsigned events) = 0; - void Add(fdevent* fde, unsigned events); - void Del(fdevent* fde, unsigned events); - - // Set a timeout on an fdevent. - // If no events are triggered by the timeout, an FDE_TIMEOUT will be generated. - // Note timeouts are not defused automatically; if a timeout is set on an fdevent, it will - // trigger repeatedly every |timeout| ms. - void SetTimeout(fdevent* fde, std::optional timeout); - - protected: - std::optional CalculatePollDuration(); - void HandleEvents(const std::vector& events); - - private: - // Run all pending functions enqueued via Run(). - void FlushRunQueue() EXCLUDES(run_queue_mutex_); - - public: - // Loop until TerminateLoop is called, handling events. - // Implementations should call FlushRunQueue on every iteration, and check the value of - // terminate_loop_ to determine whether to stop. - virtual void Loop() = 0; - - // Assert that the caller is either running on the context's main thread, or that there is no - // active main thread. - void CheckMainThread(); - - // Queue an operation to be run on the main thread. - void Run(std::function fn); - - // Test-only functionality: - void TerminateLoop(); - virtual size_t InstalledCount() = 0; - - protected: - // Interrupt the run loop. - virtual void Interrupt() = 0; - - std::optional main_thread_id_ = std::nullopt; - std::atomic terminate_loop_ = false; - - protected: - std::unordered_map installed_fdevents_; - - private: - uint64_t fdevent_id_ = 0; - std::mutex run_queue_mutex_; - std::deque> run_queue_ GUARDED_BY(run_queue_mutex_); -}; - -// Backwards compatibility shims that forward to the global fdevent_context. -fdevent* fdevent_create(int fd, fd_func func, void* arg); -fdevent* fdevent_create(int fd, fd_func2 func, void* arg); - -unique_fd fdevent_release(fdevent* fde); -void fdevent_destroy(fdevent* fde); - -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, std::optional timeout); -void fdevent_loop(); -void check_main_thread(); - -// Queue an operation to run on the main thread. -void fdevent_run_on_main_thread(std::function fn); - -// The following functions are used only for tests. -void fdevent_terminate_loop(); -size_t fdevent_installed_count(); -void fdevent_reset(); - -#endif diff --git a/adb/fdevent/fdevent_epoll.cpp b/adb/fdevent/fdevent_epoll.cpp deleted file mode 100644 index 4ef41d1eee5e3f7982ea15a6e923ef98c0194dd1..0000000000000000000000000000000000000000 --- a/adb/fdevent/fdevent_epoll.cpp +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (C) 2019 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 "fdevent_epoll.h" - -#if defined(__linux__) - -#include -#include - -#include -#include - -#include "adb_unique_fd.h" -#include "fdevent.h" - -static void fdevent_interrupt(int fd, unsigned, void*) { - uint64_t buf; - ssize_t rc = TEMP_FAILURE_RETRY(adb_read(fd, &buf, sizeof(buf))); - if (rc == -1) { - PLOG(FATAL) << "failed to read from fdevent interrupt fd"; - } -} - -fdevent_context_epoll::fdevent_context_epoll() { - epoll_fd_.reset(epoll_create1(EPOLL_CLOEXEC)); - - unique_fd interrupt_fd(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); - if (interrupt_fd == -1) { - PLOG(FATAL) << "failed to create fdevent interrupt eventfd"; - } - - unique_fd interrupt_fd_dup(fcntl(interrupt_fd.get(), F_DUPFD_CLOEXEC, 3)); - if (interrupt_fd_dup == -1) { - PLOG(FATAL) << "failed to dup fdevent interrupt eventfd"; - } - - this->interrupt_fd_ = std::move(interrupt_fd_dup); - fdevent* fde = this->Create(std::move(interrupt_fd), fdevent_interrupt, nullptr); - CHECK(fde != nullptr); - this->Add(fde, FDE_READ); -} - -fdevent_context_epoll::~fdevent_context_epoll() { - // Destroy calls virtual methods, but this class is final, so that's okay. - this->Destroy(this->interrupt_fde_); -} - -static epoll_event calculate_epoll_event(fdevent* fde) { - epoll_event result; - result.events = 0; - if (fde->state & FDE_READ) { - result.events |= EPOLLIN; - } - if (fde->state & FDE_WRITE) { - result.events |= EPOLLOUT; - } - if (fde->state & FDE_ERROR) { - result.events |= EPOLLERR; - } - result.events |= EPOLLRDHUP; - result.data.ptr = fde; - return result; -} - -void fdevent_context_epoll::Register(fdevent* fde) { - epoll_event ev = calculate_epoll_event(fde); - if (epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, fde->fd.get(), &ev) != 0) { - PLOG(FATAL) << "failed to register fd " << fde->fd.get() << " with epoll"; - } -} - -void fdevent_context_epoll::Unregister(fdevent* fde) { - if (epoll_ctl(epoll_fd_.get(), EPOLL_CTL_DEL, fde->fd.get(), nullptr) != 0) { - PLOG(FATAL) << "failed to unregister fd " << fde->fd.get() << " with epoll"; - } -} - -void fdevent_context_epoll::Set(fdevent* fde, unsigned events) { - unsigned previous_state = fde->state; - fde->state = events; - - // If the state is the same, or only differed by FDE_TIMEOUT, we don't need to modify epoll. - if ((previous_state & ~FDE_TIMEOUT) == (events & ~FDE_TIMEOUT)) { - return; - } - - epoll_event ev = calculate_epoll_event(fde); - if (epoll_ctl(epoll_fd_.get(), EPOLL_CTL_MOD, fde->fd.get(), &ev) != 0) { - PLOG(FATAL) << "failed to modify fd " << fde->fd.get() << " with epoll"; - } -} - -void fdevent_context_epoll::Loop() { - main_thread_id_ = android::base::GetThreadId(); - - std::vector fde_events; - std::vector epoll_events; - epoll_events.resize(this->installed_fdevents_.size()); - - while (true) { - if (terminate_loop_) { - break; - } - - int rc = -1; - while (rc == -1) { - std::optional timeout = CalculatePollDuration(); - int timeout_ms; - if (!timeout) { - timeout_ms = -1; - } else { - timeout_ms = timeout->count(); - } - - rc = epoll_wait(epoll_fd_.get(), epoll_events.data(), epoll_events.size(), timeout_ms); - if (rc == -1 && errno != EINTR) { - PLOG(FATAL) << "epoll_wait failed"; - } - } - - auto post_poll = std::chrono::steady_clock::now(); - std::unordered_map event_map; - for (int i = 0; i < rc; ++i) { - fdevent* fde = static_cast(epoll_events[i].data.ptr); - - unsigned events = 0; - if (epoll_events[i].events & EPOLLIN) { - CHECK(fde->state & FDE_READ); - events |= FDE_READ; - } - if (epoll_events[i].events & EPOLLOUT) { - CHECK(fde->state & FDE_WRITE); - events |= FDE_WRITE; - } - if (epoll_events[i].events & (EPOLLERR | EPOLLHUP | EPOLLRDHUP)) { - // We fake a read, as the rest of the code assumes that errors will - // be detected at that point. - events |= FDE_READ | FDE_ERROR; - } - - event_map[fde] = events; - } - - for (auto& [fd, fde] : installed_fdevents_) { - unsigned events = 0; - if (auto it = event_map.find(&fde); it != event_map.end()) { - events = it->second; - } - - if (events == 0) { - if (fde.timeout) { - auto deadline = fde.last_active + *fde.timeout; - if (deadline < post_poll) { - events |= FDE_TIMEOUT; - } - } - } - - if (events != 0) { - LOG(DEBUG) << dump_fde(&fde) << " got events " << std::hex << std::showbase - << events; - fde_events.push_back({&fde, events}); - fde.last_active = post_poll; - } - } - this->HandleEvents(fde_events); - fde_events.clear(); - } - - main_thread_id_.reset(); -} - -size_t fdevent_context_epoll::InstalledCount() { - // We always have an installed fde for interrupt. - return this->installed_fdevents_.size() - 1; -} - -void fdevent_context_epoll::Interrupt() { - uint64_t i = 1; - ssize_t rc = TEMP_FAILURE_RETRY(adb_write(this->interrupt_fd_, &i, sizeof(i))); - if (rc != sizeof(i)) { - PLOG(FATAL) << "failed to write to fdevent interrupt eventfd"; - } -} - -#endif // defined(__linux__) diff --git a/adb/fdevent/fdevent_epoll.h b/adb/fdevent/fdevent_epoll.h deleted file mode 100644 index 6214d2e2724276391c59f557bcb1b5052f817755..0000000000000000000000000000000000000000 --- a/adb/fdevent/fdevent_epoll.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -/* - * Copyright (C) 2019 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. - */ - -#if defined(__linux__) - -#include "sysdeps.h" - -#include - -#include -#include -#include -#include - -#include - -#include "adb_unique_fd.h" -#include "fdevent.h" - -struct fdevent_context_epoll final : public fdevent_context { - fdevent_context_epoll(); - virtual ~fdevent_context_epoll(); - - virtual void Register(fdevent* fde) final; - virtual void Unregister(fdevent* fde) final; - - virtual void Set(fdevent* fde, unsigned events) final; - - virtual void Loop() final; - size_t InstalledCount() final; - - protected: - virtual void Interrupt() final; - - private: - unique_fd epoll_fd_; - unique_fd interrupt_fd_; - fdevent* interrupt_fde_ = nullptr; -}; - -#endif // defined(__linux__) diff --git a/adb/fdevent/fdevent_poll.cpp b/adb/fdevent/fdevent_poll.cpp deleted file mode 100644 index ac86c08e18875289197907689bab10b1ba3971c7..0000000000000000000000000000000000000000 --- a/adb/fdevent/fdevent_poll.cpp +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright (C) 2019 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 FDEVENT - -#include "sysdeps.h" -#include "fdevent_poll.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "adb_io.h" -#include "adb_trace.h" -#include "adb_unique_fd.h" -#include "adb_utils.h" -#include "fdevent.h" -#include "sysdeps/chrono.h" - -static void fdevent_interrupt(int fd, unsigned, void*) { - char buf[BUFSIZ]; - ssize_t rc = TEMP_FAILURE_RETRY(adb_read(fd, buf, sizeof(buf))); - if (rc == -1) { - PLOG(FATAL) << "failed to read from fdevent interrupt fd"; - } -} - -fdevent_context_poll::fdevent_context_poll() { - int s[2]; - if (adb_socketpair(s) != 0) { - PLOG(FATAL) << "failed to create fdevent interrupt socketpair"; - } - - if (!set_file_block_mode(s[0], false) || !set_file_block_mode(s[1], false)) { - PLOG(FATAL) << "failed to make fdevent interrupt socket nonblocking"; - } - - this->interrupt_fd_.reset(s[0]); - fdevent* fde = this->Create(unique_fd(s[1]), fdevent_interrupt, nullptr); - CHECK(fde != nullptr); - this->Add(fde, FDE_READ); -} - -fdevent_context_poll::~fdevent_context_poll() { - // Destroy calls virtual methods, but this class is final, so that's okay. - this->Destroy(this->interrupt_fde_); -} - -void fdevent_context_poll::Set(fdevent* fde, unsigned events) { - CheckMainThread(); - fde->state = events; - D("fdevent_set: %s, events = %u", dump_fde(fde).c_str(), events); -} - -static std::string dump_pollfds(const std::vector& pollfds) { - std::string result; - for (const auto& pollfd : pollfds) { - std::string op; - if (pollfd.events & POLLIN) { - op += "R"; - } - if (pollfd.events & POLLOUT) { - op += "W"; - } - android::base::StringAppendF(&result, " %d(%s)", pollfd.fd, op.c_str()); - } - return result; -} - -void fdevent_context_poll::Loop() { - main_thread_id_ = android::base::GetThreadId(); - - std::vector pollfds; - std::vector poll_events; - - while (true) { - if (terminate_loop_) { - break; - } - - D("--- --- waiting for events"); - pollfds.clear(); - for (const auto& [fd, fde] : this->installed_fdevents_) { - adb_pollfd pfd; - pfd.fd = fd; - pfd.events = 0; - if (fde.state & FDE_READ) { - pfd.events |= POLLIN; - } - if (fde.state & FDE_WRITE) { - pfd.events |= POLLOUT; - } - if (fde.state & FDE_ERROR) { - pfd.events |= POLLERR; - } -#if defined(__linux__) - pfd.events |= POLLRDHUP; -#endif - pfd.revents = 0; - pollfds.push_back(pfd); - } - CHECK_GT(pollfds.size(), 0u); - D("poll(), pollfds = %s", dump_pollfds(pollfds).c_str()); - - std::optional timeout = CalculatePollDuration(); - int timeout_ms; - if (!timeout) { - timeout_ms = -1; - } else { - timeout_ms = timeout->count(); - } - - int ret = adb_poll(pollfds.data(), pollfds.size(), timeout_ms); - if (ret == -1) { - PLOG(ERROR) << "poll(), ret = " << ret; - return; - } - - auto post_poll = std::chrono::steady_clock::now(); - - for (const auto& pollfd : pollfds) { - unsigned events = 0; - if (pollfd.revents & POLLIN) { - events |= FDE_READ; - } - if (pollfd.revents & POLLOUT) { - events |= FDE_WRITE; - } - if (pollfd.revents & (POLLERR | POLLHUP | POLLNVAL)) { - // We fake a read, as the rest of the code assumes that errors will - // be detected at that point. - events |= FDE_READ | FDE_ERROR; - } -#if defined(__linux__) - if (pollfd.revents & POLLRDHUP) { - events |= FDE_READ | FDE_ERROR; - } -#endif - - auto it = this->installed_fdevents_.find(pollfd.fd); - CHECK(it != this->installed_fdevents_.end()); - fdevent* fde = &it->second; - - if (events == 0) { - if (fde->timeout) { - auto deadline = fde->last_active + *fde->timeout; - if (deadline < post_poll) { - events |= FDE_TIMEOUT; - } - } - } - - if (events != 0) { - D("%s got events %x", dump_fde(fde).c_str(), events); - poll_events.push_back({fde, events}); - fde->last_active = post_poll; - } - } - this->HandleEvents(poll_events); - poll_events.clear(); - } - - main_thread_id_.reset(); -} - -size_t fdevent_context_poll::InstalledCount() { - // We always have an installed fde for interrupt. - return this->installed_fdevents_.size() - 1; -} - -void fdevent_context_poll::Interrupt() { - int rc = adb_write(this->interrupt_fd_, "", 1); - - // It's possible that we get EAGAIN here, if lots of notifications came in while handling. - if (rc == 0) { - PLOG(FATAL) << "fdevent interrupt fd was closed?"; - } else if (rc == -1 && errno != EAGAIN) { - PLOG(FATAL) << "failed to write to fdevent interrupt fd"; - } -} diff --git a/adb/fdevent/fdevent_poll.h b/adb/fdevent/fdevent_poll.h deleted file mode 100644 index 98abab2839438be74aa21c94dfcd2126d394b9c1..0000000000000000000000000000000000000000 --- a/adb/fdevent/fdevent_poll.h +++ /dev/null @@ -1,63 +0,0 @@ -#pragma once - -/* - * Copyright (C) 2019 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 "adb_unique_fd.h" -#include "fdevent.h" - -struct PollNode { - fdevent* fde; - adb_pollfd pollfd; - - explicit PollNode(fdevent* fde) : fde(fde) { - memset(&pollfd, 0, sizeof(pollfd)); - pollfd.fd = fde->fd.get(); - -#if defined(__linux__) - // Always enable POLLRDHUP, so the host server can take action when some clients disconnect. - // Then we can avoid leaving many sockets in CLOSE_WAIT state. See http://b/23314034. - pollfd.events = POLLRDHUP; -#endif - } -}; - -struct fdevent_context_poll final : public fdevent_context { - fdevent_context_poll(); - virtual ~fdevent_context_poll(); - - virtual void Set(fdevent* fde, unsigned events) final; - - virtual void Loop() final; - - virtual size_t InstalledCount() final; - - protected: - virtual void Interrupt() final; - - public: - unique_fd interrupt_fd_; - fdevent* interrupt_fde_ = nullptr; -}; diff --git a/adb/fdevent/fdevent_test.cpp b/adb/fdevent/fdevent_test.cpp deleted file mode 100644 index e06b3b3299452c9ae0c5f56ec8403684283a7293..0000000000000000000000000000000000000000 --- a/adb/fdevent/fdevent_test.cpp +++ /dev/null @@ -1,321 +0,0 @@ -/* - * Copyright (C) 2015 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 "fdevent.h" - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "adb_io.h" -#include "fdevent_test.h" - -using namespace std::chrono_literals; - -class FdHandler { - public: - FdHandler(int read_fd, int write_fd, bool use_new_callback) - : read_fd_(read_fd), write_fd_(write_fd) { - if (use_new_callback) { - read_fde_ = fdevent_create(read_fd_, FdEventNewCallback, this); - write_fde_ = fdevent_create(write_fd_, FdEventNewCallback, this); - } else { - read_fde_ = fdevent_create(read_fd_, FdEventCallback, this); - write_fde_ = fdevent_create(write_fd_, FdEventCallback, this); - } - fdevent_add(read_fde_, FDE_READ); - } - - ~FdHandler() { - fdevent_destroy(read_fde_); - fdevent_destroy(write_fde_); - } - - private: - static void FdEventCallback(int fd, unsigned events, void* userdata) { - FdHandler* handler = reinterpret_cast(userdata); - ASSERT_EQ(0u, (events & ~(FDE_READ | FDE_WRITE))) << "unexpected events: " << events; - if (events & FDE_READ) { - ASSERT_EQ(fd, handler->read_fd_); - char c; - ASSERT_EQ(1, adb_read(fd, &c, 1)); - handler->queue_.push(c); - fdevent_add(handler->write_fde_, FDE_WRITE); - } - if (events & FDE_WRITE) { - ASSERT_EQ(fd, handler->write_fd_); - ASSERT_FALSE(handler->queue_.empty()); - char c = handler->queue_.front(); - handler->queue_.pop(); - ASSERT_EQ(1, adb_write(fd, &c, 1)); - if (handler->queue_.empty()) { - fdevent_del(handler->write_fde_, FDE_WRITE); - } - } - } - - static void FdEventNewCallback(fdevent* fde, unsigned events, void* userdata) { - int fd = fde->fd.get(); - FdHandler* handler = reinterpret_cast(userdata); - ASSERT_EQ(0u, (events & ~(FDE_READ | FDE_WRITE))) << "unexpected events: " << events; - if (events & FDE_READ) { - ASSERT_EQ(fd, handler->read_fd_); - char c; - ASSERT_EQ(1, adb_read(fd, &c, 1)); - handler->queue_.push(c); - fdevent_add(handler->write_fde_, FDE_WRITE); - } - if (events & FDE_WRITE) { - ASSERT_EQ(fd, handler->write_fd_); - ASSERT_FALSE(handler->queue_.empty()); - char c = handler->queue_.front(); - handler->queue_.pop(); - ASSERT_EQ(1, adb_write(fd, &c, 1)); - if (handler->queue_.empty()) { - fdevent_del(handler->write_fde_, FDE_WRITE); - } - } - } - - private: - const int read_fd_; - const int write_fd_; - fdevent* read_fde_; - fdevent* write_fde_; - std::queue queue_; -}; - -struct ThreadArg { - int first_read_fd; - int last_write_fd; - size_t middle_pipe_count; -}; - -TEST_F(FdeventTest, fdevent_terminate) { - PrepareThread(); - TerminateThread(); -} - -TEST_F(FdeventTest, smoke) { - for (bool use_new_callback : {true, false}) { - fdevent_reset(); - const size_t PIPE_COUNT = 512; - const size_t MESSAGE_LOOP_COUNT = 10; - const std::string MESSAGE = "fdevent_test"; - int fd_pair1[2]; - int fd_pair2[2]; - ASSERT_EQ(0, adb_socketpair(fd_pair1)); - ASSERT_EQ(0, adb_socketpair(fd_pair2)); - ThreadArg thread_arg; - thread_arg.first_read_fd = fd_pair1[0]; - thread_arg.last_write_fd = fd_pair2[1]; - thread_arg.middle_pipe_count = PIPE_COUNT; - int writer = fd_pair1[1]; - int reader = fd_pair2[0]; - - PrepareThread(); - - std::vector> fd_handlers; - fdevent_run_on_main_thread([&thread_arg, &fd_handlers, use_new_callback]() { - std::vector read_fds; - std::vector write_fds; - - read_fds.push_back(thread_arg.first_read_fd); - for (size_t i = 0; i < thread_arg.middle_pipe_count; ++i) { - int fds[2]; - ASSERT_EQ(0, adb_socketpair(fds)); - read_fds.push_back(fds[0]); - write_fds.push_back(fds[1]); - } - write_fds.push_back(thread_arg.last_write_fd); - - for (size_t i = 0; i < read_fds.size(); ++i) { - fd_handlers.push_back( - std::make_unique(read_fds[i], write_fds[i], use_new_callback)); - } - }); - WaitForFdeventLoop(); - - for (size_t i = 0; i < MESSAGE_LOOP_COUNT; ++i) { - std::string read_buffer = MESSAGE; - std::string write_buffer(MESSAGE.size(), 'a'); - ASSERT_TRUE(WriteFdExactly(writer, read_buffer.c_str(), read_buffer.size())); - ASSERT_TRUE(ReadFdExactly(reader, &write_buffer[0], write_buffer.size())); - ASSERT_EQ(read_buffer, write_buffer); - } - - fdevent_run_on_main_thread([&fd_handlers]() { fd_handlers.clear(); }); - WaitForFdeventLoop(); - - TerminateThread(); - ASSERT_EQ(0, adb_close(writer)); - ASSERT_EQ(0, adb_close(reader)); - } -} - -TEST_F(FdeventTest, run_on_main_thread) { - std::vector vec; - - PrepareThread(); - - // Block the main thread for a long time while we queue our callbacks. - fdevent_run_on_main_thread([]() { - check_main_thread(); - std::this_thread::sleep_for(std::chrono::seconds(1)); - }); - - for (int i = 0; i < 1000000; ++i) { - fdevent_run_on_main_thread([i, &vec]() { - check_main_thread(); - vec.push_back(i); - }); - } - - TerminateThread(); - - ASSERT_EQ(1000000u, vec.size()); - for (int i = 0; i < 1000000; ++i) { - ASSERT_EQ(i, vec[i]); - } -} - -static std::function make_appender(std::vector* vec, int value) { - return [vec, value]() { - check_main_thread(); - if (value == 100) { - return; - } - - vec->push_back(value); - fdevent_run_on_main_thread(make_appender(vec, value + 1)); - }; -} - -TEST_F(FdeventTest, run_on_main_thread_reentrant) { - std::vector vec; - - PrepareThread(); - fdevent_run_on_main_thread(make_appender(&vec, 0)); - TerminateThread(); - - ASSERT_EQ(100u, vec.size()); - for (int i = 0; i < 100; ++i) { - ASSERT_EQ(i, vec[i]); - } -} - -TEST_F(FdeventTest, timeout) { - fdevent_reset(); - PrepareThread(); - - enum class TimeoutEvent { - read, - timeout, - done, - }; - - struct TimeoutTest { - std::vector> events; - fdevent* fde; - }; - TimeoutTest test; - - int fds[2]; - ASSERT_EQ(0, adb_socketpair(fds)); - static constexpr auto delta = 100ms; - fdevent_run_on_main_thread([&]() { - test.fde = fdevent_create(fds[0], [](fdevent* fde, unsigned events, void* arg) { - auto test = static_cast(arg); - auto now = std::chrono::steady_clock::now(); - CHECK((events & FDE_READ) ^ (events & FDE_TIMEOUT)); - TimeoutEvent event; - if ((events & FDE_READ)) { - char buf[2]; - ssize_t rc = adb_read(fde->fd.get(), buf, sizeof(buf)); - if (rc == 0) { - event = TimeoutEvent::done; - } else if (rc == 1) { - event = TimeoutEvent::read; - } else { - abort(); - } - } else if ((events & FDE_TIMEOUT)) { - event = TimeoutEvent::timeout; - } else { - abort(); - } - - CHECK_EQ(fde, test->fde); - test->events.emplace_back(event, now); - - if (event == TimeoutEvent::done) { - fdevent_destroy(fde); - } - }, &test); - fdevent_add(test.fde, FDE_READ); - fdevent_set_timeout(test.fde, delta); - }); - - ASSERT_EQ(1, adb_write(fds[1], "", 1)); - - // Timeout should happen here - std::this_thread::sleep_for(delta); - - // and another. - std::this_thread::sleep_for(delta); - - // No timeout should happen here. - std::this_thread::sleep_for(delta / 2); - adb_close(fds[1]); - - TerminateThread(); - - ASSERT_EQ(4ULL, test.events.size()); - ASSERT_EQ(TimeoutEvent::read, test.events[0].first); - ASSERT_EQ(TimeoutEvent::timeout, test.events[1].first); - ASSERT_EQ(TimeoutEvent::timeout, test.events[2].first); - ASSERT_EQ(TimeoutEvent::done, test.events[3].first); - - std::vector time_deltas; - for (size_t i = 0; i < test.events.size() - 1; ++i) { - auto before = test.events[i].second; - auto after = test.events[i + 1].second; - auto diff = std::chrono::duration_cast(after - before); - time_deltas.push_back(diff.count()); - } - - std::vector expected = { - delta.count(), - delta.count(), - delta.count() / 2, - }; - - std::vector diff; - ASSERT_EQ(time_deltas.size(), expected.size()); - for (size_t i = 0; i < time_deltas.size(); ++i) { - diff.push_back(std::abs(time_deltas[i] - expected[i])); - } - - ASSERT_LT(diff[0], delta.count() * 0.5); - ASSERT_LT(diff[1], delta.count() * 0.5); - ASSERT_LT(diff[2], delta.count() * 0.5); -} diff --git a/adb/fdevent/fdevent_test.h b/adb/fdevent/fdevent_test.h deleted file mode 100644 index ecda4da97989a65fe491552b6d93bf1b4bb1c0f0..0000000000000000000000000000000000000000 --- a/adb/fdevent/fdevent_test.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2016 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 "adb_io.h" -#include "adb_unique_fd.h" -#include "socket.h" -#include "sysdeps.h" -#include "sysdeps/chrono.h" - -static void WaitForFdeventLoop() { - // Sleep for a bit to make sure that network events have propagated. - std::this_thread::sleep_for(100ms); - - // fdevent_run_on_main_thread has a guaranteed ordering, and is guaranteed to happen after - // socket events, so as soon as our function is called, we know that we've processed all - // previous events. - std::mutex mutex; - std::condition_variable cv; - std::unique_lock lock(mutex); - fdevent_run_on_main_thread([&]() { - mutex.lock(); - mutex.unlock(); - cv.notify_one(); - }); - cv.wait(lock); -} - -class FdeventTest : public ::testing::Test { - protected: - unique_fd dummy; - - ~FdeventTest() { - if (thread_.joinable()) { - TerminateThread(); - } - } - - static void SetUpTestCase() { -#if !defined(_WIN32) - ASSERT_NE(SIG_ERR, signal(SIGPIPE, SIG_IGN)); -#endif - } - - void SetUp() override { - fdevent_reset(); - ASSERT_EQ(0u, fdevent_installed_count()); - } - - // Register a dummy socket used to wake up the fdevent loop to tell it to die. - void PrepareThread() { - int dummy_fds[2]; - if (adb_socketpair(dummy_fds) != 0) { - FAIL() << "failed to create socketpair: " << strerror(errno); - } - - asocket* dummy_socket = create_local_socket(unique_fd(dummy_fds[1])); - if (!dummy_socket) { - FAIL() << "failed to create local socket: " << strerror(errno); - } - dummy_socket->ready(dummy_socket); - dummy.reset(dummy_fds[0]); - - thread_ = std::thread([]() { fdevent_loop(); }); - WaitForFdeventLoop(); - } - - size_t GetAdditionalLocalSocketCount() { - // dummy socket installed in PrepareThread() - return 1; - } - - void TerminateThread() { - fdevent_terminate_loop(); - ASSERT_TRUE(WriteFdExactly(dummy, "", 1)); - thread_.join(); - dummy.reset(); - } - - std::thread thread_; -}; diff --git a/adb/file_sync_protocol.h b/adb/file_sync_protocol.h deleted file mode 100644 index fd9a5169e67d2168c072380b8c6c3b670e6fd52d..0000000000000000000000000000000000000000 --- a/adb/file_sync_protocol.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#define MKID(a, b, c, d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24)) - -#define ID_LSTAT_V1 MKID('S', 'T', 'A', 'T') -#define ID_STAT_V2 MKID('S', 'T', 'A', '2') -#define ID_LSTAT_V2 MKID('L', 'S', 'T', '2') - -#define ID_LIST_V1 MKID('L', 'I', 'S', 'T') -#define ID_LIST_V2 MKID('L', 'I', 'S', '2') -#define ID_DENT_V1 MKID('D', 'E', 'N', 'T') -#define ID_DENT_V2 MKID('D', 'N', 'T', '2') - -#define ID_SEND_V1 MKID('S', 'E', 'N', 'D') -#define ID_SEND_V2 MKID('S', 'N', 'D', '2') -#define ID_RECV_V1 MKID('R', 'E', 'C', 'V') -#define ID_RECV_V2 MKID('R', 'C', 'V', '2') -#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') - -struct SyncRequest { - uint32_t id; // ID_STAT, et cetera. - uint32_t path_length; // <= 1024 - // Followed by 'path_length' bytes of path (not NUL-terminated). -} __attribute__((packed)); - -struct __attribute__((packed)) sync_stat_v1 { - uint32_t id; - uint32_t mode; - uint32_t size; - uint32_t mtime; -}; - -struct __attribute__((packed)) sync_stat_v2 { - uint32_t id; - uint32_t error; - uint64_t dev; - uint64_t ino; - uint32_t mode; - uint32_t nlink; - uint32_t uid; - uint32_t gid; - uint64_t size; - int64_t atime; - int64_t mtime; - int64_t ctime; -}; - -struct __attribute__((packed)) sync_dent_v1 { - uint32_t id; - uint32_t mode; - uint32_t size; - uint32_t mtime; - uint32_t namelen; -}; // followed by `namelen` bytes of the name. - -struct __attribute__((packed)) sync_dent_v2 { - uint32_t id; - uint32_t error; - uint64_t dev; - uint64_t ino; - uint32_t mode; - uint32_t nlink; - uint32_t uid; - uint32_t gid; - uint64_t size; - int64_t atime; - int64_t mtime; - int64_t ctime; - uint32_t namelen; -}; // followed by `namelen` bytes of the name. - -enum SyncFlag : uint32_t { - kSyncFlagNone = 0, - kSyncFlagBrotli = 1, -}; - -// send_v1 sent the path in a buffer, followed by a comma and the mode as a string. -// send_v2 sends just the path in the first request, and then sends another syncmsg (with the -// same ID!) with details. -struct __attribute__((packed)) sync_send_v2 { - uint32_t id; - uint32_t mode; - uint32_t flags; -}; - -// Likewise, recv_v1 just sent the path without any accompanying data. -struct __attribute__((packed)) sync_recv_v2 { - uint32_t id; - uint32_t flags; -}; - -struct __attribute__((packed)) sync_data { - uint32_t id; - uint32_t size; -}; // followed by `size` bytes of data. - -struct __attribute__((packed)) sync_status { - uint32_t id; - uint32_t msglen; -}; // followed by `msglen` bytes of error message, if id == ID_FAIL. - -union syncmsg { - sync_stat_v1 stat_v1; - sync_stat_v2 stat_v2; - sync_dent_v1 dent_v1; - sync_dent_v2 dent_v2; - sync_data data; - sync_status status; - sync_send_v2 send_v2_setup; - sync_recv_v2 recv_v2_setup; -}; - -#define SYNC_DATA_MAX (64 * 1024) diff --git a/adb/libs/.clang-format b/adb/libs/.clang-format deleted file mode 120000 index e545823f4c2634dec65ad0a0ecbc9d8c3827aa36..0000000000000000000000000000000000000000 --- a/adb/libs/.clang-format +++ /dev/null @@ -1 +0,0 @@ -../../.clang-format-2 \ No newline at end of file diff --git a/adb/libs/adbconnection/.clang-format b/adb/libs/adbconnection/.clang-format deleted file mode 120000 index e545823f4c2634dec65ad0a0ecbc9d8c3827aa36..0000000000000000000000000000000000000000 --- a/adb/libs/adbconnection/.clang-format +++ /dev/null @@ -1 +0,0 @@ -../../.clang-format-2 \ No newline at end of file diff --git a/adb/libs/adbconnection/Android.bp b/adb/libs/adbconnection/Android.bp deleted file mode 100644 index ce2ab51ef641c8f384fc3081b91274e1bb04bdf7..0000000000000000000000000000000000000000 --- a/adb/libs/adbconnection/Android.bp +++ /dev/null @@ -1,64 +0,0 @@ -// libadbconnection -// ========================================================= -// libadbconnection_client/server implement the socket handling for jdwp -// forwarding and the track-jdwp service. -cc_library { - name: "libadbconnection_server", - srcs: ["adbconnection_server.cpp"], - - export_include_dirs: ["include"], - - stl: "libc++_static", - shared_libs: ["liblog"], - static_libs: ["libbase"], - - defaults: ["adbd_defaults", "host_adbd_supported"], - - // Avoid getting duplicate symbol of android::build::GetBuildNumber(). - use_version_lib: false, - - recovery_available: true, - apex_available: [ - "com.android.adbd", - // TODO(b/151398197) remove the below - "//apex_available:platform", - ], - compile_multilib: "both", -} - -cc_library { - name: "libadbconnection_client", - srcs: ["adbconnection_client.cpp"], - - export_include_dirs: ["include"], - - stl: "libc++_static", - shared_libs: ["liblog"], - static_libs: ["libbase"], - - defaults: ["adbd_defaults"], - visibility: [ - "//art:__subpackages__", - "//system/core/adb/apex:__subpackages__", - ], - apex_available: [ - "com.android.adbd", - "test_com.android.adbd", - ], - - // libadbconnection_client doesn't need an embedded build number. - use_version_lib: false, - - target: { - linux: { - version_script: "libadbconnection_client.map.txt", - }, - }, - stubs: { - symbol_file: "libadbconnection_client.map.txt", - versions: ["1"], - }, - - host_supported: true, - compile_multilib: "both", -} diff --git a/adb/libs/adbconnection/adbconnection_client.cpp b/adb/libs/adbconnection/adbconnection_client.cpp deleted file mode 100644 index ee48abb031b1dea4895fc355d7c7c61b63d50097..0000000000000000000000000000000000000000 --- a/adb/libs/adbconnection/adbconnection_client.cpp +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (C) 2020 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 "adbconnection/client.h" - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -using android::base::unique_fd; - -static constexpr char kJdwpControlName[] = "\0jdwp-control"; - -struct AdbConnectionClientContext { - unique_fd control_socket_; -}; - -bool SocketPeerIsTrusted(int fd) { - ucred cr; - socklen_t cr_length = sizeof(cr); - if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &cr_length) != 0) { - PLOG(ERROR) << "couldn't get socket credentials"; - return false; - } - - passwd* shell = getpwnam("shell"); - if (cr.uid != 0 && cr.uid != shell->pw_uid) { - LOG(ERROR) << "untrusted uid " << cr.uid << " on other end of socket"; - return false; - } - - return true; -} - -AdbConnectionClientContext* adbconnection_client_new( - const AdbConnectionClientInfo* const* info_elems, size_t info_count) { - auto ctx = std::make_unique(); - - std::optional pid; - std::optional debuggable; - - for (size_t i = 0; i < info_count; ++i) { - auto info = info_elems[i]; - switch (info->type) { - case AdbConnectionClientInfoType::pid: - if (pid) { - LOG(ERROR) << "multiple pid entries in AdbConnectionClientInfo, ignoring"; - continue; - } - pid = info->data.pid; - break; - - case AdbConnectionClientInfoType::debuggable: - if (debuggable) { - LOG(ERROR) << "multiple debuggable entries in AdbConnectionClientInfo, ignoring"; - continue; - } - debuggable = info->data.pid; - break; - } - } - - if (!pid) { - LOG(ERROR) << "AdbConnectionClientInfo missing required field pid"; - return nullptr; - } - - if (!debuggable) { - LOG(ERROR) << "AdbConnectionClientInfo missing required field debuggable"; - return nullptr; - } - - ctx->control_socket_.reset(socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0)); - if (ctx->control_socket_ < 0) { - PLOG(ERROR) << "failed to create Unix domain socket"; - return nullptr; - } - - struct timeval timeout; - timeout.tv_sec = 1; - timeout.tv_usec = 0; - setsockopt(ctx->control_socket_.get(), SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); - - sockaddr_un addr = {}; - addr.sun_family = AF_UNIX; - memcpy(addr.sun_path, kJdwpControlName, sizeof(kJdwpControlName)); - size_t addr_len = offsetof(sockaddr_un, sun_path) + sizeof(kJdwpControlName) - 1; - - int rc = connect(ctx->control_socket_.get(), reinterpret_cast(&addr), addr_len); - if (rc != 0) { - PLOG(ERROR) << "failed to connect to jdwp control socket"; - return nullptr; - } - - bool trusted = SocketPeerIsTrusted(ctx->control_socket_.get()); - if (!trusted) { - LOG(ERROR) << "adb socket is not trusted, aborting connection"; - return nullptr; - } - - uint32_t pid_u32 = static_cast(*pid); - rc = TEMP_FAILURE_RETRY(write(ctx->control_socket_.get(), &pid_u32, sizeof(pid_u32))); - if (rc != sizeof(pid_u32)) { - PLOG(ERROR) << "failed to send JDWP process pid to adbd"; - } - - return ctx.release(); -} - -void adbconnection_client_destroy(AdbConnectionClientContext* ctx) { - delete ctx; -} - -int adbconnection_client_pollfd(AdbConnectionClientContext* ctx) { - return ctx->control_socket_.get(); -} - -int adbconnection_client_receive_jdwp_fd(AdbConnectionClientContext* ctx) { - char dummy; - unique_fd jdwp_fd; - ssize_t rc = android::base::ReceiveFileDescriptors(ctx->control_socket_, &dummy, 1, &jdwp_fd); - if (rc != 1) { - return rc; - } - return jdwp_fd.release(); -} diff --git a/adb/libs/adbconnection/adbconnection_server.cpp b/adb/libs/adbconnection/adbconnection_server.cpp deleted file mode 100644 index 939da2f6476575d7f4f9c687945d6d71ee128ea5..0000000000000000000000000000000000000000 --- a/adb/libs/adbconnection/adbconnection_server.cpp +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (C) 2019 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 "adbconnection/server.h" - -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -using android::base::unique_fd; - -#define JDWP_CONTROL_NAME "\0jdwp-control" -#define JDWP_CONTROL_NAME_LEN (sizeof(JDWP_CONTROL_NAME) - 1) - -static_assert(JDWP_CONTROL_NAME_LEN <= sizeof(reinterpret_cast(0)->sun_path)); - -// Listen for incoming jdwp clients forever. -void adbconnection_listen(void (*callback)(int fd, pid_t pid)) { - sockaddr_un addr = {}; - socklen_t addrlen = JDWP_CONTROL_NAME_LEN + sizeof(addr.sun_family); - - addr.sun_family = AF_UNIX; - memcpy(addr.sun_path, JDWP_CONTROL_NAME, JDWP_CONTROL_NAME_LEN); - - unique_fd s(socket(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0)); - if (s < 0) { - PLOG(ERROR) << "failed to create JDWP control socket"; - return; - } - - if (bind(s.get(), reinterpret_cast(&addr), addrlen) < 0) { - PLOG(ERROR) << "failed to bind JDWP control socket"; - return; - } - - if (listen(s.get(), 4) < 0) { - PLOG(ERROR) << "failed to listen on JDWP control socket"; - return; - } - - std::vector pending_connections; - - unique_fd epfd(epoll_create1(EPOLL_CLOEXEC)); - std::array events; - - events[0].events = EPOLLIN; - events[0].data.fd = -1; - if (epoll_ctl(epfd.get(), EPOLL_CTL_ADD, s.get(), &events[0]) != 0) { - LOG(FATAL) << "failed to register event with epoll fd"; - } - - while (true) { - int epoll_rc = TEMP_FAILURE_RETRY(epoll_wait(epfd.get(), events.data(), events.size(), -1)); - if (epoll_rc == -1) { - PLOG(FATAL) << "epoll_wait failed"; - } - - for (int i = 0; i < epoll_rc; ++i) { - const epoll_event& event = events[i]; - if (event.data.fd == -1) { - unique_fd client( - TEMP_FAILURE_RETRY(accept4(s.get(), nullptr, nullptr, SOCK_NONBLOCK | SOCK_CLOEXEC))); - - if (client == -1) { - PLOG(WARNING) << "failed to accept client on JDWP control socket"; - continue; - } - - epoll_event register_event; - register_event.events = EPOLLIN; - register_event.data.fd = client.get(); - - if (epoll_ctl(epfd.get(), EPOLL_CTL_ADD, client.get(), ®ister_event) != 0) { - PLOG(FATAL) << "failed to register JDWP client with epoll"; - } - - pending_connections.emplace_back(std::move(client)); - } else { - // n^2, but the backlog should be short. - auto it = std::find_if(pending_connections.begin(), pending_connections.end(), - [&](const unique_fd& fd) { return fd.get() == event.data.fd; }); - - if (it == pending_connections.end()) { - LOG(FATAL) << "failed to find JDWP client (" << event.data.fd - << ") in pending connections"; - } - - // Massively oversized buffer: we're expecting an int32_t from the other end. - char buf[32]; - int rc = TEMP_FAILURE_RETRY(recv(it->get(), buf, sizeof(buf), MSG_DONTWAIT)); - if (rc != 4) { - LOG(ERROR) << "received data of incorrect size from JDWP client: read " << rc - << ", expected 4"; - } else { - int32_t pid; - memcpy(&pid, buf, sizeof(pid)); - callback(it->release(), static_cast(pid)); - } - - if (epoll_ctl(epfd.get(), EPOLL_CTL_DEL, event.data.fd, nullptr) != 0) { - LOG(FATAL) << "failed to delete fd from JDWP epoll fd"; - } - - pending_connections.erase(it); - } - } - } -} diff --git a/adb/libs/adbconnection/include/adbconnection/client.h b/adb/libs/adbconnection/include/adbconnection/client.h deleted file mode 100644 index 692fea00d6cf30edefb84d8fec16116b06c39ab1..0000000000000000000000000000000000000000 --- a/adb/libs/adbconnection/include/adbconnection/client.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2019 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. - */ - -#pragma once - -#include -#include - -#include - -extern "C" { - -struct AdbConnectionClientContext; - -enum AdbConnectionClientInfoType { - pid, - debuggable, -}; - -struct AdbConnectionClientInfo { - AdbConnectionClientInfoType type; - union { - uint64_t pid; - bool debuggable; - } data; -}; - -// Construct a context and connect to adbd. -// Returns null if we fail to connect to adbd. -AdbConnectionClientContext* adbconnection_client_new( - const AdbConnectionClientInfo* const* info_elems, size_t info_count); - -void adbconnection_client_destroy(AdbConnectionClientContext* ctx); - -// Get an fd which can be polled upon to detect when a jdwp socket is available. -// You do not own this fd. Do not close it. -int adbconnection_client_pollfd(AdbConnectionClientContext* ctx); - -// Receive a jdwp client fd. -// Ownership is transferred to the caller of this function. -int adbconnection_client_receive_jdwp_fd(AdbConnectionClientContext* ctx); -} diff --git a/adb/libs/adbconnection/include/adbconnection/server.h b/adb/libs/adbconnection/include/adbconnection/server.h deleted file mode 100644 index 57ca6cdeea2c60ff6f643d09a3ed4fb6ddace9ae..0000000000000000000000000000000000000000 --- a/adb/libs/adbconnection/include/adbconnection/server.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2019 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. - */ - -#pragma once - -#include - -#include - -extern "C" { - -void adbconnection_listen(void (*callback)(int fd, pid_t pid)); -} diff --git a/adb/libs/adbconnection/libadbconnection_client.map.txt b/adb/libs/adbconnection/libadbconnection_client.map.txt deleted file mode 100644 index 153a0e41bc0e0b0d17753bfb6eec373aa0a71bfc..0000000000000000000000000000000000000000 --- a/adb/libs/adbconnection/libadbconnection_client.map.txt +++ /dev/null @@ -1,25 +0,0 @@ -# -# Copyright (C) 2019 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. -# - -LIBADBCONNECTION_CLIENT_1 { - global: - adbconnection_client_new; - adbconnection_client_destroy; - adbconnection_client_pollfd; - adbconnection_client_receive_jdwp_fd; - local: - *; -}; diff --git a/adb/libs/libadbd_fs/Android.bp b/adb/libs/libadbd_fs/Android.bp deleted file mode 100644 index d178148254abff1a021b1fbd6ca9753e486e1ec6..0000000000000000000000000000000000000000 --- a/adb/libs/libadbd_fs/Android.bp +++ /dev/null @@ -1,30 +0,0 @@ -// libadbd_fs -// ========================================================= -cc_library { - name: "libadbd_fs", - defaults: ["adbd_defaults"], - - srcs: ["adbd_fs.cpp"], - static_libs: [ - "libbase", - "libcutils", - "liblog", - ], - export_include_dirs: ["include"], - - version_script: "libadbd_fs.map.txt", - stubs: { - versions: ["1"], - symbol_file: "libadbd_fs.map.txt", - }, - - host_supported: true, - recovery_available: true, - compile_multilib: "both", - - target: { - darwin: { - enabled: false, - } - }, -} diff --git a/adb/libs/libadbd_fs/adbd_fs.cpp b/adb/libs/libadbd_fs/adbd_fs.cpp deleted file mode 100644 index 8e62d40d1c298f46869e383cfbbb06eb4fa755ef..0000000000000000000000000000000000000000 --- a/adb/libs/libadbd_fs/adbd_fs.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2020 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 - -void adbd_fs_config(const char* path, int dir, const char* target_out_path, uid_t* uid, gid_t* gid, - mode_t* mode, uint64_t* capabilities) { - unsigned uid_hack; - unsigned gid_hack; - unsigned mode_hack; - fs_config(path, dir, target_out_path, &uid_hack, &gid_hack, &mode_hack, capabilities); - *uid = uid_hack; - *gid = gid_hack; - *mode = mode_hack; -} diff --git a/adb/libs/libadbd_fs/include/adbd_fs.h b/adb/libs/libadbd_fs/include/adbd_fs.h deleted file mode 100644 index 6158d72081cdd76e77b08ce8b0b99fa866369ca5..0000000000000000000000000000000000000000 --- a/adb/libs/libadbd_fs/include/adbd_fs.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2020 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. - */ - -#pragma once - -#include -#include - -extern "C" { -// Thin wrapper around libcutils fs_config. -void adbd_fs_config(const char* path, int dir, const char* target_out_path, uid_t* uid, gid_t* gid, - mode_t* mode, uint64_t* capabilities); -} diff --git a/adb/libs/libadbd_fs/libadbd_fs.map.txt b/adb/libs/libadbd_fs/libadbd_fs.map.txt deleted file mode 100644 index 1454e9639c54ef0d2671824dda28daa610d06ce8..0000000000000000000000000000000000000000 --- a/adb/libs/libadbd_fs/libadbd_fs.map.txt +++ /dev/null @@ -1,6 +0,0 @@ -LIBADBD_FS { - global: - adbd_fs_config; # apex - local: - *; -}; diff --git a/adb/mdns_test.cpp b/adb/mdns_test.cpp deleted file mode 100644 index 1f662c1cada28cae475f7b12fd57ebc41af316fe..0000000000000000000000000000000000000000 --- a/adb/mdns_test.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2020 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 "adb_mdns.h" - -static bool isValidMdnsServiceName(std::string_view name) { - // The rules for Service Names [RFC6335] state that they may be no more - // than fifteen characters long (not counting the mandatory underscore), - // consisting of only letters, digits, and hyphens, must begin and end - // with a letter or digit, must not contain consecutive hyphens, and - // must contain at least one letter. - - // No more than 15 characters long - if (name.empty() || name.size() > 15) { - return false; - } - - bool hasAtLeastOneLetter = false; - bool sawHyphen = false; - for (size_t i = 0; i < name.size(); ++i) { - // Must contain at least one letter - // Only contains letters, digits and hyphens - if (name[i] == '-') { - // Cannot be at beginning or end - if (i == 0 || i == name.size() - 1) { - return false; - } - if (sawHyphen) { - // Consecutive hyphen found - return false; - } - sawHyphen = true; - continue; - } - - sawHyphen = false; - if ((name[i] >= 'a' && name[i] <= 'z') || (name[i] >= 'A' && name[i] <= 'Z')) { - hasAtLeastOneLetter = true; - continue; - } - - if (name[i] >= '0' && name[i] <= '9') { - continue; - } - - // Invalid character - return false; - } - - return hasAtLeastOneLetter; -} - -TEST(mdns, test_isValidMdnsServiceName) { - // Longer than 15 characters - EXPECT_FALSE(isValidMdnsServiceName("abcd1234abcd1234")); - - // Contains invalid characters - EXPECT_FALSE(isValidMdnsServiceName("a*a")); - EXPECT_FALSE(isValidMdnsServiceName("a_a")); - EXPECT_FALSE(isValidMdnsServiceName("_a")); - - // Does not begin or end with letter or digit - EXPECT_FALSE(isValidMdnsServiceName("")); - EXPECT_FALSE(isValidMdnsServiceName("-")); - EXPECT_FALSE(isValidMdnsServiceName("-a")); - EXPECT_FALSE(isValidMdnsServiceName("-1")); - EXPECT_FALSE(isValidMdnsServiceName("a-")); - EXPECT_FALSE(isValidMdnsServiceName("1-")); - - // Contains consecutive hyphens - EXPECT_FALSE(isValidMdnsServiceName("a--a")); - - // Does not contain at least one letter - EXPECT_FALSE(isValidMdnsServiceName("1")); - EXPECT_FALSE(isValidMdnsServiceName("12")); - EXPECT_FALSE(isValidMdnsServiceName("1-2")); - - // Some valid names - EXPECT_TRUE(isValidMdnsServiceName("a")); - EXPECT_TRUE(isValidMdnsServiceName("a1")); - EXPECT_TRUE(isValidMdnsServiceName("1A")); - EXPECT_TRUE(isValidMdnsServiceName("aZ")); - EXPECT_TRUE(isValidMdnsServiceName("a-Z")); - EXPECT_TRUE(isValidMdnsServiceName("a-b-Z")); - EXPECT_TRUE(isValidMdnsServiceName("abc-def-123-456")); -} - -TEST(mdns, ServiceName_RFC6335) { - EXPECT_TRUE(isValidMdnsServiceName(ADB_MDNS_SERVICE_TYPE)); - EXPECT_TRUE(isValidMdnsServiceName(ADB_MDNS_TLS_PAIRING_TYPE)); - EXPECT_TRUE(isValidMdnsServiceName(ADB_MDNS_TLS_CONNECT_TYPE)); -} diff --git a/adb/pairing_auth/Android.bp b/adb/pairing_auth/Android.bp deleted file mode 100644 index a43f4d03423ab83570b4cadbd7a370f387dda1cb..0000000000000000000000000000000000000000 --- a/adb/pairing_auth/Android.bp +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (C) 2020 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. - -cc_defaults { - name: "libadb_pairing_auth_defaults", - cflags: [ - "-Wall", - "-Wextra", - "-Wthread-safety", - "-Werror", - ], - - compile_multilib: "both", - - srcs: [ - "aes_128_gcm.cpp", - "pairing_auth.cpp", - ], - target: { - android: { - version_script: "libadb_pairing_auth.map.txt", - }, - windows: { - compile_multilib: "first", - enabled: true, - }, - }, - export_include_dirs: ["include"], - - visibility: [ - "//art:__subpackages__", - "//system/core/adb:__subpackages__", - ], - - // libadb_pairing_auth doesn't need an embedded build number. - use_version_lib: false, - - host_supported: true, - recovery_available: false, - - stl: "libc++_static", - - static_libs: ["libbase"], - shared_libs: [ - "libcrypto", - "liblog", - ], -} - -cc_library { - name: "libadb_pairing_auth", - defaults: ["libadb_pairing_auth_defaults"], - - apex_available: [ - "com.android.adbd", - ], - - stubs: { - symbol_file: "libadb_pairing_auth.map.txt", - versions: ["30"], - }, -} - -// For running atest (b/147158681) -cc_library_static { - name: "libadb_pairing_auth_static", - defaults: ["libadb_pairing_auth_defaults"], - - apex_available: [ - "//apex_available:platform", - ], -} diff --git a/adb/pairing_auth/aes_128_gcm.cpp b/adb/pairing_auth/aes_128_gcm.cpp deleted file mode 100644 index 51520d814dc6ca75a3e990de568651538ea49a90..0000000000000000000000000000000000000000 --- a/adb/pairing_auth/aes_128_gcm.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2020 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 "adb/pairing/aes_128_gcm.h" - -#include -#include - -#include -#include -#include - -namespace adb { -namespace pairing { - -namespace { -// Size of AES-128-GCM key, in bytes -static constexpr size_t kHkdfKeyLength = 16; - -} // namespace - -Aes128Gcm::Aes128Gcm(const uint8_t* key_material, size_t key_material_len) { - CHECK(key_material); - CHECK_NE(key_material_len, 0ul); - - uint8_t key[kHkdfKeyLength]; - uint8_t info[] = "adb pairing_auth aes-128-gcm key"; - CHECK_EQ(HKDF(key, sizeof(key), EVP_sha256(), key_material, key_material_len, nullptr, 0, info, - sizeof(info) - 1), - 1); - CHECK(EVP_AEAD_CTX_init(context_.get(), EVP_aead_aes_128_gcm(), key, sizeof(key), - EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr)); -} - -std::optional Aes128Gcm::Encrypt(const uint8_t* in, size_t in_len, uint8_t* out, - size_t out_len) { - std::vector nonce(EVP_AEAD_nonce_length(EVP_AEAD_CTX_aead(context_.get())), 0); - memcpy(nonce.data(), &enc_sequence_, sizeof(enc_sequence_)); - size_t written_sz; - if (!EVP_AEAD_CTX_seal(context_.get(), out, &written_sz, out_len, nonce.data(), nonce.size(), - in, in_len, nullptr, 0)) { - LOG(ERROR) << "Failed to encrypt (in_len=" << in_len << ", out_len=" << out_len - << ", out_len_needed=" << EncryptedSize(in_len) << ")"; - return std::nullopt; - } - - ++enc_sequence_; - return written_sz; -} - -std::optional Aes128Gcm::Decrypt(const uint8_t* in, size_t in_len, uint8_t* out, - size_t out_len) { - std::vector nonce(EVP_AEAD_nonce_length(EVP_AEAD_CTX_aead(context_.get())), 0); - memcpy(nonce.data(), &dec_sequence_, sizeof(dec_sequence_)); - size_t written_sz; - if (!EVP_AEAD_CTX_open(context_.get(), out, &written_sz, out_len, nonce.data(), nonce.size(), - in, in_len, nullptr, 0)) { - LOG(ERROR) << "Failed to decrypt (in_len=" << in_len << ", out_len=" << out_len - << ", out_len_needed=" << DecryptedSize(in_len) << ")"; - return std::nullopt; - } - - ++dec_sequence_; - return written_sz; -} - -size_t Aes128Gcm::EncryptedSize(size_t size) { - // https://commondatastorage.googleapis.com/chromium-boringssl-docs/aead.h.html#EVP_AEAD_CTX_seal - return size + EVP_AEAD_max_overhead(EVP_AEAD_CTX_aead(context_.get())); -} - -size_t Aes128Gcm::DecryptedSize(size_t size) { - // https://commondatastorage.googleapis.com/chromium-boringssl-docs/aead.h.html#EVP_AEAD_CTX_open - return size; -} - -} // namespace pairing -} // namespace adb diff --git a/adb/pairing_auth/include/adb/pairing/aes_128_gcm.h b/adb/pairing_auth/include/adb/pairing/aes_128_gcm.h deleted file mode 100644 index 6be58569048b77cbe995ccaae24bf84d90453c7d..0000000000000000000000000000000000000000 --- a/adb/pairing_auth/include/adb/pairing/aes_128_gcm.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2020 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. - */ - -#pragma once - -#include - -#include -#include - -#include - -namespace adb { -namespace pairing { - -class Aes128Gcm { - public: - explicit Aes128Gcm(const uint8_t* key_material, size_t key_material_len); - - // Encrypt a block of data in |in| of length |in_len|, this consumes all data - // in |in| and places the encrypted data in |out| if |out_len| indicates that - // there is enough space. The data contains information needed for - // decryption that is specific to this implementation and is therefore only - // suitable for decryption with this class. - // The method returns the number of bytes placed in |out| on success and a - // negative value if an error occurs. - std::optional Encrypt(const uint8_t* in, size_t in_len, uint8_t* out, size_t out_len); - // Decrypt a block of data in |in| of length |in_len|, this consumes all data - // in |in_len| bytes of data. The decrypted output is placed in the |out| - // buffer of length |out_len|. On successful decryption the number of bytes in - // |out| will be placed in |out_len|. - // The method returns the number of bytes consumed from the |in| buffer. If - // there is not enough data available in |in| the method returns zero. If - // an error occurs the method returns a negative value. - std::optional Decrypt(const uint8_t* in, size_t in_len, uint8_t* out, size_t out_len); - - // Return a safe amount of buffer storage needed to encrypt |size| bytes. - size_t EncryptedSize(size_t size); - // Return a safe amount of buffer storage needed to decrypt |size| bytes. - size_t DecryptedSize(size_t size); - - private: - bssl::ScopedEVP_AEAD_CTX context_; - // Sequence numbers to use as nonces in the encryption scheme - uint64_t dec_sequence_ = 0; - uint64_t enc_sequence_ = 0; -}; - -} // namespace pairing -} // namespace adb diff --git a/adb/pairing_auth/include/adb/pairing/pairing_auth.h b/adb/pairing_auth/include/adb/pairing/pairing_auth.h deleted file mode 100644 index 9ef97e2600bda312f647c03123c4be10e8a2bbcb..0000000000000000000000000000000000000000 --- a/adb/pairing_auth/include/adb/pairing/pairing_auth.h +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright (C) 2020 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. - */ - -#pragma once - -#include -#include -#include - -#if !defined(__INTRODUCED_IN) -#define __INTRODUCED_IN(__api_level) /* nothing */ -#endif - -__BEGIN_DECLS -#if !defined(__ANDROID__) || __ANDROID_API__ >= 30 - -/** - * PairingAuthCtx is a wrapper around the SPAKE2 protocol + cipher initialization - * for encryption. On construction, the |password| will be used to generate a - * SPAKE2 message. Each peer will exchange the messages in |pairing_auth_get_msg| - * to initialize their ciphers in |pairing_auth_init_cipher|. If both peers used the - * same |password|, then both sides will be able to decrypt each other's messages. - * - * On creation of a PairingAuthCtx, |pairing_auth_init_cipher| prior to using - * the encrypt and decrypt APIs. Furthermore, you can only initialize the cipher - * once. - * - * See pairing_auth_test.cpp for example usage. - * - */ -struct PairingAuthCtx; -typedef struct PairingAuthCtx PairingAuthCtx; - -/** - * Creates a new PairingAuthCtx instance as the server. - * - * @param pswd the shared secret the server and client use to authenticate each - * other. Will abort if null. - * @param len the length of the pswd in bytes. Will abort if 0. - * @return a new PairingAuthCtx server instance. Caller is responsible for - * destroying the context via #pairing_auth_destroy. - */ -PairingAuthCtx* pairing_auth_server_new(const uint8_t* pswd, size_t len) __INTRODUCED_IN(30); - -/** - * Creates a new PairingAuthCtx instance as the client. - * - * @param pswd the shared secret the server and client use to authenticate each - * other. Will abort if null. - * @param len the length of the pswd in bytes. Will abort if 0. - * @return a new PairingAuthCtx client instance. Caller is responsible for - * destroying the context via #pairing_auth_destroy. - */ -PairingAuthCtx* pairing_auth_client_new(const uint8_t* pswd, size_t len) __INTRODUCED_IN(30); - -/** - * Destroys the PairingAuthCtx. - * - * @param ctx the PairingAuthCtx instance to destroy. Will abort if null. - */ -void pairing_auth_destroy(PairingAuthCtx* ctx) __INTRODUCED_IN(30); - -/** - * Returns the exact size of the SPAKE2 msg. - * - * Use this size as the buffer size when retrieving the message via - * #pairing_auth_get_msg. - * - * @param ctx the PairingAuthCtx instance. Will abort if null. - * @return the size of the SPAKE2 message in bytes. This is guaranteed to be > 0. - */ -size_t pairing_auth_msg_size(PairingAuthCtx* ctx) __INTRODUCED_IN(30); - -/** - * Writes the SPAKE2 message to exchange with the other party to |out_buf|. - * - * This is guaranteed to write a valid message to |out_buf|. Use #pairing_auth_msg_size - * to get the size the |out_buf| should be. The SPAKE2 messages will be used to - * initialize the cipher for encryption/decryption (see #pairing_auth_init_cipher). - * - * @param ctx the PairingAuthCtx instance. Will abort if null. - * @param out_buf the buffer the message is written to. The buffer is assumed to - * be have at least #pairing_auth_msg_size size. Will abort if - * out_buf is null. - */ -void pairing_auth_get_spake2_msg(PairingAuthCtx* ctx, uint8_t* out_buf) __INTRODUCED_IN(30); - -/** - * Processes the peer's |their_msg| and attempts to initialize the cipher for - * encryption. - * - * You can only call this method ONCE with a non-empty |msg|, regardless of success - * or failure. On success, you can use the #pairing_auth_decrypt and #pairing_auth_encrypt - * methods to exchange any further information securely. On failure, this - * PairingAuthCtx instance has no more purpose and should be destroyed. - * - * @param ctx the PairingAuthCtx instance. Will abort if null. - * @param their_msg the peer's SPAKE2 msg. See #pairing_auth_get_msg. Will abort - * if null. - * @param msg_len the length of their_msg in bytes. Will abort if 0. - * @return true iff the client and server used the same password when creating - * the PairingAuthCtx. See - * https: *commondatastorage.googleapis.com/chromium-boringssl-docs/curve25519.h.html#SPAKE2 - * for more details on the SPAKE2 protocol. - */ -bool pairing_auth_init_cipher(PairingAuthCtx* ctx, const uint8_t* their_msg, size_t msg_len) - __INTRODUCED_IN(30); - -/** - * Returns a safe buffer size for encrypting data of a certain size. - * - * IMPORTANT: This will abort if either #pairing_auth_init_cipher was not called - * or #pairing_auth_init_cipher failed. - * - * @param ctx the PairingAuthCtx instance. Will abort if null. - * @param len the size of the message wanting to encrypt in bytes. - * @return the minimum buffer size, in bytes, to hold an encrypted message of size len. See - * #pairing_auth_encrypt for usage. - */ -size_t pairing_auth_safe_encrypted_size(PairingAuthCtx* ctx, size_t len) __INTRODUCED_IN(30); - -/** - * Encrypts input data and writes the encrypted data into a user-provided buffer. - * - * IMPORTANT: This will abort if either #pairing_auth_init_cipher was not called - * or #pairing_auth_init_cipher failed. - * - * @param ctx the PairingAuthCtx instance. Will abort if null. - * @param inbuf the buffer containing the data to encrypt. Will abort if null. - * @param inlen the size of inbuf in bytes. Will abort if 0. - * @param outbuf the buffer to write the encrypted data to. Will abort if null - * @param outlen the size of outbuf in bytes. See #pairing_auth_safe_encrypted_size. - * @return true if all the data was encrypted and written to outbuf, false - * otherwise. - */ -bool pairing_auth_encrypt(PairingAuthCtx* ctx, const uint8_t* inbuf, size_t inlen, uint8_t* outbuf, - size_t* outlen) __INTRODUCED_IN(30); - -/** - * Returns a safe buffer size for decrypting data of a certain size. - * - * IMPORTANT: This will abort if either #pairing_auth_init_cipher was not called - * or #pairing_auth_init_cipher failed. - * - * @param ctx the PairingAuthCtx instance. Will abort if null. - * @param buf the buffer containing the encrypted data. Will abort if null. - * @param len the size of the buf in bytes. Will abort if 0. - * @return the minimum buffer size, in bytes, to hold a decrypted message of size len. See - * #pairing_auth_decrypt for usage. - */ -size_t pairing_auth_safe_decrypted_size(PairingAuthCtx* ctx, const uint8_t* buf, size_t len) - __INTRODUCED_IN(30); - -/** - * Decrypts input data and writes the decrypted data into a user-provided buffer. - * - * IMPORTANT: This will abort if either #pairing_auth_init_cipher was not called - * or #pairing_auth_init_cipher failed. - * - * @param ctx the PairingAuthCtx instance. Will abort if null. - * @param inbuf the buffer containing the data to decrypt. Will abort if null. - * @param inlen the size of inbuf in bytes. WIll abort if 0. - * @param outbuf the buffer to write the decrypted data to. Will abort if null. - * @param outlen the size of outbuf in bytes. See #pairing_auth_safe_decrypted_size. - * Will abort if 0. - * @return true if all the data was decrypted and written to outbuf, false - * otherwise. - */ -bool pairing_auth_decrypt(PairingAuthCtx* ctx, const uint8_t* inbuf, size_t inlen, uint8_t* outbuf, - size_t* outlen) __INTRODUCED_IN(30); - -#endif //!__ANDROID__ || __ANDROID_API__ >= 30 -__END_DECLS diff --git a/adb/pairing_auth/libadb_pairing_auth.map.txt b/adb/pairing_auth/libadb_pairing_auth.map.txt deleted file mode 100644 index fdc15570b5b39998fd5536d74c93433f494265bb..0000000000000000000000000000000000000000 --- a/adb/pairing_auth/libadb_pairing_auth.map.txt +++ /dev/null @@ -1,15 +0,0 @@ -LIBADB_PAIRING_AUTH { - global: - pairing_auth_msg_size; # apex introduced=30 - pairing_auth_get_spake2_msg; # apex introduced=30 - pairing_auth_init_cipher; # apex introduced=30 - pairing_auth_safe_encrypted_size; # apex introduced=30 - pairing_auth_encrypt; # apex introduced=30 - pairing_auth_safe_decrypted_size; # apex introduced=30 - pairing_auth_decrypt; # apex introduced=30 - pairing_auth_server_new; # apex introduced=30 - pairing_auth_client_new; # apex introduced=30 - pairing_auth_destroy; # apex introduced=30 - local: - *; -}; diff --git a/adb/pairing_auth/pairing_auth.cpp b/adb/pairing_auth/pairing_auth.cpp deleted file mode 100644 index 0ac04e69136357d21207bd088ce184560df74c6f..0000000000000000000000000000000000000000 --- a/adb/pairing_auth/pairing_auth.cpp +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Copyright (C) 2020 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 "adb/pairing/pairing_auth.h" - -#include - -#include -#include - -#include -#include -#include - -#include "adb/pairing/aes_128_gcm.h" - -using namespace adb::pairing; - -static constexpr spake2_role_t kClientRole = spake2_role_alice; -static constexpr spake2_role_t kServerRole = spake2_role_bob; - -static const uint8_t kClientName[] = "adb pair client"; -static const uint8_t kServerName[] = "adb pair server"; - -// This class is basically a wrapper around the SPAKE2 protocol + initializing a -// cipher with the generated key material for encryption. -struct PairingAuthCtx { - public: - using Data = std::vector; - enum class Role { - Client, - Server, - }; - - explicit PairingAuthCtx(Role role, const Data& pswd); - - // Returns the message to exchange with the other party. This is guaranteed - // to have a non-empty message if creating this object with - // |PairingAuthCtx::Create|, so you won't need to check. - const Data& msg() const; - - // Processes the peer's |msg| and attempts to initialize the cipher for - // encryption. You can only call this method ONCE with a non-empty |msg|, - // regardless of success or failure. Subsequent calls will always return - // false. On success, you can use the |decrypt| - // and |encrypt| methods to exchange any further information securely. - // - // Note: Once you call this with a non-empty key, the state is locked, which - // means that you cannot try and register another key, regardless of the - // return value. In order to register another key, you have to create a new - // instance of PairingAuthCtx. - bool InitCipher(const Data& their_msg); - - // Encrypts |data| and returns the result. If encryption fails, the return - // will be an empty vector. - Data Encrypt(const Data& data); - - // Decrypts |data| and returns the result. If decryption fails, the return - // will be an empty vector. - Data Decrypt(const Data& data); - - // Returns a safe buffer size for encrypting a buffer of size |len|. - size_t SafeEncryptedSize(size_t len); - - // Returns a safe buffer size for decrypting a buffer of size |len|. - size_t SafeDecryptedSize(size_t len); - - private: - Data our_msg_; - Role role_; - bssl::UniquePtr spake2_ctx_; - std::unique_ptr cipher_; -}; // PairingAuthCtx - -PairingAuthCtx::PairingAuthCtx(Role role, const Data& pswd) : role_(role) { - CHECK(!pswd.empty()); - // Try to create the spake2 context and generate the public key. - spake2_role_t spake_role; - const uint8_t* my_name = nullptr; - const uint8_t* their_name = nullptr; - size_t my_len = 0; - size_t their_len = 0; - - // Create the SPAKE2 context - switch (role_) { - case Role::Client: - spake_role = kClientRole; - my_name = kClientName; - my_len = sizeof(kClientName); - their_name = kServerName; - their_len = sizeof(kServerName); - break; - case Role::Server: - spake_role = kServerRole; - my_name = kServerName; - my_len = sizeof(kServerName); - their_name = kClientName; - their_len = sizeof(kClientName); - break; - } - spake2_ctx_.reset(SPAKE2_CTX_new(spake_role, my_name, my_len, their_name, their_len)); - if (spake2_ctx_ == nullptr) { - LOG(ERROR) << "Unable to create a SPAKE2 context."; - return; - } - - // Generate the SPAKE2 public key - size_t key_size = 0; - uint8_t key[SPAKE2_MAX_MSG_SIZE]; - int status = SPAKE2_generate_msg(spake2_ctx_.get(), key, &key_size, SPAKE2_MAX_MSG_SIZE, - pswd.data(), pswd.size()); - if (status != 1 || key_size == 0) { - LOG(ERROR) << "Unable to generate the SPAKE2 public key."; - return; - } - our_msg_.assign(key, key + key_size); -} - -const PairingAuthCtx::Data& PairingAuthCtx::msg() const { - return our_msg_; -} - -bool PairingAuthCtx::InitCipher(const PairingAuthCtx::Data& their_msg) { - // You can only register a key once. - CHECK(!their_msg.empty()); - CHECK(!cipher_); - - // Don't even try to process a message over the SPAKE2_MAX_MSG_SIZE - if (their_msg.size() > SPAKE2_MAX_MSG_SIZE) { - LOG(ERROR) << "their_msg size [" << their_msg.size() << "] greater then max size [" - << SPAKE2_MAX_MSG_SIZE << "]."; - return false; - } - - size_t key_material_len = 0; - uint8_t key_material[SPAKE2_MAX_KEY_SIZE]; - int status = SPAKE2_process_msg(spake2_ctx_.get(), key_material, &key_material_len, - sizeof(key_material), their_msg.data(), their_msg.size()); - if (status != 1) { - LOG(ERROR) << "Unable to process their public key"; - return false; - } - - // Once SPAKE2_process_msg returns successfully, you can't do anything else - // with the context, besides destroy it. - cipher_.reset(new Aes128Gcm(key_material, key_material_len)); - - return true; -} - -PairingAuthCtx::Data PairingAuthCtx::Encrypt(const PairingAuthCtx::Data& data) { - CHECK(cipher_); - CHECK(!data.empty()); - - // Determine the size for the encrypted data based on the raw data. - Data encrypted(cipher_->EncryptedSize(data.size())); - auto out_size = cipher_->Encrypt(data.data(), data.size(), encrypted.data(), encrypted.size()); - if (!out_size.has_value() || *out_size == 0) { - LOG(ERROR) << "Unable to encrypt data"; - return Data(); - } - encrypted.resize(*out_size); - - return encrypted; -} - -PairingAuthCtx::Data PairingAuthCtx::Decrypt(const PairingAuthCtx::Data& data) { - CHECK(cipher_); - CHECK(!data.empty()); - - // Determine the size for the decrypted data based on the raw data. - Data decrypted(cipher_->DecryptedSize(data.size())); - size_t decrypted_size = decrypted.size(); - auto out_size = cipher_->Decrypt(data.data(), data.size(), decrypted.data(), decrypted_size); - if (!out_size.has_value() || *out_size == 0) { - LOG(ERROR) << "Unable to decrypt data"; - return Data(); - } - decrypted.resize(*out_size); - - return decrypted; -} - -size_t PairingAuthCtx::SafeEncryptedSize(size_t len) { - CHECK(cipher_); - return cipher_->EncryptedSize(len); -} - -size_t PairingAuthCtx::SafeDecryptedSize(size_t len) { - CHECK(cipher_); - return cipher_->DecryptedSize(len); -} - -PairingAuthCtx* pairing_auth_server_new(const uint8_t* pswd, size_t len) { - CHECK(pswd); - CHECK_GT(len, 0U); - std::vector p(pswd, pswd + len); - auto* ret = new PairingAuthCtx(PairingAuthCtx::Role::Server, std::move(p)); - CHECK(!ret->msg().empty()); - return ret; -} - -PairingAuthCtx* pairing_auth_client_new(const uint8_t* pswd, size_t len) { - CHECK(pswd); - CHECK_GT(len, 0U); - std::vector p(pswd, pswd + len); - auto* ret = new PairingAuthCtx(PairingAuthCtx::Role::Client, std::move(p)); - CHECK(!ret->msg().empty()); - return ret; -} - -size_t pairing_auth_msg_size(PairingAuthCtx* ctx) { - CHECK(ctx); - return ctx->msg().size(); -} - -void pairing_auth_get_spake2_msg(PairingAuthCtx* ctx, uint8_t* out_buf) { - CHECK(ctx); - CHECK(out_buf); - auto& msg = ctx->msg(); - memcpy(out_buf, msg.data(), msg.size()); -} - -bool pairing_auth_init_cipher(PairingAuthCtx* ctx, const uint8_t* their_msg, size_t msg_len) { - CHECK(ctx); - CHECK(their_msg); - CHECK_GT(msg_len, 0U); - - std::vector p(their_msg, their_msg + msg_len); - return ctx->InitCipher(p); -} - -size_t pairing_auth_safe_encrypted_size(PairingAuthCtx* ctx, size_t len) { - CHECK(ctx); - return ctx->SafeEncryptedSize(len); -} - -bool pairing_auth_encrypt(PairingAuthCtx* ctx, const uint8_t* inbuf, size_t inlen, uint8_t* outbuf, - size_t* outlen) { - CHECK(ctx); - CHECK(inbuf); - CHECK(outbuf); - CHECK(outlen); - CHECK_GT(inlen, 0U); - - std::vector in(inbuf, inbuf + inlen); - auto out = ctx->Encrypt(in); - if (out.empty()) { - return false; - } - - memcpy(outbuf, out.data(), out.size()); - *outlen = out.size(); - return true; -} - -size_t pairing_auth_safe_decrypted_size(PairingAuthCtx* ctx, const uint8_t* buf, size_t len) { - CHECK(ctx); - CHECK(buf); - CHECK_GT(len, 0U); - // We no longer need buf for EVP_AEAD - return ctx->SafeDecryptedSize(len); -} - -bool pairing_auth_decrypt(PairingAuthCtx* ctx, const uint8_t* inbuf, size_t inlen, uint8_t* outbuf, - size_t* outlen) { - CHECK(ctx); - CHECK(inbuf); - CHECK(outbuf); - CHECK(outlen); - CHECK_GT(inlen, 0U); - - std::vector in(inbuf, inbuf + inlen); - auto out = ctx->Decrypt(in); - if (out.empty()) { - return false; - } - - memcpy(outbuf, out.data(), out.size()); - *outlen = out.size(); - return true; -} - -void pairing_auth_destroy(PairingAuthCtx* ctx) { - CHECK(ctx); - delete ctx; -} diff --git a/adb/pairing_auth/tests/Android.bp b/adb/pairing_auth/tests/Android.bp deleted file mode 100644 index 213123d59b71514d919bca7d822a7ca013a5da27..0000000000000000000000000000000000000000 --- a/adb/pairing_auth/tests/Android.bp +++ /dev/null @@ -1,38 +0,0 @@ -// -// Copyright (C) 2020 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. -// - -cc_test { - name: "adb_pairing_auth_test", - srcs: [ - "aes_128_gcm_test.cpp", - "pairing_auth_test.cpp", - ], - - compile_multilib: "first", - - shared_libs: [ - "libbase", - "libcrypto", - ], - - // Let's statically link them so we don't have to install it onto the - // system image for testing. - static_libs: [ - "libadb_pairing_auth_static", - ], - - test_suites: ["device-tests"], -} diff --git a/adb/pairing_auth/tests/aes_128_gcm_test.cpp b/adb/pairing_auth/tests/aes_128_gcm_test.cpp deleted file mode 100644 index 55689d67adbcc542b33b4d787d3d003f4bb56128..0000000000000000000000000000000000000000 --- a/adb/pairing_auth/tests/aes_128_gcm_test.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2020 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 - -namespace adb { -namespace pairing { - -TEST(Aes128GcmTest, init_null_material) { - std::unique_ptr cipher; - ASSERT_DEATH({ cipher.reset(new Aes128Gcm(nullptr, 42)); }, ""); -} - -TEST(Aes128GcmTest, init_empty_material) { - uint8_t material[64]; - std::unique_ptr cipher; - ASSERT_DEATH({ cipher.reset(new Aes128Gcm(material, 0)); }, ""); -} - -TEST(Aes128GcmTest, encrypt_decrypt) { - const uint8_t msg[] = "alice and bob, sitting in a binary tree"; - uint8_t material[256]; - uint8_t encrypted[1024]; - uint8_t out_buf[1024] = {}; - - RAND_bytes(material, sizeof(material)); - Aes128Gcm alice(material, sizeof(material)); - Aes128Gcm bob(material, sizeof(material)); - ; - - ASSERT_GE(alice.EncryptedSize(sizeof(msg)), sizeof(msg)); - auto encrypted_size = alice.Encrypt(msg, sizeof(msg), encrypted, sizeof(encrypted)); - ASSERT_TRUE(encrypted_size.has_value()); - ASSERT_GT(*encrypted_size, 0); - size_t out_size = sizeof(out_buf); - ASSERT_GE(bob.DecryptedSize(*encrypted_size), sizeof(msg)); - auto decrypted_size = bob.Decrypt(encrypted, *encrypted_size, out_buf, out_size); - ASSERT_TRUE(decrypted_size.has_value()); - ASSERT_EQ(sizeof(msg), *decrypted_size); - ASSERT_STREQ(reinterpret_cast(msg), reinterpret_cast(out_buf)); -} - -} // namespace pairing -} // namespace adb diff --git a/adb/pairing_auth/tests/pairing_auth_test.cpp b/adb/pairing_auth/tests/pairing_auth_test.cpp deleted file mode 100644 index fdc07f1f1e3ec21c1a1fdbc3efaed77c773b3010..0000000000000000000000000000000000000000 --- a/adb/pairing_auth/tests/pairing_auth_test.cpp +++ /dev/null @@ -1,330 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "AdbPairingAuthTest" - -#include - -#include -#include - -namespace adb { -namespace pairing { - -static void PairingAuthDeleter(PairingAuthCtx* p) { - pairing_auth_destroy(p); -} - -class AdbPairingAuthTest : public testing::Test { - protected: - virtual void SetUp() override {} - - virtual void TearDown() override {} - - using PairingAuthUniquePtr = std::unique_ptr; - - PairingAuthUniquePtr makeClient(std::vector pswd) { - return PairingAuthUniquePtr(pairing_auth_client_new(pswd.data(), pswd.size()), - PairingAuthDeleter); - } - - PairingAuthUniquePtr makeServer(std::vector pswd) { - return PairingAuthUniquePtr(pairing_auth_server_new(pswd.data(), pswd.size()), - PairingAuthDeleter); - } -}; - -TEST_F(AdbPairingAuthTest, EmptyPassword) { - // Context creation should fail if password is empty - PairingAuthUniquePtr client(nullptr, PairingAuthDeleter); - ASSERT_DEATH( - { - client = PairingAuthUniquePtr(pairing_auth_client_new(nullptr, 0), - PairingAuthDeleter); - }, - ""); - ASSERT_DEATH( - { - client = PairingAuthUniquePtr(pairing_auth_client_new(nullptr, 2), - PairingAuthDeleter); - }, - ""); - ASSERT_DEATH( - { - uint8_t p; - client = PairingAuthUniquePtr(pairing_auth_client_new(&p, 0), PairingAuthDeleter); - }, - ""); -} - -TEST_F(AdbPairingAuthTest, ValidPassword) { - const char* kPswd = "password"; - std::vector pswd(kPswd, kPswd + sizeof(kPswd)); - auto client = makeClient(pswd); - auto server = makeServer(pswd); - - ASSERT_NE(nullptr, client); - ASSERT_NE(nullptr, server); - - // msg should not be empty. - { - size_t msg_size = pairing_auth_msg_size(client.get()); - std::vector buf(msg_size); - ASSERT_GT(msg_size, 0); - pairing_auth_get_spake2_msg(client.get(), buf.data()); - } - { - size_t msg_size = pairing_auth_msg_size(server.get()); - std::vector buf(msg_size); - ASSERT_GT(msg_size, 0); - pairing_auth_get_spake2_msg(server.get(), buf.data()); - } -} - -TEST_F(AdbPairingAuthTest, NoInitCipher) { - // Register a non-empty password, but not the peer's msg. - // You should not be able to encrypt/decrypt messages. - const char* kPswd = "password"; - std::vector pswd(kPswd, kPswd + sizeof(kPswd)); - std::vector data{0x01, 0x02, 0x03}; - uint8_t outbuf[256]; - size_t outsize; - - // All other functions should crash if cipher hasn't been initialized. - ASSERT_DEATH( - { - auto server = makeServer(pswd); - pairing_auth_init_cipher(server.get(), nullptr, 0); - }, - ""); - ASSERT_DEATH( - { - auto server = makeServer(pswd); - pairing_auth_encrypt(server.get(), data.data(), data.size(), outbuf, &outsize); - }, - ""); - ASSERT_DEATH( - { - auto server = makeServer(pswd); - pairing_auth_decrypt(server.get(), data.data(), data.size(), outbuf, &outsize); - }, - ""); - ASSERT_DEATH( - { - auto server = makeServer(pswd); - pairing_auth_safe_decrypted_size(server.get(), data.data(), data.size()); - }, - ""); - ASSERT_DEATH( - { - auto server = makeServer(pswd); - pairing_auth_safe_encrypted_size(server.get(), data.size()); - }, - ""); -} - -TEST_F(AdbPairingAuthTest, DifferentPasswords) { - // Register different passwords and then exchange the msgs. The - // encryption should succeed, but the decryption should fail, since the - // ciphers have been initialized with different keys. - auto client = makeClient({0x01, 0x02, 0x03}); - std::vector client_msg(pairing_auth_msg_size(client.get())); - ASSERT_FALSE(client_msg.empty()); - pairing_auth_get_spake2_msg(client.get(), client_msg.data()); - - auto server = makeServer({0x01, 0x02, 0x04}); - std::vector server_msg(pairing_auth_msg_size(server.get())); - ASSERT_FALSE(server_msg.empty()); - pairing_auth_get_spake2_msg(server.get(), server_msg.data()); - - EXPECT_TRUE(pairing_auth_init_cipher(client.get(), server_msg.data(), server_msg.size())); - EXPECT_TRUE(pairing_auth_init_cipher(server.get(), client_msg.data(), client_msg.size())); - - // We shouldn't be able to decrypt. - std::vector msg{0x2a, 0x2b, 0x2c}; - // Client encrypts, server can't decrypt - size_t out_size; - client_msg.resize(pairing_auth_safe_encrypted_size(client.get(), msg.size())); - ASSERT_GT(client_msg.size(), 0); - ASSERT_TRUE(pairing_auth_encrypt(client.get(), msg.data(), msg.size(), client_msg.data(), - &out_size)); - ASSERT_GT(out_size, 0); - client_msg.resize(out_size); - - server_msg.resize( - pairing_auth_safe_decrypted_size(server.get(), client_msg.data(), client_msg.size())); - ASSERT_GT(server_msg.size(), 0); - ASSERT_FALSE(pairing_auth_decrypt(server.get(), client_msg.data(), client_msg.size(), - server_msg.data(), &out_size)); - - // Server encrypts, client can't decrypt - server_msg.resize(pairing_auth_safe_encrypted_size(server.get(), msg.size())); - ASSERT_GT(server_msg.size(), 0); - ASSERT_TRUE(pairing_auth_encrypt(server.get(), msg.data(), msg.size(), server_msg.data(), - &out_size)); - ASSERT_GT(out_size, 0); - server_msg.resize(out_size); - - client_msg.resize( - pairing_auth_safe_decrypted_size(client.get(), server_msg.data(), server_msg.size())); - ASSERT_GT(client_msg.size(), 0); - ASSERT_FALSE(pairing_auth_decrypt(client.get(), server_msg.data(), server_msg.size(), - client_msg.data(), &out_size)); -} - -TEST_F(AdbPairingAuthTest, SamePasswords) { - // Register same password and then exchange the msgs. The - // encryption and decryption should succeed and have the same, unencrypted - // values. - std::vector pswd{0x4f, 0x5a, 0x01, 0x46}; - auto client = makeClient(pswd); - std::vector client_msg(pairing_auth_msg_size(client.get())); - ASSERT_FALSE(client_msg.empty()); - pairing_auth_get_spake2_msg(client.get(), client_msg.data()); - - auto server = makeServer(pswd); - std::vector server_msg(pairing_auth_msg_size(server.get())); - ASSERT_FALSE(server_msg.empty()); - pairing_auth_get_spake2_msg(server.get(), server_msg.data()); - - EXPECT_TRUE(pairing_auth_init_cipher(client.get(), server_msg.data(), server_msg.size())); - EXPECT_TRUE(pairing_auth_init_cipher(server.get(), client_msg.data(), client_msg.size())); - - // We should be able to decrypt. - std::vector msg{0x2a, 0x2b, 0x2c, 0xff, 0x45, 0x12, 0x33}; - // Client encrypts, server decrypts - size_t out_size; - client_msg.resize(pairing_auth_safe_encrypted_size(client.get(), msg.size())); - ASSERT_GT(client_msg.size(), 0); - ASSERT_TRUE(pairing_auth_encrypt(client.get(), msg.data(), msg.size(), client_msg.data(), - &out_size)); - ASSERT_GT(out_size, 0); - client_msg.resize(out_size); - - server_msg.resize( - pairing_auth_safe_decrypted_size(server.get(), client_msg.data(), client_msg.size())); - ASSERT_GT(server_msg.size(), 0); - ASSERT_TRUE(pairing_auth_decrypt(server.get(), client_msg.data(), client_msg.size(), - server_msg.data(), &out_size)); - ASSERT_EQ(out_size, msg.size()); - EXPECT_EQ(memcmp(msg.data(), server_msg.data(), out_size), 0); - - // Server encrypts, client decrypt - server_msg.resize(pairing_auth_safe_encrypted_size(server.get(), msg.size())); - ASSERT_GT(server_msg.size(), 0); - ASSERT_TRUE(pairing_auth_encrypt(server.get(), msg.data(), msg.size(), server_msg.data(), - &out_size)); - ASSERT_GT(out_size, 0); - server_msg.resize(out_size); - - client_msg.resize( - pairing_auth_safe_decrypted_size(client.get(), server_msg.data(), server_msg.size())); - ASSERT_GT(client_msg.size(), 0); - ASSERT_TRUE(pairing_auth_decrypt(client.get(), server_msg.data(), server_msg.size(), - client_msg.data(), &out_size)); - ASSERT_EQ(out_size, msg.size()); - EXPECT_EQ(memcmp(msg.data(), client_msg.data(), out_size), 0); -} - -TEST_F(AdbPairingAuthTest, CorruptedPayload) { - // Do a matching password for both server/client, but let's fudge with the - // header payload field. The decryption should fail. - std::vector pswd{0x4f, 0x5a, 0x01, 0x46}; - auto client = makeClient(pswd); - std::vector client_msg(pairing_auth_msg_size(client.get())); - ASSERT_FALSE(client_msg.empty()); - pairing_auth_get_spake2_msg(client.get(), client_msg.data()); - - auto server = makeServer(pswd); - std::vector server_msg(pairing_auth_msg_size(server.get())); - ASSERT_FALSE(server_msg.empty()); - pairing_auth_get_spake2_msg(server.get(), server_msg.data()); - - EXPECT_TRUE(pairing_auth_init_cipher(client.get(), server_msg.data(), server_msg.size())); - EXPECT_TRUE(pairing_auth_init_cipher(server.get(), client_msg.data(), client_msg.size())); - - std::vector msg{0x2a, 0x2b, 0x2c, 0xff, 0x45, 0x12, - 0x33, 0x45, 0x12, 0xea, 0xf2, 0xdb}; - { - // Client encrypts whole msg, server decrypts msg. Should be fine. - size_t out_size; - client_msg.resize(pairing_auth_safe_encrypted_size(client.get(), msg.size())); - ASSERT_GT(client_msg.size(), 0); - ASSERT_TRUE(pairing_auth_encrypt(client.get(), msg.data(), msg.size(), client_msg.data(), - &out_size)); - ASSERT_GT(out_size, 0); - client_msg.resize(out_size); - - server_msg.resize(pairing_auth_safe_decrypted_size(server.get(), client_msg.data(), - client_msg.size())); - ASSERT_GT(server_msg.size(), 0); - ASSERT_TRUE(pairing_auth_decrypt(server.get(), client_msg.data(), client_msg.size(), - server_msg.data(), &out_size)); - ASSERT_EQ(out_size, msg.size()); - EXPECT_EQ(memcmp(msg.data(), server_msg.data(), out_size), 0); - } - { - // 1) Client encrypts msg - // 2) append some data to the encrypted msg - // 3) change the payload field - // 4) server tries to decrypt. It should fail. - size_t out_size; - client_msg.resize(pairing_auth_safe_encrypted_size(client.get(), msg.size())); - ASSERT_GT(client_msg.size(), 0); - ASSERT_TRUE(pairing_auth_encrypt(client.get(), msg.data(), msg.size(), client_msg.data(), - &out_size)); - ASSERT_GT(out_size, 0); - client_msg.resize(out_size); - client_msg.push_back(0xaa); - // This requires knowledge of the layout of the data. payload is the - // first four bytes of the client_msg. - uint32_t* payload = reinterpret_cast(client_msg.data()); - *payload = ntohl(*payload); - *payload = htonl(*payload + 1); - - server_msg.resize(pairing_auth_safe_decrypted_size(server.get(), client_msg.data(), - client_msg.size())); - ASSERT_GT(server_msg.size(), 0); - ASSERT_FALSE(pairing_auth_decrypt(server.get(), client_msg.data(), client_msg.size(), - server_msg.data(), &out_size)); - } - { - // 1) Client encrypts msg - // 3) decrement the payload field - // 4) server tries to decrypt. It should fail. - size_t out_size; - client_msg.resize(pairing_auth_safe_encrypted_size(client.get(), msg.size())); - ASSERT_GT(client_msg.size(), 0); - ASSERT_TRUE(pairing_auth_encrypt(client.get(), msg.data(), msg.size(), client_msg.data(), - &out_size)); - ASSERT_GT(out_size, 0); - client_msg.resize(out_size); - // This requires knowledge of the layout of the data. payload is the - // first four bytes of the client_msg. - uint32_t* payload = reinterpret_cast(client_msg.data()); - *payload = ntohl(*payload); - *payload = htonl(*payload - 1); - - server_msg.resize(pairing_auth_safe_decrypted_size(server.get(), client_msg.data(), - client_msg.size())); - ASSERT_GT(server_msg.size(), 0); - ASSERT_FALSE(pairing_auth_decrypt(server.get(), client_msg.data(), client_msg.size(), - server_msg.data(), &out_size)); - } -} - -} // namespace pairing -} // namespace adb diff --git a/adb/pairing_connection/Android.bp b/adb/pairing_connection/Android.bp deleted file mode 100644 index 707161bcb477a1a887316be285a15ba3074826ca..0000000000000000000000000000000000000000 --- a/adb/pairing_connection/Android.bp +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright (C) 2020 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. - -cc_defaults { - name: "libadb_pairing_connection_defaults", - cflags: [ - "-Wall", - "-Wextra", - "-Wthread-safety", - "-Werror", - ], - - compile_multilib: "both", - - srcs: [ - "pairing_connection.cpp", - ], - target: { - android: { - version_script: "libadb_pairing_connection.map.txt", - }, - windows: { - compile_multilib: "first", - enabled: true, - }, - }, - export_include_dirs: ["include"], - - visibility: [ - "//art:__subpackages__", - "//system/core/adb:__subpackages__", - "//frameworks/base/services:__subpackages__", - - // This needs to be visible to minadbd, even though it's removed via exclude_shared_libs. - "//bootable/recovery/minadbd:__subpackages__", - ], - apex_available: [ - "com.android.adbd", - ], - - // libadb_pairing_connection doesn't need an embedded build number. - use_version_lib: false, - - stl: "libc++_static", - - host_supported: true, - recovery_available: false, - - static_libs: [ - "libbase", - "libssl", - ], - shared_libs: [ - "libcrypto", - "liblog", - "libadb_pairing_auth", - ], -} - -cc_library { - name: "libadb_pairing_connection", - defaults: ["libadb_pairing_connection_defaults"], - - apex_available: [ - "com.android.adbd", - ], - - stubs: { - symbol_file: "libadb_pairing_connection.map.txt", - versions: ["30"], - }, - - static_libs: [ - "libadb_protos", - // Statically link libadb_tls_connection because it is not - // ABI-stable. - "libadb_tls_connection", - "libprotobuf-cpp-lite", - ], -} - -// For running atest (b/147158681) -cc_library_static { - name: "libadb_pairing_connection_static", - defaults: ["libadb_pairing_connection_defaults"], - - apex_available: [ - "//apex_available:platform", - ], - - static_libs: [ - "libadb_protos_static", - "libprotobuf-cpp-lite", - "libadb_tls_connection_static", - ], -} - -cc_defaults { - name: "libadb_pairing_server_defaults", - cflags: [ - "-Wall", - "-Wextra", - "-Wthread-safety", - "-Werror", - ], - - compile_multilib: "both", - - srcs: [ - "pairing_server.cpp", - ], - target: { - android: { - version_script: "libadb_pairing_server.map.txt", - }, - }, - export_include_dirs: ["include"], - - visibility: [ - "//art:__subpackages__", - "//system/core/adb:__subpackages__", - "//frameworks/base/services:__subpackages__", - ], - - host_supported: true, - recovery_available: false, - - stl: "libc++_static", - - static_libs: [ - "libbase", - ], - shared_libs: [ - "libcrypto", - "libcrypto_utils", - "libcutils", - "liblog", - "libadb_pairing_auth", - "libadb_pairing_connection", - ], -} - -cc_library { - name: "libadb_pairing_server", - defaults: ["libadb_pairing_server_defaults"], - - apex_available: [ - "com.android.adbd", - ], - - stubs: { - symbol_file: "libadb_pairing_server.map.txt", - versions: ["30"], - }, - - static_libs: [ - // Statically link libadb_crypto because it is not - // ABI-stable. - "libadb_crypto", - "libadb_protos", - ], -} - -// For running atest (b/147158681) -cc_library_static { - name: "libadb_pairing_server_static", - defaults: ["libadb_pairing_server_defaults"], - - apex_available: [ - "//apex_available:platform", - ], - - static_libs: [ - "libadb_crypto_static", - "libadb_protos_static", - ], -} diff --git a/adb/pairing_connection/include/adb/pairing/pairing_connection.h b/adb/pairing_connection/include/adb/pairing/pairing_connection.h deleted file mode 100644 index 3543b87389f3827ef0650d7f874f95fcc6c91635..0000000000000000000000000000000000000000 --- a/adb/pairing_connection/include/adb/pairing/pairing_connection.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (C) 2020 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. - */ - -#pragma once - -#include -#include -#include - -#if !defined(__INTRODUCED_IN) -#define __INTRODUCED_IN(__api_level) /* nothing */ -#endif - -// These APIs are for the Adb pairing protocol. This protocol requires both -// sides to possess a shared secret to authenticate each other. The connection -// is over TLS, and requires that both the client and server have a valid -// certificate. -// -// This protocol is one-to-one, i.e., one PairingConnectionCtx server instance -// interacts with only one PairingConnectionCtx client instance. In other words, -// every new client instance must be bound to a new server instance. -// -// If both sides have authenticated, they will exchange their peer information -// (see #PeerInfo). -__BEGIN_DECLS -#if !defined(__ANDROID__) || __ANDROID_API__ >= 30 - -const uint32_t kMaxPeerInfoSize = 8192; -struct PeerInfo { - uint8_t type; - uint8_t data[kMaxPeerInfoSize - 1]; -} __attribute__((packed)); -typedef struct PeerInfo PeerInfo; -static_assert(sizeof(PeerInfo) == kMaxPeerInfoSize, "PeerInfo has weird size"); - -enum PeerInfoType : uint8_t { - ADB_RSA_PUB_KEY = 0, - ADB_DEVICE_GUID = 1, -}; - -struct PairingConnectionCtx; -typedef struct PairingConnectionCtx PairingConnectionCtx; -typedef void (*pairing_result_cb)(const PeerInfo*, int, void*); - -// Starts the pairing connection on a separate thread. -// -// Upon completion, if the pairing was successful, -// |cb| will be called with the peer information and certificate. -// Otherwise, |cb| will be called with empty data. |fd| should already -// be opened. PairingConnectionCtx will take ownership of the |fd|. -// -// Pairing is successful if both server/client uses the same non-empty -// |pswd|, and they are able to exchange the information. |pswd| and -// |certificate| must be non-empty. start() can only be called once in the -// lifetime of this object. -// -// @param ctx the PairingConnectionCtx instance. Will abort if null. -// @param fd the fd connecting the peers. This will take ownership of fd. -// @param cb the user-provided callback that is called with the result of the -// pairing. The callback will be called on a different thread from the -// caller. -// @param opaque opaque userdata. -// @return true if the thread was successfully started, false otherwise. To stop -// the connection process, destroy the instance (see -// #pairing_connection_destroy). If false is returned, cb will not be -// invoked. Otherwise, cb is guaranteed to be invoked, even if you -// destroy the ctx while in the pairing process. -bool pairing_connection_start(PairingConnectionCtx* ctx, int fd, pairing_result_cb cb, void* opaque) - __INTRODUCED_IN(30); - -// Creates a new PairingConnectionCtx instance as the client. -// -// @param pswd the password to authenticate both peers. Will abort if null. -// @param pswd_len the length of pswd. Will abort if 0. -// @param peer_info the PeerInfo struct that is exchanged between peers if the -// pairing was successful. Will abort if null. -// @param x509_cert_pem the X.509 certificate in PEM format. Will abort if null. -// @param x509_size the size of x509_cert_pem. Will abort if 0. -// @param priv_key_pem the private key corresponding to the given X.509 -// certificate, in PEM format. Will abort if null. -// @param priv_size the size of priv_key_pem. Will abort if 0. -// @return a new PairingConnectionCtx client instance. The caller is responsible -// for destroying the context via #pairing_connection_destroy. -PairingConnectionCtx* pairing_connection_client_new(const uint8_t* pswd, size_t pswd_len, - const PeerInfo* peer_info, - const uint8_t* x509_cert_pem, size_t x509_size, - const uint8_t* priv_key_pem, size_t priv_size) - __INTRODUCED_IN(30); - -// Creates a new PairingConnectionCtx instance as the server. -// -// @param pswd the password to authenticate both peers. Will abort if null. -// @param pswd_len the length of pswd. Will abort if 0. -// @param peer_info the PeerInfo struct that is exchanged between peers if the -// pairing was successful. Will abort if null. -// @param x509_cert_pem the X.509 certificate in PEM format. Will abort if null. -// @param x509_size the size of x509_cert_pem. Will abort if 0. -// @param priv_key_pem the private key corresponding to the given X.509 -// certificate, in PEM format. Will abort if null. -// @param priv_size the size of priv_key_pem. Will abort if 0. -// @return a new PairingConnectionCtx server instance. The caller is responsible -// for destroying the context via #pairing_connection_destroy. -PairingConnectionCtx* pairing_connection_server_new(const uint8_t* pswd, size_t pswd_len, - const PeerInfo* peer_info, - const uint8_t* x509_cert_pem, size_t x509_size, - const uint8_t* priv_key_pem, size_t priv_size) - __INTRODUCED_IN(30); - -// Destroys the PairingConnectionCtx instance. -// -// It is safe to destroy the instance at any point in the pairing process. -// -// @param ctx the PairingConnectionCtx instance to destroy. Will abort if null. -void pairing_connection_destroy(PairingConnectionCtx* ctx) __INTRODUCED_IN(30); - -#endif //!__ANDROID__ || __ANDROID_API__ >= 30 -__END_DECLS diff --git a/adb/pairing_connection/include/adb/pairing/pairing_server.h b/adb/pairing_connection/include/adb/pairing/pairing_server.h deleted file mode 100644 index 178a174bdbb5b605712de07b34c14dca7873636b..0000000000000000000000000000000000000000 --- a/adb/pairing_connection/include/adb/pairing/pairing_server.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2020 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. - */ - -#pragma once - -#include -#include -#include - -#include -#include -#include -#include - -#include "adb/pairing/pairing_connection.h" - -#if !defined(__INTRODUCED_IN) -#define __INTRODUCED_IN(__api_level) /* nothing */ -#endif - -__BEGIN_DECLS -#if !defined(__ANDROID__) || __ANDROID_API__ >= 30 - -// PairingServerCtx is a wrapper around the #PairingConnectionCtx APIs, -// which handles multiple client connections. -// -// See pairing_connection_test.cpp for example usage. -// -struct PairingServerCtx; -typedef struct PairingServerCtx PairingServerCtx; - -// Callback containing the result of the pairing. If #PeerInfo is null, -// then the pairing failed. Otherwise, pairing succeeded and #PeerInfo -// contains information about the peer. -typedef void (*pairing_server_result_cb)(const PeerInfo*, void*) __INTRODUCED_IN(30); - -// Starts the pairing server. -// -// This call is non-blocking. Upon completion, if the pairing was successful, -// then |cb| will be called with the PeerInfo -// containing the info of the trusted peer. Otherwise, |cb| will be -// called with an empty value. Start can only be called once in the lifetime -// of this object. -// -// @param ctx the PairingServerCtx instance. -// @param cb the user-provided callback to notify the result of the pairing. See -// #pairing_server_result_cb. -// @param opaque the opaque userdata. -// @return the port number the server is listening on. Returns 0 on failure. -uint16_t pairing_server_start(PairingServerCtx* ctx, pairing_server_result_cb cb, void* opaque) - __INTRODUCED_IN(30); - -// Creates a new PairingServerCtx instance. -// -// @param pswd the password used to authenticate the client and server. -// @param pswd_len the length of pswd. -// @param peer_info the #PeerInfo struct passed to the client on successful -// pairing. -// @param x509_cert_pem the X.509 certificate in PEM format. Cannot be empty. -// @param x509_size the size of x509_cert_pem. -// @param priv_key_pem the private key corresponding to the given X.509 -// certificate, in PEM format. Cannot be empty. -// @param priv_size the size of priv_key_pem. -// @param port the port number the server should listen on. Must be within the -// valid port range [0, 65535]. If port is 0, then the server will -// find an open port to listen on. See #pairing_server_start to -// obtain the port used. -// @return a new PairingServerCtx instance The caller is responsible -// for destroying the context via #pairing_server_destroy. -PairingServerCtx* pairing_server_new(const uint8_t* pswd, size_t pswd_len, - const PeerInfo* peer_info, const uint8_t* x509_cert_pem, - size_t x509_size, const uint8_t* priv_key_pem, - size_t priv_size, uint16_t port) __INTRODUCED_IN(30); - -// Same as #pairing_server_new, except that the x509 certificate and private key -// is generated internally. -// -// @param pswd the password used to authenticate the client and server. -// @param pswd_len the length of pswd. -// @param peer_info the #PeerInfo struct passed to the client on successful -// pairing. -// @param port the port number the server should listen on. Must be within the -// valid port range [0, 65535]. If port is 0, then the server will -// find an open port to listen on. See #pairing_server_start to -// obtain the port used. -// @return a new PairingServerCtx instance The caller is responsible -// for destroying the context via #pairing_server_destroy. -PairingServerCtx* pairing_server_new_no_cert(const uint8_t* pswd, size_t pswd_len, - const PeerInfo* peer_info, uint16_t port) - __INTRODUCED_IN(30); - -// Destroys the PairingServerCtx instance. -// -// @param ctx the PairingServerCtx instance to destroy. -void pairing_server_destroy(PairingServerCtx* ctx) __INTRODUCED_IN(30); - -#endif //!__ANDROID__ || __ANDROID_API__ >= 30 -__END_DECLS diff --git a/adb/pairing_connection/internal/constants.h b/adb/pairing_connection/internal/constants.h deleted file mode 100644 index 9a04f174e81c6e41e7ded1d135803a0185a5051a..0000000000000000000000000000000000000000 --- a/adb/pairing_connection/internal/constants.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2020 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. - */ - -#pragma once - -// This file contains constants that can be used both in the pairing_connection -// code and tested in the pairing_connection_test code. -namespace adb { -namespace pairing { -namespace internal { - -// The maximum number of connections the PairingServer can handle at once. -constexpr int kMaxConnections = 10; -// The maximum number of attempts the PairingServer will take before quitting. -// This is to prevent someone malicious from quickly brute-forcing every -// combination. -constexpr int kMaxPairingAttempts = 20; - -} // namespace internal -} // namespace pairing -} // namespace adb diff --git a/adb/pairing_connection/libadb_pairing_connection.map.txt b/adb/pairing_connection/libadb_pairing_connection.map.txt deleted file mode 100644 index abd5f16d42d509b1000620a98416fee114c05fec..0000000000000000000000000000000000000000 --- a/adb/pairing_connection/libadb_pairing_connection.map.txt +++ /dev/null @@ -1,10 +0,0 @@ -LIBADB_PAIRING_CONNECTION { - global: - pairing_connection_client_new; # apex introduced=30 - pairing_connection_server_new; # apex introduced=30 - pairing_connection_start; # apex introduced=30 - pairing_connection_destroy; # apex introduced=30 - - local: - *; -}; diff --git a/adb/pairing_connection/libadb_pairing_server.map.txt b/adb/pairing_connection/libadb_pairing_server.map.txt deleted file mode 100644 index dc0dc89a37717fe14699e5f6926b6dffb535713d..0000000000000000000000000000000000000000 --- a/adb/pairing_connection/libadb_pairing_server.map.txt +++ /dev/null @@ -1,10 +0,0 @@ -LIBADB_PAIRING_SERVER { - global: - pairing_server_start; # apex introduced=30 - pairing_server_new; # apex introduced=30 - pairing_server_new_no_cert; # apex introduced=30 - pairing_server_destroy; # apex introduced=30 - - local: - *; -}; diff --git a/adb/pairing_connection/pairing_connection.cpp b/adb/pairing_connection/pairing_connection.cpp deleted file mode 100644 index ffe49a91e34c263c69a34bc002e4a4e4c17c8e11..0000000000000000000000000000000000000000 --- a/adb/pairing_connection/pairing_connection.cpp +++ /dev/null @@ -1,491 +0,0 @@ -/* - * Copyright (C) 2020 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 "adb/pairing/pairing_connection.h" - -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "pairing.pb.h" - -using namespace adb; -using android::base::unique_fd; -using TlsError = tls::TlsConnection::TlsError; - -const uint8_t kCurrentKeyHeaderVersion = 1; -const uint8_t kMinSupportedKeyHeaderVersion = 1; -const uint8_t kMaxSupportedKeyHeaderVersion = 1; -const uint32_t kMaxPayloadSize = kMaxPeerInfoSize * 2; - -struct PairingPacketHeader { - uint8_t version; // PairingPacket version - uint8_t type; // the type of packet (PairingPacket.Type) - uint32_t payload; // Size of the payload in bytes -} __attribute__((packed)); - -struct PairingAuthDeleter { - void operator()(PairingAuthCtx* p) { pairing_auth_destroy(p); } -}; // PairingAuthDeleter -using PairingAuthPtr = std::unique_ptr; - -// PairingConnectionCtx encapsulates the protocol to authenticate two peers with -// each other. This class will open the tcp sockets and handle the pairing -// process. On completion, both sides will have each other's public key -// (certificate) if successful, otherwise, the pairing failed. The tcp port -// number is hardcoded (see pairing_connection.cpp). -// -// Each PairingConnectionCtx instance represents a different device trying to -// pair. So for the device, we can have multiple PairingConnectionCtxs while the -// host may have only one (unless host has a PairingServer). -// -// See pairing_connection_test.cpp for example usage. -// -struct PairingConnectionCtx { - public: - using Data = std::vector; - using ResultCallback = pairing_result_cb; - enum class Role { - Client, - Server, - }; - - explicit PairingConnectionCtx(Role role, const Data& pswd, const PeerInfo& peer_info, - const Data& certificate, const Data& priv_key); - virtual ~PairingConnectionCtx(); - - // Starts the pairing connection on a separate thread. - // Upon completion, if the pairing was successful, - // |cb| will be called with the peer information and certificate. - // Otherwise, |cb| will be called with empty data. |fd| should already - // be opened. PairingConnectionCtx will take ownership of the |fd|. - // - // Pairing is successful if both server/client uses the same non-empty - // |pswd|, and they are able to exchange the information. |pswd| and - // |certificate| must be non-empty. Start() can only be called once in the - // lifetime of this object. - // - // Returns true if the thread was successfully started, false otherwise. - bool Start(int fd, ResultCallback cb, void* opaque); - - private: - // Setup the tls connection. - bool SetupTlsConnection(); - - /************ PairingPacketHeader methods ****************/ - // Tries to write out the header and payload. - bool WriteHeader(const PairingPacketHeader* header, std::string_view payload); - // Tries to parse incoming data into the |header|. Returns true if header - // is valid and header version is supported. |header| is filled on success. - // |header| may contain garbage if unsuccessful. - bool ReadHeader(PairingPacketHeader* header); - // Creates a PairingPacketHeader. - void CreateHeader(PairingPacketHeader* header, adb::proto::PairingPacket::Type type, - uint32_t payload_size); - // Checks if actual matches expected. - bool CheckHeaderType(adb::proto::PairingPacket::Type expected, uint8_t actual); - - /*********** State related methods **************/ - // Handles the State::ExchangingMsgs state. - bool DoExchangeMsgs(); - // Handles the State::ExchangingPeerInfo state. - bool DoExchangePeerInfo(); - - // The background task to do the pairing. - void StartWorker(); - - // Calls |cb_| and sets the state to Stopped. - void NotifyResult(const PeerInfo* p); - - static PairingAuthPtr CreatePairingAuthPtr(Role role, const Data& pswd); - - enum class State { - Ready, - ExchangingMsgs, - ExchangingPeerInfo, - Stopped, - }; - - std::atomic state_{State::Ready}; - Role role_; - Data pswd_; - PeerInfo peer_info_; - Data cert_; - Data priv_key_; - - // Peer's info - PeerInfo their_info_; - - ResultCallback cb_; - void* opaque_ = nullptr; - std::unique_ptr tls_; - PairingAuthPtr auth_; - unique_fd fd_; - std::thread thread_; - static constexpr size_t kExportedKeySize = 64; -}; // PairingConnectionCtx - -PairingConnectionCtx::PairingConnectionCtx(Role role, const Data& pswd, const PeerInfo& peer_info, - const Data& cert, const Data& priv_key) - : role_(role), pswd_(pswd), peer_info_(peer_info), cert_(cert), priv_key_(priv_key) { - CHECK(!pswd_.empty() && !cert_.empty() && !priv_key_.empty()); -} - -PairingConnectionCtx::~PairingConnectionCtx() { - // Force close the fd and wait for the worker thread to finish. - fd_.reset(); - if (thread_.joinable()) { - thread_.join(); - } -} - -bool PairingConnectionCtx::SetupTlsConnection() { - tls_ = tls::TlsConnection::Create( - role_ == Role::Server ? tls::TlsConnection::Role::Server - : tls::TlsConnection::Role::Client, - std::string_view(reinterpret_cast(cert_.data()), cert_.size()), - std::string_view(reinterpret_cast(priv_key_.data()), priv_key_.size()), - fd_); - - if (tls_ == nullptr) { - LOG(ERROR) << "Unable to start TlsConnection. Unable to pair fd=" << fd_.get(); - return false; - } - - // Allow any peer certificate - tls_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; }); - - // SSL doesn't seem to behave correctly with fdevents so just do a blocking - // read for the pairing data. - if (tls_->DoHandshake() != TlsError::Success) { - LOG(ERROR) << "Failed to handshake with the peer fd=" << fd_.get(); - return false; - } - - // To ensure the connection is not stolen while we do the PAKE, append the - // exported key material from the tls connection to the password. - std::vector exportedKeyMaterial = tls_->ExportKeyingMaterial(kExportedKeySize); - if (exportedKeyMaterial.empty()) { - LOG(ERROR) << "Failed to export key material"; - return false; - } - pswd_.insert(pswd_.end(), std::make_move_iterator(exportedKeyMaterial.begin()), - std::make_move_iterator(exportedKeyMaterial.end())); - auth_ = CreatePairingAuthPtr(role_, pswd_); - - return true; -} - -bool PairingConnectionCtx::WriteHeader(const PairingPacketHeader* header, - std::string_view payload) { - PairingPacketHeader network_header = *header; - network_header.payload = htonl(network_header.payload); - if (!tls_->WriteFully(std::string_view(reinterpret_cast(&network_header), - sizeof(PairingPacketHeader))) || - !tls_->WriteFully(payload)) { - LOG(ERROR) << "Failed to write out PairingPacketHeader"; - state_ = State::Stopped; - return false; - } - return true; -} - -bool PairingConnectionCtx::ReadHeader(PairingPacketHeader* header) { - auto data = tls_->ReadFully(sizeof(PairingPacketHeader)); - if (data.empty()) { - return false; - } - - uint8_t* p = data.data(); - // First byte is always PairingPacketHeader version - header->version = *p; - ++p; - if (header->version < kMinSupportedKeyHeaderVersion || - header->version > kMaxSupportedKeyHeaderVersion) { - LOG(ERROR) << "PairingPacketHeader version mismatch (us=" << kCurrentKeyHeaderVersion - << " them=" << header->version << ")"; - return false; - } - // Next byte is the PairingPacket::Type - if (!adb::proto::PairingPacket::Type_IsValid(*p)) { - LOG(ERROR) << "Unknown PairingPacket type=" << static_cast(*p); - return false; - } - header->type = *p; - ++p; - // Last, the payload size - header->payload = ntohl(*(reinterpret_cast(p))); - if (header->payload == 0 || header->payload > kMaxPayloadSize) { - LOG(ERROR) << "header payload not within a safe payload size (size=" << header->payload - << ")"; - return false; - } - - return true; -} - -void PairingConnectionCtx::CreateHeader(PairingPacketHeader* header, - adb::proto::PairingPacket::Type type, - uint32_t payload_size) { - header->version = kCurrentKeyHeaderVersion; - uint8_t type8 = static_cast(static_cast(type)); - header->type = type8; - header->payload = payload_size; -} - -bool PairingConnectionCtx::CheckHeaderType(adb::proto::PairingPacket::Type expected_type, - uint8_t actual) { - uint8_t expected = *reinterpret_cast(&expected_type); - if (actual != expected) { - LOG(ERROR) << "Unexpected header type (expected=" << static_cast(expected) - << " actual=" << static_cast(actual) << ")"; - return false; - } - return true; -} - -void PairingConnectionCtx::NotifyResult(const PeerInfo* p) { - cb_(p, fd_.get(), opaque_); - state_ = State::Stopped; -} - -bool PairingConnectionCtx::Start(int fd, ResultCallback cb, void* opaque) { - if (fd < 0) { - return false; - } - fd_.reset(fd); - - State expected = State::Ready; - if (!state_.compare_exchange_strong(expected, State::ExchangingMsgs)) { - return false; - } - - cb_ = cb; - opaque_ = opaque; - - thread_ = std::thread([this] { StartWorker(); }); - return true; -} - -bool PairingConnectionCtx::DoExchangeMsgs() { - uint32_t payload = pairing_auth_msg_size(auth_.get()); - std::vector msg(payload); - pairing_auth_get_spake2_msg(auth_.get(), msg.data()); - - PairingPacketHeader header; - CreateHeader(&header, adb::proto::PairingPacket::SPAKE2_MSG, payload); - - // Write our SPAKE2 msg - if (!WriteHeader(&header, - std::string_view(reinterpret_cast(msg.data()), msg.size()))) { - LOG(ERROR) << "Failed to write SPAKE2 msg."; - return false; - } - - // Read the peer's SPAKE2 msg header - if (!ReadHeader(&header)) { - LOG(ERROR) << "Invalid PairingPacketHeader."; - return false; - } - if (!CheckHeaderType(adb::proto::PairingPacket::SPAKE2_MSG, header.type)) { - return false; - } - - // Read the SPAKE2 msg payload and initialize the cipher for - // encrypting the PeerInfo and certificate. - auto their_msg = tls_->ReadFully(header.payload); - if (their_msg.empty() || - !pairing_auth_init_cipher(auth_.get(), their_msg.data(), their_msg.size())) { - LOG(ERROR) << "Unable to initialize pairing cipher [their_msg.size=" << their_msg.size() - << "]"; - return false; - } - - return true; -} - -bool PairingConnectionCtx::DoExchangePeerInfo() { - // Encrypt PeerInfo - std::vector buf; - uint8_t* p = reinterpret_cast(&peer_info_); - buf.assign(p, p + sizeof(peer_info_)); - std::vector outbuf(pairing_auth_safe_encrypted_size(auth_.get(), buf.size())); - CHECK(!outbuf.empty()); - size_t outsize; - if (!pairing_auth_encrypt(auth_.get(), buf.data(), buf.size(), outbuf.data(), &outsize)) { - LOG(ERROR) << "Failed to encrypt peer info"; - return false; - } - outbuf.resize(outsize); - - // Write out the packet header - PairingPacketHeader out_header; - out_header.version = kCurrentKeyHeaderVersion; - out_header.type = static_cast(static_cast(adb::proto::PairingPacket::PEER_INFO)); - out_header.payload = htonl(outbuf.size()); - if (!tls_->WriteFully( - std::string_view(reinterpret_cast(&out_header), sizeof(out_header)))) { - LOG(ERROR) << "Unable to write PairingPacketHeader"; - return false; - } - - // Write out the encrypted payload - if (!tls_->WriteFully( - std::string_view(reinterpret_cast(outbuf.data()), outbuf.size()))) { - LOG(ERROR) << "Unable to write encrypted peer info"; - return false; - } - - // Read in the peer's packet header - PairingPacketHeader header; - if (!ReadHeader(&header)) { - LOG(ERROR) << "Invalid PairingPacketHeader."; - return false; - } - - if (!CheckHeaderType(adb::proto::PairingPacket::PEER_INFO, header.type)) { - return false; - } - - // Read in the encrypted peer certificate - buf = tls_->ReadFully(header.payload); - if (buf.empty()) { - return false; - } - - // Try to decrypt the certificate - outbuf.resize(pairing_auth_safe_decrypted_size(auth_.get(), buf.data(), buf.size())); - if (outbuf.empty()) { - LOG(ERROR) << "Unsupported payload while decrypting peer info."; - return false; - } - - if (!pairing_auth_decrypt(auth_.get(), buf.data(), buf.size(), outbuf.data(), &outsize)) { - LOG(ERROR) << "Failed to decrypt"; - return false; - } - outbuf.resize(outsize); - - // The decrypted message should contain the PeerInfo. - if (outbuf.size() != sizeof(PeerInfo)) { - LOG(ERROR) << "Got size=" << outbuf.size() << "PeerInfo.size=" << sizeof(PeerInfo); - return false; - } - - p = outbuf.data(); - ::memcpy(&their_info_, p, sizeof(PeerInfo)); - p += sizeof(PeerInfo); - - return true; -} - -void PairingConnectionCtx::StartWorker() { - // Setup the secure transport - if (!SetupTlsConnection()) { - NotifyResult(nullptr); - return; - } - - for (;;) { - switch (state_) { - case State::ExchangingMsgs: - if (!DoExchangeMsgs()) { - NotifyResult(nullptr); - return; - } - state_ = State::ExchangingPeerInfo; - break; - case State::ExchangingPeerInfo: - if (!DoExchangePeerInfo()) { - NotifyResult(nullptr); - return; - } - NotifyResult(&their_info_); - return; - case State::Ready: - case State::Stopped: - LOG(FATAL) << __func__ << ": Got invalid state"; - return; - } - } -} - -// static -PairingAuthPtr PairingConnectionCtx::CreatePairingAuthPtr(Role role, const Data& pswd) { - switch (role) { - case Role::Client: - return PairingAuthPtr(pairing_auth_client_new(pswd.data(), pswd.size())); - break; - case Role::Server: - return PairingAuthPtr(pairing_auth_server_new(pswd.data(), pswd.size())); - break; - } -} - -static PairingConnectionCtx* CreateConnection(PairingConnectionCtx::Role role, const uint8_t* pswd, - size_t pswd_len, const PeerInfo* peer_info, - const uint8_t* x509_cert_pem, size_t x509_size, - const uint8_t* priv_key_pem, size_t priv_size) { - CHECK(pswd); - CHECK_GT(pswd_len, 0U); - CHECK(x509_cert_pem); - CHECK_GT(x509_size, 0U); - CHECK(priv_key_pem); - CHECK_GT(priv_size, 0U); - CHECK(peer_info); - std::vector vec_pswd(pswd, pswd + pswd_len); - std::vector vec_x509_cert(x509_cert_pem, x509_cert_pem + x509_size); - std::vector vec_priv_key(priv_key_pem, priv_key_pem + priv_size); - return new PairingConnectionCtx(role, vec_pswd, *peer_info, vec_x509_cert, vec_priv_key); -} - -PairingConnectionCtx* pairing_connection_client_new(const uint8_t* pswd, size_t pswd_len, - const PeerInfo* peer_info, - const uint8_t* x509_cert_pem, size_t x509_size, - const uint8_t* priv_key_pem, size_t priv_size) { - return CreateConnection(PairingConnectionCtx::Role::Client, pswd, pswd_len, peer_info, - x509_cert_pem, x509_size, priv_key_pem, priv_size); -} - -PairingConnectionCtx* pairing_connection_server_new(const uint8_t* pswd, size_t pswd_len, - const PeerInfo* peer_info, - const uint8_t* x509_cert_pem, size_t x509_size, - const uint8_t* priv_key_pem, size_t priv_size) { - return CreateConnection(PairingConnectionCtx::Role::Server, pswd, pswd_len, peer_info, - x509_cert_pem, x509_size, priv_key_pem, priv_size); -} - -void pairing_connection_destroy(PairingConnectionCtx* ctx) { - CHECK(ctx); - delete ctx; -} - -bool pairing_connection_start(PairingConnectionCtx* ctx, int fd, pairing_result_cb cb, - void* opaque) { - return ctx->Start(fd, cb, opaque); -} diff --git a/adb/pairing_connection/pairing_server.cpp b/adb/pairing_connection/pairing_server.cpp deleted file mode 100644 index 7218eacf2c06b25a961835b0cf70cfd634891419..0000000000000000000000000000000000000000 --- a/adb/pairing_connection/pairing_server.cpp +++ /dev/null @@ -1,466 +0,0 @@ -/* - * Copyright (C) 2020 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 "adb/pairing/pairing_server.h" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "internal/constants.h" - -using android::base::ScopedLockAssertion; -using android::base::unique_fd; -using namespace adb::crypto; -using namespace adb::pairing; - -// The implementation has two background threads running: one to handle and -// accept any new pairing connection requests (socket accept), and the other to -// handle connection events (connection started, connection finished). -struct PairingServerCtx { - public: - using Data = std::vector; - - virtual ~PairingServerCtx(); - - // All parameters must be non-empty. - explicit PairingServerCtx(const Data& pswd, const PeerInfo& peer_info, const Data& cert, - const Data& priv_key, uint16_t port); - - // Starts the pairing server. This call is non-blocking. Upon completion, - // if the pairing was successful, then |cb| will be called with the PublicKeyHeader - // containing the info of the trusted peer. Otherwise, |cb| will be - // called with an empty value. Start can only be called once in the lifetime - // of this object. - // - // Returns the port number if PairingServerCtx was successfully started. Otherwise, - // returns 0. - uint16_t Start(pairing_server_result_cb cb, void* opaque); - - private: - // Setup the server socket to accept incoming connections. Returns the - // server port number (> 0 on success). - uint16_t SetupServer(); - // Force stop the server thread. - void StopServer(); - - // handles a new pairing client connection - bool HandleNewClientConnection(int fd) EXCLUDES(conn_mutex_); - - // ======== connection events thread ============= - std::mutex conn_mutex_; - std::condition_variable conn_cv_; - - using FdVal = int; - struct ConnectionDeleter { - void operator()(PairingConnectionCtx* p) { pairing_connection_destroy(p); } - }; - using ConnectionPtr = std::unique_ptr; - static ConnectionPtr CreatePairingConnection(const Data& pswd, const PeerInfo& peer_info, - const Data& cert, const Data& priv_key); - using NewConnectionEvent = std::tuple; - // - using ConnectionFinishedEvent = std::tuple>; - using ConnectionEvent = std::variant; - // Queue for connections to write into. We have a separate queue to read - // from, in order to minimize the time the server thread is blocked. - std::deque conn_write_queue_ GUARDED_BY(conn_mutex_); - std::deque conn_read_queue_; - // Map of fds to their PairingConnections currently running. - std::unordered_map connections_; - - // Two threads launched when starting the pairing server: - // 1) A server thread that waits for incoming client connections, and - // 2) A connection events thread that synchonizes events from all of the - // clients, since each PairingConnection is running in it's own thread. - void StartConnectionEventsThread(); - void StartServerThread(); - - static void PairingConnectionCallback(const PeerInfo* peer_info, int fd, void* opaque); - - std::thread conn_events_thread_; - void ConnectionEventsWorker(); - std::thread server_thread_; - void ServerWorker(); - bool is_terminate_ GUARDED_BY(conn_mutex_) = false; - - enum class State { - Ready, - Running, - Stopped, - }; - State state_ = State::Ready; - Data pswd_; - PeerInfo peer_info_; - Data cert_; - Data priv_key_; - uint16_t port_; - - pairing_server_result_cb cb_; - void* opaque_ = nullptr; - bool got_valid_pairing_ = false; - - static const int kEpollConstSocket = 0; - // Used to break the server thread from epoll_wait - static const int kEpollConstEventFd = 1; - unique_fd epoll_fd_; - unique_fd server_fd_; - unique_fd event_fd_; -}; // PairingServerCtx - -// static -PairingServerCtx::ConnectionPtr PairingServerCtx::CreatePairingConnection(const Data& pswd, - const PeerInfo& peer_info, - const Data& cert, - const Data& priv_key) { - return ConnectionPtr(pairing_connection_server_new(pswd.data(), pswd.size(), &peer_info, - cert.data(), cert.size(), priv_key.data(), - priv_key.size())); -} - -PairingServerCtx::PairingServerCtx(const Data& pswd, const PeerInfo& peer_info, const Data& cert, - const Data& priv_key, uint16_t port) - : pswd_(pswd), peer_info_(peer_info), cert_(cert), priv_key_(priv_key), port_(port) { - CHECK(!pswd_.empty() && !cert_.empty() && !priv_key_.empty()); -} - -PairingServerCtx::~PairingServerCtx() { - // Since these connections have references to us, let's make sure they - // destruct before us. - if (server_thread_.joinable()) { - StopServer(); - server_thread_.join(); - } - - { - std::lock_guard lock(conn_mutex_); - is_terminate_ = true; - } - conn_cv_.notify_one(); - if (conn_events_thread_.joinable()) { - conn_events_thread_.join(); - } - - // Notify the cb_ if it hasn't already. - if (!got_valid_pairing_ && cb_ != nullptr) { - cb_(nullptr, opaque_); - } -} - -uint16_t PairingServerCtx::Start(pairing_server_result_cb cb, void* opaque) { - cb_ = cb; - opaque_ = opaque; - - if (state_ != State::Ready) { - LOG(ERROR) << "PairingServerCtx already running or stopped"; - return 0; - } - - port_ = SetupServer(); - if (port_ == 0) { - LOG(ERROR) << "Unable to start PairingServer"; - state_ = State::Stopped; - return 0; - } - LOG(INFO) << "Pairing server started on port " << port_; - - state_ = State::Running; - return port_; -} - -void PairingServerCtx::StopServer() { - if (event_fd_.get() == -1) { - return; - } - uint64_t value = 1; - ssize_t rc = write(event_fd_.get(), &value, sizeof(value)); - if (rc == -1) { - // This can happen if the server didn't start. - PLOG(ERROR) << "write to eventfd failed"; - } else if (rc != sizeof(value)) { - LOG(FATAL) << "write to event returned short (" << rc << ")"; - } -} - -uint16_t PairingServerCtx::SetupServer() { - epoll_fd_.reset(epoll_create1(EPOLL_CLOEXEC)); - if (epoll_fd_ == -1) { - PLOG(ERROR) << "failed to create epoll fd"; - return 0; - } - - event_fd_.reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); - if (event_fd_ == -1) { - PLOG(ERROR) << "failed to create eventfd"; - return 0; - } - - server_fd_.reset(socket_inaddr_any_server(port_, SOCK_STREAM)); - if (server_fd_.get() == -1) { - PLOG(ERROR) << "Failed to start pairing connection server"; - return 0; - } else if (fcntl(server_fd_.get(), F_SETFD, FD_CLOEXEC) != 0) { - PLOG(ERROR) << "Failed to make server socket cloexec"; - return 0; - } else if (fcntl(server_fd_.get(), F_SETFD, O_NONBLOCK) != 0) { - PLOG(ERROR) << "Failed to make server socket nonblocking"; - return 0; - } - - StartConnectionEventsThread(); - StartServerThread(); - int port = socket_get_local_port(server_fd_.get()); - return (port <= 0 ? 0 : port); -} - -void PairingServerCtx::StartServerThread() { - server_thread_ = std::thread([this]() { ServerWorker(); }); -} - -void PairingServerCtx::StartConnectionEventsThread() { - conn_events_thread_ = std::thread([this]() { ConnectionEventsWorker(); }); -} - -void PairingServerCtx::ServerWorker() { - { - struct epoll_event event; - event.events = EPOLLIN; - event.data.u64 = kEpollConstSocket; - CHECK_EQ(0, epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, server_fd_.get(), &event)); - } - - { - struct epoll_event event; - event.events = EPOLLIN; - event.data.u64 = kEpollConstEventFd; - CHECK_EQ(0, epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, event_fd_.get(), &event)); - } - - while (true) { - struct epoll_event events[2]; - int rc = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd_.get(), events, 2, -1)); - if (rc == -1) { - PLOG(ERROR) << "epoll_wait failed"; - return; - } else if (rc == 0) { - LOG(ERROR) << "epoll_wait returned 0"; - return; - } - - for (int i = 0; i < rc; ++i) { - struct epoll_event& event = events[i]; - switch (event.data.u64) { - case kEpollConstSocket: - HandleNewClientConnection(server_fd_.get()); - break; - case kEpollConstEventFd: - uint64_t dummy; - int rc = TEMP_FAILURE_RETRY(read(event_fd_.get(), &dummy, sizeof(dummy))); - if (rc != sizeof(dummy)) { - PLOG(FATAL) << "failed to read from eventfd (rc=" << rc << ")"; - } - return; - } - } - } -} - -// static -void PairingServerCtx::PairingConnectionCallback(const PeerInfo* peer_info, int fd, void* opaque) { - auto* p = reinterpret_cast(opaque); - - ConnectionFinishedEvent event; - if (peer_info != nullptr) { - if (peer_info->type == ADB_RSA_PUB_KEY) { - event = std::make_tuple(fd, peer_info->type, - std::string(reinterpret_cast(peer_info->data))); - } else { - LOG(WARNING) << "Ignoring successful pairing because of unknown " - << "PeerInfo type=" << peer_info->type; - } - } else { - event = std::make_tuple(fd, 0, std::nullopt); - } - { - std::lock_guard lock(p->conn_mutex_); - p->conn_write_queue_.push_back(std::move(event)); - } - p->conn_cv_.notify_one(); -} - -void PairingServerCtx::ConnectionEventsWorker() { - uint8_t num_tries = 0; - for (;;) { - // Transfer the write queue to the read queue. - { - std::unique_lock lock(conn_mutex_); - ScopedLockAssertion assume_locked(conn_mutex_); - - if (is_terminate_) { - // We check |is_terminate_| twice because condition_variable's - // notify() only wakes up a thread if it is in the wait state - // prior to notify(). Furthermore, we aren't holding the mutex - // when processing the events in |conn_read_queue_|. - return; - } - if (conn_write_queue_.empty()) { - // We need to wait for new events, or the termination signal. - conn_cv_.wait(lock, [this]() REQUIRES(conn_mutex_) { - return (is_terminate_ || !conn_write_queue_.empty()); - }); - } - if (is_terminate_) { - // We're done. - return; - } - // Move all events into the read queue. - conn_read_queue_ = std::move(conn_write_queue_); - conn_write_queue_.clear(); - } - - // Process all events in the read queue. - while (conn_read_queue_.size() > 0) { - auto& event = conn_read_queue_.front(); - if (auto* p = std::get_if(&event)) { - // Ignore if we are already at the max number of connections - if (connections_.size() >= internal::kMaxConnections) { - conn_read_queue_.pop_front(); - continue; - } - auto [ufd, connection] = std::move(*p); - int fd = ufd.release(); - bool started = pairing_connection_start(connection.get(), fd, - PairingConnectionCallback, this); - if (!started) { - LOG(ERROR) << "PairingServer unable to start a PairingConnection fd=" << fd; - ufd.reset(fd); - } else { - connections_[fd] = std::move(connection); - } - } else if (auto* p = std::get_if(&event)) { - auto [fd, info_type, public_key] = std::move(*p); - if (public_key.has_value() && !public_key->empty()) { - // Valid pairing. Let's shutdown the server and close any - // pairing connections in progress. - StopServer(); - connections_.clear(); - - PeerInfo info = {}; - info.type = info_type; - strncpy(reinterpret_cast(info.data), public_key->data(), - public_key->size()); - - cb_(&info, opaque_); - - got_valid_pairing_ = true; - return; - } - // Invalid pairing. Close the invalid connection. - if (connections_.find(fd) != connections_.end()) { - connections_.erase(fd); - } - - if (++num_tries >= internal::kMaxPairingAttempts) { - cb_(nullptr, opaque_); - // To prevent the destructor from calling it again. - cb_ = nullptr; - return; - } - } - conn_read_queue_.pop_front(); - } - } -} - -bool PairingServerCtx::HandleNewClientConnection(int fd) { - unique_fd ufd(TEMP_FAILURE_RETRY(accept4(fd, nullptr, nullptr, SOCK_CLOEXEC))); - if (ufd == -1) { - PLOG(WARNING) << "adb_socket_accept failed fd=" << fd; - return false; - } - auto connection = CreatePairingConnection(pswd_, peer_info_, cert_, priv_key_); - if (connection == nullptr) { - LOG(ERROR) << "PairingServer unable to create a PairingConnection fd=" << fd; - return false; - } - // send the new connection to the connection thread for further processing - NewConnectionEvent event = std::make_tuple(std::move(ufd), std::move(connection)); - { - std::lock_guard lock(conn_mutex_); - conn_write_queue_.push_back(std::move(event)); - } - conn_cv_.notify_one(); - - return true; -} - -uint16_t pairing_server_start(PairingServerCtx* ctx, pairing_server_result_cb cb, void* opaque) { - return ctx->Start(cb, opaque); -} - -PairingServerCtx* pairing_server_new(const uint8_t* pswd, size_t pswd_len, - const PeerInfo* peer_info, const uint8_t* x509_cert_pem, - size_t x509_size, const uint8_t* priv_key_pem, - size_t priv_size, uint16_t port) { - CHECK(pswd); - CHECK_GT(pswd_len, 0U); - CHECK(x509_cert_pem); - CHECK_GT(x509_size, 0U); - CHECK(priv_key_pem); - CHECK_GT(priv_size, 0U); - CHECK(peer_info); - std::vector vec_pswd(pswd, pswd + pswd_len); - std::vector vec_x509_cert(x509_cert_pem, x509_cert_pem + x509_size); - std::vector vec_priv_key(priv_key_pem, priv_key_pem + priv_size); - return new PairingServerCtx(vec_pswd, *peer_info, vec_x509_cert, vec_priv_key, port); -} - -PairingServerCtx* pairing_server_new_no_cert(const uint8_t* pswd, size_t pswd_len, - const PeerInfo* peer_info, uint16_t port) { - auto rsa_2048 = CreateRSA2048Key(); - auto x509_cert = GenerateX509Certificate(rsa_2048->GetEvpPkey()); - std::string pkey_pem = Key::ToPEMString(rsa_2048->GetEvpPkey()); - std::string cert_pem = X509ToPEMString(x509_cert.get()); - - return pairing_server_new(pswd, pswd_len, peer_info, - reinterpret_cast(cert_pem.data()), cert_pem.size(), - reinterpret_cast(pkey_pem.data()), pkey_pem.size(), - port); -} - -void pairing_server_destroy(PairingServerCtx* ctx) { - CHECK(ctx); - delete ctx; -} diff --git a/adb/pairing_connection/tests/Android.bp b/adb/pairing_connection/tests/Android.bp deleted file mode 100644 index bf075bcb9dbd27992d5471126b4724fee53f8907..0000000000000000000000000000000000000000 --- a/adb/pairing_connection/tests/Android.bp +++ /dev/null @@ -1,47 +0,0 @@ -// -// Copyright (C) 2020 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. -// - -cc_test { - name: "adb_pairing_connection_test", - srcs: [ - "pairing_client.cpp", - "pairing_connection_test.cpp", - ], - - compile_multilib: "first", - - shared_libs: [ - "libbase", - "libcutils", - "libcrypto", - "libcrypto_utils", - "libprotobuf-cpp-lite", - "libssl", - ], - - // Let's statically link them so we don't have to install it onto the - // system image for testing. - static_libs: [ - "libadb_pairing_auth_static", - "libadb_pairing_connection_static", - "libadb_pairing_server_static", - "libadb_crypto_static", - "libadb_protos_static", - "libadb_tls_connection_static", - ], - - test_suites: ["device-tests"], -} diff --git a/adb/pairing_connection/tests/pairing_client.cpp b/adb/pairing_connection/tests/pairing_client.cpp deleted file mode 100644 index 1f3ef5a349eccf2d2f7aa2919c0a14dba7012292..0000000000000000000000000000000000000000 --- a/adb/pairing_connection/tests/pairing_client.cpp +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (C) 2020 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 "pairing_client.h" - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -namespace adb { -namespace pairing { - -using android::base::unique_fd; - -static void ConnectionDeleter(PairingConnectionCtx* p) { - pairing_connection_destroy(p); -} -using ConnectionPtr = std::unique_ptr; - -namespace { - -class PairingClientImpl : public PairingClient { - public: - explicit PairingClientImpl(const Data& pswd, const PeerInfo& peer_info, const Data& cert, - const Data& priv_key); - - // Starts the pairing client. This call is non-blocking. Upon pairing - // completion, |cb| will be called with the PeerInfo on success, - // or an empty value on failure. - // - // Returns true if PairingClient was successfully started. Otherwise, - // return false. - virtual bool Start(std::string_view ip_addr, pairing_client_result_cb cb, - void* opaque) override; - - private: - static ConnectionPtr CreatePairingConnection(const Data& pswd, const PeerInfo& peer_info, - const Data& cert, const Data& priv_key); - - static void PairingResultCallback(const PeerInfo* peer_info, int fd, void* opaque); - // Setup and start the PairingConnection - bool StartConnection(); - - enum class State { - Ready, - Running, - Stopped, - }; - - State state_ = State::Ready; - Data pswd_; - PeerInfo peer_info_; - Data cert_; - Data priv_key_; - std::string host_; - int port_; - - ConnectionPtr connection_; - pairing_client_result_cb cb_; - void* opaque_ = nullptr; -}; // PairingClientImpl - -// static -ConnectionPtr PairingClientImpl::CreatePairingConnection(const Data& pswd, - const PeerInfo& peer_info, - const Data& cert, const Data& priv_key) { - return ConnectionPtr( - pairing_connection_client_new(pswd.data(), pswd.size(), &peer_info, cert.data(), - cert.size(), priv_key.data(), priv_key.size()), - ConnectionDeleter); -} - -PairingClientImpl::PairingClientImpl(const Data& pswd, const PeerInfo& peer_info, const Data& cert, - const Data& priv_key) - : pswd_(pswd), - peer_info_(peer_info), - cert_(cert), - priv_key_(priv_key), - connection_(nullptr, ConnectionDeleter) { - CHECK(!pswd_.empty() && !cert_.empty() && !priv_key_.empty()); - - state_ = State::Ready; -} - -bool PairingClientImpl::Start(std::string_view ip_addr, pairing_client_result_cb cb, void* opaque) { - CHECK(!ip_addr.empty()); - cb_ = cb; - opaque_ = opaque; - - if (state_ != State::Ready) { - LOG(ERROR) << "PairingClient already running or finished"; - return false; - } - - // Try to parse the host address - std::string err; - CHECK(android::base::ParseNetAddress(std::string(ip_addr), &host_, &port_, nullptr, &err)); - CHECK(port_ > 0 && port_ <= 65535); - - if (!StartConnection()) { - LOG(ERROR) << "Unable to start PairingClient connection"; - state_ = State::Stopped; - return false; - } - - state_ = State::Running; - return true; -} - -static int network_connect(const std::string& host, int port, int type, int timeout, - std::string* error) { - int getaddrinfo_error = 0; - int fd = socket_network_client_timeout(host.c_str(), port, type, timeout, &getaddrinfo_error); - if (fd != -1) { - return fd; - } - if (getaddrinfo_error != 0) { - *error = android::base::StringPrintf("failed to resolve host: '%s': %s", host.c_str(), - gai_strerror(getaddrinfo_error)); - LOG(WARNING) << *error; - } else { - *error = android::base::StringPrintf("failed to connect to '%s:%d': %s", host.c_str(), port, - strerror(errno)); - LOG(WARNING) << *error; - } - return -1; -} - -// static -void PairingClientImpl::PairingResultCallback(const PeerInfo* peer_info, int /* fd */, - void* opaque) { - auto* p = reinterpret_cast(opaque); - p->cb_(peer_info, p->opaque_); -} - -bool PairingClientImpl::StartConnection() { - std::string err; - const int timeout = 10; // seconds - unique_fd fd(network_connect(host_, port_, SOCK_STREAM, timeout, &err)); - if (fd.get() == -1) { - LOG(ERROR) << "Failed to start pairing connection client [" << err << "]"; - return false; - } - int off = 1; - setsockopt(fd.get(), IPPROTO_TCP, TCP_NODELAY, &off, sizeof(off)); - - connection_ = CreatePairingConnection(pswd_, peer_info_, cert_, priv_key_); - if (connection_ == nullptr) { - LOG(ERROR) << "PairingClient unable to create a PairingConnection"; - return false; - } - - if (!pairing_connection_start(connection_.get(), fd.release(), PairingResultCallback, this)) { - LOG(ERROR) << "PairingClient failed to start the PairingConnection"; - state_ = State::Stopped; - return false; - } - - return true; -} - -} // namespace - -// static -std::unique_ptr PairingClient::Create(const Data& pswd, const PeerInfo& peer_info, - const Data& cert, const Data& priv_key) { - CHECK(!pswd.empty()); - CHECK(!cert.empty()); - CHECK(!priv_key.empty()); - - return std::unique_ptr(new PairingClientImpl(pswd, peer_info, cert, priv_key)); -} - -} // namespace pairing -} // namespace adb diff --git a/adb/pairing_connection/tests/pairing_client.h b/adb/pairing_connection/tests/pairing_client.h deleted file mode 100644 index be0db5ce4c10450af09f7cc8edb11ba9e4d786ea..0000000000000000000000000000000000000000 --- a/adb/pairing_connection/tests/pairing_client.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2020 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. - */ - -#pragma once - -#include -#include - -#include -#include -#include -#include - -#include "adb/pairing/pairing_connection.h" - -typedef void (*pairing_client_result_cb)(const PeerInfo*, void*); - -namespace adb { -namespace pairing { - -// PairingClient is the client side of the PairingConnection protocol. It will -// attempt to connect to a PairingServer specified at |host| and |port|, and -// allocate a new PairingConnection for processing. -// -// See pairing_connection_test.cpp for example usage. -// -class PairingClient { - public: - using Data = std::vector; - - virtual ~PairingClient() = default; - - // Starts the pairing client. This call is non-blocking. Upon completion, - // if the pairing was successful, then |cb| will be called with the PeerInfo - // containing the info of the trusted peer. Otherwise, |cb| will be - // called with an empty value. Start can only be called once in the lifetime - // of this object. |ip_addr| requires a port to be specified. - // - // Returns true if PairingClient was successfully started. Otherwise, - // returns false. - virtual bool Start(std::string_view ip_addr, pairing_client_result_cb cb, void* opaque) = 0; - - // Creates a new PairingClient instance. May return null if unable - // to create an instance. |pswd|, |certificate|, |priv_key| and - // |ip_addr| cannot be empty. |peer_info| must contain non-empty strings for - // the guid and name fields. - static std::unique_ptr Create(const Data& pswd, const PeerInfo& peer_info, - const Data& certificate, const Data& priv_key); - - protected: - PairingClient() = default; -}; // class PairingClient - -} // namespace pairing -} // namespace adb diff --git a/adb/pairing_connection/tests/pairing_connection_test.cpp b/adb/pairing_connection/tests/pairing_connection_test.cpp deleted file mode 100644 index b6e09f190452e0c276e032832a61c0e1e042a015..0000000000000000000000000000000000000000 --- a/adb/pairing_connection/tests/pairing_connection_test.cpp +++ /dev/null @@ -1,500 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "AdbPairingConnectionTest" - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "../internal/constants.h" -#include "pairing_client.h" - -using namespace std::chrono_literals; - -namespace adb { -namespace pairing { - -// Test X.509 certificates (RSA 2048) -static const std::string kTestRsa2048ServerCert = - "-----BEGIN CERTIFICATE-----\n" - "MIIDFzCCAf+gAwIBAgIBATANBgkqhkiG9w0BAQsFADAtMQswCQYDVQQGEwJVUzEQ\n" - "MA4GA1UECgwHQW5kcm9pZDEMMAoGA1UEAwwDQWRiMB4XDTIwMDEyMTIyMjU1NVoX\n" - "DTMwMDExODIyMjU1NVowLTELMAkGA1UEBhMCVVMxEDAOBgNVBAoMB0FuZHJvaWQx\n" - "DDAKBgNVBAMMA0FkYjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK8E\n" - "2Ck9TfuKlz7wqWdMfknjZ1luFDp2IHxAUZzh/F6jeI2dOFGAjpeloSnGOE86FIaT\n" - "d1EvpyTh7nBwbrLZAA6XFZTo7Bl6BdNOQdqb2d2+cLEN0inFxqUIycevRtohUE1Y\n" - "FHM9fg442X1jOTWXjDZWeiqFWo95paAPhzm6pWqfJK1+YKfT1LsWZpYqJGGQE5pi\n" - "C3qOBYYgFpoXMxTYJNoZo3uOYEdM6upc8/vh15nMgIxX/ymJxEY5BHPpZPPWjXLg\n" - "BfzVaV9fUfv0JT4HQ4t2WvxC3cD/UsjWp2a6p454uUp2ENrANa+jRdRJepepg9D2\n" - "DKsx9L8zjc5Obqexrt0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B\n" - "Af8EBAMCAYYwHQYDVR0OBBYEFDFW+8GTErwoZN5Uu9KyY4QdGYKpMA0GCSqGSIb3\n" - "DQEBCwUAA4IBAQBCDEn6SHXGlq5TU7J8cg1kRPd9bsJW+0hDuKSq0REXDkl0PcBf\n" - "fy282Agg9enKPPKmnpeQjM1dmnxdM8tT8LIUbMl779i3fn6v9HJVB+yG4gmRFThW\n" - "c+AGlBnrIT820cX/gU3h3R3FTahfsq+1rrSJkEgHyuC0HYeRyveSckBdaEOLvx0S\n" - "toun+32JJl5hWydpUUZhE9Mbb3KHBRM2YYZZU9JeJ08Apjl+3lRUeMAUwI5fkAAu\n" - "z/1SqnuGL96bd8P5ixdkA1+rF8FPhodGcq9mQOuUGP9g5HOXjaNoJYvwVRUdLeGh\n" - "cP/ReOTwQIzM1K5a83p8cX8AGGYmM7dQp7ec\n" - "-----END CERTIFICATE-----\n"; - -static const std::string kTestRsa2048ServerPrivKey = - "-----BEGIN PRIVATE KEY-----\n" - "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCvBNgpPU37ipc+\n" - "8KlnTH5J42dZbhQ6diB8QFGc4fxeo3iNnThRgI6XpaEpxjhPOhSGk3dRL6ck4e5w\n" - "cG6y2QAOlxWU6OwZegXTTkHam9ndvnCxDdIpxcalCMnHr0baIVBNWBRzPX4OONl9\n" - "Yzk1l4w2VnoqhVqPeaWgD4c5uqVqnyStfmCn09S7FmaWKiRhkBOaYgt6jgWGIBaa\n" - "FzMU2CTaGaN7jmBHTOrqXPP74deZzICMV/8picRGOQRz6WTz1o1y4AX81WlfX1H7\n" - "9CU+B0OLdlr8Qt3A/1LI1qdmuqeOeLlKdhDawDWvo0XUSXqXqYPQ9gyrMfS/M43O\n" - "Tm6nsa7dAgMBAAECggEAFCS2bPdUKIgjbzLgtHW+hT+J2hD20rcHdyAp+dNH/2vI\n" - "yLfDJHJA4chGMRondKA704oDw2bSJxxlG9t83326lB35yxPhye7cM8fqgWrK8PVl\n" - "tU22FhO1ZgeJvb9OeXWNxKZyDW9oOOJ8eazNXVMuEo+dFj7B6l3MXQyHJPL2mJDm\n" - "u9ofFLdypX+gJncVO0oW0FNJnEUn2MMwHDNlo7gc4WdQuidPkuZItKRGcB8TTGF3\n" - "Ka1/2taYdTQ4Aq//Z84LlFvE0zD3T4c8LwYYzOzD4gGGTXvft7vSHzIun1S8YLRS\n" - "dEKXdVjtaFhgH3uUe4j+1b/vMvSHeoGBNX/G88GD+wKBgQDWUYVlMVqc9HD2IeYi\n" - "EfBcNwAJFJkh51yAl5QbUBgFYgFJVkkS/EDxEGFPvEmI3/pAeQFHFY13BI466EPs\n" - "o8Z8UUwWDp+Z1MFHHKQKnFakbsZbZlbqjJ9VJsqpezbpWhMHTOmcG0dmE7rf0lyM\n" - "eQv9slBB8qp2NEUs5Of7f2C2bwKBgQDRDq4nUuMQF1hbjM05tGKSIwkobmGsLspv\n" - "TMhkM7fq4RpbFHmbNgsFqMhcqYZ8gY6/scv5KCuAZ4yHUkbqwf5h+QCwrJ4uJeUJ\n" - "ZgJfHus2mmcNSo8FwSkNoojIQtzcbJav7bs2K9VTuertk/i7IJLApU4FOZZ5pghN\n" - "EXu0CZF1cwKBgDWFGhjRIF29tU/h20R60llU6s9Zs3wB+NmsALJpZ/ZAKS4VPB5f\n" - "nCAXBRYSYRKrTCU5kpYbzb4BBzuysPOxWmnFK4j+keCqfrGxd02nCQP7HdHJVr8v\n" - "6sIq88UrHeVcNxBFprjzHvtgxfQK5k22FMZ/9wbhAKyQFQ5HA5+MiaxFAoGAIcZZ\n" - "ZIkDninnYIMS9OursShv5lRO+15j3i9tgKLKZ+wOMgDQ1L6acUOfezj4PU1BHr8+\n" - "0PYocQpJreMhCfRlgLaV4fVBaPs+UZJld7CrF5tCYudUy/01ALrtlk0XGZWBktK5\n" - "mDrksC4tQkzRtonAq9cJD9cJ9IVaefkFH0UcdvkCgYBpZj50VLeGhnHHBnkJRlV1\n" - "fV+/P6PAq6RtqjA6O9Qdaoj5V3w2d63aQcQXQLJjH2BBmtCIy47r04rFvZpbCxP7\n" - "NH/OnK9NHpk2ucRTe8TAnVbvF/TZzPJoIxAO/D3OWaW6df4R8en8u6GYzWFglAyT\n" - "sydGT8yfWD1FYUWgfrVRbg==\n" - "-----END PRIVATE KEY-----\n"; - -static const std::string kTestRsa2048ClientCert = - "-----BEGIN CERTIFICATE-----\n" - "MIIDFzCCAf+gAwIBAgIBATANBgkqhkiG9w0BAQsFADAtMQswCQYDVQQGEwJVUzEQ\n" - "MA4GA1UECgwHQW5kcm9pZDEMMAoGA1UEAwwDQWRiMB4XDTIwMDEyMTIyMjU1NloX\n" - "DTMwMDExODIyMjU1NlowLTELMAkGA1UEBhMCVVMxEDAOBgNVBAoMB0FuZHJvaWQx\n" - "DDAKBgNVBAMMA0FkYjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI3a\n" - "EXh1S5FTbet7JVONswffRPaekdIK53cb8SnAbSO9X5OLA4zGwdkrBvDTsd96SKrp\n" - "JxmoNOE1DhbZh05KPlWAPkGKacjGWaz+S7biDOL0I6aaLbTlU/il1Ub9olPSBVUx\n" - "0nhdtEFgIOzddnP6/1KmyIIeRxS5lTKeg4avqUkZNXkz/wL1dHBFL7FNFf0SCcbo\n" - "tsub/deFbjZ27LTDN+SIBgFttTNqC5NTvoBAoMdyCOAgNYwaHO+fKiK3edfJieaw\n" - "7HD8qqmQxcpCtRlA8CUPj7GfR+WHiCJmlevhnkFXCo56R1BS0F4wuD4KPdSWt8gc\n" - "27ejH/9/z2cKo/6SLJMCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B\n" - "Af8EBAMCAYYwHQYDVR0OBBYEFO/Mr5ygqqpyU/EHM9v7RDvcqaOkMA0GCSqGSIb3\n" - "DQEBCwUAA4IBAQAH33KMouzF2DYbjg90KDrDQr4rq3WfNb6P743knxdUFuvb+40U\n" - "QjC2OJZHkSexH7wfG/y6ic7vfCfF4clNs3QvU1lEjOZC57St8Fk7mdNdsWLwxEMD\n" - "uePFz0dvclSxNUHyCVMqNxddzQYzxiDWQRmXWrUBliMduQqEQelcxW2yDtg8bj+s\n" - "aMpR1ra9scaD4jzIZIIxLoOS9zBMuNRbgP217sZrniyGMhzoI1pZ/izN4oXpyH7O\n" - "THuaCzzRT3ph2f8EgmHSodz3ttgSf2DHzi/Ez1xUkk7NOlgNtmsxEdrM47+cC5ae\n" - "fIf2V+1o1JW8J7D11RmRbNPh3vfisueB4f88\n" - "-----END CERTIFICATE-----\n"; - -static const std::string kTestRsa2048ClientPrivKey = - "-----BEGIN PRIVATE KEY-----\n" - "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCN2hF4dUuRU23r\n" - "eyVTjbMH30T2npHSCud3G/EpwG0jvV+TiwOMxsHZKwbw07Hfekiq6ScZqDThNQ4W\n" - "2YdOSj5VgD5BimnIxlms/ku24gzi9COmmi205VP4pdVG/aJT0gVVMdJ4XbRBYCDs\n" - "3XZz+v9SpsiCHkcUuZUynoOGr6lJGTV5M/8C9XRwRS+xTRX9EgnG6LbLm/3XhW42\n" - "duy0wzfkiAYBbbUzaguTU76AQKDHcgjgIDWMGhzvnyoit3nXyYnmsOxw/KqpkMXK\n" - "QrUZQPAlD4+xn0flh4giZpXr4Z5BVwqOekdQUtBeMLg+Cj3UlrfIHNu3ox//f89n\n" - "CqP+kiyTAgMBAAECggEAAa64eP6ggCob1P3c73oayYPIbvRqiQdAFOrr7Vwu7zbr\n" - "z0rde+n6RU0mrpc+4NuzyPMtrOGQiatLbidJB5Cx3z8U00ovqbCl7PtcgorOhFKe\n" - "VEzihebCcYyQqbWQcKtpDMhOgBxRwFoXieJb6VGXfa96FAZalCWvXgOrTl7/BF2X\n" - "qMqIm9nJi+yS5tIO8VdOsOmrMWRH/b/ENUcef4WpLoxTXr0EEgyKWraeZ/hhXo1e\n" - "z29dZKqdr9wMsq11NPsRddwS94jnDkXTo+EQyWVTfB7gb6yyp07s8jysaDb21tVv\n" - "UXB9MRhDV1mOv0ncXfXZ4/+4A2UahmZaLDAVLaat4QKBgQDAVRredhGRGl2Nkic3\n" - "KvZCAfyxug788CgasBdEiouz19iCCwcgMIDwnq0s3/WM7h/laCamT2x38riYDnpq\n" - "rkYMfuVtU9CjEL9pTrdfwbIRhTwYNqADaPz2mXwQUhRXutE5TIdgxxC/a+ZTh0qN\n" - "S+vhTj/4hf0IZhMh5Nqj7IPExQKBgQC8zxEzhmSGjys0GuE6Wl6Doo2TpiR6vwvi\n" - "xPLU9lmIz5eca/Rd/eERioFQqeoIWDLzx52DXuz6rUoQhbJWz9hP3yqCwXD+pbNP\n" - "oDJqDDbCC4IMYEb0IK/PEPH+gIpnTjoFcW+ecKDFG7W5Lt05J8WsJsfOaJvMrOU+\n" - "dLXq3IgxdwKBgQC5RAFq0v6e8G+3hFaEHL0z3igkpt3zJf7rnj37hx2FMmDa+3Z0\n" - "umQp5B9af61PgL12xLmeMBmC/Wp1BlVDV/Yf6Uhk5Hyv5t0KuomHEtTNbbLyfAPs\n" - "5P/vJu/L5NS1oT4S3LX3MineyjgGs+bLbpub3z1dzutrYLADUSiPCK/xJQKBgBQt\n" - "nQ0Ao+Wtj1R2OvPdjJRM3wyUiPmFSWPm4HzaBx+T8AQLlYYmB9O0FbXlMtnJc0iS\n" - "YMcVcgYoVu4FG9YjSF7g3s4yljzgwJUV7c1fmMqMKE3iTDLy+1cJ3JLycdgwiArk\n" - "4KTyLHxkRbuQwpvFIF8RlfD9RQlOwQE3v+llwDhpAoGBAL6XG6Rp6mBoD2Ds5c9R\n" - "943yYgSUes3ji1SI9zFqeJtj8Ml/enuK1xu+8E/BxB0//+vgZsH6i3i8GFwygKey\n" - "CGJF8CbiHc3EJc3NQIIRXcni/CGacf0HwC6m+PGFDBIpA4H2iDpVvCSofxttQiq0\n" - "/Z7HXmXUvZHVyYi/QzX2Gahj\n" - "-----END PRIVATE KEY-----\n"; - -struct ServerDeleter { - void operator()(PairingServerCtx* p) { pairing_server_destroy(p); } -}; -using ServerPtr = std::unique_ptr; - -struct ResultWaiter { - std::mutex mutex_; - std::condition_variable cv_; - std::optional is_valid_; - PeerInfo peer_info_; - - static void ResultCallback(const PeerInfo* peer_info, void* opaque) { - auto* p = reinterpret_cast(opaque); - { - std::unique_lock lock(p->mutex_); - if (peer_info) { - memcpy(&(p->peer_info_), peer_info, sizeof(PeerInfo)); - } - p->is_valid_ = (peer_info != nullptr); - } - p->cv_.notify_one(); - } -}; - -class AdbPairingConnectionTest : public testing::Test { - protected: - virtual void SetUp() override {} - - virtual void TearDown() override {} - - void InitPairing(const std::vector& server_pswd, - const std::vector& client_pswd) { - server_ = CreateServer(server_pswd); - client_ = CreateClient(client_pswd); - } - - ServerPtr CreateServer(const std::vector& pswd) { - return CreateServer(pswd, &server_info_, kTestRsa2048ServerCert, kTestRsa2048ServerPrivKey, - 0); - } - - std::unique_ptr CreateClient(const std::vector pswd) { - std::vector cert; - std::vector key; - // Include the null-byte as well. - cert.assign(reinterpret_cast(kTestRsa2048ClientCert.data()), - reinterpret_cast(kTestRsa2048ClientCert.data()) + - kTestRsa2048ClientCert.size() + 1); - key.assign(reinterpret_cast(kTestRsa2048ClientPrivKey.data()), - reinterpret_cast(kTestRsa2048ClientPrivKey.data()) + - kTestRsa2048ClientPrivKey.size() + 1); - return PairingClient::Create(pswd, client_info_, cert, key); - } - - static ServerPtr CreateServer(const std::vector& pswd, const PeerInfo* peer_info, - const std::string_view cert, const std::string_view priv_key, - int port) { - return ServerPtr(pairing_server_new( - pswd.data(), pswd.size(), peer_info, reinterpret_cast(cert.data()), - cert.size(), reinterpret_cast(priv_key.data()), priv_key.size(), - port)); - } - - ServerPtr server_; - const PeerInfo server_info_ = { - .type = ADB_DEVICE_GUID, - .data = "my_server_info", - }; - std::unique_ptr client_; - const PeerInfo client_info_ = { - .type = ADB_RSA_PUB_KEY, - .data = "my_client_info", - }; - std::string ip_addr_ = "127.0.0.1:"; -}; - -TEST_F(AdbPairingConnectionTest, ServerCreation) { - // All parameters bad - ASSERT_DEATH({ auto server = CreateServer({}, nullptr, "", "", 0); }, ""); - // Bad password - ASSERT_DEATH( - { - auto server = CreateServer({}, &server_info_, kTestRsa2048ServerCert, - kTestRsa2048ServerPrivKey, 0); - }, - ""); - // Bad peer_info - ASSERT_DEATH( - { - auto server = CreateServer({0x01}, nullptr, kTestRsa2048ServerCert, - kTestRsa2048ServerPrivKey, 0); - }, - ""); - // Bad certificate - ASSERT_DEATH( - { - auto server = CreateServer({0x01}, &server_info_, "", kTestRsa2048ServerPrivKey, 0); - }, - ""); - // Bad private key - ASSERT_DEATH( - { auto server = CreateServer({0x01}, &server_info_, kTestRsa2048ServerCert, "", 0); }, - ""); - // Valid params - auto server = CreateServer({0x01}, &server_info_, kTestRsa2048ServerCert, - kTestRsa2048ServerPrivKey, 0); - EXPECT_NE(nullptr, server); -} - -TEST_F(AdbPairingConnectionTest, ClientCreation) { - std::vector pswd{0x01, 0x03, 0x05, 0x07}; - // Bad password - ASSERT_DEATH( - { - pairing_connection_client_new( - nullptr, pswd.size(), &client_info_, - reinterpret_cast(kTestRsa2048ClientCert.data()), - kTestRsa2048ClientCert.size(), - reinterpret_cast(kTestRsa2048ClientPrivKey.data()), - kTestRsa2048ClientPrivKey.size()); - }, - ""); - ASSERT_DEATH( - { - pairing_connection_client_new( - pswd.data(), 0, &client_info_, - reinterpret_cast(kTestRsa2048ClientCert.data()), - kTestRsa2048ClientCert.size(), - reinterpret_cast(kTestRsa2048ClientPrivKey.data()), - kTestRsa2048ClientPrivKey.size()); - }, - ""); - - // Bad peer_info - ASSERT_DEATH( - { - pairing_connection_client_new( - pswd.data(), pswd.size(), nullptr, - reinterpret_cast(kTestRsa2048ClientCert.data()), - kTestRsa2048ClientCert.size(), - reinterpret_cast(kTestRsa2048ClientPrivKey.data()), - kTestRsa2048ClientPrivKey.size()); - }, - ""); - - // Bad certificate - ASSERT_DEATH( - { - pairing_connection_client_new( - pswd.data(), pswd.size(), &client_info_, nullptr, - kTestRsa2048ClientCert.size(), - reinterpret_cast(kTestRsa2048ClientPrivKey.data()), - kTestRsa2048ClientPrivKey.size()); - }, - ""); - ASSERT_DEATH( - { - pairing_connection_client_new( - pswd.data(), pswd.size(), &client_info_, - reinterpret_cast(kTestRsa2048ClientCert.data()), 0, - reinterpret_cast(kTestRsa2048ClientPrivKey.data()), - kTestRsa2048ClientPrivKey.size()); - }, - ""); - - // Bad private key - ASSERT_DEATH( - { - pairing_connection_client_new( - pswd.data(), pswd.size(), &client_info_, - reinterpret_cast(kTestRsa2048ClientCert.data()), - kTestRsa2048ClientCert.size(), nullptr, kTestRsa2048ClientPrivKey.size()); - }, - ""); - ASSERT_DEATH( - { - pairing_connection_client_new( - pswd.data(), pswd.size(), &client_info_, - reinterpret_cast(kTestRsa2048ClientCert.data()), - kTestRsa2048ClientCert.size(), - reinterpret_cast(kTestRsa2048ClientPrivKey.data()), 0); - }, - ""); - - // Valid params - auto client = pairing_connection_client_new( - pswd.data(), pswd.size(), &client_info_, - reinterpret_cast(kTestRsa2048ClientCert.data()), - kTestRsa2048ClientCert.size(), - reinterpret_cast(kTestRsa2048ClientPrivKey.data()), - kTestRsa2048ClientPrivKey.size()); - EXPECT_NE(nullptr, client); -} - -TEST_F(AdbPairingConnectionTest, SmokeValidPairing) { - std::vector pswd{0x01, 0x03, 0x05, 0x07}; - InitPairing(pswd, pswd); - - // Start the server - ResultWaiter server_waiter; - std::unique_lock server_lock(server_waiter.mutex_); - auto port = pairing_server_start(server_.get(), server_waiter.ResultCallback, &server_waiter); - ASSERT_GT(port, 0); - ip_addr_ += std::to_string(port); - - // Start the client - ResultWaiter client_waiter; - std::unique_lock client_lock(client_waiter.mutex_); - ASSERT_TRUE(client_->Start(ip_addr_, client_waiter.ResultCallback, &client_waiter)); - client_waiter.cv_.wait(client_lock, [&]() { return client_waiter.is_valid_.has_value(); }); - ASSERT_TRUE(*(client_waiter.is_valid_)); - ASSERT_EQ(strlen(reinterpret_cast(client_waiter.peer_info_.data)), - strlen(reinterpret_cast(server_info_.data))); - EXPECT_EQ(memcmp(client_waiter.peer_info_.data, server_info_.data, sizeof(server_info_.data)), - 0); - - // Kill server if the pairing failed, since server only shuts down when - // it gets a valid pairing. - if (!client_waiter.is_valid_) { - server_lock.unlock(); - server_.reset(); - } else { - server_waiter.cv_.wait(server_lock, [&]() { return server_waiter.is_valid_.has_value(); }); - ASSERT_TRUE(*(server_waiter.is_valid_)); - ASSERT_EQ(strlen(reinterpret_cast(server_waiter.peer_info_.data)), - strlen(reinterpret_cast(client_info_.data))); - EXPECT_EQ( - memcmp(server_waiter.peer_info_.data, client_info_.data, sizeof(client_info_.data)), - 0); - } -} - -TEST_F(AdbPairingConnectionTest, CancelPairing) { - std::vector pswd{0x01, 0x03, 0x05, 0x07}; - std::vector pswd2{0x01, 0x03, 0x05, 0x06}; - InitPairing(pswd, pswd2); - - // Start the server - ResultWaiter server_waiter; - std::unique_lock server_lock(server_waiter.mutex_); - auto port = pairing_server_start(server_.get(), server_waiter.ResultCallback, &server_waiter); - ASSERT_GT(port, 0); - ip_addr_ += std::to_string(port); - - // Start the client. Client should fail to pair - ResultWaiter client_waiter; - std::unique_lock client_lock(client_waiter.mutex_); - ASSERT_TRUE(client_->Start(ip_addr_, client_waiter.ResultCallback, &client_waiter)); - client_waiter.cv_.wait(client_lock, [&]() { return client_waiter.is_valid_.has_value(); }); - ASSERT_FALSE(*(client_waiter.is_valid_)); - - // Kill the server. We should still receive the callback with no valid - // pairing. - server_lock.unlock(); - server_.reset(); - server_lock.lock(); - ASSERT_TRUE(server_waiter.is_valid_.has_value()); - EXPECT_FALSE(*(server_waiter.is_valid_)); -} - -TEST_F(AdbPairingConnectionTest, MultipleClientsAllFail) { - std::vector pswd{0x01, 0x03, 0x05, 0x07}; - std::vector pswd2{0x01, 0x03, 0x05, 0x06}; - - // Start the server - auto server = CreateServer(pswd); - ResultWaiter server_waiter; - std::unique_lock server_lock(server_waiter.mutex_); - auto port = pairing_server_start(server.get(), server_waiter.ResultCallback, &server_waiter); - ASSERT_GT(port, 0); - ip_addr_ += std::to_string(port); - - // Start multiple clients, all with bad passwords - int test_num_clients = 5; - int num_clients_done = 0; - std::mutex global_clients_mutex; - std::unique_lock global_clients_lock(global_clients_mutex); - std::condition_variable global_cv_; - for (int i = 0; i < test_num_clients; ++i) { - std::thread([&]() { - auto client = CreateClient(pswd2); - ResultWaiter client_waiter; - std::unique_lock client_lock(client_waiter.mutex_); - ASSERT_TRUE(client->Start(ip_addr_, client_waiter.ResultCallback, &client_waiter)); - client_waiter.cv_.wait(client_lock, - [&]() { return client_waiter.is_valid_.has_value(); }); - ASSERT_FALSE(*(client_waiter.is_valid_)); - { - std::lock_guard global_lock(global_clients_mutex); - ++num_clients_done; - } - global_cv_.notify_one(); - }).detach(); - } - - global_cv_.wait(global_clients_lock, [&]() { return num_clients_done == test_num_clients; }); - server_lock.unlock(); - server.reset(); - server_lock.lock(); - ASSERT_TRUE(server_waiter.is_valid_.has_value()); - EXPECT_FALSE(*(server_waiter.is_valid_)); -} - -TEST_F(AdbPairingConnectionTest, MultipleClientsOnePass) { - // Send multiple clients with bad passwords, but send the last one with the - // correct password. - std::vector pswd{0x01, 0x03, 0x05, 0x07}; - std::vector pswd2{0x01, 0x03, 0x05, 0x06}; - - // Start the server - auto server = CreateServer(pswd); - ResultWaiter server_waiter; - std::unique_lock server_lock(server_waiter.mutex_); - auto port = pairing_server_start(server.get(), server_waiter.ResultCallback, &server_waiter); - ASSERT_GT(port, 0); - ip_addr_ += std::to_string(port); - - // Start multiple clients, all with bad passwords - int test_num_clients = 5; - int num_clients_done = 0; - std::mutex global_clients_mutex; - std::unique_lock global_clients_lock(global_clients_mutex); - std::condition_variable global_cv_; - for (int i = 0; i < test_num_clients; ++i) { - std::thread([&, i]() { - bool good_client = (i == (test_num_clients - 1)); - auto client = CreateClient((good_client ? pswd : pswd2)); - ResultWaiter client_waiter; - std::unique_lock client_lock(client_waiter.mutex_); - ASSERT_TRUE(client->Start(ip_addr_, client_waiter.ResultCallback, &client_waiter)); - client_waiter.cv_.wait(client_lock, - [&]() { return client_waiter.is_valid_.has_value(); }); - if (good_client) { - ASSERT_TRUE(*(client_waiter.is_valid_)); - ASSERT_EQ(strlen(reinterpret_cast(client_waiter.peer_info_.data)), - strlen(reinterpret_cast(server_info_.data))); - EXPECT_EQ(memcmp(client_waiter.peer_info_.data, server_info_.data, - sizeof(server_info_.data)), - 0); - } else { - ASSERT_FALSE(*(client_waiter.is_valid_)); - } - { - std::lock_guard global_lock(global_clients_mutex); - ++num_clients_done; - } - global_cv_.notify_one(); - }).detach(); - } - - global_cv_.wait(global_clients_lock, [&]() { return num_clients_done == test_num_clients; }); - server_waiter.cv_.wait(server_lock, [&]() { return server_waiter.is_valid_.has_value(); }); - ASSERT_TRUE(*(server_waiter.is_valid_)); - ASSERT_EQ(strlen(reinterpret_cast(server_waiter.peer_info_.data)), - strlen(reinterpret_cast(client_info_.data))); - EXPECT_EQ(memcmp(server_waiter.peer_info_.data, client_info_.data, sizeof(client_info_.data)), - 0); -} - -} // namespace pairing -} // namespace adb diff --git a/adb/proto/Android.bp b/adb/proto/Android.bp deleted file mode 100644 index f7cba95222e626ec3bac4a6f984c3fa4d197fe37..0000000000000000000000000000000000000000 --- a/adb/proto/Android.bp +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (C) 2020 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. - -cc_defaults { - name: "libadb_protos_defaults", - cflags: [ - "-Wall", - "-Wextra", - "-Wthread-safety", - "-Werror", - ], - - compile_multilib: "both", - - proto: { - export_proto_headers: true, - type: "lite", - }, - srcs: [ - "adb_known_hosts.proto", - "key_type.proto", - "pairing.proto", - ], - target: { - windows: { - compile_multilib: "first", - enabled: true, - }, - }, - - visibility: [ - "//system/core/adb:__subpackages__", - - // This needs to be visible to minadbd, even though it's removed via exclude_shared_libs. - "//bootable/recovery/minadbd:__subpackages__", - ], - - stl: "libc++_static", - - host_supported: true, - recovery_available: true, -} - -cc_library { - name: "libadb_protos", - defaults: ["libadb_protos_defaults"], - - apex_available: [ - "com.android.adbd", - "test_com.android.adbd", - ], -} - -// For running atest (b/147158681) -cc_library_static { - name: "libadb_protos_static", - defaults: ["libadb_protos_defaults"], - - apex_available: [ - "//apex_available:platform", - ], -} diff --git a/adb/proto/adb_known_hosts.proto b/adb/proto/adb_known_hosts.proto deleted file mode 100644 index 85d1489ff3aa6cc0fed2a22d8922150a02f6597d..0000000000000000000000000000000000000000 --- a/adb/proto/adb_known_hosts.proto +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2020 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. - */ - -syntax = "proto3"; - -option java_package = "com.android.server.adb.protos"; -option java_outer_classname = "AdbKnownHostsProto"; - -package adb.proto; - -// Each known host -message HostInfo { - string guid = 1; -} - -// Protobuf definition for the adb_known_hosts. -message AdbKnownHosts { - repeated HostInfo host_infos = 1; -} diff --git a/adb/proto/jarjar-rules.txt b/adb/proto/jarjar-rules.txt deleted file mode 100644 index 4e40637063528d678d9879c56f02bb9f345fa8a4..0000000000000000000000000000000000000000 --- a/adb/proto/jarjar-rules.txt +++ /dev/null @@ -1 +0,0 @@ -rule com.google.protobuf.** com.android.framework.protobuf.@1 diff --git a/adb/proto/key_type.proto b/adb/proto/key_type.proto deleted file mode 100644 index ed451c51142a9311bb9301af8350aef7994fa1fe..0000000000000000000000000000000000000000 --- a/adb/proto/key_type.proto +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2020 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. - */ - -syntax = "proto3"; - -option java_package = "com.android.server.adb.protos"; -option java_outer_classname = "KeyTypeProto"; - -package adb.proto; - -enum KeyType { - RSA_2048 = 0; -} diff --git a/adb/proto/pairing.proto b/adb/proto/pairing.proto deleted file mode 100644 index b0be20e530bddf5dc3a1f0ea5f305373a7d947e1..0000000000000000000000000000000000000000 --- a/adb/proto/pairing.proto +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2020 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. - */ - -syntax = "proto3"; - -option java_package = "com.android.server.adb.protos"; -option java_outer_classname = "PairingProto"; - -package adb.proto; - -// The type of packets used in the pairing protocol -message PairingPacket { - enum Type { - SPAKE2_MSG = 0; - PEER_INFO = 1; - } -} diff --git a/adb/protocol.txt b/adb/protocol.txt deleted file mode 100644 index 75700a4d5f3d6f0f9168ab3f56e93062b1bc7705..0000000000000000000000000000000000000000 --- a/adb/protocol.txt +++ /dev/null @@ -1,298 +0,0 @@ - ---- 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 (A_CNXN, ...) */ - 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") ---------------- - -Command constant: A_CNXN - -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=256*1024. Older versions of adb -hard-coded maxdata=4096, so CONNECT and AUTH packets sent to a device must not -be larger than that because they're sent before the CONNECT from the device -that tells the adb server what maxdata the device can support. - -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. - ---- STLS(type, version, "") -------------------------------------------- - -Command constant: A_STLS - -The TLS message informs the recipient that the connection will be encrypted -and will need to perform a TLS handshake. version is the current version of -the protocol. - - ---- AUTH(type, 0, "data") ---------------------------------------------- - -Command constant: A_AUTH - -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") ----------------------------------- - -Command constant: A_OPEN - -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, "") ------------------------------------- - -Command constant: A_OKAY - -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(local-id, remote-id, "data") --------------------------------- - -Command constant: A_WRTE - -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, "") ------------------------------------- - -Command constant: A_CLSE - -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, "") ----------------------------------------- - -Command constant: A_SYNC - -*** obsolete, no longer used *** - -The SYNC message was used by the io pump to make sure that stale -outbound messages are discarded when the connection to the remote side -is broken. It was 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 -#define A_STLS 0x534C5453 - - - ---- 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" - diff --git a/adb/security_log_tags.h b/adb/security_log_tags.h deleted file mode 100644 index 1d02744948e78363023644f7ece8fb44e8eddb83..0000000000000000000000000000000000000000 --- a/adb/security_log_tags.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2016 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 __SECURITY_LOG_TAGS_H -#define __SECURITY_LOG_TAGS_H - -/* TODO: Automatically generate this file from the logtags file when build - * infrastructure is in place. - * Defined in frameworks/base/core/java/android/auditing/SecurityLog.logtags - */ -#define SEC_TAG_ADB_SHELL_INTERACTIVE 210001 -#define SEC_TAG_ADB_SHELL_CMD 210002 -#define SEC_TAG_ADB_RECV_FILE 210003 -#define SEC_TAG_ADB_SEND_FILE 210004 - -#endif diff --git a/adb/services.cpp b/adb/services.cpp deleted file mode 100644 index 853d658976e149c10aa65b839186084bfb92ec00..0000000000000000000000000000000000000000 --- a/adb/services.cpp +++ /dev/null @@ -1,272 +0,0 @@ -/* - * 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 SERVICES - -#include "sysdeps.h" - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include "adb.h" -#include "adb_io.h" -#include "adb_unique_fd.h" -#include "adb_utils.h" -#include "adb_wifi.h" -#include "services.h" -#include "socket_spec.h" -#include "sysdeps.h" -#include "transport.h" - -namespace { - -void service_bootstrap_func(std::string service_name, std::function func, - unique_fd fd) { - adb_thread_setname(android::base::StringPrintf("%s svc %d", service_name.c_str(), fd.get())); - func(std::move(fd)); -} - -} // namespace - -unique_fd create_service_thread(const char* service_name, std::function func) { - int s[2]; - if (adb_socketpair(s)) { - printf("cannot create service socket pair\n"); - return unique_fd(); - } - D("socketpair: (%d,%d)", s[0], s[1]); - -#if !ADB_HOST - if (strcmp(service_name, "sync") == 0) { - // Set file sync service socket to maximum size - int max_buf = LINUX_MAX_SOCKET_SIZE; - adb_setsockopt(s[0], SOL_SOCKET, SO_SNDBUF, &max_buf, sizeof(max_buf)); - adb_setsockopt(s[1], SOL_SOCKET, SO_SNDBUF, &max_buf, sizeof(max_buf)); - } -#endif // !ADB_HOST - - std::thread(service_bootstrap_func, service_name, func, unique_fd(s[1])).detach(); - - D("service thread started, %d:%d", s[0], s[1]); - return unique_fd(s[0]); -} - -unique_fd service_to_fd(std::string_view name, atransport* transport) { - unique_fd ret; - - if (is_socket_spec(name)) { - std::string error; - if (!socket_spec_connect(&ret, name, nullptr, nullptr, &error)) { - LOG(ERROR) << "failed to connect to socket '" << name << "': " << error; - } - } else { -#if !ADB_HOST - ret = daemon_service_to_fd(name, transport); -#endif - } - - if (ret >= 0) { - close_on_exec(ret.get()); - } - return ret; -} - -#if ADB_HOST -struct state_info { - TransportType transport_type; - std::string serial; - TransportId transport_id; - ConnectionState state; -}; - -static void wait_for_state(unique_fd fd, state_info* sinfo) { - D("wait_for_state %d", sinfo->state); - - while (true) { - bool is_ambiguous = false; - std::string error = "unknown error"; - const char* serial = sinfo->serial.length() ? sinfo->serial.c_str() : nullptr; - atransport* t = acquire_one_transport(sinfo->transport_type, serial, sinfo->transport_id, - &is_ambiguous, &error); - if (sinfo->state == kCsOffline) { - // wait-for-disconnect uses kCsOffline, we don't actually want to wait for 'offline'. - if (t == nullptr) { - SendOkay(fd); - break; - } - } else if (t != nullptr && - (sinfo->state == kCsAny || sinfo->state == t->GetConnectionState())) { - SendOkay(fd); - break; - } - - if (!is_ambiguous) { - adb_pollfd pfd = {.fd = fd.get(), .events = POLLIN}; - int rc = adb_poll(&pfd, 1, 100); - if (rc < 0) { - SendFail(fd, error); - break; - } else if (rc > 0 && (pfd.revents & POLLHUP) != 0) { - // The other end of the socket is closed, probably because the other side was - // terminated, bail out. - break; - } - - // Try again... - } else { - SendFail(fd, error); - break; - } - } - - D("wait_for_state is done"); -} - -void connect_emulator(const std::string& port_spec, std::string* response) { - std::vector pieces = android::base::Split(port_spec, ","); - if (pieces.size() != 2) { - *response = android::base::StringPrintf("unable to parse '%s' as ,", - port_spec.c_str()); - return; - } - - int console_port = strtol(pieces[0].c_str(), nullptr, 0); - int adb_port = strtol(pieces[1].c_str(), nullptr, 0); - if (console_port <= 0 || adb_port <= 0) { - *response = android::base::StringPrintf("Invalid port numbers: %s", port_spec.c_str()); - 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 != nullptr) { - *response = android::base::StringPrintf("Emulator already registered on port %d", adb_port); - return; - } - - // Preconditions met, try to connect to the emulator. - std::string error; - if (!local_connect_arbitrary_ports(console_port, adb_port, &error)) { - *response = android::base::StringPrintf("Connected to emulator on ports %d,%d", - console_port, adb_port); - } else { - *response = android::base::StringPrintf("Could not connect to emulator on ports %d,%d: %s", - console_port, adb_port, error.c_str()); - } -} - -static void connect_service(unique_fd fd, std::string host) { - std::string response; - if (!strncmp(host.c_str(), "emu:", 4)) { - connect_emulator(host.c_str() + 4, &response); - } else { - connect_device(host, &response); - } - - // Send response for emulator and device - SendProtocolString(fd.get(), response); -} - -static void pair_service(unique_fd fd, std::string host, std::string password) { - std::string response; - adb_wifi_pair_device(host, password, response); - SendProtocolString(fd.get(), response); -} -#endif - -#if ADB_HOST -asocket* host_service_to_socket(std::string_view name, std::string_view serial, - TransportId transport_id) { - if (name == "track-devices") { - return create_device_tracker(false); - } else if (name == "track-devices-l") { - return create_device_tracker(true); - } else if (android::base::ConsumePrefix(&name, "wait-for-")) { - std::shared_ptr sinfo = std::make_shared(); - if (sinfo == nullptr) { - fprintf(stderr, "couldn't allocate state_info: %s", strerror(errno)); - return nullptr; - } - - sinfo->serial = serial; - sinfo->transport_id = transport_id; - - if (android::base::ConsumePrefix(&name, "local")) { - sinfo->transport_type = kTransportLocal; - } else if (android::base::ConsumePrefix(&name, "usb")) { - sinfo->transport_type = kTransportUsb; - } else if (android::base::ConsumePrefix(&name, "any")) { - sinfo->transport_type = kTransportAny; - } else { - return nullptr; - } - - if (name == "-device") { - sinfo->state = kCsDevice; - } else if (name == "-recovery") { - sinfo->state = kCsRecovery; - } else if (name == "-rescue") { - sinfo->state = kCsRescue; - } else if (name == "-sideload") { - sinfo->state = kCsSideload; - } else if (name == "-bootloader") { - sinfo->state = kCsBootloader; - } else if (name == "-any") { - sinfo->state = kCsAny; - } else if (name == "-disconnect") { - sinfo->state = kCsOffline; - } else { - return nullptr; - } - - unique_fd fd = create_service_thread( - "wait", [sinfo](unique_fd fd) { wait_for_state(std::move(fd), sinfo.get()); }); - return create_local_socket(std::move(fd)); - } else if (android::base::ConsumePrefix(&name, "connect:")) { - std::string host(name); - unique_fd fd = create_service_thread( - "connect", std::bind(connect_service, std::placeholders::_1, host)); - return create_local_socket(std::move(fd)); - } else if (android::base::ConsumePrefix(&name, "pair:")) { - const char* divider = strchr(name.data(), ':'); - if (!divider) { - return nullptr; - } - std::string password(name.data(), divider); - std::string host(divider + 1); - unique_fd fd = create_service_thread( - "pair", std::bind(pair_service, std::placeholders::_1, host, password)); - return create_local_socket(std::move(fd)); - } - return nullptr; -} -#endif /* ADB_HOST */ diff --git a/adb/services.h b/adb/services.h deleted file mode 100644 index 6fc89d71f45c2b403a6251c175d103cebe559a8d..0000000000000000000000000000000000000000 --- a/adb/services.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2015 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 SERVICES_H_ -#define SERVICES_H_ - -#include "adb_unique_fd.h" - -constexpr char kShellServiceArgRaw[] = "raw"; -constexpr char kShellServiceArgPty[] = "pty"; -constexpr char kShellServiceArgShellProtocol[] = "v2"; - -// Special flags sent by minadbd. They indicate the end of sideload transfer and the result of -// installation or wipe. -constexpr char kMinadbdServicesExitSuccess[] = "DONEDONE"; -constexpr char kMinadbdServicesExitFailure[] = "FAILFAIL"; - -unique_fd create_service_thread(const char* service_name, std::function func); -#endif // SERVICES_H_ diff --git a/adb/shell_protocol.h b/adb/shell_protocol.h deleted file mode 100644 index 4aab8131c1b7c9a9542f45eb1d1c2680eca2ed28..0000000000000000000000000000000000000000 --- a/adb/shell_protocol.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -#pragma once - -#include - -#include - -#include "adb.h" -#include "adb_unique_fd.h" - -// Class to send and receive shell protocol packets. -// -// To keep things simple and predictable, reads and writes block until an entire -// packet is complete. -// -// Example: read raw data from |fd| and send it in a packet. -// ShellProtocol* p = new ShellProtocol(protocol_fd); -// int len = adb_read(stdout_fd, p->data(), p->data_capacity()); -// packet->WritePacket(ShellProtocol::kIdStdout, len); -// -// Example: read a packet and print it to |stdout|. -// ShellProtocol* p = new ShellProtocol(protocol_fd); -// if (p->ReadPacket() && p->id() == kIdStdout) { -// fwrite(p->data(), 1, p->data_length(), stdout); -// } -class ShellProtocol { - public: - // This is an unscoped enum to make it easier to compare against raw bytes. - enum Id : uint8_t { - kIdStdin = 0, - kIdStdout = 1, - kIdStderr = 2, - kIdExit = 3, - - // Close subprocess stdin if possible. - kIdCloseStdin = 4, - - // Window size change (an ASCII version of struct winsize). - kIdWindowSizeChange = 5, - - // Indicates an invalid or unknown packet. - kIdInvalid = 255, - }; - - // ShellPackets will probably be too large to allocate on the stack so they - // should be dynamically allocated on the heap instead. - // - // |fd| is an open file descriptor to be used to send or receive packets. - explicit ShellProtocol(borrowed_fd fd); - virtual ~ShellProtocol(); - - // Returns a pointer to the data buffer. - const char* data() const { return buffer_ + kHeaderSize; } - char* data() { return buffer_ + kHeaderSize; } - - // Returns the total capacity of the data buffer. - size_t data_capacity() const { return buffer_end_ - data(); } - - // Reads a packet from the FD. - // - // If a packet is too big to fit in the buffer then Read() will split the - // packet across multiple calls. For example, reading a 50-byte packet into - // a 20-byte buffer would read 20 bytes, 20 bytes, then 10 bytes. - // - // Returns false if the FD closed or errored. - bool Read(); - - // Returns the ID of the packet in the buffer. - int id() const { return buffer_[0]; } - - // Returns the number of bytes that have been read into the data buffer. - size_t data_length() const { return data_length_; } - - // Writes the packet currently in the buffer to the FD. - // - // Returns false if the FD closed or errored. - bool Write(Id id, size_t length); - - private: - // Packets support 4-byte lengths. - typedef uint32_t length_t; - - enum { - // It's OK if MAX_PAYLOAD doesn't match on the sending and receiving - // end, reading will split larger packets into multiple smaller ones. - kBufferSize = MAX_PAYLOAD, - - // Header is 1 byte ID + 4 bytes length. - kHeaderSize = sizeof(Id) + sizeof(length_t) - }; - - borrowed_fd fd_; - char buffer_[kBufferSize]; - size_t data_length_ = 0, bytes_left_ = 0; - - // We need to be able to modify this value for testing purposes, but it - // will stay constant during actual program use. - char* buffer_end_ = buffer_ + sizeof(buffer_); - - friend class ShellProtocolTest; - - DISALLOW_COPY_AND_ASSIGN(ShellProtocol); -}; diff --git a/adb/shell_service_protocol.cpp b/adb/shell_service_protocol.cpp deleted file mode 100644 index 95afaffe71a1341b7663233afc0ffef85699d7b3..0000000000000000000000000000000000000000 --- a/adb/shell_service_protocol.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2015 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 "shell_protocol.h" - -#include - -#include - -#include "adb_io.h" - -ShellProtocol::ShellProtocol(borrowed_fd fd) : fd_(fd) { - buffer_[0] = kIdInvalid; -} - -ShellProtocol::~ShellProtocol() { -} - -bool ShellProtocol::Read() { - // Only read a new header if we've finished the last packet. - if (!bytes_left_) { - if (!ReadFdExactly(fd_, buffer_, kHeaderSize)) { - return false; - } - - length_t packet_length; - memcpy(&packet_length, &buffer_[1], sizeof(packet_length)); - bytes_left_ = packet_length; - data_length_ = 0; - } - - size_t read_length = std::min(bytes_left_, data_capacity()); - if (read_length && !ReadFdExactly(fd_, data(), read_length)) { - return false; - } - - bytes_left_ -= read_length; - data_length_ = read_length; - - return true; -} - -bool ShellProtocol::Write(Id id, size_t length) { - buffer_[0] = id; - length_t typed_length = length; - memcpy(&buffer_[1], &typed_length, sizeof(typed_length)); - - return WriteFdExactly(fd_, buffer_, kHeaderSize + length); -} diff --git a/adb/shell_service_protocol_test.cpp b/adb/shell_service_protocol_test.cpp deleted file mode 100644 index a10b5c055e0ca56af819665c221542454204aa8e..0000000000000000000000000000000000000000 --- a/adb/shell_service_protocol_test.cpp +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (C) 2015 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 "shell_protocol.h" - -#include - -#include -#include - -#include "sysdeps.h" - -class ShellProtocolTest : public ::testing::Test { - public: - static void SetUpTestCase() { -#if !defined(_WIN32) - // This is normally done in main.cpp. - saved_sigpipe_handler_ = signal(SIGPIPE, SIG_IGN); -#endif - } - - static void TearDownTestCase() { -#if !defined(_WIN32) - signal(SIGPIPE, saved_sigpipe_handler_); -#endif - } - - // Initializes the socketpair and ShellProtocols needed for testing. - void SetUp() { - int fds[2]; - ASSERT_EQ(0, adb_socketpair(fds)); - read_fd_ = fds[0]; - write_fd_ = fds[1]; - - write_protocol_ = new ShellProtocol(write_fd_); - ASSERT_TRUE(write_protocol_ != nullptr); - - read_protocol_ = new ShellProtocol(read_fd_); - ASSERT_TRUE(read_protocol_ != nullptr); - } - - // Cleans up FDs and ShellProtocols. If an FD is closed manually during a - // test, set it to -1 to prevent TearDown() trying to close it again. - void TearDown() { - for (int fd : {read_fd_, write_fd_}) { - if (fd >= 0) { - adb_close(fd); - } - } - for (ShellProtocol* protocol : {read_protocol_, write_protocol_}) { - if (protocol) { - delete protocol; - } - } - } - - // Fakes the buffer size so we can test filling buffers. - void SetReadDataCapacity(size_t size) { - read_protocol_->buffer_end_ = read_protocol_->data() + size; - } - -#if !defined(_WIN32) - static sig_t saved_sigpipe_handler_; -#endif - - int read_fd_ = -1, write_fd_ = -1; - ShellProtocol *read_protocol_ = nullptr, *write_protocol_ = nullptr; -}; - -#if !defined(_WIN32) -sig_t ShellProtocolTest::saved_sigpipe_handler_ = nullptr; -#endif - -namespace { - -// Returns true if the packet contains the given values. `data` can't be null. -bool PacketEquals(const ShellProtocol* protocol, ShellProtocol::Id id, - const void* data, size_t data_length) { - // Note that passing memcmp null is bad, even if data_length is 0. - return (protocol->id() == id && - protocol->data_length() == data_length && - !memcmp(data, protocol->data(), data_length)); -} - -} // namespace - -// Tests data that can fit in a single packet. -TEST_F(ShellProtocolTest, FullPacket) { - ShellProtocol::Id id = ShellProtocol::kIdStdout; - char data[] = "abc 123 \0\r\n"; - - memcpy(write_protocol_->data(), data, sizeof(data)); - ASSERT_TRUE(write_protocol_->Write(id, sizeof(data))); - - ASSERT_TRUE(read_protocol_->Read()); - ASSERT_TRUE(PacketEquals(read_protocol_, id, data, sizeof(data))); -} - -// Tests data that has to be read multiple times due to smaller read buffer. -TEST_F(ShellProtocolTest, ReadBufferOverflow) { - ShellProtocol::Id id = ShellProtocol::kIdStdin; - - memcpy(write_protocol_->data(), "1234567890", 10); - ASSERT_TRUE(write_protocol_->Write(id, 10)); - - SetReadDataCapacity(4); - ASSERT_TRUE(read_protocol_->Read()); - ASSERT_TRUE(PacketEquals(read_protocol_, id, "1234", 4)); - ASSERT_TRUE(read_protocol_->Read()); - ASSERT_TRUE(PacketEquals(read_protocol_, id, "5678", 4)); - ASSERT_TRUE(read_protocol_->Read()); - ASSERT_TRUE(PacketEquals(read_protocol_, id, "90", 2)); -} - -// Tests a zero length packet. -TEST_F(ShellProtocolTest, ZeroLengthPacket) { - ShellProtocol::Id id = ShellProtocol::kIdStderr; - - ASSERT_TRUE(write_protocol_->Write(id, 0)); - ASSERT_TRUE(read_protocol_->Read()); - char buf[1]; - ASSERT_TRUE(PacketEquals(read_protocol_, id, buf, 0)); -} - -// Tests exit code packets. -TEST_F(ShellProtocolTest, ExitCodePacket) { - write_protocol_->data()[0] = 20; - ASSERT_TRUE(write_protocol_->Write(ShellProtocol::kIdExit, 1)); - - ASSERT_TRUE(read_protocol_->Read()); - ASSERT_EQ(ShellProtocol::kIdExit, read_protocol_->id()); - ASSERT_EQ(20, read_protocol_->data()[0]); -} - -// Tests writing to a closed pipe. -TEST_F(ShellProtocolTest, WriteToClosedPipeFail) { - adb_close(read_fd_); - read_fd_ = -1; - - ASSERT_FALSE(write_protocol_->Write(ShellProtocol::kIdStdout, 0)); -} - -// Tests writing to a closed FD. -TEST_F(ShellProtocolTest, WriteToClosedFdFail) { - adb_close(write_fd_); - write_fd_ = -1; - - ASSERT_FALSE(write_protocol_->Write(ShellProtocol::kIdStdout, 0)); -} - -// Tests reading from a closed pipe. -TEST_F(ShellProtocolTest, ReadFromClosedPipeFail) { - adb_close(write_fd_); - write_fd_ = -1; - - ASSERT_FALSE(read_protocol_->Read()); -} - -// Tests reading from a closed FD. -TEST_F(ShellProtocolTest, ReadFromClosedFdFail) { - adb_close(read_fd_); - read_fd_ = -1; - - ASSERT_FALSE(read_protocol_->Read()); -} - -// Tests reading from a closed pipe that has a packet waiting. This checks that -// even if the pipe closes before we can fully read its contents we will still -// be able to access the last packets. -TEST_F(ShellProtocolTest, ReadPacketFromClosedPipe) { - ShellProtocol::Id id = ShellProtocol::kIdStdout; - char data[] = "foo bar"; - - memcpy(write_protocol_->data(), data, sizeof(data)); - ASSERT_TRUE(write_protocol_->Write(id, sizeof(data))); - adb_close(write_fd_); - write_fd_ = -1; - - // First read should grab the packet. - ASSERT_TRUE(read_protocol_->Read()); - ASSERT_TRUE(PacketEquals(read_protocol_, id, data, sizeof(data))); - - // Second read should fail. - ASSERT_FALSE(read_protocol_->Read()); -} diff --git a/adb/socket.h b/adb/socket.h deleted file mode 100644 index 4276851d252aa6579608ac1e120d7c7af70a1e53..0000000000000000000000000000000000000000 --- a/adb/socket.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (C) 2015 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_SOCKET_H -#define __ADB_SOCKET_H - -#include - -#include -#include -#include - -#include "adb_unique_fd.h" -#include "fdevent/fdevent.h" -#include "types.h" - -class atransport; - -/* 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 { - /* the unique identifier for this asocket - */ - unsigned id = 0; - - /* flag: set when the socket's peer has closed - * but packets are still queued for delivery - */ - int closing = 0; - - // flag: set when the socket failed to write, so the socket will not wait to - // write packets and close directly. - bool has_write_error = 0; - - /* flag: quit adbd when both ends close the - * local service socket - */ - int exit_on_close = 0; - - // the asocket we are connected to - asocket* peer = nullptr; - - /* 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 = nullptr; - int fd = -1; - - // queue of data waiting to be written - IOVector packet_queue; - - std::string smart_socket_data; - - /* 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::payload_type data) = nullptr; - - /* ready is called by the peer when it is ready for - * us to send data via enqueue again - */ - void (*ready)(asocket* s) = nullptr; - - /* 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) = nullptr; - - /* 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) = nullptr; - - /* A socket is bound to atransport */ - atransport* transport = nullptr; - - size_t get_max_payload() const; -}; - -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); - -asocket* create_local_socket(unique_fd fd); -asocket* create_local_service_socket(std::string_view destination, atransport* transport); - -asocket *create_remote_socket(unsigned id, atransport *t); -void connect_to_remote(asocket* s, std::string_view destination); -void connect_to_smartsocket(asocket *s); - -// Internal functions that are only made available here for testing purposes. -namespace internal { - -#if ADB_HOST -bool parse_host_service(std::string_view* out_serial, std::string_view* out_command, - std::string_view service); -#endif - -} // namespace internal - -#endif // __ADB_SOCKET_H diff --git a/adb/socket_spec.cpp b/adb/socket_spec.cpp deleted file mode 100644 index d17036cec9a5c7c51aaaa86e2cfc2dcdc5e392bc..0000000000000000000000000000000000000000 --- a/adb/socket_spec.cpp +++ /dev/null @@ -1,449 +0,0 @@ -/* - * Copyright (C) 2016 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 "socket_spec.h" - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "adb.h" -#include "adb_utils.h" -#include "sysdeps.h" - -using namespace std::string_literals; - -using android::base::ConsumePrefix; -using android::base::StringPrintf; - -#if defined(__linux__) -#define ADB_LINUX 1 -#else -#define ADB_LINUX 0 -#endif - -#if defined(_WIN32) -#define ADB_WINDOWS 1 -#else -#define ADB_WINDOWS 0 -#endif - -#if ADB_LINUX -#include -#include "sysdeps/vm_sockets.h" -#endif - -// Not static because it is used in commandline.c. -int gListenAll = 0; - -struct LocalSocketType { - int socket_namespace; - bool available; -}; - -static auto& kLocalSocketTypes = *new std::unordered_map({ -#if ADB_HOST - { "local", { ANDROID_SOCKET_NAMESPACE_FILESYSTEM, !ADB_WINDOWS } }, -#else - { "local", { ANDROID_SOCKET_NAMESPACE_RESERVED, !ADB_WINDOWS } }, -#endif - - { "localreserved", { ANDROID_SOCKET_NAMESPACE_RESERVED, !ADB_HOST } }, - { "localabstract", { ANDROID_SOCKET_NAMESPACE_ABSTRACT, ADB_LINUX } }, - { "localfilesystem", { ANDROID_SOCKET_NAMESPACE_FILESYSTEM, !ADB_WINDOWS } }, -}); - -bool parse_tcp_socket_spec(std::string_view spec, std::string* hostname, int* port, - std::string* serial, std::string* error) { - if (!spec.starts_with("tcp:")) { - *error = "specification is not tcp: "; - *error += spec; - return false; - } - - std::string hostname_value; - int port_value; - - // If the spec is tcp:, parse it ourselves. - // Otherwise, delegate to android::base::ParseNetAddress. - if (android::base::ParseInt(&spec[4], &port_value)) { - // Do the range checking ourselves, because ParseInt rejects 'tcp:65536' and 'tcp:foo:1234' - // identically. - if (port_value < 0 || port_value > 65535) { - *error = StringPrintf("bad port number '%d'", port_value); - return false; - } - } else { - std::string addr(spec.substr(4)); - port_value = DEFAULT_ADB_LOCAL_TRANSPORT_PORT; - - // FIXME: ParseNetAddress rejects port 0. This currently doesn't hurt, because listening - // on an address that isn't 'localhost' is unsupported. - if (!android::base::ParseNetAddress(addr, &hostname_value, &port_value, serial, error)) { - return false; - } - - if (port_value == -1) { - *error = "missing port in specification: "; - *error += spec; - return false; - } - } - - if (hostname) { - *hostname = std::move(hostname_value); - } - - if (port) { - *port = port_value; - } - - return true; -} - -int get_host_socket_spec_port(std::string_view spec, std::string* error) { - int port; - if (spec.starts_with("tcp:")) { - if (!parse_tcp_socket_spec(spec, nullptr, &port, nullptr, error)) { - return -1; - } - } else if (spec.starts_with("vsock:")) { -#if ADB_LINUX - std::string spec_str(spec); - std::vector fragments = android::base::Split(spec_str, ":"); - if (fragments.size() != 2) { - *error = "given vsock server socket string was invalid"; - return -1; - } - if (!android::base::ParseInt(fragments[1], &port)) { - *error = "could not parse vsock port"; - errno = EINVAL; - return -1; - } - if (port < 0) { - *error = "vsock port was negative."; - errno = EINVAL; - return -1; - } -#else // ADB_LINUX - *error = "vsock is only supported on linux"; - return -1; -#endif // ADB_LINUX - } else { - *error = "given socket spec string was invalid"; - return -1; - } - return port; -} - -static bool tcp_host_is_local(std::string_view hostname) { - // FIXME - return hostname.empty() || hostname == "localhost"; -} - -bool is_socket_spec(std::string_view spec) { - for (const auto& it : kLocalSocketTypes) { - std::string prefix = it.first + ":"; - if (spec.starts_with(prefix)) { - return true; - } - } - return spec.starts_with("tcp:") || spec.starts_with("acceptfd:"); -} - -bool is_local_socket_spec(std::string_view spec) { - for (const auto& it : kLocalSocketTypes) { - std::string prefix = it.first + ":"; - if (spec.starts_with(prefix)) { - return true; - } - } - - std::string error; - std::string hostname; - if (!parse_tcp_socket_spec(spec, &hostname, nullptr, nullptr, &error)) { - return false; - } - return tcp_host_is_local(hostname); -} - -bool socket_spec_connect(unique_fd* fd, std::string_view address, int* port, std::string* serial, - std::string* error) { - if (address.starts_with("tcp:")) { - std::string hostname; - int port_value = port ? *port : 0; - if (!parse_tcp_socket_spec(address, &hostname, &port_value, serial, error)) { - return false; - } - - if (tcp_host_is_local(hostname)) { - fd->reset(network_loopback_client(port_value, SOCK_STREAM, error)); - } else { -#if ADB_HOST - fd->reset(network_connect(hostname, port_value, SOCK_STREAM, 0, error)); -#else - // Disallow arbitrary connections in adbd. - *error = "adbd does not support arbitrary tcp connections"; - return false; -#endif - } - - if (fd->get() > 0) { - disable_tcp_nagle(fd->get()); - if (port) { - *port = port_value; - } - return true; - } - return false; - } else if (address.starts_with("vsock:")) { -#if ADB_LINUX - std::string spec_str(address); - std::vector fragments = android::base::Split(spec_str, ":"); - unsigned int port_value = port ? *port : 0; - if (fragments.size() != 2 && fragments.size() != 3) { - *error = android::base::StringPrintf("expected vsock:cid or vsock:port:cid in '%s'", - spec_str.c_str()); - errno = EINVAL; - return false; - } - unsigned int cid = 0; - if (!android::base::ParseUint(fragments[1], &cid)) { - *error = android::base::StringPrintf("could not parse vsock cid in '%s'", - spec_str.c_str()); - errno = EINVAL; - return false; - } - if (fragments.size() == 3 && !android::base::ParseUint(fragments[2], &port_value)) { - *error = android::base::StringPrintf("could not parse vsock port in '%s'", - spec_str.c_str()); - errno = EINVAL; - return false; - } - if (port_value == 0) { - *error = android::base::StringPrintf("vsock port was not provided."); - errno = EINVAL; - return false; - } - fd->reset(socket(AF_VSOCK, SOCK_STREAM, 0)); - if (fd->get() == -1) { - *error = "could not open vsock socket"; - return false; - } - sockaddr_vm addr{}; - addr.svm_family = AF_VSOCK; - addr.svm_port = port_value; - addr.svm_cid = cid; - if (serial) { - *serial = android::base::StringPrintf("vsock:%u:%d", cid, port_value); - } - if (connect(fd->get(), reinterpret_cast(&addr), sizeof(addr))) { - int error_num = errno; - *error = android::base::StringPrintf("could not connect to vsock address '%s'", - spec_str.c_str()); - errno = error_num; - return false; - } - if (port) { - *port = port_value; - } - return true; -#else // ADB_LINUX - *error = "vsock is only supported on linux"; - return false; -#endif // ADB_LINUX - } else if (address.starts_with("acceptfd:")) { - *error = "cannot connect to acceptfd"; - return false; - } - - for (const auto& it : kLocalSocketTypes) { - std::string prefix = it.first + ":"; - if (address.starts_with(prefix)) { - if (!it.second.available) { - *error = StringPrintf("socket type %s is unavailable on this platform", - it.first.c_str()); - return false; - } - - fd->reset(network_local_client(&address[prefix.length()], it.second.socket_namespace, - SOCK_STREAM, error)); - - if (fd->get() < 0) { - *error = - android::base::StringPrintf("could not connect to %s address '%s'", - it.first.c_str(), std::string(address).c_str()); - return false; - } - - if (serial) { - *serial = address; - } - return true; - } - } - - *error = "unknown socket specification: "; - *error += address; - return false; -} - -int socket_spec_listen(std::string_view spec, std::string* error, int* resolved_port) { - if (spec.starts_with("tcp:")) { - std::string hostname; - int port; - if (!parse_tcp_socket_spec(spec, &hostname, &port, nullptr, error)) { - return -1; - } - - int result; -#if ADB_HOST - if (hostname.empty() && gListenAll) { -#else - if (hostname.empty()) { -#endif - result = network_inaddr_any_server(port, SOCK_STREAM, error); - } else if (tcp_host_is_local(hostname)) { - result = network_loopback_server(port, SOCK_STREAM, error, true); - } else if (hostname == "::1") { - result = network_loopback_server(port, SOCK_STREAM, error, false); - } else { - // TODO: Implement me. - *error = "listening on specified hostname currently unsupported"; - return -1; - } - - if (result >= 0 && resolved_port) { - *resolved_port = adb_socket_get_local_port(result); - } - return result; - } else if (spec.starts_with("vsock:")) { -#if ADB_LINUX - std::string spec_str(spec); - std::vector fragments = android::base::Split(spec_str, ":"); - if (fragments.size() != 2) { - *error = "given vsock server socket string was invalid"; - return -1; - } - int port; - if (!android::base::ParseInt(fragments[1], &port)) { - *error = "could not parse vsock port"; - errno = EINVAL; - return -1; - } else if (port < 0) { - *error = "vsock port was negative."; - errno = EINVAL; - return -1; - } - unique_fd serverfd(socket(AF_VSOCK, SOCK_STREAM, 0)); - if (serverfd == -1) { - int error_num = errno; - *error = android::base::StringPrintf("could not create vsock server: '%s'", - strerror(error_num)); - errno = error_num; - return -1; - } - sockaddr_vm addr{}; - addr.svm_family = AF_VSOCK; - addr.svm_port = port == 0 ? VMADDR_PORT_ANY : port; - addr.svm_cid = VMADDR_CID_ANY; - socklen_t addr_len = sizeof(addr); - if (bind(serverfd.get(), reinterpret_cast(&addr), addr_len)) { - return -1; - } - if (listen(serverfd.get(), 4)) { - return -1; - } - if (serverfd >= 0 && resolved_port) { - if (getsockname(serverfd.get(), reinterpret_cast(&addr), &addr_len) == 0) { - *resolved_port = addr.svm_port; - } else { - return -1; - } - } - return serverfd.release(); -#else // ADB_LINUX - *error = "vsock is only supported on linux"; - return -1; -#endif // ADB_LINUX - } else if (ConsumePrefix(&spec, "acceptfd:")) { -#if ADB_WINDOWS - *error = "socket activation not supported under Windows"; - return -1; -#else - // We inherited the socket from some kind of launcher. It's already bound and - // listening. Return a copy of the FD instead of the FD itself so we implement the - // normal "listen" contract and can succeed more than once. - unsigned int fd_u; - if (!ParseUint(&fd_u, spec) || fd_u > std::numeric_limits::max()) { - *error = "invalid fd"; - return -1; - } - int fd = static_cast(fd_u); - int flags = get_fd_flags(fd); - if (flags < 0) { - *error = android::base::StringPrintf("could not get flags of inherited fd %d: '%s'", fd, - strerror(errno)); - return -1; - } - if (flags & FD_CLOEXEC) { - *error = android::base::StringPrintf("fd %d was not inherited from parent", fd); - return -1; - } - - int dummy_sock_type; - socklen_t dummy_sock_type_size = sizeof(dummy_sock_type); - if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &dummy_sock_type, &dummy_sock_type_size)) { - *error = android::base::StringPrintf("fd %d does not refer to a socket", fd); - return -1; - } - - int new_fd = fcntl(fd, F_DUPFD_CLOEXEC, 0); - if (new_fd < 0) { - *error = android::base::StringPrintf("could not dup inherited fd %d: '%s'", fd, - strerror(errno)); - return -1; - } - return new_fd; -#endif - } - - for (const auto& it : kLocalSocketTypes) { - std::string prefix = it.first + ":"; - if (spec.starts_with(prefix)) { - if (!it.second.available) { - *error = "attempted to listen on unavailable socket type: "; - *error += spec; - return -1; - } - - return network_local_server(&spec[prefix.length()], it.second.socket_namespace, - SOCK_STREAM, error); - } - } - - *error = "unknown socket specification:"; - *error += spec; - return -1; -} diff --git a/adb/socket_spec.h b/adb/socket_spec.h deleted file mode 100644 index 94719c811944fdd334d57d448b80c051ab787787..0000000000000000000000000000000000000000 --- a/adb/socket_spec.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2016 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. - */ - -#pragma once - -#include -#include - -#include "adb_unique_fd.h" - -// Returns true if the argument starts with a plausible socket prefix. -bool is_socket_spec(std::string_view spec); -bool is_local_socket_spec(std::string_view spec); - -bool socket_spec_connect(unique_fd* fd, std::string_view address, int* port, std::string* serial, - std::string* error); -int socket_spec_listen(std::string_view spec, std::string* error, int* resolved_tcp_port = nullptr); - -bool parse_tcp_socket_spec(std::string_view spec, std::string* hostname, int* port, - std::string* serial, std::string* error); - -int get_host_socket_spec_port(std::string_view spec, std::string* error); diff --git a/adb/socket_spec_test.cpp b/adb/socket_spec_test.cpp deleted file mode 100644 index e9d5270ca5f1ba0d8671cd3dcd28647b0e119d0b..0000000000000000000000000000000000000000 --- a/adb/socket_spec_test.cpp +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (C) 2016 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 "socket_spec.h" - -#include - -#include - -#include -#include -#include - -TEST(socket_spec, parse_tcp_socket_spec_just_port) { - std::string hostname, error, serial; - int port; - EXPECT_TRUE(parse_tcp_socket_spec("tcp:5037", &hostname, &port, &serial, &error)); - EXPECT_EQ("", hostname); - EXPECT_EQ(5037, port); - EXPECT_EQ("", serial); -} - -TEST(socket_spec, parse_tcp_socket_spec_bad_ports) { - std::string hostname, error, serial; - int port; - EXPECT_FALSE(parse_tcp_socket_spec("tcp:", &hostname, &port, &serial, &error)); - EXPECT_FALSE(parse_tcp_socket_spec("tcp:-1", &hostname, &port, &serial, &error)); - EXPECT_FALSE(parse_tcp_socket_spec("tcp:65536", &hostname, &port, &serial, &error)); -} - -TEST(socket_spec, parse_tcp_socket_spec_host_and_port) { - std::string hostname, error, serial; - int port; - EXPECT_TRUE(parse_tcp_socket_spec("tcp:localhost:1234", &hostname, &port, &serial, &error)); - EXPECT_EQ("localhost", hostname); - EXPECT_EQ(1234, port); - EXPECT_EQ("localhost:1234", serial); -} - -TEST(socket_spec, parse_tcp_socket_spec_host_no_port) { - std::string hostname, error, serial; - int port; - EXPECT_TRUE(parse_tcp_socket_spec("tcp:localhost", &hostname, &port, &serial, &error)); - EXPECT_EQ("localhost", hostname); - EXPECT_EQ(5555, port); - EXPECT_EQ("localhost:5555", serial); -} - -TEST(socket_spec, parse_tcp_socket_spec_host_bad_ports) { - std::string hostname, error, serial; - int port; - EXPECT_FALSE(parse_tcp_socket_spec("tcp:localhost:", &hostname, &port, &serial, &error)); - EXPECT_FALSE(parse_tcp_socket_spec("tcp:localhost:-1", &hostname, &port, &serial, &error)); - EXPECT_FALSE(parse_tcp_socket_spec("tcp:localhost:65536", &hostname, &port, &serial, &error)); -} - -TEST(socket_spec, parse_tcp_socket_spec_ipv6_and_port) { - std::string hostname, error, serial; - int port; - EXPECT_TRUE(parse_tcp_socket_spec("tcp:[::1]:1234", &hostname, &port, &serial, &error)); - EXPECT_EQ("::1", hostname); - EXPECT_EQ(1234, port); - EXPECT_EQ("[::1]:1234", serial); -} - -TEST(socket_spec, parse_tcp_socket_spec_ipv6_no_port) { - std::string hostname, error, serial; - int port; - EXPECT_TRUE(parse_tcp_socket_spec("tcp:::1", &hostname, &port, &serial, &error)); - EXPECT_EQ("::1", hostname); - EXPECT_EQ(5555, port); - EXPECT_EQ("[::1]:5555", serial); -} - -TEST(socket_spec, parse_tcp_socket_spec_ipv6_bad_ports) { - std::string hostname, error, serial; - int port; - EXPECT_FALSE(parse_tcp_socket_spec("tcp:[::1]", &hostname, &port, &serial, &error)); - EXPECT_FALSE(parse_tcp_socket_spec("tcp:[::1]:", &hostname, &port, &serial, &error)); - EXPECT_FALSE(parse_tcp_socket_spec("tcp:[::1]:-1", &hostname, &port, &serial, &error)); -} - -TEST(socket_spec, get_host_socket_spec_port) { - std::string error; - EXPECT_EQ(5555, get_host_socket_spec_port("tcp:5555", &error)); - EXPECT_EQ(5555, get_host_socket_spec_port("tcp:localhost:5555", &error)); - EXPECT_EQ(5555, get_host_socket_spec_port("tcp:[::1]:5555", &error)); - EXPECT_EQ(5555, get_host_socket_spec_port("vsock:5555", &error)); -} - -TEST(socket_spec, get_host_socket_spec_port_no_port) { - std::string error; - EXPECT_EQ(5555, get_host_socket_spec_port("tcp:localhost", &error)); - EXPECT_EQ(-1, get_host_socket_spec_port("vsock:localhost", &error)); -} - -TEST(socket_spec, get_host_socket_spec_port_bad_ports) { - std::string error; - EXPECT_EQ(-1, get_host_socket_spec_port("tcp:65536", &error)); - EXPECT_EQ(-1, get_host_socket_spec_port("tcp:-5", &error)); - EXPECT_EQ(-1, get_host_socket_spec_port("vsock:-5", &error)); - EXPECT_EQ(-1, get_host_socket_spec_port("vsock:5:5555", &error)); -} - -TEST(socket_spec, get_host_socket_spec_port_bad_string) { - std::string error; - EXPECT_EQ(-1, get_host_socket_spec_port("tcpz:5555", &error)); - EXPECT_EQ(-1, get_host_socket_spec_port("vsockz:5555", &error)); - EXPECT_EQ(-1, get_host_socket_spec_port("abcd:5555", &error)); - EXPECT_EQ(-1, get_host_socket_spec_port("abcd", &error)); -} - -TEST(socket_spec, socket_spec_listen_connect_tcp) { - std::string error, serial; - int port; - unique_fd server_fd, client_fd; - EXPECT_FALSE(socket_spec_connect(&client_fd, "tcp:localhost:7777", &port, &serial, &error)); - server_fd.reset(socket_spec_listen("tcp:7777", &error, &port)); - EXPECT_NE(server_fd.get(), -1); - EXPECT_TRUE(socket_spec_connect(&client_fd, "tcp:localhost:7777", &port, &serial, &error)); - EXPECT_NE(client_fd.get(), -1); -} - -TEST(socket_spec, socket_spec_listen_connect_localfilesystem) { - std::string error, serial; - int port; - unique_fd server_fd, client_fd; - TemporaryDir sock_dir; - - // Only run this test if the created directory is writable. - int result = access(sock_dir.path, W_OK); - if (result == 0) { - std::string sock_addr = - android::base::StringPrintf("localfilesystem:%s/af_unix_socket", sock_dir.path); - EXPECT_FALSE(socket_spec_connect(&client_fd, sock_addr, &port, &serial, &error)); - server_fd.reset(socket_spec_listen(sock_addr, &error, &port)); - EXPECT_NE(server_fd.get(), -1); - EXPECT_TRUE(socket_spec_connect(&client_fd, sock_addr, &port, &serial, &error)); - EXPECT_NE(client_fd.get(), -1); - } -} diff --git a/adb/socket_test.cpp b/adb/socket_test.cpp deleted file mode 100644 index 1601ff0ac1fc7eb7f7b5f6d8e3485881ec1824f4..0000000000000000000000000000000000000000 --- a/adb/socket_test.cpp +++ /dev/null @@ -1,386 +0,0 @@ -/* - * Copyright (C) 2015 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 "fdevent/fdevent.h" - -#include - -#include -#include -#include -#include -#include -#include - -#include - -#include "adb.h" -#include "adb_io.h" -#include "fdevent/fdevent_test.h" -#include "socket.h" -#include "sysdeps.h" -#include "sysdeps/chrono.h" - -using namespace std::string_literals; -using namespace std::string_view_literals; - -struct ThreadArg { - int first_read_fd; - int last_write_fd; - size_t middle_pipe_count; -}; - -class LocalSocketTest : public FdeventTest {}; - -TEST_F(LocalSocketTest, smoke) { - // Join two socketpairs with a chain of intermediate socketpairs. - int first[2]; - std::vector> intermediates; - int last[2]; - - constexpr size_t INTERMEDIATE_COUNT = 50; - constexpr size_t MESSAGE_LOOP_COUNT = 100; - const std::string MESSAGE = "socket_test"; - - intermediates.resize(INTERMEDIATE_COUNT); - ASSERT_EQ(0, adb_socketpair(first)) << strerror(errno); - ASSERT_EQ(0, adb_socketpair(last)) << strerror(errno); - asocket* prev_tail = create_local_socket(unique_fd(first[1])); - ASSERT_NE(nullptr, prev_tail); - - auto connect = [](asocket* tail, asocket* head) { - tail->peer = head; - head->peer = tail; - tail->ready(tail); - }; - - for (auto& intermediate : intermediates) { - ASSERT_EQ(0, adb_socketpair(intermediate.data())) << strerror(errno); - - asocket* head = create_local_socket(unique_fd(intermediate[0])); - ASSERT_NE(nullptr, head); - - asocket* tail = create_local_socket(unique_fd(intermediate[1])); - ASSERT_NE(nullptr, tail); - - connect(prev_tail, head); - prev_tail = tail; - } - - asocket* end = create_local_socket(unique_fd(last[0])); - ASSERT_NE(nullptr, end); - connect(prev_tail, end); - - PrepareThread(); - - for (size_t i = 0; i < MESSAGE_LOOP_COUNT; ++i) { - std::string read_buffer = MESSAGE; - std::string write_buffer(MESSAGE.size(), 'a'); - ASSERT_TRUE(WriteFdExactly(first[0], &read_buffer[0], read_buffer.size())); - ASSERT_TRUE(ReadFdExactly(last[1], &write_buffer[0], write_buffer.size())); - ASSERT_EQ(read_buffer, write_buffer); - } - - ASSERT_EQ(0, adb_close(first[0])); - ASSERT_EQ(0, adb_close(last[1])); - - // Wait until the local sockets are closed. - WaitForFdeventLoop(); - ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count()); - TerminateThread(); -} - -struct CloseWithPacketArg { - unique_fd socket_fd; - size_t bytes_written; - unique_fd cause_close_fd; -}; - -static void CreateCloser(CloseWithPacketArg* arg) { - fdevent_run_on_main_thread([arg]() { - asocket* s = create_local_socket(std::move(arg->socket_fd)); - ASSERT_TRUE(s != nullptr); - arg->bytes_written = 0; - - // On platforms that implement sockets via underlying sockets (e.g. Wine), - // a socket can appear to be full, and then become available for writes - // again without read being called on the other end. Loop and sleep after - // each write to give the underlying implementation time to flush. - bool socket_filled = false; - for (int i = 0; i < 128; ++i) { - apacket::payload_type data; - data.resize(MAX_PAYLOAD); - arg->bytes_written += data.size(); - int ret = s->enqueue(s, std::move(data)); - if (ret == 1) { - socket_filled = true; - break; - } - ASSERT_NE(-1, ret); - - std::this_thread::sleep_for(250ms); - } - ASSERT_TRUE(socket_filled); - - asocket* cause_close_s = create_local_socket(std::move(arg->cause_close_fd)); - ASSERT_TRUE(cause_close_s != nullptr); - cause_close_s->peer = s; - s->peer = cause_close_s; - cause_close_s->ready(cause_close_s); - }); - WaitForFdeventLoop(); -} - -// This test checks if we can close local socket in the following situation: -// The socket is closing but having some packets, so it is not closed. Then -// some write error happens in the socket's file handler, e.g., the file -// handler is closed. -TEST_F(LocalSocketTest, close_socket_with_packet) { - int socket_fd[2]; - ASSERT_EQ(0, adb_socketpair(socket_fd)); - int cause_close_fd[2]; - ASSERT_EQ(0, adb_socketpair(cause_close_fd)); - CloseWithPacketArg arg; - arg.socket_fd.reset(socket_fd[1]); - arg.cause_close_fd.reset(cause_close_fd[1]); - - PrepareThread(); - CreateCloser(&arg); - - ASSERT_EQ(0, adb_close(cause_close_fd[0])); - - WaitForFdeventLoop(); - EXPECT_EQ(1u + GetAdditionalLocalSocketCount(), fdevent_installed_count()); - ASSERT_EQ(0, adb_close(socket_fd[0])); - - WaitForFdeventLoop(); - ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count()); - TerminateThread(); -} - -// This test checks if we can read packets from a closing local socket. -TEST_F(LocalSocketTest, read_from_closing_socket) { - int socket_fd[2]; - ASSERT_EQ(0, adb_socketpair(socket_fd)); - int cause_close_fd[2]; - ASSERT_EQ(0, adb_socketpair(cause_close_fd)); - CloseWithPacketArg arg; - arg.socket_fd.reset(socket_fd[1]); - arg.cause_close_fd.reset(cause_close_fd[1]); - - PrepareThread(); - CreateCloser(&arg); - - WaitForFdeventLoop(); - ASSERT_EQ(0, adb_close(cause_close_fd[0])); - - WaitForFdeventLoop(); - EXPECT_EQ(1u + GetAdditionalLocalSocketCount(), fdevent_installed_count()); - - // Verify if we can read successfully. - std::vector buf(arg.bytes_written); - ASSERT_NE(0u, arg.bytes_written); - ASSERT_EQ(true, ReadFdExactly(socket_fd[0], buf.data(), buf.size())); - ASSERT_EQ(0, adb_close(socket_fd[0])); - - WaitForFdeventLoop(); - ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count()); - TerminateThread(); -} - -// This test checks if we can close local socket in the following situation: -// The socket is not closed and has some packets. When it fails to write to -// the socket's file handler because the other end is closed, we check if the -// socket is closed. -TEST_F(LocalSocketTest, write_error_when_having_packets) { - int socket_fd[2]; - ASSERT_EQ(0, adb_socketpair(socket_fd)); - int cause_close_fd[2]; - ASSERT_EQ(0, adb_socketpair(cause_close_fd)); - CloseWithPacketArg arg; - arg.socket_fd.reset(socket_fd[1]); - arg.cause_close_fd.reset(cause_close_fd[1]); - - PrepareThread(); - CreateCloser(&arg); - - WaitForFdeventLoop(); - EXPECT_EQ(2u + GetAdditionalLocalSocketCount(), fdevent_installed_count()); - ASSERT_EQ(0, adb_close(socket_fd[0])); - - std::this_thread::sleep_for(2s); - - WaitForFdeventLoop(); - ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count()); - TerminateThread(); -} - -// Ensure that if we fail to write output to an fd, we will still flush data coming from it. -TEST_F(LocalSocketTest, flush_after_shutdown) { - int head_fd[2]; - int tail_fd[2]; - ASSERT_EQ(0, adb_socketpair(head_fd)); - ASSERT_EQ(0, adb_socketpair(tail_fd)); - - asocket* head = create_local_socket(unique_fd(head_fd[1])); - asocket* tail = create_local_socket(unique_fd(tail_fd[1])); - - head->peer = tail; - head->ready(head); - - tail->peer = head; - tail->ready(tail); - - PrepareThread(); - - EXPECT_TRUE(WriteFdExactly(head_fd[0], "foo", 3)); - - EXPECT_EQ(0, adb_shutdown(head_fd[0], SHUT_RD)); - const char* str = "write succeeds, but local_socket will fail to write"; - EXPECT_TRUE(WriteFdExactly(tail_fd[0], str, strlen(str))); - EXPECT_TRUE(WriteFdExactly(head_fd[0], "bar", 3)); - - char buf[6]; - EXPECT_TRUE(ReadFdExactly(tail_fd[0], buf, 6)); - EXPECT_EQ(0, memcmp(buf, "foobar", 6)); - - adb_close(head_fd[0]); - adb_close(tail_fd[0]); - - WaitForFdeventLoop(); - ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count()); - TerminateThread(); -} - -#if defined(__linux__) - -static void ClientThreadFunc() { - std::string error; - int fd = network_loopback_client(5038, SOCK_STREAM, &error); - ASSERT_GE(fd, 0) << error; - std::this_thread::sleep_for(1s); - ASSERT_EQ(0, adb_close(fd)); -} - -// This test checks if we can close sockets in CLOSE_WAIT state. -TEST_F(LocalSocketTest, close_socket_in_CLOSE_WAIT_state) { - std::string error; - int listen_fd = network_inaddr_any_server(5038, SOCK_STREAM, &error); - ASSERT_GE(listen_fd, 0); - - std::thread client_thread(ClientThreadFunc); - - int accept_fd = adb_socket_accept(listen_fd, nullptr, nullptr); - ASSERT_GE(accept_fd, 0); - - PrepareThread(); - - fdevent_run_on_main_thread([accept_fd]() { - asocket* s = create_local_socket(unique_fd(accept_fd)); - ASSERT_TRUE(s != nullptr); - }); - - WaitForFdeventLoop(); - EXPECT_EQ(1u + GetAdditionalLocalSocketCount(), fdevent_installed_count()); - - // Wait until the client closes its socket. - client_thread.join(); - - WaitForFdeventLoop(); - ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count()); - TerminateThread(); -} - -#endif // defined(__linux__) - -#if ADB_HOST - -#define VerifyParseHostServiceFailed(s) \ - do { \ - std::string service(s); \ - std::string_view serial, command; \ - bool result = internal::parse_host_service(&serial, &command, service); \ - EXPECT_FALSE(result); \ - } while (0) - -#define VerifyParseHostService(s, expected_serial, expected_command) \ - do { \ - std::string service(s); \ - std::string_view serial, command; \ - bool result = internal::parse_host_service(&serial, &command, service); \ - EXPECT_TRUE(result); \ - EXPECT_EQ(std::string(expected_serial), std::string(serial)); \ - EXPECT_EQ(std::string(expected_command), std::string(command)); \ - } while (0); - -// Check [tcp:|udp:][:]: format. -TEST(socket_test, test_parse_host_service) { - for (const std::string& protocol : {"", "tcp:", "udp:"}) { - VerifyParseHostServiceFailed(protocol); - VerifyParseHostServiceFailed(protocol + "foo"); - - { - std::string serial = protocol + "foo"; - VerifyParseHostService(serial + ":bar", serial, "bar"); - VerifyParseHostService(serial + " :bar:baz", serial, "bar:baz"); - } - - { - // With port. - std::string serial = protocol + "foo:123"; - VerifyParseHostService(serial + ":bar", serial, "bar"); - VerifyParseHostService(serial + ":456", serial, "456"); - VerifyParseHostService(serial + ":bar:baz", serial, "bar:baz"); - } - - // Don't register a port unless it's all numbers and ends with ':'. - VerifyParseHostService(protocol + "foo:123", protocol + "foo", "123"); - VerifyParseHostService(protocol + "foo:123bar:baz", protocol + "foo", "123bar:baz"); - - std::string addresses[] = {"100.100.100.100", "[0123:4567:89ab:CDEF:0:9:a:f]", "[::1]"}; - for (const std::string& address : addresses) { - std::string serial = protocol + address; - std::string serial_with_port = protocol + address + ":5555"; - VerifyParseHostService(serial + ":foo", serial, "foo"); - VerifyParseHostService(serial_with_port + ":foo", serial_with_port, "foo"); - } - - // If we can't find both [] then treat it as a normal serial with [ in it. - VerifyParseHostService(protocol + "[0123:foo", protocol + "[0123", "foo"); - - // Don't be fooled by random IPv6 addresses in the command string. - VerifyParseHostService(protocol + "foo:ping [0123:4567:89ab:CDEF:0:9:a:f]:5555", - protocol + "foo", "ping [0123:4567:89ab:CDEF:0:9:a:f]:5555"); - - // Handle embedded NULs properly. - VerifyParseHostService(protocol + "foo:echo foo\0bar"s, protocol + "foo", - "echo foo\0bar"sv); - } -} - -// Check :: format. -TEST(socket_test, test_parse_host_service_prefix) { - for (const std::string& prefix : {"usb:", "product:", "model:", "device:"}) { - VerifyParseHostServiceFailed(prefix); - VerifyParseHostServiceFailed(prefix + "foo"); - - VerifyParseHostService(prefix + "foo:bar", prefix + "foo", "bar"); - VerifyParseHostService(prefix + "foo:bar:baz", prefix + "foo", "bar:baz"); - VerifyParseHostService(prefix + "foo:123:bar", prefix + "foo", "123:bar"); - } -} - -#endif // ADB_HOST diff --git a/adb/sockets.cpp b/adb/sockets.cpp deleted file mode 100644 index 423af67f1c542016e9753669aff829dd0516ccb6..0000000000000000000000000000000000000000 --- a/adb/sockets.cpp +++ /dev/null @@ -1,935 +0,0 @@ -/* - * 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 SOCKETS - -#include "sysdeps.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#if !ADB_HOST -#include -#include -#endif - -#include "adb.h" -#include "adb_io.h" -#include "adb_utils.h" -#include "transport.h" -#include "types.h" - -using namespace std::chrono_literals; - -static std::recursive_mutex& local_socket_list_lock = *new std::recursive_mutex(); -static unsigned local_socket_next_id = 1; - -static auto& local_socket_list = *new std::vector(); - -/* the the list of currently closing local sockets. -** these have no peer anymore, but still packets to -** write to their fd. -*/ -static auto& local_socket_closing_list = *new std::vector(); - -// 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* result = nullptr; - - std::lock_guard lock(local_socket_list_lock); - for (asocket* s : local_socket_list) { - if (s->id != local_id) { - continue; - } - if (peer_id == 0 || (s->peer && s->peer->id == peer_id)) { - result = s; - } - break; - } - - return result; -} - -void install_local_socket(asocket* s) { - std::lock_guard lock(local_socket_list_lock); - - s->id = local_socket_next_id++; - - // Socket ids should never be 0. - if (local_socket_next_id == 0) { - LOG(FATAL) << "local socket id overflow"; - } - - local_socket_list.push_back(s); -} - -void remove_socket(asocket* s) { - std::lock_guard lock(local_socket_list_lock); - for (auto list : { &local_socket_list, &local_socket_closing_list }) { - list->erase(std::remove_if(list->begin(), list->end(), [s](asocket* x) { return x == s; }), - list->end()); - } -} - -void close_all_sockets(atransport* t) { - /* this is a little gross, but since s->close() *will* modify - ** the list out from under you, your options are limited. - */ - std::lock_guard lock(local_socket_list_lock); -restart: - for (asocket* s : local_socket_list) { - if (s->transport == t || (s->peer && s->peer->transport == t)) { - s->close(s); - goto restart; - } - } -} - -enum class SocketFlushResult { - Destroyed, - TryAgain, - Completed, -}; - -static SocketFlushResult local_socket_flush_incoming(asocket* s) { - if (!s->packet_queue.empty()) { - std::vector iov = s->packet_queue.iovecs(); - ssize_t rc = adb_writev(s->fd, iov.data(), iov.size()); - if (rc > 0 && static_cast(rc) == s->packet_queue.size()) { - s->packet_queue.clear(); - } else if (rc > 0) { - s->packet_queue.drop_front(rc); - fdevent_add(s->fde, FDE_WRITE); - return SocketFlushResult::TryAgain; - } else if (rc == -1 && errno == EAGAIN) { - fdevent_add(s->fde, FDE_WRITE); - return SocketFlushResult::TryAgain; - } else { - // We failed to write, but it's possible that we can still read from the socket. - // Give that a try before giving up. - s->has_write_error = true; - } - } - - // If we sent the last packet of a closing socket, we can now destroy it. - if (s->closing) { - s->close(s); - return SocketFlushResult::Destroyed; - } - - fdevent_del(s->fde, FDE_WRITE); - return SocketFlushResult::Completed; -} - -// Returns false if the socket has been closed and destroyed as a side-effect of this function. -static bool local_socket_flush_outgoing(asocket* s) { - const size_t max_payload = s->get_max_payload(); - apacket::payload_type data; - data.resize(max_payload); - char* x = &data[0]; - size_t avail = max_payload; - int r = 0; - int is_eof = 0; - - while (avail > 0) { - r = adb_read(s->fd, x, avail); - D("LS(%d): post adb_read(fd=%d,...) r=%d (errno=%d) avail=%zu", s->id, s->fd, r, - r < 0 ? errno : 0, avail); - if (r == -1) { - if (errno == EAGAIN) { - break; - } - } else if (r > 0) { - avail -= r; - x += r; - 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", s->id, s->fd, r, is_eof, - s->fde->force_eof); - - if (avail != max_payload && s->peer) { - data.resize(max_payload - avail); - - // s->peer->enqueue() may call s->close() and free s, - // so save variables for debug printing below. - unsigned saved_id = s->id; - int saved_fd = s->fd; - r = s->peer->enqueue(s->peer, std::move(data)); - D("LS(%u): fd=%d post peer->enqueue(). r=%d", saved_id, saved_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 false; - } - - 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", is_eof, r, s->fde->force_eof); - s->close(s); - return false; - } - - return true; -} - -static int local_socket_enqueue(asocket* s, apacket::payload_type data) { - D("LS(%d): enqueue %zu", s->id, data.size()); - - s->packet_queue.append(std::move(data)); - switch (local_socket_flush_incoming(s)) { - case SocketFlushResult::Destroyed: - return -1; - - case SocketFlushResult::TryAgain: - return 1; - - case SocketFlushResult::Completed: - return 0; - } - - return !s->packet_queue.empty(); -} - -static void local_socket_ready(asocket* s) { - /* far side is ready for data, pay attention to - readable events */ - fdevent_add(s->fde, FDE_READ); -} - -struct ClosingSocket { - std::chrono::steady_clock::time_point begin; -}; - -// The standard (RFC 1122 - 4.2.2.13) says that if we call close on a -// socket while we have pending data, a TCP RST should be sent to the -// other end to notify it that we didn't read all of its data. However, -// this can result in data that we've successfully written out to be dropped -// on the other end. To avoid this, instead of immediately closing a -// socket, call shutdown on it instead, and then read from the file -// descriptor until we hit EOF or an error before closing. -static void deferred_close(unique_fd fd) { - // Shutdown the socket in the outgoing direction only, so that - // we don't have the same problem on the opposite end. - adb_shutdown(fd.get(), SHUT_WR); - auto callback = [](fdevent* fde, unsigned event, void* arg) { - auto socket_info = static_cast(arg); - if (event & FDE_READ) { - ssize_t rc; - char buf[BUFSIZ]; - while ((rc = adb_read(fde->fd.get(), buf, sizeof(buf))) > 0) { - continue; - } - - if (rc == -1 && errno == EAGAIN) { - // There's potentially more data to read. - auto duration = std::chrono::steady_clock::now() - socket_info->begin; - if (duration > 1s) { - LOG(WARNING) << "timeout expired while flushing socket, closing"; - } else { - return; - } - } - } else if (event & FDE_TIMEOUT) { - LOG(WARNING) << "timeout expired while flushing socket, closing"; - } - - // Either there was an error, we hit the end of the socket, or our timeout expired. - fdevent_destroy(fde); - delete socket_info; - }; - - ClosingSocket* socket_info = new ClosingSocket{ - .begin = std::chrono::steady_clock::now(), - }; - - fdevent* fde = fdevent_create(fd.release(), callback, socket_info); - fdevent_add(fde, FDE_READ); - fdevent_set_timeout(fde, 1s); -} - -// be sure to hold the socket list lock when calling this -static void local_socket_destroy(asocket* s) { - int exit_on_close = s->exit_on_close; - - D("LS(%d): destroying fde.fd=%d", s->id, s->fd); - - deferred_close(fdevent_release(s->fde)); - - remove_socket(s); - delete s; - - if (exit_on_close) { - D("local_socket_destroy: exiting"); - exit(1); - } -} - -static void local_socket_close(asocket* s) { - D("entered local_socket_close. LS(%d) fd=%d", s->id, s->fd); - std::lock_guard lock(local_socket_list_lock); - if (s->peer) { - D("LS(%d): closing peer. peer->id=%d peer->fd=%d", 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 = nullptr; - s->peer->close(s->peer); - s->peer = nullptr; - } - - /* If we are already closing, or if there are no - ** pending packets, destroy immediately - */ - if (s->closing || s->has_write_error || s->packet_queue.empty()) { - int id = s->id; - local_socket_destroy(s); - D("LS(%d): closed", id); - return; - } - - /* otherwise, put on the closing list - */ - D("LS(%d): closing", s->id); - s->closing = 1; - fdevent_del(s->fde, FDE_READ); - remove_socket(s); - D("LS(%d): put on socket_closing_list fd=%d", s->id, s->fd); - local_socket_closing_list.push_back(s); - CHECK_EQ(FDE_WRITE, s->fde->state & FDE_WRITE); -} - -static void local_socket_event_func(int fd, unsigned ev, void* _s) { - asocket* s = reinterpret_cast(_s); - D("LS(%d): event_func(fd=%d(==%d), ev=%04x)", 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) { - switch (local_socket_flush_incoming(s)) { - case SocketFlushResult::Destroyed: - return; - - case SocketFlushResult::TryAgain: - break; - - case SocketFlushResult::Completed: - s->peer->ready(s->peer); - break; - } - } - - if (ev & FDE_READ) { - if (!local_socket_flush_outgoing(s)) { - return; - } - } - - 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. - */ - D("LS(%d): FDE_ERROR (fd=%d)", s->id, s->fd); - return; - } -} - -asocket* create_local_socket(unique_fd ufd) { - int fd = ufd.release(); - asocket* s = new asocket(); - s->fd = fd; - s->enqueue = local_socket_enqueue; - s->ready = local_socket_ready; - s->shutdown = nullptr; - s->close = local_socket_close; - install_local_socket(s); - - s->fde = fdevent_create(fd, local_socket_event_func, s); - D("LS(%d): created (fd=%d)", s->id, s->fd); - return s; -} - -asocket* create_local_service_socket(std::string_view name, atransport* transport) { -#if !ADB_HOST - if (asocket* s = daemon_service_to_socket(name); s) { - return s; - } -#endif - unique_fd fd = service_to_fd(name, transport); - if (fd < 0) { - return nullptr; - } - - int fd_value = fd.get(); - asocket* s = create_local_socket(std::move(fd)); - LOG(VERBOSE) << "LS(" << s->id << "): bound to '" << name << "' via " << fd_value; - -#if !ADB_HOST - if ((name.starts_with("root:") && getuid() != 0 && __android_log_is_debuggable()) || - (name.starts_with("unroot:") && getuid() == 0) || name.starts_with("usb:") || - name.starts_with("tcpip:")) { - D("LS(%d): enabling exit_on_close", s->id); - s->exit_on_close = 1; - } -#endif - - return s; -} - -static int remote_socket_enqueue(asocket* s, apacket::payload_type data) { - D("entered remote_socket_enqueue RS(%d) WRITE fd=%d peer.fd=%d", s->id, s->fd, s->peer->fd); - apacket* p = get_apacket(); - - p->msg.command = A_WRTE; - p->msg.arg0 = s->peer->id; - p->msg.arg1 = s->id; - - if (data.size() > MAX_PAYLOAD) { - put_apacket(p); - return -1; - } - - p->payload = std::move(data); - p->msg.data_length = p->payload.size(); - - 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", 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", 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 = nullptr; - D("RS(%d) peer->close()ing peer->id=%d peer->fd=%d", 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", s->id, s->fd, - s->peer ? s->peer->fd : -1); - D("RS(%d): closed", s->id); - delete s; -} - -// Create a remote socket 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) { - if (id == 0) { - LOG(FATAL) << "invalid remote socket id (0)"; - } - asocket* s = new asocket(); - 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; - - D("RS(%d): created", s->id); - return s; -} - -void connect_to_remote(asocket* s, std::string_view destination) { - D("Connect_to_remote call RS(%d) fd=%d", s->id, s->fd); - apacket* p = get_apacket(); - - LOG(VERBOSE) << "LS(" << s->id << ": connect(" << destination << ")"; - p->msg.command = A_OPEN; - p->msg.arg0 = s->id; - - // adbd used to expect a null-terminated string. - // Keep doing so to maintain backward compatibility. - p->payload.resize(destination.size() + 1); - memcpy(p->payload.data(), destination.data(), destination.size()); - p->payload[destination.size()] = '\0'; - p->msg.data_length = p->payload.size(); - - CHECK_LE(p->msg.data_length, s->get_max_payload()); - - 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 = nullptr; - s->close = local_socket_close; - SendOkay(s->fd); - 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 = nullptr; - s->close = local_socket_close; - SendFail(s->fd, "closed"); - s->close(s); -} - -static unsigned unhex(const 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; -} - -#if ADB_HOST - -namespace internal { - -// Parses a host service string of the following format: -// * [tcp:|udp:][:]: -// * :: -// Where must be a base-10 number and may be any of {usb,product,model,device}. -bool parse_host_service(std::string_view* out_serial, std::string_view* out_command, - std::string_view full_service) { - if (full_service.empty()) { - return false; - } - - std::string_view serial; - std::string_view command = full_service; - // Remove |count| bytes from the beginning of command and add them to |serial|. - auto consume = [&full_service, &serial, &command](size_t count) { - CHECK_LE(count, command.size()); - if (!serial.empty()) { - CHECK_EQ(serial.data() + serial.size(), command.data()); - } - - serial = full_service.substr(0, serial.size() + count); - command.remove_prefix(count); - }; - - // Remove the trailing : from serial, and assign the values to the output parameters. - auto finish = [out_serial, out_command, &serial, &command] { - if (serial.empty() || command.empty()) { - return false; - } - - CHECK_EQ(':', serial.back()); - serial.remove_suffix(1); - - *out_serial = serial; - *out_command = command; - return true; - }; - - static constexpr std::string_view prefixes[] = { - "usb:", "product:", "model:", "device:", "localfilesystem:"}; - for (std::string_view prefix : prefixes) { - if (command.starts_with(prefix)) { - consume(prefix.size()); - - size_t offset = command.find_first_of(':'); - if (offset == std::string::npos) { - return false; - } - consume(offset + 1); - return finish(); - } - } - - // For fastboot compatibility, ignore protocol prefixes. - if (command.starts_with("tcp:") || command.starts_with("udp:")) { - consume(4); - if (command.empty()) { - return false; - } - } - if (command.starts_with("vsock:")) { - // vsock serials are vsock:cid:port, which have an extra colon compared to tcp. - size_t next_colon = command.find(':'); - if (next_colon == std::string::npos) { - return false; - } - consume(next_colon + 1); - } - - bool found_address = false; - if (command[0] == '[') { - // Read an IPv6 address. `adb connect` creates the serial number from the canonical - // network address so it will always have the [] delimiters. - size_t ipv6_end = command.find_first_of(']'); - if (ipv6_end != std::string::npos) { - consume(ipv6_end + 1); - if (command.empty()) { - // Nothing after the IPv6 address. - return false; - } else if (command[0] != ':') { - // Garbage after the IPv6 address. - return false; - } - consume(1); - found_address = true; - } - } - - if (!found_address) { - // Scan ahead to the next colon. - size_t offset = command.find_first_of(':'); - if (offset == std::string::npos) { - return false; - } - consume(offset + 1); - } - - // We're either at the beginning of a port, or the command itself. - // Look for a port in between colons. - size_t next_colon = command.find_first_of(':'); - if (next_colon == std::string::npos) { - // No colon, we must be at the command. - return finish(); - } - - bool port_valid = true; - if (command.size() <= next_colon) { - return false; - } - - std::string_view port = command.substr(0, next_colon); - for (auto digit : port) { - if (!isdigit(digit)) { - // Port isn't a number. - port_valid = false; - break; - } - } - - if (port_valid) { - consume(next_colon + 1); - } - return finish(); -} - -} // namespace internal - -#endif // ADB_HOST - -static int smart_socket_enqueue(asocket* s, apacket::payload_type data) { -#if ADB_HOST - std::string_view service; - std::string_view serial; - TransportId transport_id = 0; - TransportType type = kTransportAny; -#endif - - D("SS(%d): enqueue %zu", s->id, data.size()); - - if (s->smart_socket_data.empty()) { - // TODO: Make this an IOVector? - s->smart_socket_data.assign(data.begin(), data.end()); - } else { - std::copy(data.begin(), data.end(), std::back_inserter(s->smart_socket_data)); - } - - /* don't bother if we can't decode the length */ - if (s->smart_socket_data.size() < 4) { - return 0; - } - - uint32_t len = unhex(s->smart_socket_data.data(), 4); - if (len == 0 || len > MAX_PAYLOAD) { - D("SS(%d): bad size (%u)", s->id, len); - goto fail; - } - - D("SS(%d): len is %u", s->id, len); - /* can't do anything until we have the full header */ - if ((len + 4) > s->smart_socket_data.size()) { - D("SS(%d): waiting for %zu more bytes", s->id, len + 4 - s->smart_socket_data.size()); - return 0; - } - - s->smart_socket_data[len + 4] = 0; - - D("SS(%d): '%s'", s->id, (char*)(s->smart_socket_data.data() + 4)); - -#if ADB_HOST - service = std::string_view(s->smart_socket_data).substr(4); - - // TODO: These should be handled in handle_host_request. - if (android::base::ConsumePrefix(&service, "host-serial:")) { - // serial number should follow "host:" and could be a host:port string. - if (!internal::parse_host_service(&serial, &service, service)) { - LOG(ERROR) << "SS(" << s->id << "): failed to parse host service: " << service; - goto fail; - } - } else if (android::base::ConsumePrefix(&service, "host-transport-id:")) { - if (!ParseUint(&transport_id, service, &service)) { - LOG(ERROR) << "SS(" << s->id << "): failed to parse host transport id: " << service; - return -1; - } - if (!android::base::ConsumePrefix(&service, ":")) { - LOG(ERROR) << "SS(" << s->id << "): host-transport-id without command"; - return -1; - } - } else if (android::base::ConsumePrefix(&service, "host-usb:")) { - type = kTransportUsb; - } else if (android::base::ConsumePrefix(&service, "host-local:")) { - type = kTransportLocal; - } else if (android::base::ConsumePrefix(&service, "host:")) { - type = kTransportAny; - } else { - service = std::string_view{}; - } - - if (!service.empty()) { - 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. - auto host_request_result = handle_host_request( - service, type, serial.empty() ? nullptr : std::string(serial).c_str(), transport_id, - s->peer->fd, s); - - switch (host_request_result) { - case HostRequestResult::Handled: - LOG(VERBOSE) << "SS(" << s->id << "): handled host service '" << service << "'"; - goto fail; - - case HostRequestResult::SwitchedTransport: - D("SS(%d): okay transport", s->id); - s->smart_socket_data.clear(); - return 0; - - case HostRequestResult::Unhandled: - break; - } - - /* try to find a local service with this name. - ** if no such service exists, we'll fail out - ** and tear down here. - */ - // TODO: Convert to string_view. - s2 = host_service_to_socket(service, serial, transport_id); - if (s2 == nullptr) { - LOG(VERBOSE) << "SS(" << s->id << "): couldn't create host service '" << service << "'"; - SendFail(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. - */ - SendOkay(s->peer->fd); - - s->peer->ready = local_socket_ready; - s->peer->shutdown = nullptr; - s->peer->close = local_socket_close; - s->peer->peer = s2; - s2->peer = s->peer; - s->peer = nullptr; - D("SS(%d): okay", s->id); - s->close(s); - - /* initial state is "ready" */ - s2->ready(s2); - return 0; - } -#else /* !ADB_HOST */ - if (s->transport == nullptr) { - std::string error_msg = "unknown failure"; - s->transport = acquire_one_transport(kTransportAny, nullptr, 0, nullptr, &error_msg); - if (s->transport == nullptr) { - SendFail(s->peer->fd, error_msg); - goto fail; - } - } -#endif - - if (!s->transport) { - SendFail(s->peer->fd, "device offline (no transport)"); - goto fail; - } else if (!ConnectionStateIsOnline(s->transport->GetConnectionState())) { - /* if there's no remote we fail the connection - ** right here and terminate it - */ - SendFail(s->peer->fd, "device offline (transport offline)"); - 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 = nullptr; - s->peer->close = local_socket_close_notify; - s->peer->peer = nullptr; - /* give him our transport and upref it */ - s->peer->transport = s->transport; - - connect_to_remote(s->peer, std::string_view(s->smart_socket_data).substr(4)); - s->peer = nullptr; - 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", s->id); -} - -static void smart_socket_close(asocket* s) { - D("SS(%d): closed", s->id); - if (s->peer) { - s->peer->peer = nullptr; - s->peer->close(s->peer); - s->peer = nullptr; - } - delete s; -} - -static asocket* create_smart_socket(void) { - D("Creating smart socket"); - asocket* s = new asocket(); - s->enqueue = smart_socket_enqueue; - s->ready = smart_socket_ready; - s->shutdown = nullptr; - s->close = smart_socket_close; - - D("SS(%d)", s->id); - return s; -} - -void connect_to_smartsocket(asocket* s) { - D("Connecting to smart socket"); - asocket* ss = create_smart_socket(); - s->peer = ss; - ss->peer = s; - s->ready(s); -} - -size_t asocket::get_max_payload() const { - size_t max_payload = MAX_PAYLOAD; - if (transport) { - max_payload = std::min(max_payload, transport->get_max_payload()); - } - if (peer && peer->transport) { - max_payload = std::min(max_payload, peer->transport->get_max_payload()); - } - return max_payload; -} diff --git a/adb/sockets.dia b/adb/sockets.dia deleted file mode 100644 index c626f20f0aa3ba846658cd95bb60d1792128afc5..0000000000000000000000000000000000000000 Binary files a/adb/sockets.dia and /dev/null differ diff --git a/adb/sysdeps.h b/adb/sysdeps.h deleted file mode 100644 index 1eed0d20a27aae13466bff6fa1d2e1875f069c30..0000000000000000000000000000000000000000 --- a/adb/sysdeps.h +++ /dev/null @@ -1,719 +0,0 @@ -/* - * 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. - */ - -#pragma once - -/* this file contains system-dependent definitions used by ADB - * they're related to threads, sockets and file descriptors - */ - -#ifdef __CYGWIN__ -# undef _WIN32 -#endif - -#include - -#include -#include -#include - -// Include this before open/close/unlink are defined as macros below. -#include -#include -#include -#include -#include - -#include "adb_unique_fd.h" -#include "sysdeps/errno.h" -#include "sysdeps/network.h" -#include "sysdeps/stat.h" - -#if defined(__APPLE__) -static inline void* mempcpy(void* dst, const void* src, size_t n) { - return static_cast(memcpy(dst, src, n)) + n; -} -#endif - -#ifdef _WIN32 - -// Clang-only nullability specifiers -#define _Nonnull -#define _Nullable - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include // unique_ptr -#include - -#define OS_PATH_SEPARATORS "\\/" -#define OS_PATH_SEPARATOR '\\' -#define OS_PATH_SEPARATOR_STR "\\" -#define ENV_PATH_SEPARATOR_STR ";" - -static inline bool adb_is_separator(char c) { - return c == '\\' || c == '/'; -} - -extern int adb_thread_setname(const std::string& name); - -static inline void close_on_exec(borrowed_fd fd) { - /* nothing really */ -} - -extern int adb_unlink(const char* path); -#undef unlink -#define unlink ___xxx_unlink - -extern int adb_mkdir(const std::string& path, int mode); -#undef mkdir -#define mkdir ___xxx_mkdir - -extern int adb_rename(const char* oldpath, const char* newpath); - -// See the comments for the !defined(_WIN32) versions of adb_*(). -extern int adb_open(const char* path, int options); -extern int adb_creat(const char* path, int mode); -extern int adb_read(borrowed_fd fd, void* buf, int len); -extern int adb_pread(borrowed_fd fd, void* buf, int len, off64_t offset); -extern int adb_write(borrowed_fd fd, const void* buf, int len); -extern int adb_pwrite(borrowed_fd fd, const void* buf, int len, off64_t offset); -extern int64_t adb_lseek(borrowed_fd fd, int64_t pos, int where); -extern int adb_shutdown(borrowed_fd fd, int direction = SHUT_RDWR); -extern int adb_close(int fd); -extern int adb_register_socket(SOCKET s); -extern HANDLE adb_get_os_handle(borrowed_fd fd); - -extern int adb_gethostname(char* name, size_t len); -extern int adb_getlogin_r(char* buf, size_t bufsize); - -// See the comments for the !defined(_WIN32) version of unix_close(). -static inline int unix_close(int fd) { - return close(fd); -} -#undef close -#define close ____xxx_close - -// Like unix_read(), but may return EINTR. -extern int unix_read_interruptible(borrowed_fd fd, void* buf, size_t len); - -// See the comments for the !defined(_WIN32) version of unix_read(). -static inline int unix_read(borrowed_fd fd, void* buf, size_t len) { - return TEMP_FAILURE_RETRY(unix_read_interruptible(fd, buf, len)); -} - -#undef read -#define read ___xxx_read - -#undef pread -#define pread ___xxx_pread - -// See the comments for the !defined(_WIN32) version of unix_write(). -static inline int unix_write(borrowed_fd fd, const void* buf, size_t len) { - return write(fd.get(), buf, len); -} -#undef write -#define write ___xxx_write - -#undef pwrite -#define pwrite ___xxx_pwrite - -// See the comments for the !defined(_WIN32) version of unix_lseek(). -static inline int unix_lseek(borrowed_fd fd, int pos, int where) { - return lseek(fd.get(), pos, where); -} -#undef lseek -#define lseek ___xxx_lseek - -// See the comments for the !defined(_WIN32) version of adb_open_mode(). -static inline int adb_open_mode(const char* path, int options, int mode) { - return adb_open(path, options); -} - -// See the comments for the !defined(_WIN32) version of unix_open(). -extern int unix_open(std::string_view path, int options, ...); -#define open ___xxx_unix_open - -// Checks if |fd| corresponds to a console. -// Standard Windows isatty() returns 1 for both console FDs and character -// devices like NUL. unix_isatty() performs some extra checking to only match -// console FDs. -// |fd| must be a real file descriptor, meaning STDxx_FILENO or unix_open() FDs -// will work but adb_open() FDs will not. Additionally the OS handle associated -// with |fd| must have GENERIC_READ access (which console FDs have by default). -// Returns 1 if |fd| is a console FD, 0 otherwise. The value of errno after -// calling this function is unreliable and should not be used. -int unix_isatty(borrowed_fd fd); -#define isatty ___xxx_isatty - -int network_inaddr_any_server(int port, int type, std::string* error); - -inline int network_local_client(const char* name, int namespace_id, int type, std::string* error) { - abort(); -} - -inline int network_local_server(const char* name, int namespace_id, int type, std::string* error) { - abort(); -} - -int network_connect(const std::string& host, int port, int type, int timeout, - std::string* error); - -extern int adb_socket_accept(borrowed_fd serverfd, struct sockaddr* addr, socklen_t* addrlen); - -#undef accept -#define accept ___xxx_accept - -// Returns the local port number of a bound socket, or -1 on failure. -int adb_socket_get_local_port(borrowed_fd fd); - -extern int adb_setsockopt(borrowed_fd fd, int level, int optname, const void* optval, - socklen_t optlen); - -#undef setsockopt -#define setsockopt ___xxx_setsockopt - -extern int adb_socketpair(int sv[2]); - -struct adb_pollfd { - int fd; - short events; - short revents; -}; -extern int adb_poll(adb_pollfd* fds, size_t nfds, int timeout); -#define poll ___xxx_poll - -static inline int adb_is_absolute_host_path(const char* path) { - return isalpha(path[0]) && path[1] == ':' && path[2] == '\\'; -} - -// UTF-8 versions of POSIX APIs. -extern DIR* adb_opendir(const char* dirname); -extern struct dirent* adb_readdir(DIR* dir); -extern int adb_closedir(DIR* dir); - -extern int adb_utime(const char *, struct utimbuf *); -extern int adb_chmod(const char *, int); - -extern int adb_vfprintf(FILE* stream, const char* format, va_list ap) - __attribute__((__format__(__printf__, 2, 0))); -extern int adb_vprintf(const char* format, va_list ap) __attribute__((__format__(__printf__, 1, 0))); -extern int adb_fprintf(FILE* stream, const char* format, ...) - __attribute__((__format__(__printf__, 2, 3))); -extern int adb_printf(const char* format, ...) __attribute__((__format__(__printf__, 1, 2))); - -extern int adb_fputs(const char* buf, FILE* stream); -extern int adb_fputc(int ch, FILE* stream); -extern int adb_putchar(int ch); -extern int adb_puts(const char* buf); -extern size_t adb_fwrite(const void* ptr, size_t size, size_t nmemb, FILE* stream); - -extern FILE* adb_fopen(const char* f, const char* m); - -extern char* adb_getenv(const char* name); - -extern char* adb_getcwd(char* buf, int size); - -// Remap calls to POSIX APIs to our UTF-8 versions. -#define opendir adb_opendir -#define readdir adb_readdir -#define closedir adb_closedir -#define rewinddir rewinddir_utf8_not_yet_implemented -#define telldir telldir_utf8_not_yet_implemented -// Some compiler's C++ headers have members named seekdir, so we can't do the -// macro technique and instead cause a link error if seekdir is called. -inline void seekdir(DIR*, long) { - extern int seekdir_utf8_not_yet_implemented; - seekdir_utf8_not_yet_implemented = 1; -} - -#define utime adb_utime -#define chmod adb_chmod - -#define vfprintf adb_vfprintf -#define vprintf adb_vprintf -#define fprintf adb_fprintf -#define printf adb_printf -#define fputs adb_fputs -#define fputc adb_fputc -// putc may be a macro, so if so, undefine it, so that we can redefine it. -#undef putc -#define putc(c, s) adb_fputc(c, s) -#define putchar adb_putchar -#define puts adb_puts -#define fwrite adb_fwrite - -#define fopen adb_fopen -#define freopen freopen_utf8_not_yet_implemented - -#define getenv adb_getenv -#define putenv putenv_utf8_not_yet_implemented -#define setenv setenv_utf8_not_yet_implemented -#define unsetenv unsetenv_utf8_not_yet_implemented - -#define getcwd adb_getcwd - -// A very simple wrapper over a launched child process -class Process { - public: - constexpr explicit Process(HANDLE h = nullptr) : h_(h) {} - constexpr Process(Process&& other) : h_(std::exchange(other.h_, nullptr)) {} - ~Process() { close(); } - constexpr explicit operator bool() const { return h_ != nullptr; } - - void wait() { - if (*this) { - ::WaitForSingleObject(h_, INFINITE); - close(); - } - } - void kill() { - if (*this) { - ::TerminateProcess(h_, -1); - } - } - - private: - DISALLOW_COPY_AND_ASSIGN(Process); - - void close() { - if (*this) { - ::CloseHandle(h_); - h_ = nullptr; - } - } - - HANDLE h_; -}; - -Process adb_launch_process(std::string_view executable, std::vector args, - std::initializer_list fds_to_inherit = {}); - -// Helper class to convert UTF-16 argv from wmain() to UTF-8 args that can be -// passed to main(). -class NarrowArgs { -public: - NarrowArgs(int argc, wchar_t** argv); - ~NarrowArgs(); - - inline char** data() { - return narrow_args; - } - -private: - char** narrow_args; -}; - -// Windows HANDLE values only use 32-bits of the type, even on 64-bit machines, -// so they can fit in an int. To convert back, we just need to sign-extend. -// https://msdn.microsoft.com/en-us/library/windows/desktop/aa384203%28v=vs.85%29.aspx -// Note that this does not make a HANDLE value work with APIs like open(), nor -// does this make a value from open() passable to APIs taking a HANDLE. This -// just lets you take a HANDLE, pass it around as an int, and then use it again -// as a HANDLE. -inline int cast_handle_to_int(const HANDLE h) { - // truncate - return static_cast(reinterpret_cast(h)); -} - -inline HANDLE cast_int_to_handle(const int fd) { - // sign-extend - return reinterpret_cast(static_cast(fd)); -} - -// Deleter for unique_handle. Adapted from many sources, including: -// http://stackoverflow.com/questions/14841396/stdunique-ptr-deleters-and-the-win32-api -// https://visualstudiomagazine.com/articles/2013/09/01/get-a-handle-on-the-windows-api.aspx -class handle_deleter { -public: - typedef HANDLE pointer; - - void operator()(HANDLE h); -}; - -// Like std::unique_ptr, but for Windows HANDLE objects that should be -// CloseHandle()'d. Operator bool() only checks if the handle != nullptr, -// but does not check if the handle != INVALID_HANDLE_VALUE. -typedef std::unique_ptr unique_handle; - -namespace internal { - -size_t ParseCompleteUTF8(const char* first, const char* last, std::vector* remaining_bytes); - -} - -#else /* !_WIN32 a.k.a. Unix */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#define OS_PATH_SEPARATORS "/" -#define OS_PATH_SEPARATOR '/' -#define OS_PATH_SEPARATOR_STR "/" -#define ENV_PATH_SEPARATOR_STR ":" - -static inline bool adb_is_separator(char c) { - return c == '/'; -} - -static inline int get_fd_flags(borrowed_fd fd) { - return fcntl(fd.get(), F_GETFD); -} - -static inline void close_on_exec(borrowed_fd fd) { - int flags = get_fd_flags(fd); - if (flags >= 0 && (flags & FD_CLOEXEC) == 0) { - fcntl(fd.get(), F_SETFD, flags | FD_CLOEXEC); - } -} - -// Open a file and return a file descriptor that may be used with unix_read(), -// unix_write(), unix_close(), but not adb_read(), adb_write(), adb_close(). -// -// On Unix, this is based on open(), so the file descriptor is a real OS file -// descriptor, but the Windows implementation (in sysdeps_win32.cpp) returns a -// file descriptor that can only be used with C Runtime APIs (which are wrapped -// by unix_read(), unix_write(), unix_close()). Also, the C Runtime has -// configurable CR/LF translation which defaults to text mode, but is settable -// with _setmode(). -static inline int unix_open(std::string_view path, int options, ...) { - std::string zero_terminated(path.begin(), path.end()); - if ((options & O_CREAT) == 0) { - return TEMP_FAILURE_RETRY(open(zero_terminated.c_str(), options)); - } else { - int mode; - va_list args; - va_start(args, options); - mode = va_arg(args, int); - va_end(args); - return TEMP_FAILURE_RETRY(open(zero_terminated.c_str(), options, mode)); - } -} - -// Similar to the two-argument adb_open(), but takes a mode parameter for file -// creation. See adb_open() for more info. -static inline int adb_open_mode(const char* pathname, int options, int mode) { - return TEMP_FAILURE_RETRY(open(pathname, options, mode)); -} - -// Open a file and return a file descriptor that may be used with adb_read(), -// adb_write(), adb_close(), but not unix_read(), unix_write(), unix_close(). -// -// On Unix, this is based on open(), but the Windows implementation (in -// sysdeps_win32.cpp) uses Windows native file I/O and bypasses the C Runtime -// and its CR/LF translation. The returned file descriptor should be used with -// adb_read(), adb_write(), adb_close(), etc. -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(borrowed_fd fd, int direction = SHUT_RDWR) { - return shutdown(fd.get(), direction); -} - -#undef shutdown -#define shutdown ____xxx_shutdown - -// Closes a file descriptor that came from adb_open() or adb_open_mode(), but -// not designed to take a file descriptor from unix_open(). See the comments -// for adb_open() for more info. -inline int adb_close(int fd) { - return close(fd); -} -#undef close -#define close ____xxx_close - -// On Windows, ADB has an indirection layer for file descriptors. If we get a -// Win32 SOCKET object from an external library, we have to map it in to that -// indirection layer, which this does. -inline int adb_register_socket(int s) { - return s; -} - -static inline int adb_gethostname(char* name, size_t len) { - return gethostname(name, len); -} - -static inline int adb_getlogin_r(char* buf, size_t bufsize) { - return getlogin_r(buf, bufsize); -} - -static inline int adb_read(borrowed_fd fd, void* buf, size_t len) { - return TEMP_FAILURE_RETRY(read(fd.get(), buf, len)); -} - -static inline int adb_pread(borrowed_fd fd, void* buf, size_t len, off64_t offset) { -#if defined(__APPLE__) - return TEMP_FAILURE_RETRY(pread(fd.get(), buf, len, offset)); -#else - return TEMP_FAILURE_RETRY(pread64(fd.get(), buf, len, offset)); -#endif -} - -// Like unix_read(), but does not handle EINTR. -static inline int unix_read_interruptible(borrowed_fd fd, void* buf, size_t len) { - return read(fd.get(), buf, len); -} - -#undef read -#define read ___xxx_read -#undef pread -#define pread ___xxx_pread - -static inline int adb_write(borrowed_fd fd, const void* buf, size_t len) { - return TEMP_FAILURE_RETRY(write(fd.get(), buf, len)); -} - -static inline int adb_pwrite(int fd, const void* buf, size_t len, off64_t offset) { -#if defined(__APPLE__) - return TEMP_FAILURE_RETRY(pwrite(fd, buf, len, offset)); -#else - return TEMP_FAILURE_RETRY(pwrite64(fd, buf, len, offset)); -#endif -} - -#undef write -#define write ___xxx_write -#undef pwrite -#define pwrite ___xxx_pwrite - -static inline int64_t adb_lseek(borrowed_fd fd, int64_t pos, int where) { -#if defined(__APPLE__) - return lseek(fd.get(), pos, where); -#else - return lseek64(fd.get(), pos, where); -#endif -} -#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 unix_isatty(borrowed_fd fd) { - return isatty(fd.get()); -} -#define isatty ___xxx_isatty - -// Helper for network_* functions. -inline int _fd_set_error_str(int fd, std::string* error) { - if (fd == -1) { - *error = strerror(errno); - } - return fd; -} - -inline int network_inaddr_any_server(int port, int type, std::string* error) { - return _fd_set_error_str(socket_inaddr_any_server(port, type), error); -} - -inline int network_local_client(const char* name, int namespace_id, int type, std::string* error) { - return _fd_set_error_str(socket_local_client(name, namespace_id, type), error); -} - -inline int network_local_server(const char* name, int namespace_id, int type, std::string* error) { - return _fd_set_error_str(socket_local_server(name, namespace_id, type), error); -} - -int network_connect(const std::string& host, int port, int type, int timeout, std::string* error); - -static inline int adb_socket_accept(borrowed_fd serverfd, struct sockaddr* addr, - socklen_t* addrlen) { - int fd; - - fd = TEMP_FAILURE_RETRY(accept(serverfd.get(), addr, addrlen)); - if (fd >= 0) close_on_exec(fd); - - return fd; -} - -#undef accept -#define accept ___xxx_accept - -inline int adb_socket_get_local_port(borrowed_fd fd) { - return socket_get_local_port(fd.get()); -} - -// Operate on a file descriptor returned from unix_open() or a well-known file -// descriptor such as STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO. -// -// On Unix, unix_read(), unix_write(), unix_close() map to adb_read(), -// adb_write(), adb_close() (which all map to Unix system calls), but the -// Windows implementations (in the ifdef above and in sysdeps_win32.cpp) call -// into the C Runtime and its configurable CR/LF translation (which is settable -// via _setmode()). -#define unix_read adb_read -#define unix_write adb_write -#define unix_lseek adb_lseek -#define unix_close adb_close - -static inline int adb_thread_setname(const std::string& name) { -#ifdef __APPLE__ - return pthread_setname_np(name.c_str()); -#else - // Both bionic and glibc's pthread_setname_np fails rather than truncating long strings. - // glibc doesn't have strlcpy, so we have to fake it. - char buf[16]; // MAX_TASK_COMM_LEN, but that's not exported by the kernel headers. - strncpy(buf, name.c_str(), sizeof(buf) - 1); - buf[sizeof(buf) - 1] = '\0'; - return pthread_setname_np(pthread_self(), buf); -#endif -} - -static inline int adb_setsockopt(borrowed_fd fd, int level, int optname, const void* optval, - socklen_t optlen) { - return setsockopt(fd.get(), level, optname, optval, optlen); -} - -#undef setsockopt -#define setsockopt ___xxx_setsockopt - -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 - -typedef struct pollfd adb_pollfd; -static inline int adb_poll(adb_pollfd* fds, size_t nfds, int timeout) { - return TEMP_FAILURE_RETRY(poll(fds, nfds, timeout)); -} - -#define poll ___xxx_poll - -static inline int adb_mkdir(const std::string& path, int mode) { - return mkdir(path.c_str(), mode); -} - -#undef mkdir -#define mkdir ___xxx_mkdir - -static inline int adb_rename(const char* oldpath, const char* newpath) { - return rename(oldpath, newpath); -} - -static inline int adb_is_absolute_host_path(const char* path) { - return path[0] == '/'; -} - -static inline int adb_get_os_handle(borrowed_fd fd) { - return fd.get(); -} - -// A very simple wrapper over a launched child process -class Process { - public: - constexpr explicit Process(pid_t pid) : pid_(pid) {} - constexpr Process(Process&& other) : pid_(std::exchange(other.pid_, -1)) {} - - constexpr explicit operator bool() const { return pid_ >= 0; } - - void wait() { - if (*this) { - int status; - ::waitpid(pid_, &status, 0); - pid_ = -1; - } - } - void kill() { - if (*this) { - ::kill(pid_, SIGTERM); - } - } - - private: - DISALLOW_COPY_AND_ASSIGN(Process); - - pid_t pid_; -}; - -Process adb_launch_process(std::string_view executable, std::vector args, - std::initializer_list fds_to_inherit = {}); - -#endif /* !_WIN32 */ - -static inline void disable_tcp_nagle(borrowed_fd fd) { - int off = 1; - adb_setsockopt(fd.get(), IPPROTO_TCP, TCP_NODELAY, &off, sizeof(off)); -} - -// Sets TCP socket |fd| to send a keepalive TCP message every |interval_sec| seconds. Set -// |interval_sec| to 0 to disable keepalives. If keepalives are enabled, the connection will be -// configured to drop after 10 missed keepalives. Returns true on success. -bool set_tcp_keepalive(borrowed_fd fd, int interval_sec); - -#if defined(_WIN32) -// Win32 defines ERROR, which we don't need, but which conflicts with google3 logging. -#undef ERROR -#endif diff --git a/adb/sysdeps/chrono.h b/adb/sysdeps/chrono.h deleted file mode 100644 index 5c5af7cd6e6cfed8139652b75b08c9f3e3aed254..0000000000000000000000000000000000000000 --- a/adb/sysdeps/chrono.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2016 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. - */ - -#pragma once - -#include - -using namespace std::chrono_literals; diff --git a/adb/sysdeps/errno.cpp b/adb/sysdeps/errno.cpp deleted file mode 100644 index 9a37ea2fdad8d6e1313cf3d5f4f08b9356ada66e..0000000000000000000000000000000000000000 --- a/adb/sysdeps/errno.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2016 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/errno.h" - -#include - -#include -#include -#include - -#include "adb.h" - -// Use the linux asm-generic values for errno (which are used on all android archs but mips). -#define ERRNO_VALUES() \ - ERRNO_VALUE(EACCES, 13); \ - ERRNO_VALUE(EEXIST, 17); \ - ERRNO_VALUE(EFAULT, 14); \ - ERRNO_VALUE(EFBIG, 27); \ - ERRNO_VALUE(EINTR, 4); \ - ERRNO_VALUE(EINVAL, 22); \ - ERRNO_VALUE(EIO, 5); \ - ERRNO_VALUE(EISDIR, 21); \ - ERRNO_VALUE(ELOOP, 40); \ - ERRNO_VALUE(EMFILE, 24); \ - ERRNO_VALUE(ENAMETOOLONG, 36); \ - ERRNO_VALUE(ENFILE, 23); \ - ERRNO_VALUE(ENOENT, 2); \ - ERRNO_VALUE(ENOMEM, 12); \ - ERRNO_VALUE(ENOSPC, 28); \ - ERRNO_VALUE(ENOTDIR, 20); \ - ERRNO_VALUE(EOVERFLOW, 75); \ - ERRNO_VALUE(EPERM, 1); \ - ERRNO_VALUE(EROFS, 30); \ - ERRNO_VALUE(ETXTBSY, 26) - -// Make sure these values are actually correct. -#if defined(__linux__) && !defined(__mips__) -#define ERRNO_VALUE(error_name, wire_value) static_assert((error_name) == (wire_value), "") -ERRNO_VALUES(); -#undef ERRNO_VALUE -#endif - -static std::unordered_map* generate_host_to_wire() { - auto result = new std::unordered_map(); -#define ERRNO_VALUE(error_name, wire_value) \ - result->insert(std::make_pair((error_name), (wire_value))) - ERRNO_VALUES(); -#undef ERRNO_VALUE - return result; -} - -static std::unordered_map* generate_wire_to_host() { - auto result = new std::unordered_map(); -#define ERRNO_VALUE(error_name, wire_value) \ - result->insert(std::make_pair((wire_value), (error_name))) - ERRNO_VALUES(); -#undef ERRNO_VALUE - return result; -} - -static std::unordered_map& host_to_wire = *generate_host_to_wire(); -static std::unordered_map& wire_to_host = *generate_wire_to_host(); - -int errno_to_wire(int error) { - auto it = host_to_wire.find(error); - if (it == host_to_wire.end()) { - LOG(ERROR) << "failed to convert errno " << error << " (" << strerror(error) << ") to wire"; - - // Return EIO; - return 5; - } - return it->second; -} - -int errno_from_wire(int error) { - auto it = host_to_wire.find(error); - if (it == host_to_wire.end()) { - LOG(ERROR) << "failed to convert errno " << error << " from wire"; - return EIO; - } - return it->second; -} diff --git a/adb/sysdeps/errno.h b/adb/sysdeps/errno.h deleted file mode 100644 index 72816b127f89ec25dafae30ec252e140e5f68f0a..0000000000000000000000000000000000000000 --- a/adb/sysdeps/errno.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2016 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. - */ - -#pragma once - -#include -#include - -#if defined(_WIN32) -char* adb_strerror(int err); -#define strerror adb_strerror -#endif - -// errno values differ between operating systems and between Linux architectures. -// Arbitrarily select the Linux asm-generic values to use in the wire protocol. -int errno_to_wire(int error); -int errno_from_wire(int error); diff --git a/adb/sysdeps/network.h b/adb/sysdeps/network.h deleted file mode 100644 index fadd15598b41c003427fd601547e408abd1df1a6..0000000000000000000000000000000000000000 --- a/adb/sysdeps/network.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -/* - * Copyright (C) 2017 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 - -int network_loopback_client(int port, int type, std::string* error); -int network_loopback_server(int port, int type, std::string* error, bool prefer_ipv4); diff --git a/adb/sysdeps/posix/network.cpp b/adb/sysdeps/posix/network.cpp deleted file mode 100644 index a4d9013d315adfa18ea92dbb67d5972e8721bc18..0000000000000000000000000000000000000000 --- a/adb/sysdeps/posix/network.cpp +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (C) 2017 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/network.h" - -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include "adb_unique_fd.h" - -static void set_error(std::string* error) { - if (error) { - *error = strerror(errno); - } -} - -static sockaddr* loopback_addr4(sockaddr_storage* addr, socklen_t* addrlen, int port) { - struct sockaddr_in* addr4 = reinterpret_cast(addr); - *addrlen = sizeof(*addr4); - - addr4->sin_family = AF_INET; - addr4->sin_addr.s_addr = htonl(INADDR_LOOPBACK); - addr4->sin_port = htons(port); - return reinterpret_cast(addr); -} - -static sockaddr* loopback_addr6(sockaddr_storage* addr, socklen_t* addrlen, int port) { - struct sockaddr_in6* addr6 = reinterpret_cast(addr); - *addrlen = sizeof(*addr6); - - addr6->sin6_family = AF_INET6; - addr6->sin6_addr = in6addr_loopback; - addr6->sin6_port = htons(port); - return reinterpret_cast(addr); -} - -static int _network_loopback_client(bool ipv6, int port, int type, std::string* error) { - unique_fd s(socket(ipv6 ? AF_INET6 : AF_INET, type, 0)); - if (s == -1) { - set_error(error); - return -1; - } - - struct sockaddr_storage addr_storage = {}; - socklen_t addrlen = sizeof(addr_storage); - sockaddr* addr = (ipv6 ? loopback_addr6 : loopback_addr4)(&addr_storage, &addrlen, 0); - - if (bind(s.get(), addr, addrlen) != 0) { - set_error(error); - return -1; - } - - addr = (ipv6 ? loopback_addr6 : loopback_addr4)(&addr_storage, &addrlen, port); - - if (connect(s.get(), addr, addrlen) != 0) { - set_error(error); - return -1; - } - - return s.release(); -} - -int network_loopback_client(int port, int type, std::string* error) { - // Try IPv4 first, use IPv6 as a fallback. - int rc = _network_loopback_client(false, port, type, error); - if (rc == -1) { - return _network_loopback_client(true, port, type, error); - } - return rc; -} - -static int _network_loopback_server(bool ipv6, int port, int type, std::string* error) { - unique_fd s(socket(ipv6 ? AF_INET6 : AF_INET, type, 0)); - if (s == -1) { - set_error(error); - return -1; - } - - int n = 1; - setsockopt(s.get(), SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)); - - struct sockaddr_storage addr_storage = {}; - socklen_t addrlen = sizeof(addr_storage); - sockaddr* addr = (ipv6 ? loopback_addr6 : loopback_addr4)(&addr_storage, &addrlen, port); - - if (bind(s.get(), addr, addrlen) != 0) { - set_error(error); - return -1; - } - - if (type == SOCK_STREAM || type == SOCK_SEQPACKET) { - if (listen(s.get(), SOMAXCONN) != 0) { - set_error(error); - return -1; - } - } - - return s.release(); -} - -int network_loopback_server(int port, int type, std::string* error, bool prefer_ipv4) { - int rc = -1; - if (prefer_ipv4) { - rc = _network_loopback_server(false, port, type, error); - } - - // Only attempt to listen on IPv6 if IPv4 is unavailable or prefer_ipv4 is false - // We don't want to start an IPv6 server if there's already an IPv4 one running. - if (rc == -1 && (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT || !prefer_ipv4)) { - return _network_loopback_server(true, port, type, error); - } - return rc; -} - -int network_connect(const std::string& host, int port, int type, int timeout, std::string* error) { - int getaddrinfo_error = 0; - int fd = socket_network_client_timeout(host.c_str(), port, type, timeout, &getaddrinfo_error); - if (fd != -1) { - return fd; - } - if (getaddrinfo_error != 0) { - *error = android::base::StringPrintf("failed to resolve host: '%s': %s", host.c_str(), - gai_strerror(getaddrinfo_error)); - LOG(WARNING) << *error; - } else { - *error = android::base::StringPrintf("failed to connect to '%s:%d': %s", host.c_str(), port, - strerror(errno)); - LOG(WARNING) << *error; - } - return -1; -} diff --git a/adb/sysdeps/stat.h b/adb/sysdeps/stat.h deleted file mode 100644 index ed2cf25fb04f404f94ca01ed91bef709a0864594..0000000000000000000000000000000000000000 --- a/adb/sysdeps/stat.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2016 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. - */ - -#pragma once - -#include -#include -#include - -#if defined(_WIN32) -// stat is broken on Win32: stat on a path with a trailing slash or backslash will always fail with -// ENOENT. -int adb_stat(const char* path, struct adb_stat* buf); - -// We later define a macro mapping 'stat' to 'adb_stat'. This causes: -// struct stat s; -// stat(filename, &s); -// To turn into the following: -// struct adb_stat s; -// adb_stat(filename, &s); -// To get this to work, we need to make 'struct adb_stat' the same as -// 'struct stat'. Note that this definition of 'struct adb_stat' uses the -// *current* macro definition of stat, so it may actually be inheriting from -// struct _stat32i64 (or some other remapping). -struct adb_stat : public stat {}; - -#undef stat -#define stat adb_stat - -// Windows doesn't have lstat. -#define lstat adb_stat - -// mingw doesn't define S_IFLNK or S_ISLNK. -#define S_IFLNK 0120000 -#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) - -// mingw defines S_IFBLK to a different value from bionic. -#undef S_IFBLK -#define S_IFBLK 0060000 -#undef S_ISBLK -#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK) -#endif - -// Make sure that host file mode values match the ones on the device. -static_assert(S_IFMT == 00170000, ""); -static_assert(S_IFLNK == 0120000, ""); -static_assert(S_IFREG == 0100000, ""); -static_assert(S_IFBLK == 0060000, ""); -static_assert(S_IFDIR == 0040000, ""); -static_assert(S_IFCHR == 0020000, ""); diff --git a/adb/sysdeps/stat_test.cpp b/adb/sysdeps/stat_test.cpp deleted file mode 100644 index 67155d992464eefc0f8c4d1221e554897cc8d161..0000000000000000000000000000000000000000 --- a/adb/sysdeps/stat_test.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2015 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 "adb_utils.h" -#include "sysdeps.h" - -TEST(sysdeps, stat) { - TemporaryDir td; - TemporaryFile tf; - - struct stat st; - ASSERT_EQ(0, stat(td.path, &st)); - ASSERT_FALSE(S_ISREG(st.st_mode)); - ASSERT_TRUE(S_ISDIR(st.st_mode)); - - ASSERT_EQ(0, stat((std::string(td.path) + '/').c_str(), &st)); - ASSERT_TRUE(S_ISDIR(st.st_mode)); - -#if defined(_WIN32) - ASSERT_EQ(0, stat((std::string(td.path) + '\\').c_str(), &st)); - ASSERT_TRUE(S_ISDIR(st.st_mode)); -#endif - - std::string nonexistent_path = std::string(td.path) + "/nonexistent"; - ASSERT_EQ(-1, stat(nonexistent_path.c_str(), &st)); - ASSERT_EQ(ENOENT, errno); - - ASSERT_EQ(-1, stat((nonexistent_path + "/").c_str(), &st)); - ASSERT_EQ(ENOENT, errno); - -#if defined(_WIN32) - ASSERT_EQ(-1, stat((nonexistent_path + "\\").c_str(), &st)); - ASSERT_EQ(ENOENT, errno); -#endif - - ASSERT_EQ(0, stat(tf.path, &st)); - ASSERT_TRUE(S_ISREG(st.st_mode)); - ASSERT_FALSE(S_ISDIR(st.st_mode)); - - ASSERT_EQ(-1, stat((std::string(tf.path) + '/').c_str(), &st)); - ASSERT_EQ(ENOTDIR, errno); - -#if defined(_WIN32) - ASSERT_EQ(-1, stat((std::string(tf.path) + '\\').c_str(), &st)); - ASSERT_EQ(ENOTDIR, errno); -#endif -} diff --git a/adb/sysdeps/uio.h b/adb/sysdeps/uio.h deleted file mode 100644 index ced884ba5cb7f20f8f9315f5c9d794ff229fd79a..0000000000000000000000000000000000000000 --- a/adb/sysdeps/uio.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2018 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. - */ - -#pragma once - -#include - -#include "adb_unique_fd.h" - -#if defined(_WIN32) - -// Layout of this struct must match struct WSABUF (verified via static assert in sysdeps_win32.cpp) -struct adb_iovec { - size_t iov_len; - void* iov_base; -}; - -ssize_t adb_writev(borrowed_fd fd, const adb_iovec* iov, int iovcnt); - -#else - -#include -using adb_iovec = struct iovec; -inline ssize_t adb_writev(borrowed_fd fd, const adb_iovec* iov, int iovcnt) { - return writev(fd.get(), iov, iovcnt); -} - -#endif - -#pragma GCC poison writev diff --git a/adb/sysdeps/vm_sockets.h b/adb/sysdeps/vm_sockets.h deleted file mode 100644 index 75c5f44af4a6cda3fb187821ae4e3d1a4f3f3235..0000000000000000000000000000000000000000 --- a/adb/sysdeps/vm_sockets.h +++ /dev/null @@ -1,49 +0,0 @@ -#if __BIONIC__ -#include -#else -/**************************************************************************** - **************************************************************************** - *** - *** This header was automatically generated from a Linux kernel header - *** of the same name, to make information necessary for userspace to - *** call into the kernel available to libc. It contains only constants, - *** structures, and macros generated from the original header, and thus, - *** contains no copyrightable information. - *** - *** Copied and modified from bionic/libc/kernel/uapi/linux/vm_sockets.h - *** - **************************************************************************** - ****************************************************************************/ -#ifndef _UAPI_VM_SOCKETS_H -#define _UAPI_VM_SOCKETS_H -#include -#define SO_VM_SOCKETS_BUFFER_SIZE 0 -#define SO_VM_SOCKETS_BUFFER_MIN_SIZE 1 -#define SO_VM_SOCKETS_BUFFER_MAX_SIZE 2 -#define SO_VM_SOCKETS_PEER_HOST_VM_ID 3 -#define SO_VM_SOCKETS_TRUSTED 5 -#define SO_VM_SOCKETS_CONNECT_TIMEOUT 6 -#define SO_VM_SOCKETS_NONBLOCK_TXRX 7 -#define VMADDR_CID_ANY -1U -#define VMADDR_PORT_ANY -1U -#define VMADDR_CID_HYPERVISOR 0 -#define VMADDR_CID_RESERVED 1 -#define VMADDR_CID_HOST 2 -#define VM_SOCKETS_INVALID_VERSION -1U -#define VM_SOCKETS_VERSION_EPOCH(_v) (((_v)&0xFF000000) >> 24) -#define VM_SOCKETS_VERSION_MAJOR(_v) (((_v)&0x00FF0000) >> 16) -#define VM_SOCKETS_VERSION_MINOR(_v) (((_v)&0x0000FFFF)) -struct sockaddr_vm { - __kernel_sa_family_t svm_family; - unsigned short svm_reserved1; - unsigned int svm_port; - unsigned int svm_cid; - unsigned char svm_zero[sizeof(struct sockaddr) - sizeof(sa_family_t) - sizeof(unsigned short) - - sizeof(unsigned int) - sizeof(unsigned int)]; -}; -#define IOCTL_VM_SOCKETS_GET_LOCAL_CID _IO(7, 0xb9) -#ifndef AF_VSOCK -#define AF_VSOCK 40 -#endif -#endif -#endif diff --git a/adb/sysdeps/win32/errno.cpp b/adb/sysdeps/win32/errno.cpp deleted file mode 100644 index a3b9d9b9732437a15771aec041a379f9af97d7d2..0000000000000000000000000000000000000000 --- a/adb/sysdeps/win32/errno.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2016 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/errno.h" - -#include - -#include - -// Overrides strerror() to handle error codes not supported by the Windows C -// Runtime (MSVCRT.DLL). -char* adb_strerror(int err) { -// sysdeps.h defines strerror to adb_strerror, but in this function, we -// want to call the real C Runtime strerror(). -#pragma push_macro("strerror") -#undef strerror - const int saved_err = errno; // Save because we overwrite it later. - - // Lookup the string for an unknown error. - char* errmsg = strerror(-1); - const std::string unknown_error = (errmsg == nullptr) ? "" : errmsg; - - // Lookup the string for this error to see if the C Runtime has it. - errmsg = strerror(err); - if (errmsg != nullptr && unknown_error != errmsg) { - // The CRT returned an error message and it is different than the error - // message for an unknown error, so it is probably valid, so use it. - } else { - // Check if we have a string for this error code. - const char* custom_msg = nullptr; - switch (err) { -#pragma push_macro("ERR") -#undef ERR -#define ERR(errnum, desc) case errnum: custom_msg = desc; break - // These error strings are from AOSP bionic/libc/include/sys/_errdefs.h. - // Note that these cannot be longer than 94 characters because we - // pass this to _strerror() which has that requirement. - ERR(ECONNRESET, "Connection reset by peer"); - ERR(EHOSTUNREACH, "No route to host"); - ERR(ENETDOWN, "Network is down"); - ERR(ENETRESET, "Network dropped connection because of reset"); - ERR(ENOBUFS, "No buffer space available"); - ERR(ENOPROTOOPT, "Protocol not available"); - ERR(ENOTCONN, "Transport endpoint is not connected"); - ERR(ENOTSOCK, "Socket operation on non-socket"); - ERR(EOPNOTSUPP, "Operation not supported on transport endpoint"); -#pragma pop_macro("ERR") - } - - if (custom_msg != nullptr) { - // Use _strerror() to write our string into the writable per-thread - // buffer used by strerror()/_strerror(). _strerror() appends the - // msg for the current value of errno, so set errno to a consistent - // value for every call so that our code-path is always the same. - errno = 0; - errmsg = _strerror(custom_msg); - const size_t custom_msg_len = strlen(custom_msg); - // Just in case _strerror() returned a read-only string, check if - // the returned string starts with our custom message because that - // implies that the string is not read-only. - if ((errmsg != nullptr) && !strncmp(custom_msg, errmsg, custom_msg_len)) { - // _strerror() puts other text after our custom message, so - // remove that by terminating after our message. - errmsg[custom_msg_len] = '\0'; - } else { - // For some reason nullptr was returned or a pointer to a - // read-only string was returned, so fallback to whatever - // strerror() can muster (probably "Unknown error" or some - // generic CRT error string). - errmsg = strerror(err); - } - } else { - // We don't have a custom message, so use whatever strerror(err) - // returned earlier. - } - } - - errno = saved_err; // restore - - return errmsg; -#pragma pop_macro("strerror") -} diff --git a/adb/sysdeps/win32/errno_test.cpp b/adb/sysdeps/win32/errno_test.cpp deleted file mode 100644 index 09ec52c861fe62806796b131df82381fa3a40c4f..0000000000000000000000000000000000000000 --- a/adb/sysdeps/win32/errno_test.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2016 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/errno.h" - -#include - -#include - -void TestAdbStrError(int err, const char* expected) { - errno = 12345; - const char* result = adb_strerror(err); - // Check that errno is not overwritten. - EXPECT_EQ(12345, errno); - EXPECT_STREQ(expected, result); -} - -TEST(sysdeps_win32, adb_strerror) { - // Test an error code that should not have a mapped string. Use an error - // code that is not used by the internal implementation of adb_strerror(). - TestAdbStrError(-2, "Unknown error"); - // adb_strerror() uses -1 internally, so test that it can still be passed - // as a parameter. - TestAdbStrError(-1, "Unknown error"); - // Test very big, positive unknown error. - TestAdbStrError(1000000, "Unknown error"); - - // Test success case. - // Wine returns "Success" for strerror(0), Windows returns "No error", so accept both. - std::string success = adb_strerror(0); - EXPECT_TRUE(success == "Success" || success == "No error") << "strerror(0) = " << success; - - // Test error that regular strerror() should have a string for. - TestAdbStrError(EPERM, "Operation not permitted"); - // Test error that regular strerror() doesn't have a string for, but that - // adb_strerror() returns. - TestAdbStrError(ECONNRESET, "Connection reset by peer"); -} diff --git a/adb/sysdeps/win32/stat.cpp b/adb/sysdeps/win32/stat.cpp deleted file mode 100644 index 844c1ce9ae7893e36560fa9c26b5ba36d7dd7c22..0000000000000000000000000000000000000000 --- a/adb/sysdeps/win32/stat.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2016 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/stat.h" - -#include -#include -#include -#include - -#include - -#include - -// Version of stat() that takes a UTF-8 path. -int adb_stat(const char* path, struct adb_stat* s) { -// This definition of wstat seems to be missing from . -#if defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS == 64) -#ifdef _USE_32BIT_TIME_T -#define wstat _wstat32i64 -#else -#define wstat _wstat64 -#endif -#else -// has a function prototype for wstat() that should be available. -#endif - - std::wstring path_wide; - if (!android::base::UTF8ToWide(path, &path_wide)) { - errno = ENOENT; - return -1; - } - - // If the path has a trailing slash, stat will fail with ENOENT regardless of whether the path - // is a directory or not. - bool expected_directory = false; - while (*path_wide.rbegin() == u'/' || *path_wide.rbegin() == u'\\') { - path_wide.pop_back(); - expected_directory = true; - } - - struct adb_stat st; - int result = wstat(path_wide.c_str(), &st); - if (result == 0 && expected_directory) { - if (!S_ISDIR(st.st_mode)) { - errno = ENOTDIR; - return -1; - } - } - - memcpy(s, &st, sizeof(st)); - return result; -} diff --git a/adb/sysdeps_test.cpp b/adb/sysdeps_test.cpp deleted file mode 100644 index 0f4b39c1f684707ce2193d9b1a9372076e509ae4..0000000000000000000000000000000000000000 --- a/adb/sysdeps_test.cpp +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright (C) 2016 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 "adb_io.h" -#include "sysdeps.h" -#include "sysdeps/chrono.h" - -#if defined(_WIN32) -#include -static bool IsWine() { - HMODULE ntdll = GetModuleHandleW(L"ntdll.dll"); - if (!ntdll) { - return false; - } - return GetProcAddress(ntdll, "wine_get_version") != nullptr; -} -#else -static bool IsWine() { - return false; -} -#endif - -TEST(sysdeps_socketpair, smoke) { - int fds[2]; - ASSERT_EQ(0, adb_socketpair(fds)) << strerror(errno); - ASSERT_TRUE(WriteFdExactly(fds[0], "foo", 4)); - ASSERT_TRUE(WriteFdExactly(fds[1], "bar", 4)); - - char buf[4]; - ASSERT_TRUE(ReadFdExactly(fds[1], buf, 4)); - ASSERT_STREQ(buf, "foo"); - ASSERT_TRUE(ReadFdExactly(fds[0], buf, 4)); - ASSERT_STREQ(buf, "bar"); - ASSERT_EQ(0, adb_close(fds[0])); - ASSERT_EQ(0, adb_close(fds[1])); -} - -TEST(sysdeps_fd, exhaustion) { - std::vector fds; - int socketpair[2]; - - while (adb_socketpair(socketpair) == 0) { - fds.push_back(socketpair[0]); - fds.push_back(socketpair[1]); - } - - ASSERT_EQ(EMFILE, errno) << strerror(errno); - for (int fd : fds) { - ASSERT_EQ(0, adb_close(fd)); - } - ASSERT_EQ(0, adb_socketpair(socketpair)); - ASSERT_EQ(socketpair[0], fds[0]); - ASSERT_EQ(socketpair[1], fds[1]); - ASSERT_EQ(0, adb_close(socketpair[0])); - ASSERT_EQ(0, adb_close(socketpair[1])); -} - -class sysdeps_poll : public ::testing::Test { - protected: - int fds[2]; - void SetUp() override { - ASSERT_EQ(0, adb_socketpair(fds)) << strerror(errno); - } - - void TearDown() override { - if (fds[0] >= 0) { - ASSERT_EQ(0, adb_close(fds[0])); - } - if (fds[1] >= 0) { - ASSERT_EQ(0, adb_close(fds[1])); - } - } -}; - -TEST_F(sysdeps_poll, smoke) { - adb_pollfd pfd[2] = {}; - pfd[0].fd = fds[0]; - pfd[0].events = POLLRDNORM; - pfd[1].fd = fds[1]; - pfd[1].events = POLLWRNORM; - - pfd[0].revents = -1; - pfd[1].revents = -1; - EXPECT_EQ(1, adb_poll(pfd, 2, 0)); - EXPECT_EQ(0, pfd[0].revents); - EXPECT_EQ(POLLWRNORM, pfd[1].revents); - - ASSERT_TRUE(WriteFdExactly(fds[1], "foo", 4)); - - // Wait for the socketpair to be flushed. - pfd[0].revents = -1; - EXPECT_EQ(1, adb_poll(pfd, 1, 100)); - EXPECT_EQ(POLLRDNORM, pfd[0].revents); - pfd[0].revents = -1; - pfd[1].revents = -1; - EXPECT_EQ(2, adb_poll(pfd, 2, 0)); - EXPECT_EQ(POLLRDNORM, pfd[0].revents); - EXPECT_EQ(POLLWRNORM, pfd[1].revents); -} - -TEST_F(sysdeps_poll, timeout) { - adb_pollfd pfd = {}; - pfd.fd = fds[0]; - pfd.events = POLLRDNORM; - - EXPECT_EQ(0, adb_poll(&pfd, 1, 100)); - EXPECT_EQ(0, pfd.revents); - - ASSERT_TRUE(WriteFdExactly(fds[1], "foo", 4)); - - EXPECT_EQ(1, adb_poll(&pfd, 1, 100)); - EXPECT_EQ(POLLRDNORM, pfd.revents); -} - -TEST_F(sysdeps_poll, invalid_fd) { - adb_pollfd pfd[3] = {}; - pfd[0].fd = fds[0]; - pfd[0].events = POLLRDNORM; - pfd[0].revents = ~0; - pfd[1].fd = INT_MAX; - pfd[1].events = POLLRDNORM; - pfd[1].revents = ~0; - pfd[2].fd = fds[1]; - pfd[2].events = POLLWRNORM; - pfd[2].revents = ~0; - - ASSERT_TRUE(WriteFdExactly(fds[1], "foo", 4)); - - // Wait for the socketpair to be flushed. - EXPECT_EQ(1, adb_poll(pfd, 1, 100)); - EXPECT_EQ(POLLRDNORM, pfd[0].revents); - - EXPECT_EQ(3, adb_poll(pfd, 3, 0)); - EXPECT_EQ(POLLRDNORM, pfd[0].revents); - EXPECT_EQ(POLLNVAL, pfd[1].revents); - EXPECT_EQ(POLLWRNORM, pfd[2].revents); - - // Make sure that we return immediately if an invalid FD is given. - pfd[0].fd = fds[0]; - pfd[0].events = POLLRDNORM; - pfd[0].revents = ~0; - pfd[1].fd = INT_MAX; - pfd[1].events = POLLRDNORM; - pfd[1].revents = ~0; - EXPECT_EQ(2, adb_poll(pfd, 2, -1)); - EXPECT_EQ(POLLRDNORM, pfd[0].revents); - EXPECT_EQ(POLLNVAL, pfd[1].revents); -} - -TEST_F(sysdeps_poll, duplicate_fd) { - adb_pollfd pfd[2] = {}; - pfd[0].fd = fds[0]; - pfd[0].events = POLLRDNORM; - pfd[1] = pfd[0]; - - EXPECT_EQ(0, adb_poll(pfd, 2, 0)); - EXPECT_EQ(0, pfd[0].revents); - EXPECT_EQ(0, pfd[1].revents); - - ASSERT_TRUE(WriteFdExactly(fds[1], "foo", 4)); - - EXPECT_EQ(2, adb_poll(pfd, 2, 100)); - EXPECT_EQ(POLLRDNORM, pfd[0].revents); - EXPECT_EQ(POLLRDNORM, pfd[1].revents); -} - -TEST_F(sysdeps_poll, disconnect) { - adb_pollfd pfd = {}; - pfd.fd = fds[0]; - pfd.events = POLLIN; - - EXPECT_EQ(0, adb_poll(&pfd, 1, 0)); - EXPECT_EQ(0, pfd.revents); - - EXPECT_EQ(0, adb_close(fds[1])); - fds[1] = -1; - - EXPECT_EQ(1, adb_poll(&pfd, 1, 100)); - - if (!IsWine()) { - // Linux returns POLLIN | POLLHUP, Windows returns just POLLHUP. - EXPECT_EQ(POLLHUP, pfd.revents & POLLHUP); - } -} - -TEST_F(sysdeps_poll, fd_count) { - // https://code.google.com/p/android/issues/detail?id=12141 - static constexpr int num_sockets = 256; - std::vector sockets; - std::vector pfds; - sockets.resize(num_sockets * 2); - for (int32_t i = 0; i < num_sockets; ++i) { - ASSERT_EQ(0, adb_socketpair(&sockets[i * 2])) << strerror(errno); - ASSERT_TRUE(WriteFdExactly(sockets[i * 2], &i, sizeof(i))); - adb_pollfd pfd; - pfd.events = POLLIN; - pfd.fd = sockets[i * 2 + 1]; - pfds.push_back(pfd); - } - - ASSERT_EQ(num_sockets, adb_poll(pfds.data(), pfds.size(), 0)); - for (int i = 0; i < num_sockets; ++i) { - ASSERT_NE(0, pfds[i].revents & POLLIN); - - int32_t buf[2] = { -1, -1 }; - ASSERT_EQ(adb_read(pfds[i].fd, buf, sizeof(buf)), static_cast(sizeof(int32_t))); - ASSERT_EQ(i, buf[0]); - } - - for (int fd : sockets) { - adb_close(fd); - } -} - -TEST(sysdeps_condition_variable, smoke) { - static std::mutex &m = *new std::mutex; - static std::condition_variable &cond = *new std::condition_variable; - static volatile bool flag = false; - - std::unique_lock lock(m); - std::thread thread([]() { - m.lock(); - flag = true; - cond.notify_one(); - m.unlock(); - }); - - while (!flag) { - cond.wait(lock); - } - - thread.join(); -} diff --git a/adb/sysdeps_unix.cpp b/adb/sysdeps_unix.cpp deleted file mode 100644 index e56570676c3eabb4b414a331def697d31f76844d..0000000000000000000000000000000000000000 --- a/adb/sysdeps_unix.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2016 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" - -bool set_tcp_keepalive(borrowed_fd fd, int interval_sec) { - int enable = (interval_sec > 0); - if (adb_setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable))) { - return false; - } - - if (!enable) { - return true; - } - - // Idle time before sending the first keepalive is TCP_KEEPIDLE on Linux, TCP_KEEPALIVE on Mac. -#if defined(TCP_KEEPIDLE) - if (adb_setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &interval_sec, sizeof(interval_sec))) { - return false; - } -#elif defined(TCP_KEEPALIVE) - if (adb_setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &interval_sec, sizeof(interval_sec))) { - return false; - } -#endif - - // TCP_KEEPINTVL and TCP_KEEPCNT are available on Linux 2.4+ and OS X 10.8+ (Mountain Lion). -#if defined(TCP_KEEPINTVL) - if (adb_setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &interval_sec, sizeof(interval_sec))) { - return false; - } -#endif - -#if defined(TCP_KEEPCNT) - // On Windows this value is hardcoded to 10. This is a reasonable value, so we do the same here - // to match behavior. See SO_KEEPALIVE documentation at - // https://msdn.microsoft.com/en-us/library/windows/desktop/ee470551(v=vs.85).aspx. - const int keepcnt = 10; - if (adb_setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &keepcnt, sizeof(keepcnt))) { - return false; - } -#endif - - return true; -} - -static __inline__ void disable_close_on_exec(borrowed_fd fd) { - const auto oldFlags = fcntl(fd.get(), F_GETFD); - const auto newFlags = (oldFlags & ~FD_CLOEXEC); - if (newFlags != oldFlags) { - fcntl(fd.get(), F_SETFD, newFlags); - } -} - -Process adb_launch_process(std::string_view executable, std::vector args, - std::initializer_list fds_to_inherit) { - const auto pid = fork(); - if (pid != 0) { - // parent, includes the case when failed to fork() - return Process(pid); - } - // child - std::vector copies; - copies.reserve(args.size() + 1); - copies.emplace_back(executable); - copies.insert(copies.end(), std::make_move_iterator(args.begin()), - std::make_move_iterator(args.end())); - - std::vector rawArgs; - rawArgs.reserve(copies.size() + 1); - for (auto&& str : copies) { - rawArgs.push_back(str.data()); - } - rawArgs.push_back(nullptr); - for (auto fd : fds_to_inherit) { - disable_close_on_exec(fd); - } - exit(execv(copies.front().data(), rawArgs.data())); -} diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp deleted file mode 100644 index be82bc0d168df6b2eae0647540190a4e1eb74ad8..0000000000000000000000000000000000000000 --- a/adb/sysdeps_win32.cpp +++ /dev/null @@ -1,2981 +0,0 @@ -/* - * Copyright (C) 2015 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 SYSDEPS - -#include "sysdeps.h" - -#include -#include -#include /* winsock.h *must* be included before windows.h. */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "adb.h" -#include "adb_utils.h" - -#include "sysdeps/uio.h" - -/* forward declarations */ - -typedef const struct FHClassRec_* FHClass; -typedef struct FHRec_* FH; - -typedef struct FHClassRec_ { - void (*_fh_init)(FH); - int (*_fh_close)(FH); - int64_t (*_fh_lseek)(FH, int64_t, int); - int (*_fh_read)(FH, void*, int); - int (*_fh_write)(FH, const void*, int); - int (*_fh_writev)(FH, const adb_iovec*, int); - intptr_t (*_fh_get_os_handle)(FH); -} FHClassRec; - -static void _fh_file_init(FH); -static int _fh_file_close(FH); -static int64_t _fh_file_lseek(FH, int64_t, int); -static int _fh_file_read(FH, void*, int); -static int _fh_file_write(FH, const void*, int); -static int _fh_file_writev(FH, const adb_iovec*, int); -static intptr_t _fh_file_get_os_handle(FH f); - -static const FHClassRec _fh_file_class = { - _fh_file_init, _fh_file_close, _fh_file_lseek, _fh_file_read, - _fh_file_write, _fh_file_writev, _fh_file_get_os_handle, -}; - -static void _fh_socket_init(FH); -static int _fh_socket_close(FH); -static int64_t _fh_socket_lseek(FH, int64_t, int); -static int _fh_socket_read(FH, void*, int); -static int _fh_socket_write(FH, const void*, int); -static int _fh_socket_writev(FH, const adb_iovec*, int); -static intptr_t _fh_socket_get_os_handle(FH f); - -static const FHClassRec _fh_socket_class = { - _fh_socket_init, _fh_socket_close, _fh_socket_lseek, _fh_socket_read, - _fh_socket_write, _fh_socket_writev, _fh_socket_get_os_handle, -}; - -#if defined(assert) -#undef assert -#endif - -void handle_deleter::operator()(HANDLE h) { - // CreateFile() is documented to return INVALID_HANDLE_FILE on error, - // implying that NULL is a valid handle, but this is probably impossible. - // Other APIs like CreateEvent() are documented to return NULL on error, - // implying that INVALID_HANDLE_VALUE is a valid handle, but this is also - // probably impossible. Thus, consider both NULL and INVALID_HANDLE_VALUE - // as invalid handles. std::unique_ptr won't call a deleter with NULL, so we - // only need to check for INVALID_HANDLE_VALUE. - if (h != INVALID_HANDLE_VALUE) { - if (!CloseHandle(h)) { - D("CloseHandle(%p) failed: %s", h, - android::base::SystemErrorCodeToString(GetLastError()).c_str()); - } - } -} - -/**************************************************************************/ -/**************************************************************************/ -/***** *****/ -/***** common file descriptor handling *****/ -/***** *****/ -/**************************************************************************/ -/**************************************************************************/ - -typedef struct FHRec_ -{ - FHClass clazz; - int used; - int eof; - union { - HANDLE handle; - SOCKET socket; - } u; - - char name[32]; -} FHRec; - -#define fh_handle u.handle -#define fh_socket u.socket - -#define WIN32_FH_BASE 2048 -#define WIN32_MAX_FHS 2048 - -static std::mutex& _win32_lock = *new std::mutex(); -static FHRec _win32_fhs[ WIN32_MAX_FHS ]; -static int _win32_fh_next; // where to start search for free FHRec - -static FH _fh_from_int(borrowed_fd bfd, const char* func) { - FH f; - - int fd = bfd.get(); - fd -= WIN32_FH_BASE; - - if (fd < 0 || fd >= WIN32_MAX_FHS) { - D("_fh_from_int: invalid fd %d passed to %s", fd + WIN32_FH_BASE, func); - errno = EBADF; - return nullptr; - } - - f = &_win32_fhs[fd]; - - if (f->used == 0) { - D("_fh_from_int: invalid fd %d passed to %s", fd + WIN32_FH_BASE, func); - errno = EBADF; - return nullptr; - } - - 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) { - FH f = nullptr; - - std::lock_guard lock(_win32_lock); - - for (int i = _win32_fh_next; i < WIN32_MAX_FHS; ++i) { - if (_win32_fhs[i].clazz == nullptr) { - f = &_win32_fhs[i]; - _win32_fh_next = i + 1; - f->clazz = clazz; - f->used = 1; - f->eof = 0; - f->name[0] = '\0'; - clazz->_fh_init(f); - return f; - } - } - - D("_fh_alloc: no more free file descriptors"); - errno = EMFILE; // Too many open files - return nullptr; -} - -static int _fh_close(FH f) { - // Use lock so that closing only happens once and so that _fh_alloc can't - // allocate a FH that we're in the middle of closing. - std::lock_guard lock(_win32_lock); - - int offset = f - _win32_fhs; - if (_win32_fh_next > offset) { - _win32_fh_next = offset; - } - - if (f->used) { - f->clazz->_fh_close( f ); - f->name[0] = '\0'; - f->eof = 0; - f->used = 0; - f->clazz = nullptr; - } - return 0; -} - -// Deleter for unique_fh. -class fh_deleter { - public: - void operator()(struct FHRec_* fh) { - // We're called from a destructor and destructors should not overwrite - // errno because callers may do: - // errno = EBLAH; - // return -1; // calls destructor, which should not overwrite errno - const int saved_errno = errno; - _fh_close(fh); - errno = saved_errno; - } -}; - -// Like std::unique_ptr, but calls _fh_close() instead of operator delete(). -typedef std::unique_ptr unique_fh; - -/**************************************************************************/ -/**************************************************************************/ -/***** *****/ -/***** 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, nullptr)) { - D("adb_read: could not read %d bytes from %s", len, f->name); - errno = EIO; - return -1; - } else if (read_bytes < (DWORD)len) { - f->eof = 1; - } - return 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, nullptr)) { - D("adb_file_write: could not write %d bytes from %s", len, f->name); - errno = EIO; - return -1; - } else if (wrote_bytes < (DWORD)len) { - f->eof = 1; - } - return wrote_bytes; -} - -static int _fh_file_writev(FH f, const adb_iovec* iov, int iovcnt) { - if (iovcnt <= 0) { - errno = EINVAL; - return -1; - } - - DWORD wrote_bytes = 0; - - for (int i = 0; i < iovcnt; ++i) { - ssize_t rc = _fh_file_write(f, iov[i].iov_base, iov[i].iov_len); - if (rc == -1) { - return wrote_bytes > 0 ? wrote_bytes : -1; - } else if (rc == 0) { - return wrote_bytes; - } - - wrote_bytes += rc; - - if (static_cast(rc) < iov[i].iov_len) { - return wrote_bytes; - } - } - - return wrote_bytes; -} - -static int64_t _fh_file_lseek(FH f, int64_t pos, int origin) { - DWORD method; - 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; - } - - LARGE_INTEGER li = {.QuadPart = pos}; - if (!SetFilePointerEx(f->fh_handle, li, &li, method)) { - errno = EIO; - return -1; - } - f->eof = 0; - return li.QuadPart; -} - -static intptr_t _fh_file_get_os_handle(FH f) { - return reinterpret_cast(f->u.handle); -} - -/**************************************************************************/ -/**************************************************************************/ -/***** *****/ -/***** 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; - - // CreateFileW is inherently O_CLOEXEC by default. - options &= ~O_CLOEXEC; - - 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)", options); - errno = EINVAL; - return -1; - } - - f = _fh_alloc(&_fh_file_class); - if (!f) { - return -1; - } - - std::wstring path_wide; - if (!android::base::UTF8ToWide(path, &path_wide)) { - return -1; - } - f->fh_handle = - CreateFileW(path_wide.c_str(), desiredAccess, shareMode, nullptr, OPEN_EXISTING, 0, nullptr); - - if (f->fh_handle == INVALID_HANDLE_VALUE) { - const DWORD err = GetLastError(); - _fh_close(f); - D("adb_open: could not open '%s': ", path); - switch (err) { - case ERROR_FILE_NOT_FOUND: - D("file not found"); - errno = ENOENT; - return -1; - - case ERROR_PATH_NOT_FOUND: - D("path not found"); - errno = ENOTDIR; - return -1; - - default: - D("unknown error: %s", android::base::SystemErrorCodeToString(err).c_str()); - errno = ENOENT; - return -1; - } - } - - snprintf(f->name, sizeof(f->name), "%d(%s)", _fh_to_int(f), path); - D("adb_open: '%s' => fd %d", 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) { - return -1; - } - - std::wstring path_wide; - if (!android::base::UTF8ToWide(path, &path_wide)) { - return -1; - } - f->fh_handle = CreateFileW(path_wide.c_str(), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, - nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); - - if (f->fh_handle == INVALID_HANDLE_VALUE) { - const DWORD err = GetLastError(); - _fh_close(f); - D("adb_creat: could not open '%s': ", path); - switch (err) { - case ERROR_FILE_NOT_FOUND: - D("file not found"); - errno = ENOENT; - return -1; - - case ERROR_PATH_NOT_FOUND: - D("path not found"); - errno = ENOTDIR; - return -1; - - default: - D("unknown error: %s", android::base::SystemErrorCodeToString(err).c_str()); - errno = ENOENT; - return -1; - } - } - snprintf(f->name, sizeof(f->name), "%d(%s)", _fh_to_int(f), path); - D("adb_creat: '%s' => fd %d", path, _fh_to_int(f)); - return _fh_to_int(f); -} - -int adb_read(borrowed_fd fd, void* buf, int len) { - FH f = _fh_from_int(fd, __func__); - - if (f == nullptr) { - errno = EBADF; - return -1; - } - - return f->clazz->_fh_read(f, buf, len); -} - -int adb_pread(borrowed_fd fd, void* buf, int len, off64_t offset) { - OVERLAPPED overlapped = {}; - overlapped.Offset = static_cast(offset); - overlapped.OffsetHigh = static_cast(offset >> 32); - DWORD bytes_read; - if (!::ReadFile(adb_get_os_handle(fd), buf, static_cast(len), &bytes_read, - &overlapped)) { - D("adb_pread: could not read %d bytes from FD %d", len, fd.get()); - switch (::GetLastError()) { - case ERROR_IO_PENDING: - errno = EAGAIN; - return -1; - default: - errno = EINVAL; - return -1; - } - } - return static_cast(bytes_read); -} - -int adb_write(borrowed_fd fd, const void* buf, int len) { - FH f = _fh_from_int(fd, __func__); - - if (f == nullptr) { - errno = EBADF; - return -1; - } - - return f->clazz->_fh_write(f, buf, len); -} - -ssize_t adb_writev(borrowed_fd fd, const adb_iovec* iov, int iovcnt) { - FH f = _fh_from_int(fd, __func__); - - if (f == nullptr) { - errno = EBADF; - return -1; - } - - return f->clazz->_fh_writev(f, iov, iovcnt); -} - -int adb_pwrite(borrowed_fd fd, const void* buf, int len, off64_t offset) { - OVERLAPPED params = {}; - params.Offset = static_cast(offset); - params.OffsetHigh = static_cast(offset >> 32); - DWORD bytes_written = 0; - if (!::WriteFile(adb_get_os_handle(fd), buf, len, &bytes_written, ¶ms)) { - D("adb_pwrite: could not write %d bytes to FD %d", len, fd.get()); - switch (::GetLastError()) { - case ERROR_IO_PENDING: - errno = EAGAIN; - return -1; - default: - errno = EINVAL; - return -1; - } - } - return static_cast(bytes_written); -} - -int64_t adb_lseek(borrowed_fd fd, int64_t pos, int where) { - FH f = _fh_from_int(fd, __func__); - if (!f) { - errno = EBADF; - return -1; - } - return f->clazz->_fh_lseek(f, pos, where); -} - -int adb_close(int fd) { - FH f = _fh_from_int(fd, __func__); - - if (!f) { - errno = EBADF; - return -1; - } - - D("adb_close: %s", f->name); - _fh_close(f); - return 0; -} - -HANDLE adb_get_os_handle(borrowed_fd fd) { - FH f = _fh_from_int(fd, __func__); - - if (!f) { - errno = EBADF; - return nullptr; - } - - D("adb_get_os_handle: %s", f->name); - const intptr_t intptr_handle = f->clazz->_fh_get_os_handle(f); - const HANDLE handle = reinterpret_cast(intptr_handle); - return handle; -} - -/**************************************************************************/ -/**************************************************************************/ -/***** *****/ -/***** socket-based file descriptors *****/ -/***** *****/ -/**************************************************************************/ -/**************************************************************************/ - -#undef setsockopt - -static void _socket_set_errno( const DWORD err ) { - // Because the Windows C Runtime (MSVCRT.DLL) strerror() does not support a - // lot of POSIX and socket error codes, some of the resulting error codes - // are mapped to strings by adb_strerror(). - switch ( err ) { - case 0: errno = 0; break; - // Don't map WSAEINTR since that is only for Winsock 1.1 which we don't use. - // case WSAEINTR: errno = EINTR; break; - case WSAEFAULT: errno = EFAULT; break; - case WSAEINVAL: errno = EINVAL; break; - case WSAEMFILE: errno = EMFILE; break; - // Mapping WSAEWOULDBLOCK to EAGAIN is absolutely critical because - // non-blocking sockets can cause an error code of WSAEWOULDBLOCK and - // callers check specifically for EAGAIN. - case WSAEWOULDBLOCK: errno = EAGAIN; break; - case WSAENOTSOCK: errno = ENOTSOCK; break; - case WSAENOPROTOOPT: errno = ENOPROTOOPT; break; - case WSAEOPNOTSUPP: errno = EOPNOTSUPP; break; - case WSAENETDOWN: errno = ENETDOWN; break; - case WSAENETRESET: errno = ENETRESET; break; - // Map WSAECONNABORTED to EPIPE instead of ECONNABORTED because POSIX seems - // to use EPIPE for these situations and there are some callers that look - // for EPIPE. - case WSAECONNABORTED: errno = EPIPE; break; - case WSAECONNRESET: errno = ECONNRESET; break; - case WSAENOBUFS: errno = ENOBUFS; break; - case WSAENOTCONN: errno = ENOTCONN; break; - // Don't map WSAETIMEDOUT because we don't currently use SO_RCVTIMEO or - // SO_SNDTIMEO which would cause WSAETIMEDOUT to be returned. Future - // considerations: Reportedly send() can return zero on timeout, and POSIX - // code may expect EAGAIN instead of ETIMEDOUT on timeout. - // case WSAETIMEDOUT: errno = ETIMEDOUT; break; - case WSAEHOSTUNREACH: errno = EHOSTUNREACH; break; - default: - errno = EINVAL; - D( "_socket_set_errno: mapping Windows error code %lu to errno %d", - err, errno ); - } -} - -extern int adb_poll(adb_pollfd* fds, size_t nfds, int timeout) { - // WSAPoll doesn't handle invalid/non-socket handles, so we need to handle them ourselves. - int skipped = 0; - std::vector sockets; - std::vector original; - - for (size_t i = 0; i < nfds; ++i) { - FH fh = _fh_from_int(fds[i].fd, __func__); - if (!fh || !fh->used || fh->clazz != &_fh_socket_class) { - D("adb_poll received bad FD %d", fds[i].fd); - fds[i].revents = POLLNVAL; - ++skipped; - } else { - WSAPOLLFD wsapollfd = { - .fd = fh->u.socket, - .events = static_cast(fds[i].events) - }; - sockets.push_back(wsapollfd); - original.push_back(&fds[i]); - } - } - - if (sockets.empty()) { - return skipped; - } - - // If we have any invalid FDs in our FD set, make sure to return immediately. - if (skipped > 0) { - timeout = 0; - } - - int result = WSAPoll(sockets.data(), sockets.size(), timeout); - if (result == SOCKET_ERROR) { - _socket_set_errno(WSAGetLastError()); - return -1; - } - - // Map the results back onto the original set. - for (size_t i = 0; i < sockets.size(); ++i) { - original[i]->revents = sockets[i].revents; - } - - // WSAPoll appears to return the number of unique FDs with available events, instead of how many - // of the pollfd elements have a non-zero revents field, which is what it and poll are specified - // to do. Ignore its result and calculate the proper return value. - result = 0; - for (size_t i = 0; i < nfds; ++i) { - if (fds[i].revents != 0) { - ++result; - } - } - return result; -} - -static void _fh_socket_init(FH f) { - f->fh_socket = INVALID_SOCKET; -} - -static int _fh_socket_close(FH f) { - if (f->fh_socket != INVALID_SOCKET) { - if (closesocket(f->fh_socket) == SOCKET_ERROR) { - // Don't set errno here, since adb_close will ignore it. - const DWORD err = WSAGetLastError(); - D("closesocket failed: %s", android::base::SystemErrorCodeToString(err).c_str()); - } - f->fh_socket = INVALID_SOCKET; - } - return 0; -} - -static int64_t _fh_socket_lseek(FH f, int64_t pos, int origin) { - errno = EPIPE; - return -1; -} - -static int _fh_socket_read(FH f, void* buf, int len) { - int result = recv(f->fh_socket, reinterpret_cast(buf), len, 0); - if (result == SOCKET_ERROR) { - const DWORD err = WSAGetLastError(); - // WSAEWOULDBLOCK is normal with a non-blocking socket, so don't trace - // that to reduce spam and confusion. - if (err != WSAEWOULDBLOCK) { - D("recv fd %d failed: %s", _fh_to_int(f), - android::base::SystemErrorCodeToString(err).c_str()); - } - _socket_set_errno(err); - result = -1; - } - return result; -} - -static int _fh_socket_write(FH f, const void* buf, int len) { - int result = send(f->fh_socket, reinterpret_cast(buf), len, 0); - if (result == SOCKET_ERROR) { - const DWORD err = WSAGetLastError(); - // WSAEWOULDBLOCK is normal with a non-blocking socket, so don't trace - // that to reduce spam and confusion. - if (err != WSAEWOULDBLOCK) { - D("send fd %d failed: %s", _fh_to_int(f), - android::base::SystemErrorCodeToString(err).c_str()); - } - _socket_set_errno(err); - result = -1; - } else { - // According to https://code.google.com/p/chromium/issues/detail?id=27870 - // Winsock Layered Service Providers may cause this. - CHECK_LE(result, len) << "Tried to write " << len << " bytes to " << f->name << ", but " - << result << " bytes reportedly written"; - } - return result; -} - -// Make sure that adb_iovec is compatible with WSABUF. -static_assert(sizeof(adb_iovec) == sizeof(WSABUF), ""); -static_assert(SIZEOF_MEMBER(adb_iovec, iov_len) == SIZEOF_MEMBER(WSABUF, len), ""); -static_assert(offsetof(adb_iovec, iov_len) == offsetof(WSABUF, len), ""); - -static_assert(SIZEOF_MEMBER(adb_iovec, iov_base) == SIZEOF_MEMBER(WSABUF, buf), ""); -static_assert(offsetof(adb_iovec, iov_base) == offsetof(WSABUF, buf), ""); - -static int _fh_socket_writev(FH f, const adb_iovec* iov, int iovcnt) { - if (iovcnt <= 0) { - errno = EINVAL; - return -1; - } - - WSABUF* wsabuf = reinterpret_cast(const_cast(iov)); - DWORD bytes_written = 0; - int result = WSASend(f->fh_socket, wsabuf, iovcnt, &bytes_written, 0, nullptr, nullptr); - if (result == SOCKET_ERROR) { - const DWORD err = WSAGetLastError(); - // WSAEWOULDBLOCK is normal with a non-blocking socket, so don't trace - // that to reduce spam and confusion. - if (err != WSAEWOULDBLOCK) { - D("send fd %d failed: %s", _fh_to_int(f), - android::base::SystemErrorCodeToString(err).c_str()); - } - _socket_set_errno(err); - return -1; - } - CHECK_GE(static_cast(std::numeric_limits::max()), bytes_written); - return static_cast(bytes_written); -} - -static intptr_t _fh_socket_get_os_handle(FH f) { - return f->u.socket; -} - -/**************************************************************************/ -/**************************************************************************/ -/***** *****/ -/***** replacement for libs/cutils/socket_xxxx.c *****/ -/***** *****/ -/**************************************************************************/ -/**************************************************************************/ - -static void _init_winsock() { - static std::once_flag once; - std::call_once(once, []() { - WSADATA wsaData; - int rc = WSAStartup(MAKEWORD(2, 2), &wsaData); - if (rc != 0) { - LOG(FATAL) << "could not initialize Winsock: " - << android::base::SystemErrorCodeToString(rc); - } - - // Note that we do not call atexit() to register WSACleanup to be called - // at normal process termination because: - // 1) When exit() is called, there are still threads actively using - // Winsock because we don't cleanly shutdown all threads, so it - // doesn't make sense to call WSACleanup() and may cause problems - // with those threads. - // 2) A deadlock can occur when exit() holds a C Runtime lock, then it - // calls WSACleanup() which tries to unload a DLL, which tries to - // grab the LoaderLock. This conflicts with the device_poll_thread - // which holds the LoaderLock because AdbWinApi.dll calls - // setupapi.dll which tries to load wintrust.dll which tries to load - // crypt32.dll which calls atexit() which tries to acquire the C - // Runtime lock that the other thread holds. - }); -} - -// Map a socket type to an explicit socket protocol instead of using the socket -// protocol of 0. Explicit socket protocols are used by most apps and we should -// do the same to reduce the chance of exercising uncommon code-paths that might -// have problems or that might load different Winsock service providers that -// have problems. -static int GetSocketProtocolFromSocketType(int type) { - switch (type) { - case SOCK_STREAM: - return IPPROTO_TCP; - case SOCK_DGRAM: - return IPPROTO_UDP; - default: - LOG(FATAL) << "Unknown socket type: " << type; - return 0; - } -} - -int network_loopback_client(int port, int type, std::string* error) { - struct sockaddr_in addr; - SOCKET s; - - unique_fh f(_fh_alloc(&_fh_socket_class)); - if (!f) { - *error = strerror(errno); - return -1; - } - - 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, GetSocketProtocolFromSocketType(type)); - if (s == INVALID_SOCKET) { - const DWORD err = WSAGetLastError(); - *error = android::base::StringPrintf("cannot create socket: %s", - android::base::SystemErrorCodeToString(err).c_str()); - D("%s", error->c_str()); - _socket_set_errno(err); - return -1; - } - f->fh_socket = s; - - if (connect(s, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) { - // Save err just in case inet_ntoa() or ntohs() changes the last error. - const DWORD err = WSAGetLastError(); - *error = android::base::StringPrintf("cannot connect to %s:%u: %s", - inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), - android::base::SystemErrorCodeToString(err).c_str()); - D("could not connect to %s:%d: %s", type != SOCK_STREAM ? "udp" : "tcp", port, - error->c_str()); - _socket_set_errno(err); - return -1; - } - - const int fd = _fh_to_int(f.get()); - snprintf(f->name, sizeof(f->name), "%d(lo-client:%s%d)", fd, type != SOCK_STREAM ? "udp:" : "", - port); - D("port %d type %s => fd %d", port, type != SOCK_STREAM ? "udp" : "tcp", fd); - f.release(); - return fd; -} - -// interface_address is INADDR_LOOPBACK or INADDR_ANY. -static int _network_server(int port, int type, u_long interface_address, std::string* error) { - struct sockaddr_in addr; - SOCKET s; - int n; - - unique_fh f(_fh_alloc(&_fh_socket_class)); - if (!f) { - *error = strerror(errno); - return -1; - } - - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr.s_addr = htonl(interface_address); - - // TODO: Consider using dual-stack socket that can simultaneously listen on - // IPv4 and IPv6. - s = socket(AF_INET, type, GetSocketProtocolFromSocketType(type)); - if (s == INVALID_SOCKET) { - const DWORD err = WSAGetLastError(); - *error = android::base::StringPrintf("cannot create socket: %s", - android::base::SystemErrorCodeToString(err).c_str()); - D("%s", error->c_str()); - _socket_set_errno(err); - return -1; - } - - f->fh_socket = s; - - // Note: SO_REUSEADDR on Windows allows multiple processes to bind to the - // same port, so instead use SO_EXCLUSIVEADDRUSE. - n = 1; - if (setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*)&n, sizeof(n)) == SOCKET_ERROR) { - const DWORD err = WSAGetLastError(); - *error = android::base::StringPrintf("cannot set socket option SO_EXCLUSIVEADDRUSE: %s", - android::base::SystemErrorCodeToString(err).c_str()); - D("%s", error->c_str()); - _socket_set_errno(err); - return -1; - } - - if (bind(s, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) { - // Save err just in case inet_ntoa() or ntohs() changes the last error. - const DWORD err = WSAGetLastError(); - *error = android::base::StringPrintf("cannot bind to %s:%u: %s", inet_ntoa(addr.sin_addr), - ntohs(addr.sin_port), - android::base::SystemErrorCodeToString(err).c_str()); - D("could not bind to %s:%d: %s", type != SOCK_STREAM ? "udp" : "tcp", port, error->c_str()); - _socket_set_errno(err); - return -1; - } - if (type == SOCK_STREAM) { - if (listen(s, SOMAXCONN) == SOCKET_ERROR) { - const DWORD err = WSAGetLastError(); - *error = android::base::StringPrintf( - "cannot listen on socket: %s", android::base::SystemErrorCodeToString(err).c_str()); - D("could not listen on %s:%d: %s", type != SOCK_STREAM ? "udp" : "tcp", port, - error->c_str()); - _socket_set_errno(err); - return -1; - } - } - const int fd = _fh_to_int(f.get()); - snprintf(f->name, sizeof(f->name), "%d(%s-server:%s%d)", fd, - interface_address == INADDR_LOOPBACK ? "lo" : "any", type != SOCK_STREAM ? "udp:" : "", - port); - D("port %d type %s => fd %d", port, type != SOCK_STREAM ? "udp" : "tcp", fd); - f.release(); - return fd; -} - -int network_loopback_server(int port, int type, std::string* error, bool prefer_ipv4) { - // TODO implement IPv6 support on windows - return _network_server(port, type, INADDR_LOOPBACK, error); -} - -int network_inaddr_any_server(int port, int type, std::string* error) { - return _network_server(port, type, INADDR_ANY, error); -} - -int network_connect(const std::string& host, int port, int type, int timeout, std::string* error) { - unique_fh f(_fh_alloc(&_fh_socket_class)); - if (!f) { - *error = strerror(errno); - return -1; - } - - struct addrinfo hints; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = type; - hints.ai_protocol = GetSocketProtocolFromSocketType(type); - - char port_str[16]; - snprintf(port_str, sizeof(port_str), "%d", port); - - struct addrinfo* addrinfo_ptr = nullptr; - -#if (NTDDI_VERSION >= NTDDI_WINXPSP2) || (_WIN32_WINNT >= _WIN32_WINNT_WS03) -// TODO: When the Android SDK tools increases the Windows system -// requirements >= WinXP SP2, switch to android::base::UTF8ToWide() + GetAddrInfoW(). -#else -// Otherwise, keep using getaddrinfo(), or do runtime API detection -// with GetProcAddress("GetAddrInfoW"). -#endif - if (getaddrinfo(host.c_str(), port_str, &hints, &addrinfo_ptr) != 0) { - const DWORD err = WSAGetLastError(); - *error = android::base::StringPrintf("cannot resolve host '%s' and port %s: %s", - host.c_str(), port_str, - android::base::SystemErrorCodeToString(err).c_str()); - - D("%s", error->c_str()); - _socket_set_errno(err); - return -1; - } - std::unique_ptr addrinfo(addrinfo_ptr, freeaddrinfo); - addrinfo_ptr = nullptr; - - // TODO: Try all the addresses if there's more than one? This just uses - // the first. Or, could call WSAConnectByName() (Windows Vista and newer) - // which tries all addresses, takes a timeout and more. - SOCKET s = socket(addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol); - if (s == INVALID_SOCKET) { - const DWORD err = WSAGetLastError(); - *error = android::base::StringPrintf("cannot create socket: %s", - android::base::SystemErrorCodeToString(err).c_str()); - D("%s", error->c_str()); - _socket_set_errno(err); - return -1; - } - f->fh_socket = s; - - // TODO: Implement timeouts for Windows. Seems like the default in theory - // (according to http://serverfault.com/a/671453) and in practice is 21 sec. - if (connect(s, addrinfo->ai_addr, addrinfo->ai_addrlen) == SOCKET_ERROR) { - // TODO: Use WSAAddressToString or inet_ntop on address. - const DWORD err = WSAGetLastError(); - *error = android::base::StringPrintf("cannot connect to %s:%s: %s", host.c_str(), port_str, - android::base::SystemErrorCodeToString(err).c_str()); - D("could not connect to %s:%s:%s: %s", type != SOCK_STREAM ? "udp" : "tcp", host.c_str(), - port_str, error->c_str()); - _socket_set_errno(err); - return -1; - } - - const int fd = _fh_to_int(f.get()); - snprintf(f->name, sizeof(f->name), "%d(net-client:%s%d)", fd, type != SOCK_STREAM ? "udp:" : "", - port); - D("host '%s' port %d type %s => fd %d", host.c_str(), port, type != SOCK_STREAM ? "udp" : "tcp", - fd); - f.release(); - return fd; -} - -int adb_register_socket(SOCKET s) { - FH f = _fh_alloc(&_fh_socket_class); - f->fh_socket = s; - return _fh_to_int(f); -} - -static bool isBlankStr(const char* str) { - for (; *str != '\0'; ++str) { - if (!isblank(*str)) { - return false; - } - } - return true; -} - -int adb_gethostname(char* name, size_t len) { - const char* computerName = adb_getenv("COMPUTERNAME"); - if (computerName && !isBlankStr(computerName)) { - strncpy(name, computerName, len); - name[len - 1] = '\0'; - return 0; - } - - wchar_t buffer[MAX_COMPUTERNAME_LENGTH + 1]; - DWORD size = sizeof(buffer); - if (!GetComputerNameW(buffer, &size)) { - return -1; - } - std::string name_utf8; - if (!android::base::WideToUTF8(buffer, &name_utf8)) { - return -1; - } - - strncpy(name, name_utf8.c_str(), len); - name[len - 1] = '\0'; - return 0; -} - -int adb_getlogin_r(char* buf, size_t bufsize) { - wchar_t buffer[UNLEN + 1]; - DWORD len = sizeof(buffer); - if (!GetUserNameW(buffer, &len)) { - return -1; - } - - std::string login; - if (!android::base::WideToUTF8(buffer, &login)) { - return -1; - } - - strncpy(buf, login.c_str(), bufsize); - buf[bufsize - 1] = '\0'; - return 0; -} - -#undef accept -int adb_socket_accept(borrowed_fd serverfd, struct sockaddr* addr, socklen_t* addrlen) { - FH serverfh = _fh_from_int(serverfd, __func__); - - if (!serverfh || serverfh->clazz != &_fh_socket_class) { - D("adb_socket_accept: invalid fd %d", serverfd.get()); - errno = EBADF; - return -1; - } - - unique_fh fh(_fh_alloc(&_fh_socket_class)); - if (!fh) { - PLOG(ERROR) << "adb_socket_accept: failed to allocate accepted socket " - "descriptor"; - return -1; - } - - fh->fh_socket = accept(serverfh->fh_socket, addr, addrlen); - if (fh->fh_socket == INVALID_SOCKET) { - const DWORD err = WSAGetLastError(); - LOG(ERROR) << "adb_socket_accept: accept on fd " << serverfd.get() - << " failed: " + android::base::SystemErrorCodeToString(err); - _socket_set_errno(err); - return -1; - } - - const int fd = _fh_to_int(fh.get()); - snprintf(fh->name, sizeof(fh->name), "%d(accept:%s)", fd, serverfh->name); - D("adb_socket_accept on fd %d returns fd %d", serverfd.get(), fd); - fh.release(); - return fd; -} - -int adb_setsockopt(borrowed_fd fd, int level, int optname, const void* optval, socklen_t optlen) { - FH fh = _fh_from_int(fd, __func__); - - if (!fh || fh->clazz != &_fh_socket_class) { - D("adb_setsockopt: invalid fd %d", fd.get()); - errno = EBADF; - return -1; - } - - // TODO: Once we can assume Windows Vista or later, if the caller is trying - // to set SOL_SOCKET, SO_SNDBUF/SO_RCVBUF, ignore it since the OS has - // auto-tuning. - - int result = - setsockopt(fh->fh_socket, level, optname, reinterpret_cast(optval), optlen); - if (result == SOCKET_ERROR) { - const DWORD err = WSAGetLastError(); - D("adb_setsockopt: setsockopt on fd %d level %d optname %d failed: %s\n", fd.get(), level, - optname, android::base::SystemErrorCodeToString(err).c_str()); - _socket_set_errno(err); - result = -1; - } - return result; -} - -static int adb_getsockname(borrowed_fd fd, struct sockaddr* sockaddr, socklen_t* optlen) { - FH fh = _fh_from_int(fd, __func__); - - if (!fh || fh->clazz != &_fh_socket_class) { - D("adb_getsockname: invalid fd %d", fd.get()); - errno = EBADF; - return -1; - } - - int result = getsockname(fh->fh_socket, sockaddr, optlen); - if (result == SOCKET_ERROR) { - const DWORD err = WSAGetLastError(); - D("adb_getsockname: setsockopt on fd %d failed: %s\n", fd.get(), - android::base::SystemErrorCodeToString(err).c_str()); - _socket_set_errno(err); - result = -1; - } - return result; -} - -int adb_socket_get_local_port(borrowed_fd fd) { - sockaddr_storage addr_storage; - socklen_t addr_len = sizeof(addr_storage); - - if (adb_getsockname(fd, reinterpret_cast(&addr_storage), &addr_len) < 0) { - D("adb_socket_get_local_port: adb_getsockname failed: %s", strerror(errno)); - return -1; - } - - if (!(addr_storage.ss_family == AF_INET || addr_storage.ss_family == AF_INET6)) { - D("adb_socket_get_local_port: unknown address family received: %d", addr_storage.ss_family); - errno = ECONNABORTED; - return -1; - } - - return ntohs(reinterpret_cast(&addr_storage)->sin_port); -} - -int adb_shutdown(borrowed_fd fd, int direction) { - FH f = _fh_from_int(fd, __func__); - - if (!f || f->clazz != &_fh_socket_class) { - D("adb_shutdown: invalid fd %d", fd.get()); - errno = EBADF; - return -1; - } - - D("adb_shutdown: %s", f->name); - if (shutdown(f->fh_socket, direction) == SOCKET_ERROR) { - const DWORD err = WSAGetLastError(); - D("socket shutdown fd %d failed: %s", fd.get(), - android::base::SystemErrorCodeToString(err).c_str()); - _socket_set_errno(err); - return -1; - } - return 0; -} - -// Emulate socketpair(2) by binding and connecting to a socket. -int adb_socketpair(int sv[2]) { - int server = -1; - int client = -1; - int accepted = -1; - int local_port = -1; - std::string error; - - server = network_loopback_server(0, SOCK_STREAM, &error, true); - if (server < 0) { - D("adb_socketpair: failed to create server: %s", error.c_str()); - goto fail; - } - - local_port = adb_socket_get_local_port(server); - if (local_port < 0) { - D("adb_socketpair: failed to get server port number: %s", error.c_str()); - goto fail; - } - D("adb_socketpair: bound on port %d", local_port); - - client = network_loopback_client(local_port, SOCK_STREAM, &error); - if (client < 0) { - D("adb_socketpair: failed to connect client: %s", error.c_str()); - goto fail; - } - - accepted = adb_socket_accept(server, nullptr, nullptr); - if (accepted < 0) { - D("adb_socketpair: failed to accept: %s", strerror(errno)); - goto fail; - } - adb_close(server); - sv[0] = client; - sv[1] = accepted; - return 0; - -fail: - if (server >= 0) { - adb_close(server); - } - if (client >= 0) { - adb_close(client); - } - if (accepted >= 0) { - adb_close(accepted); - } - return -1; -} - -bool set_file_block_mode(borrowed_fd fd, bool block) { - FH fh = _fh_from_int(fd, __func__); - - if (!fh || !fh->used) { - errno = EBADF; - D("Setting nonblocking on bad file descriptor %d", fd.get()); - return false; - } - - if (fh->clazz == &_fh_socket_class) { - u_long x = !block; - if (ioctlsocket(fh->u.socket, FIONBIO, &x) != 0) { - int error = WSAGetLastError(); - _socket_set_errno(error); - D("Setting %d nonblocking failed (%d)", fd.get(), error); - return false; - } - return true; - } else { - errno = ENOTSOCK; - D("Setting nonblocking on non-socket %d", fd.get()); - return false; - } -} - -bool set_tcp_keepalive(borrowed_fd fd, int interval_sec) { - FH fh = _fh_from_int(fd, __func__); - - if (!fh || fh->clazz != &_fh_socket_class) { - D("set_tcp_keepalive(%d) failed: invalid fd", fd.get()); - errno = EBADF; - return false; - } - - tcp_keepalive keepalive; - keepalive.onoff = (interval_sec > 0); - keepalive.keepalivetime = interval_sec * 1000; - keepalive.keepaliveinterval = interval_sec * 1000; - - DWORD bytes_returned = 0; - if (WSAIoctl(fh->fh_socket, SIO_KEEPALIVE_VALS, &keepalive, sizeof(keepalive), nullptr, 0, - &bytes_returned, nullptr, nullptr) != 0) { - const DWORD err = WSAGetLastError(); - D("set_tcp_keepalive(%d) failed: %s", fd.get(), - android::base::SystemErrorCodeToString(err).c_str()); - _socket_set_errno(err); - return false; - } - - return true; -} - -/**************************************************************************/ -/**************************************************************************/ -/***** *****/ -/***** Console Window Terminal Emulation *****/ -/***** *****/ -/**************************************************************************/ -/**************************************************************************/ - -// This reads input from a Win32 console window and translates it into Unix -// terminal-style sequences. This emulates mostly Gnome Terminal (in Normal -// mode, not Application mode), which itself emulates xterm. Gnome Terminal -// is emulated instead of xterm because it is probably more popular than xterm: -// Ubuntu's default Ctrl-Alt-T shortcut opens Gnome Terminal, Gnome Terminal -// supports modern fonts, etc. It seems best to emulate the terminal that most -// Android developers use because they'll fix apps (the shell, etc.) to keep -// working with that terminal's emulation. -// -// The point of this emulation is not to be perfect or to solve all issues with -// console windows on Windows, but to be better than the original code which -// just called read() (which called ReadFile(), which called ReadConsoleA()) -// which did not support Ctrl-C, tab completion, shell input line editing -// keys, server echo, and more. -// -// This implementation reconfigures the console with SetConsoleMode(), then -// calls ReadConsoleInput() to get raw input which it remaps to Unix -// terminal-style sequences which is returned via unix_read() which is used -// by the 'adb shell' command. -// -// Code organization: -// -// * _get_console_handle() and unix_isatty() provide console information. -// * stdin_raw_init() and stdin_raw_restore() reconfigure the console. -// * unix_read() detects console windows (as opposed to pipes, files, etc.). -// * _console_read() is the main code of the emulation. - -// Returns a console HANDLE if |fd| is a console, otherwise returns nullptr. -// If a valid HANDLE is returned and |mode| is not null, |mode| is also filled -// with the console mode. Requires GENERIC_READ access to the underlying HANDLE. -static HANDLE _get_console_handle(borrowed_fd fd, DWORD* mode = nullptr) { - // First check isatty(); this is very fast and eliminates most non-console - // FDs, but returns 1 for both consoles and character devices like NUL. -#pragma push_macro("isatty") -#undef isatty - if (!isatty(fd.get())) { - return nullptr; - } -#pragma pop_macro("isatty") - - // To differentiate between character devices and consoles we need to get - // the underlying HANDLE and use GetConsoleMode(), which is what requires - // GENERIC_READ permissions. - const intptr_t intptr_handle = _get_osfhandle(fd.get()); - if (intptr_handle == -1) { - return nullptr; - } - const HANDLE handle = reinterpret_cast(intptr_handle); - DWORD temp_mode = 0; - if (!GetConsoleMode(handle, mode ? mode : &temp_mode)) { - return nullptr; - } - - return handle; -} - -// Returns a console handle if |stream| is a console, otherwise returns nullptr. -static HANDLE _get_console_handle(FILE* const stream) { - // Save and restore errno to make it easier for callers to prevent from overwriting errno. - android::base::ErrnoRestorer er; - const int fd = fileno(stream); - if (fd < 0) { - return nullptr; - } - return _get_console_handle(fd); -} - -int unix_isatty(borrowed_fd fd) { - return _get_console_handle(fd) ? 1 : 0; -} - -// Get the next KEY_EVENT_RECORD that should be processed. -static bool _get_key_event_record(const HANDLE console, INPUT_RECORD* const input_record) { - for (;;) { - DWORD read_count = 0; - memset(input_record, 0, sizeof(*input_record)); - if (!ReadConsoleInputA(console, input_record, 1, &read_count)) { - D("_get_key_event_record: ReadConsoleInputA() failed: %s\n", - android::base::SystemErrorCodeToString(GetLastError()).c_str()); - errno = EIO; - return false; - } - - if (read_count == 0) { // should be impossible - LOG(FATAL) << "ReadConsoleInputA returned 0"; - } - - if (read_count != 1) { // should be impossible - LOG(FATAL) << "ReadConsoleInputA did not return one input record"; - } - - // If the console window is resized, emulate SIGWINCH by breaking out - // of read() with errno == EINTR. Note that there is no event on - // vertical resize because we don't give the console our own custom - // screen buffer (with CreateConsoleScreenBuffer() + - // SetConsoleActiveScreenBuffer()). Instead, we use the default which - // supports scrollback, but doesn't seem to raise an event for vertical - // window resize. - if (input_record->EventType == WINDOW_BUFFER_SIZE_EVENT) { - errno = EINTR; - return false; - } - - if ((input_record->EventType == KEY_EVENT) && - (input_record->Event.KeyEvent.bKeyDown)) { - if (input_record->Event.KeyEvent.wRepeatCount == 0) { - LOG(FATAL) << "ReadConsoleInputA returned a key event with zero repeat count"; - } - - // Got an interesting INPUT_RECORD, so return - return true; - } - } -} - -static __inline__ bool _is_shift_pressed(const DWORD control_key_state) { - return (control_key_state & SHIFT_PRESSED) != 0; -} - -static __inline__ bool _is_ctrl_pressed(const DWORD control_key_state) { - return (control_key_state & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) != 0; -} - -static __inline__ bool _is_alt_pressed(const DWORD control_key_state) { - return (control_key_state & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) != 0; -} - -static __inline__ bool _is_numlock_on(const DWORD control_key_state) { - return (control_key_state & NUMLOCK_ON) != 0; -} - -static __inline__ bool _is_capslock_on(const DWORD control_key_state) { - return (control_key_state & CAPSLOCK_ON) != 0; -} - -static __inline__ bool _is_enhanced_key(const DWORD control_key_state) { - return (control_key_state & ENHANCED_KEY) != 0; -} - -// Constants from MSDN for ToAscii(). -static const BYTE TOASCII_KEY_OFF = 0x00; -static const BYTE TOASCII_KEY_DOWN = 0x80; -static const BYTE TOASCII_KEY_TOGGLED_ON = 0x01; // for CapsLock - -// Given a key event, ignore a modifier key and return the character that was -// entered without the modifier. Writes to *ch and returns the number of bytes -// written. -static size_t _get_char_ignoring_modifier(char* const ch, - const KEY_EVENT_RECORD* const key_event, const DWORD control_key_state, - const WORD modifier) { - // If there is no character from Windows, try ignoring the specified - // modifier and look for a character. Note that if AltGr is being used, - // there will be a character from Windows. - if (key_event->uChar.AsciiChar == '\0') { - // Note that we read the control key state from the passed in argument - // instead of from key_event since the argument has been normalized. - if (((modifier == VK_SHIFT) && - _is_shift_pressed(control_key_state)) || - ((modifier == VK_CONTROL) && - _is_ctrl_pressed(control_key_state)) || - ((modifier == VK_MENU) && _is_alt_pressed(control_key_state))) { - - BYTE key_state[256] = {0}; - key_state[VK_SHIFT] = _is_shift_pressed(control_key_state) ? - TOASCII_KEY_DOWN : TOASCII_KEY_OFF; - key_state[VK_CONTROL] = _is_ctrl_pressed(control_key_state) ? - TOASCII_KEY_DOWN : TOASCII_KEY_OFF; - key_state[VK_MENU] = _is_alt_pressed(control_key_state) ? - TOASCII_KEY_DOWN : TOASCII_KEY_OFF; - key_state[VK_CAPITAL] = _is_capslock_on(control_key_state) ? - TOASCII_KEY_TOGGLED_ON : TOASCII_KEY_OFF; - - // cause this modifier to be ignored - key_state[modifier] = TOASCII_KEY_OFF; - - WORD translated = 0; - if (ToAscii(key_event->wVirtualKeyCode, - key_event->wVirtualScanCode, key_state, &translated, 0) == 1) { - // Ignoring the modifier, we found a character. - *ch = (CHAR)translated; - return 1; - } - } - } - - // Just use whatever Windows told us originally. - *ch = key_event->uChar.AsciiChar; - - // If the character from Windows is NULL, return a size of zero. - return (*ch == '\0') ? 0 : 1; -} - -// If a Ctrl key is pressed, lookup the character, ignoring the Ctrl key, -// but taking into account the shift key. This is because for a sequence like -// Ctrl-Alt-0, we want to find the character '0' and for Ctrl-Alt-Shift-0, -// we want to find the character ')'. -// -// Note that Windows doesn't seem to pass bKeyDown for Ctrl-Shift-NoAlt-0 -// because it is the default key-sequence to switch the input language. -// This is configurable in the Region and Language control panel. -static __inline__ size_t _get_non_control_char(char* const ch, - const KEY_EVENT_RECORD* const key_event, const DWORD control_key_state) { - return _get_char_ignoring_modifier(ch, key_event, control_key_state, - VK_CONTROL); -} - -// Get without Alt. -static __inline__ size_t _get_non_alt_char(char* const ch, - const KEY_EVENT_RECORD* const key_event, const DWORD control_key_state) { - return _get_char_ignoring_modifier(ch, key_event, control_key_state, - VK_MENU); -} - -// Ignore the control key, find the character from Windows, and apply any -// Control key mappings (for example, Ctrl-2 is a NULL character). Writes to -// *pch and returns number of bytes written. -static size_t _get_control_character(char* const pch, - const KEY_EVENT_RECORD* const key_event, const DWORD control_key_state) { - const size_t len = _get_non_control_char(pch, key_event, - control_key_state); - - if ((len == 1) && _is_ctrl_pressed(control_key_state)) { - char ch = *pch; - switch (ch) { - case '2': - case '@': - case '`': - ch = '\0'; - break; - case '3': - case '[': - case '{': - ch = '\x1b'; - break; - case '4': - case '\\': - case '|': - ch = '\x1c'; - break; - case '5': - case ']': - case '}': - ch = '\x1d'; - break; - case '6': - case '^': - case '~': - ch = '\x1e'; - break; - case '7': - case '-': - case '_': - ch = '\x1f'; - break; - case '8': - ch = '\x7f'; - break; - case '/': - if (!_is_alt_pressed(control_key_state)) { - ch = '\x1f'; - } - break; - case '?': - if (!_is_alt_pressed(control_key_state)) { - ch = '\x7f'; - } - break; - } - *pch = ch; - } - - return len; -} - -static DWORD _normalize_altgr_control_key_state( - const KEY_EVENT_RECORD* const key_event) { - DWORD control_key_state = key_event->dwControlKeyState; - - // If we're in an AltGr situation where the AltGr key is down (depending on - // the keyboard layout, that might be the physical right alt key which - // produces a control_key_state where Right-Alt and Left-Ctrl are down) or - // AltGr-equivalent keys are down (any Ctrl key + any Alt key), and we have - // a character (which indicates that there was an AltGr mapping), then act - // as if alt and control are not really down for the purposes of modifiers. - // This makes it so that if the user with, say, a German keyboard layout - // presses AltGr-] (which we see as Right-Alt + Left-Ctrl + key), we just - // output the key and we don't see the Alt and Ctrl keys. - if (_is_ctrl_pressed(control_key_state) && - _is_alt_pressed(control_key_state) - && (key_event->uChar.AsciiChar != '\0')) { - // Try to remove as few bits as possible to improve our chances of - // detecting combinations like Left-Alt + AltGr, Right-Ctrl + AltGr, or - // Left-Alt + Right-Ctrl + AltGr. - if ((control_key_state & RIGHT_ALT_PRESSED) != 0) { - // Remove Right-Alt. - control_key_state &= ~RIGHT_ALT_PRESSED; - // If uChar is set, a Ctrl key is pressed, and Right-Alt is - // pressed, Left-Ctrl is almost always set, except if the user - // presses Right-Ctrl, then AltGr (in that specific order) for - // whatever reason. At any rate, make sure the bit is not set. - control_key_state &= ~LEFT_CTRL_PRESSED; - } else if ((control_key_state & LEFT_ALT_PRESSED) != 0) { - // Remove Left-Alt. - control_key_state &= ~LEFT_ALT_PRESSED; - // Whichever Ctrl key is down, remove it from the state. We only - // remove one key, to improve our chances of detecting the - // corner-case of Left-Ctrl + Left-Alt + Right-Ctrl. - if ((control_key_state & LEFT_CTRL_PRESSED) != 0) { - // Remove Left-Ctrl. - control_key_state &= ~LEFT_CTRL_PRESSED; - } else if ((control_key_state & RIGHT_CTRL_PRESSED) != 0) { - // Remove Right-Ctrl. - control_key_state &= ~RIGHT_CTRL_PRESSED; - } - } - - // Note that this logic isn't 100% perfect because Windows doesn't - // allow us to detect all combinations because a physical AltGr key - // press shows up as two bits, plus some combinations are ambiguous - // about what is actually physically pressed. - } - - return control_key_state; -} - -// If NumLock is on and Shift is pressed, SHIFT_PRESSED is not set in -// dwControlKeyState for the following keypad keys: period, 0-9. If we detect -// this scenario, set the SHIFT_PRESSED bit so we can add modifiers -// appropriately. -static DWORD _normalize_keypad_control_key_state(const WORD vk, - const DWORD control_key_state) { - if (!_is_numlock_on(control_key_state)) { - return control_key_state; - } - if (!_is_enhanced_key(control_key_state)) { - switch (vk) { - case VK_INSERT: // 0 - case VK_DELETE: // . - case VK_END: // 1 - case VK_DOWN: // 2 - case VK_NEXT: // 3 - case VK_LEFT: // 4 - case VK_CLEAR: // 5 - case VK_RIGHT: // 6 - case VK_HOME: // 7 - case VK_UP: // 8 - case VK_PRIOR: // 9 - return control_key_state | SHIFT_PRESSED; - } - } - - return control_key_state; -} - -static const char* _get_keypad_sequence(const DWORD control_key_state, - const char* const normal, const char* const shifted) { - if (_is_shift_pressed(control_key_state)) { - // Shift is pressed and NumLock is off - return shifted; - } else { - // Shift is not pressed and NumLock is off, or, - // Shift is pressed and NumLock is on, in which case we want the - // NumLock and Shift to neutralize each other, thus, we want the normal - // sequence. - return normal; - } - // If Shift is not pressed and NumLock is on, a different virtual key code - // is returned by Windows, which can be taken care of by a different case - // statement in _console_read(). -} - -// Write sequence to buf and return the number of bytes written. -static size_t _get_modifier_sequence(char* const buf, const WORD vk, - DWORD control_key_state, const char* const normal) { - // Copy the base sequence into buf. - const size_t len = strlen(normal); - memcpy(buf, normal, len); - - int code = 0; - - control_key_state = _normalize_keypad_control_key_state(vk, - control_key_state); - - if (_is_shift_pressed(control_key_state)) { - code |= 0x1; - } - if (_is_alt_pressed(control_key_state)) { // any alt key pressed - code |= 0x2; - } - if (_is_ctrl_pressed(control_key_state)) { // any control key pressed - code |= 0x4; - } - // If some modifier was held down, then we need to insert the modifier code - if (code != 0) { - if (len == 0) { - // Should be impossible because caller should pass a string of - // non-zero length. - return 0; - } - size_t index = len - 1; - const char lastChar = buf[index]; - if (lastChar != '~') { - buf[index++] = '1'; - } - buf[index++] = ';'; // modifier separator - // 2 = shift, 3 = alt, 4 = shift & alt, 5 = control, - // 6 = shift & control, 7 = alt & control, 8 = shift & alt & control - buf[index++] = '1' + code; - buf[index++] = lastChar; // move ~ (or other last char) to the end - return index; - } - return len; -} - -// Write sequence to buf and return the number of bytes written. -static size_t _get_modifier_keypad_sequence(char* const buf, const WORD vk, - const DWORD control_key_state, const char* const normal, - const char shifted) { - if (_is_shift_pressed(control_key_state)) { - // Shift is pressed and NumLock is off - if (shifted != '\0') { - buf[0] = shifted; - return sizeof(buf[0]); - } else { - return 0; - } - } else { - // Shift is not pressed and NumLock is off, or, - // Shift is pressed and NumLock is on, in which case we want the - // NumLock and Shift to neutralize each other, thus, we want the normal - // sequence. - return _get_modifier_sequence(buf, vk, control_key_state, normal); - } - // If Shift is not pressed and NumLock is on, a different virtual key code - // is returned by Windows, which can be taken care of by a different case - // statement in _console_read(). -} - -// The decimal key on the keypad produces a '.' for U.S. English and a ',' for -// Standard German. Figure this out at runtime so we know what to output for -// Shift-VK_DELETE. -static char _get_decimal_char() { - return (char)MapVirtualKeyA(VK_DECIMAL, MAPVK_VK_TO_CHAR); -} - -// Prefix the len bytes in buf with the escape character, and then return the -// new buffer length. -static size_t _escape_prefix(char* const buf, const size_t len) { - // If nothing to prefix, don't do anything. We might be called with - // len == 0, if alt was held down with a dead key which produced nothing. - if (len == 0) { - return 0; - } - - memmove(&buf[1], buf, len); - buf[0] = '\x1b'; - return len + 1; -} - -// Internal buffer to satisfy future _console_read() calls. -static auto& g_console_input_buffer = *new std::vector(); - -// Writes to buffer buf (of length len), returning number of bytes written or -1 on error. Never -// returns zero on console closure because Win32 consoles are never 'closed' (as far as I can tell). -static int _console_read(const HANDLE console, void* buf, size_t len) { - for (;;) { - // Read of zero bytes should not block waiting for something from the console. - if (len == 0) { - return 0; - } - - // Flush as much as possible from input buffer. - if (!g_console_input_buffer.empty()) { - const int bytes_read = std::min(len, g_console_input_buffer.size()); - memcpy(buf, g_console_input_buffer.data(), bytes_read); - const auto begin = g_console_input_buffer.begin(); - g_console_input_buffer.erase(begin, begin + bytes_read); - return bytes_read; - } - - // Read from the actual console. This may block until input. - INPUT_RECORD input_record; - if (!_get_key_event_record(console, &input_record)) { - return -1; - } - - KEY_EVENT_RECORD* const key_event = &input_record.Event.KeyEvent; - const WORD vk = key_event->wVirtualKeyCode; - const CHAR ch = key_event->uChar.AsciiChar; - const DWORD control_key_state = _normalize_altgr_control_key_state( - key_event); - - // The following emulation code should write the output sequence to - // either seqstr or to seqbuf and seqbuflen. - const char* seqstr = nullptr; // NULL terminated C-string - // Enough space for max sequence string below, plus modifiers and/or - // escape prefix. - char seqbuf[16]; - size_t seqbuflen = 0; // Space used in seqbuf. - -#define MATCH(vk, normal) \ - case (vk): \ - { \ - seqstr = (normal); \ - } \ - break; - - // Modifier keys should affect the output sequence. -#define MATCH_MODIFIER(vk, normal) \ - case (vk): \ - { \ - seqbuflen = _get_modifier_sequence(seqbuf, (vk), \ - control_key_state, (normal)); \ - } \ - break; - - // The shift key should affect the output sequence. -#define MATCH_KEYPAD(vk, normal, shifted) \ - case (vk): \ - { \ - seqstr = _get_keypad_sequence(control_key_state, (normal), \ - (shifted)); \ - } \ - break; - - // The shift key and other modifier keys should affect the output - // sequence. -#define MATCH_MODIFIER_KEYPAD(vk, normal, shifted) \ - case (vk): \ - { \ - seqbuflen = _get_modifier_keypad_sequence(seqbuf, (vk), \ - control_key_state, (normal), (shifted)); \ - } \ - break; - -#define ESC "\x1b" -#define CSI ESC "[" -#define SS3 ESC "O" - - // Only support normal mode, not application mode. - - // Enhanced keys: - // * 6-pack: insert, delete, home, end, page up, page down - // * cursor keys: up, down, right, left - // * keypad: divide, enter - // * Undocumented: VK_PAUSE (Ctrl-NumLock), VK_SNAPSHOT, - // VK_CANCEL (Ctrl-Pause/Break), VK_NUMLOCK - if (_is_enhanced_key(control_key_state)) { - switch (vk) { - case VK_RETURN: // Enter key on keypad - if (_is_ctrl_pressed(control_key_state)) { - seqstr = "\n"; - } else { - seqstr = "\r"; - } - break; - - MATCH_MODIFIER(VK_PRIOR, CSI "5~"); // Page Up - MATCH_MODIFIER(VK_NEXT, CSI "6~"); // Page Down - - // gnome-terminal currently sends SS3 "F" and SS3 "H", but that - // will be fixed soon to match xterm which sends CSI "F" and - // CSI "H". https://bugzilla.redhat.com/show_bug.cgi?id=1119764 - MATCH(VK_END, CSI "F"); - MATCH(VK_HOME, CSI "H"); - - MATCH_MODIFIER(VK_LEFT, CSI "D"); - MATCH_MODIFIER(VK_UP, CSI "A"); - MATCH_MODIFIER(VK_RIGHT, CSI "C"); - MATCH_MODIFIER(VK_DOWN, CSI "B"); - - MATCH_MODIFIER(VK_INSERT, CSI "2~"); - MATCH_MODIFIER(VK_DELETE, CSI "3~"); - - MATCH(VK_DIVIDE, "/"); - } - } else { // Non-enhanced keys: - switch (vk) { - case VK_BACK: // backspace - if (_is_alt_pressed(control_key_state)) { - seqstr = ESC "\x7f"; - } else { - seqstr = "\x7f"; - } - break; - - case VK_TAB: - if (_is_shift_pressed(control_key_state)) { - seqstr = CSI "Z"; - } else { - seqstr = "\t"; - } - break; - - // Number 5 key in keypad when NumLock is off, or if NumLock is - // on and Shift is down. - MATCH_KEYPAD(VK_CLEAR, CSI "E", "5"); - - case VK_RETURN: // Enter key on main keyboard - if (_is_alt_pressed(control_key_state)) { - seqstr = ESC "\n"; - } else if (_is_ctrl_pressed(control_key_state)) { - seqstr = "\n"; - } else { - seqstr = "\r"; - } - break; - - // VK_ESCAPE: Don't do any special handling. The OS uses many - // of the sequences with Escape and many of the remaining - // sequences don't produce bKeyDown messages, only !bKeyDown - // for whatever reason. - - case VK_SPACE: - if (_is_alt_pressed(control_key_state)) { - seqstr = ESC " "; - } else if (_is_ctrl_pressed(control_key_state)) { - seqbuf[0] = '\0'; // NULL char - seqbuflen = 1; - } else { - seqstr = " "; - } - break; - - MATCH_MODIFIER_KEYPAD(VK_PRIOR, CSI "5~", '9'); // Page Up - MATCH_MODIFIER_KEYPAD(VK_NEXT, CSI "6~", '3'); // Page Down - - MATCH_KEYPAD(VK_END, CSI "4~", "1"); - MATCH_KEYPAD(VK_HOME, CSI "1~", "7"); - - MATCH_MODIFIER_KEYPAD(VK_LEFT, CSI "D", '4'); - MATCH_MODIFIER_KEYPAD(VK_UP, CSI "A", '8'); - MATCH_MODIFIER_KEYPAD(VK_RIGHT, CSI "C", '6'); - MATCH_MODIFIER_KEYPAD(VK_DOWN, CSI "B", '2'); - - MATCH_MODIFIER_KEYPAD(VK_INSERT, CSI "2~", '0'); - MATCH_MODIFIER_KEYPAD(VK_DELETE, CSI "3~", - _get_decimal_char()); - - case 0x30: // 0 - case 0x31: // 1 - case 0x39: // 9 - case VK_OEM_1: // ;: - case VK_OEM_PLUS: // =+ - case VK_OEM_COMMA: // ,< - case VK_OEM_PERIOD: // .> - case VK_OEM_7: // '" - case VK_OEM_102: // depends on keyboard, could be <> or \| - case VK_OEM_2: // /? - case VK_OEM_3: // `~ - case VK_OEM_4: // [{ - case VK_OEM_5: // \| - case VK_OEM_6: // ]} - { - seqbuflen = _get_control_character(seqbuf, key_event, - control_key_state); - - if (_is_alt_pressed(control_key_state)) { - seqbuflen = _escape_prefix(seqbuf, seqbuflen); - } - } - break; - - case 0x32: // 2 - case 0x33: // 3 - case 0x34: // 4 - case 0x35: // 5 - case 0x36: // 6 - case 0x37: // 7 - case 0x38: // 8 - case VK_OEM_MINUS: // -_ - { - seqbuflen = _get_control_character(seqbuf, key_event, - control_key_state); - - // If Alt is pressed and it isn't Ctrl-Alt-ShiftUp, then - // prefix with escape. - if (_is_alt_pressed(control_key_state) && - !(_is_ctrl_pressed(control_key_state) && - !_is_shift_pressed(control_key_state))) { - seqbuflen = _escape_prefix(seqbuf, seqbuflen); - } - } - break; - - case 0x41: // a - case 0x42: // b - case 0x43: // c - case 0x44: // d - case 0x45: // e - case 0x46: // f - case 0x47: // g - case 0x48: // h - case 0x49: // i - case 0x4a: // j - case 0x4b: // k - case 0x4c: // l - case 0x4d: // m - case 0x4e: // n - case 0x4f: // o - case 0x50: // p - case 0x51: // q - case 0x52: // r - case 0x53: // s - case 0x54: // t - case 0x55: // u - case 0x56: // v - case 0x57: // w - case 0x58: // x - case 0x59: // y - case 0x5a: // z - { - seqbuflen = _get_non_alt_char(seqbuf, key_event, - control_key_state); - - // If Alt is pressed, then prefix with escape. - if (_is_alt_pressed(control_key_state)) { - seqbuflen = _escape_prefix(seqbuf, seqbuflen); - } - } - break; - - // These virtual key codes are generated by the keys on the - // keypad *when NumLock is on* and *Shift is up*. - MATCH(VK_NUMPAD0, "0"); - MATCH(VK_NUMPAD1, "1"); - MATCH(VK_NUMPAD2, "2"); - MATCH(VK_NUMPAD3, "3"); - MATCH(VK_NUMPAD4, "4"); - MATCH(VK_NUMPAD5, "5"); - MATCH(VK_NUMPAD6, "6"); - MATCH(VK_NUMPAD7, "7"); - MATCH(VK_NUMPAD8, "8"); - MATCH(VK_NUMPAD9, "9"); - - MATCH(VK_MULTIPLY, "*"); - MATCH(VK_ADD, "+"); - MATCH(VK_SUBTRACT, "-"); - // VK_DECIMAL is generated by the . key on the keypad *when - // NumLock is on* and *Shift is up* and the sequence is not - // Ctrl-Alt-NoShift-. (which causes Ctrl-Alt-Del and the - // Windows Security screen to come up). - case VK_DECIMAL: - // U.S. English uses '.', Germany German uses ','. - seqbuflen = _get_non_control_char(seqbuf, key_event, - control_key_state); - break; - - MATCH_MODIFIER(VK_F1, SS3 "P"); - MATCH_MODIFIER(VK_F2, SS3 "Q"); - MATCH_MODIFIER(VK_F3, SS3 "R"); - MATCH_MODIFIER(VK_F4, SS3 "S"); - MATCH_MODIFIER(VK_F5, CSI "15~"); - MATCH_MODIFIER(VK_F6, CSI "17~"); - MATCH_MODIFIER(VK_F7, CSI "18~"); - MATCH_MODIFIER(VK_F8, CSI "19~"); - MATCH_MODIFIER(VK_F9, CSI "20~"); - MATCH_MODIFIER(VK_F10, CSI "21~"); - MATCH_MODIFIER(VK_F11, CSI "23~"); - MATCH_MODIFIER(VK_F12, CSI "24~"); - - MATCH_MODIFIER(VK_F13, CSI "25~"); - MATCH_MODIFIER(VK_F14, CSI "26~"); - MATCH_MODIFIER(VK_F15, CSI "28~"); - MATCH_MODIFIER(VK_F16, CSI "29~"); - MATCH_MODIFIER(VK_F17, CSI "31~"); - MATCH_MODIFIER(VK_F18, CSI "32~"); - MATCH_MODIFIER(VK_F19, CSI "33~"); - MATCH_MODIFIER(VK_F20, CSI "34~"); - - // MATCH_MODIFIER(VK_F21, ???); - // MATCH_MODIFIER(VK_F22, ???); - // MATCH_MODIFIER(VK_F23, ???); - // MATCH_MODIFIER(VK_F24, ???); - } - } - -#undef MATCH -#undef MATCH_MODIFIER -#undef MATCH_KEYPAD -#undef MATCH_MODIFIER_KEYPAD -#undef ESC -#undef CSI -#undef SS3 - - const char* out; - size_t outlen; - - // Check for output in any of: - // * seqstr is set (and strlen can be used to determine the length). - // * seqbuf and seqbuflen are set - // Fallback to ch from Windows. - if (seqstr != nullptr) { - out = seqstr; - outlen = strlen(seqstr); - } else if (seqbuflen > 0) { - out = seqbuf; - outlen = seqbuflen; - } else if (ch != '\0') { - // Use whatever Windows told us it is. - seqbuf[0] = ch; - seqbuflen = 1; - out = seqbuf; - outlen = seqbuflen; - } else { - // No special handling for the virtual key code and Windows isn't - // telling us a character code, then we don't know how to translate - // the key press. - // - // Consume the input and 'continue' to cause us to get a new key - // event. - D("_console_read: unknown virtual key code: %d, enhanced: %s", - vk, _is_enhanced_key(control_key_state) ? "true" : "false"); - continue; - } - - // put output wRepeatCount times into g_console_input_buffer - while (key_event->wRepeatCount-- > 0) { - g_console_input_buffer.insert(g_console_input_buffer.end(), out, out + outlen); - } - - // Loop around and try to flush g_console_input_buffer - } -} - -static DWORD _old_console_mode; // previous GetConsoleMode() result -static HANDLE _console_handle; // when set, console mode should be restored - -void stdin_raw_init() { - const HANDLE in = _get_console_handle(STDIN_FILENO, &_old_console_mode); - if (in == nullptr) { - return; - } - - // Disable ENABLE_PROCESSED_INPUT so that Ctrl-C is read instead of - // calling the process Ctrl-C routine (configured by - // SetConsoleCtrlHandler()). - // Disable ENABLE_LINE_INPUT so that input is immediately sent. - // Disable ENABLE_ECHO_INPUT to disable local echo. Disabling this - // flag also seems necessary to have proper line-ending processing. - DWORD new_console_mode = _old_console_mode & ~(ENABLE_PROCESSED_INPUT | - ENABLE_LINE_INPUT | - ENABLE_ECHO_INPUT); - // Enable ENABLE_WINDOW_INPUT to get window resizes. - new_console_mode |= ENABLE_WINDOW_INPUT; - - if (!SetConsoleMode(in, new_console_mode)) { - // This really should not fail. - D("stdin_raw_init: SetConsoleMode() failed: %s", - android::base::SystemErrorCodeToString(GetLastError()).c_str()); - } - - // Once this is set, it means that stdin has been configured for - // reading from and that the old console mode should be restored later. - _console_handle = in; - - // Note that we don't need to configure C Runtime line-ending - // translation because _console_read() does not call the C Runtime to - // read from the console. -} - -void stdin_raw_restore() { - if (_console_handle != nullptr) { - const HANDLE in = _console_handle; - _console_handle = nullptr; // clear state - - if (!SetConsoleMode(in, _old_console_mode)) { - // This really should not fail. - D("stdin_raw_restore: SetConsoleMode() failed: %s", - android::base::SystemErrorCodeToString(GetLastError()).c_str()); - } - } -} - -// Called by 'adb shell' and 'adb exec-in' (via unix_read()) to read from stdin. -int unix_read_interruptible(borrowed_fd fd, void* buf, size_t len) { - if ((fd == STDIN_FILENO) && (_console_handle != nullptr)) { - // If it is a request to read from stdin, and stdin_raw_init() has been - // called, and it successfully configured the console, then read from - // the console using Win32 console APIs and partially emulate a unix - // terminal. - return _console_read(_console_handle, buf, len); - } else { - // On older versions of Windows (definitely 7, definitely not 10), - // ReadConsole() with a size >= 31367 fails, so if |fd| is a console - // we need to limit the read size. - if (len > 4096 && unix_isatty(fd)) { - len = 4096; - } - // Just call into C Runtime which can read from pipes/files and which - // can do LF/CR translation (which is overridable with _setmode()). - // Undefine the macro that is set in sysdeps.h which bans calls to - // plain read() in favor of unix_read() or adb_read(). -#pragma push_macro("read") -#undef read - return read(fd.get(), buf, len); -#pragma pop_macro("read") - } -} - -/**************************************************************************/ -/**************************************************************************/ -/***** *****/ -/***** Unicode support *****/ -/***** *****/ -/**************************************************************************/ -/**************************************************************************/ - -// This implements support for using files with Unicode filenames and for -// outputting Unicode text to a Win32 console window. This is inspired from -// http://utf8everywhere.org/. -// -// Background -// ---------- -// -// On POSIX systems, to deal with files with Unicode filenames, just pass UTF-8 -// filenames to APIs such as open(). This works because filenames are largely -// opaque 'cookies' (perhaps excluding path separators). -// -// On Windows, the native file APIs such as CreateFileW() take 2-byte wchar_t -// UTF-16 strings. There is an API, CreateFileA() that takes 1-byte char -// strings, but the strings are in the ANSI codepage and not UTF-8. (The -// CreateFile() API is really just a macro that adds the W/A based on whether -// the UNICODE preprocessor symbol is defined). -// -// Options -// ------- -// -// Thus, to write a portable program, there are a few options: -// -// 1. Write the program with wchar_t filenames (wchar_t path[256];). -// For Windows, just call CreateFileW(). For POSIX, write a wrapper openW() -// that takes a wchar_t string, converts it to UTF-8 and then calls the real -// open() API. -// -// 2. Write the program with a TCHAR typedef that is 2 bytes on Windows and -// 1 byte on POSIX. Make T-* wrappers for various OS APIs and call those, -// potentially touching a lot of code. -// -// 3. Write the program with a 1-byte char filenames (char path[256];) that are -// UTF-8. For POSIX, just call open(). For Windows, write a wrapper that -// takes a UTF-8 string, converts it to UTF-16 and then calls the real OS -// or C Runtime API. -// -// The Choice -// ---------- -// -// The code below chooses option 3, the UTF-8 everywhere strategy. It uses -// android::base::WideToUTF8() which converts UTF-16 to UTF-8. This is used by the -// NarrowArgs helper class that is used to convert wmain() args into UTF-8 -// args that are passed to main() at the beginning of program startup. We also use -// android::base::UTF8ToWide() which converts from UTF-8 to UTF-16. This is used to -// implement wrappers below that call UTF-16 OS and C Runtime APIs. -// -// Unicode console output -// ---------------------- -// -// The way to output Unicode to a Win32 console window is to call -// WriteConsoleW() with UTF-16 text. (The user must also choose a proper font -// such as Lucida Console or Consolas, and in the case of East Asian languages -// (such as Chinese, Japanese, Korean), the user must go to the Control Panel -// and change the "system locale" to Chinese, etc., which allows a Chinese, etc. -// font to be used in console windows.) -// -// The problem is getting the C Runtime to make fprintf and related APIs call -// WriteConsoleW() under the covers. The C Runtime API, _setmode() sounds -// promising, but the various modes have issues: -// -// 1. _setmode(_O_TEXT) (the default) does not use WriteConsoleW() so UTF-8 and -// UTF-16 do not display properly. -// 2. _setmode(_O_BINARY) does not use WriteConsoleW() and the text comes out -// totally wrong. -// 3. _setmode(_O_U8TEXT) seems to cause the C Runtime _invalid_parameter -// handler to be called (upon a later I/O call), aborting the process. -// 4. _setmode(_O_U16TEXT) and _setmode(_O_WTEXT) cause non-wide printf/fprintf -// to output nothing. -// -// So the only solution is to write our own adb_fprintf() that converts UTF-8 -// to UTF-16 and then calls WriteConsoleW(). - - -// Constructor for helper class to convert wmain() UTF-16 args to UTF-8 to -// be passed to main(). -NarrowArgs::NarrowArgs(const int argc, wchar_t** const argv) { - narrow_args = new char*[argc + 1]; - - for (int i = 0; i < argc; ++i) { - std::string arg_narrow; - if (!android::base::WideToUTF8(argv[i], &arg_narrow)) { - PLOG(FATAL) << "cannot convert argument from UTF-16 to UTF-8"; - } - narrow_args[i] = strdup(arg_narrow.c_str()); - } - narrow_args[argc] = nullptr; // terminate -} - -NarrowArgs::~NarrowArgs() { - if (narrow_args != nullptr) { - for (char** argp = narrow_args; *argp != nullptr; ++argp) { - free(*argp); - } - delete[] narrow_args; - narrow_args = nullptr; - } -} - -int unix_open(std::string_view path, int options, ...) { - std::wstring path_wide; - if (!android::base::UTF8ToWide(path.data(), path.size(), &path_wide)) { - return -1; - } - if ((options & O_CREAT) == 0) { - return _wopen(path_wide.c_str(), options); - } else { - int mode; - va_list args; - va_start(args, options); - mode = va_arg(args, int); - va_end(args); - return _wopen(path_wide.c_str(), options, mode); - } -} - -// Version of opendir() that takes a UTF-8 path. -DIR* adb_opendir(const char* path) { - std::wstring path_wide; - if (!android::base::UTF8ToWide(path, &path_wide)) { - return nullptr; - } - - // Just cast _WDIR* to DIR*. This doesn't work if the caller reads any of - // the fields, but right now all the callers treat the structure as - // opaque. - return reinterpret_cast(_wopendir(path_wide.c_str())); -} - -// Version of readdir() that returns UTF-8 paths. -struct dirent* adb_readdir(DIR* dir) { - _WDIR* const wdir = reinterpret_cast<_WDIR*>(dir); - struct _wdirent* const went = _wreaddir(wdir); - if (went == nullptr) { - return nullptr; - } - - // Convert from UTF-16 to UTF-8. - std::string name_utf8; - if (!android::base::WideToUTF8(went->d_name, &name_utf8)) { - return nullptr; - } - - // Cast the _wdirent* to dirent* and overwrite the d_name field (which has - // space for UTF-16 wchar_t's) with UTF-8 char's. - struct dirent* ent = reinterpret_cast(went); - - if (name_utf8.length() + 1 > sizeof(went->d_name)) { - // Name too big to fit in existing buffer. - errno = ENOMEM; - return nullptr; - } - - // Note that sizeof(_wdirent::d_name) is bigger than sizeof(dirent::d_name) - // because _wdirent contains wchar_t instead of char. So even if name_utf8 - // can fit in _wdirent::d_name, the resulting dirent::d_name field may be - // bigger than the caller expects because they expect a dirent structure - // which has a smaller d_name field. Ignore this since the caller should be - // resilient. - - // Rewrite the UTF-16 d_name field to UTF-8. - strcpy(ent->d_name, name_utf8.c_str()); - - return ent; -} - -// Version of closedir() to go with our version of adb_opendir(). -int adb_closedir(DIR* dir) { - return _wclosedir(reinterpret_cast<_WDIR*>(dir)); -} - -// Version of unlink() that takes a UTF-8 path. -int adb_unlink(const char* path) { - std::wstring wpath; - if (!android::base::UTF8ToWide(path, &wpath)) { - return -1; - } - - int rc = _wunlink(wpath.c_str()); - - 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 = _wchmod(wpath.c_str(), _S_IREAD | _S_IWRITE); - if (rc == 0) - rc = _wunlink(wpath.c_str()); - } - return rc; -} - -// Version of mkdir() that takes a UTF-8 path. -int adb_mkdir(const std::string& path, int mode) { - std::wstring path_wide; - if (!android::base::UTF8ToWide(path, &path_wide)) { - return -1; - } - - return _wmkdir(path_wide.c_str()); -} - -int adb_rename(const char* oldpath, const char* newpath) { - std::wstring oldpath_wide, newpath_wide; - if (!android::base::UTF8ToWide(oldpath, &oldpath_wide)) { - return -1; - } - if (!android::base::UTF8ToWide(newpath, &newpath_wide)) { - return -1; - } - - // MSDN just says the return value is non-zero on failure, make sure it - // returns -1 on failure so that it behaves the same as other systems. - return _wrename(oldpath_wide.c_str(), newpath_wide.c_str()) ? -1 : 0; -} - -// Version of utime() that takes a UTF-8 path. -int adb_utime(const char* path, struct utimbuf* u) { - std::wstring path_wide; - if (!android::base::UTF8ToWide(path, &path_wide)) { - return -1; - } - - static_assert(sizeof(struct utimbuf) == sizeof(struct _utimbuf), - "utimbuf and _utimbuf should be the same size because they both " - "contain the same types, namely time_t"); - return _wutime(path_wide.c_str(), reinterpret_cast(u)); -} - -// Version of chmod() that takes a UTF-8 path. -int adb_chmod(const char* path, int mode) { - std::wstring path_wide; - if (!android::base::UTF8ToWide(path, &path_wide)) { - return -1; - } - - return _wchmod(path_wide.c_str(), mode); -} - -// From libutils/Unicode.cpp, get the length of a UTF-8 sequence given the lead byte. -static inline size_t utf8_codepoint_len(uint8_t ch) { - return ((0xe5000000 >> ((ch >> 3) & 0x1e)) & 3) + 1; -} - -namespace internal { - -// Given a sequence of UTF-8 bytes (denoted by the range [first, last)), return the number of bytes -// (from the beginning) that are complete UTF-8 sequences and append the remaining bytes to -// remaining_bytes. -size_t ParseCompleteUTF8(const char* const first, const char* const last, - std::vector* const remaining_bytes) { - // Walk backwards from the end of the sequence looking for the beginning of a UTF-8 sequence. - // Current_after points one byte past the current byte to be examined. - for (const char* current_after = last; current_after != first; --current_after) { - const char* const current = current_after - 1; - const char ch = *current; - const char kHighBit = 0x80u; - const char kTwoHighestBits = 0xC0u; - if ((ch & kHighBit) == 0) { // high bit not set - // The buffer ends with a one-byte UTF-8 sequence, possibly followed by invalid trailing - // bytes with no leading byte, so return the entire buffer. - break; - } else if ((ch & kTwoHighestBits) == kTwoHighestBits) { // top two highest bits set - // Lead byte in UTF-8 sequence, so check if we have all the bytes in the sequence. - const size_t bytes_available = last - current; - if (bytes_available < utf8_codepoint_len(ch)) { - // We don't have all the bytes in the UTF-8 sequence, so return all the bytes - // preceding the current incomplete UTF-8 sequence and append the remaining bytes - // to remaining_bytes. - remaining_bytes->insert(remaining_bytes->end(), current, last); - return current - first; - } else { - // The buffer ends with a complete UTF-8 sequence, possibly followed by invalid - // trailing bytes with no lead byte, so return the entire buffer. - break; - } - } else { - // Trailing byte, so keep going backwards looking for the lead byte. - } - } - - // Return the size of the entire buffer. It is possible that we walked backward past invalid - // trailing bytes with no lead byte, in which case we want to return all those invalid bytes - // so that they can be processed. - return last - first; -} - -} - -// Bytes that have not yet been output to the console because they are incomplete UTF-8 sequences. -// Note that we use only one buffer even though stderr and stdout are logically separate streams. -// This matches the behavior of Linux. - -// Internal helper function to write UTF-8 bytes to a console. Returns -1 on error. -static int _console_write_utf8(const char* const buf, const size_t buf_size, FILE* stream, - HANDLE console) { - static std::mutex& console_output_buffer_lock = *new std::mutex(); - static auto& console_output_buffer = *new std::vector(); - - const int saved_errno = errno; - std::vector combined_buffer; - - // Complete UTF-8 sequences that should be immediately written to the console. - const char* utf8; - size_t utf8_size; - - { - std::lock_guard lock(console_output_buffer_lock); - if (console_output_buffer.empty()) { - // If console_output_buffer doesn't have a buffered up incomplete UTF-8 sequence (the - // common case with plain ASCII), parse buf directly. - utf8 = buf; - utf8_size = internal::ParseCompleteUTF8(buf, buf + buf_size, &console_output_buffer); - } else { - // If console_output_buffer has a buffered up incomplete UTF-8 sequence, move it to - // combined_buffer (and effectively clear console_output_buffer) and append buf to - // combined_buffer, then parse it all together. - combined_buffer.swap(console_output_buffer); - combined_buffer.insert(combined_buffer.end(), buf, buf + buf_size); - - utf8 = combined_buffer.data(); - utf8_size = internal::ParseCompleteUTF8(utf8, utf8 + combined_buffer.size(), - &console_output_buffer); - } - } - - std::wstring utf16; - - // Try to convert from data that might be UTF-8 to UTF-16, ignoring errors (just like Linux - // which does not return an error on bad UTF-8). Data might not be UTF-8 if the user cat's - // random data, runs dmesg (which might have non-UTF-8), etc. - // This could throw std::bad_alloc. - (void)android::base::UTF8ToWide(utf8, utf8_size, &utf16); - - // Note that this does not do \n => \r\n translation because that - // doesn't seem necessary for the Windows console. For the Windows - // console \r moves to the beginning of the line and \n moves to a new - // line. - - // Flush any stream buffering so that our output is afterwards which - // makes sense because our call is afterwards. - (void)fflush(stream); - - // Write UTF-16 to the console. - DWORD written = 0; - if (!WriteConsoleW(console, utf16.c_str(), utf16.length(), &written, nullptr)) { - errno = EIO; - return -1; - } - - // Return the size of the original buffer passed in, signifying that we consumed it all, even - // if nothing was displayed, in the case of being passed an incomplete UTF-8 sequence. This - // matches the Linux behavior. - errno = saved_errno; - return buf_size; -} - -// Function prototype because attributes cannot be placed on func definitions. -static int _console_vfprintf(const HANDLE console, FILE* stream, const char* format, va_list ap) - __attribute__((__format__(__printf__, 3, 0))); - -// Internal function to format a UTF-8 string and write it to a Win32 console. -// Returns -1 on error. -static int _console_vfprintf(const HANDLE console, FILE* stream, - const char *format, va_list ap) { - const int saved_errno = errno; - std::string output_utf8; - - // Format the string. - // This could throw std::bad_alloc. - android::base::StringAppendV(&output_utf8, format, ap); - - const int result = _console_write_utf8(output_utf8.c_str(), output_utf8.length(), stream, - console); - if (result != -1) { - errno = saved_errno; - } else { - // If -1 was returned, errno has been set. - } - return result; -} - -// Version of vfprintf() that takes UTF-8 and can write Unicode to a -// Windows console. -int adb_vfprintf(FILE *stream, const char *format, va_list ap) { - const HANDLE console = _get_console_handle(stream); - - // If there is an associated Win32 console, write to it specially, - // otherwise defer to the regular C Runtime, passing it UTF-8. - if (console != nullptr) { - return _console_vfprintf(console, stream, format, ap); - } else { - // If vfprintf is a macro, undefine it, so we can call the real - // C Runtime API. -#pragma push_macro("vfprintf") -#undef vfprintf - return vfprintf(stream, format, ap); -#pragma pop_macro("vfprintf") - } -} - -// Version of vprintf() that takes UTF-8 and can write Unicode to a Windows console. -int adb_vprintf(const char *format, va_list ap) { - return adb_vfprintf(stdout, format, ap); -} - -// Version of fprintf() that takes UTF-8 and can write Unicode to a -// Windows console. -int adb_fprintf(FILE *stream, const char *format, ...) { - va_list ap; - va_start(ap, format); - const int result = adb_vfprintf(stream, format, ap); - va_end(ap); - - return result; -} - -// Version of printf() that takes UTF-8 and can write Unicode to a -// Windows console. -int adb_printf(const char *format, ...) { - va_list ap; - va_start(ap, format); - const int result = adb_vfprintf(stdout, format, ap); - va_end(ap); - - return result; -} - -// Version of fputs() that takes UTF-8 and can write Unicode to a -// Windows console. -int adb_fputs(const char* buf, FILE* stream) { - // adb_fprintf returns -1 on error, which is conveniently the same as EOF - // which fputs (and hence adb_fputs) should return on error. - static_assert(EOF == -1, "EOF is not -1, so this code needs to be fixed"); - return adb_fprintf(stream, "%s", buf); -} - -// Version of fputc() that takes UTF-8 and can write Unicode to a -// Windows console. -int adb_fputc(int ch, FILE* stream) { - const int result = adb_fprintf(stream, "%c", ch); - if (result == -1) { - return EOF; - } - // For success, fputc returns the char, cast to unsigned char, then to int. - return static_cast(ch); -} - -// Version of putchar() that takes UTF-8 and can write Unicode to a Windows console. -int adb_putchar(int ch) { - return adb_fputc(ch, stdout); -} - -// Version of puts() that takes UTF-8 and can write Unicode to a Windows console. -int adb_puts(const char* buf) { - // adb_printf returns -1 on error, which is conveniently the same as EOF - // which puts (and hence adb_puts) should return on error. - static_assert(EOF == -1, "EOF is not -1, so this code needs to be fixed"); - return adb_printf("%s\n", buf); -} - -// Internal function to write UTF-8 to a Win32 console. Returns the number of -// items (of length size) written. On error, returns a short item count or 0. -static size_t _console_fwrite(const void* ptr, size_t size, size_t nmemb, - FILE* stream, HANDLE console) { - const int result = _console_write_utf8(reinterpret_cast(ptr), size * nmemb, stream, - console); - if (result == -1) { - return 0; - } - return result / size; -} - -// Version of fwrite() that takes UTF-8 and can write Unicode to a -// Windows console. -size_t adb_fwrite(const void* ptr, size_t size, size_t nmemb, FILE* stream) { - const HANDLE console = _get_console_handle(stream); - - // If there is an associated Win32 console, write to it specially, - // otherwise defer to the regular C Runtime, passing it UTF-8. - if (console != nullptr) { - return _console_fwrite(ptr, size, nmemb, stream, console); - } else { - // If fwrite is a macro, undefine it, so we can call the real - // C Runtime API. -#pragma push_macro("fwrite") -#undef fwrite - return fwrite(ptr, size, nmemb, stream); -#pragma pop_macro("fwrite") - } -} - -// Version of fopen() that takes a UTF-8 filename and can access a file with -// a Unicode filename. -FILE* adb_fopen(const char* path, const char* mode) { - std::wstring path_wide; - if (!android::base::UTF8ToWide(path, &path_wide)) { - return nullptr; - } - - std::wstring mode_wide; - if (!android::base::UTF8ToWide(mode, &mode_wide)) { - return nullptr; - } - - return _wfopen(path_wide.c_str(), mode_wide.c_str()); -} - -// Return a lowercase version of the argument. Uses C Runtime tolower() on -// each byte which is not UTF-8 aware, and theoretically uses the current C -// Runtime locale (which in practice is not changed, so this becomes a ASCII -// conversion). -static std::string ToLower(const std::string& anycase) { - // copy string - std::string str(anycase); - // transform the copy - std::transform(str.begin(), str.end(), str.begin(), tolower); - return str; -} - -extern "C" int main(int argc, char** argv); - -// Link with -municode to cause this wmain() to be used as the program -// entrypoint. It will convert the args from UTF-16 to UTF-8 and call the -// regular main() with UTF-8 args. -extern "C" int wmain(int argc, wchar_t **argv) { - // Convert args from UTF-16 to UTF-8 and pass that to main(). - NarrowArgs narrow_args(argc, argv); - - // Avoid destructing NarrowArgs: argv might have been mutated to point to string literals. - _exit(main(argc, narrow_args.data())); -} - -// Shadow UTF-8 environment variable name/value pairs that are created from -// _wenviron by _init_env(). Note that this is not currently updated if putenv, setenv, unsetenv are -// called. Note that no thread synchronization is done, but we're called early enough in -// single-threaded startup that things work ok. -static auto& g_environ_utf8 = *new std::unordered_map(); - -// Setup shadow UTF-8 environment variables. -static void _init_env() { - // If some name/value pairs exist, then we've already done the setup below. - if (g_environ_utf8.size() != 0) { - return; - } - - if (_wenviron == nullptr) { - // If _wenviron is null, then -municode probably wasn't used. That - // linker flag will cause the entry point to setup _wenviron. It will - // also require an implementation of wmain() (which we provide above). - LOG(FATAL) << "_wenviron is not set, did you link with -municode?"; - } - - // Read name/value pairs from UTF-16 _wenviron and write new name/value - // pairs to UTF-8 g_environ_utf8. Note that it probably does not make sense - // to use the D() macro here because that tracing only works if the - // ADB_TRACE environment variable is setup, but that env var can't be read - // until this code completes. - for (wchar_t** env = _wenviron; *env != nullptr; ++env) { - wchar_t* const equal = wcschr(*env, L'='); - if (equal == nullptr) { - // Malformed environment variable with no equal sign. Shouldn't - // really happen, but we should be resilient to this. - continue; - } - - // If we encounter an error converting UTF-16, don't error-out on account of a single env - // var because the program might never even read this particular variable. - std::string name_utf8; - if (!android::base::WideToUTF8(*env, equal - *env, &name_utf8)) { - continue; - } - - // Store lowercase name so that we can do case-insensitive searches. - name_utf8 = ToLower(name_utf8); - - std::string value_utf8; - if (!android::base::WideToUTF8(equal + 1, &value_utf8)) { - continue; - } - - char* const value_dup = strdup(value_utf8.c_str()); - - // Don't overwrite a previus env var with the same name. In reality, - // the system probably won't let two env vars with the same name exist - // in _wenviron. - g_environ_utf8.insert({name_utf8, value_dup}); - } -} - -// Version of getenv() that takes a UTF-8 environment variable name and -// retrieves a UTF-8 value. Case-insensitive to match getenv() on Windows. -char* adb_getenv(const char* name) { - // Case-insensitive search by searching for lowercase name in a map of - // lowercase names. - const auto it = g_environ_utf8.find(ToLower(std::string(name))); - if (it == g_environ_utf8.end()) { - return nullptr; - } - - return it->second; -} - -// Version of getcwd() that returns the current working directory in UTF-8. -char* adb_getcwd(char* buf, int size) { - wchar_t* wbuf = _wgetcwd(nullptr, 0); - if (wbuf == nullptr) { - return nullptr; - } - - std::string buf_utf8; - const bool narrow_result = android::base::WideToUTF8(wbuf, &buf_utf8); - free(wbuf); - wbuf = nullptr; - - if (!narrow_result) { - return nullptr; - } - - // If size was specified, make sure all the chars will fit. - if (size != 0) { - if (size < static_cast(buf_utf8.length() + 1)) { - errno = ERANGE; - return nullptr; - } - } - - // If buf was not specified, allocate storage. - if (buf == nullptr) { - if (size == 0) { - size = buf_utf8.length() + 1; - } - buf = reinterpret_cast(malloc(size)); - if (buf == nullptr) { - return nullptr; - } - } - - // Destination buffer was allocated with enough space, or we've already - // checked an existing buffer size for enough space. - strcpy(buf, buf_utf8.c_str()); - - return buf; -} - -void enable_inherit(borrowed_fd fd) { - auto osh = adb_get_os_handle(fd); - const auto h = reinterpret_cast(osh); - ::SetHandleInformation(h, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); -} - -void disable_inherit(borrowed_fd fd) { - auto osh = adb_get_os_handle(fd); - const auto h = reinterpret_cast(osh); - ::SetHandleInformation(h, HANDLE_FLAG_INHERIT, 0); -} - -Process adb_launch_process(std::string_view executable, std::vector args, - std::initializer_list fds_to_inherit) { - std::wstring wexe; - if (!android::base::UTF8ToWide(executable.data(), executable.size(), &wexe)) { - return Process(); - } - - std::wstring wargs = L"\"" + wexe + L"\""; - std::wstring warg; - for (auto arg : args) { - warg.clear(); - if (!android::base::UTF8ToWide(arg.data(), arg.size(), &warg)) { - return Process(); - } - wargs += L" \""; - wargs += warg; - wargs += L'\"'; - } - - STARTUPINFOW sinfo = {sizeof(sinfo)}; - PROCESS_INFORMATION pinfo = {}; - - // TODO: use the Vista+ API to pass the list of inherited handles explicitly; - // see http://blogs.msdn.com/b/oldnewthing/archive/2011/12/16/10248328.aspx - for (auto fd : fds_to_inherit) { - enable_inherit(fd); - } - const auto created = CreateProcessW(wexe.c_str(), wargs.data(), - nullptr, // process attributes - nullptr, // thread attributes - fds_to_inherit.size() > 0, // inherit any handles? - 0, // flags - nullptr, // environment - nullptr, // current directory - &sinfo, // startup info - &pinfo); - for (auto fd : fds_to_inherit) { - disable_inherit(fd); - } - - if (!created) { - return Process(); - } - - ::CloseHandle(pinfo.hThread); - return Process(pinfo.hProcess); -} - -// The SetThreadDescription API was brought in version 1607 of Windows 10. -typedef HRESULT(WINAPI* SetThreadDescription)(HANDLE hThread, PCWSTR lpThreadDescription); - -// Based on PlatformThread::SetName() from -// https://cs.chromium.org/chromium/src/base/threading/platform_thread_win.cc -int adb_thread_setname(const std::string& name) { - // The SetThreadDescription API works even if no debugger is attached. - auto set_thread_description_func = reinterpret_cast( - ::GetProcAddress(::GetModuleHandleW(L"Kernel32.dll"), "SetThreadDescription")); - if (set_thread_description_func) { - std::wstring name_wide; - if (!android::base::UTF8ToWide(name.c_str(), &name_wide)) { - return errno; - } - set_thread_description_func(::GetCurrentThread(), name_wide.c_str()); - } - - // Don't use the thread naming SEH exception because we're compiled with -fno-exceptions. - // https://docs.microsoft.com/en-us/visualstudio/debugger/how-to-set-a-thread-name-in-native-code?view=vs-2017 - - return 0; -} - -#if !defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING) -#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 -#endif - -#if !defined(DISABLE_NEWLINE_AUTO_RETURN) -#define DISABLE_NEWLINE_AUTO_RETURN 0x0008 -#endif - -static void _init_console() { - DWORD old_out_console_mode; - - const HANDLE out = _get_console_handle(STDOUT_FILENO, &old_out_console_mode); - if (out == nullptr) { - return; - } - - // Try to use ENABLE_VIRTUAL_TERMINAL_PROCESSING on the output console to process virtual - // terminal sequences on newer versions of Windows 10 and later. - // https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences - // On older OSes that don't support the flag, SetConsoleMode() will return an error. - // ENABLE_VIRTUAL_TERMINAL_PROCESSING also solves a problem where the last column of the - // console cannot be overwritten. - // - // Note that we don't use DISABLE_NEWLINE_AUTO_RETURN because it doesn't seem to be necessary. - // If we use DISABLE_NEWLINE_AUTO_RETURN, _console_write_utf8() would need to be modified to - // translate \n to \r\n. - if (!SetConsoleMode(out, old_out_console_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING)) { - return; - } - - // If SetConsoleMode() succeeded, the console supports virtual terminal processing, so we - // should set the TERM env var to match so that it will be propagated to adbd on devices. - // - // Below's direct manipulation of env vars and not g_environ_utf8 assumes that _init_env() has - // not yet been called. If this fails, _init_env() should be called after _init_console(). - if (g_environ_utf8.size() > 0) { - LOG(FATAL) << "environment variables have already been converted to UTF-8"; - } - -#pragma push_macro("getenv") -#undef getenv -#pragma push_macro("putenv") -#undef putenv - if (getenv("TERM") == nullptr) { - // This is the same TERM value used by Gnome Terminal and the version of ssh included with - // Windows. - putenv("TERM=xterm-256color"); - } -#pragma pop_macro("putenv") -#pragma pop_macro("getenv") -} - -static bool _init_sysdeps() { - // _init_console() depends on _init_env() not being called yet. - _init_console(); - _init_env(); - _init_winsock(); - return true; -} - -static bool _sysdeps_init = _init_sysdeps(); diff --git a/adb/sysdeps_win32_test.cpp b/adb/sysdeps_win32_test.cpp deleted file mode 100644 index 183cd5b59d6213b1c40040d86c71054cfdb24e61..0000000000000000000000000000000000000000 --- a/adb/sysdeps_win32_test.cpp +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright (C) 2015 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 "sysdeps.h" - -#include - -TEST(sysdeps_win32, adb_getenv) { - // Insert all test env vars before first call to adb_getenv() which will - // read the env var block only once. - ASSERT_EQ(0, _putenv("SYSDEPS_WIN32_TEST_UPPERCASE=1")); - ASSERT_EQ(0, _putenv("sysdeps_win32_test_lowercase=2")); - ASSERT_EQ(0, _putenv("Sysdeps_Win32_Test_MixedCase=3")); - - // UTF-16 value - ASSERT_EQ(0, _wputenv(L"SYSDEPS_WIN32_TEST_UNICODE=\u00a1\u0048\u006f\u006c" - L"\u0061\u0021\u03b1\u03b2\u03b3\u0061\u006d\u0062" - L"\u0075\u006c\u014d\u043f\u0440\u0438\u0432\u0435" - L"\u0442")); - - // Search for non-existant env vars. - EXPECT_STREQ(nullptr, adb_getenv("SYSDEPS_WIN32_TEST_NONEXISTANT")); - - // Search for existing env vars. - - // There is no test for an env var with a value of a zero-length string - // because _putenv() does not support inserting such an env var. - - // Search for env var that is uppercase. - EXPECT_STREQ("1", adb_getenv("SYSDEPS_WIN32_TEST_UPPERCASE")); - EXPECT_STREQ("1", adb_getenv("sysdeps_win32_test_uppercase")); - EXPECT_STREQ("1", adb_getenv("Sysdeps_Win32_Test_Uppercase")); - - // Search for env var that is lowercase. - EXPECT_STREQ("2", adb_getenv("SYSDEPS_WIN32_TEST_LOWERCASE")); - EXPECT_STREQ("2", adb_getenv("sysdeps_win32_test_lowercase")); - EXPECT_STREQ("2", adb_getenv("Sysdeps_Win32_Test_Lowercase")); - - // Search for env var that is mixed-case. - EXPECT_STREQ("3", adb_getenv("SYSDEPS_WIN32_TEST_MIXEDCASE")); - EXPECT_STREQ("3", adb_getenv("sysdeps_win32_test_mixedcase")); - EXPECT_STREQ("3", adb_getenv("Sysdeps_Win32_Test_MixedCase")); - - // Check that UTF-16 was converted to UTF-8. - EXPECT_STREQ("\xc2\xa1\x48\x6f\x6c\x61\x21\xce\xb1\xce\xb2\xce\xb3\x61\x6d" - "\x62\x75\x6c\xc5\x8d\xd0\xbf\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5" - "\xd1\x82", - adb_getenv("SYSDEPS_WIN32_TEST_UNICODE")); - - // Check an env var that should always be set. - const char* path_val = adb_getenv("PATH"); - EXPECT_NE(nullptr, path_val); - if (path_val != nullptr) { - EXPECT_GT(strlen(path_val), 0U); - } -} - -TEST(sysdeps_win32, unix_isatty) { - // stdin and stdout should be consoles. Use CONIN$ and CONOUT$ special files - // so that we can test this even if stdin/stdout have been redirected. Read - // permissions are required for unix_isatty(). - int conin_fd = unix_open("CONIN$", O_RDONLY); - int conout_fd = unix_open("CONOUT$", O_RDWR); - for (const int fd : {conin_fd, conout_fd}) { - EXPECT_TRUE(fd >= 0); - EXPECT_EQ(1, unix_isatty(fd)); - EXPECT_EQ(0, unix_close(fd)); - } - - // nul returns 1 from isatty(), make sure unix_isatty() corrects that. - for (auto flags : {O_RDONLY, O_RDWR}) { - int nul_fd = unix_open("nul", flags); - EXPECT_TRUE(nul_fd >= 0); - EXPECT_EQ(0, unix_isatty(nul_fd)); - EXPECT_EQ(0, unix_close(nul_fd)); - } - - // Check a real file, both read-write and read-only. - TemporaryFile temp_file; - EXPECT_TRUE(temp_file.fd >= 0); - EXPECT_EQ(0, unix_isatty(temp_file.fd)); - - int temp_file_ro_fd = unix_open(temp_file.path, O_RDONLY); - EXPECT_TRUE(temp_file_ro_fd >= 0); - EXPECT_EQ(0, unix_isatty(temp_file_ro_fd)); - EXPECT_EQ(0, unix_close(temp_file_ro_fd)); - - // Check a real OS pipe. - int pipe_fds[2]; - EXPECT_EQ(0, _pipe(pipe_fds, 64, _O_BINARY)); - EXPECT_EQ(0, unix_isatty(pipe_fds[0])); - EXPECT_EQ(0, unix_isatty(pipe_fds[1])); - EXPECT_EQ(0, _close(pipe_fds[0])); - EXPECT_EQ(0, _close(pipe_fds[1])); - - // Make sure an invalid FD is handled correctly. - EXPECT_EQ(0, unix_isatty(-1)); -} - -void TestParseCompleteUTF8(const char* buf, const size_t buf_size, - const size_t expected_complete_bytes, - const std::vector& expected_remaining_bytes) { - std::vector remaining_bytes; - const size_t complete_bytes = internal::ParseCompleteUTF8(buf, buf + buf_size, - &remaining_bytes); - EXPECT_EQ(expected_complete_bytes, complete_bytes); - EXPECT_EQ(expected_remaining_bytes, remaining_bytes); -} - -TEST(sysdeps_win32, ParseCompleteUTF8) { - const std::vector> multi_byte_sequences = { - { '\xc2', '\xa9' }, // 2 byte UTF-8 sequence - { '\xe1', '\xb4', '\xa8' }, // 3 byte UTF-8 sequence - { '\xf0', '\x9f', '\x98', '\x80' }, // 4 byte UTF-8 sequence - }; - std::vector> all_sequences = { - {}, // 0 bytes - { '\0' }, // NULL byte - { 'a' }, // 1 byte UTF-8 sequence - }; - all_sequences.insert(all_sequences.end(), multi_byte_sequences.begin(), - multi_byte_sequences.end()); - - // Vary a prefix of bytes in front of the sequence that we're actually interested in parsing. - for (const auto& prefix : all_sequences) { - // Parse (prefix + one byte of the sequence at a time) - for (const auto& seq : multi_byte_sequences) { - std::vector buffer(prefix); - - // For every byte of the sequence except the last - for (size_t i = 0; i < seq.size() - 1; ++i) { - buffer.push_back(seq[i]); - - // When parsing an incomplete UTF-8 sequence, the amount of the buffer preceding - // the start of the incomplete UTF-8 sequence is valid. The remaining bytes are the - // bytes of the incomplete UTF-8 sequence. - TestParseCompleteUTF8(buffer.data(), buffer.size(), prefix.size(), - std::vector(seq.begin(), seq.begin() + i + 1)); - } - - // For the last byte of the sequence - buffer.push_back(seq.back()); - TestParseCompleteUTF8(buffer.data(), buffer.size(), buffer.size(), std::vector()); - } - - // Parse (prefix (aka sequence) + invalid trailing bytes) to verify that the invalid - // trailing bytes are immediately "returned" to prevent them from being stuck in some - // buffer. - std::vector buffer(prefix); - for (size_t i = 0; i < 8; ++i) { - buffer.push_back(0x80); // trailing byte - TestParseCompleteUTF8(buffer.data(), buffer.size(), buffer.size(), std::vector()); - } - } -} diff --git a/adb/test_adb.py b/adb/test_adb.py deleted file mode 100755 index c872fb0f72028bdec5f06561aa06b5073e32a55c..0000000000000000000000000000000000000000 --- a/adb/test_adb.py +++ /dev/null @@ -1,587 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (C) 2015 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. -# -"""Tests for the adb program itself. - -This differs from things in test_device.py in that there is no API for these -things. Most of these tests involve specific error messages or the help text. -""" - -import contextlib -import os -import random -import select -import socket -import struct -import subprocess -import sys -import threading -import time -import unittest -import warnings - -def find_open_port(): - # Find an open port. - with socket.socket() as s: - s.bind(("localhost", 0)) - return s.getsockname()[1] - -@contextlib.contextmanager -def fake_adbd(protocol=socket.AF_INET, port=0): - """Creates a fake ADB daemon that just replies with a CNXN packet.""" - - serversock = socket.socket(protocol, socket.SOCK_STREAM) - serversock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - if protocol == socket.AF_INET: - serversock.bind(("127.0.0.1", port)) - else: - serversock.bind(("::1", port)) - serversock.listen(1) - - # A pipe that is used to signal the thread that it should terminate. - readsock, writesock = socket.socketpair() - - def _adb_packet(command: bytes, arg0: int, arg1: int, data: bytes) -> bytes: - bin_command = struct.unpack("I", command)[0] - buf = struct.pack("IIIIII", bin_command, arg0, arg1, len(data), 0, - bin_command ^ 0xffffffff) - buf += data - return buf - - def _handle(sock): - with contextlib.closing(sock) as serversock: - rlist = [readsock, serversock] - cnxn_sent = {} - while True: - read_ready, _, _ = select.select(rlist, [], []) - for ready in read_ready: - if ready == readsock: - # Closure pipe - for f in rlist: - f.close() - return - elif ready == serversock: - # Server socket - conn, _ = ready.accept() - rlist.append(conn) - else: - # Client socket - data = ready.recv(1024) - if not data or data.startswith(b"OPEN"): - if ready in cnxn_sent: - del cnxn_sent[ready] - ready.shutdown(socket.SHUT_RDWR) - ready.close() - rlist.remove(ready) - continue - if ready in cnxn_sent: - continue - cnxn_sent[ready] = True - ready.sendall(_adb_packet(b"CNXN", 0x01000001, 1024 * 1024, - b"device::ro.product.name=fakeadb")) - - port = serversock.getsockname()[1] - server_thread = threading.Thread(target=_handle, args=(serversock,)) - server_thread.start() - - try: - yield port, writesock - finally: - writesock.close() - server_thread.join() - - -@contextlib.contextmanager -def adb_connect(unittest, serial): - """Context manager for an ADB connection. - - This automatically disconnects when done with the connection. - """ - - output = subprocess.check_output(["adb", "connect", serial]) - unittest.assertEqual(output.strip(), - "connected to {}".format(serial).encode("utf8")) - - try: - yield - finally: - # Perform best-effort disconnection. Discard the output. - subprocess.Popen(["adb", "disconnect", serial], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE).communicate() - - -@contextlib.contextmanager -def adb_server(): - """Context manager for an ADB server. - - This creates an ADB server and returns the port it's listening on. - """ - - port = find_open_port() - read_pipe, write_pipe = os.pipe() - - if sys.platform == "win32": - import msvcrt - write_handle = msvcrt.get_osfhandle(write_pipe) - os.set_handle_inheritable(write_handle, True) - reply_fd = str(write_handle) - else: - os.set_inheritable(write_pipe, True) - reply_fd = str(write_pipe) - - proc = subprocess.Popen(["adb", "-L", "tcp:localhost:{}".format(port), - "fork-server", "server", - "--reply-fd", reply_fd], close_fds=False) - try: - os.close(write_pipe) - greeting = os.read(read_pipe, 1024) - assert greeting == b"OK\n", repr(greeting) - yield port - finally: - proc.terminate() - proc.wait() - - -class CommandlineTest(unittest.TestCase): - """Tests for the ADB commandline.""" - - def test_help(self): - """Make sure we get _something_ out of help.""" - out = subprocess.check_output( - ["adb", "help"], stderr=subprocess.STDOUT) - self.assertGreater(len(out), 0) - - def test_version(self): - """Get a version number out of the output of adb.""" - lines = subprocess.check_output(["adb", "version"]).splitlines() - version_line = lines[0] - self.assertRegex( - version_line, rb"^Android Debug Bridge version \d+\.\d+\.\d+$") - if len(lines) == 2: - # Newer versions of ADB have a second line of output for the - # version that includes a specific revision (git SHA). - revision_line = lines[1] - self.assertRegex( - revision_line, rb"^Revision [0-9a-f]{12}-android$") - - def test_tcpip_error_messages(self): - """Make sure 'adb tcpip' parsing is sane.""" - proc = subprocess.Popen(["adb", "tcpip"], - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) - out, _ = proc.communicate() - self.assertEqual(1, proc.returncode) - self.assertIn(b"requires an argument", out) - - proc = subprocess.Popen(["adb", "tcpip", "foo"], - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) - out, _ = proc.communicate() - self.assertEqual(1, proc.returncode) - self.assertIn(b"invalid port", out) - - -class ServerTest(unittest.TestCase): - """Tests for the ADB server.""" - - @staticmethod - def _read_pipe_and_set_event(pipe, event): - """Reads a pipe until it is closed, then sets the event.""" - pipe.read() - event.set() - - def test_handle_inheritance(self): - """Test that launch_server() does not inherit handles. - - launch_server() should not let the adb server inherit - stdin/stdout/stderr handles, which can cause callers of adb.exe to hang. - This test also runs fine on unix even though the impetus is an issue - unique to Windows. - """ - # This test takes 5 seconds to run on Windows: if there is no adb server - # running on the the port used below, adb kill-server tries to make a - # TCP connection to a closed port and that takes 1 second on Windows; - # adb start-server does the same TCP connection which takes another - # second, and it waits 3 seconds after starting the server. - - # Start adb client with redirected stdin/stdout/stderr to check if it - # passes those redirections to the adb server that it starts. To do - # this, run an instance of the adb server on a non-default port so we - # don't conflict with a pre-existing adb server that may already be - # setup with adb TCP/emulator connections. If there is a pre-existing - # adb server, this also tests whether multiple instances of the adb - # server conflict on adb.log. - - port = find_open_port() - - try: - # We get warnings for unclosed files for the subprocess's pipes, - # and it's somewhat cumbersome to close them, so just ignore this. - warnings.simplefilter("ignore", ResourceWarning) - - # Run the adb client and have it start the adb server. - proc = subprocess.Popen(["adb", "-P", str(port), "start-server"], - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - - # Start threads that set events when stdout/stderr are closed. - stdout_event = threading.Event() - stdout_thread = threading.Thread( - target=ServerTest._read_pipe_and_set_event, - args=(proc.stdout, stdout_event)) - stdout_thread.start() - - stderr_event = threading.Event() - stderr_thread = threading.Thread( - target=ServerTest._read_pipe_and_set_event, - args=(proc.stderr, stderr_event)) - stderr_thread.start() - - # Wait for the adb client to finish. Once that has occurred, if - # stdin/stderr/stdout are still open, it must be open in the adb - # server. - proc.wait() - - # Try to write to stdin which we expect is closed. If it isn't - # closed, we should get an IOError. If we don't get an IOError, - # stdin must still be open in the adb server. The adb client is - # probably letting the adb server inherit stdin which would be - # wrong. - with self.assertRaises(IOError): - proc.stdin.write(b"x") - proc.stdin.flush() - - # Wait a few seconds for stdout/stderr to be closed (in the success - # case, this won't wait at all). If there is a timeout, that means - # stdout/stderr were not closed and and they must be open in the adb - # server, suggesting that the adb client is letting the adb server - # inherit stdout/stderr which would be wrong. - self.assertTrue(stdout_event.wait(5), "adb stdout not closed") - self.assertTrue(stderr_event.wait(5), "adb stderr not closed") - stdout_thread.join() - stderr_thread.join() - finally: - # If we started a server, kill it. - subprocess.check_output(["adb", "-P", str(port), "kill-server"], - stderr=subprocess.STDOUT) - - @unittest.skipUnless( - os.name == "posix", - "adb doesn't yet support IPv6 on Windows", - ) - def test_starts_on_ipv6_localhost(self): - """ - Tests that the server can start up on ::1 and that it's accessible - """ - - server_port = find_open_port() - try: - subprocess.check_output( - ["adb", "-L", "tcp:[::1]:{}".format(server_port), "server"], - stderr=subprocess.STDOUT, - ) - with fake_adbd() as (port, _): - with adb_connect(self, serial="localhost:{}".format(port)): - pass - finally: - # If we started a server, kill it. - subprocess.check_output( - ["adb", "-P", str(server_port), "kill-server"], - stderr=subprocess.STDOUT, - ) - - - - -class EmulatorTest(unittest.TestCase): - """Tests for the emulator connection.""" - - def _reset_socket_on_close(self, sock): - """Use SO_LINGER to cause TCP RST segment to be sent on socket close.""" - # The linger structure is two shorts on Windows, but two ints on Unix. - linger_format = "hh" if os.name == "nt" else "ii" - l_onoff = 1 - l_linger = 0 - - sock.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, - struct.pack(linger_format, l_onoff, l_linger)) - # Verify that we set the linger structure properly by retrieving it. - linger = sock.getsockopt(socket.SOL_SOCKET, socket.SO_LINGER, 16) - self.assertEqual((l_onoff, l_linger), - struct.unpack_from(linger_format, linger)) - - def test_emu_kill(self): - """Ensure that adb emu kill works. - - Bug: https://code.google.com/p/android/issues/detail?id=21021 - """ - with contextlib.closing( - socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as listener: - # Use SO_REUSEADDR so subsequent runs of the test can grab the port - # even if it is in TIME_WAIT. - listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - listener.bind(("127.0.0.1", 0)) - listener.listen(4) - port = listener.getsockname()[1] - - # Now that listening has started, start adb emu kill, telling it to - # connect to our mock emulator. - proc = subprocess.Popen( - ["adb", "-s", "emulator-" + str(port), "emu", "kill"], - stderr=subprocess.STDOUT) - - accepted_connection, addr = listener.accept() - with contextlib.closing(accepted_connection) as conn: - # If WSAECONNABORTED (10053) is raised by any socket calls, - # then adb probably isn't reading the data that we sent it. - conn.sendall(("Android Console: type 'help' for a list " - "of commands\r\n").encode("utf8")) - conn.sendall(b"OK\r\n") - - with contextlib.closing(conn.makefile()) as connf: - line = connf.readline() - if line.startswith("auth"): - # Ignore the first auth line. - line = connf.readline() - self.assertEqual("kill\n", line) - self.assertEqual("quit\n", connf.readline()) - - conn.sendall(b"OK: killing emulator, bye bye\r\n") - - # Use SO_LINGER to send TCP RST segment to test whether adb - # ignores WSAECONNRESET on Windows. This happens with the - # real emulator because it just calls exit() without closing - # the socket or calling shutdown(SD_SEND). At process - # termination, Windows sends a TCP RST segment for every - # open socket that shutdown(SD_SEND) wasn't used on. - self._reset_socket_on_close(conn) - - # Wait for adb to finish, so we can check return code. - proc.communicate() - - # If this fails, adb probably isn't ignoring WSAECONNRESET when - # reading the response from the adb emu kill command (on Windows). - self.assertEqual(0, proc.returncode) - - def test_emulator_connect(self): - """Ensure that the emulator can connect. - - Bug: http://b/78991667 - """ - with adb_server() as server_port: - with fake_adbd() as (port, _): - serial = "emulator-{}".format(port - 1) - # Ensure that the emulator is not there. - try: - subprocess.check_output(["adb", "-P", str(server_port), - "-s", serial, "get-state"], - stderr=subprocess.STDOUT) - self.fail("Device should not be available") - except subprocess.CalledProcessError as err: - self.assertEqual( - err.output.strip(), - "error: device '{}' not found".format(serial).encode("utf8")) - - # Let the ADB server know that the emulator has started. - with contextlib.closing( - socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock: - sock.connect(("localhost", server_port)) - command = "host:emulator:{}".format(port).encode("utf8") - sock.sendall(b"%04x%s" % (len(command), command)) - - # Ensure the emulator is there. - subprocess.check_call(["adb", "-P", str(server_port), - "-s", serial, "wait-for-device"]) - output = subprocess.check_output(["adb", "-P", str(server_port), - "-s", serial, "get-state"]) - self.assertEqual(output.strip(), b"device") - - -class ConnectionTest(unittest.TestCase): - """Tests for adb connect.""" - - def test_connect_ipv4_ipv6(self): - """Ensure that `adb connect localhost:1234` will try both IPv4 and IPv6. - - Bug: http://b/30313466 - """ - for protocol in (socket.AF_INET, socket.AF_INET6): - try: - with fake_adbd(protocol=protocol) as (port, _): - serial = "localhost:{}".format(port) - with adb_connect(self, serial): - pass - except socket.error: - print("IPv6 not available, skipping") - continue - - def test_already_connected(self): - """Ensure that an already-connected device stays connected.""" - - with fake_adbd() as (port, _): - serial = "localhost:{}".format(port) - with adb_connect(self, serial): - # b/31250450: this always returns 0 but probably shouldn't. - output = subprocess.check_output(["adb", "connect", serial]) - self.assertEqual( - output.strip(), - "already connected to {}".format(serial).encode("utf8")) - - @unittest.skip("Currently failing b/123247844") - def test_reconnect(self): - """Ensure that a disconnected device reconnects.""" - - with fake_adbd() as (port, _): - serial = "localhost:{}".format(port) - with adb_connect(self, serial): - # Wait a bit to give adb some time to connect. - time.sleep(0.25) - - output = subprocess.check_output(["adb", "-s", serial, - "get-state"]) - self.assertEqual(output.strip(), b"device") - - # This will fail. - proc = subprocess.Popen(["adb", "-s", serial, "shell", "true"], - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) - output, _ = proc.communicate() - self.assertEqual(output.strip(), b"error: closed") - - subprocess.check_call(["adb", "-s", serial, "wait-for-device"]) - - output = subprocess.check_output(["adb", "-s", serial, - "get-state"]) - self.assertEqual(output.strip(), b"device") - - # Once we explicitly kick a device, it won't attempt to - # reconnect. - output = subprocess.check_output(["adb", "disconnect", serial]) - self.assertEqual( - output.strip(), - "disconnected {}".format(serial).encode("utf8")) - try: - subprocess.check_output(["adb", "-s", serial, "get-state"], - stderr=subprocess.STDOUT) - self.fail("Device should not be available") - except subprocess.CalledProcessError as err: - self.assertEqual( - err.output.strip(), - "error: device '{}' not found".format(serial).encode("utf8")) - - -class DisconnectionTest(unittest.TestCase): - """Tests for adb disconnect.""" - - def test_disconnect(self): - """Ensure that `adb disconnect` takes effect immediately.""" - - def _devices(port): - output = subprocess.check_output(["adb", "-P", str(port), "devices"]) - return [x.split("\t") for x in output.decode("utf8").strip().splitlines()[1:]] - - with adb_server() as server_port: - with fake_adbd() as (port, sock): - device_name = "localhost:{}".format(port) - output = subprocess.check_output(["adb", "-P", str(server_port), - "connect", device_name]) - self.assertEqual(output.strip(), - "connected to {}".format(device_name).encode("utf8")) - - - self.assertEqual(_devices(server_port), [[device_name, "device"]]) - - # Send a deliberately malformed packet to make the device go offline. - packet = struct.pack("IIIIII", 0, 0, 0, 0, 0, 0) - sock.sendall(packet) - - # Wait a bit. - time.sleep(0.1) - - self.assertEqual(_devices(server_port), [[device_name, "offline"]]) - - # Disconnect the device. - output = subprocess.check_output(["adb", "-P", str(server_port), - "disconnect", device_name]) - - # Wait a bit. - time.sleep(0.1) - - self.assertEqual(_devices(server_port), []) - - -@unittest.skipUnless(sys.platform == "win32", "requires Windows") -class PowerTest(unittest.TestCase): - def test_resume_usb_kick(self): - """Resuming from sleep/hibernate should kick USB devices.""" - try: - usb_serial = subprocess.check_output(["adb", "-d", "get-serialno"]).strip() - except subprocess.CalledProcessError: - # If there are multiple USB devices, we don't have a way to check whether the selected - # device is USB. - raise unittest.SkipTest('requires single USB device') - - try: - serial = subprocess.check_output(["adb", "get-serialno"]).strip() - except subprocess.CalledProcessError: - # Did you forget to select a device with $ANDROID_SERIAL? - raise unittest.SkipTest('requires $ANDROID_SERIAL set to a USB device') - - # Test only works with USB devices because adb _power_notification_thread does not kick - # non-USB devices on resume event. - if serial != usb_serial: - raise unittest.SkipTest('requires USB device') - - # Run an adb shell command in the background that takes a while to complete. - proc = subprocess.Popen(['adb', 'shell', 'sleep', '5']) - - # Wait for startup of adb server's _power_notification_thread. - time.sleep(0.1) - - # Simulate resuming from sleep/hibernation by sending Windows message. - import ctypes - from ctypes import wintypes - HWND_BROADCAST = 0xffff - WM_POWERBROADCAST = 0x218 - PBT_APMRESUMEAUTOMATIC = 0x12 - - PostMessageW = ctypes.windll.user32.PostMessageW - PostMessageW.restype = wintypes.BOOL - PostMessageW.argtypes = (wintypes.HWND, wintypes.UINT, wintypes.WPARAM, wintypes.LPARAM) - result = PostMessageW(HWND_BROADCAST, WM_POWERBROADCAST, PBT_APMRESUMEAUTOMATIC, 0) - if not result: - raise ctypes.WinError() - - # Wait for connection to adb shell to be broken by _power_notification_thread detecting the - # Windows message. - start = time.time() - proc.wait() - end = time.time() - - # If the power event was detected, the adb shell command should be broken very quickly. - self.assertLess(end - start, 2) - - -def main(): - """Main entrypoint.""" - random.seed(0) - unittest.main(verbosity=3) - - -if __name__ == "__main__": - main() diff --git a/adb/test_device.py b/adb/test_device.py deleted file mode 100755 index 6a9ff89ef9574713f71497e84063cebf20434928..0000000000000000000000000000000000000000 --- a/adb/test_device.py +++ /dev/null @@ -1,1678 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -# -# Copyright (C) 2015 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. -# -from __future__ import print_function - -import contextlib -import hashlib -import os -import posixpath -import random -import re -import shlex -import shutil -import signal -import socket -import string -import subprocess -import sys -import tempfile -import threading -import time -import unittest - -from datetime import datetime - -import adb - -def requires_root(func): - def wrapper(self, *args): - if self.device.get_prop('ro.debuggable') != '1': - raise unittest.SkipTest('requires rootable build') - - was_root = self.device.shell(['id', '-un'])[0].strip() == 'root' - if not was_root: - self.device.root() - self.device.wait() - - try: - func(self, *args) - finally: - if not was_root: - self.device.unroot() - self.device.wait() - - return wrapper - - -def requires_non_root(func): - def wrapper(self, *args): - was_root = self.device.shell(['id', '-un'])[0].strip() == 'root' - if was_root: - self.device.unroot() - self.device.wait() - - try: - func(self, *args) - finally: - if was_root: - self.device.root() - self.device.wait() - - return wrapper - - -class DeviceTest(unittest.TestCase): - def setUp(self): - self.device = adb.get_device() - - -class AbbTest(DeviceTest): - def test_smoke(self): - result = subprocess.run(['adb', 'abb'], capture_output=True) - self.assertEqual(1, result.returncode) - expected_output = b"cmd: No service specified; use -l to list all services\n" - self.assertEqual(expected_output, result.stderr) - -class ForwardReverseTest(DeviceTest): - def _test_no_rebind(self, description, direction_list, direction, - direction_no_rebind, direction_remove_all): - msg = direction_list() - self.assertEqual('', msg.strip(), - description + ' list must be empty to run this test.') - - # Use --no-rebind with no existing binding - direction_no_rebind('tcp:5566', 'tcp:6655') - msg = direction_list() - self.assertTrue(re.search(r'tcp:5566.+tcp:6655', msg)) - - # Use --no-rebind with existing binding - with self.assertRaises(subprocess.CalledProcessError): - direction_no_rebind('tcp:5566', 'tcp:6677') - msg = direction_list() - self.assertFalse(re.search(r'tcp:5566.+tcp:6677', msg)) - self.assertTrue(re.search(r'tcp:5566.+tcp:6655', msg)) - - # Use the absence of --no-rebind with existing binding - direction('tcp:5566', 'tcp:6677') - msg = direction_list() - self.assertFalse(re.search(r'tcp:5566.+tcp:6655', msg)) - self.assertTrue(re.search(r'tcp:5566.+tcp:6677', msg)) - - direction_remove_all() - msg = direction_list() - self.assertEqual('', msg.strip()) - - def test_forward_no_rebind(self): - self._test_no_rebind('forward', self.device.forward_list, - self.device.forward, self.device.forward_no_rebind, - self.device.forward_remove_all) - - def test_reverse_no_rebind(self): - self._test_no_rebind('reverse', self.device.reverse_list, - self.device.reverse, self.device.reverse_no_rebind, - self.device.reverse_remove_all) - - def test_forward(self): - msg = self.device.forward_list() - self.assertEqual('', msg.strip(), - 'Forwarding list must be empty to run this test.') - self.device.forward('tcp:5566', 'tcp:6655') - msg = self.device.forward_list() - self.assertTrue(re.search(r'tcp:5566.+tcp:6655', msg)) - self.device.forward('tcp:7788', 'tcp:8877') - msg = self.device.forward_list() - self.assertTrue(re.search(r'tcp:5566.+tcp:6655', msg)) - self.assertTrue(re.search(r'tcp:7788.+tcp:8877', msg)) - self.device.forward_remove('tcp:5566') - msg = self.device.forward_list() - self.assertFalse(re.search(r'tcp:5566.+tcp:6655', msg)) - self.assertTrue(re.search(r'tcp:7788.+tcp:8877', msg)) - self.device.forward_remove_all() - msg = self.device.forward_list() - self.assertEqual('', msg.strip()) - - def test_forward_old_protocol(self): - serialno = subprocess.check_output(self.device.adb_cmd + ['get-serialno']).strip() - - msg = self.device.forward_list() - self.assertEqual('', msg.strip(), - 'Forwarding list must be empty to run this test.') - - s = socket.create_connection(("localhost", 5037)) - service = b"host-serial:%s:forward:tcp:5566;tcp:6655" % serialno - cmd = b"%04x%s" % (len(service), service) - s.sendall(cmd) - - msg = self.device.forward_list() - self.assertTrue(re.search(r'tcp:5566.+tcp:6655', msg)) - - self.device.forward_remove_all() - msg = self.device.forward_list() - self.assertEqual('', msg.strip()) - - def test_forward_tcp_port_0(self): - self.assertEqual('', self.device.forward_list().strip(), - 'Forwarding list must be empty to run this test.') - - try: - # If resolving TCP port 0 is supported, `adb forward` will print - # the actual port number. - port = self.device.forward('tcp:0', 'tcp:8888').strip() - if not port: - raise unittest.SkipTest('Forwarding tcp:0 is not available.') - - self.assertTrue(re.search(r'tcp:{}.+tcp:8888'.format(port), - self.device.forward_list())) - finally: - self.device.forward_remove_all() - - def test_reverse(self): - msg = self.device.reverse_list() - self.assertEqual('', msg.strip(), - 'Reverse forwarding list must be empty to run this test.') - self.device.reverse('tcp:5566', 'tcp:6655') - msg = self.device.reverse_list() - self.assertTrue(re.search(r'tcp:5566.+tcp:6655', msg)) - self.device.reverse('tcp:7788', 'tcp:8877') - msg = self.device.reverse_list() - self.assertTrue(re.search(r'tcp:5566.+tcp:6655', msg)) - self.assertTrue(re.search(r'tcp:7788.+tcp:8877', msg)) - self.device.reverse_remove('tcp:5566') - msg = self.device.reverse_list() - self.assertFalse(re.search(r'tcp:5566.+tcp:6655', msg)) - self.assertTrue(re.search(r'tcp:7788.+tcp:8877', msg)) - self.device.reverse_remove_all() - msg = self.device.reverse_list() - self.assertEqual('', msg.strip()) - - def test_reverse_tcp_port_0(self): - self.assertEqual('', self.device.reverse_list().strip(), - 'Reverse list must be empty to run this test.') - - try: - # If resolving TCP port 0 is supported, `adb reverse` will print - # the actual port number. - port = self.device.reverse('tcp:0', 'tcp:8888').strip() - if not port: - raise unittest.SkipTest('Reversing tcp:0 is not available.') - - self.assertTrue(re.search(r'tcp:{}.+tcp:8888'.format(port), - self.device.reverse_list())) - finally: - self.device.reverse_remove_all() - - def test_forward_reverse_echo(self): - """Send data through adb forward and read it back via adb reverse""" - forward_port = 12345 - reverse_port = forward_port + 1 - forward_spec = 'tcp:' + str(forward_port) - reverse_spec = 'tcp:' + str(reverse_port) - forward_setup = False - reverse_setup = False - - try: - # listen on localhost:forward_port, connect to remote:forward_port - self.device.forward(forward_spec, forward_spec) - forward_setup = True - # listen on remote:forward_port, connect to localhost:reverse_port - self.device.reverse(forward_spec, reverse_spec) - reverse_setup = True - - listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - with contextlib.closing(listener): - # Use SO_REUSEADDR so that subsequent runs of the test can grab - # the port even if it is in TIME_WAIT. - listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - - # Listen on localhost:reverse_port before connecting to - # localhost:forward_port because that will cause adb to connect - # back to localhost:reverse_port. - listener.bind(('127.0.0.1', reverse_port)) - listener.listen(4) - - client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - with contextlib.closing(client): - # Connect to the listener. - client.connect(('127.0.0.1', forward_port)) - - # Accept the client connection. - accepted_connection, addr = listener.accept() - with contextlib.closing(accepted_connection) as server: - data = b'hello' - - # Send data into the port setup by adb forward. - client.sendall(data) - # Explicitly close() so that server gets EOF. - client.close() - - # Verify that the data came back via adb reverse. - self.assertEqual(data, server.makefile().read().encode("utf8")) - finally: - if reverse_setup: - self.device.reverse_remove(forward_spec) - if forward_setup: - self.device.forward_remove(forward_spec) - - -class ShellTest(DeviceTest): - def _interactive_shell(self, shell_args, input): - """Runs an interactive adb shell. - - Args: - shell_args: List of string arguments to `adb shell`. - input: bytes input to send to the interactive shell. - - Returns: - The remote exit code. - - Raises: - unittest.SkipTest: The device doesn't support exit codes. - """ - if not self.device.has_shell_protocol(): - raise unittest.SkipTest('exit codes are unavailable on this device') - - proc = subprocess.Popen( - self.device.adb_cmd + ['shell'] + shell_args, - stdin=subprocess.PIPE, stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - # Closing host-side stdin doesn't trigger a PTY shell to exit so we need - # to explicitly add an exit command to close the session from the device - # side, plus the necessary newline to complete the interactive command. - proc.communicate(input + b'; exit\n') - return proc.returncode - - def test_cat(self): - """Check that we can at least cat a file.""" - out = self.device.shell(['cat', '/proc/uptime'])[0].strip() - elements = out.split() - self.assertEqual(len(elements), 2) - - uptime, idle = elements - self.assertGreater(float(uptime), 0.0) - self.assertGreater(float(idle), 0.0) - - def test_throws_on_failure(self): - self.assertRaises(adb.ShellError, self.device.shell, ['false']) - - def test_output_not_stripped(self): - out = self.device.shell(['echo', 'foo'])[0] - self.assertEqual(out, 'foo' + self.device.linesep) - - def test_shell_command_length(self): - # Devices that have shell_v2 should be able to handle long commands. - if self.device.has_shell_protocol(): - rc, out, err = self.device.shell_nocheck(['echo', 'x' * 16384]) - self.assertEqual(rc, 0) - self.assertTrue(out == ('x' * 16384 + '\n')) - - def test_shell_nocheck_failure(self): - rc, out, _ = self.device.shell_nocheck(['false']) - self.assertNotEqual(rc, 0) - self.assertEqual(out, '') - - def test_shell_nocheck_output_not_stripped(self): - rc, out, _ = self.device.shell_nocheck(['echo', 'foo']) - self.assertEqual(rc, 0) - self.assertEqual(out, 'foo' + self.device.linesep) - - def test_can_distinguish_tricky_results(self): - # If result checking on ADB shell is naively implemented as - # `adb shell ; echo $?`, we would be unable to distinguish the - # output from the result for a cmd of `echo -n 1`. - rc, out, _ = self.device.shell_nocheck(['echo', '-n', '1']) - self.assertEqual(rc, 0) - self.assertEqual(out, '1') - - def test_line_endings(self): - """Ensure that line ending translation is not happening in the pty. - - Bug: http://b/19735063 - """ - output = self.device.shell(['uname'])[0] - self.assertEqual(output, 'Linux' + self.device.linesep) - - def test_pty_logic(self): - """Tests that a PTY is allocated when it should be. - - PTY allocation behavior should match ssh. - """ - def check_pty(args): - """Checks adb shell PTY allocation. - - Tests |args| for terminal and non-terminal stdin. - - Args: - args: -Tt args in a list (e.g. ['-t', '-t']). - - Returns: - A tuple (, ). True indicates - the corresponding shell allocated a remote PTY. - """ - test_cmd = self.device.adb_cmd + ['shell'] + args + ['[ -t 0 ]'] - - terminal = subprocess.Popen( - test_cmd, stdin=None, - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - terminal.communicate() - - non_terminal = subprocess.Popen( - test_cmd, stdin=subprocess.PIPE, - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - non_terminal.communicate() - - return (terminal.returncode == 0, non_terminal.returncode == 0) - - # -T: never allocate PTY. - self.assertEqual((False, False), check_pty(['-T'])) - - # These tests require a new device. - if self.device.has_shell_protocol() and os.isatty(sys.stdin.fileno()): - # No args: PTY only if stdin is a terminal and shell is interactive, - # which is difficult to reliably test from a script. - self.assertEqual((False, False), check_pty([])) - - # -t: PTY if stdin is a terminal. - self.assertEqual((True, False), check_pty(['-t'])) - - # -t -t: always allocate PTY. - self.assertEqual((True, True), check_pty(['-t', '-t'])) - - # -tt: always allocate PTY, POSIX style (http://b/32216152). - self.assertEqual((True, True), check_pty(['-tt'])) - - # -ttt: ssh has weird even/odd behavior with multiple -t flags, but - # we follow the man page instead. - self.assertEqual((True, True), check_pty(['-ttt'])) - - # -ttx: -x and -tt aren't incompatible (though -Tx would be an error). - self.assertEqual((True, True), check_pty(['-ttx'])) - - # -Ttt: -tt cancels out -T. - self.assertEqual((True, True), check_pty(['-Ttt'])) - - # -ttT: -T cancels out -tt. - self.assertEqual((False, False), check_pty(['-ttT'])) - - def test_shell_protocol(self): - """Tests the shell protocol on the device. - - If the device supports shell protocol, this gives us the ability - to separate stdout/stderr and return the exit code directly. - - Bug: http://b/19734861 - """ - if not self.device.has_shell_protocol(): - raise unittest.SkipTest('shell protocol unsupported on this device') - - # Shell protocol should be used by default. - result = self.device.shell_nocheck( - shlex.split('echo foo; echo bar >&2; exit 17')) - self.assertEqual(17, result[0]) - self.assertEqual('foo' + self.device.linesep, result[1]) - self.assertEqual('bar' + self.device.linesep, result[2]) - - self.assertEqual(17, self._interactive_shell([], b'exit 17')) - - # -x flag should disable shell protocol. - result = self.device.shell_nocheck( - shlex.split('-x echo foo; echo bar >&2; exit 17')) - self.assertEqual(0, result[0]) - self.assertEqual('foo{0}bar{0}'.format(self.device.linesep), result[1]) - self.assertEqual('', result[2]) - - self.assertEqual(0, self._interactive_shell(['-x'], b'exit 17')) - - def test_non_interactive_sigint(self): - """Tests that SIGINT in a non-interactive shell kills the process. - - This requires the shell protocol in order to detect the broken - pipe; raw data transfer mode will only see the break once the - subprocess tries to read or write. - - Bug: http://b/23825725 - """ - if not self.device.has_shell_protocol(): - raise unittest.SkipTest('shell protocol unsupported on this device') - - # Start a long-running process. - sleep_proc = subprocess.Popen( - self.device.adb_cmd + shlex.split('shell echo $$; sleep 60'), - stdin=subprocess.PIPE, stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) - remote_pid = sleep_proc.stdout.readline().strip().decode("utf8") - self.assertIsNone(sleep_proc.returncode, 'subprocess terminated early') - proc_query = shlex.split('ps {0} | grep {0}'.format(remote_pid)) - - # Verify that the process is running, send signal, verify it stopped. - self.device.shell(proc_query) - os.kill(sleep_proc.pid, signal.SIGINT) - sleep_proc.communicate() - - # It can take some time for the process to receive the signal and die. - end_time = time.time() + 3 - while self.device.shell_nocheck(proc_query)[0] != 1: - self.assertFalse(time.time() > end_time, - 'subprocess failed to terminate in time') - - def test_non_interactive_stdin(self): - """Tests that non-interactive shells send stdin.""" - if not self.device.has_shell_protocol(): - raise unittest.SkipTest('non-interactive stdin unsupported ' - 'on this device') - - # Test both small and large inputs. - small_input = b'foo' - characters = [c.encode("utf8") for c in string.ascii_letters + string.digits] - large_input = b'\n'.join(characters) - - - for input in (small_input, large_input): - proc = subprocess.Popen(self.device.adb_cmd + ['shell', 'cat'], - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - stdout, stderr = proc.communicate(input) - self.assertEqual(input.splitlines(), stdout.splitlines()) - self.assertEqual(b'', stderr) - - def test_sighup(self): - """Ensure that SIGHUP gets sent upon non-interactive ctrl-c""" - log_path = "/data/local/tmp/adb_signal_test.log" - - # Clear the output file. - self.device.shell_nocheck(["echo", ">", log_path]) - - script = """ - trap "echo SIGINT > {path}; exit 0" SIGINT - trap "echo SIGHUP > {path}; exit 0" SIGHUP - echo Waiting - read - """.format(path=log_path) - - script = ";".join([x.strip() for x in script.strip().splitlines()]) - - process = self.device.shell_popen([script], kill_atexit=False, - stdin=subprocess.PIPE, - stdout=subprocess.PIPE) - - self.assertEqual(b"Waiting\n", process.stdout.readline()) - process.send_signal(signal.SIGINT) - process.wait() - - # Waiting for the local adb to finish is insufficient, since it hangs - # up immediately. - time.sleep(1) - - stdout, _ = self.device.shell(["cat", log_path]) - self.assertEqual(stdout.strip(), "SIGHUP") - - def test_exit_stress(self): - """Hammer `adb shell exit 42` with multiple threads.""" - thread_count = 48 - result = dict() - def hammer(thread_idx, thread_count, result): - success = True - for i in range(thread_idx, 240, thread_count): - ret = subprocess.call(['adb', 'shell', 'exit {}'.format(i)]) - if ret != i % 256: - success = False - break - result[thread_idx] = success - - threads = [] - for i in range(thread_count): - thread = threading.Thread(target=hammer, args=(i, thread_count, result)) - thread.start() - threads.append(thread) - for thread in threads: - thread.join() - for i, success in result.items(): - self.assertTrue(success) - - def disabled_test_parallel(self): - """Spawn a bunch of `adb shell` instances in parallel. - - This was broken historically due to the use of select, which only works - for fds that are numerically less than 1024. - - Bug: http://b/141955761""" - - n_procs = 2048 - procs = dict() - for i in range(0, n_procs): - procs[i] = subprocess.Popen( - ['adb', 'shell', 'read foo; echo $foo; read rc; exit $rc'], - stdin=subprocess.PIPE, - stdout=subprocess.PIPE - ) - - for i in range(0, n_procs): - procs[i].stdin.write("%d\n" % i) - - for i in range(0, n_procs): - response = procs[i].stdout.readline() - assert(response == "%d\n" % i) - - for i in range(0, n_procs): - procs[i].stdin.write("%d\n" % (i % 256)) - - for i in range(0, n_procs): - assert(procs[i].wait() == i % 256) - - -class ArgumentEscapingTest(DeviceTest): - def test_shell_escaping(self): - """Make sure that argument escaping is somewhat sane.""" - - # http://b/19734868 - # Note that this actually matches ssh(1)'s behavior --- it's - # converted to `sh -c echo hello; echo world` which sh interprets - # as `sh -c echo` (with an argument to that shell of "hello"), - # and then `echo world` back in the first shell. - result = self.device.shell( - shlex.split("sh -c 'echo hello; echo world'"))[0] - result = result.splitlines() - self.assertEqual(['', 'world'], result) - # If you really wanted "hello" and "world", here's what you'd do: - result = self.device.shell( - shlex.split(r'echo hello\;echo world'))[0].splitlines() - self.assertEqual(['hello', 'world'], result) - - # http://b/15479704 - result = self.device.shell(shlex.split("'true && echo t'"))[0].strip() - self.assertEqual('t', result) - result = self.device.shell( - shlex.split("sh -c 'true && echo t'"))[0].strip() - self.assertEqual('t', result) - - # http://b/20564385 - result = self.device.shell(shlex.split('FOO=a BAR=b echo t'))[0].strip() - self.assertEqual('t', result) - result = self.device.shell( - shlex.split(r'echo -n 123\;uname'))[0].strip() - self.assertEqual('123Linux', result) - - def test_install_argument_escaping(self): - """Make sure that install argument escaping works.""" - # http://b/20323053, http://b/3090932. - for file_suffix in (b'-text;ls;1.apk', b"-Live Hold'em.apk"): - tf = tempfile.NamedTemporaryFile('wb', suffix=file_suffix, - delete=False) - tf.close() - - # Installing bogus .apks fails if the device supports exit codes. - try: - output = self.device.install(tf.name.decode("utf8")) - except subprocess.CalledProcessError as e: - output = e.output - - self.assertIn(file_suffix, output) - os.remove(tf.name) - - -class RootUnrootTest(DeviceTest): - def _test_root(self): - message = self.device.root() - if 'adbd cannot run as root in production builds' in message: - return - self.device.wait() - self.assertEqual('root', self.device.shell(['id', '-un'])[0].strip()) - - def _test_unroot(self): - self.device.unroot() - self.device.wait() - self.assertEqual('shell', self.device.shell(['id', '-un'])[0].strip()) - - def test_root_unroot(self): - """Make sure that adb root and adb unroot work, using id(1).""" - if self.device.get_prop('ro.debuggable') != '1': - raise unittest.SkipTest('requires rootable build') - - original_user = self.device.shell(['id', '-un'])[0].strip() - try: - if original_user == 'root': - self._test_unroot() - self._test_root() - elif original_user == 'shell': - self._test_root() - self._test_unroot() - finally: - if original_user == 'root': - self.device.root() - else: - self.device.unroot() - self.device.wait() - - -class TcpIpTest(DeviceTest): - def test_tcpip_failure_raises(self): - """adb tcpip requires a port. - - Bug: http://b/22636927 - """ - self.assertRaises( - subprocess.CalledProcessError, self.device.tcpip, '') - self.assertRaises( - subprocess.CalledProcessError, self.device.tcpip, 'foo') - - -class SystemPropertiesTest(DeviceTest): - def test_get_prop(self): - self.assertEqual(self.device.get_prop('init.svc.adbd'), 'running') - - @requires_root - def test_set_prop(self): - prop_name = 'foo.bar' - self.device.shell(['setprop', prop_name, '""']) - - self.device.set_prop(prop_name, 'qux') - self.assertEqual( - self.device.shell(['getprop', prop_name])[0].strip(), 'qux') - - -def compute_md5(string): - hsh = hashlib.md5() - hsh.update(string) - return hsh.hexdigest() - - -def get_md5_prog(device): - """Older platforms (pre-L) had the name md5 rather than md5sum.""" - try: - device.shell(['md5sum', '/proc/uptime']) - return 'md5sum' - except adb.ShellError: - return 'md5' - - -class HostFile(object): - def __init__(self, handle, checksum): - self.handle = handle - self.checksum = checksum - self.full_path = handle.name - self.base_name = os.path.basename(self.full_path) - - -class DeviceFile(object): - def __init__(self, checksum, full_path): - self.checksum = checksum - self.full_path = full_path - self.base_name = posixpath.basename(self.full_path) - - -def make_random_host_files(in_dir, num_files): - min_size = 1 * (1 << 10) - max_size = 16 * (1 << 10) - - files = [] - for _ in range(num_files): - file_handle = tempfile.NamedTemporaryFile(dir=in_dir, delete=False) - - size = random.randrange(min_size, max_size, 1024) - rand_str = os.urandom(size) - file_handle.write(rand_str) - file_handle.flush() - file_handle.close() - - md5 = compute_md5(rand_str) - files.append(HostFile(file_handle, md5)) - return files - - -def make_random_device_files(device, in_dir, num_files, prefix='device_tmpfile'): - min_size = 1 * (1 << 10) - max_size = 16 * (1 << 10) - - files = [] - for file_num in range(num_files): - size = random.randrange(min_size, max_size, 1024) - - base_name = prefix + str(file_num) - full_path = posixpath.join(in_dir, base_name) - - device.shell(['dd', 'if=/dev/urandom', 'of={}'.format(full_path), - 'bs={}'.format(size), 'count=1']) - dev_md5, _ = device.shell([get_md5_prog(device), full_path])[0].split() - - files.append(DeviceFile(dev_md5, full_path)) - return files - - -class FileOperationsTest(DeviceTest): - SCRATCH_DIR = '/data/local/tmp' - DEVICE_TEMP_FILE = SCRATCH_DIR + '/adb_test_file' - DEVICE_TEMP_DIR = SCRATCH_DIR + '/adb_test_dir' - - def _verify_remote(self, checksum, remote_path): - dev_md5, _ = self.device.shell([get_md5_prog(self.device), - remote_path])[0].split() - self.assertEqual(checksum, dev_md5) - - def _verify_local(self, checksum, local_path): - with open(local_path, 'rb') as host_file: - host_md5 = compute_md5(host_file.read()) - self.assertEqual(host_md5, checksum) - - def test_push(self): - """Push a randomly generated file to specified device.""" - kbytes = 512 - tmp = tempfile.NamedTemporaryFile(mode='wb', delete=False) - rand_str = os.urandom(1024 * kbytes) - tmp.write(rand_str) - tmp.close() - - self.device.shell(['rm', '-rf', self.DEVICE_TEMP_FILE]) - self.device.push(local=tmp.name, remote=self.DEVICE_TEMP_FILE) - - self._verify_remote(compute_md5(rand_str), self.DEVICE_TEMP_FILE) - self.device.shell(['rm', '-f', self.DEVICE_TEMP_FILE]) - - os.remove(tmp.name) - - def test_push_dir(self): - """Push a randomly generated directory of files to the device.""" - self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR]) - self.device.shell(['mkdir', self.DEVICE_TEMP_DIR]) - - try: - host_dir = tempfile.mkdtemp() - - # Make sure the temp directory isn't setuid, or else adb will complain. - os.chmod(host_dir, 0o700) - - # Create 32 random files. - temp_files = make_random_host_files(in_dir=host_dir, num_files=32) - self.device.push(host_dir, self.DEVICE_TEMP_DIR) - - for temp_file in temp_files: - remote_path = posixpath.join(self.DEVICE_TEMP_DIR, - os.path.basename(host_dir), - temp_file.base_name) - self._verify_remote(temp_file.checksum, remote_path) - self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR]) - finally: - if host_dir is not None: - shutil.rmtree(host_dir) - - def disabled_test_push_empty(self): - """Push an empty directory to the device.""" - self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR]) - self.device.shell(['mkdir', self.DEVICE_TEMP_DIR]) - - try: - host_dir = tempfile.mkdtemp() - - # Make sure the temp directory isn't setuid, or else adb will complain. - os.chmod(host_dir, 0o700) - - # Create an empty directory. - empty_dir_path = os.path.join(host_dir, 'empty') - os.mkdir(empty_dir_path); - - self.device.push(empty_dir_path, self.DEVICE_TEMP_DIR) - - remote_path = os.path.join(self.DEVICE_TEMP_DIR, "empty") - test_empty_cmd = ["[", "-d", remote_path, "]"] - rc, _, _ = self.device.shell_nocheck(test_empty_cmd) - - self.assertEqual(rc, 0) - self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR]) - finally: - if host_dir is not None: - shutil.rmtree(host_dir) - - @unittest.skipIf(sys.platform == "win32", "symlinks require elevated privileges on windows") - def test_push_symlink(self): - """Push a symlink. - - Bug: http://b/31491920 - """ - try: - host_dir = tempfile.mkdtemp() - - # Make sure the temp directory isn't setuid, or else adb will - # complain. - os.chmod(host_dir, 0o700) - - with open(os.path.join(host_dir, 'foo'), 'w') as f: - f.write('foo') - - symlink_path = os.path.join(host_dir, 'symlink') - os.symlink('foo', symlink_path) - - self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR]) - self.device.shell(['mkdir', self.DEVICE_TEMP_DIR]) - self.device.push(symlink_path, self.DEVICE_TEMP_DIR) - rc, out, _ = self.device.shell_nocheck( - ['cat', posixpath.join(self.DEVICE_TEMP_DIR, 'symlink')]) - self.assertEqual(0, rc) - self.assertEqual(out.strip(), 'foo') - finally: - if host_dir is not None: - shutil.rmtree(host_dir) - - def test_multiple_push(self): - """Push multiple files to the device in one adb push command. - - Bug: http://b/25324823 - """ - - self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR]) - self.device.shell(['mkdir', self.DEVICE_TEMP_DIR]) - - try: - host_dir = tempfile.mkdtemp() - - # Create some random files and a subdirectory containing more files. - temp_files = make_random_host_files(in_dir=host_dir, num_files=4) - - subdir = os.path.join(host_dir, 'subdir') - os.mkdir(subdir) - subdir_temp_files = make_random_host_files(in_dir=subdir, - num_files=4) - - paths = [x.full_path for x in temp_files] - paths.append(subdir) - self.device._simple_call(['push'] + paths + [self.DEVICE_TEMP_DIR]) - - for temp_file in temp_files: - remote_path = posixpath.join(self.DEVICE_TEMP_DIR, - temp_file.base_name) - self._verify_remote(temp_file.checksum, remote_path) - - for subdir_temp_file in subdir_temp_files: - remote_path = posixpath.join(self.DEVICE_TEMP_DIR, - # BROKEN: http://b/25394682 - # 'subdir'; - temp_file.base_name) - self._verify_remote(temp_file.checksum, remote_path) - - - self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR]) - finally: - if host_dir is not None: - shutil.rmtree(host_dir) - - @requires_non_root - def test_push_error_reporting(self): - """Make sure that errors that occur while pushing a file get reported - - Bug: http://b/26816782 - """ - with tempfile.NamedTemporaryFile() as tmp_file: - tmp_file.write(b'\0' * 1024 * 1024) - tmp_file.flush() - try: - self.device.push(local=tmp_file.name, remote='/system/') - self.fail('push should not have succeeded') - except subprocess.CalledProcessError as e: - output = e.output - - self.assertTrue(b'Permission denied' in output or - b'Read-only file system' in output) - - @requires_non_root - def test_push_directory_creation(self): - """Regression test for directory creation. - - Bug: http://b/110953234 - """ - with tempfile.NamedTemporaryFile() as tmp_file: - tmp_file.write(b'\0' * 1024 * 1024) - tmp_file.flush() - remote_path = self.DEVICE_TEMP_DIR + '/test_push_directory_creation' - self.device.shell(['rm', '-rf', remote_path]) - - remote_path += '/filename' - self.device.push(local=tmp_file.name, remote=remote_path) - - def disabled_test_push_multiple_slash_root(self): - """Regression test for pushing to //data/local/tmp. - - Bug: http://b/141311284 - - Disabled because this broken on the adbd side as well: b/141943968 - """ - with tempfile.NamedTemporaryFile() as tmp_file: - tmp_file.write('\0' * 1024 * 1024) - tmp_file.flush() - remote_path = '/' + self.DEVICE_TEMP_DIR + '/test_push_multiple_slash_root' - self.device.shell(['rm', '-rf', remote_path]) - self.device.push(local=tmp_file.name, remote=remote_path) - - def _test_pull(self, remote_file, checksum): - tmp_write = tempfile.NamedTemporaryFile(mode='wb', delete=False) - tmp_write.close() - self.device.pull(remote=remote_file, local=tmp_write.name) - with open(tmp_write.name, 'rb') as tmp_read: - host_contents = tmp_read.read() - host_md5 = compute_md5(host_contents) - self.assertEqual(checksum, host_md5) - os.remove(tmp_write.name) - - @requires_non_root - def test_pull_error_reporting(self): - self.device.shell(['touch', self.DEVICE_TEMP_FILE]) - self.device.shell(['chmod', 'a-rwx', self.DEVICE_TEMP_FILE]) - - try: - output = self.device.pull(remote=self.DEVICE_TEMP_FILE, local='x') - except subprocess.CalledProcessError as e: - output = e.output - - self.assertIn(b'Permission denied', output) - - self.device.shell(['rm', '-f', self.DEVICE_TEMP_FILE]) - - def test_pull(self): - """Pull a randomly generated file from specified device.""" - kbytes = 512 - self.device.shell(['rm', '-rf', self.DEVICE_TEMP_FILE]) - cmd = ['dd', 'if=/dev/urandom', - 'of={}'.format(self.DEVICE_TEMP_FILE), 'bs=1024', - 'count={}'.format(kbytes)] - self.device.shell(cmd) - dev_md5, _ = self.device.shell( - [get_md5_prog(self.device), self.DEVICE_TEMP_FILE])[0].split() - self._test_pull(self.DEVICE_TEMP_FILE, dev_md5) - self.device.shell_nocheck(['rm', self.DEVICE_TEMP_FILE]) - - def test_pull_dir(self): - """Pull a randomly generated directory of files from the device.""" - try: - host_dir = tempfile.mkdtemp() - - self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR]) - self.device.shell(['mkdir', '-p', self.DEVICE_TEMP_DIR]) - - # Populate device directory with random files. - temp_files = make_random_device_files( - self.device, in_dir=self.DEVICE_TEMP_DIR, num_files=32) - - self.device.pull(remote=self.DEVICE_TEMP_DIR, local=host_dir) - - for temp_file in temp_files: - host_path = os.path.join( - host_dir, posixpath.basename(self.DEVICE_TEMP_DIR), - temp_file.base_name) - self._verify_local(temp_file.checksum, host_path) - - self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR]) - finally: - if host_dir is not None: - shutil.rmtree(host_dir) - - def test_pull_dir_symlink(self): - """Pull a directory into a symlink to a directory. - - Bug: http://b/27362811 - """ - if os.name != 'posix': - raise unittest.SkipTest('requires POSIX') - - try: - host_dir = tempfile.mkdtemp() - real_dir = os.path.join(host_dir, 'dir') - symlink = os.path.join(host_dir, 'symlink') - os.mkdir(real_dir) - os.symlink(real_dir, symlink) - - self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR]) - self.device.shell(['mkdir', '-p', self.DEVICE_TEMP_DIR]) - - # Populate device directory with random files. - temp_files = make_random_device_files( - self.device, in_dir=self.DEVICE_TEMP_DIR, num_files=32) - - self.device.pull(remote=self.DEVICE_TEMP_DIR, local=symlink) - - for temp_file in temp_files: - host_path = os.path.join( - real_dir, posixpath.basename(self.DEVICE_TEMP_DIR), - temp_file.base_name) - self._verify_local(temp_file.checksum, host_path) - - self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR]) - finally: - if host_dir is not None: - shutil.rmtree(host_dir) - - def test_pull_dir_symlink_collision(self): - """Pull a directory into a colliding symlink to directory.""" - if os.name != 'posix': - raise unittest.SkipTest('requires POSIX') - - try: - host_dir = tempfile.mkdtemp() - real_dir = os.path.join(host_dir, 'real') - tmp_dirname = os.path.basename(self.DEVICE_TEMP_DIR) - symlink = os.path.join(host_dir, tmp_dirname) - os.mkdir(real_dir) - os.symlink(real_dir, symlink) - - self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR]) - self.device.shell(['mkdir', '-p', self.DEVICE_TEMP_DIR]) - - # Populate device directory with random files. - temp_files = make_random_device_files( - self.device, in_dir=self.DEVICE_TEMP_DIR, num_files=32) - - self.device.pull(remote=self.DEVICE_TEMP_DIR, local=host_dir) - - for temp_file in temp_files: - host_path = os.path.join(real_dir, temp_file.base_name) - self._verify_local(temp_file.checksum, host_path) - - self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR]) - finally: - if host_dir is not None: - shutil.rmtree(host_dir) - - def test_pull_dir_nonexistent(self): - """Pull a directory of files from the device to a nonexistent path.""" - try: - host_dir = tempfile.mkdtemp() - dest_dir = os.path.join(host_dir, 'dest') - - self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR]) - self.device.shell(['mkdir', '-p', self.DEVICE_TEMP_DIR]) - - # Populate device directory with random files. - temp_files = make_random_device_files( - self.device, in_dir=self.DEVICE_TEMP_DIR, num_files=32) - - self.device.pull(remote=self.DEVICE_TEMP_DIR, local=dest_dir) - - for temp_file in temp_files: - host_path = os.path.join(dest_dir, temp_file.base_name) - self._verify_local(temp_file.checksum, host_path) - - self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR]) - finally: - if host_dir is not None: - shutil.rmtree(host_dir) - - # selinux prevents adbd from accessing symlinks on /data/local/tmp. - def disabled_test_pull_symlink_dir(self): - """Pull a symlink to a directory of symlinks to files.""" - try: - host_dir = tempfile.mkdtemp() - - remote_dir = posixpath.join(self.DEVICE_TEMP_DIR, 'contents') - remote_links = posixpath.join(self.DEVICE_TEMP_DIR, 'links') - remote_symlink = posixpath.join(self.DEVICE_TEMP_DIR, 'symlink') - - self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR]) - self.device.shell(['mkdir', '-p', remote_dir, remote_links]) - self.device.shell(['ln', '-s', remote_links, remote_symlink]) - - # Populate device directory with random files. - temp_files = make_random_device_files( - self.device, in_dir=remote_dir, num_files=32) - - for temp_file in temp_files: - self.device.shell( - ['ln', '-s', '../contents/{}'.format(temp_file.base_name), - posixpath.join(remote_links, temp_file.base_name)]) - - self.device.pull(remote=remote_symlink, local=host_dir) - - for temp_file in temp_files: - host_path = os.path.join( - host_dir, 'symlink', temp_file.base_name) - self._verify_local(temp_file.checksum, host_path) - - self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR]) - finally: - if host_dir is not None: - shutil.rmtree(host_dir) - - def test_pull_empty(self): - """Pull a directory containing an empty directory from the device.""" - try: - host_dir = tempfile.mkdtemp() - - remote_empty_path = posixpath.join(self.DEVICE_TEMP_DIR, 'empty') - self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR]) - self.device.shell(['mkdir', '-p', remote_empty_path]) - - self.device.pull(remote=remote_empty_path, local=host_dir) - self.assertTrue(os.path.isdir(os.path.join(host_dir, 'empty'))) - finally: - if host_dir is not None: - shutil.rmtree(host_dir) - - def test_multiple_pull(self): - """Pull a randomly generated directory of files from the device.""" - - try: - host_dir = tempfile.mkdtemp() - - subdir = posixpath.join(self.DEVICE_TEMP_DIR, 'subdir') - self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR]) - self.device.shell(['mkdir', '-p', subdir]) - - # Create some random files and a subdirectory containing more files. - temp_files = make_random_device_files( - self.device, in_dir=self.DEVICE_TEMP_DIR, num_files=4) - - subdir_temp_files = make_random_device_files( - self.device, in_dir=subdir, num_files=4, prefix='subdir_') - - paths = [x.full_path for x in temp_files] - paths.append(subdir) - self.device._simple_call(['pull'] + paths + [host_dir]) - - for temp_file in temp_files: - local_path = os.path.join(host_dir, temp_file.base_name) - self._verify_local(temp_file.checksum, local_path) - - for subdir_temp_file in subdir_temp_files: - local_path = os.path.join(host_dir, - 'subdir', - subdir_temp_file.base_name) - self._verify_local(subdir_temp_file.checksum, local_path) - - self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR]) - finally: - if host_dir is not None: - shutil.rmtree(host_dir) - - def verify_sync(self, device, temp_files, device_dir): - """Verifies that a list of temp files was synced to the device.""" - # Confirm that every file on the device mirrors that on the host. - for temp_file in temp_files: - device_full_path = posixpath.join( - device_dir, temp_file.base_name) - dev_md5, _ = device.shell( - [get_md5_prog(self.device), device_full_path])[0].split() - self.assertEqual(temp_file.checksum, dev_md5) - - def test_sync(self): - """Sync a host directory to the data partition.""" - - try: - base_dir = tempfile.mkdtemp() - - # Create mirror device directory hierarchy within base_dir. - full_dir_path = base_dir + self.DEVICE_TEMP_DIR - os.makedirs(full_dir_path) - - # Create 32 random files within the host mirror. - temp_files = make_random_host_files( - in_dir=full_dir_path, num_files=32) - - # Clean up any stale files on the device. - device = adb.get_device() # pylint: disable=no-member - device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR]) - - old_product_out = os.environ.get('ANDROID_PRODUCT_OUT') - os.environ['ANDROID_PRODUCT_OUT'] = base_dir - device.sync('data') - if old_product_out is None: - del os.environ['ANDROID_PRODUCT_OUT'] - else: - os.environ['ANDROID_PRODUCT_OUT'] = old_product_out - - self.verify_sync(device, temp_files, self.DEVICE_TEMP_DIR) - - #self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR]) - finally: - if base_dir is not None: - shutil.rmtree(base_dir) - - def test_push_sync(self): - """Sync a host directory to a specific path.""" - - try: - temp_dir = tempfile.mkdtemp() - temp_files = make_random_host_files(in_dir=temp_dir, num_files=32) - - device_dir = posixpath.join(self.DEVICE_TEMP_DIR, 'sync_src_dst') - - # Clean up any stale files on the device. - device = adb.get_device() # pylint: disable=no-member - device.shell(['rm', '-rf', device_dir]) - - device.push(temp_dir, device_dir, sync=True) - - self.verify_sync(device, temp_files, device_dir) - - self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR]) - finally: - if temp_dir is not None: - shutil.rmtree(temp_dir) - - def test_unicode_paths(self): - """Ensure that we can support non-ASCII paths, even on Windows.""" - name = u'로보카 í´ë¦¬' - - self.device.shell(['rm', '-f', '/data/local/tmp/adb-test-*']) - remote_path = u'/data/local/tmp/adb-test-{}'.format(name) - - ## push. - tf = tempfile.NamedTemporaryFile('wb', suffix=name, delete=False) - tf.close() - self.device.push(tf.name, remote_path) - os.remove(tf.name) - self.assertFalse(os.path.exists(tf.name)) - - # Verify that the device ended up with the expected UTF-8 path - output = self.device.shell( - ['ls', '/data/local/tmp/adb-test-*'])[0].strip() - self.assertEqual(remote_path, output) - - # pull. - self.device.pull(remote_path, tf.name) - self.assertTrue(os.path.exists(tf.name)) - os.remove(tf.name) - self.device.shell(['rm', '-f', '/data/local/tmp/adb-test-*']) - - -class DeviceOfflineTest(DeviceTest): - def _get_device_state(self, serialno): - output = subprocess.check_output(self.device.adb_cmd + ['devices']) - for line in output.split('\n'): - m = re.match('(\S+)\s+(\S+)', line) - if m and m.group(1) == serialno: - return m.group(2) - return None - - def disabled_test_killed_when_pushing_a_large_file(self): - """ - While running adb push with a large file, kill adb server. - Occasionally the device becomes offline. Because the device is still - reading data without realizing that the adb server has been restarted. - Test if we can bring the device online automatically now. - http://b/32952319 - """ - serialno = subprocess.check_output(self.device.adb_cmd + ['get-serialno']).strip() - # 1. Push a large file - file_path = 'tmp_large_file' - try: - fh = open(file_path, 'w') - fh.write('\0' * (100 * 1024 * 1024)) - fh.close() - subproc = subprocess.Popen(self.device.adb_cmd + ['push', file_path, '/data/local/tmp']) - time.sleep(0.1) - # 2. Kill the adb server - subprocess.check_call(self.device.adb_cmd + ['kill-server']) - subproc.terminate() - finally: - try: - os.unlink(file_path) - except: - pass - # 3. See if the device still exist. - # Sleep to wait for the adb server exit. - time.sleep(0.5) - # 4. The device should be online - self.assertEqual(self._get_device_state(serialno), 'device') - - def disabled_test_killed_when_pulling_a_large_file(self): - """ - While running adb pull with a large file, kill adb server. - Occasionally the device can't be connected. Because the device is trying to - send a message larger than what is expected by the adb server. - Test if we can bring the device online automatically now. - """ - serialno = subprocess.check_output(self.device.adb_cmd + ['get-serialno']).strip() - file_path = 'tmp_large_file' - try: - # 1. Create a large file on device. - self.device.shell(['dd', 'if=/dev/zero', 'of=/data/local/tmp/tmp_large_file', - 'bs=1000000', 'count=100']) - # 2. Pull the large file on host. - subproc = subprocess.Popen(self.device.adb_cmd + - ['pull','/data/local/tmp/tmp_large_file', file_path]) - time.sleep(0.1) - # 3. Kill the adb server - subprocess.check_call(self.device.adb_cmd + ['kill-server']) - subproc.terminate() - finally: - try: - os.unlink(file_path) - except: - pass - # 4. See if the device still exist. - # Sleep to wait for the adb server exit. - time.sleep(0.5) - self.assertEqual(self._get_device_state(serialno), 'device') - - - def test_packet_size_regression(self): - """Test for http://b/37783561 - - Receiving packets of a length divisible by 512 but not 1024 resulted in - the adb client waiting indefinitely for more input. - """ - # The values that trigger things are 507 (512 - 5 bytes from shell protocol) + 1024*n - # Probe some surrounding values as well, for the hell of it. - for base in [512] + list(range(1024, 1024 * 16, 1024)): - for offset in [-6, -5, -4]: - length = base + offset - cmd = ['dd', 'if=/dev/zero', 'bs={}'.format(length), 'count=1', '2>/dev/null;' - 'echo', 'foo'] - rc, stdout, _ = self.device.shell_nocheck(cmd) - - self.assertEqual(0, rc) - - # Output should be '\0' * length, followed by "foo\n" - self.assertEqual(length, len(stdout) - 4) - self.assertEqual(stdout, "\0" * length + "foo\n") - - def test_zero_packet(self): - """Test for http://b/113070258 - - Make sure that we don't blow up when sending USB transfers that line up - exactly with the USB packet size. - """ - - local_port = int(self.device.forward("tcp:0", "tcp:12345")) - try: - for size in [512, 1024]: - def listener(): - cmd = ["echo foo | nc -l -p 12345; echo done"] - rc, stdout, stderr = self.device.shell_nocheck(cmd) - - thread = threading.Thread(target=listener) - thread.start() - - # Wait a bit to let the shell command start. - time.sleep(0.25) - - sock = socket.create_connection(("localhost", local_port)) - with contextlib.closing(sock): - bytesWritten = sock.send(b"a" * size) - self.assertEqual(size, bytesWritten) - readBytes = sock.recv(4096) - self.assertEqual(b"foo\n", readBytes) - - thread.join() - finally: - self.device.forward_remove("tcp:{}".format(local_port)) - - -class SocketTest(DeviceTest): - def test_socket_flush(self): - """Test that we handle socket closure properly. - - If we're done writing to a socket, closing before the other end has - closed will send a TCP_RST if we have incoming data queued up, which - may result in data that we've written being discarded. - - Bug: http://b/74616284 - """ - s = socket.create_connection(("localhost", 5037)) - - def adb_length_prefixed(string): - encoded = string.encode("utf8") - result = b"%04x%s" % (len(encoded), encoded) - return result - - if "ANDROID_SERIAL" in os.environ: - transport_string = "host:transport:" + os.environ["ANDROID_SERIAL"] - else: - transport_string = "host:transport-any" - - s.sendall(adb_length_prefixed(transport_string)) - response = s.recv(4) - self.assertEqual(b"OKAY", response) - - shell_string = "shell:sleep 0.5; dd if=/dev/zero bs=1m count=1 status=none; echo foo" - s.sendall(adb_length_prefixed(shell_string)) - - response = s.recv(4) - self.assertEqual(b"OKAY", response) - - # Spawn a thread that dumps garbage into the socket until failure. - def spam(): - buf = b"\0" * 16384 - try: - while True: - s.sendall(buf) - except Exception as ex: - print(ex) - - thread = threading.Thread(target=spam) - thread.start() - - time.sleep(1) - - received = b"" - while True: - read = s.recv(512) - if len(read) == 0: - break - received += read - - self.assertEqual(1024 * 1024 + len("foo\n"), len(received)) - thread.join() - - -if sys.platform == "win32": - # From https://stackoverflow.com/a/38749458 - import os - import contextlib - import msvcrt - import ctypes - from ctypes import wintypes - - kernel32 = ctypes.WinDLL('kernel32', use_last_error=True) - - GENERIC_READ = 0x80000000 - GENERIC_WRITE = 0x40000000 - FILE_SHARE_READ = 1 - FILE_SHARE_WRITE = 2 - CONSOLE_TEXTMODE_BUFFER = 1 - INVALID_HANDLE_VALUE = wintypes.HANDLE(-1).value - STD_OUTPUT_HANDLE = wintypes.DWORD(-11) - STD_ERROR_HANDLE = wintypes.DWORD(-12) - - def _check_zero(result, func, args): - if not result: - raise ctypes.WinError(ctypes.get_last_error()) - return args - - def _check_invalid(result, func, args): - if result == INVALID_HANDLE_VALUE: - raise ctypes.WinError(ctypes.get_last_error()) - return args - - if not hasattr(wintypes, 'LPDWORD'): # Python 2 - wintypes.LPDWORD = ctypes.POINTER(wintypes.DWORD) - wintypes.PSMALL_RECT = ctypes.POINTER(wintypes.SMALL_RECT) - - class COORD(ctypes.Structure): - _fields_ = (('X', wintypes.SHORT), - ('Y', wintypes.SHORT)) - - class CONSOLE_SCREEN_BUFFER_INFOEX(ctypes.Structure): - _fields_ = (('cbSize', wintypes.ULONG), - ('dwSize', COORD), - ('dwCursorPosition', COORD), - ('wAttributes', wintypes.WORD), - ('srWindow', wintypes.SMALL_RECT), - ('dwMaximumWindowSize', COORD), - ('wPopupAttributes', wintypes.WORD), - ('bFullscreenSupported', wintypes.BOOL), - ('ColorTable', wintypes.DWORD * 16)) - def __init__(self, *args, **kwds): - super(CONSOLE_SCREEN_BUFFER_INFOEX, self).__init__( - *args, **kwds) - self.cbSize = ctypes.sizeof(self) - - PCONSOLE_SCREEN_BUFFER_INFOEX = ctypes.POINTER( - CONSOLE_SCREEN_BUFFER_INFOEX) - LPSECURITY_ATTRIBUTES = wintypes.LPVOID - - kernel32.GetStdHandle.errcheck = _check_invalid - kernel32.GetStdHandle.restype = wintypes.HANDLE - kernel32.GetStdHandle.argtypes = ( - wintypes.DWORD,) # _In_ nStdHandle - - kernel32.CreateConsoleScreenBuffer.errcheck = _check_invalid - kernel32.CreateConsoleScreenBuffer.restype = wintypes.HANDLE - kernel32.CreateConsoleScreenBuffer.argtypes = ( - wintypes.DWORD, # _In_ dwDesiredAccess - wintypes.DWORD, # _In_ dwShareMode - LPSECURITY_ATTRIBUTES, # _In_opt_ lpSecurityAttributes - wintypes.DWORD, # _In_ dwFlags - wintypes.LPVOID) # _Reserved_ lpScreenBufferData - - kernel32.GetConsoleScreenBufferInfoEx.errcheck = _check_zero - kernel32.GetConsoleScreenBufferInfoEx.argtypes = ( - wintypes.HANDLE, # _In_ hConsoleOutput - PCONSOLE_SCREEN_BUFFER_INFOEX) # _Out_ lpConsoleScreenBufferInfo - - kernel32.SetConsoleScreenBufferInfoEx.errcheck = _check_zero - kernel32.SetConsoleScreenBufferInfoEx.argtypes = ( - wintypes.HANDLE, # _In_ hConsoleOutput - PCONSOLE_SCREEN_BUFFER_INFOEX) # _In_ lpConsoleScreenBufferInfo - - kernel32.SetConsoleWindowInfo.errcheck = _check_zero - kernel32.SetConsoleWindowInfo.argtypes = ( - wintypes.HANDLE, # _In_ hConsoleOutput - wintypes.BOOL, # _In_ bAbsolute - wintypes.PSMALL_RECT) # _In_ lpConsoleWindow - - kernel32.FillConsoleOutputCharacterW.errcheck = _check_zero - kernel32.FillConsoleOutputCharacterW.argtypes = ( - wintypes.HANDLE, # _In_ hConsoleOutput - wintypes.WCHAR, # _In_ cCharacter - wintypes.DWORD, # _In_ nLength - COORD, # _In_ dwWriteCoord - wintypes.LPDWORD) # _Out_ lpNumberOfCharsWritten - - kernel32.ReadConsoleOutputCharacterW.errcheck = _check_zero - kernel32.ReadConsoleOutputCharacterW.argtypes = ( - wintypes.HANDLE, # _In_ hConsoleOutput - wintypes.LPWSTR, # _Out_ lpCharacter - wintypes.DWORD, # _In_ nLength - COORD, # _In_ dwReadCoord - wintypes.LPDWORD) # _Out_ lpNumberOfCharsRead - - @contextlib.contextmanager - def allocate_console(): - allocated = kernel32.AllocConsole() - try: - yield allocated - finally: - if allocated: - kernel32.FreeConsole() - - @contextlib.contextmanager - def console_screen(ncols=None, nrows=None): - info = CONSOLE_SCREEN_BUFFER_INFOEX() - new_info = CONSOLE_SCREEN_BUFFER_INFOEX() - nwritten = (wintypes.DWORD * 1)() - hStdOut = kernel32.GetStdHandle(STD_OUTPUT_HANDLE) - kernel32.GetConsoleScreenBufferInfoEx( - hStdOut, ctypes.byref(info)) - if ncols is None: - ncols = info.dwSize.X - if nrows is None: - nrows = info.dwSize.Y - elif nrows > 9999: - raise ValueError('nrows must be 9999 or less') - fd_screen = None - hScreen = kernel32.CreateConsoleScreenBuffer( - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, - None, CONSOLE_TEXTMODE_BUFFER, None) - try: - fd_screen = msvcrt.open_osfhandle( - hScreen, os.O_RDWR | os.O_BINARY) - kernel32.GetConsoleScreenBufferInfoEx( - hScreen, ctypes.byref(new_info)) - new_info.dwSize = COORD(ncols, nrows) - new_info.srWindow = wintypes.SMALL_RECT( - Left=0, Top=0, Right=(ncols - 1), - Bottom=(info.srWindow.Bottom - info.srWindow.Top)) - kernel32.SetConsoleScreenBufferInfoEx( - hScreen, ctypes.byref(new_info)) - kernel32.SetConsoleWindowInfo(hScreen, True, - ctypes.byref(new_info.srWindow)) - kernel32.FillConsoleOutputCharacterW( - hScreen, u'\0', ncols * nrows, COORD(0,0), nwritten) - kernel32.SetConsoleActiveScreenBuffer(hScreen) - try: - yield fd_screen - finally: - kernel32.SetConsoleScreenBufferInfoEx( - hStdOut, ctypes.byref(info)) - kernel32.SetConsoleWindowInfo(hStdOut, True, - ctypes.byref(info.srWindow)) - kernel32.SetConsoleActiveScreenBuffer(hStdOut) - finally: - if fd_screen is not None: - os.close(fd_screen) - else: - kernel32.CloseHandle(hScreen) - - def read_screen(fd): - hScreen = msvcrt.get_osfhandle(fd) - csbi = CONSOLE_SCREEN_BUFFER_INFOEX() - kernel32.GetConsoleScreenBufferInfoEx( - hScreen, ctypes.byref(csbi)) - ncols = csbi.dwSize.X - pos = csbi.dwCursorPosition - length = ncols * pos.Y + pos.X + 1 - buf = (ctypes.c_wchar * length)() - n = (wintypes.DWORD * 1)() - kernel32.ReadConsoleOutputCharacterW( - hScreen, buf, length, COORD(0,0), n) - lines = [buf[i:i+ncols].rstrip(u'\0') - for i in range(0, n[0], ncols)] - return u'\n'.join(lines) - -@unittest.skipUnless(sys.platform == "win32", "requires Windows") -class WindowsConsoleTest(DeviceTest): - def test_unicode_output(self): - """Test Unicode command line parameters and Unicode console window output. - - Bug: https://issuetracker.google.com/issues/111972753 - """ - # If we don't have a console window, allocate one. This isn't necessary if we're already - # being run from a console window, which is typical. - with allocate_console() as allocated_console: - # Create a temporary console buffer and switch to it. We could also pass a parameter of - # ncols=len(unicode_string), but it causes the window to flash as it is resized and - # likely unnecessary given the typical console window size. - with console_screen(nrows=1000) as screen: - unicode_string = u'로보카 í´ë¦¬' - # Run adb and allow it to detect that stdout is a console, not a pipe, by using - # device.shell_popen() which does not use a pipe, unlike device.shell(). - process = self.device.shell_popen(['echo', '"' + unicode_string + '"']) - process.wait() - # Read what was written by adb to the temporary console buffer. - console_output = read_screen(screen) - self.assertEqual(unicode_string, console_output) - - -def main(): - random.seed(0) - if len(adb.get_devices()) > 0: - suite = unittest.TestLoader().loadTestsFromName(__name__) - unittest.TextTestRunner(verbosity=3).run(suite) - else: - print('Test suite must be run with attached devices') - - -if __name__ == '__main__': - main() diff --git a/adb/tls/Android.bp b/adb/tls/Android.bp deleted file mode 100644 index e5204f343881565b2386779ea5b8c56d90ff9c6b..0000000000000000000000000000000000000000 --- a/adb/tls/Android.bp +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (C) 2020 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. - -cc_defaults { - name: "libadb_tls_connection_defaults", - cflags: [ - "-Wall", - "-Wextra", - "-Wthread-safety", - "-Werror", - ], - - compile_multilib: "both", - - srcs: [ - "adb_ca_list.cpp", - "tls_connection.cpp", - ], - target: { - windows: { - compile_multilib: "first", - enabled: true, - }, - }, - export_include_dirs: ["include"], - - host_supported: true, - recovery_available: true, - - visibility: [ - "//bootable/recovery/minadbd:__subpackages__", - "//system/core/adb:__subpackages__", - ], - - shared_libs: [ - "libbase", - "libcrypto", - "liblog", - "libssl", - ], -} - -cc_library { - name: "libadb_tls_connection", - defaults: ["libadb_tls_connection_defaults"], - - apex_available: [ - "com.android.adbd", - "test_com.android.adbd", - ], -} - -// For running atest (b/147158681) -cc_library_static { - name: "libadb_tls_connection_static", - defaults: ["libadb_tls_connection_defaults"], - - apex_available: [ - "//apex_available:platform", - ], -} diff --git a/adb/tls/adb_ca_list.cpp b/adb/tls/adb_ca_list.cpp deleted file mode 100644 index 36afe4209fe9067763b44a27149504a24ffff725..0000000000000000000000000000000000000000 --- a/adb/tls/adb_ca_list.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2020 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 "adb/tls/adb_ca_list.h" - -#include -#include -#include - -#include -#include -#include - -namespace adb { -namespace tls { - -namespace { - -// CA issuer identifier to distinguished embedded keys. Also has version -// information appended to the end of the string (e.g. "AdbKey-0"). -static constexpr int kAdbKeyIdentifierNid = NID_organizationName; -static constexpr char kAdbKeyIdentifierV0[] = "AdbKey-0"; - -// Where we store the actual data -static constexpr int kAdbKeyValueNid = NID_commonName; - -// TODO: Remove this once X509_NAME_add_entry_by_NID is fixed to use const unsigned char* -// https://boringssl-review.googlesource.com/c/boringssl/+/39764 -int X509_NAME_add_entry_by_NID_const(X509_NAME* name, int nid, int type, const unsigned char* bytes, - int len, int loc, int set) { - return X509_NAME_add_entry_by_NID(name, nid, type, const_cast(bytes), len, loc, - set); -} - -bool IsHexDigit(char c) { - return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'); -} - -// Wrapper around X509_NAME_get_text_by_NID that first calculates the size -// of the string. Returns empty string on failure. -std::optional GetX509NameTextByNid(X509_NAME* name, int nid) { - // |len| is the len of the text excluding the final null - int len = X509_NAME_get_text_by_NID(name, nid, nullptr, -1); - if (len <= 0) { - return std::nullopt; - } - - // Include the space for the final null byte - std::vector buf(len + 1, '\0'); - CHECK(X509_NAME_get_text_by_NID(name, nid, buf.data(), buf.size())); - return std::make_optional(std::string(buf.data())); -} - -} // namespace - -// Takes an encoded public key and generates a X509_NAME that can be used in -// TlsConnection::SetClientCAList(), to allow the client to figure out which of -// its keys it should try to use in the TLS handshake. -bssl::UniquePtr CreateCAIssuerFromEncodedKey(std::string_view key) { - // "O=AdbKey-0;CN=;" - CHECK(!key.empty()); - - std::string identifier = kAdbKeyIdentifierV0; - bssl::UniquePtr name(X509_NAME_new()); - CHECK(X509_NAME_add_entry_by_NID_const(name.get(), kAdbKeyIdentifierNid, MBSTRING_ASC, - reinterpret_cast(identifier.data()), - identifier.size(), -1, 0)); - - CHECK(X509_NAME_add_entry_by_NID_const(name.get(), kAdbKeyValueNid, MBSTRING_ASC, - reinterpret_cast(key.data()), key.size(), - -1, 0)); - return name; -} - -// Parses a CA issuer and returns the encoded key, if any. -std::optional ParseEncodedKeyFromCAIssuer(X509_NAME* issuer) { - CHECK(issuer); - - auto buf = GetX509NameTextByNid(issuer, kAdbKeyIdentifierNid); - if (!buf) { - return std::nullopt; - } - - // Check for supported versions - if (*buf == kAdbKeyIdentifierV0) { - return GetX509NameTextByNid(issuer, kAdbKeyValueNid); - } - return std::nullopt; -} - -std::string SHA256BitsToHexString(std::string_view sha256) { - CHECK_EQ(sha256.size(), static_cast(SHA256_DIGEST_LENGTH)); - std::stringstream ss; - auto* u8 = reinterpret_cast(sha256.data()); - ss << std::uppercase << std::setfill('0') << std::hex; - // Convert to hex-string representation - for (size_t i = 0; i < SHA256_DIGEST_LENGTH; ++i) { - // Need to cast to something bigger than one byte, or - // stringstream will interpret it as a char value. - ss << std::setw(2) << static_cast(u8[i]); - } - return ss.str(); -} - -std::optional SHA256HexStringToBits(std::string_view sha256_str) { - if (sha256_str.size() != SHA256_DIGEST_LENGTH * 2) { - return std::nullopt; - } - - std::string result; - for (size_t i = 0; i < SHA256_DIGEST_LENGTH; ++i) { - auto bytestr = std::string(sha256_str.substr(i * 2, 2)); - if (!IsHexDigit(bytestr[0]) || !IsHexDigit(bytestr[1])) { - LOG(ERROR) << "SHA256 string has invalid non-hex chars"; - return std::nullopt; - } - result += static_cast(std::stol(bytestr, nullptr, 16)); - } - return result; -} - -} // namespace tls -} // namespace adb diff --git a/adb/tls/include/adb/tls/adb_ca_list.h b/adb/tls/include/adb/tls/adb_ca_list.h deleted file mode 100644 index a1ab9a77937fb64b178437bc88b7a97760b347fe..0000000000000000000000000000000000000000 --- a/adb/tls/include/adb/tls/adb_ca_list.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2020 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. - */ - -#pragma once - -#include -#include -#include - -// These APIs is used to embed adbd's known public keys into client-allowed CA -// issuer list that can indicate to the client which key to use. -namespace adb { -namespace tls { - -// Takes an encoded public key and generates a X509_NAME that can be used in -// TlsConnection::SetClientCAList(), to allow the client to figure out which of -// its keys it should try to use in the TLS handshake. This is guaranteed to -// return a valid X509_NAME, given a non-empty key. -bssl::UniquePtr CreateCAIssuerFromEncodedKey(std::string_view key); - -// Parses a CA issuer and returns the encoded key, if any. On failure, returns -// nullopt. -std::optional ParseEncodedKeyFromCAIssuer(X509_NAME* issuer); - -// Converts SHA256 bits to a hex string representation. |sha256| must be exactly -// |SHA256_DIGEST_LENGTH| in size. -std::string SHA256BitsToHexString(std::string_view sha256); - -// Converts a valid SHA256 hex string to the actual bits. Returns nullopt on -// failure. -std::optional SHA256HexStringToBits(std::string_view sha256_str); - -} // namespace tls -} // namespace adb diff --git a/adb/tls/include/adb/tls/tls_connection.h b/adb/tls/include/adb/tls/tls_connection.h deleted file mode 100644 index bc5b98abf822e37648b100b7929a178034e3d64a..0000000000000000000000000000000000000000 --- a/adb/tls/include/adb/tls/tls_connection.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (C) 2020 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. - */ - -#pragma once - -#include -#include - -#include -#include - -#include -#include -#include - -namespace adb { -namespace tls { - -class TlsConnection { - public: - // This class will require both client and server to exchange valid - // certificates. - enum class Role { - Server, - Client, - }; - - enum class TlsError : uint8_t { - Success = 0, - // An error indicating that we rejected the peer's certificate. - CertificateRejected, - // An error indicating that the peer rejected our certificate. - PeerRejectedCertificate, - // Add more if needed - UnknownFailure, - }; - - using CertVerifyCb = std::function; - using SetCertCb = std::function; - - virtual ~TlsConnection() = default; - - // Adds a trusted certificate to the list for the SSL connection. - // During the handshake phase, it will check the list of trusted certificates. - // The connection will fail if the peer's certificate is not in the list. If - // you would like to accept any certificate, use #SetCertVerifyCallback and - // set your callback to always return 1. - // - // Returns true if |cert| was successfully added, false otherwise. - virtual bool AddTrustedCertificate(std::string_view cert) = 0; - - // Sets a custom certificate verify callback. |cb| must return 1 if the - // certificate is trusted. Otherwise, return 0 if not. - virtual void SetCertVerifyCallback(CertVerifyCb cb) = 0; - - // Configures a client |ca_list| that the server sends to the client in the - // CertificateRequest message. - virtual void SetClientCAList(STACK_OF(X509_NAME) * ca_list) = 0; - - // Sets a callback that will be called to select a certificate. See - // https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_CTX_set_cert_cb - // for more details. - virtual void SetCertificateCallback(SetCertCb cb) = 0; - - // Exports a value derived from the master secret used in the TLS - // connection. This value should be used alongside any PAKE to ensure the - // peer is the intended peer. |length| is the requested length for the - // keying material. This is only valid after |DoHandshake| succeeds. - virtual std::vector ExportKeyingMaterial(size_t length) = 0; - - // Enable client-side check on whether server accepted the handshake. In TLS - // 1.3, client will not know the server rejected the handshake until after - // performing a read operation. Basically, this will perform an - // SSL_peek right after the handshake and see whether that succeeds. - // - // IMPORTANT: this will only work if the protocol is a server-speaks-first - // type. Enabling this for the server is a no-op. This is disabled by - // default. - virtual void EnableClientPostHandshakeCheck(bool enable) = 0; - - // Starts the handshake process. Returns TlsError::Success if handshake - // succeeded. - virtual TlsError DoHandshake() = 0; - - // Reads |size| bytes and returns the data. The returned data has either - // size |size| or zero, in which case the read failed. - virtual std::vector ReadFully(size_t size) = 0; - - // Overloaded ReadFully method, which accepts a buffer for writing in. - // Returns true iff exactly |size| amount of data was written into |buf|, - // false otherwise. - virtual bool ReadFully(void* buf, size_t size) = 0; - - // Writes |size| bytes. Returns true if all |size| bytes were read. - // Returns false otherwise. - virtual bool WriteFully(std::string_view data) = 0; - - // Create a new TlsConnection instance. |cert| and |priv_key| cannot be - // empty. - static std::unique_ptr Create(Role role, std::string_view cert, - std::string_view priv_key, - android::base::borrowed_fd fd); - - // Helper to set the certificate and key strings to a SSL client/server. - // Useful when in the set-certificate callback. - static bool SetCertAndKey(SSL* ssl, std::string_view cert_chain, std::string_view priv_key); - - protected: - TlsConnection() = default; -}; // TlsConnection - -} // namespace tls -} // namespace adb diff --git a/adb/tls/tests/Android.bp b/adb/tls/tests/Android.bp deleted file mode 100644 index 198de58dae10b2e822fded702d69836ec1b841dc..0000000000000000000000000000000000000000 --- a/adb/tls/tests/Android.bp +++ /dev/null @@ -1,42 +0,0 @@ -// -// Copyright (C) 2019 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. -// - -cc_test { - name: "adb_tls_connection_test", - srcs: [ - "adb_ca_list_test.cpp", - "tls_connection_test.cpp", - ], - - compile_multilib: "first", - - shared_libs: [ - "libbase", - "libcrypto", - "libcrypto_utils", - "libssl", - ], - - // Let's statically link them so we don't have to install it onto the - // system image for testing. - static_libs: [ - "libadb_crypto_static", - "libadb_protos_static", - "libadb_tls_connection_static", - ], - - test_suites: ["device-tests"], -} diff --git a/adb/tls/tests/adb_ca_list_test.cpp b/adb/tls/tests/adb_ca_list_test.cpp deleted file mode 100644 index c727e5f1a11715ad36fdc7970cfc86871912bea6..0000000000000000000000000000000000000000 --- a/adb/tls/tests/adb_ca_list_test.cpp +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "AdbCAListTest" - -#include - -#include -#include -#include -#include - -namespace adb { -namespace tls { - -class AdbCAListTest : public testing::Test { - protected: - virtual void SetUp() override {} - - virtual void TearDown() override {} -}; - -TEST_F(AdbCAListTest, SHA256BitsToHexString_BadParam) { - // Should crash if not exactly SHA256_DIGEST_LENGTH size - ASSERT_DEATH( - { - // empty - std::string sha; - SHA256BitsToHexString(sha); - }, - ""); - ASSERT_DEATH( - { - std::string sha(1, 0x80); - SHA256BitsToHexString(sha); - }, - ""); - ASSERT_DEATH( - { - std::string sha(SHA256_DIGEST_LENGTH - 1, 0x80); - SHA256BitsToHexString(sha); - }, - ""); - ASSERT_DEATH( - { - std::string sha(SHA256_DIGEST_LENGTH + 1, 0x80); - SHA256BitsToHexString(sha); - }, - ""); -} - -TEST_F(AdbCAListTest, SHA256HexStringToBits_BadParam) { - { - // empty - std::string sha_str; - auto res = SHA256HexStringToBits(sha_str); - EXPECT_FALSE(res.has_value()); - } - { - std::string sha_str(1, 'a'); - auto res = SHA256HexStringToBits(sha_str); - EXPECT_FALSE(res.has_value()); - } - { - std::string sha_str(SHA256_DIGEST_LENGTH * 2 - 1, 'a'); - auto res = SHA256HexStringToBits(sha_str); - EXPECT_FALSE(res.has_value()); - } - { - std::string sha_str(SHA256_DIGEST_LENGTH * 2 + 1, 'a'); - auto res = SHA256HexStringToBits(sha_str); - EXPECT_FALSE(res.has_value()); - } - { - // Non-hex chars - std::string sha_str(SHA256_DIGEST_LENGTH * 2, 'a'); - sha_str[32] = 'x'; - auto res = SHA256HexStringToBits(sha_str); - EXPECT_FALSE(res.has_value()); - } -} - -TEST_F(AdbCAListTest, SHA256BitsToHexString_ValidParam) { - uint8_t ct = 0; - // Test every possible byte - std::vector expectedStr = { - "000102030405060708090A0B0C0D0E0F" - "101112131415161718191A1B1C1D1E1F", - - "202122232425262728292A2B2C2D2E2F" - "303132333435363738393A3B3C3D3E3F", - - "404142434445464748494A4B4C4D4E4F" - "505152535455565758595A5B5C5D5E5F", - - "606162636465666768696A6B6C6D6E6F" - "707172737475767778797A7B7C7D7E7F", - - "808182838485868788898A8B8C8D8E8F" - "909192939495969798999A9B9C9D9E9F", - - "A0A1A2A3A4A5A6A7A8A9AAABACADAEAF" - "B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF", - - "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF" - "D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF", - - "E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF" - "F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF", - }; - - for (auto& expected : expectedStr) { - std::string sha; - while (sha.size() < SHA256_DIGEST_LENGTH) { - sha += ct++; - } - - auto sha_str = SHA256BitsToHexString(sha); - EXPECT_EQ(expected, sha_str); - - // try to convert back to bits - auto out_sha = SHA256HexStringToBits(sha_str); - ASSERT_TRUE(out_sha.has_value()); - EXPECT_EQ(*out_sha, sha); - } -} - -TEST_F(AdbCAListTest, CreateCAIssuerFromEncodedKey_EmptyKey) { - ASSERT_DEATH({ auto issuer = CreateCAIssuerFromEncodedKey(""); }, ""); -} - -TEST_F(AdbCAListTest, Smoke) { - { - std::string key = - "A45BC1FF6C89BF0E" - "65F9BA153FBC9876" - "4969B4113F1CF878" - "EEF9BF1C3F9C9227"; - auto issuer = CreateCAIssuerFromEncodedKey(key); - ASSERT_NE(issuer, nullptr); - - // Try to parse the encoded key out of the X509_NAME - auto out_key = ParseEncodedKeyFromCAIssuer(issuer.get()); - ASSERT_TRUE(out_key.has_value()); - EXPECT_EQ(key, *out_key); - } -} - -} // namespace tls -} // namespace adb diff --git a/adb/tls/tests/tls_connection_test.cpp b/adb/tls/tests/tls_connection_test.cpp deleted file mode 100644 index 27bc1c9289a6aa18601f3c317a28b9bfce187373..0000000000000000000000000000000000000000 --- a/adb/tls/tests/tls_connection_test.cpp +++ /dev/null @@ -1,608 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "AdbWifiTlsConnectionTest" - -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace adb::crypto; - -namespace adb { -namespace tls { - -using android::base::unique_fd; -using TlsError = TlsConnection::TlsError; - -// Test X.509 certificates (RSA 2048) -static const std::string kTestRsa2048ServerCert = - "-----BEGIN CERTIFICATE-----\n" - "MIIDFzCCAf+gAwIBAgIBATANBgkqhkiG9w0BAQsFADAtMQswCQYDVQQGEwJVUzEQ\n" - "MA4GA1UECgwHQW5kcm9pZDEMMAoGA1UEAwwDQWRiMB4XDTIwMDEyMTIyMjU1NVoX\n" - "DTMwMDExODIyMjU1NVowLTELMAkGA1UEBhMCVVMxEDAOBgNVBAoMB0FuZHJvaWQx\n" - "DDAKBgNVBAMMA0FkYjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK8E\n" - "2Ck9TfuKlz7wqWdMfknjZ1luFDp2IHxAUZzh/F6jeI2dOFGAjpeloSnGOE86FIaT\n" - "d1EvpyTh7nBwbrLZAA6XFZTo7Bl6BdNOQdqb2d2+cLEN0inFxqUIycevRtohUE1Y\n" - "FHM9fg442X1jOTWXjDZWeiqFWo95paAPhzm6pWqfJK1+YKfT1LsWZpYqJGGQE5pi\n" - "C3qOBYYgFpoXMxTYJNoZo3uOYEdM6upc8/vh15nMgIxX/ymJxEY5BHPpZPPWjXLg\n" - "BfzVaV9fUfv0JT4HQ4t2WvxC3cD/UsjWp2a6p454uUp2ENrANa+jRdRJepepg9D2\n" - "DKsx9L8zjc5Obqexrt0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B\n" - "Af8EBAMCAYYwHQYDVR0OBBYEFDFW+8GTErwoZN5Uu9KyY4QdGYKpMA0GCSqGSIb3\n" - "DQEBCwUAA4IBAQBCDEn6SHXGlq5TU7J8cg1kRPd9bsJW+0hDuKSq0REXDkl0PcBf\n" - "fy282Agg9enKPPKmnpeQjM1dmnxdM8tT8LIUbMl779i3fn6v9HJVB+yG4gmRFThW\n" - "c+AGlBnrIT820cX/gU3h3R3FTahfsq+1rrSJkEgHyuC0HYeRyveSckBdaEOLvx0S\n" - "toun+32JJl5hWydpUUZhE9Mbb3KHBRM2YYZZU9JeJ08Apjl+3lRUeMAUwI5fkAAu\n" - "z/1SqnuGL96bd8P5ixdkA1+rF8FPhodGcq9mQOuUGP9g5HOXjaNoJYvwVRUdLeGh\n" - "cP/ReOTwQIzM1K5a83p8cX8AGGYmM7dQp7ec\n" - "-----END CERTIFICATE-----\n"; - -static const std::string kTestRsa2048ServerPrivKey = - "-----BEGIN PRIVATE KEY-----\n" - "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCvBNgpPU37ipc+\n" - "8KlnTH5J42dZbhQ6diB8QFGc4fxeo3iNnThRgI6XpaEpxjhPOhSGk3dRL6ck4e5w\n" - "cG6y2QAOlxWU6OwZegXTTkHam9ndvnCxDdIpxcalCMnHr0baIVBNWBRzPX4OONl9\n" - "Yzk1l4w2VnoqhVqPeaWgD4c5uqVqnyStfmCn09S7FmaWKiRhkBOaYgt6jgWGIBaa\n" - "FzMU2CTaGaN7jmBHTOrqXPP74deZzICMV/8picRGOQRz6WTz1o1y4AX81WlfX1H7\n" - "9CU+B0OLdlr8Qt3A/1LI1qdmuqeOeLlKdhDawDWvo0XUSXqXqYPQ9gyrMfS/M43O\n" - "Tm6nsa7dAgMBAAECggEAFCS2bPdUKIgjbzLgtHW+hT+J2hD20rcHdyAp+dNH/2vI\n" - "yLfDJHJA4chGMRondKA704oDw2bSJxxlG9t83326lB35yxPhye7cM8fqgWrK8PVl\n" - "tU22FhO1ZgeJvb9OeXWNxKZyDW9oOOJ8eazNXVMuEo+dFj7B6l3MXQyHJPL2mJDm\n" - "u9ofFLdypX+gJncVO0oW0FNJnEUn2MMwHDNlo7gc4WdQuidPkuZItKRGcB8TTGF3\n" - "Ka1/2taYdTQ4Aq//Z84LlFvE0zD3T4c8LwYYzOzD4gGGTXvft7vSHzIun1S8YLRS\n" - "dEKXdVjtaFhgH3uUe4j+1b/vMvSHeoGBNX/G88GD+wKBgQDWUYVlMVqc9HD2IeYi\n" - "EfBcNwAJFJkh51yAl5QbUBgFYgFJVkkS/EDxEGFPvEmI3/pAeQFHFY13BI466EPs\n" - "o8Z8UUwWDp+Z1MFHHKQKnFakbsZbZlbqjJ9VJsqpezbpWhMHTOmcG0dmE7rf0lyM\n" - "eQv9slBB8qp2NEUs5Of7f2C2bwKBgQDRDq4nUuMQF1hbjM05tGKSIwkobmGsLspv\n" - "TMhkM7fq4RpbFHmbNgsFqMhcqYZ8gY6/scv5KCuAZ4yHUkbqwf5h+QCwrJ4uJeUJ\n" - "ZgJfHus2mmcNSo8FwSkNoojIQtzcbJav7bs2K9VTuertk/i7IJLApU4FOZZ5pghN\n" - "EXu0CZF1cwKBgDWFGhjRIF29tU/h20R60llU6s9Zs3wB+NmsALJpZ/ZAKS4VPB5f\n" - "nCAXBRYSYRKrTCU5kpYbzb4BBzuysPOxWmnFK4j+keCqfrGxd02nCQP7HdHJVr8v\n" - "6sIq88UrHeVcNxBFprjzHvtgxfQK5k22FMZ/9wbhAKyQFQ5HA5+MiaxFAoGAIcZZ\n" - "ZIkDninnYIMS9OursShv5lRO+15j3i9tgKLKZ+wOMgDQ1L6acUOfezj4PU1BHr8+\n" - "0PYocQpJreMhCfRlgLaV4fVBaPs+UZJld7CrF5tCYudUy/01ALrtlk0XGZWBktK5\n" - "mDrksC4tQkzRtonAq9cJD9cJ9IVaefkFH0UcdvkCgYBpZj50VLeGhnHHBnkJRlV1\n" - "fV+/P6PAq6RtqjA6O9Qdaoj5V3w2d63aQcQXQLJjH2BBmtCIy47r04rFvZpbCxP7\n" - "NH/OnK9NHpk2ucRTe8TAnVbvF/TZzPJoIxAO/D3OWaW6df4R8en8u6GYzWFglAyT\n" - "sydGT8yfWD1FYUWgfrVRbg==\n" - "-----END PRIVATE KEY-----\n"; - -static const std::string kTestRsa2048ClientCert = - "-----BEGIN CERTIFICATE-----\n" - "MIIDFzCCAf+gAwIBAgIBATANBgkqhkiG9w0BAQsFADAtMQswCQYDVQQGEwJVUzEQ\n" - "MA4GA1UECgwHQW5kcm9pZDEMMAoGA1UEAwwDQWRiMB4XDTIwMDEyMTIyMjU1NloX\n" - "DTMwMDExODIyMjU1NlowLTELMAkGA1UEBhMCVVMxEDAOBgNVBAoMB0FuZHJvaWQx\n" - "DDAKBgNVBAMMA0FkYjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI3a\n" - "EXh1S5FTbet7JVONswffRPaekdIK53cb8SnAbSO9X5OLA4zGwdkrBvDTsd96SKrp\n" - "JxmoNOE1DhbZh05KPlWAPkGKacjGWaz+S7biDOL0I6aaLbTlU/il1Ub9olPSBVUx\n" - "0nhdtEFgIOzddnP6/1KmyIIeRxS5lTKeg4avqUkZNXkz/wL1dHBFL7FNFf0SCcbo\n" - "tsub/deFbjZ27LTDN+SIBgFttTNqC5NTvoBAoMdyCOAgNYwaHO+fKiK3edfJieaw\n" - "7HD8qqmQxcpCtRlA8CUPj7GfR+WHiCJmlevhnkFXCo56R1BS0F4wuD4KPdSWt8gc\n" - "27ejH/9/z2cKo/6SLJMCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B\n" - "Af8EBAMCAYYwHQYDVR0OBBYEFO/Mr5ygqqpyU/EHM9v7RDvcqaOkMA0GCSqGSIb3\n" - "DQEBCwUAA4IBAQAH33KMouzF2DYbjg90KDrDQr4rq3WfNb6P743knxdUFuvb+40U\n" - "QjC2OJZHkSexH7wfG/y6ic7vfCfF4clNs3QvU1lEjOZC57St8Fk7mdNdsWLwxEMD\n" - "uePFz0dvclSxNUHyCVMqNxddzQYzxiDWQRmXWrUBliMduQqEQelcxW2yDtg8bj+s\n" - "aMpR1ra9scaD4jzIZIIxLoOS9zBMuNRbgP217sZrniyGMhzoI1pZ/izN4oXpyH7O\n" - "THuaCzzRT3ph2f8EgmHSodz3ttgSf2DHzi/Ez1xUkk7NOlgNtmsxEdrM47+cC5ae\n" - "fIf2V+1o1JW8J7D11RmRbNPh3vfisueB4f88\n" - "-----END CERTIFICATE-----\n"; - -static const std::string kTestRsa2048ClientPrivKey = - "-----BEGIN PRIVATE KEY-----\n" - "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCN2hF4dUuRU23r\n" - "eyVTjbMH30T2npHSCud3G/EpwG0jvV+TiwOMxsHZKwbw07Hfekiq6ScZqDThNQ4W\n" - "2YdOSj5VgD5BimnIxlms/ku24gzi9COmmi205VP4pdVG/aJT0gVVMdJ4XbRBYCDs\n" - "3XZz+v9SpsiCHkcUuZUynoOGr6lJGTV5M/8C9XRwRS+xTRX9EgnG6LbLm/3XhW42\n" - "duy0wzfkiAYBbbUzaguTU76AQKDHcgjgIDWMGhzvnyoit3nXyYnmsOxw/KqpkMXK\n" - "QrUZQPAlD4+xn0flh4giZpXr4Z5BVwqOekdQUtBeMLg+Cj3UlrfIHNu3ox//f89n\n" - "CqP+kiyTAgMBAAECggEAAa64eP6ggCob1P3c73oayYPIbvRqiQdAFOrr7Vwu7zbr\n" - "z0rde+n6RU0mrpc+4NuzyPMtrOGQiatLbidJB5Cx3z8U00ovqbCl7PtcgorOhFKe\n" - "VEzihebCcYyQqbWQcKtpDMhOgBxRwFoXieJb6VGXfa96FAZalCWvXgOrTl7/BF2X\n" - "qMqIm9nJi+yS5tIO8VdOsOmrMWRH/b/ENUcef4WpLoxTXr0EEgyKWraeZ/hhXo1e\n" - "z29dZKqdr9wMsq11NPsRddwS94jnDkXTo+EQyWVTfB7gb6yyp07s8jysaDb21tVv\n" - "UXB9MRhDV1mOv0ncXfXZ4/+4A2UahmZaLDAVLaat4QKBgQDAVRredhGRGl2Nkic3\n" - "KvZCAfyxug788CgasBdEiouz19iCCwcgMIDwnq0s3/WM7h/laCamT2x38riYDnpq\n" - "rkYMfuVtU9CjEL9pTrdfwbIRhTwYNqADaPz2mXwQUhRXutE5TIdgxxC/a+ZTh0qN\n" - "S+vhTj/4hf0IZhMh5Nqj7IPExQKBgQC8zxEzhmSGjys0GuE6Wl6Doo2TpiR6vwvi\n" - "xPLU9lmIz5eca/Rd/eERioFQqeoIWDLzx52DXuz6rUoQhbJWz9hP3yqCwXD+pbNP\n" - "oDJqDDbCC4IMYEb0IK/PEPH+gIpnTjoFcW+ecKDFG7W5Lt05J8WsJsfOaJvMrOU+\n" - "dLXq3IgxdwKBgQC5RAFq0v6e8G+3hFaEHL0z3igkpt3zJf7rnj37hx2FMmDa+3Z0\n" - "umQp5B9af61PgL12xLmeMBmC/Wp1BlVDV/Yf6Uhk5Hyv5t0KuomHEtTNbbLyfAPs\n" - "5P/vJu/L5NS1oT4S3LX3MineyjgGs+bLbpub3z1dzutrYLADUSiPCK/xJQKBgBQt\n" - "nQ0Ao+Wtj1R2OvPdjJRM3wyUiPmFSWPm4HzaBx+T8AQLlYYmB9O0FbXlMtnJc0iS\n" - "YMcVcgYoVu4FG9YjSF7g3s4yljzgwJUV7c1fmMqMKE3iTDLy+1cJ3JLycdgwiArk\n" - "4KTyLHxkRbuQwpvFIF8RlfD9RQlOwQE3v+llwDhpAoGBAL6XG6Rp6mBoD2Ds5c9R\n" - "943yYgSUes3ji1SI9zFqeJtj8Ml/enuK1xu+8E/BxB0//+vgZsH6i3i8GFwygKey\n" - "CGJF8CbiHc3EJc3NQIIRXcni/CGacf0HwC6m+PGFDBIpA4H2iDpVvCSofxttQiq0\n" - "/Z7HXmXUvZHVyYi/QzX2Gahj\n" - "-----END PRIVATE KEY-----\n"; - -static const std::string kTestRsa2048UnknownPrivKey = - "-----BEGIN PRIVATE KEY-----\n" - "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCrIhr+CS+6UI0w\n" - "CTaVzQAicKBe6X531LeQAGYx7j5RLHR1QIoJ0WCc5msmXKe2VzcWuLbVdTGAIP1H\n" - "mwbPqlbO4ioxeJhiDv+WPuLG8+j4Iw1Yqxt8cfohxjfvNmIQM8aF5hGyyaaTetDF\n" - "EYWONoYCBC4WnFWgYCPb8mzWXlhHE3F66GnHpc32zydPTg3ZurGvSsFf7fNY9yRw\n" - "8WtwPiI6mpRxt+n2bQUp+LZ+g/3rXLFPg8uWDGYG7IvLluWc9gR9lxjL64t6ryLU\n" - "2cm7eTfDgLw/B1F/wEgCJDnby1JgQ4rq6klJO3BR2ooUr/7T343y5njG5hQJreV7\n" - "5ZnSmRLZAgMBAAECggEABPrfeHZFuWkj7KqN+DbAmt/2aMCodZ3+7/20+528WkIe\n" - "CvXzdmTth+9UHagLWNzpnVuHdYd9JuZ+3F00aelh8JAIDIu++naHhUSj9ohtRoBF\n" - "oIeNK5ZJAj/Zi5hkauaIz8dxyyc/VdIYfm2bundXd7pNqYqH2tyFWp6PwH67GKlZ\n" - "1lC7o8gKAK8sz9g0Ctdoe+hDqAsvYFCW4EWDM2qboucSgn8g3E/Gux/KrpXVv7d0\n" - "PMQ60m+dyTOCMGqXIoDR3TAvQR7ex5sQ/QZSREdxKy878s/2FY4ktxtCUWlhrmcI\n" - "VKtrDOGEKwNoiMluf2635rsVq2e01XhQlmdxbRFU0QKBgQDjOhhD1m9duFTQ2b+J\n" - "Xfn6m8Rs7sZqO4Az7gLOWmD/vYWlK4n2nZsh6u5/cB1N+PA+ncvvV4yKJAlLHxbT\n" - "pVvfzJ/jbUsj/NJg/w7+KYC9gXgRmBonuG2gRZF/5Otdlza4vMcoSkqGjlGxJyzL\n" - "+9umEziN3tEYMRwipYvt7BgbUQKBgQDAzaXryJ3YD3jpecy/+fSnQvFjpyeDRqU1\n" - "KDA9nxN5tJN6bnKhUlMhy64SsgvVX9jUuN7cK+qYV0uzdBn6kIAJNLWTdbtH93+e\n" - "vNVgluR3jmixW4QfY9vfZKdXZbVGNc0DFMi1vJqgxTgQ5Mq5PxxxRL4FsAF840V1\n" - "Wu9uhU0NCQKBgBfjga2QG8E0oeYbHmHouWE5gxsYt09v1fifqzfalJwOZsCIpUaC\n" - "J08Xjd9kABC0fT14BXqyL5pOU5PMPvAdUF1k++JDGUU9TTjZV9AsuNYziFYBMa6/\n" - "WvcgmT1i6cO7JAuj/SQlO1SOHdSME8+WOO9q0eVIaZ8repPB58YprhchAoGBAJyR\n" - "Y8AJdkTSq7nNszvi245IioYGY8vzPo3gSOyBlesrfOfbcTMYC3JSWNXNyFZKM2br\n" - "ie75qtRzb4IXMlGLrq3LI/jPjnpuvjBF4HFDl9yOxO3iB3UGPrM2pb4PVhnh7s4l\n" - "vqf2tQsBnPn7EbVFTu+ch0NPHqYwWWNnqS/zCBMhAoGBAIkYjOE0iD9W2FXee6VL\n" - "iN8wDqlqsGEEtLvykIDmTmM+ZX5ftQuPo18khpE9wQKmJ5OpoVTYIP1UsJFBakgo\n" - "+dGaf6xVuPvmydNFqixlW3z227n4Px6GX7CXlCaAleTeItezli+dWf/9astwTA3x\n" - "IazYzsxUUpZFC4dJ1GhBn3y1\n" - "-----END PRIVATE KEY-----\n"; - -static const std::string kTestRsa2048UnknownCert = - "-----BEGIN CERTIFICATE-----\n" - "MIIDFzCCAf+gAwIBAgIBATANBgkqhkiG9w0BAQsFADAtMQswCQYDVQQGEwJVUzEQ\n" - "MA4GA1UECgwHQW5kcm9pZDEMMAoGA1UEAwwDQWRiMB4XDTIwMDEyNDE4MzMwNVoX\n" - "DTMwMDEyMTE4MzMwNVowLTELMAkGA1UEBhMCVVMxEDAOBgNVBAoMB0FuZHJvaWQx\n" - "DDAKBgNVBAMMA0FkYjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKsi\n" - "Gv4JL7pQjTAJNpXNACJwoF7pfnfUt5AAZjHuPlEsdHVAignRYJzmayZcp7ZXNxa4\n" - "ttV1MYAg/UebBs+qVs7iKjF4mGIO/5Y+4sbz6PgjDVirG3xx+iHGN+82YhAzxoXm\n" - "EbLJppN60MURhY42hgIELhacVaBgI9vybNZeWEcTcXroacelzfbPJ09ODdm6sa9K\n" - "wV/t81j3JHDxa3A+IjqalHG36fZtBSn4tn6D/etcsU+Dy5YMZgbsi8uW5Zz2BH2X\n" - "GMvri3qvItTZybt5N8OAvD8HUX/ASAIkOdvLUmBDiurqSUk7cFHaihSv/tPfjfLm\n" - "eMbmFAmt5XvlmdKZEtkCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B\n" - "Af8EBAMCAYYwHQYDVR0OBBYEFDtRSOm1ilhnq6bKN4qJ1ekK/PAkMA0GCSqGSIb3\n" - "DQEBCwUAA4IBAQAP6Q8/OxnBA3BO8oxKer0tjI4rZMefUhbAKUWXYjTTNEBm5//b\n" - "lVGP2RptO7bxj8w1L3rxsjmVcv2TqBOhrbJqvGVPE2ntoYlFhBBkRvmxuu1y5W9V\n" - "uJU7SF9lNmDXShTURULu3P8GdeT1HGeXzWQ4x7VhY9a3VIbmN5VxjB+3C6hYZxSs\n" - "DCpmidu/sR+n5Azlh6oqrhOxmv17PuF/ioTUsHd4y2Z41IvvO47oghxNDtboUUsg\n" - "LfsM1MOxVC9PqOfQphFU4i8owNIYzBMadDLw+1TSQj0ALqZVyc9Dq+WDFdz+JAE+\n" - "k7TkVU06UPGVSnLVzJeYwGCXQp3apBszY9vO\n" - "-----END CERTIFICATE-----\n"; - -struct CAIssuerField { - int nid; - std::vector val; -}; -using CAIssuer = std::vector; -static std::vector kCAIssuers = { - { - {NID_commonName, {'a', 'b', 'c', 'd', 'e'}}, - {NID_organizationName, {'d', 'e', 'f', 'g'}}, - }, - { - {NID_commonName, {'h', 'i', 'j', 'k', 'l', 'm'}}, - {NID_countryName, {'n', 'o'}}, - }, -}; - -class AdbWifiTlsConnectionTest : public testing::Test { - protected: - virtual void SetUp() override { - android::base::Socketpair(SOCK_STREAM, &server_fd_, &client_fd_); - server_ = TlsConnection::Create(TlsConnection::Role::Server, kTestRsa2048ServerCert, - kTestRsa2048ServerPrivKey, server_fd_); - client_ = TlsConnection::Create(TlsConnection::Role::Client, kTestRsa2048ClientCert, - kTestRsa2048ClientPrivKey, client_fd_); - ASSERT_NE(nullptr, server_); - ASSERT_NE(nullptr, client_); - } - - virtual void TearDown() override { - WaitForClientConnection(); - // Shutdown the SSL connection first. - server_.reset(); - client_.reset(); - } - - bssl::UniquePtr GetCAIssuerList() { - bssl::UniquePtr ret(sk_X509_NAME_new_null()); - for (auto& issuer : kCAIssuers) { - bssl::UniquePtr name(X509_NAME_new()); - for (auto& attr : issuer) { - CHECK(X509_NAME_add_entry_by_NID(name.get(), attr.nid, MBSTRING_ASC, - attr.val.data(), attr.val.size(), -1, 0)); - } - - CHECK(bssl::PushToStack(ret.get(), std::move(name))); - } - - return ret; - } - - void StartClientHandshakeAsync(TlsError expected) { - client_thread_ = std::thread([=]() { EXPECT_EQ(client_->DoHandshake(), expected); }); - } - - void WaitForClientConnection() { - if (client_thread_.joinable()) { - client_thread_.join(); - } - } - - unique_fd server_fd_; - unique_fd client_fd_; - const std::vector msg_{0xff, 0xab, 0x32, 0xf6, 0x12, 0x56}; - std::unique_ptr server_; - std::unique_ptr client_; - std::thread client_thread_; -}; - -TEST_F(AdbWifiTlsConnectionTest, InvalidCreationParams) { - // Verify that passing empty certificate/private key results in a crash. - ASSERT_DEATH( - { - server_ = TlsConnection::Create(TlsConnection::Role::Server, "", - kTestRsa2048ServerPrivKey, server_fd_); - }, - ""); - ASSERT_DEATH( - { - server_ = TlsConnection::Create(TlsConnection::Role::Server, kTestRsa2048ServerCert, - "", server_fd_); - }, - ""); - ASSERT_DEATH( - { - client_ = TlsConnection::Create(TlsConnection::Role::Client, "", - kTestRsa2048ClientPrivKey, client_fd_); - }, - ""); - ASSERT_DEATH( - { - client_ = TlsConnection::Create(TlsConnection::Role::Client, kTestRsa2048ClientCert, - "", client_fd_); - }, - ""); -} - -TEST_F(AdbWifiTlsConnectionTest, NoCertificateVerification) { - // Allow any certificate - server_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; }); - client_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; }); - StartClientHandshakeAsync(TlsError::Success); - - // Handshake should succeed - ASSERT_EQ(server_->DoHandshake(), TlsError::Success); - WaitForClientConnection(); - - // Test client/server read and writes - client_thread_ = std::thread([&]() { - EXPECT_TRUE(client_->WriteFully( - std::string_view(reinterpret_cast(msg_.data()), msg_.size()))); - // Try with overloaded ReadFully - std::vector buf(msg_.size()); - ASSERT_TRUE(client_->ReadFully(buf.data(), msg_.size())); - EXPECT_EQ(buf, msg_); - }); - - auto data = server_->ReadFully(msg_.size()); - EXPECT_EQ(data, msg_); - EXPECT_TRUE(server_->WriteFully( - std::string_view(reinterpret_cast(msg_.data()), msg_.size()))); - - WaitForClientConnection(); -} - -TEST_F(AdbWifiTlsConnectionTest, NoTrustedCertificates) { - StartClientHandshakeAsync(TlsError::CertificateRejected); - - // Handshake should not succeed - ASSERT_EQ(server_->DoHandshake(), TlsError::PeerRejectedCertificate); - WaitForClientConnection(); - - // All writes and reads should fail - client_thread_ = std::thread([&]() { - // Client write, server read should fail - EXPECT_FALSE(client_->WriteFully( - std::string_view(reinterpret_cast(msg_.data()), msg_.size()))); - auto data = client_->ReadFully(msg_.size()); - EXPECT_EQ(data.size(), 0); - }); - - auto data = server_->ReadFully(msg_.size()); - EXPECT_EQ(data.size(), 0); - EXPECT_FALSE(server_->WriteFully( - std::string_view(reinterpret_cast(msg_.data()), msg_.size()))); - - WaitForClientConnection(); -} - -TEST_F(AdbWifiTlsConnectionTest, AddTrustedCertificates) { - // Add peer certificates - EXPECT_TRUE(client_->AddTrustedCertificate(kTestRsa2048ServerCert)); - EXPECT_TRUE(server_->AddTrustedCertificate(kTestRsa2048ClientCert)); - - StartClientHandshakeAsync(TlsError::Success); - - // Handshake should succeed - ASSERT_EQ(server_->DoHandshake(), TlsError::Success); - WaitForClientConnection(); - - // All read writes should succeed - client_thread_ = std::thread([&]() { - EXPECT_TRUE(client_->WriteFully( - std::string_view(reinterpret_cast(msg_.data()), msg_.size()))); - auto data = client_->ReadFully(msg_.size()); - EXPECT_EQ(data, msg_); - }); - - auto data = server_->ReadFully(msg_.size()); - EXPECT_EQ(data, msg_); - EXPECT_TRUE(server_->WriteFully( - std::string_view(reinterpret_cast(msg_.data()), msg_.size()))); - - WaitForClientConnection(); -} - -TEST_F(AdbWifiTlsConnectionTest, AddTrustedCertificates_ClientWrongCert) { - // Server trusts a certificate, client has the wrong certificate - EXPECT_TRUE(server_->AddTrustedCertificate(kTestRsa2048UnknownCert)); - // Client accepts any certificate - client_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; }); - - // Without enabling EnableClientPostHandshakeCheck(), DoHandshake() will - // succeed, because in TLS 1.3, the client doesn't get notified if the - // server rejected the certificate until a read operation is called. - StartClientHandshakeAsync(TlsError::Success); - - // Handshake should fail for server, succeed for client - ASSERT_EQ(server_->DoHandshake(), TlsError::CertificateRejected); - WaitForClientConnection(); - - // Client writes will succeed, everything else will fail. - client_thread_ = std::thread([&]() { - EXPECT_TRUE(client_->WriteFully( - std::string_view(reinterpret_cast(msg_.data()), msg_.size()))); - auto data = client_->ReadFully(msg_.size()); - EXPECT_EQ(data.size(), 0); - }); - - auto data = server_->ReadFully(msg_.size()); - EXPECT_EQ(data.size(), 0); - EXPECT_FALSE(server_->WriteFully( - std::string_view(reinterpret_cast(msg_.data()), msg_.size()))); - - WaitForClientConnection(); -} - -TEST_F(AdbWifiTlsConnectionTest, ExportKeyingMaterial) { - // Allow any certificate - server_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; }); - client_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; }); - - // Add peer certificates - EXPECT_TRUE(client_->AddTrustedCertificate(kTestRsa2048ServerCert)); - EXPECT_TRUE(server_->AddTrustedCertificate(kTestRsa2048ClientCert)); - - StartClientHandshakeAsync(TlsError::Success); - - // Handshake should succeed - ASSERT_EQ(server_->DoHandshake(), TlsError::Success); - WaitForClientConnection(); - - // Verify the client and server's exported key material match. - const size_t key_size = 64; - auto client_key_material = client_->ExportKeyingMaterial(key_size); - ASSERT_FALSE(client_key_material.empty()); - auto server_key_material = server_->ExportKeyingMaterial(key_size); - ASSERT_TRUE(!server_key_material.empty()); - ASSERT_EQ(client_key_material.size(), key_size); - ASSERT_EQ(client_key_material, server_key_material); -} - -TEST_F(AdbWifiTlsConnectionTest, SetCertVerifyCallback_ClientAcceptsServerRejects) { - // Client accepts all - client_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; }); - // Server rejects all - server_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 0; }); - // Client handshake should succeed, because in TLS 1.3, client does not - // realize that the peer rejected the certificate until after a read - // operation. - StartClientHandshakeAsync(TlsError::Success); - - // Server handshake should fail - ASSERT_EQ(server_->DoHandshake(), TlsError::CertificateRejected); - WaitForClientConnection(); -} - -TEST_F(AdbWifiTlsConnectionTest, SetCertVerifyCallback_ClientAcceptsServerRejects_PostHSCheck) { - // Client accepts all - client_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; }); - // Client should now get a failure in the handshake - client_->EnableClientPostHandshakeCheck(true); - // Server rejects all - server_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 0; }); - - // Client handshake should fail because server rejects everything - StartClientHandshakeAsync(TlsError::PeerRejectedCertificate); - - // Server handshake should fail - ASSERT_EQ(server_->DoHandshake(), TlsError::CertificateRejected); - WaitForClientConnection(); -} - -TEST_F(AdbWifiTlsConnectionTest, SetCertVerifyCallback_ClientRejectsServerAccepts) { - // Client rejects all - client_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 0; }); - // Server accepts all - server_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; }); - // Client handshake should fail - StartClientHandshakeAsync(TlsError::CertificateRejected); - - // Server handshake should fail - ASSERT_EQ(server_->DoHandshake(), TlsError::PeerRejectedCertificate); - WaitForClientConnection(); -} - -TEST_F(AdbWifiTlsConnectionTest, SetCertVerifyCallback_ClientRejectsServerAccepts_PostHSCheck) { - // Client rejects all - client_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 0; }); - // This shouldn't affect the error types returned in the - // #SetCertVerifyCallback_ClientRejectsServerAccepts test, since - // the failure is still within the TLS 1.3 handshake. - client_->EnableClientPostHandshakeCheck(true); - // Server accepts all - server_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; }); - - // Client handshake should fail - StartClientHandshakeAsync(TlsError::CertificateRejected); - - // Server handshake should fail - ASSERT_EQ(server_->DoHandshake(), TlsError::PeerRejectedCertificate); - WaitForClientConnection(); -} - -TEST_F(AdbWifiTlsConnectionTest, EnableClientPostHandshakeCheck_ClientWrongCert) { - client_->AddTrustedCertificate(kTestRsa2048ServerCert); - // client's DoHandshake() will fail if the server rejected the certificate - client_->EnableClientPostHandshakeCheck(true); - - // Add peer certificates - EXPECT_TRUE(server_->AddTrustedCertificate(kTestRsa2048UnknownCert)); - - // Handshake should fail for client - StartClientHandshakeAsync(TlsError::PeerRejectedCertificate); - - // Handshake should fail for server - ASSERT_EQ(server_->DoHandshake(), TlsError::CertificateRejected); - WaitForClientConnection(); - - // All read writes should fail - client_thread_ = std::thread([&]() { - EXPECT_FALSE(client_->WriteFully( - std::string_view(reinterpret_cast(msg_.data()), msg_.size()))); - auto data = client_->ReadFully(msg_.size()); - EXPECT_EQ(data.size(), 0); - }); - - auto data = server_->ReadFully(msg_.size()); - EXPECT_EQ(data.size(), 0); - EXPECT_FALSE(server_->WriteFully( - std::string_view(reinterpret_cast(msg_.data()), msg_.size()))); - - WaitForClientConnection(); -} - -TEST_F(AdbWifiTlsConnectionTest, SetClientCAList_Empty) { - // Setting an empty CA list should not crash - server_->SetClientCAList(nullptr); - ASSERT_DEATH( - { - // Client cannot use this API - client_->SetClientCAList(nullptr); - }, - ""); -} - -TEST_F(AdbWifiTlsConnectionTest, SetClientCAList_Smoke) { - auto bsslIssuerList = GetCAIssuerList(); - server_->SetClientCAList(bsslIssuerList.get()); - client_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; }); - - client_thread_ = std::thread([&]() { - client_->SetCertificateCallback([&](SSL* ssl) -> int { - const STACK_OF(X509_NAME)* received = SSL_get_client_CA_list(ssl); - EXPECT_NE(received, nullptr); - const size_t num_names = sk_X509_NAME_num(received); - EXPECT_EQ(kCAIssuers.size(), num_names); - - // Client initially registered with the wrong key. Let's change it - // here to verify this callback actually changes the client - // certificate to the right one. - EXPECT_TRUE(TlsConnection::SetCertAndKey(ssl, kTestRsa2048UnknownCert, - kTestRsa2048UnknownPrivKey)); - - const size_t buf_size = 256; - uint8_t buf[buf_size]; - size_t idx = 0; - for (auto& issuer : kCAIssuers) { - auto* name = sk_X509_NAME_value(received, idx++); - for (auto& attr : issuer) { - EXPECT_EQ(X509_NAME_get_text_by_NID(name, attr.nid, - reinterpret_cast(buf), buf_size), - attr.val.size()); - std::vector out(buf, buf + attr.val.size()); - EXPECT_EQ(out, attr.val); - } - } - - return 1; - }); - // Client handshake should succeed - ASSERT_EQ(client_->DoHandshake(), TlsError::Success); - }); - - EXPECT_TRUE(server_->AddTrustedCertificate(kTestRsa2048UnknownCert)); - // Server handshake should succeed - ASSERT_EQ(server_->DoHandshake(), TlsError::Success); - client_thread_.join(); -} - -TEST_F(AdbWifiTlsConnectionTest, SetClientCAList_AdbCAList) { - bssl::UniquePtr ca_list(sk_X509_NAME_new_null()); - std::string keyhash = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; - auto issuer = CreateCAIssuerFromEncodedKey(keyhash); - ASSERT_TRUE(bssl::PushToStack(ca_list.get(), std::move(issuer))); - server_->SetClientCAList(ca_list.get()); - client_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; }); - - client_thread_ = std::thread([&]() { - client_->SetCertificateCallback([&](SSL* ssl) -> int { - // Client initially registered with a certificate that is not trusted by - // the server. Let's test that we can change the certificate to the - // trusted one here. - const STACK_OF(X509_NAME)* received = SSL_get_client_CA_list(ssl); - EXPECT_NE(received, nullptr); - const size_t num_names = sk_X509_NAME_num(received); - EXPECT_EQ(1, num_names); - - auto* name = sk_X509_NAME_value(received, 0); - EXPECT_NE(name, nullptr); - auto enc_key = ParseEncodedKeyFromCAIssuer(name); - EXPECT_EQ(keyhash, enc_key); - - return 1; - }); - // Client handshake should succeed - ASSERT_EQ(client_->DoHandshake(), TlsError::Success); - }); - - server_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; }); - // Server handshake should succeed - ASSERT_EQ(server_->DoHandshake(), TlsError::Success); - client_thread_.join(); -} -} // namespace tls -} // namespace adb diff --git a/adb/tls/tls_connection.cpp b/adb/tls/tls_connection.cpp deleted file mode 100644 index 853cdac08ca141bfcc95d3bb8b0398a5a4522234..0000000000000000000000000000000000000000 --- a/adb/tls/tls_connection.cpp +++ /dev/null @@ -1,394 +0,0 @@ -/* - * Copyright (C) 2019 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 "adb/tls/tls_connection.h" - -#include -#include - -#include -#include -#include -#include - -using android::base::borrowed_fd; - -namespace adb { -namespace tls { - -namespace { - -static constexpr char kExportedKeyLabel[] = "adb-label"; - -class TlsConnectionImpl : public TlsConnection { - public: - explicit TlsConnectionImpl(Role role, std::string_view cert, std::string_view priv_key, - borrowed_fd fd); - ~TlsConnectionImpl() override; - - bool AddTrustedCertificate(std::string_view cert) override; - void SetCertVerifyCallback(CertVerifyCb cb) override; - void SetCertificateCallback(SetCertCb cb) override; - void SetClientCAList(STACK_OF(X509_NAME) * ca_list) override; - std::vector ExportKeyingMaterial(size_t length) override; - void EnableClientPostHandshakeCheck(bool enable) override; - TlsError DoHandshake() override; - std::vector ReadFully(size_t size) override; - bool ReadFully(void* buf, size_t size) override; - bool WriteFully(std::string_view data) override; - - static bssl::UniquePtr EvpPkeyFromPEM(std::string_view pem); - static bssl::UniquePtr BufferFromPEM(std::string_view pem); - - private: - static int SSLSetCertVerifyCb(X509_STORE_CTX* ctx, void* opaque); - static int SSLSetCertCb(SSL* ssl, void* opaque); - - static bssl::UniquePtr X509FromBuffer(bssl::UniquePtr buffer); - static const char* SSLErrorString(); - void Invalidate(); - TlsError GetFailureReason(int err); - const char* RoleToString() { return role_ == Role::Server ? kServerRoleStr : kClientRoleStr; } - - Role role_; - bssl::UniquePtr priv_key_; - bssl::UniquePtr cert_; - - bssl::UniquePtr ca_list_; - bssl::UniquePtr ssl_ctx_; - bssl::UniquePtr ssl_; - std::vector> known_certificates_; - bool client_verify_post_handshake_ = false; - - CertVerifyCb cert_verify_cb_; - SetCertCb set_cert_cb_; - borrowed_fd fd_; - static constexpr char kClientRoleStr[] = "[client]: "; - static constexpr char kServerRoleStr[] = "[server]: "; -}; // TlsConnectionImpl - -TlsConnectionImpl::TlsConnectionImpl(Role role, std::string_view cert, std::string_view priv_key, - borrowed_fd fd) - : role_(role), fd_(fd) { - CHECK(!cert.empty() && !priv_key.empty()); - LOG(INFO) << RoleToString() << "Initializing adbwifi TlsConnection"; - cert_ = BufferFromPEM(cert); - CHECK(cert_); - priv_key_ = EvpPkeyFromPEM(priv_key); - CHECK(priv_key_); -} - -TlsConnectionImpl::~TlsConnectionImpl() { - // shutdown the SSL connection - if (ssl_ != nullptr) { - SSL_shutdown(ssl_.get()); - } -} - -// static -const char* TlsConnectionImpl::SSLErrorString() { - auto sslerr = ERR_peek_last_error(); - return ERR_reason_error_string(sslerr); -} - -// static -bssl::UniquePtr TlsConnectionImpl::EvpPkeyFromPEM(std::string_view pem) { - bssl::UniquePtr bio(BIO_new_mem_buf(pem.data(), pem.size())); - return bssl::UniquePtr(PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr)); -} - -// static -bssl::UniquePtr TlsConnectionImpl::BufferFromPEM(std::string_view pem) { - bssl::UniquePtr bio(BIO_new_mem_buf(pem.data(), pem.size())); - char* name = nullptr; - char* header = nullptr; - uint8_t* data = nullptr; - long data_len = 0; - - if (!PEM_read_bio(bio.get(), &name, &header, &data, &data_len)) { - LOG(ERROR) << "Failed to read certificate"; - return nullptr; - } - OPENSSL_free(name); - OPENSSL_free(header); - - auto ret = bssl::UniquePtr(CRYPTO_BUFFER_new(data, data_len, nullptr)); - OPENSSL_free(data); - return ret; -} - -// static -bssl::UniquePtr TlsConnectionImpl::X509FromBuffer(bssl::UniquePtr buffer) { - if (!buffer) { - return nullptr; - } - return bssl::UniquePtr(X509_parse_from_buffer(buffer.get())); -} - -// static -int TlsConnectionImpl::SSLSetCertVerifyCb(X509_STORE_CTX* ctx, void* opaque) { - auto* p = reinterpret_cast(opaque); - return p->cert_verify_cb_(ctx); -} - -// static -int TlsConnectionImpl::SSLSetCertCb(SSL* ssl, void* opaque) { - auto* p = reinterpret_cast(opaque); - return p->set_cert_cb_(ssl); -} - -bool TlsConnectionImpl::AddTrustedCertificate(std::string_view cert) { - // Create X509 buffer from the certificate string - auto buf = X509FromBuffer(BufferFromPEM(cert)); - if (buf == nullptr) { - LOG(ERROR) << RoleToString() << "Failed to create a X509 buffer for the certificate."; - return false; - } - known_certificates_.push_back(std::move(buf)); - return true; -} - -void TlsConnectionImpl::SetCertVerifyCallback(CertVerifyCb cb) { - cert_verify_cb_ = cb; -} - -void TlsConnectionImpl::SetCertificateCallback(SetCertCb cb) { - set_cert_cb_ = cb; -} - -void TlsConnectionImpl::SetClientCAList(STACK_OF(X509_NAME) * ca_list) { - CHECK(role_ == Role::Server); - ca_list_.reset(ca_list != nullptr ? SSL_dup_CA_list(ca_list) : nullptr); -} - -std::vector TlsConnectionImpl::ExportKeyingMaterial(size_t length) { - if (ssl_.get() == nullptr) { - return {}; - } - - std::vector out(length); - if (SSL_export_keying_material(ssl_.get(), out.data(), out.size(), kExportedKeyLabel, - sizeof(kExportedKeyLabel), nullptr, 0, false) == 0) { - return {}; - } - return out; -} - -void TlsConnectionImpl::EnableClientPostHandshakeCheck(bool enable) { - client_verify_post_handshake_ = enable; -} - -TlsConnection::TlsError TlsConnectionImpl::GetFailureReason(int err) { - switch (ERR_GET_REASON(err)) { - case SSL_R_SSLV3_ALERT_BAD_CERTIFICATE: - case SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE: - case SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED: - case SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED: - case SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN: - case SSL_R_TLSV1_ALERT_ACCESS_DENIED: - case SSL_R_TLSV1_ALERT_UNKNOWN_CA: - case SSL_R_TLSV1_CERTIFICATE_REQUIRED: - return TlsError::PeerRejectedCertificate; - case SSL_R_CERTIFICATE_VERIFY_FAILED: - return TlsError::CertificateRejected; - default: - return TlsError::UnknownFailure; - } -} - -TlsConnection::TlsError TlsConnectionImpl::DoHandshake() { - LOG(INFO) << RoleToString() << "Starting adbwifi tls handshake"; - ssl_ctx_.reset(SSL_CTX_new(TLS_method())); - // TODO: Remove set_max_proto_version() once external/boringssl is updated - // past - // https://boringssl.googlesource.com/boringssl/+/58d56f4c59969a23e5f52014e2651c76fea2f877 - if (ssl_ctx_.get() == nullptr || - !SSL_CTX_set_min_proto_version(ssl_ctx_.get(), TLS1_3_VERSION) || - !SSL_CTX_set_max_proto_version(ssl_ctx_.get(), TLS1_3_VERSION)) { - LOG(ERROR) << RoleToString() << "Failed to create SSL context"; - return TlsError::UnknownFailure; - } - - // Register user-supplied known certificates - for (auto const& cert : known_certificates_) { - if (X509_STORE_add_cert(SSL_CTX_get_cert_store(ssl_ctx_.get()), cert.get()) == 0) { - LOG(ERROR) << RoleToString() << "Unable to add certificates into the X509_STORE"; - return TlsError::UnknownFailure; - } - } - - // Custom certificate verification - if (cert_verify_cb_) { - SSL_CTX_set_cert_verify_callback(ssl_ctx_.get(), SSLSetCertVerifyCb, this); - } - - // set select certificate callback, if any. - if (set_cert_cb_) { - SSL_CTX_set_cert_cb(ssl_ctx_.get(), SSLSetCertCb, this); - } - - // Server-allowed client CA list - if (ca_list_ != nullptr) { - bssl::UniquePtr names(SSL_dup_CA_list(ca_list_.get())); - SSL_CTX_set_client_CA_list(ssl_ctx_.get(), names.release()); - } - - // Register our certificate and private key. - std::vector cert_chain = { - cert_.get(), - }; - if (!SSL_CTX_set_chain_and_key(ssl_ctx_.get(), cert_chain.data(), cert_chain.size(), - priv_key_.get(), nullptr)) { - LOG(ERROR) << RoleToString() - << "Unable to register the certificate chain file and private key [" - << SSLErrorString() << "]"; - Invalidate(); - return TlsError::UnknownFailure; - } - - SSL_CTX_set_verify(ssl_ctx_.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr); - - // Okay! Let's try to do the handshake! - ssl_.reset(SSL_new(ssl_ctx_.get())); - if (!SSL_set_fd(ssl_.get(), fd_.get())) { - LOG(ERROR) << RoleToString() << "SSL_set_fd failed. [" << SSLErrorString() << "]"; - return TlsError::UnknownFailure; - } - - switch (role_) { - case Role::Server: - SSL_set_accept_state(ssl_.get()); - break; - case Role::Client: - SSL_set_connect_state(ssl_.get()); - break; - } - if (SSL_do_handshake(ssl_.get()) != 1) { - LOG(ERROR) << RoleToString() << "Handshake failed in SSL_accept/SSL_connect [" - << SSLErrorString() << "]"; - auto sslerr = ERR_get_error(); - Invalidate(); - return GetFailureReason(sslerr); - } - - if (client_verify_post_handshake_ && role_ == Role::Client) { - uint8_t check; - // Try to peek one byte for any failures. This assumes on success that - // the server actually sends something. - if (SSL_peek(ssl_.get(), &check, 1) <= 0) { - LOG(ERROR) << RoleToString() << "Post-handshake SSL_peek failed [" << SSLErrorString() - << "]"; - auto sslerr = ERR_get_error(); - Invalidate(); - return GetFailureReason(sslerr); - } - } - - LOG(INFO) << RoleToString() << "Handshake succeeded."; - return TlsError::Success; -} - -void TlsConnectionImpl::Invalidate() { - ssl_.reset(); - ssl_ctx_.reset(); -} - -std::vector TlsConnectionImpl::ReadFully(size_t size) { - std::vector buf(size); - if (!ReadFully(buf.data(), buf.size())) { - return {}; - } - - return buf; -} - -bool TlsConnectionImpl::ReadFully(void* buf, size_t size) { - CHECK_GT(size, 0U); - if (!ssl_) { - LOG(ERROR) << RoleToString() << "Tried to read on a null SSL connection"; - return false; - } - - size_t offset = 0; - uint8_t* p8 = reinterpret_cast(buf); - while (size > 0) { - int bytes_read = - SSL_read(ssl_.get(), p8 + offset, std::min(static_cast(INT_MAX), size)); - if (bytes_read <= 0) { - LOG(ERROR) << RoleToString() << "SSL_read failed [" << SSLErrorString() << "]"; - return false; - } - size -= bytes_read; - offset += bytes_read; - } - return true; -} - -bool TlsConnectionImpl::WriteFully(std::string_view data) { - CHECK(!data.empty()); - if (!ssl_) { - LOG(ERROR) << RoleToString() << "Tried to read on a null SSL connection"; - return false; - } - - while (!data.empty()) { - int bytes_out = SSL_write(ssl_.get(), data.data(), - std::min(static_cast(INT_MAX), data.size())); - if (bytes_out <= 0) { - LOG(ERROR) << RoleToString() << "SSL_write failed [" << SSLErrorString() << "]"; - return false; - } - data = data.substr(bytes_out); - } - return true; -} -} // namespace - -// static -std::unique_ptr TlsConnection::Create(TlsConnection::Role role, - std::string_view cert, - std::string_view priv_key, borrowed_fd fd) { - CHECK(!cert.empty()); - CHECK(!priv_key.empty()); - - return std::make_unique(role, cert, priv_key, fd); -} - -// static -bool TlsConnection::SetCertAndKey(SSL* ssl, std::string_view cert, std::string_view priv_key) { - CHECK(ssl); - // Note: declaring these in local scope is okay because - // SSL_set_chain_and_key will increase the refcount (bssl::UpRef). - auto x509_cert = TlsConnectionImpl::BufferFromPEM(cert); - auto evp_pkey = TlsConnectionImpl::EvpPkeyFromPEM(priv_key); - if (x509_cert == nullptr || evp_pkey == nullptr) { - return false; - } - - std::vector cert_chain = { - x509_cert.get(), - }; - if (!SSL_set_chain_and_key(ssl, cert_chain.data(), cert_chain.size(), evp_pkey.get(), - nullptr)) { - LOG(ERROR) << "SSL_set_chain_and_key failed"; - return false; - } - - return true; -} - -} // namespace tls -} // namespace adb diff --git a/adb/tools/Android.bp b/adb/tools/Android.bp deleted file mode 100644 index 71e32b78f236aa303ab49176a40eae95116e03fd..0000000000000000000000000000000000000000 --- a/adb/tools/Android.bp +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (C) 2017 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. - -cc_binary_host { - name: "check_ms_os_desc", - - defaults: ["adb_defaults"], - - srcs: [ - "check_ms_os_desc.cpp", - ], - - static_libs: [ - "libbase", - "libusb", - ], - - stl: "libc++_static", - - dist: { - targets: [ - "sdk", - ], - }, -} diff --git a/adb/tools/check_ms_os_desc.cpp b/adb/tools/check_ms_os_desc.cpp deleted file mode 100644 index 8e858094a4da1960f864ecdf6dbfa8f526ee8014..0000000000000000000000000000000000000000 --- a/adb/tools/check_ms_os_desc.cpp +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright (C) 2019 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 - -static bool is_adb_device(libusb_device* device) { - libusb_device_descriptor device_desc; - libusb_get_device_descriptor(device, &device_desc); - if (device_desc.bDeviceClass != 0) { - return false; - } - - libusb_config_descriptor* config_desc; - int rc = libusb_get_active_config_descriptor(device, &config_desc); - if (rc != 0) { - fprintf(stderr, "failed to get config descriptor for device %u:%u: %s\n", - libusb_get_bus_number(device), libusb_get_port_number(device), - libusb_error_name(rc)); - return false; - } - - for (size_t i = 0; i < config_desc->bNumInterfaces; ++i) { - const libusb_interface* interface = &config_desc->interface[i]; - for (int j = 0; j < interface->num_altsetting; ++j) { - const libusb_interface_descriptor* interface_descriptor = &interface->altsetting[j]; - if (interface_descriptor->bInterfaceClass == 0xff && - interface_descriptor->bInterfaceSubClass == 0x42 && - interface_descriptor->bInterfaceProtocol == 1) { - return true; - } - } - } - - return false; -} - -static std::optional> get_descriptor(libusb_device_handle* handle, - uint8_t type, uint8_t index, - uint16_t length) { - std::vector result; - result.resize(length); - int rc = libusb_get_descriptor(handle, type, index, result.data(), result.size()); - if (rc < 0) { - fprintf(stderr, "libusb_get_descriptor failed: %s\n", libusb_error_name(rc)); - return std::nullopt; - } - result.resize(rc); - return result; -} - -static std::optional get_string_descriptor(libusb_device_handle* handle, - uint8_t index) { - std::string result; - result.resize(4096); - int rc = libusb_get_string_descriptor_ascii( - handle, index, reinterpret_cast(result.data()), result.size()); - if (rc < 0) { - fprintf(stderr, "libusb_get_string_descriptor_ascii failed: %s\n", libusb_error_name(rc)); - return std::nullopt; - } - result.resize(rc); - return result; -} - -static void check_ms_os_desc_v1(libusb_device_handle* device_handle, const std::string& serial) { - auto os_desc = get_descriptor(device_handle, 0x03, 0xEE, 0x12); - if (!os_desc) { - errx(1, "failed to retrieve MS OS descriptor"); - } - - if (os_desc->size() != 0x12) { - errx(1, "os descriptor size mismatch"); - } - - if (memcmp(os_desc->data() + 2, u"MSFT100\0", 14) != 0) { - errx(1, "os descriptor signature mismatch"); - } - - uint8_t vendor_code = (*os_desc)[16]; - uint8_t pad = (*os_desc)[17]; - - if (pad != 0) { - errx(1, "os descriptor padding non-zero"); - } - - std::vector data; - data.resize(0x10); - int rc = libusb_control_transfer(device_handle, 0xC0, vendor_code, 0x00, 0x04, data.data(), - data.size(), 0); - if (rc != 0x10) { - errx(1, "failed to retrieve MS OS v1 compat descriptor header: %s", libusb_error_name(rc)); - } - - struct __attribute__((packed)) ms_os_desc_v1_header { - uint32_t dwLength; - uint16_t bcdVersion; - uint16_t wIndex; - uint8_t bCount; - uint8_t reserved[7]; - }; - static_assert(sizeof(ms_os_desc_v1_header) == 0x10); - - ms_os_desc_v1_header hdr; - memcpy(&hdr, data.data(), data.size()); - - data.resize(hdr.dwLength); - rc = libusb_control_transfer(device_handle, 0xC0, vendor_code, 0x00, 0x04, data.data(), - data.size(), 0); - if (static_cast(rc) != data.size()) { - errx(1, "failed to retrieve MS OS v1 compat descriptor: %s", libusb_error_name(rc)); - } - - struct __attribute__((packed)) ms_os_desc_v1_function { - uint8_t bFirstInterfaceNumber; - uint8_t reserved1; - uint8_t compatibleID[8]; - uint8_t subCompatibleID[8]; - uint8_t reserved2[6]; - }; - - if (sizeof(ms_os_desc_v1_header) + hdr.bCount * sizeof(ms_os_desc_v1_function) != data.size()) { - errx(1, "MS OS v1 compat descriptor size mismatch"); - } - - for (int i = 0; i < hdr.bCount; ++i) { - ms_os_desc_v1_function function; - memcpy(&function, - data.data() + sizeof(ms_os_desc_v1_header) + i * sizeof(ms_os_desc_v1_function), - sizeof(function)); - if (memcmp("WINUSB\0\0", function.compatibleID, 8) == 0) { - return; - } - } - - errx(1, "failed to find v1 MS OS descriptor specifying WinUSB for device %s", serial.c_str()); -} - -static void check_ms_os_desc_v2(libusb_device_handle* device_handle, const std::string& serial) { - libusb_bos_descriptor* bos; - int rc = libusb_get_bos_descriptor(device_handle, &bos); - - if (rc != 0) { - fprintf(stderr, "failed to get bos descriptor for device %s\n", serial.c_str()); - return; - } - - for (size_t i = 0; i < bos->bNumDeviceCaps; ++i) { - libusb_bos_dev_capability_descriptor* desc = bos->dev_capability[i]; - if (desc->bDescriptorType != LIBUSB_DT_DEVICE_CAPABILITY) { - errx(1, "invalid BOS descriptor type: %d", desc->bDescriptorType); - } - - if (desc->bDevCapabilityType != 0x05 /* PLATFORM */) { - fprintf(stderr, "skipping non-platform dev capability: %#02x\n", - desc->bDevCapabilityType); - continue; - } - - if (desc->bLength < sizeof(*desc) + 16) { - errx(1, "received device capability descriptor not long enough to contain a UUID?"); - } - - char uuid[16]; - memcpy(uuid, desc->dev_capability_data, 16); - - constexpr uint8_t ms_os_uuid[16] = {0xD8, 0xDD, 0x60, 0xDF, 0x45, 0x89, 0x4C, 0xC7, - 0x9C, 0xD2, 0x65, 0x9D, 0x9E, 0x64, 0x8A, 0x9F}; - if (memcmp(uuid, ms_os_uuid, 16) != 0) { - fprintf(stderr, "skipping unknown UUID\n"); - continue; - } - - size_t data_length = desc->bLength - sizeof(*desc) - 16; - fprintf(stderr, "found MS OS 2.0 descriptor, length = %zu\n", data_length); - - // Linux does not appear to support MS OS 2.0 Descriptors. - // TODO: If and when it does, verify that we're emitting them properly. - } -} - -int main(int argc, char** argv) { - libusb_context* ctx; - if (libusb_init(&ctx) != 0) { - errx(1, "failed to initialize libusb context"); - } - - libusb_device** device_list = nullptr; - ssize_t device_count = libusb_get_device_list(ctx, &device_list); - if (device_count < 0) { - errx(1, "libusb_get_device_list failed"); - } - - const char* expected_serial = getenv("ANDROID_SERIAL"); - bool found = false; - - for (ssize_t i = 0; i < device_count; ++i) { - libusb_device* device = device_list[i]; - if (!is_adb_device(device)) { - continue; - } - - libusb_device_handle* device_handle = nullptr; - int rc = libusb_open(device, &device_handle); - if (rc != 0) { - fprintf(stderr, "failed to open device %u:%u: %s\n", libusb_get_bus_number(device), - libusb_get_port_number(device), libusb_error_name(rc)); - continue; - } - - libusb_device_descriptor device_desc; - libusb_get_device_descriptor(device, &device_desc); - - std::optional serial = - get_string_descriptor(device_handle, device_desc.iSerialNumber); - if (!serial) { - errx(1, "failed to get serial for device %u:%u", libusb_get_bus_number(device), - libusb_get_port_number(device)); - } - - if (expected_serial && *serial != expected_serial) { - fprintf(stderr, "skipping %s (wanted %s)\n", serial->c_str(), expected_serial); - continue; - } - - // Check for MS OS Descriptor v1. - // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpeusb/c2f351f9-84d2-4a1b-9fe3-a6ca195f84d0 - fprintf(stderr, "fetching v1 OS descriptor from device %s\n", serial->c_str()); - check_ms_os_desc_v1(device_handle, *serial); - fprintf(stderr, "found v1 OS descriptor for device %s\n", serial->c_str()); - - // Read BOS for MS OS Descriptor 2.0 descriptors: - // http://download.microsoft.com/download/3/5/6/3563ED4A-F318-4B66-A181-AB1D8F6FD42D/MS_OS_2_0_desc.docx - fprintf(stderr, "fetching v2 OS descriptor from device %s\n", serial->c_str()); - check_ms_os_desc_v2(device_handle, *serial); - - found = true; - } - - if (expected_serial && !found) { - errx(1, "failed to find device with serial %s", expected_serial); - } - return 0; -} diff --git a/adb/trace.sh b/adb/trace.sh deleted file mode 100755 index 49e50264f778885a0a231cab61d1a47dab7c135a..0000000000000000000000000000000000000000 --- a/adb/trace.sh +++ /dev/null @@ -1,17 +0,0 @@ -set -e - -if ! [ -e $ANDROID_BUILD_TOP/external/chromium-trace/systrace.py ]; then - echo "error: can't find systrace.py at \$ANDROID_BUILD_TOP/external/chromium-trace/systrace.py" - exit 1 -fi - -adb shell "sleep 1; atrace -b 65536 --async_start adb sched power freq idle disk mmc load" -adb shell killall adbd -adb wait-for-device -echo "press enter to finish..." -read -TRACE_TEMP=`mktemp /tmp/trace.XXXXXX` -echo Saving trace to ${TRACE_TEMP}, html file to ${TRACE_TEMP}.html -adb shell atrace --async_stop -z > ${TRACE_TEMP} -$ANDROID_BUILD_TOP/external/chromium-trace/systrace.py --from-file=${TRACE_TEMP} -o ${TRACE_TEMP}.html -chrome ${TRACE_TEMP}.html diff --git a/adb/transport.cpp b/adb/transport.cpp deleted file mode 100644 index fe286dee4f5ab95c79f84308de6264abfbdccef1..0000000000000000000000000000000000000000 --- a/adb/transport.cpp +++ /dev/null @@ -1,1534 +0,0 @@ -/* - * 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 TRANSPORT - -#include "sysdeps.h" - -#include "transport.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "adb.h" -#include "adb_auth.h" -#include "adb_io.h" -#include "adb_trace.h" -#include "adb_utils.h" -#include "fdevent/fdevent.h" -#include "sysdeps/chrono.h" - -using namespace adb::crypto; -using namespace adb::tls; -using android::base::ScopedLockAssertion; -using TlsError = TlsConnection::TlsError; - -static void remove_transport(atransport* transport); -static void transport_destroy(atransport* transport); - -// TODO: unordered_map -static auto& transport_list = *new std::list(); -static auto& pending_list = *new std::list(); - -static auto& transport_lock = *new std::recursive_mutex(); - -const char* const kFeatureShell2 = "shell_v2"; -const char* const kFeatureCmd = "cmd"; -const char* const kFeatureStat2 = "stat_v2"; -const char* const kFeatureLs2 = "ls_v2"; -const char* const kFeatureLibusb = "libusb"; -const char* const kFeaturePushSync = "push_sync"; -const char* const kFeatureApex = "apex"; -const char* const kFeatureFixedPushMkdir = "fixed_push_mkdir"; -const char* const kFeatureAbb = "abb"; -const char* const kFeatureFixedPushSymlinkTimestamp = "fixed_push_symlink_timestamp"; -const char* const kFeatureAbbExec = "abb_exec"; -const char* const kFeatureRemountShell = "remount_shell"; -const char* const kFeatureSendRecv2 = "sendrecv_v2"; -const char* const kFeatureSendRecv2Brotli = "sendrecv_v2_brotli"; - -namespace { - -#if ADB_HOST -// Tracks and handles atransport*s that are attempting reconnection. -class ReconnectHandler { - public: - ReconnectHandler() = default; - ~ReconnectHandler() = default; - - // Starts the ReconnectHandler thread. - void Start(); - - // Requests the ReconnectHandler thread to stop. - void Stop(); - - // Adds the atransport* to the queue of reconnect attempts. - void TrackTransport(atransport* transport); - - // Wake up the ReconnectHandler thread to have it check for kicked transports. - void CheckForKicked(); - - private: - // The main thread loop. - void Run(); - - // Tracks a reconnection attempt. - struct ReconnectAttempt { - atransport* transport; - std::chrono::steady_clock::time_point reconnect_time; - size_t attempts_left; - - bool operator<(const ReconnectAttempt& rhs) const { - if (reconnect_time == rhs.reconnect_time) { - return reinterpret_cast(transport) < - reinterpret_cast(rhs.transport); - } - return reconnect_time < rhs.reconnect_time; - } - }; - - // Only retry for up to one minute. - static constexpr const std::chrono::seconds kDefaultTimeout = 10s; - static constexpr const size_t kMaxAttempts = 6; - - // Protects all members. - std::mutex reconnect_mutex_; - bool running_ GUARDED_BY(reconnect_mutex_) = true; - std::thread handler_thread_; - std::condition_variable reconnect_cv_; - std::set reconnect_queue_ GUARDED_BY(reconnect_mutex_); - - DISALLOW_COPY_AND_ASSIGN(ReconnectHandler); -}; - -void ReconnectHandler::Start() { - check_main_thread(); - handler_thread_ = std::thread(&ReconnectHandler::Run, this); -} - -void ReconnectHandler::Stop() { - check_main_thread(); - { - std::lock_guard lock(reconnect_mutex_); - running_ = false; - } - reconnect_cv_.notify_one(); - handler_thread_.join(); - - // Drain the queue to free all resources. - std::lock_guard lock(reconnect_mutex_); - while (!reconnect_queue_.empty()) { - ReconnectAttempt attempt = *reconnect_queue_.begin(); - reconnect_queue_.erase(reconnect_queue_.begin()); - remove_transport(attempt.transport); - } -} - -void ReconnectHandler::TrackTransport(atransport* transport) { - check_main_thread(); - { - std::lock_guard lock(reconnect_mutex_); - if (!running_) return; - // Arbitrary sleep to give adbd time to get ready, if we disconnected because it exited. - auto reconnect_time = std::chrono::steady_clock::now() + 250ms; - reconnect_queue_.emplace( - ReconnectAttempt{transport, reconnect_time, ReconnectHandler::kMaxAttempts}); - } - reconnect_cv_.notify_one(); -} - -void ReconnectHandler::CheckForKicked() { - reconnect_cv_.notify_one(); -} - -void ReconnectHandler::Run() { - while (true) { - ReconnectAttempt attempt; - { - std::unique_lock lock(reconnect_mutex_); - ScopedLockAssertion assume_lock(reconnect_mutex_); - - if (!reconnect_queue_.empty()) { - // FIXME: libstdc++ (used on Windows) implements condition_variable with - // system_clock as its clock, so we're probably hosed if the clock changes, - // even if we use steady_clock throughout. This problem goes away once we - // switch to libc++. - reconnect_cv_.wait_until(lock, reconnect_queue_.begin()->reconnect_time); - } else { - reconnect_cv_.wait(lock); - } - - if (!running_) return; - - // Scan the whole list for kicked transports, so that we immediately handle an explicit - // disconnect request. - bool kicked = false; - for (auto it = reconnect_queue_.begin(); it != reconnect_queue_.end();) { - if (it->transport->kicked()) { - D("transport %s was kicked. giving up on it.", it->transport->serial.c_str()); - remove_transport(it->transport); - it = reconnect_queue_.erase(it); - } else { - ++it; - } - kicked = true; - } - - if (reconnect_queue_.empty()) continue; - - // Go back to sleep if we either woke up spuriously, or we were woken up to remove - // a kicked transport, and the first transport isn't ready for reconnection yet. - auto now = std::chrono::steady_clock::now(); - if (reconnect_queue_.begin()->reconnect_time > now) { - continue; - } - - attempt = *reconnect_queue_.begin(); - reconnect_queue_.erase(reconnect_queue_.begin()); - } - D("attempting to reconnect %s", attempt.transport->serial.c_str()); - - switch (attempt.transport->Reconnect()) { - case ReconnectResult::Retry: { - D("attempting to reconnect %s failed.", attempt.transport->serial.c_str()); - if (attempt.attempts_left == 0) { - D("transport %s exceeded the number of retry attempts. giving up on it.", - attempt.transport->serial.c_str()); - remove_transport(attempt.transport); - continue; - } - - std::lock_guard lock(reconnect_mutex_); - reconnect_queue_.emplace(ReconnectAttempt{ - attempt.transport, - std::chrono::steady_clock::now() + ReconnectHandler::kDefaultTimeout, - attempt.attempts_left - 1}); - continue; - } - - case ReconnectResult::Success: - D("reconnection to %s succeeded.", attempt.transport->serial.c_str()); - register_transport(attempt.transport); - continue; - - case ReconnectResult::Abort: - D("cancelling reconnection attempt to %s.", attempt.transport->serial.c_str()); - remove_transport(attempt.transport); - continue; - } - } -} - -static auto& reconnect_handler = *new ReconnectHandler(); - -#endif - -} // namespace - -TransportId NextTransportId() { - static std::atomic next(1); - return next++; -} - -void Connection::Reset() { - LOG(INFO) << "Connection::Reset(): stopping"; - Stop(); -} - -BlockingConnectionAdapter::BlockingConnectionAdapter(std::unique_ptr connection) - : underlying_(std::move(connection)) {} - -BlockingConnectionAdapter::~BlockingConnectionAdapter() { - LOG(INFO) << "BlockingConnectionAdapter(" << this->transport_name_ << "): destructing"; - Stop(); -} - -void BlockingConnectionAdapter::Start() { - std::lock_guard lock(mutex_); - if (started_) { - LOG(FATAL) << "BlockingConnectionAdapter(" << this->transport_name_ - << "): started multiple times"; - } - - StartReadThread(); - - write_thread_ = std::thread([this]() { - LOG(INFO) << this->transport_name_ << ": write thread spawning"; - while (true) { - std::unique_lock lock(mutex_); - ScopedLockAssertion assume_locked(mutex_); - cv_.wait(lock, [this]() REQUIRES(mutex_) { - return this->stopped_ || !this->write_queue_.empty(); - }); - - if (this->stopped_) { - return; - } - - std::unique_ptr packet = std::move(this->write_queue_.front()); - this->write_queue_.pop_front(); - lock.unlock(); - - if (!this->underlying_->Write(packet.get())) { - break; - } - } - std::call_once(this->error_flag_, [this]() { this->error_callback_(this, "write failed"); }); - }); - - started_ = true; -} - -void BlockingConnectionAdapter::StartReadThread() { - read_thread_ = std::thread([this]() { - LOG(INFO) << this->transport_name_ << ": read thread spawning"; - while (true) { - auto packet = std::make_unique(); - if (!underlying_->Read(packet.get())) { - PLOG(INFO) << this->transport_name_ << ": read failed"; - break; - } - - bool got_stls_cmd = false; - if (packet->msg.command == A_STLS) { - got_stls_cmd = true; - } - - read_callback_(this, std::move(packet)); - - // If we received the STLS packet, we are about to perform the TLS - // handshake. So this read thread must stop and resume after the - // handshake completes otherwise this will interfere in the process. - if (got_stls_cmd) { - LOG(INFO) << this->transport_name_ - << ": Received STLS packet. Stopping read thread."; - return; - } - } - std::call_once(this->error_flag_, [this]() { this->error_callback_(this, "read failed"); }); - }); -} - -bool BlockingConnectionAdapter::DoTlsHandshake(RSA* key, std::string* auth_key) { - std::lock_guard lock(mutex_); - if (read_thread_.joinable()) { - read_thread_.join(); - } - bool success = this->underlying_->DoTlsHandshake(key, auth_key); - StartReadThread(); - return success; -} - -void BlockingConnectionAdapter::Reset() { - { - std::lock_guard lock(mutex_); - if (!started_) { - LOG(INFO) << "BlockingConnectionAdapter(" << this->transport_name_ << "): not started"; - return; - } - - if (stopped_) { - LOG(INFO) << "BlockingConnectionAdapter(" << this->transport_name_ - << "): already stopped"; - return; - } - } - - LOG(INFO) << "BlockingConnectionAdapter(" << this->transport_name_ << "): resetting"; - this->underlying_->Reset(); - Stop(); -} - -void BlockingConnectionAdapter::Stop() { - { - std::lock_guard lock(mutex_); - if (!started_) { - LOG(INFO) << "BlockingConnectionAdapter(" << this->transport_name_ << "): not started"; - return; - } - - if (stopped_) { - LOG(INFO) << "BlockingConnectionAdapter(" << this->transport_name_ - << "): already stopped"; - return; - } - - stopped_ = true; - } - - LOG(INFO) << "BlockingConnectionAdapter(" << this->transport_name_ << "): stopping"; - - this->underlying_->Close(); - this->cv_.notify_one(); - - // Move the threads out into locals with the lock taken, and then unlock to let them exit. - std::thread read_thread; - std::thread write_thread; - - { - std::lock_guard lock(mutex_); - read_thread = std::move(read_thread_); - write_thread = std::move(write_thread_); - } - - read_thread.join(); - write_thread.join(); - - LOG(INFO) << "BlockingConnectionAdapter(" << this->transport_name_ << "): stopped"; - std::call_once(this->error_flag_, [this]() { this->error_callback_(this, "requested stop"); }); -} - -bool BlockingConnectionAdapter::Write(std::unique_ptr packet) { - { - std::lock_guard lock(this->mutex_); - write_queue_.emplace_back(std::move(packet)); - } - - cv_.notify_one(); - return true; -} - -FdConnection::FdConnection(unique_fd fd) : fd_(std::move(fd)) {} - -FdConnection::~FdConnection() {} - -bool FdConnection::DispatchRead(void* buf, size_t len) { - if (tls_ != nullptr) { - // The TlsConnection doesn't allow 0 byte reads - if (len == 0) { - return true; - } - return tls_->ReadFully(buf, len); - } - - return ReadFdExactly(fd_.get(), buf, len); -} - -bool FdConnection::DispatchWrite(void* buf, size_t len) { - if (tls_ != nullptr) { - // The TlsConnection doesn't allow 0 byte writes - if (len == 0) { - return true; - } - return tls_->WriteFully(std::string_view(reinterpret_cast(buf), len)); - } - - return WriteFdExactly(fd_.get(), buf, len); -} - -bool FdConnection::Read(apacket* packet) { - if (!DispatchRead(&packet->msg, sizeof(amessage))) { - D("remote local: read terminated (message)"); - return false; - } - - if (packet->msg.data_length > MAX_PAYLOAD) { - D("remote local: read overflow (data length = %" PRIu32 ")", packet->msg.data_length); - return false; - } - - packet->payload.resize(packet->msg.data_length); - - if (!DispatchRead(&packet->payload[0], packet->payload.size())) { - D("remote local: terminated (data)"); - return false; - } - - return true; -} - -bool FdConnection::Write(apacket* packet) { - if (!DispatchWrite(&packet->msg, sizeof(packet->msg))) { - D("remote local: write terminated"); - return false; - } - - if (packet->msg.data_length) { - if (!DispatchWrite(&packet->payload[0], packet->msg.data_length)) { - D("remote local: write terminated"); - return false; - } - } - - return true; -} - -bool FdConnection::DoTlsHandshake(RSA* key, std::string* auth_key) { - bssl::UniquePtr evp_pkey(EVP_PKEY_new()); - if (!EVP_PKEY_set1_RSA(evp_pkey.get(), key)) { - LOG(ERROR) << "EVP_PKEY_set1_RSA failed"; - return false; - } - auto x509 = GenerateX509Certificate(evp_pkey.get()); - auto x509_str = X509ToPEMString(x509.get()); - auto evp_str = Key::ToPEMString(evp_pkey.get()); -#ifdef _WIN32 - int osh = cast_handle_to_int(adb_get_os_handle(fd_)); -#else - int osh = adb_get_os_handle(fd_); -#endif - -#if ADB_HOST - tls_ = TlsConnection::Create(TlsConnection::Role::Client, x509_str, evp_str, osh); -#else - tls_ = TlsConnection::Create(TlsConnection::Role::Server, x509_str, evp_str, osh); -#endif - CHECK(tls_); -#if ADB_HOST - // TLS 1.3 gives the client no message if the server rejected the - // certificate. This will enable a check in the tls connection to check - // whether the client certificate got rejected. Note that this assumes - // that, on handshake success, the server speaks first. - tls_->EnableClientPostHandshakeCheck(true); - // Add callback to set the certificate when server issues the - // CertificateRequest. - tls_->SetCertificateCallback(adb_tls_set_certificate); - // Allow any server certificate - tls_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; }); -#else - // Add callback to check certificate against a list of known public keys - tls_->SetCertVerifyCallback( - [auth_key](X509_STORE_CTX* ctx) { return adbd_tls_verify_cert(ctx, auth_key); }); - // Add the list of allowed client CA issuers - auto ca_list = adbd_tls_client_ca_list(); - tls_->SetClientCAList(ca_list.get()); -#endif - - auto err = tls_->DoHandshake(); - if (err == TlsError::Success) { - return true; - } - - tls_.reset(); - return false; -} - -void FdConnection::Close() { - adb_shutdown(fd_.get()); - fd_.reset(); -} - -void send_packet(apacket* p, atransport* t) { - p->msg.magic = p->msg.command ^ 0xffffffff; - // compute a checksum for connection/auth packets for compatibility reasons - if (t->get_protocol_version() >= A_VERSION_SKIP_CHECKSUM) { - p->msg.data_check = 0; - } else { - p->msg.data_check = calculate_apacket_checksum(p); - } - - VLOG(TRANSPORT) << dump_packet(t->serial.c_str(), "to remote", p); - - if (t == nullptr) { - LOG(FATAL) << "Transport is null"; - } - - if (t->Write(p) != 0) { - D("%s: failed to enqueue packet, closing transport", t->serial.c_str()); - t->Kick(); - } -} - -void kick_transport(atransport* t, bool reset) { - std::lock_guard lock(transport_lock); - // As kick_transport() can be called from threads without guarantee that t is valid, - // check if the transport is in transport_list first. - // - // TODO(jmgao): WTF? Is this actually true? - if (std::find(transport_list.begin(), transport_list.end(), t) != transport_list.end()) { - if (reset) { - t->Reset(); - } else { - t->Kick(); - } - } - -#if ADB_HOST - reconnect_handler.CheckForKicked(); -#endif -} - -static int transport_registration_send = -1; -static int transport_registration_recv = -1; -static fdevent* transport_registration_fde; - -#if ADB_HOST - -/* 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 - */ -struct device_tracker { - asocket socket; - bool update_needed = false; - bool long_output = false; - device_tracker* next = nullptr; -}; - -/* 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; - - std::lock_guard lock(transport_lock); - while (node) { - if (node == tracker) { - *pnode = node->next; - break; - } - pnode = &node->next; - node = *pnode; - } -} - -static void device_tracker_close(asocket* socket) { - device_tracker* tracker = (device_tracker*)socket; - asocket* peer = socket->peer; - - D("device tracker %p removed", tracker); - if (peer) { - peer->peer = nullptr; - peer->close(peer); - } - device_tracker_remove(tracker); - delete tracker; -} - -static int device_tracker_enqueue(asocket* socket, apacket::payload_type) { - /* you can't read from a device tracker, close immediately */ - device_tracker_close(socket); - return -1; -} - -static int device_tracker_send(device_tracker* tracker, const std::string& string) { - asocket* peer = tracker->socket.peer; - - apacket::payload_type data; - data.resize(4 + string.size()); - char buf[5]; - snprintf(buf, sizeof(buf), "%04x", static_cast(string.size())); - memcpy(&data[0], buf, 4); - memcpy(&data[4], string.data(), string.size()); - return peer->enqueue(peer, std::move(data)); -} - -static void device_tracker_ready(asocket* socket) { - device_tracker* tracker = reinterpret_cast(socket); - - // We want to send the device list when the tracker connects - // for the first time, even if no update occurred. - if (tracker->update_needed) { - tracker->update_needed = false; - device_tracker_send(tracker, list_transports(tracker->long_output)); - } -} - -asocket* create_device_tracker(bool long_output) { - device_tracker* tracker = new device_tracker(); - if (tracker == nullptr) LOG(FATAL) << "cannot allocate device tracker"; - - D("device tracker %p created", tracker); - - tracker->socket.enqueue = device_tracker_enqueue; - tracker->socket.ready = device_tracker_ready; - tracker->socket.close = device_tracker_close; - tracker->update_needed = true; - tracker->long_output = long_output; - - tracker->next = device_tracker_list; - device_tracker_list = tracker; - - return &tracker->socket; -} - -// Check if all of the USB transports are connected. -bool iterate_transports(std::function fn) { - std::lock_guard lock(transport_lock); - for (const auto& t : transport_list) { - if (!fn(t)) { - return false; - } - } - for (const auto& t : pending_list) { - if (!fn(t)) { - return false; - } - } - return true; -} - -// Call this function each time the transport list has changed. -void update_transports() { - update_transport_status(); - - // Notify `adb track-devices` clients. - device_tracker* tracker = device_tracker_list; - while (tracker != nullptr) { - device_tracker* next = tracker->next; - // This may destroy the tracker if the connection is closed. - device_tracker_send(tracker, list_transports(tracker->long_output)); - tracker = next; - } -} - -#else - -void update_transports() { - // Nothing to do on the device side. -} - -#endif // ADB_HOST - -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 { - D("transport_read_action: on fd %d: %s", fd, 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 { - D("transport_write_action: on fd %d: %s", fd, strerror(errno)); - return -1; - } - } - return 0; -} - -static void transport_registration_func(int _fd, unsigned ev, void*) { - tmsg m; - atransport* t; - - if (!(ev & FDE_READ)) { - return; - } - - if (transport_read_action(_fd, &m)) { - PLOG(FATAL) << "cannot read transport registration socket"; - } - - t = m.transport; - - if (m.action == 0) { - D("transport: %s deleting", t->serial.c_str()); - - { - std::lock_guard lock(transport_lock); - transport_list.remove(t); - } - - delete t; - - update_transports(); - return; - } - - /* don't create transport threads for inaccessible devices */ - if (t->GetConnectionState() != kCsNoPerm) { - // The connection gets a reference to the atransport. It will release it - // upon a read/write error. - t->connection()->SetTransportName(t->serial_name()); - t->connection()->SetReadCallback([t](Connection*, std::unique_ptr p) { - if (!check_header(p.get(), t)) { - D("%s: remote read: bad header", t->serial.c_str()); - return false; - } - - VLOG(TRANSPORT) << dump_packet(t->serial.c_str(), "from remote", p.get()); - apacket* packet = p.release(); - - // TODO: Does this need to run on the main thread? - fdevent_run_on_main_thread([packet, t]() { handle_packet(packet, t); }); - return true; - }); - t->connection()->SetErrorCallback([t](Connection*, const std::string& error) { - LOG(INFO) << t->serial_name() << ": connection terminated: " << error; - fdevent_run_on_main_thread([t]() { - handle_offline(t); - transport_destroy(t); - }); - }); - - t->connection()->Start(); -#if ADB_HOST - send_connect(t); -#endif - } - - { - std::lock_guard lock(transport_lock); - auto it = std::find(pending_list.begin(), pending_list.end(), t); - if (it != pending_list.end()) { - pending_list.remove(t); - transport_list.push_front(t); - } - } - - update_transports(); -} - -#if ADB_HOST -void init_reconnect_handler(void) { - reconnect_handler.Start(); -} -#endif - -void init_transport_registration(void) { - int s[2]; - - if (adb_socketpair(s)) { - PLOG(FATAL) << "cannot open transport registration socketpair"; - } - D("socketpair: (%d,%d)", s[0], s[1]); - - transport_registration_send = s[0]; - transport_registration_recv = s[1]; - - transport_registration_fde = - fdevent_create(transport_registration_recv, transport_registration_func, nullptr); - fdevent_set(transport_registration_fde, FDE_READ); -} - -void kick_all_transports() { -#if ADB_HOST - reconnect_handler.Stop(); -#endif - // To avoid only writing part of a packet to a transport after exit, kick all transports. - std::lock_guard lock(transport_lock); - for (auto t : transport_list) { - t->Kick(); - } -} - -void kick_all_tcp_tls_transports() { - std::lock_guard lock(transport_lock); - for (auto t : transport_list) { - if (t->IsTcpDevice() && t->use_tls) { - t->Kick(); - } - } -} - -#if !ADB_HOST -void kick_all_transports_by_auth_key(std::string_view auth_key) { - std::lock_guard lock(transport_lock); - for (auto t : transport_list) { - if (auth_key == t->auth_key) { - t->Kick(); - } - } -} -#endif - -/* the fdevent select pump is single threaded */ -void register_transport(atransport* transport) { - tmsg m; - m.transport = transport; - m.action = 1; - D("transport: %s registered", transport->serial.c_str()); - if (transport_write_action(transport_registration_send, &m)) { - PLOG(FATAL) << "cannot write transport registration socket"; - } -} - -static void remove_transport(atransport* transport) { - tmsg m; - m.transport = transport; - m.action = 0; - D("transport: %s removed", transport->serial.c_str()); - if (transport_write_action(transport_registration_send, &m)) { - PLOG(FATAL) << "cannot write transport registration socket"; - } -} - -static void transport_destroy(atransport* t) { - check_main_thread(); - CHECK(t != nullptr); - - std::lock_guard lock(transport_lock); - LOG(INFO) << "destroying transport " << t->serial_name(); - t->connection()->Stop(); -#if ADB_HOST - if (t->IsTcpDevice() && !t->kicked()) { - D("transport: %s destroy (attempting reconnection)", t->serial.c_str()); - - // We need to clear the transport's keys, so that on the next connection, it tries - // again from the beginning. - t->ResetKeys(); - reconnect_handler.TrackTransport(t); - return; - } -#endif - - D("transport: %s destroy (kicking and closing)", t->serial.c_str()); - remove_transport(t); -} - -static int qual_match(const std::string& to_test, const char* prefix, const std::string& qual, - bool sanitize_qual) { - if (to_test.empty()) /* Return true if both the qual and to_test are empty strings. */ - return qual.empty(); - - if (qual.empty()) return 0; - - const char* ptr = to_test.c_str(); - if (prefix) { - while (*prefix) { - if (*prefix++ != *ptr++) return 0; - } - } - - for (char ch : qual) { - if (sanitize_qual && !isalnum(ch)) ch = '_'; - if (ch != *ptr++) return 0; - } - - /* Everything matched so far. Return true if *ptr is a NUL. */ - return !*ptr; -} - -atransport* acquire_one_transport(TransportType type, const char* serial, TransportId transport_id, - bool* is_ambiguous, std::string* error_out, - bool accept_any_state) { - atransport* result = nullptr; - - if (transport_id != 0) { - *error_out = - android::base::StringPrintf("no device with transport id '%" PRIu64 "'", transport_id); - } else if (serial) { - *error_out = android::base::StringPrintf("device '%s' not found", serial); - } else if (type == kTransportLocal) { - *error_out = "no emulators found"; - } else if (type == kTransportAny) { - *error_out = "no devices/emulators found"; - } else { - *error_out = "no devices found"; - } - - std::unique_lock lock(transport_lock); - for (const auto& t : transport_list) { - if (t->GetConnectionState() == kCsNoPerm) { - *error_out = UsbNoPermissionsLongHelpText(); - continue; - } - - if (transport_id) { - if (t->id == transport_id) { - result = t; - break; - } - } else if (serial) { - if (t->MatchesTarget(serial)) { - if (result) { - *error_out = "more than one device"; - if (is_ambiguous) *is_ambiguous = true; - result = nullptr; - break; - } - result = t; - } - } else { - if (type == kTransportUsb && t->type == kTransportUsb) { - if (result) { - *error_out = "more than one device"; - if (is_ambiguous) *is_ambiguous = true; - result = nullptr; - break; - } - result = t; - } else if (type == kTransportLocal && t->type == kTransportLocal) { - if (result) { - *error_out = "more than one emulator"; - if (is_ambiguous) *is_ambiguous = true; - result = nullptr; - break; - } - result = t; - } else if (type == kTransportAny) { - if (result) { - *error_out = "more than one device/emulator"; - if (is_ambiguous) *is_ambiguous = true; - result = nullptr; - break; - } - result = t; - } - } - } - lock.unlock(); - - if (result && !accept_any_state) { - // The caller requires an active transport. - // Make sure that we're actually connected. - ConnectionState state = result->GetConnectionState(); - switch (state) { - case kCsConnecting: - *error_out = "device still connecting"; - result = nullptr; - break; - - case kCsAuthorizing: - *error_out = "device still authorizing"; - result = nullptr; - break; - - case kCsUnauthorized: { - *error_out = "device unauthorized.\n"; - char* ADB_VENDOR_KEYS = getenv("ADB_VENDOR_KEYS"); - *error_out += "This adb server's $ADB_VENDOR_KEYS is "; - *error_out += ADB_VENDOR_KEYS ? ADB_VENDOR_KEYS : "not set"; - *error_out += "\n"; - *error_out += "Try 'adb kill-server' if that seems wrong.\n"; - *error_out += "Otherwise check for a confirmation dialog on your device."; - result = nullptr; - break; - } - - case kCsOffline: - *error_out = "device offline"; - result = nullptr; - break; - - default: - break; - } - } - - if (result) { - *error_out = "success"; - } - - return result; -} - -bool ConnectionWaitable::WaitForConnection(std::chrono::milliseconds timeout) { - std::unique_lock lock(mutex_); - ScopedLockAssertion assume_locked(mutex_); - return cv_.wait_for(lock, timeout, [&]() REQUIRES(mutex_) { - return connection_established_ready_; - }) && connection_established_; -} - -void ConnectionWaitable::SetConnectionEstablished(bool success) { - { - std::lock_guard lock(mutex_); - if (connection_established_ready_) return; - connection_established_ready_ = true; - connection_established_ = success; - D("connection established with %d", success); - } - cv_.notify_one(); -} - -atransport::~atransport() { - // If the connection callback had not been run before, run it now. - SetConnectionEstablished(false); -} - -int atransport::Write(apacket* p) { - return this->connection()->Write(std::unique_ptr(p)) ? 0 : -1; -} - -void atransport::Reset() { - if (!kicked_.exchange(true)) { - LOG(INFO) << "resetting transport " << this << " " << this->serial; - this->connection()->Reset(); - } -} - -void atransport::Kick() { - if (!kicked_.exchange(true)) { - LOG(INFO) << "kicking transport " << this << " " << this->serial; - this->connection()->Stop(); - } -} - -ConnectionState atransport::GetConnectionState() const { - return connection_state_; -} - -void atransport::SetConnectionState(ConnectionState state) { - check_main_thread(); - connection_state_ = state; -} - -void atransport::SetConnection(std::unique_ptr connection) { - std::lock_guard lock(mutex_); - connection_ = std::shared_ptr(std::move(connection)); -} - -std::string atransport::connection_state_name() const { - ConnectionState state = GetConnectionState(); - switch (state) { - case kCsOffline: - return "offline"; - case kCsBootloader: - return "bootloader"; - case kCsDevice: - return "device"; - case kCsHost: - return "host"; - case kCsRecovery: - return "recovery"; - case kCsRescue: - return "rescue"; - case kCsNoPerm: - return UsbNoPermissionsShortHelpText(); - case kCsSideload: - return "sideload"; - case kCsUnauthorized: - return "unauthorized"; - case kCsAuthorizing: - return "authorizing"; - case kCsConnecting: - return "connecting"; - default: - return "unknown"; - } -} - -void atransport::update_version(int version, size_t payload) { - protocol_version = std::min(version, A_VERSION); - max_payload = std::min(payload, MAX_PAYLOAD); -} - -int atransport::get_protocol_version() const { - return protocol_version; -} - -int atransport::get_tls_version() const { - return tls_version; -} - -size_t atransport::get_max_payload() const { - return max_payload; -} - -const FeatureSet& supported_features() { - // Local static allocation to avoid global non-POD variables. - static const FeatureSet* features = new FeatureSet{ - kFeatureShell2, - kFeatureCmd, - kFeatureStat2, - kFeatureLs2, - kFeatureFixedPushMkdir, - kFeatureApex, - kFeatureAbb, - kFeatureFixedPushSymlinkTimestamp, - kFeatureAbbExec, - kFeatureRemountShell, - kFeatureSendRecv2, - kFeatureSendRecv2Brotli, - // Increment ADB_SERVER_VERSION when adding a feature that adbd needs - // to know about. Otherwise, the client can be stuck running an old - // version of the server even after upgrading their copy of adb. - // (http://b/24370690) - }; - - return *features; -} - -std::string FeatureSetToString(const FeatureSet& features) { - return android::base::Join(features, ','); -} - -FeatureSet StringToFeatureSet(const std::string& features_string) { - if (features_string.empty()) { - return FeatureSet(); - } - - auto names = android::base::Split(features_string, ","); - return FeatureSet(names.begin(), names.end()); -} - -bool CanUseFeature(const FeatureSet& feature_set, const std::string& feature) { - return feature_set.count(feature) > 0 && supported_features().count(feature) > 0; -} - -bool atransport::has_feature(const std::string& feature) const { - return features_.count(feature) > 0; -} - -void atransport::SetFeatures(const std::string& features_string) { - features_ = StringToFeatureSet(features_string); -} - -void atransport::AddDisconnect(adisconnect* disconnect) { - disconnects_.push_back(disconnect); -} - -void atransport::RemoveDisconnect(adisconnect* disconnect) { - disconnects_.remove(disconnect); -} - -void atransport::RunDisconnects() { - for (const auto& disconnect : disconnects_) { - disconnect->func(disconnect->opaque, this); - } - disconnects_.clear(); -} - -bool atransport::MatchesTarget(const std::string& target) const { - if (!serial.empty()) { - if (target == serial) { - return true; - } else if (type == kTransportLocal) { - // Local transports can match [tcp:|udp:][:port]. - const char* local_target_ptr = target.c_str(); - - // For fastboot compatibility, ignore protocol prefixes. - if (android::base::StartsWith(target, "tcp:") || - android::base::StartsWith(target, "udp:")) { - local_target_ptr += 4; - } - - // Parse our |serial| and the given |target| to check if the hostnames and ports match. - std::string serial_host, error; - int serial_port = -1; - if (android::base::ParseNetAddress(serial, &serial_host, &serial_port, nullptr, &error)) { - // |target| may omit the port to default to ours. - std::string target_host; - int target_port = serial_port; - if (android::base::ParseNetAddress(local_target_ptr, &target_host, &target_port, - nullptr, &error) && - serial_host == target_host && serial_port == target_port) { - return true; - } - } - } - } - - return (target == devpath) || qual_match(target, "product:", product, false) || - qual_match(target, "model:", model, true) || - qual_match(target, "device:", device, false); -} - -void atransport::SetConnectionEstablished(bool success) { - connection_waitable_->SetConnectionEstablished(success); -} - -ReconnectResult atransport::Reconnect() { - return reconnect_(this); -} - -#if ADB_HOST - -// We use newline as our delimiter, make sure to never output it. -static std::string sanitize(std::string str, bool alphanumeric) { - auto pred = alphanumeric ? [](const char c) { return !isalnum(c); } - : [](const char c) { return c == '\n'; }; - std::replace_if(str.begin(), str.end(), pred, '_'); - return str; -} - -static void append_transport_info(std::string* result, const char* key, const std::string& value, - bool alphanumeric) { - if (value.empty()) { - return; - } - - *result += ' '; - *result += key; - *result += sanitize(value, alphanumeric); -} - -static void append_transport(const atransport* t, std::string* result, bool long_listing) { - std::string serial = t->serial; - if (serial.empty()) { - serial = "(no serial number)"; - } - - if (!long_listing) { - *result += serial; - *result += '\t'; - *result += t->connection_state_name(); - } else { - android::base::StringAppendF(result, "%-22s %s", serial.c_str(), - t->connection_state_name().c_str()); - - append_transport_info(result, "", t->devpath, false); - append_transport_info(result, "product:", t->product, false); - append_transport_info(result, "model:", t->model, true); - append_transport_info(result, "device:", t->device, false); - - // Put id at the end, so that anyone parsing the output here can always find it by scanning - // backwards from newlines, even with hypothetical devices named 'transport_id:1'. - *result += " transport_id:"; - *result += std::to_string(t->id); - } - *result += '\n'; -} - -std::string list_transports(bool long_listing) { - std::lock_guard lock(transport_lock); - - auto sorted_transport_list = transport_list; - sorted_transport_list.sort([](atransport*& x, atransport*& y) { - if (x->type != y->type) { - return x->type < y->type; - } - return x->serial < y->serial; - }); - - std::string result; - for (const auto& t : sorted_transport_list) { - append_transport(t, &result, long_listing); - } - return result; -} - -void close_usb_devices(std::function predicate, bool reset) { - std::lock_guard lock(transport_lock); - for (auto& t : transport_list) { - if (predicate(t)) { - if (reset) { - t->Reset(); - } else { - t->Kick(); - } - } - } -} - -/* hack for osx */ -void close_usb_devices(bool reset) { - close_usb_devices([](const atransport*) { return true; }, reset); -} -#endif // ADB_HOST - -bool register_socket_transport(unique_fd s, std::string serial, int port, int local, - atransport::ReconnectCallback reconnect, bool use_tls, int* error) { - atransport* t = new atransport(std::move(reconnect), kCsOffline); - t->use_tls = use_tls; - - D("transport: %s init'ing for socket %d, on port %d", serial.c_str(), s.get(), port); - if (init_socket_transport(t, std::move(s), port, local) < 0) { - delete t; - if (error) *error = errno; - return false; - } - - std::unique_lock lock(transport_lock); - for (const auto& transport : pending_list) { - if (serial == transport->serial) { - VLOG(TRANSPORT) << "socket transport " << transport->serial - << " is already in pending_list and fails to register"; - delete t; - if (error) *error = EALREADY; - return false; - } - } - - for (const auto& transport : transport_list) { - if (serial == transport->serial) { - VLOG(TRANSPORT) << "socket transport " << transport->serial - << " is already in transport_list and fails to register"; - delete t; - if (error) *error = EALREADY; - return false; - } - } - - t->serial = std::move(serial); - pending_list.push_front(t); - - lock.unlock(); - - auto waitable = t->connection_waitable(); - register_transport(t); - - if (local == 1) { - // Do not wait for emulator transports. - return true; - } - - if (!waitable->WaitForConnection(std::chrono::seconds(10))) { - if (error) *error = ETIMEDOUT; - return false; - } - - if (t->GetConnectionState() == kCsUnauthorized) { - if (error) *error = EPERM; - return false; - } - - return true; -} - -#if ADB_HOST -atransport* find_transport(const char* serial) { - atransport* result = nullptr; - - std::lock_guard lock(transport_lock); - for (auto& t : transport_list) { - if (strcmp(serial, t->serial.c_str()) == 0) { - result = t; - break; - } - } - - return result; -} - -void kick_all_tcp_devices() { - std::lock_guard lock(transport_lock); - for (auto& t : transport_list) { - if (t->IsTcpDevice()) { - // Kicking breaks the read_transport thread of this transport out of any read, then - // the read_transport thread will notify the main thread to make this transport - // offline. Then the main thread will notify the write_transport thread to exit. - // Finally, this transport will be closed and freed in the main thread. - t->Kick(); - } - } -#if ADB_HOST - reconnect_handler.CheckForKicked(); -#endif -} - -#endif - -#if ADB_HOST -void register_usb_transport(usb_handle* usb, const char* serial, const char* devpath, - unsigned writeable) { - atransport* t = new atransport(writeable ? kCsOffline : kCsNoPerm); - - D("transport: %p init'ing for usb_handle %p (sn='%s')", t, usb, serial ? serial : ""); - init_usb_transport(t, usb); - if (serial) { - t->serial = serial; - } - - if (devpath) { - t->devpath = devpath; - } - - { - std::lock_guard lock(transport_lock); - pending_list.push_front(t); - } - - register_transport(t); -} -#endif - -#if ADB_HOST -// This should only be used for transports with connection_state == kCsNoPerm. -void unregister_usb_transport(usb_handle* usb) { - std::lock_guard lock(transport_lock); - transport_list.remove_if([usb](atransport* t) { - return t->GetUsbHandle() == usb && t->GetConnectionState() == kCsNoPerm; - }); -} -#endif - -bool check_header(apacket* p, atransport* t) { - if (p->msg.magic != (p->msg.command ^ 0xffffffff)) { - VLOG(RWX) << "check_header(): invalid magic command = " << std::hex << p->msg.command - << ", magic = " << p->msg.magic; - return false; - } - - if (p->msg.data_length > t->get_max_payload()) { - VLOG(RWX) << "check_header(): " << p->msg.data_length - << " atransport::max_payload = " << t->get_max_payload(); - return false; - } - - return true; -} - -#if ADB_HOST -std::shared_ptr atransport::Key() { - if (keys_.empty()) { - return nullptr; - } - - std::shared_ptr result = keys_[0]; - return result; -} - -std::shared_ptr atransport::NextKey() { - if (keys_.empty()) { - LOG(INFO) << "fetching keys for transport " << this->serial_name(); - keys_ = adb_auth_get_private_keys(); - - // We should have gotten at least one key: the one that's automatically generated. - CHECK(!keys_.empty()); - } else { - keys_.pop_front(); - } - - std::shared_ptr result = keys_[0]; - return result; -} - -void atransport::ResetKeys() { - keys_.clear(); -} -#endif diff --git a/adb/transport.h b/adb/transport.h deleted file mode 100644 index 26d804b3f0b09e20e911fc05344de9b50d07dc84..0000000000000000000000000000000000000000 --- a/adb/transport.h +++ /dev/null @@ -1,477 +0,0 @@ -/* - * 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 - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "adb.h" -#include "adb_unique_fd.h" -#include "types.h" - -typedef std::unordered_set FeatureSet; - -namespace adb { -namespace tls { - -class TlsConnection; - -} // namespace tls -} // namespace adb - -const FeatureSet& supported_features(); - -// Encodes and decodes FeatureSet objects into human-readable strings. -std::string FeatureSetToString(const FeatureSet& features); -FeatureSet StringToFeatureSet(const std::string& features_string); - -// Returns true if both local features and |feature_set| support |feature|. -bool CanUseFeature(const FeatureSet& feature_set, const std::string& feature); - -// Do not use any of [:;=,] in feature strings, they have special meaning -// in the connection banner. -extern const char* const kFeatureShell2; -// The 'cmd' command is available -extern const char* const kFeatureCmd; -extern const char* const kFeatureStat2; -extern const char* const kFeatureLs2; -// The server is running with libusb enabled. -extern const char* const kFeatureLibusb; -// adbd supports `push --sync`. -extern const char* const kFeaturePushSync; -// adbd supports installing .apex packages. -extern const char* const kFeatureApex; -// adbd has b/110953234 fixed. -extern const char* const kFeatureFixedPushMkdir; -// adbd supports android binder bridge (abb) in interactive mode using shell protocol. -extern const char* const kFeatureAbb; -// adbd supports abb using raw pipe. -extern const char* const kFeatureAbbExec; -// adbd properly updates symlink timestamps on push. -extern const char* const kFeatureFixedPushSymlinkTimestamp; -// Implement `adb remount` via shelling out to /system/bin/remount. -extern const char* const kFeatureRemountShell; -// adbd supports version 2 of send/recv. -extern const char* const kFeatureSendRecv2; -// adbd supports brotli for send/recv v2. -extern const char* const kFeatureSendRecv2Brotli; - -TransportId NextTransportId(); - -// Abstraction for a non-blocking packet transport. -struct Connection { - Connection() = default; - virtual ~Connection() = default; - - void SetTransportName(std::string transport_name) { - transport_name_ = std::move(transport_name); - } - - using ReadCallback = std::function)>; - void SetReadCallback(ReadCallback callback) { - CHECK(!read_callback_); - read_callback_ = callback; - } - - // Called after the Connection has terminated, either by an error or because Stop was called. - using ErrorCallback = std::function; - void SetErrorCallback(ErrorCallback callback) { - CHECK(!error_callback_); - error_callback_ = callback; - } - - virtual bool Write(std::unique_ptr packet) = 0; - - virtual void Start() = 0; - virtual void Stop() = 0; - - virtual bool DoTlsHandshake(RSA* key, std::string* auth_key = nullptr) = 0; - - // Stop, and reset the device if it's a USB connection. - virtual void Reset(); - - std::string transport_name_; - ReadCallback read_callback_; - ErrorCallback error_callback_; - - static std::unique_ptr FromFd(unique_fd fd); -}; - -// Abstraction for a blocking packet transport. -struct BlockingConnection { - BlockingConnection() = default; - BlockingConnection(const BlockingConnection& copy) = delete; - BlockingConnection(BlockingConnection&& move) = delete; - - // Destroy a BlockingConnection. Formerly known as 'Close' in atransport. - virtual ~BlockingConnection() = default; - - // Read/Write a packet. These functions are concurrently called from a transport's reader/writer - // threads. - virtual bool Read(apacket* packet) = 0; - virtual bool Write(apacket* packet) = 0; - - virtual bool DoTlsHandshake(RSA* key, std::string* auth_key = nullptr) = 0; - - // Terminate a connection. - // This method must be thread-safe, and must cause concurrent Reads/Writes to terminate. - // Formerly known as 'Kick' in atransport. - virtual void Close() = 0; - - // Terminate a connection, and reset it. - virtual void Reset() = 0; -}; - -struct BlockingConnectionAdapter : public Connection { - explicit BlockingConnectionAdapter(std::unique_ptr connection); - - virtual ~BlockingConnectionAdapter(); - - virtual bool Write(std::unique_ptr packet) override final; - - virtual void Start() override final; - virtual void Stop() override final; - virtual bool DoTlsHandshake(RSA* key, std::string* auth_key) override final; - - virtual void Reset() override final; - - private: - void StartReadThread() REQUIRES(mutex_); - bool started_ GUARDED_BY(mutex_) = false; - bool stopped_ GUARDED_BY(mutex_) = false; - - std::unique_ptr underlying_; - std::thread read_thread_ GUARDED_BY(mutex_); - std::thread write_thread_ GUARDED_BY(mutex_); - - std::deque> write_queue_ GUARDED_BY(mutex_); - std::mutex mutex_; - std::condition_variable cv_; - - std::once_flag error_flag_; -}; - -struct FdConnection : public BlockingConnection { - explicit FdConnection(unique_fd fd); - ~FdConnection(); - - bool Read(apacket* packet) override final; - bool Write(apacket* packet) override final; - bool DoTlsHandshake(RSA* key, std::string* auth_key) override final; - - void Close() override; - virtual void Reset() override final { Close(); } - - private: - bool DispatchRead(void* buf, size_t len); - bool DispatchWrite(void* buf, size_t len); - - unique_fd fd_; - std::unique_ptr tls_; -}; - -// Waits for a transport's connection to be not pending. This is a separate -// object so that the transport can be destroyed and another thread can be -// notified of it in a race-free way. -class ConnectionWaitable { - public: - ConnectionWaitable() = default; - ~ConnectionWaitable() = default; - - // Waits until the first CNXN packet has been received by the owning - // atransport, or the specified timeout has elapsed. Can be called from any - // thread. - // - // Returns true if the CNXN packet was received in a timely fashion, false - // otherwise. - bool WaitForConnection(std::chrono::milliseconds timeout); - - // Can be called from any thread when the connection stops being pending. - // Only the first invocation will be acknowledged, the rest will be no-ops. - void SetConnectionEstablished(bool success); - - private: - bool connection_established_ GUARDED_BY(mutex_) = false; - bool connection_established_ready_ GUARDED_BY(mutex_) = false; - std::mutex mutex_; - std::condition_variable cv_; - - DISALLOW_COPY_AND_ASSIGN(ConnectionWaitable); -}; - -enum class ReconnectResult { - Retry, - Success, - Abort, -}; - -#if ADB_HOST -struct usb_handle; -#endif - -class atransport : public enable_weak_from_this { - public: - // TODO(danalbert): We expose waaaaaaay too much stuff because this was - // historically just a struct, but making the whole thing a more idiomatic - // class in one go is a very large change. Given how bad our testing is, - // it's better to do this piece by piece. - - using ReconnectCallback = std::function; - - atransport(ReconnectCallback reconnect, ConnectionState state) - : id(NextTransportId()), - kicked_(false), - connection_state_(state), - connection_waitable_(std::make_shared()), - connection_(nullptr), - reconnect_(std::move(reconnect)) { - // Initialize protocol to min version for compatibility with older versions. - // Version will be updated post-connect. - protocol_version = A_VERSION_MIN; - max_payload = MAX_PAYLOAD; - } - atransport(ConnectionState state = kCsOffline) - : atransport([](atransport*) { return ReconnectResult::Abort; }, state) {} - ~atransport(); - - int Write(apacket* p); - void Reset(); - void Kick(); - bool kicked() const { return kicked_; } - - // ConnectionState can be read by all threads, but can only be written in the main thread. - ConnectionState GetConnectionState() const; - void SetConnectionState(ConnectionState state); - - void SetConnection(std::unique_ptr connection); - std::shared_ptr connection() { - std::lock_guard lock(mutex_); - return connection_; - } - -#if ADB_HOST - void SetUsbHandle(usb_handle* h) { usb_handle_ = h; } - usb_handle* GetUsbHandle() { return usb_handle_; } -#endif - - const TransportId id; - - bool online = false; - TransportType type = kTransportAny; - - // Used to identify transports for clients. - std::string serial; - std::string product; - std::string model; - std::string device; - std::string devpath; - - // If this is set, the transport will initiate the connection with a - // START_TLS command, instead of AUTH. - bool use_tls = false; - int tls_version = A_STLS_VERSION; - int get_tls_version() const; - -#if !ADB_HOST - // Used to provide the key to the framework. - std::string auth_key; - std::optional auth_id; -#endif - - bool IsTcpDevice() const { return type == kTransportLocal; } - -#if ADB_HOST - // The current key being authorized. - std::shared_ptr Key(); - std::shared_ptr NextKey(); - void ResetKeys(); -#endif - - char token[TOKEN_SIZE] = {}; - size_t failed_auth_attempts = 0; - - std::string serial_name() const { return !serial.empty() ? serial : ""; } - std::string connection_state_name() const; - - void update_version(int version, size_t payload); - int get_protocol_version() const; - size_t get_max_payload() const; - - const FeatureSet& features() const { - return features_; - } - - bool has_feature(const std::string& feature) const; - - // Loads the transport's feature set from the given string. - void SetFeatures(const std::string& features_string); - - void AddDisconnect(adisconnect* disconnect); - void RemoveDisconnect(adisconnect* disconnect); - void RunDisconnects(); - - // Returns true if |target| matches this transport. A matching |target| can be any of: - // * - // * - // * product: - // * model: - // * device: - // - // If this is a local transport, serial will also match [tcp:|udp:][:port] targets. - // For example, serial "100.100.100.100:5555" would match any of: - // * 100.100.100.100 - // * tcp:100.100.100.100 - // * udp:100.100.100.100:5555 - // This is to make it easier to use the same network target for both fastboot and adb. - bool MatchesTarget(const std::string& target) const; - - // Notifies that the atransport is no longer waiting for the connection - // being established. - void SetConnectionEstablished(bool success); - - // Gets a shared reference to the ConnectionWaitable. - std::shared_ptr connection_waitable() { return connection_waitable_; } - - // Attempts to reconnect with the underlying Connection. - ReconnectResult Reconnect(); - - private: - std::atomic kicked_; - - // A set of features transmitted in the banner with the initial connection. - // This is stored in the banner as 'features=feature0,feature1,etc'. - FeatureSet features_; - int protocol_version; - size_t max_payload; - - // A list of adisconnect callbacks called when the transport is kicked. - std::list disconnects_; - - std::atomic connection_state_; -#if ADB_HOST - std::deque> keys_; -#endif - - // A sharable object that can be used to wait for the atransport's - // connection to be established. - std::shared_ptr connection_waitable_; - - // The underlying connection object. - std::shared_ptr connection_ GUARDED_BY(mutex_); - -#if ADB_HOST - // USB handle for the connection, if available. - usb_handle* usb_handle_ = nullptr; -#endif - - // A callback that will be invoked when the atransport needs to reconnect. - ReconnectCallback reconnect_; - - std::mutex mutex_; - - DISALLOW_COPY_AND_ASSIGN(atransport); -}; - -/* - * Obtain a transport from the available transports. - * If serial is non-null then only the device with that serial will be chosen. - * If transport_id is non-zero then only the device with that transport ID will be chosen. - * If multiple devices/emulators would match, *is_ambiguous (if non-null) - * is set to true and nullptr returned. - * If no suitable transport is found, error is set and nullptr returned. - */ -atransport* acquire_one_transport(TransportType type, const char* serial, TransportId transport_id, - bool* is_ambiguous, std::string* error_out, - bool accept_any_state = false); -void kick_transport(atransport* t, bool reset = false); -void update_transports(void); - -// Iterates across all of the current and pending transports. -// Stops iteration and returns false if fn returns false, otherwise returns true. -bool iterate_transports(std::function fn); - -void init_reconnect_handler(void); -void init_transport_registration(void); -void init_mdns_transport_discovery(void); -std::string list_transports(bool long_listing); -atransport* find_transport(const char* serial); -void kick_all_tcp_devices(); -void kick_all_transports(); -void kick_all_tcp_tls_transports(); -#if !ADB_HOST -void kick_all_transports_by_auth_key(std::string_view auth_key); -#endif - -void register_transport(atransport* transport); - -#if ADB_HOST -void init_usb_transport(atransport* t, usb_handle* usb); -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 == kCsNoPerm. -void unregister_usb_transport(usb_handle* usb); -#endif - -/* Connect to a network address and register it as a device */ -void connect_device(const std::string& address, std::string* response); - -/* cause new transports to be init'd and added to the list */ -bool register_socket_transport(unique_fd s, std::string serial, int port, int local, - atransport::ReconnectCallback reconnect, bool use_tls, - int* error = nullptr); - -bool check_header(apacket* p, atransport* t); - -void close_usb_devices(bool reset = false); -void close_usb_devices(std::function predicate, bool reset = false); - -void send_packet(apacket* p, atransport* t); - -asocket* create_device_tracker(bool long_output); - -#if !ADB_HOST -unique_fd adb_listen(std::string_view addr, std::string* error); -void server_socket_thread(std::function listen_func, - std::string_view addr); - -#if defined(__ANDROID__) -void qemu_socket_thread(std::string_view addr); -bool use_qemu_goldfish(); -#endif - -#endif - -#endif /* __TRANSPORT_H */ diff --git a/adb/transport_benchmark.cpp b/adb/transport_benchmark.cpp deleted file mode 100644 index 022808f290b3c3e87a6ede759737100393bd8060..0000000000000000000000000000000000000000 --- a/adb/transport_benchmark.cpp +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright (C) 2018 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 "adb_trace.h" -#include "sysdeps.h" -#include "transport.h" - -#define ADB_CONNECTION_BENCHMARK(benchmark_name, ...) \ - BENCHMARK_TEMPLATE(benchmark_name, FdConnection, ##__VA_ARGS__) \ - ->Arg(1) \ - ->Arg(16384) \ - ->Arg(MAX_PAYLOAD) \ - ->UseRealTime(); \ - BENCHMARK_TEMPLATE(benchmark_name, NonblockingFdConnection, ##__VA_ARGS__) \ - ->Arg(1) \ - ->Arg(16384) \ - ->Arg(MAX_PAYLOAD) \ - ->UseRealTime() - -struct NonblockingFdConnection; -template -std::unique_ptr MakeConnection(unique_fd fd); - -template <> -std::unique_ptr MakeConnection(unique_fd fd) { - auto fd_connection = std::make_unique(std::move(fd)); - return std::make_unique(std::move(fd_connection)); -} - -template <> -std::unique_ptr MakeConnection(unique_fd fd) { - return Connection::FromFd(std::move(fd)); -} - -template -void BM_Connection_Unidirectional(benchmark::State& state) { - int fds[2]; - if (adb_socketpair(fds) != 0) { - LOG(FATAL) << "failed to create socketpair"; - } - - auto client = MakeConnection(unique_fd(fds[0])); - auto server = MakeConnection(unique_fd(fds[1])); - - std::atomic received_bytes; - - client->SetReadCallback([](Connection*, std::unique_ptr) -> bool { return true; }); - server->SetReadCallback([&received_bytes](Connection*, std::unique_ptr packet) -> bool { - received_bytes += packet->payload.size(); - return true; - }); - - client->SetErrorCallback( - [](Connection*, const std::string& error) { LOG(INFO) << "client closed: " << error; }); - server->SetErrorCallback( - [](Connection*, const std::string& error) { LOG(INFO) << "server closed: " << error; }); - - client->Start(); - server->Start(); - - for (auto _ : state) { - size_t data_size = state.range(0); - std::unique_ptr packet = std::make_unique(); - memset(&packet->msg, 0, sizeof(packet->msg)); - packet->msg.command = A_WRTE; - packet->msg.data_length = data_size; - packet->payload.resize(data_size); - - memset(&packet->payload[0], 0xff, data_size); - - received_bytes = 0; - client->Write(std::move(packet)); - while (received_bytes < data_size) { - continue; - } - } - state.SetBytesProcessed(static_cast(state.iterations()) * state.range(0)); - - client->Stop(); - server->Stop(); -} - -ADB_CONNECTION_BENCHMARK(BM_Connection_Unidirectional); - -enum class ThreadPolicy { - MainThread, - SameThread, -}; - -template -void BM_Connection_Echo(benchmark::State& state) { - int fds[2]; - if (adb_socketpair(fds) != 0) { - LOG(FATAL) << "failed to create socketpair"; - } - - auto client = MakeConnection(unique_fd(fds[0])); - auto server = MakeConnection(unique_fd(fds[1])); - - std::atomic received_bytes; - - fdevent_reset(); - std::thread fdevent_thread([]() { fdevent_loop(); }); - - client->SetReadCallback([&received_bytes](Connection*, std::unique_ptr packet) -> bool { - received_bytes += packet->payload.size(); - return true; - }); - - static const auto handle_packet = [](Connection* connection, std::unique_ptr packet) { - connection->Write(std::move(packet)); - }; - - server->SetReadCallback([](Connection* connection, std::unique_ptr packet) -> bool { - if (Policy == ThreadPolicy::MainThread) { - auto raw_packet = packet.release(); - fdevent_run_on_main_thread([connection, raw_packet]() { - std::unique_ptr packet(raw_packet); - handle_packet(connection, std::move(packet)); - }); - } else { - handle_packet(connection, std::move(packet)); - } - return true; - }); - - client->SetErrorCallback( - [](Connection*, const std::string& error) { LOG(INFO) << "client closed: " << error; }); - server->SetErrorCallback( - [](Connection*, const std::string& error) { LOG(INFO) << "server closed: " << error; }); - - client->Start(); - server->Start(); - - for (auto _ : state) { - size_t data_size = state.range(0); - std::unique_ptr packet = std::make_unique(); - memset(&packet->msg, 0, sizeof(packet->msg)); - packet->msg.command = A_WRTE; - packet->msg.data_length = data_size; - packet->payload.resize(data_size); - - memset(&packet->payload[0], 0xff, data_size); - - received_bytes = 0; - client->Write(std::move(packet)); - while (received_bytes < data_size) { - continue; - } - } - state.SetBytesProcessed(static_cast(state.iterations()) * state.range(0)); - - client->Stop(); - server->Stop(); - - // TODO: Make it so that you don't need to poke the fdevent loop to make it terminate? - fdevent_terminate_loop(); - fdevent_run_on_main_thread([]() {}); - - fdevent_thread.join(); -} - -ADB_CONNECTION_BENCHMARK(BM_Connection_Echo, ThreadPolicy::SameThread); -ADB_CONNECTION_BENCHMARK(BM_Connection_Echo, ThreadPolicy::MainThread); - -int main(int argc, char** argv) { - // Set M_DECAY_TIME so that our allocations aren't immediately purged on free. - mallopt(M_DECAY_TIME, 1); - - android::base::SetMinimumLogSeverity(android::base::WARNING); - adb_trace_init(argv); - ::benchmark::Initialize(&argc, argv); - if (::benchmark::ReportUnrecognizedArguments(argc, argv)) return 1; - ::benchmark::RunSpecifiedBenchmarks(); -} diff --git a/adb/transport_fd.cpp b/adb/transport_fd.cpp deleted file mode 100644 index b9b4f42b9641b7112b7dcda21ee46f939351f99c..0000000000000000000000000000000000000000 --- a/adb/transport_fd.cpp +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Copyright (C) 2018 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 "adb_unique_fd.h" -#include "adb_utils.h" -#include "sysdeps.h" -#include "transport.h" -#include "types.h" - -static void CreateWakeFds(unique_fd* read, unique_fd* write) { - // TODO: eventfd on linux? - int wake_fds[2]; - int rc = adb_socketpair(wake_fds); - set_file_block_mode(wake_fds[0], false); - set_file_block_mode(wake_fds[1], false); - CHECK_EQ(0, rc); - *read = unique_fd(wake_fds[0]); - *write = unique_fd(wake_fds[1]); -} - -struct NonblockingFdConnection : public Connection { - NonblockingFdConnection(unique_fd fd) : started_(false), fd_(std::move(fd)) { - set_file_block_mode(fd_.get(), false); - CreateWakeFds(&wake_fd_read_, &wake_fd_write_); - } - - void SetRunning(bool value) { - std::lock_guard lock(run_mutex_); - running_ = value; - } - - bool IsRunning() { - std::lock_guard lock(run_mutex_); - return running_; - } - - void Run(std::string* error) { - SetRunning(true); - while (IsRunning()) { - adb_pollfd pfds[2] = { - {.fd = fd_.get(), .events = POLLIN}, - {.fd = wake_fd_read_.get(), .events = POLLIN}, - }; - - { - std::lock_guard lock(this->write_mutex_); - if (!writable_) { - pfds[0].events |= POLLOUT; - } - } - - int rc = adb_poll(pfds, 2, -1); - if (rc == -1) { - *error = android::base::StringPrintf("poll failed: %s", strerror(errno)); - return; - } else if (rc == 0) { - LOG(FATAL) << "poll timed out with an infinite timeout?"; - } - - if (pfds[0].revents) { - if ((pfds[0].revents & POLLOUT)) { - std::lock_guard lock(this->write_mutex_); - if (DispatchWrites() == WriteResult::Error) { - *error = "write failed"; - return; - } - } - - if (pfds[0].revents & POLLIN) { - // TODO: Should we be getting blocks from a free list? - auto block = IOVector::block_type(MAX_PAYLOAD); - rc = adb_read(fd_.get(), &block[0], block.size()); - if (rc == -1) { - *error = std::string("read failed: ") + strerror(errno); - return; - } else if (rc == 0) { - *error = "read failed: EOF"; - return; - } - block.resize(rc); - read_buffer_.append(std::move(block)); - - if (!read_header_ && read_buffer_.size() >= sizeof(amessage)) { - auto header_buf = read_buffer_.take_front(sizeof(amessage)).coalesce(); - CHECK_EQ(sizeof(amessage), header_buf.size()); - read_header_ = std::make_unique(); - memcpy(read_header_.get(), header_buf.data(), sizeof(amessage)); - } - - if (read_header_ && read_buffer_.size() >= read_header_->data_length) { - auto data_chain = read_buffer_.take_front(read_header_->data_length); - - // TODO: Make apacket carry around a IOVector instead of coalescing. - auto payload = std::move(data_chain).coalesce(); - auto packet = std::make_unique(); - packet->msg = *read_header_; - packet->payload = std::move(payload); - read_header_ = nullptr; - read_callback_(this, std::move(packet)); - } - } - } - - if (pfds[1].revents) { - uint64_t buf; - rc = adb_read(wake_fd_read_.get(), &buf, sizeof(buf)); - CHECK_EQ(static_cast(sizeof(buf)), rc); - - // We were woken up either to add POLLOUT to our events, or to exit. - // Do nothing. - } - } - } - - void Start() override final { - if (started_.exchange(true)) { - LOG(FATAL) << "Connection started multiple times?"; - } - - thread_ = std::thread([this]() { - std::string error = "connection closed"; - Run(&error); - this->error_callback_(this, error); - }); - } - - void Stop() override final { - SetRunning(false); - WakeThread(); - thread_.join(); - } - - bool DoTlsHandshake(RSA* key, std::string* auth_key) override final { - LOG(FATAL) << "Not supported yet"; - return false; - } - - void WakeThread() { - uint64_t buf = 0; - if (TEMP_FAILURE_RETRY(adb_write(wake_fd_write_.get(), &buf, sizeof(buf))) != sizeof(buf)) { - LOG(FATAL) << "failed to wake up thread"; - } - } - - enum class WriteResult { - Error, - Completed, - TryAgain, - }; - - WriteResult DispatchWrites() REQUIRES(write_mutex_) { - CHECK(!write_buffer_.empty()); - auto iovs = write_buffer_.iovecs(); - ssize_t rc = adb_writev(fd_.get(), iovs.data(), iovs.size()); - if (rc == -1) { - if (errno == EAGAIN || errno == EWOULDBLOCK) { - writable_ = false; - return WriteResult::TryAgain; - } - - return WriteResult::Error; - } else if (rc == 0) { - errno = 0; - return WriteResult::Error; - } - - write_buffer_.drop_front(rc); - writable_ = write_buffer_.empty(); - if (write_buffer_.empty()) { - return WriteResult::Completed; - } - - // There's data left in the range, which means our write returned early. - return WriteResult::TryAgain; - } - - bool Write(std::unique_ptr packet) final { - std::lock_guard lock(write_mutex_); - const char* header_begin = reinterpret_cast(&packet->msg); - const char* header_end = header_begin + sizeof(packet->msg); - auto header_block = IOVector::block_type(header_begin, header_end); - write_buffer_.append(std::move(header_block)); - if (!packet->payload.empty()) { - write_buffer_.append(std::move(packet->payload)); - } - - WriteResult result = DispatchWrites(); - if (result == WriteResult::TryAgain) { - WakeThread(); - } - return result != WriteResult::Error; - } - - std::thread thread_; - - std::atomic started_; - std::mutex run_mutex_; - bool running_ GUARDED_BY(run_mutex_); - - std::unique_ptr read_header_; - IOVector read_buffer_; - - unique_fd fd_; - unique_fd wake_fd_read_; - unique_fd wake_fd_write_; - - std::mutex write_mutex_; - bool writable_ GUARDED_BY(write_mutex_) = true; - IOVector write_buffer_ GUARDED_BY(write_mutex_); - - IOVector incoming_queue_; -}; - -std::unique_ptr Connection::FromFd(unique_fd fd) { - return std::make_unique(std::move(fd)); -} diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp deleted file mode 100644 index 5ec8e1665824d04453cb4c9ffcbaf19586d3b551..0000000000000000000000000000000000000000 --- a/adb/transport_local.cpp +++ /dev/null @@ -1,389 +0,0 @@ -/* - * 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 TRANSPORT - -#include "sysdeps.h" -#include "transport.h" - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#if !ADB_HOST -#include -#endif - -#include "adb.h" -#include "adb_io.h" -#include "adb_unique_fd.h" -#include "adb_utils.h" -#include "socket_spec.h" -#include "sysdeps/chrono.h" - -#if ADB_HOST - -// Android Wear has been using port 5601 in all of its documentation/tooling, -// but we search for emulators on ports [5554, 5555 + ADB_LOCAL_TRANSPORT_MAX]. -// Avoid stomping on their port by restricting the active scanning range. -// Once emulators self-(re-)register, they'll have to avoid 5601 in their own way. -static int adb_local_transport_max_port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT + 16 * 2 - 1; - -static std::mutex& local_transports_lock = *new std::mutex(); - -static void adb_local_transport_max_port_env_override() { - const char* env_max_s = getenv("ADB_LOCAL_TRANSPORT_MAX_PORT"); - if (env_max_s != nullptr) { - size_t env_max; - if (ParseUint(&env_max, env_max_s, nullptr) && env_max < 65536) { - // < DEFAULT_ADB_LOCAL_TRANSPORT_PORT harmlessly mimics ADB_EMU=0 - adb_local_transport_max_port = env_max; - D("transport: ADB_LOCAL_TRANSPORT_MAX_PORT read as %d", adb_local_transport_max_port); - } else { - D("transport: ADB_LOCAL_TRANSPORT_MAX_PORT '%s' invalid or >= 65536, so ignored", - env_max_s); - } - } -} - -// We keep a map from emulator port to transport. -// TODO: weak_ptr? -static auto& local_transports GUARDED_BY(local_transports_lock) = - *new std::unordered_map(); -#endif /* ADB_HOST */ - -bool local_connect(int port) { - std::string dummy; - return local_connect_arbitrary_ports(port - 1, port, &dummy) == 0; -} - -void connect_device(const std::string& address, std::string* response) { - if (address.empty()) { - *response = "empty address"; - return; - } - - D("connection requested to '%s'", address.c_str()); - unique_fd fd; - int port; - std::string serial, prefix_addr; - - // If address does not match any socket type, it should default to TCP. - if (address.starts_with("vsock:") || address.starts_with("localfilesystem:")) { - prefix_addr = address; - } else { - prefix_addr = "tcp:" + address; - } - - socket_spec_connect(&fd, prefix_addr, &port, &serial, response); - if (fd.get() == -1) { - return; - } - auto reconnect = [prefix_addr](atransport* t) { - std::string response; - unique_fd fd; - int port; - std::string serial; - socket_spec_connect(&fd, prefix_addr, &port, &serial, &response); - if (fd == -1) { - D("reconnect failed: %s", response.c_str()); - return ReconnectResult::Retry; - } - // This invokes the part of register_socket_transport() that needs to be - // invoked if the atransport* has already been setup. This eventually - // calls atransport->SetConnection() with a newly created Connection* - // that will in turn send the CNXN packet. - return init_socket_transport(t, std::move(fd), port, 0) >= 0 ? ReconnectResult::Success - : ReconnectResult::Retry; - }; - - int error; - if (!register_socket_transport(std::move(fd), serial, port, 0, std::move(reconnect), false, - &error)) { - if (error == EALREADY) { - *response = android::base::StringPrintf("already connected to %s", serial.c_str()); - } else if (error == EPERM) { - *response = android::base::StringPrintf("failed to authenticate to %s", serial.c_str()); - } else { - *response = android::base::StringPrintf("failed to connect to %s", serial.c_str()); - } - } else { - *response = android::base::StringPrintf("connected to %s", serial.c_str()); - } -} - - -int local_connect_arbitrary_ports(int console_port, int adb_port, std::string* error) { - unique_fd fd; - -#if ADB_HOST - if (find_emulator_transport_by_adb_port(adb_port) != nullptr || - find_emulator_transport_by_console_port(console_port) != nullptr) { - return -1; - } - - const char *host = getenv("ADBHOST"); - if (host) { - fd.reset(network_connect(host, adb_port, SOCK_STREAM, 0, error)); - } -#endif - if (fd < 0) { - fd.reset(network_loopback_client(adb_port, SOCK_STREAM, error)); - } - - if (fd >= 0) { - D("client: connected on remote on fd %d", fd.get()); - close_on_exec(fd.get()); - disable_tcp_nagle(fd.get()); - std::string serial = getEmulatorSerialString(console_port); - if (register_socket_transport( - std::move(fd), std::move(serial), adb_port, 1, - [](atransport*) { return ReconnectResult::Abort; }, false)) { - return 0; - } - } - return -1; -} - -#if ADB_HOST - -static void PollAllLocalPortsForEmulator() { - // Try to connect to any number of running emulator instances. - for (int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT; port <= adb_local_transport_max_port; - port += 2) { - local_connect(port); // Note, uses port and port-1, so '=max_port' is OK. - } -} - -// Retry the disconnected local port for 60 times, and sleep 1 second between two retries. -static constexpr uint32_t LOCAL_PORT_RETRY_COUNT = 60; -static constexpr auto LOCAL_PORT_RETRY_INTERVAL = 1s; - -struct RetryPort { - int port; - uint32_t retry_count; -}; - -// Retry emulators just kicked. -static std::vector& retry_ports = *new std::vector; -std::mutex &retry_ports_lock = *new std::mutex; -std::condition_variable &retry_ports_cond = *new std::condition_variable; - -static void client_socket_thread(std::string_view) { - adb_thread_setname("client_socket_thread"); - D("transport: client_socket_thread() starting"); - PollAllLocalPortsForEmulator(); - while (true) { - std::vector ports; - // Collect retry ports. - { - std::unique_lock lock(retry_ports_lock); - while (retry_ports.empty()) { - retry_ports_cond.wait(lock); - } - retry_ports.swap(ports); - } - // Sleep here instead of the end of loop, because if we immediately try to reconnect - // the emulator just kicked, the adbd on the emulator may not have time to remove the - // just kicked transport. - std::this_thread::sleep_for(LOCAL_PORT_RETRY_INTERVAL); - - // Try connecting retry ports. - std::vector next_ports; - for (auto& port : ports) { - VLOG(TRANSPORT) << "retry port " << port.port << ", last retry_count " - << port.retry_count; - if (local_connect(port.port)) { - VLOG(TRANSPORT) << "retry port " << port.port << " successfully"; - continue; - } - if (--port.retry_count > 0) { - next_ports.push_back(port); - } else { - VLOG(TRANSPORT) << "stop retrying port " << port.port; - } - } - - // Copy back left retry ports. - { - std::unique_lock lock(retry_ports_lock); - retry_ports.insert(retry_ports.end(), next_ports.begin(), next_ports.end()); - } - } -} - -#else // !ADB_HOST - -void server_socket_thread(std::function listen_func, - std::string_view addr) { - adb_thread_setname("server socket"); - - unique_fd serverfd; - std::string error; - - while (serverfd == -1) { - errno = 0; - serverfd = listen_func(addr, &error); - if (errno == EAFNOSUPPORT || errno == EINVAL || errno == EPROTONOSUPPORT) { - D("unrecoverable error: '%s'", error.c_str()); - return; - } else if (serverfd < 0) { - D("server: cannot bind socket yet: %s", error.c_str()); - std::this_thread::sleep_for(1s); - continue; - } - close_on_exec(serverfd.get()); - } - - while (true) { - D("server: trying to get new connection from fd %d", serverfd.get()); - unique_fd fd(adb_socket_accept(serverfd, nullptr, nullptr)); - if (fd >= 0) { - D("server: new connection on fd %d", fd.get()); - close_on_exec(fd.get()); - disable_tcp_nagle(fd.get()); - std::string serial = android::base::StringPrintf("host-%d", fd.get()); - // We don't care about port value in "register_socket_transport" as it is used - // only from ADB_HOST. "server_socket_thread" is never called from ADB_HOST. - register_socket_transport( - std::move(fd), std::move(serial), 0, 1, - [](atransport*) { return ReconnectResult::Abort; }, false); - } - } - D("transport: server_socket_thread() exiting"); -} - -#endif - -#if !ADB_HOST -unique_fd adb_listen(std::string_view addr, std::string* error) { - return unique_fd{socket_spec_listen(addr, error, nullptr)}; -} -#endif - -void local_init(const std::string& addr) { -#if ADB_HOST - D("transport: local client init"); - std::thread(client_socket_thread, addr).detach(); - adb_local_transport_max_port_env_override(); -#elif !defined(__ANDROID__) - // Host adbd. - D("transport: local server init"); - std::thread(server_socket_thread, adb_listen, addr).detach(); -#else - D("transport: local server init"); - // For the adbd daemon in the system image we need to distinguish - // between the device, and the emulator. - if (addr.starts_with("tcp:") && use_qemu_goldfish()) { - std::thread(qemu_socket_thread, addr).detach(); - } else { - std::thread(server_socket_thread, adb_listen, addr).detach(); - } -#endif // !ADB_HOST -} - -#if ADB_HOST -struct EmulatorConnection : public FdConnection { - EmulatorConnection(unique_fd fd, int local_port) - : FdConnection(std::move(fd)), local_port_(local_port) {} - - ~EmulatorConnection() { - VLOG(TRANSPORT) << "remote_close, local_port = " << local_port_; - std::unique_lock lock(retry_ports_lock); - RetryPort port; - port.port = local_port_; - port.retry_count = LOCAL_PORT_RETRY_COUNT; - retry_ports.push_back(port); - retry_ports_cond.notify_one(); - } - - void Close() override { - std::lock_guard lock(local_transports_lock); - local_transports.erase(local_port_); - FdConnection::Close(); - } - - int local_port_; -}; - -/* Only call this function if you already hold local_transports_lock. */ -static atransport* find_emulator_transport_by_adb_port_locked(int adb_port) - REQUIRES(local_transports_lock) { - auto it = local_transports.find(adb_port); - if (it == local_transports.end()) { - return nullptr; - } - return it->second; -} - -atransport* find_emulator_transport_by_adb_port(int adb_port) { - std::lock_guard lock(local_transports_lock); - return find_emulator_transport_by_adb_port_locked(adb_port); -} - -atransport* find_emulator_transport_by_console_port(int console_port) { - return find_transport(getEmulatorSerialString(console_port).c_str()); -} -#endif - -std::string getEmulatorSerialString(int console_port) { - return android::base::StringPrintf("emulator-%d", console_port); -} - -int init_socket_transport(atransport* t, unique_fd fd, int adb_port, int local) { - int fail = 0; - - t->type = kTransportLocal; - -#if ADB_HOST - // Emulator connection. - if (local) { - auto emulator_connection = std::make_unique(std::move(fd), adb_port); - t->SetConnection( - std::make_unique(std::move(emulator_connection))); - std::lock_guard lock(local_transports_lock); - atransport* existing_transport = find_emulator_transport_by_adb_port_locked(adb_port); - if (existing_transport != nullptr) { - D("local transport for port %d already registered (%p)?", adb_port, existing_transport); - fail = -1; - } else { - local_transports[adb_port] = t; - } - - return fail; - } -#endif - - // Regular tcp connection. - auto fd_connection = std::make_unique(std::move(fd)); - t->SetConnection(std::make_unique(std::move(fd_connection))); - return fail; -} diff --git a/adb/transport_test.cpp b/adb/transport_test.cpp deleted file mode 100644 index 00beb3a2be7d25f57fdd45765577a6e5f37e5d52..0000000000000000000000000000000000000000 --- a/adb/transport_test.cpp +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (C) 2015 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 "transport.h" - -#include - -#include "adb.h" -#include "fdevent/fdevent_test.h" - -struct TransportTest : public FdeventTest {}; - -static void DisconnectFunc(void* arg, atransport*) { - int* count = reinterpret_cast(arg); - ++*count; -} - -TEST_F(TransportTest, RunDisconnects) { - atransport t; - // RunDisconnects() can be called with an empty atransport. - t.RunDisconnects(); - - int count = 0; - adisconnect disconnect; - disconnect.func = DisconnectFunc; - disconnect.opaque = &count; - t.AddDisconnect(&disconnect); - t.RunDisconnects(); - ASSERT_EQ(1, count); - - // disconnect should have been removed automatically. - t.RunDisconnects(); - ASSERT_EQ(1, count); - - count = 0; - t.AddDisconnect(&disconnect); - t.RemoveDisconnect(&disconnect); - t.RunDisconnects(); - ASSERT_EQ(0, count); -} - -TEST_F(TransportTest, SetFeatures) { - atransport t; - ASSERT_EQ(0U, t.features().size()); - - t.SetFeatures(FeatureSetToString(FeatureSet{"foo"})); - ASSERT_EQ(1U, t.features().size()); - ASSERT_TRUE(t.has_feature("foo")); - - t.SetFeatures(FeatureSetToString(FeatureSet{"foo", "bar"})); - ASSERT_EQ(2U, t.features().size()); - ASSERT_TRUE(t.has_feature("foo")); - ASSERT_TRUE(t.has_feature("bar")); - - t.SetFeatures(FeatureSetToString(FeatureSet{"foo", "bar", "foo"})); - ASSERT_EQ(2U, t.features().size()); - ASSERT_TRUE(t.has_feature("foo")); - ASSERT_TRUE(t.has_feature("bar")); - - t.SetFeatures(FeatureSetToString(FeatureSet{"bar", "baz"})); - ASSERT_EQ(2U, t.features().size()); - ASSERT_FALSE(t.has_feature("foo")); - ASSERT_TRUE(t.has_feature("bar")); - ASSERT_TRUE(t.has_feature("baz")); - - t.SetFeatures(""); - ASSERT_EQ(0U, t.features().size()); -} - -TEST_F(TransportTest, parse_banner_no_features) { - atransport t; - - parse_banner("host::", &t); - - ASSERT_EQ(0U, t.features().size()); - ASSERT_EQ(kCsHost, t.GetConnectionState()); - - ASSERT_EQ(std::string(), t.product); - ASSERT_EQ(std::string(), t.model); - ASSERT_EQ(std::string(), t.device); -} - -TEST_F(TransportTest, parse_banner_product_features) { - atransport t; - - const char banner[] = - "host::ro.product.name=foo;ro.product.model=bar;ro.product.device=baz;"; - parse_banner(banner, &t); - - ASSERT_EQ(kCsHost, t.GetConnectionState()); - - ASSERT_EQ(0U, t.features().size()); - - ASSERT_EQ(std::string("foo"), t.product); - ASSERT_EQ(std::string("bar"), t.model); - ASSERT_EQ(std::string("baz"), t.device); -} - -TEST_F(TransportTest, parse_banner_features) { - atransport t; - const char banner[] = - "host::ro.product.name=foo;ro.product.model=bar;ro.product.device=baz;" - "features=woodly,doodly"; - parse_banner(banner, &t); - - ASSERT_EQ(kCsHost, t.GetConnectionState()); - - ASSERT_EQ(2U, t.features().size()); - ASSERT_TRUE(t.has_feature("woodly")); - ASSERT_TRUE(t.has_feature("doodly")); - - ASSERT_EQ(std::string("foo"), t.product); - ASSERT_EQ(std::string("bar"), t.model); - ASSERT_EQ(std::string("baz"), t.device); -} - -TEST_F(TransportTest, test_matches_target) { - std::string serial = "foo"; - std::string devpath = "/path/to/bar"; - std::string product = "test_product"; - std::string model = "test_model"; - std::string device = "test_device"; - - atransport t; - t.serial = &serial[0]; - t.devpath = &devpath[0]; - t.product = &product[0]; - t.model = &model[0]; - t.device = &device[0]; - - // These tests should not be affected by the transport type. - for (TransportType type : {kTransportAny, kTransportLocal}) { - t.type = type; - - EXPECT_TRUE(t.MatchesTarget(serial)); - EXPECT_TRUE(t.MatchesTarget(devpath)); - EXPECT_TRUE(t.MatchesTarget("product:" + product)); - EXPECT_TRUE(t.MatchesTarget("model:" + model)); - EXPECT_TRUE(t.MatchesTarget("device:" + device)); - - // Product, model, and device don't match without the prefix. - EXPECT_FALSE(t.MatchesTarget(product)); - EXPECT_FALSE(t.MatchesTarget(model)); - EXPECT_FALSE(t.MatchesTarget(device)); - } -} - -TEST_F(TransportTest, test_matches_target_local) { - std::string serial = "100.100.100.100:5555"; - - atransport t; - t.serial = &serial[0]; - - // Network address matching should only be used for local transports. - for (TransportType type : {kTransportAny, kTransportLocal}) { - t.type = type; - bool should_match = (type == kTransportLocal); - - EXPECT_EQ(should_match, t.MatchesTarget("100.100.100.100")); - EXPECT_EQ(should_match, t.MatchesTarget("tcp:100.100.100.100")); - EXPECT_EQ(should_match, t.MatchesTarget("tcp:100.100.100.100:5555")); - EXPECT_EQ(should_match, t.MatchesTarget("udp:100.100.100.100")); - EXPECT_EQ(should_match, t.MatchesTarget("udp:100.100.100.100:5555")); - - // Wrong protocol, hostname, or port should never match. - EXPECT_FALSE(t.MatchesTarget("100.100.100")); - EXPECT_FALSE(t.MatchesTarget("100.100.100.100:")); - EXPECT_FALSE(t.MatchesTarget("100.100.100.100:-1")); - EXPECT_FALSE(t.MatchesTarget("100.100.100.100:5554")); - EXPECT_FALSE(t.MatchesTarget("abc:100.100.100.100")); - } -} diff --git a/adb/types.cpp b/adb/types.cpp deleted file mode 100644 index 26b77ab62080b2d561911376391f5500f89e3a5e..0000000000000000000000000000000000000000 --- a/adb/types.cpp +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright (C) 2019 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 "types.h" - -IOVector& IOVector::operator=(IOVector&& move) noexcept { - chain_ = std::move(move.chain_); - chain_length_ = move.chain_length_; - begin_offset_ = move.begin_offset_; - start_index_ = move.start_index_; - - move.clear(); - return *this; -} - -IOVector::block_type IOVector::clear() { - chain_length_ = 0; - begin_offset_ = 0; - start_index_ = 0; - block_type res; - if (!chain_.empty()) { - res = std::move(chain_.back()); - } - chain_.clear(); - return res; -} - -void IOVector::drop_front(IOVector::size_type len) { - if (len == 0) { - return; - } - if (len == size()) { - clear(); - return; - } - CHECK_LT(len, size()); - - auto dropped = 0u; - while (dropped < len) { - const auto next = chain_[start_index_].size() - begin_offset_; - if (dropped + next < len) { - pop_front_block(); - dropped += next; - } else { - const auto taken = len - dropped; - begin_offset_ += taken; - break; - } - } -} - -IOVector IOVector::take_front(IOVector::size_type len) { - if (len == 0) { - return {}; - } - if (len == size()) { - return std::move(*this); - } - - CHECK_GE(size(), len); - IOVector res; - // first iterate over the blocks that completely go into the other vector - while (chain_[start_index_].size() - begin_offset_ <= len) { - chain_length_ -= chain_[start_index_].size(); - len -= chain_[start_index_].size() - begin_offset_; - if (chain_[start_index_].size() > begin_offset_) { - res.append(std::move(chain_[start_index_])); - if (begin_offset_) { - res.begin_offset_ = std::exchange(begin_offset_, 0); - } - } else { - begin_offset_ = 0; - } - ++start_index_; - } - - if (len > 0) { - // what's left is a single buffer that needs to be split between the |res| and |this| - // we know that it has to be split - there was a check for the case when it has to - // go away as a whole. - if (begin_offset_ != 0 || len < chain_[start_index_].size() / 2) { - // let's memcpy the data out - block_type block(chain_[start_index_].begin() + begin_offset_, - chain_[start_index_].begin() + begin_offset_ + len); - res.append(std::move(block)); - begin_offset_ += len; - } else { - CHECK_EQ(begin_offset_, 0u); - // move out the internal buffer out and copy only the tail of it back in - block_type block(chain_[start_index_].begin() + len, chain_[start_index_].end()); - chain_length_ -= chain_[start_index_].size(); - chain_[start_index_].resize(len); - res.append(std::move(chain_[start_index_])); - chain_length_ += block.size(); - chain_[start_index_] = std::move(block); - } - } - return res; -} - -void IOVector::trim_front() { - if ((begin_offset_ == 0 && start_index_ == 0) || chain_.empty()) { - return; - } - block_type& first_block = chain_[start_index_]; - if (begin_offset_ == first_block.size()) { - ++start_index_; - } else { - memmove(first_block.data(), first_block.data() + begin_offset_, - first_block.size() - begin_offset_); - first_block.resize(first_block.size() - begin_offset_); - } - chain_length_ -= begin_offset_; - begin_offset_ = 0; - trim_chain_front(); -} - -void IOVector::trim_chain_front() { - if (start_index_) { - chain_.erase(chain_.begin(), chain_.begin() + start_index_); - start_index_ = 0; - } -} - -void IOVector::pop_front_block() { - chain_length_ -= chain_[start_index_].size(); - begin_offset_ = 0; - chain_[start_index_].clear(); - ++start_index_; - if (start_index_ > std::max(4, chain_.size() / 2)) { - trim_chain_front(); - } -} - -IOVector::block_type IOVector::coalesce() && { - // Destructive coalesce() may optimize for several cases when it doesn't need to allocate - // new buffer, or even return one of the existing blocks as is. The only guarantee is that - // after this call the IOVector is in some valid state. Nothing is guaranteed about the - // specifics. - if (size() == 0) { - return {}; - } - if (begin_offset_ == chain_[start_index_].size() && chain_.size() == start_index_ + 2) { - chain_length_ -= chain_.back().size(); - auto res = std::move(chain_.back()); - chain_.pop_back(); - return res; - } - if (chain_.size() == start_index_ + 1) { - chain_length_ -= chain_.back().size(); - auto res = std::move(chain_.back()); - chain_.pop_back(); - if (begin_offset_ != 0) { - memmove(res.data(), res.data() + begin_offset_, res.size() - begin_offset_); - res.resize(res.size() - begin_offset_); - begin_offset_ = 0; - } - return res; - } - if (auto& firstBuffer = chain_[start_index_]; firstBuffer.capacity() >= size()) { - auto res = std::move(chain_[start_index_]); - auto size = res.size(); - chain_length_ -= size; - if (begin_offset_ != 0) { - memmove(res.data(), res.data() + begin_offset_, res.size() - begin_offset_); - size -= begin_offset_; - begin_offset_ = 0; - } - for (auto i = start_index_ + 1; i < chain_.size(); ++i) { - memcpy(res.data() + size, chain_[i].data(), chain_[i].size()); - size += chain_[i].size(); - } - res.resize(size); - ++start_index_; - return res; - } - return const_cast(this)->coalesce<>(); -} - -std::vector IOVector::iovecs() const { - std::vector result; - result.reserve(chain_.size() - start_index_); - iterate_blocks([&result](const char* data, size_t len) { - adb_iovec iov; - iov.iov_base = const_cast(data); - iov.iov_len = len; - result.emplace_back(iov); - }); - - return result; -} diff --git a/adb/types.h b/adb/types.h deleted file mode 100644 index deca7eafb6dc9e09bb69d47b86764cc16b1e56a4..0000000000000000000000000000000000000000 --- a/adb/types.h +++ /dev/null @@ -1,358 +0,0 @@ -/* - * Copyright (C) 2018 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. - */ - -#pragma once - -#include - -#include -#include -#include -#include - -#include - -#include "fdevent/fdevent.h" -#include "sysdeps/uio.h" - -// Essentially std::vector, except without zero initialization or reallocation. -struct Block { - using iterator = char*; - - Block() = default; - - explicit Block(size_t size) { allocate(size); } - - template - Block(Iterator begin, Iterator end) : Block(end - begin) { - std::copy(begin, end, data_.get()); - } - - Block(const Block& copy) = delete; - Block(Block&& move) noexcept - : data_(std::exchange(move.data_, nullptr)), - capacity_(std::exchange(move.capacity_, 0)), - size_(std::exchange(move.size_, 0)) {} - - Block& operator=(const Block& copy) = delete; - Block& operator=(Block&& move) noexcept { - clear(); - data_ = std::exchange(move.data_, nullptr); - capacity_ = std::exchange(move.capacity_, 0); - size_ = std::exchange(move.size_, 0); - return *this; - } - - ~Block() = default; - - void resize(size_t new_size) { - if (!data_) { - allocate(new_size); - } else { - CHECK_GE(capacity_, new_size); - size_ = new_size; - } - } - - template - void assign(InputIt begin, InputIt end) { - clear(); - allocate(end - begin); - std::copy(begin, end, data_.get()); - } - - void clear() { - data_.reset(); - capacity_ = 0; - size_ = 0; - } - - size_t capacity() const { return capacity_; } - size_t size() const { return size_; } - bool empty() const { return size() == 0; } - - char* data() { return data_.get(); } - const char* data() const { return data_.get(); } - - char* begin() { return data_.get(); } - const char* begin() const { return data_.get(); } - - char* end() { return data() + size_; } - const char* end() const { return data() + size_; } - - char& operator[](size_t idx) { return data()[idx]; } - const char& operator[](size_t idx) const { return data()[idx]; } - - bool operator==(const Block& rhs) const { - return size() == rhs.size() && memcmp(data(), rhs.data(), size()) == 0; - } - - private: - void allocate(size_t size) { - CHECK(data_ == nullptr); - CHECK_EQ(0ULL, capacity_); - CHECK_EQ(0ULL, size_); - if (size != 0) { - // This isn't std::make_unique because that's equivalent to `new char[size]()`, which - // value-initializes the array instead of leaving it uninitialized. As an optimization, - // call new without parentheses to avoid this costly initialization. - data_.reset(new char[size]); - capacity_ = size; - size_ = size; - } - } - - std::unique_ptr data_; - size_t capacity_ = 0; - size_t size_ = 0; -}; - -struct amessage { - uint32_t command; /* command identifier constant */ - uint32_t arg0; /* first argument */ - uint32_t arg1; /* second argument */ - uint32_t data_length; /* length of payload (0 is allowed) */ - uint32_t data_check; /* checksum of data payload */ - uint32_t magic; /* command ^ 0xffffffff */ -}; - -struct apacket { - using payload_type = Block; - amessage msg; - payload_type payload; -}; - -struct IOVector { - using value_type = char; - using block_type = Block; - using size_type = size_t; - - IOVector() = default; - - explicit IOVector(block_type&& block) { append(std::move(block)); } - - IOVector(const IOVector& copy) = delete; - IOVector(IOVector&& move) noexcept : IOVector() { *this = std::move(move); } - - IOVector& operator=(const IOVector& copy) = delete; - IOVector& operator=(IOVector&& move) noexcept; - - const value_type* front_data() const { - if (chain_.empty()) { - return nullptr; - } - - return chain_.front().data() + begin_offset_; - } - - size_type front_size() const { - if (chain_.empty()) { - return 0; - } - - return chain_.front().size() - begin_offset_; - } - - size_type size() const { return chain_length_ - begin_offset_; } - bool empty() const { return size() == 0; } - - // Return the last block so the caller can still reuse its allocated capacity - // or it can be simply ignored. - block_type clear(); - - void drop_front(size_type len); - - // Split the first |len| bytes out of this chain into its own. - IOVector take_front(size_type len); - - // Add a nonempty block to the chain. - void append(block_type&& block) { - if (block.size() == 0) { - return; - } - CHECK_NE(0ULL, block.size()); - chain_length_ += block.size(); - chain_.emplace_back(std::move(block)); - } - - void trim_front(); - - private: - void trim_chain_front(); - - // Drop the front block from the chain, and update chain_length_ appropriately. - void pop_front_block(); - - // Iterate over the blocks with a callback with an operator()(const char*, size_t). - template - void iterate_blocks(Fn&& callback) const { - if (size() == 0) { - return; - } - - for (size_t i = start_index_; i < chain_.size(); ++i) { - const auto& block = chain_[i]; - const char* begin = block.data(); - size_t length = block.size(); - - if (i == start_index_) { - CHECK_GE(block.size(), begin_offset_); - begin += begin_offset_; - length -= begin_offset_; - } - callback(begin, length); - } - } - - public: - // Copy all of the blocks into a single block. - template - CollectionType coalesce() const& { - CollectionType result; - if (size() == 0) { - return result; - } - - result.resize(size()); - - size_t offset = 0; - iterate_blocks([&offset, &result](const char* data, size_t len) { - memcpy(&result[offset], data, len); - offset += len; - }); - - return result; - } - - block_type coalesce() &&; - - template - auto coalesced(FunctionType&& f) const { - if (chain_.size() == start_index_ + 1) { - // If we only have one block, we can use it directly. - return f(chain_[start_index_].data() + begin_offset_, size()); - } else { - // Otherwise, copy to a single block. - auto data = coalesce(); - return f(data.data(), data.size()); - } - } - - // Get a list of iovecs that can be used to write out all of the blocks. - std::vector iovecs() const; - - private: - // Total length of all of the blocks in the chain. - size_t chain_length_ = 0; - - size_t begin_offset_ = 0; - size_t start_index_ = 0; - std::vector chain_; -}; - -// An implementation of weak pointers tied to the fdevent run loop. -// -// This allows for code to submit a request for an object, and upon receiving -// a response, know whether the object is still alive, or has been destroyed -// because of other reasons. We keep a list of living weak_ptrs in each object, -// and clear the weak_ptrs when the object is destroyed. This is safe, because -// we require that both the destructor of the referent and the get method on -// the weak_ptr are executed on the main thread. -template -struct enable_weak_from_this; - -template -struct weak_ptr { - weak_ptr() = default; - explicit weak_ptr(T* ptr) { reset(ptr); } - weak_ptr(const weak_ptr& copy) { reset(copy.get()); } - - weak_ptr(weak_ptr&& move) { - reset(move.get()); - move.reset(); - } - - ~weak_ptr() { reset(); } - - weak_ptr& operator=(const weak_ptr& copy) { - if (© == this) { - return *this; - } - - reset(copy.get()); - return *this; - } - - weak_ptr& operator=(weak_ptr&& move) { - if (&move == this) { - return *this; - } - - reset(move.get()); - move.reset(); - return *this; - } - - T* get() { - check_main_thread(); - return ptr_; - } - - void reset(T* ptr = nullptr) { - check_main_thread(); - - if (ptr == ptr_) { - return; - } - - if (ptr_) { - ptr_->weak_ptrs_.erase( - std::remove(ptr_->weak_ptrs_.begin(), ptr_->weak_ptrs_.end(), this)); - } - - ptr_ = ptr; - if (ptr_) { - ptr_->weak_ptrs_.push_back(this); - } - } - - private: - friend struct enable_weak_from_this; - T* ptr_ = nullptr; -}; - -template -struct enable_weak_from_this { - ~enable_weak_from_this() { - if (!weak_ptrs_.empty()) { - check_main_thread(); - for (auto& weak : weak_ptrs_) { - weak->ptr_ = nullptr; - } - weak_ptrs_.clear(); - } - } - - weak_ptr weak() { return weak_ptr(static_cast(this)); } - - void schedule_deletion() { - fdevent_run_on_main_thread([this]() { delete this; }); - } - - private: - friend struct weak_ptr; - std::vector*> weak_ptrs_; -}; diff --git a/adb/types_test.cpp b/adb/types_test.cpp deleted file mode 100644 index 2c99f9512a71d0485ef3de491004d2ecdd7e241a..0000000000000000000000000000000000000000 --- a/adb/types_test.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (C) 2018 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 "types.h" - -static IOVector::block_type create_block(const std::string& string) { - return IOVector::block_type(string.begin(), string.end()); -} - -static IOVector::block_type create_block(char value, size_t len) { - auto block = IOVector::block_type(); - block.resize(len); - memset(&(block)[0], value, len); - return block; -} - -template -static IOVector::block_type copy_block(const T& block) { - auto copy = IOVector::block_type(); - copy.assign(block.begin(), block.end()); - return copy; -} - -TEST(IOVector, empty) { - // Empty IOVector. - IOVector bc; - CHECK_EQ(0ULL, bc.coalesce().size()); -} - -TEST(IOVector, single_block) { - // A single block. - auto block = create_block('x', 100); - IOVector bc; - bc.append(copy_block(block)); - ASSERT_EQ(100ULL, bc.size()); - auto coalesced = bc.coalesce(); - ASSERT_EQ(block, coalesced); -} - -TEST(IOVector, single_block_split) { - // One block split. - IOVector bc; - bc.append(create_block("foobar")); - IOVector foo = bc.take_front(3); - ASSERT_EQ(3ULL, foo.size()); - ASSERT_EQ(3ULL, bc.size()); - ASSERT_EQ(create_block("foo"), foo.coalesce()); - ASSERT_EQ(create_block("bar"), bc.coalesce()); -} - -TEST(IOVector, aligned_split) { - IOVector bc; - bc.append(create_block("foo")); - bc.append(create_block("bar")); - bc.append(create_block("baz")); - ASSERT_EQ(9ULL, bc.size()); - - IOVector foo = bc.take_front(3); - ASSERT_EQ(3ULL, foo.size()); - ASSERT_EQ(create_block("foo"), foo.coalesce()); - - IOVector bar = bc.take_front(3); - ASSERT_EQ(3ULL, bar.size()); - ASSERT_EQ(create_block("bar"), bar.coalesce()); - - IOVector baz = bc.take_front(3); - ASSERT_EQ(3ULL, baz.size()); - ASSERT_EQ(create_block("baz"), baz.coalesce()); - - ASSERT_EQ(0ULL, bc.size()); -} - -TEST(IOVector, misaligned_split) { - IOVector bc; - bc.append(create_block("foo")); - bc.append(create_block("bar")); - bc.append(create_block("baz")); - bc.append(create_block("qux")); - bc.append(create_block("quux")); - - // Aligned left, misaligned right, across multiple blocks. - IOVector foob = bc.take_front(4); - ASSERT_EQ(4ULL, foob.size()); - ASSERT_EQ(create_block("foob"), foob.coalesce()); - - // Misaligned left, misaligned right, in one block. - IOVector a = bc.take_front(1); - ASSERT_EQ(1ULL, a.size()); - ASSERT_EQ(create_block("a"), a.coalesce()); - - // Misaligned left, misaligned right, across two blocks. - IOVector rba = bc.take_front(3); - ASSERT_EQ(3ULL, rba.size()); - ASSERT_EQ(create_block("rba"), rba.coalesce()); - - // Misaligned left, misaligned right, across three blocks. - IOVector zquxquu = bc.take_front(7); - ASSERT_EQ(7ULL, zquxquu.size()); - ASSERT_EQ(create_block("zquxquu"), zquxquu.coalesce()); - - ASSERT_EQ(1ULL, bc.size()); - ASSERT_EQ(create_block("x"), bc.coalesce()); -}