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 c361a14bc397ac139b9e047601aa09150bc4ef33..0000000000000000000000000000000000000000 --- a/adb/Android.bp +++ /dev/null @@ -1,914 +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. - -tidy_errors = [ - "-*", - "bugprone-inaccurate-erase", -] - -cc_defaults { - name: "adb_defaults", - - cflags: [ - "-Wall", - "-Wextra", - "-Werror", - "-Wexit-time-destructors", - "-Wno-non-virtual-dtor", - "-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", - ], - }, - }, - - tidy: true, - tidy_checks: tidy_errors, - tidy_checks_as_errors: tidy_errors, -} - -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_sysdeps", - "libadb_tls_connection", - "libadbd", - "libadbd_core", - "libadbconnection_server", - "libasyncio", - "libbase", - "libbrotli", - "libcutils_sockets", - "libdiagnose_usb", - "libmdnssd", - "libzstd", - - "libadb_protos", - "libapp_processes_protos_lite", - "libprotobuf-cpp-lite", - ], - - 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", - "services.cpp", - "sockets.cpp", - "socket_spec.cpp", - "sysdeps/env.cpp", - "sysdeps/errno.cpp", - "transport.cpp", - "transport_fd.cpp", - "types.cpp", -] - -libadb_darwin_srcs = [ - "fdevent/fdevent_poll.cpp", -] - -libadb_windows_srcs = [ - "fdevent/fdevent_poll.cpp", - "sysdeps_win32.cpp", - "sysdeps/win32/errno.cpp", - "sysdeps/win32/stat.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_local.cpp", - "client/transport_mdns.cpp", - "client/mdns_utils.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"] + libadb_darwin_srcs, - }, - not_windows: { - srcs: libadb_posix_srcs, - }, - windows: { - enabled: true, - srcs: [ - "client/usb_windows.cpp", - ] + libadb_windows_srcs, - 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_library { - name: "libadb_sysdeps", - defaults: ["adb_defaults"], - recovery_available: true, - host_supported: true, - compile_multilib: "both", - min_sdk_version: "apex_inherit", - // This library doesn't use build::GetBuildNumber() - use_version_lib: false, - - srcs: [ - "sysdeps/env.cpp", - ], - - shared_libs: [ - "libbase", - "liblog", - ], - - target: { - windows: { - enabled: true, - ldflags: ["-municode"], - }, - }, - - export_include_dirs: ["."], - - visibility: [ - "//bootable/recovery/minadbd:__subpackages__", - "//packages/modules/adb:__subpackages__", - "//system/core/adb:__subpackages__", - ], - - apex_available: [ - "com.android.adbd", - "test_com.android.adbd", - ], -} - -cc_test_host { - name: "adb_test", - defaults: ["adb_defaults"], - srcs: libadb_test_srcs + [ - "client/mdns_utils_test.cpp", - ], - - static_libs: [ - "libadb_crypto_static", - "libadb_host", - "libadb_pairing_auth_static", - "libadb_pairing_connection_static", - "libadb_protos_static", - "libadb_sysdeps", - "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_sysdeps", - "libadb_tls_connection", - "libandroidfw", - "libapp_processes_protos_full", - "libbase", - "libbrotli", - "libcutils", - "libcrypto_utils", - "libcrypto", - "libfastdeploy_host", - "libdiagnose_usb", - "liblog", - "liblz4", - "libmdnssd", - "libprotobuf-cpp-full", - "libssl", - "libusb", - "libutils", - "liblog", - "libziparchive", - "libz", - "libzstd", - ], - - // 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/adb_wifi.cpp", - "daemon/auth.cpp", - "daemon/jdwp_service.cpp", - "daemon/logging.cpp", - "daemon/transport_local.cpp", - ], - - generated_headers: ["platform_tools_version"], - - static_libs: [ - "libdiagnose_usb", - ], - - shared_libs: [ - "libadbconnection_server", - "libadb_crypto", - "libadb_pairing_connection", - "libadb_protos", - "libadb_tls_connection", - "libadbd_auth", - "libapp_processes_protos_lite", - "libasyncio", - "libbase", - "libcrypto", - "libcrypto_utils", - "libcutils_sockets", - "liblog", - ], - - proto: { - type: "lite", - static: true, - export_proto_headers: true, - }, - - 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", - "libapp_processes_protos_lite", - ], - } - }, - - apex_available: [ - "//apex_available:platform", - "com.android.adbd", - ], - visibility: [ - "//bootable/recovery/minadbd", - "//packages/modules/adb:__subpackages__", - "//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", - "liblz4", - "libzstd", - ], - - shared_libs: [ - "libadb_crypto", - "libadb_pairing_connection", - "libadb_protos", - "libadb_tls_connection", - "libapp_processes_protos_lite", - "libasyncio", - "libbase", - "libcrypto_utils", - "libcutils_sockets", - "libprotobuf-cpp-lite", - - // 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: [ - "//packages/modules/adb", - "//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: [ - "libadbconnection_server", - "libapp_processes_protos_lite", - "libprotobuf-cpp-lite", - "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", - "liblz4", - "libmdnssd", - "libzstd", - ], - - visibility: [ - "//bootable/recovery/minadbd", - "//packages/modules/adb", - "//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", - "liblz4", - "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_sysdeps", - "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/README.md b/adb/README.md deleted file mode 100644 index 224387c48edcb4740cab9ba9ab3641cafef5c4bd..0000000000000000000000000000000000000000 --- a/adb/README.md +++ /dev/null @@ -1,94 +0,0 @@ -# ADB Internals - -If you are new to adb source code, you should start by reading [OVERVIEW.TXT](OVERVIEW.TXT) which describes the three components of adb pipeline. - -This document is here to boost what can be achieved within a "window of naive interest". You will not find function or class documentation here but rather the "big picture" which should allow you to build a mental map to help navigate the code. - -## Three components of adb pipeline - -As outlined in the overview, this codebase generates three components (Client, Server (a.k.a Host), and Daemon (a.k.a adbd)). The central part is the Server which runs on the Host computer. On one side the Server exposes a "Smart Socket" to Clients such as adb or DDMLIB. On the other side, the Server continuously monitors for connecting Daemons (as USB devices or TCP emulator). Communication with a device is done with a Transport. - -``` -+----------+ +------------------------+ -| ADB +----------+ | ADB SERVER | +----------+ -| CLIENT | | | | (USB)| ADBD | -+----------+ | | Transport+-------------+ (DEVICE) | - | | | +----------+ -+----------- | | | -| ADB | v + | +----------+ -| CLIENT +--------->SmartSocket | (USB)| ADBD | -+----------+ ^ | (TCP/IP) Transport+-------------+ (DEVICE) | - | | | +----------+ -+----------+ | | | -| DDMLIB | | | Transport+--+ +----------+ -| CLIENT +----------+ | | | (TCP/IP)| ADBD | -+----------+ +------------------------+ +----------|(EMULATOR)| - +----------+ -``` - -The Client and the Server are contained in the same executable and both run on the Host machine. Code sections specific to the Host is enclosed within `ADB_HOST` guard. adbd runs on the Android Device. Daemon specific code is enclosed in `!ADB_HOST` but also sometimes with-in `__ANDROID__` guard. - - -## "SMART SOCKET" and TRANSPORT - -A smart socket is a simple TCP socket with a smart protocol built on top of it. This is what Clients connect onto from the Host side. The Client must always initiate communication via a human readable request but the response format varies. The smart protocol is documented in [SERVICES.TXT](SERVICES.TXT). - -On the other side, the Server communicate with a device via a Transport. adb initially targeted devices connecting over USB, which is restricted to a fixed number of data streams. Therefore, adb multiplexes multiple byte streams over a single pipe via Transport. When devices connecting over other mechanisms (e.g. emulators over TCP) were introduced, the existing transport protocol was maintained. - -## THREADING MODEL and FDEVENT system - -At the heart of both the Server and Daemon is a main thread running an fdevent loop, which is an platform-independent abstraction over poll/epoll/WSAPoll monitoring file descriptors events. Requests and services are usually server from the main thread but some service requests result in new threads being spawned. - -To allow for operations to run on the Main thread, fdevent features a RunQueue combined with an interrupt fd to force polling to return. - -``` -+------------+ +-------------------------^ -| RUNQUEUE | | | -+------------+ | POLLING (Main thread) | -| Function<> | | | -+------------+ | | -| Function<> | ^-^-------^-------^------^^ -+------------+ | | | | -| ... | | | | | -+------------+ | | | | -| | | | | | -|============| | | | | -|Interrupt fd+------+ +----+ +----+ +----+ -+------------+ fd Socket Pipe -``` - -## ASOCKET, APACKET, and AMESSAGE - -The asocket, apacket, and amessage constructs exist only to wrap data while it transits on a Transport. An asocket handles a stream of apackets. An apacket consists in a amessage header featuring a command (`A_SYNC`, `A_OPEN`, `A_CLSE`, `A_WRTE`, `A_OKAY`, ...) followed by a payload (find more documentation in [protocol.txt](protocol.txt). There is no `A_READ` command because an asocket is unidirectional. To model a bi-directional stream, asocket have a peer which go in the opposite direction. - -An asocket features a buffer where the elemental unit is an apacket. Is traffic is inbound, the buffer stores apacket until they are consumed. If the traffic is oubound, the buffer store apackets until they are sent down the wire (with `A_WRTE` commands). - -``` -+---------------------ASocket------------------------+ - | | - | +----------------APacket Queue------------------+ | - | | | | - | | APacket APacket APacket | | - | | +--------+ +--------+ +--------+ | | - | | |AMessage| |AMessage| |AMessage| | | - | | +--------+ +--------+ +--------+ | | - | | | | | | | | | | - | | ..... | | | | | | | | - | | | Data | | Data | | Data | | | - | | | | | | | | | | - | | | | | | | | | | - | | +--------+ +--------+ +--------+ | | - | | | | - | +-----------------------------------------------+ | - +---------------------------------------------------+ -``` - -This system allows to multiplex data streams on an unique byte stream. Without entering too much into details, the amessage fields arg1 and arg2 are used alike in the TCP protocol where local and remote ports identify an unique stream. Note that unlike TCP which feature an "unacknowledged-send window", an apacket is sent only after the previous one has been confirmed to be received. - -The two types of asocket (Remote and Local) differentiate between outbound and inbound traffic. - -## adbd <-> APPPLICATION communication - -This pipeline is detailed in [services.cpp](services.cpp). The JDWP extension implemented by Dalvik/ART are documented in: -- platform/dalvik/+/master/docs/debugmon.html -- platform/dalvik/+/master/docs/debugger.html 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 08986b77e03071049c53a23259106e303af65a0b..0000000000000000000000000000000000000000 --- a/adb/adb.cpp +++ /dev/null @@ -1,1394 +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; -#if ADB_HOST - t->SetConnectionEstablished(true); -#endif -} - -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 { - int flags = 0; - if (no_rebind) { - flags |= INSTALL_LISTENER_NO_REBIND; - } - r = install_listener(pieces[0], pieces[1].c_str(), transport, flags, &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; -} - -static bool g_reject_kill_server = false; -void adb_set_reject_kill_server(bool value) { - g_reject_kill_server = value; -} - -static bool handle_mdns_request(std::string_view service, int reply_fd) { - if (!android::base::ConsumePrefix(&service, "mdns:")) { - return false; - } - - if (service == "check") { - std::string check = mdns_check(); - SendOkay(reply_fd, check); - return true; - } - if (service == "services") { - std::string services_list = mdns_list_discovered_services(); - SendOkay(reply_fd, services_list); - return true; - } - - return false; -} - -HostRequestResult handle_host_request(std::string_view service, TransportType type, - const char* serial, TransportId transport_id, int reply_fd, - asocket* s) { - if (service == "kill") { - if (g_reject_kill_server) { - LOG(WARNING) << "adb server ignoring kill-server"; - SendFail(reply_fd, "kill-server rejected by remote server"); - } else { - fprintf(stderr, "adb server killed by remote request\n"); - 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.emplace_back(kFeatureLibusb); - } - features.emplace_back(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; - } - - if (handle_mdns_request(service, 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 476ed9b0b9e03b42ed5239e9e9829bcfddebbedf..0000000000000000000000000000000000000000 --- a/adb/adb.h +++ /dev/null @@ -1,261 +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 -#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(); -asocket* create_app_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); - -#if ADB_HOST -// 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(); -#endif // ADB_HOST - -#if ADB_HOST -// When ssh-forwarding to a remote adb server, kill-server is almost never what you actually want, -// and unfortunately, many other tools issue it. This adds a knob to reject kill-servers. -void adb_set_reject_kill_server(bool reject); -#endif - -void usb_init(); 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 124e2d8dcd30f55ab46995e9504f989298f807f2..0000000000000000000000000000000000000000 --- a/adb/adb_listeners.cpp +++ /dev/null @@ -1,256 +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(); - -#if ADB_HOST -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; - } - } -} -#endif - -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 enable_server_sockets() EXCLUDES(listener_list_mutex) { - std::lock_guard lock(listener_list_mutex); - for (auto& l : listener_list) { - if (l->connect_to == "*smartsocket*") { - fdevent_set(l->fde, FDE_READ); - } - } -} - -#if ADB_HOST -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); -} -#endif - -InstallStatus install_listener(const std::string& local_name, const char* connect_to, - atransport* transport, int flags, 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 INSTALL_LISTENER_NO_REBIND is set - if (flags & INSTALL_LISTENER_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*") { -#if ADB_HOST - listener->fde = fdevent_create(listener->fd, ss_listener_event_func, listener.get()); -#else - LOG(FATAL) << "attempted to connect to *smartsocket* in daemon"; -#endif - } else { - listener->fde = fdevent_create(listener->fd, listener_event_func, listener.get()); - } - if ((flags & INSTALL_LISTENER_DISABLED) == 0) { - 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 0aa774a7d61dc0277228d84ea14af9cf509385b5..0000000000000000000000000000000000000000 --- a/adb/adb_listeners.h +++ /dev/null @@ -1,49 +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 "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, -}; - -inline constexpr int INSTALL_LISTENER_NO_REBIND = 1 << 0; -inline constexpr int INSTALL_LISTENER_DISABLED = 1 << 1; - -InstallStatus install_listener(const std::string& local_name, const char* connect_to, - atransport* transport, int flags, 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); - -#if ADB_HOST -void enable_server_sockets(); -void close_smartsockets(); -#endif 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 210241ce7d5512ef30d1aa141b32fd041524bbc6..0000000000000000000000000000000000000000 --- a/adb/adb_trace.cpp +++ /dev/null @@ -1,192 +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() { -#if ADB_HOST || !defined(__ANDROID__) - const char* setting = getenv("ADB_TRACE"); - if (setting == nullptr) { - setting = ""; - } - return setting; -#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 e72d8b6f873af4d8860bc9339fe1bc88669617ad..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 valid. 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 42f414b2858d2b7c84f1941ce6fb3e0669eb94be..0000000000000000000000000000000000000000 --- a/adb/adb_wifi.h +++ /dev/null @@ -1,54 +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.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); - -std::string mdns_check(); -std::string mdns_list_discovered_services(); - -struct MdnsInfo { - std::string service_name; - std::string service_type; - std::string addr; - uint16_t port = 0; - - MdnsInfo(std::string_view name, std::string_view type, std::string_view addr, uint16_t port) - : service_name(name), service_type(type), addr(addr), port(port) {} -}; - -std::optional mdns_get_connect_service_info(std::string_view name); -std::optional mdns_get_pairing_service_info(std::string_view name); - -#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 04444093dbef1d9d7ac3b562e56daca29f69eb04..0000000000000000000000000000000000000000 --- a/adb/apex/apex_manifest.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "com.android.adbd", - "version": 300000000 -} 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/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 a3087323699ece49bf8421abf2634c7fc68b8dd1..0000000000000000000000000000000000000000 --- a/adb/client/adb_client.cpp +++ /dev/null @@ -1,435 +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 - -#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; - } - - char buf[4]; - if (!ReadFdExactly(fd.get(), buf, 4)) { - fprintf(stderr, "error: failed to read response from server\n"); - return false; - } - - if (memcmp(buf, "OKAY", 4) == 0) { - // Nothing to do. - } else if (memcmp(buf, "FAIL", 4) == 0) { - std::string output, error; - if (!ReadProtocolString(fd.get(), &output, &error)) { - fprintf(stderr, "error: %s\n", error.c_str()); - return false; - } - - fprintf(stderr, "error: %s\n", output.c_str()); - return false; - } - - // 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); -} - -const std::optional& adb_get_feature_set(std::string* error) { - static std::mutex feature_mutex [[clang::no_destroy]]; - static std::optional features [[clang::no_destroy]] GUARDED_BY(feature_mutex); - std::lock_guard lock(feature_mutex); - if (!features) { - std::string result; - std::string err; - if (adb_query(format_host_command("features"), &result, &err)) { - features = StringToFeatureSet(result); - } else { - if (error) { - *error = err; - } - } - } - return features; -} diff --git a/adb/client/adb_client.h b/adb/client/adb_client.h deleted file mode 100644 index caf4e86ac4386053272205142c4017a666b7d7d3..0000000000000000000000000000000000000000 --- a/adb/client/adb_client.h +++ /dev/null @@ -1,106 +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. -const std::optional& adb_get_feature_set(std::string* _Nullable 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 ea50f591adaf1ce2caadb43d90b78901bb0668b4..0000000000000000000000000000000000000000 --- a/adb/client/adb_install.cpp +++ /dev/null @@ -1,994 +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) { - // We ignore errors here, if the device is missing, we'll notice when we try to push install. - auto&& features = adb_get_feature_set(nullptr); - if (!features) { - 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, CompressionType::Any, false)) { - 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(split).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 61a9a480c919633e4972a8fdc94855f9827ea918..0000000000000000000000000000000000000000 --- a/adb/client/adb_wifi.cpp +++ /dev/null @@ -1,254 +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) { - auto mdns_info = mdns_get_pairing_service_info(host); - - if (!mdns_info.has_value()) { - // 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(mdns_info.has_value() - ? android::base::StringPrintf("%s:%d", mdns_info->addr.c_str(), - mdns_info->port) - : 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 db4c4790341c0ba234c0778a40dd1a4b7fd6c116..0000000000000000000000000000000000000000 --- a/adb/client/auth.cpp +++ /dev/null @@ -1,559 +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()); - bool already_loaded = (g_keys.find(fingerprint) != g_keys.end()); - if (!already_loaded) { - g_keys[fingerprint] = std::move(key); - } - LOG(INFO) << (already_loaded ? "ignored already-loaded" : "loaded new") << " key from '" << file - << "' with fingerprint " << SHA256BitsToHexString(fingerprint); - 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) << "load_keys: failed to stat '" << path << "'"; - return false; - } - - if (S_ISREG(st.st_mode)) { - return load_key(path); - } - - 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) << "load_keys: refusing to recurse into directory '" << path << "'"; - return false; - } - - std::unique_ptr dir(opendir(path.c_str()), closedir); - if (!dir) { - PLOG(ERROR) << "load_keys: 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) << "skipped non-adb_key '" << path << "/" << name << "'"; - continue; - } - - result |= load_key((path + OS_PATH_SEPARATOR + name)); - } - return result; - } - - LOG(ERROR) << "load_keys: 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 b765a302b49d85afbb05612599640aa2aa623690..0000000000000000000000000000000000000000 --- a/adb/client/bugreport.cpp +++ /dev/null @@ -1,289 +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) { - printf("Bug report copied to %s\n", destination.c_str()); - } else { - 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 this instead:\n" - "\tadb bugreport > bugreport.txt\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, CompressionType::None, 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 d9e69f72844297f0a533a6e6c9f34a05cea2a0df..0000000000000000000000000000000000000000 --- a/adb/client/commandline.cpp +++ /dev/null @@ -1,2168 +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 - -#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 "app_processes.pb.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] [PAIRING CODE]\n" - " 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" - " mdns check check if mdns discovery is available\n" - " mdns services list all discovered services\n" - "\n" - "file transfer:\n" - " push [--sync] [-z ALGORITHM] [-Z] LOCAL... REMOTE\n" - " copy local files/directories to device\n" - " --sync: only push files that are newer on the host than the device\n" - " -n: dry run: push files to device without storing to the filesystem\n" - " -z: enable compression with a specified algorithm (any, none, brotli)\n" - " -Z: disable compression\n" - " pull [-a] [-z ALGORITHM] [-Z] REMOTE... LOCAL\n" - " copy files/dirs from device\n" - " -a: preserve file timestamp and mode\n" - " -z: enable compression with a specified algorithm (any, none, brotli)\n" - " -Z: disable compression\n" - " sync [-l] [-z ALGORITHM] [-Z] [all|data|odm|oem|product|system|system_ext|vendor]\n" - " sync a local build from $ANDROID_PRODUCT_OUT to the device (default all)\n" - " -n: dry run: push files to device without storing to the filesystem\n" - " -l: list files that would be copied, but don't copy them\n" - " -z: enable compression with a specified algorithm (any, none, brotli)\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 a 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" - " $ADB_MDNS_AUTO_CONNECT comma-separated list of mdns services to allow auto-connect (default adb-tls-connect)\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) { - std::string error; - auto&& features = adb_get_feature_set(&error); - if (!features) { - error_exit("%s", error.c_str()); - } - - 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) { - std::string error; - auto&& features = adb_get_feature_set(&error); - if (!features) { - error_exit("%s", error.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) { - fprintf(stderr, "adb: couldn't parse 'wait-for' command: %s\n", service); - return false; - } - - // If the first thing after "wait-for-" wasn't a TRANSPORT, insert whatever - // the current transport implies. - if (components[2] != "usb" && components[2] != "local" && components[2] != "any") { - TransportType t; - adb_get_transport(&t, nullptr, nullptr); - 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"); - } - } - - // Stitch it back together and send it over... - 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", 12000ms); - } - - 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) { - auto&& features = adb_get_feature_set(nullptr); - if (features) { - 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 CompressionType parse_compression_type(const std::string& str, bool allow_numbers) { - if (allow_numbers) { - if (str == "0") { - return CompressionType::None; - } else if (str == "1") { - return CompressionType::Any; - } - } - - if (str == "any") { - return CompressionType::Any; - } else if (str == "none") { - return CompressionType::None; - } - - if (str == "brotli") { - return CompressionType::Brotli; - } else if (str == "lz4") { - return CompressionType::LZ4; - } else if (str == "zstd") { - return CompressionType::Zstd; - } - - error_exit("unexpected compression type %s", str.c_str()); -} - -static void parse_push_pull_args(const char** arg, int narg, std::vector* srcs, - const char** dst, bool* copy_attrs, bool* sync, - CompressionType* compression, bool* dry_run) { - *copy_attrs = false; - if (const char* adb_compression = getenv("ADB_COMPRESSION")) { - *compression = parse_compression_type(adb_compression, true); - } - - 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 (narg < 2) { - error_exit("-z requires an argument"); - } - *compression = parse_compression_type(*++arg, false); - --narg; - } else if (!strcmp(*arg, "-Z")) { - *compression = CompressionType::None; - } else if (dry_run && !strcmp(*arg, "-n")) { - *dry_run = true; - } 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, - StandardStreamsCallbackInterface* callback) { - 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, false, callback); - return 0; -} - -static int adb_connect_command(const std::string& command, TransportId* transport = nullptr) { - return adb_connect_command(command, transport, &DEFAULT_STANDARD_STREAMS_CALLBACK); -} - -// A class that prints out human readable form of the protobuf message for "track-app" service -// (received in binary format). -class TrackAppStreamsCallback : public DefaultStandardStreamsCallback { - public: - TrackAppStreamsCallback() : DefaultStandardStreamsCallback(nullptr, nullptr) {} - - // Assume the buffer contains at least 4 bytes of valid data. - void OnStdout(const char* buffer, int length) override { - if (length < 4) return; // Unexpected length received. Do nothing. - - adb::proto::AppProcesses binary_proto; - // The first 4 bytes are the length of remaining content in hexadecimal format. - binary_proto.ParseFromString(std::string(buffer + 4, length - 4)); - char summary[24]; // The following string includes digits and 16 fixed characters. - int written = snprintf(summary, sizeof(summary), "Process count: %d\n", - binary_proto.process_size()); - OnStream(nullptr, stdout, summary, written); - - std::string string_proto; - google::protobuf::TextFormat::PrintToString(binary_proto, &string_proto); - OnStream(nullptr, stdout, string_proto.data(), string_proto.length()); - } - - private: - DISALLOW_COPY_AND_ASSIGN(TrackAppStreamsCallback); -}; - -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], "transport-id")) { - TransportId transport_id; - std::string error; - unique_fd fd(adb_connect(&transport_id, "host:features", &error, true)); - if (fd == -1) { - error_exit("%s", error.c_str()); - } - printf("%" PRIu64 "\n", transport_id); - return 0; - } 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 || argc > 3) error_exit("usage: adb pair HOST[:PORT] [PAIRING CODE]"); - - std::string password; - if (argc == 2) { - printf("Enter pairing code: "); - fflush(stdout); - if (!std::getline(std::cin, password) || password.empty()) { - error_exit("No pairing code provided"); - } - } else { - password = argv[2]; - } - 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")) { - std::string error; - auto&& features = adb_get_feature_set(&error); - if (!features) { - error_exit("%s", error.c_str()); - } - - 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; - } else if (!strcmp(argv[0], "mdns")) { - --argc; - if (argc < 1) error_exit("mdns requires an argument"); - ++argv; - - std::string error; - if (!adb_check_server_version(&error)) { - error_exit("failed to check server version: %s", error.c_str()); - } - - std::string query = "host:mdns:"; - if (!strcmp(argv[0], "check")) { - if (argc != 1) error_exit("mdns %s doesn't take any arguments", argv[0]); - query += "check"; - } else if (!strcmp(argv[0], "services")) { - if (argc != 1) error_exit("mdns %s doesn't take any arguments", argv[0]); - query += "services"; - printf("List of discovered mdns services\n"); - } else { - error_exit("unknown mdns command [%s]", argv[0]); - } - - return adb_query_command(query); - } - /* 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 dry_run = false; - CompressionType compression = CompressionType::Any; - std::vector srcs; - const char* dst = nullptr; - - parse_push_pull_args(&argv[1], argc - 1, &srcs, &dst, ©_attrs, &sync, &compression, - &dry_run); - if (srcs.empty() || !dst) error_exit("push requires an argument"); - return do_sync_push(srcs, dst, sync, compression, dry_run) ? 0 : 1; - } else if (!strcmp(argv[0], "pull")) { - bool copy_attrs = false; - CompressionType compression = CompressionType::Any; - std::vector srcs; - const char* dst = "."; - - parse_push_pull_args(&argv[1], argc - 1, &srcs, &dst, ©_attrs, nullptr, &compression, - nullptr); - if (srcs.empty()) error_exit("pull requires an argument"); - return do_sync_pull(srcs, dst, copy_attrs, compression) ? 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 dry_run = false; - CompressionType compression = CompressionType::Any; - - if (const char* adb_compression = getenv("ADB_COMPRESSION"); adb_compression) { - compression = parse_compression_type(adb_compression, true); - } - - int opt; - while ((opt = getopt(argc, const_cast(argv), "lnz:Z")) != -1) { - switch (opt) { - case 'l': - list_only = true; - break; - case 'n': - dry_run = true; - break; - case 'z': - compression = parse_compression_type(optarg, false); - break; - case 'Z': - compression = CompressionType::None; - break; - default: - error_exit("usage: adb sync [-l] [-n] [-z ALGORITHM] [-Z] [PARTITION]"); - } - } - - if (optind == argc) { - src = "all"; - } else if (optind + 1 == argc) { - src = argv[optind]; - } else { - error_exit("usage: adb sync [-l] [-n] [-z ALGORITHM] [-Z] [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, compression, dry_run)) { - 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-app")) { - std::string error; - auto&& features = adb_get_feature_set(&error); - if (!features) { - error_exit("%s", error.c_str()); - } - if (!CanUseFeature(*features, kFeatureTrackApp)) { - error_exit("track-app is not supported by the device"); - } - TrackAppStreamsCallback callback; - return adb_connect_command("track-app", nullptr, &callback); - } 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. - std::string error; - auto&& features = adb_get_feature_set(&error); - if (!features) { - error_exit("%s", error.c_str()); - } - - 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 bc4b91bb9aa12a11c36d72e9e637d68a208d84b3..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, CompressionType::Any, false)) { - 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 2e8b9756663c9b19f9f8069b69ae74429b88147c..0000000000000000000000000000000000000000 --- a/adb/client/file_sync_client.cpp +++ /dev/null @@ -1,1773 +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 - -#include "sysdeps.h" - -#include "adb.h" -#include "adb_client.h" -#include "adb_io.h" -#include "adb_utils.h" -#include "compression_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; - auto&& features = adb_get_feature_set(&error); - if (!features) { - Error("failed to get feature set: %s", error.c_str()); - } else { - features_ = &*features; - 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); - have_sendrecv_v2_lz4_ = CanUseFeature(*features, kFeatureSendRecv2LZ4); - have_sendrecv_v2_zstd_ = CanUseFeature(*features, kFeatureSendRecv2Zstd); - have_sendrecv_v2_dry_run_send_ = CanUseFeature(*features, kFeatureSendRecv2DryRunSend); - std::string error; - 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_; } - bool HaveSendRecv2LZ4() const { return have_sendrecv_v2_lz4_; } - bool HaveSendRecv2Zstd() const { return have_sendrecv_v2_zstd_; } - bool HaveSendRecv2DryRunSend() const { return have_sendrecv_v2_dry_run_send_; } - - // Resolve a compression type which might be CompressionType::Any to a specific compression - // algorithm. - CompressionType ResolveCompressionType(CompressionType compression) const { - if (compression == CompressionType::Any) { - if (HaveSendRecv2Zstd()) { - return CompressionType::Zstd; - } else if (HaveSendRecv2LZ4()) { - return CompressionType::LZ4; - } else if (HaveSendRecv2Brotli()) { - return CompressionType::Brotli; - } - return CompressionType::None; - } - return compression; - } - - 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, CompressionType compression, bool dry_run) { - 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 = 0; - switch (compression) { - case CompressionType::None: - break; - - case CompressionType::Brotli: - msg.send_v2_setup.flags = kSyncFlagBrotli; - break; - - case CompressionType::LZ4: - msg.send_v2_setup.flags = kSyncFlagLZ4; - break; - - case CompressionType::Zstd: - msg.send_v2_setup.flags = kSyncFlagZstd; - break; - - case CompressionType::Any: - LOG(FATAL) << "unexpected CompressionType::Any"; - } - - if (dry_run) { - msg.send_v2_setup.flags |= kSyncFlagDryRun; - } - - 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, CompressionType compression) { - 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 = 0; - switch (compression) { - case CompressionType::None: - break; - - case CompressionType::Brotli: - msg.recv_v2_setup.flags |= kSyncFlagBrotli; - break; - - case CompressionType::LZ4: - msg.recv_v2_setup.flags |= kSyncFlagLZ4; - break; - - case CompressionType::Zstd: - msg.recv_v2_setup.flags |= kSyncFlagZstd; - break; - - case CompressionType::Any: - LOG(FATAL) << "unexpected CompressionType::Any"; - } - - 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, bool dry_run) { - if (dry_run) { - // We need to use send v2 for dry run. - return SendLargeFile(path, mode, lpath, rpath, mtime, CompressionType::None, dry_run); - } - - 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 SendLargeFile(const std::string& path, mode_t mode, const std::string& lpath, - const std::string& rpath, unsigned mtime, CompressionType compression, - bool dry_run) { - if (dry_run && !HaveSendRecv2DryRunSend()) { - Error("dry-run not supported by the device"); - return false; - } - - if (!HaveSendRecv2()) { - return SendLargeFileLegacy(path, mode, lpath, rpath, mtime); - } - - compression = ResolveCompressionType(compression); - - if (!SendSend2(path, mode, compression, dry_run)) { - 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; - - std::variant - encoder_storage; - Encoder* encoder = nullptr; - switch (compression) { - case CompressionType::None: - encoder = &encoder_storage.emplace(SYNC_DATA_MAX); - break; - - case CompressionType::Brotli: - encoder = &encoder_storage.emplace(SYNC_DATA_MAX); - break; - - case CompressionType::LZ4: - encoder = &encoder_storage.emplace(SYNC_DATA_MAX); - break; - - case CompressionType::Zstd: - encoder = &encoder_storage.emplace(SYNC_DATA_MAX); - break; - - case CompressionType::Any: - LOG(FATAL) << "unexpected CompressionType::Any"; - } - - 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; - EncodeResult result = encoder->Encode(&output); - if (result == EncodeResult::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 == EncodeResult::Done) { - sending = false; - break; - } else if (result == EncodeResult::NeedInput) { - break; - } else if (result == EncodeResult::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 SendLargeFileLegacy(const std::string& path, mode_t mode, const std::string& lpath, - const std::string& rpath, unsigned 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_; - const FeatureSet* features_ = nullptr; - bool have_stat_v2_; - bool have_ls_v2_; - bool have_sendrecv_v2_; - bool have_sendrecv_v2_brotli_; - bool have_sendrecv_v2_lz4_; - bool have_sendrecv_v2_zstd_; - bool have_sendrecv_v2_dry_run_send_; - - 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, CompressionType compression, - bool dry_run) { - 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, dry_run)) { - return false; - } - return sc.ReadAcknowledgements(sync); -#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(), - dry_run)) { - return false; - } - } else { - if (!sc.SendLargeFile(rpath, mode, lpath, rpath, mtime, compression, dry_run)) { - return false; - } - } - return sc.ReadAcknowledgements(sync); -} - -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, CompressionType compression) { - compression = sc.ResolveCompressionType(compression); - - if (!sc.SendRecv2(rpath, compression)) 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); - std::variant - decoder_storage; - Decoder* decoder = nullptr; - - std::span buffer_span(buffer.data(), buffer.size()); - switch (compression) { - case CompressionType::None: - decoder = &decoder_storage.emplace(buffer_span); - break; - - case CompressionType::Brotli: - decoder = &decoder_storage.emplace(buffer_span); - break; - - case CompressionType::LZ4: - decoder = &decoder_storage.emplace(buffer_span); - break; - - case CompressionType::Zstd: - decoder = &decoder_storage.emplace(buffer_span); - break; - - case CompressionType::Any: - LOG(FATAL) << "unexpected CompressionType::Any"; - } - - while (true) { - syncmsg msg; - if (!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) { - adb_unlink(lpath); - return false; - } - - if (msg.data.id == ID_DONE) { - if (!decoder->Finish()) { - sc.Error("unexpected ID_DONE"); - return false; - } - } else if (msg.data.id != ID_DATA) { - adb_unlink(lpath); - sc.ReportCopyFailure(rpath, lpath, msg); - return false; - } else { - 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; - DecodeResult result = decoder->Decode(&output); - - if (result == DecodeResult::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(output.size()); - sc.ReportProgress(name != nullptr ? name : rpath, bytes_copied, expected_size); - - if (result == DecodeResult::NeedInput) { - break; - } else if (result == DecodeResult::MoreOutput) { - continue; - } else if (result == DecodeResult::Done) { - sc.RecordFilesTransferred(1); - return true; - } else { - LOG(FATAL) << "invalid DecodeResult: " << static_cast(result); - } - } - } -} - -static bool sync_recv(SyncConnection& sc, const char* rpath, const char* lpath, const char* name, - uint64_t expected_size, CompressionType compression) { - if (sc.HaveSendRecv2()) { - return sync_recv_v2(sc, rpath, lpath, name, expected_size, compression); - } 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, - CompressionType compression, bool dry_run) { - 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, compression, - dry_run)) { - 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, - CompressionType compression, bool dry_run) { - 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, compression, dry_run); - 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, compression, - dry_run); - 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, 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, &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, CompressionType compression) { - 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, compression)) { - 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, - CompressionType compression, 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, compression); - 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, compression)) { - 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, - CompressionType compression, bool dry_run) { - SyncConnection sc; - if (!sc.IsValid()) return false; - - bool success = copy_local_dir_remote(sc, lpath, rpath, true, list_only, compression, dry_run); - 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 cb8ca93239f5f6c1a4aea21f896fae1e1cf3009c..0000000000000000000000000000000000000000 --- a/adb/client/file_sync_client.h +++ /dev/null @@ -1,31 +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 "file_sync_protocol.h" - -bool do_sync_ls(const char* path); -bool do_sync_push(const std::vector& srcs, const char* dst, bool sync, - CompressionType compression, bool dry_run); -bool do_sync_pull(const std::vector& srcs, const char* dst, bool copy_attrs, - CompressionType compression, const char* name = nullptr); - -bool do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only, - CompressionType compression, bool dry_run); diff --git a/adb/client/incremental.cpp b/adb/client/incremental.cpp deleted file mode 100644 index 60735f8c5ed1a1bdfac6952e6286d5bc610ec60b..0000000000000000000000000000000000000000 --- a/adb/client/incremental.cpp +++ /dev/null @@ -1,256 +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.\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.\n", signature_file.c_str()); - } - return {}; - } - - auto [signature, tree_size] = read_id_sig_headers(fd); - - std::vector invalid_signature; - if (signature.size() > kMaxSignatureSize) { - if (!silent) { - fprintf(stderr, "Signature is too long. Max allowed is %d. Abort.\n", - kMaxSignatureSize); - } - return {std::move(fd), std::move(invalid_signature)}; - } - - 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 {std::move(fd), std::move(invalid_signature)}; - } - - 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) { - std::string encoded_signature; - - auto [fd, signature] = read_signature(file_size, std::move(signature_file), silent); - if (!fd.ok() || signature.empty()) { - return {std::move(fd), std::move(encoded_signature)}; - } - - 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::move(fd), std::move(encoded_signature)}; - } - - encoded_signature.resize(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() && signature.empty()) { - 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; - } - - if (android::base::EndsWithIgnoreCase(file, ".apk")) { - // Signature has to be present for APKs. - auto [fd, _] = read_signature(st.st_size, file, /*silent=*/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 = cast_handle_to_int(adb_get_os_handle(connection_fd.get())); - auto fd_param = std::to_string(osh); - - // pipe for child process to write output - int print_fds[2]; - if (adb_socketpair(print_fds) != 0) { - if (!silent) { - fprintf(stderr, "adb: 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(cast_handle_to_int(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) { - if (!silent) { - fprintf(stderr, "adb: install command failed"); - } - return {}; - } - - // 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 0654a11b4a4a2024bb6cf08bde16af2a339039bc..0000000000000000000000000000000000000000 --- a/adb/client/incremental_server.cpp +++ /dev/null @@ -1,722 +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_; } - - bool hasTree() const { return tree_fd_.ok(); } - - 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]; - if (!file.hasTree()) { - return true; - } - 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) { - D("No signature file found for '%s'('%s')", filepath, signature_file.c_str()); - return {}; - } - - 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 1a071fd5386ec82d9fcd0ceab6039a65e4aab990..0000000000000000000000000000000000000000 --- a/adb/client/incremental_utils.cpp +++ /dev/null @@ -1,379 +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 - -#include "adb_io.h" -#include "adb_trace.h" -#include "sysdeps.h" - -using namespace std::literals; - -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)}; -} - -static std::vector InstallationPriorityBlocks(borrowed_fd fd, Size fileSize) { - static constexpr std::array additional_matches = { - "resources.arsc"sv, "AndroidManifest.xml"sv, "classes.dex"sv}; - - auto [zip, _] = openZipArchive(fd, fileSize); - if (!zip) { - return {}; - } - - auto matcher = [](std::string_view entry_name) { - if (entry_name.starts_with("lib/"sv) && entry_name.ends_with(".so"sv)) { - return true; - } - return std::any_of(additional_matches.begin(), additional_matches.end(), - [entry_name](std::string_view i) { return i == entry_name; }); - }; - - void* cookie = nullptr; - if (StartIteration(zip, &cookie, std::move(matcher)) != 0) { - D("%s failed at StartIteration: %d", __func__, errno); - return {}; - } - - std::vector installationPriorityBlocks; - ZipEntry64 entry; - std::string_view entryName; - while (Next(cookie, &entry, &entryName) == 0) { - if (entryName == "classes.dex"sv) { - // Only the head is needed for installation - int32_t startBlockIndex = offsetToBlockIndex(entry.offset); - appendBlocks(startBlockIndex, 2, &installationPriorityBlocks); - D("\tadding to priority blocks: '%.*s' (%d)", (int)entryName.size(), entryName.data(), - 2); - } else { - // 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' (%d)", (int)entryName.size(), entryName.data(), - numNewBlocks); - } - } - - 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 4ad60dd280b0835ce42404d433827b2b6878c6c3..0000000000000000000000000000000000000000 --- a/adb/client/incremental_utils.h +++ /dev/null @@ -1,49 +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 int kMaxSignatureSize = 8096; // incrementalfs.h - -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 a19bd6d3113dc3dadf2826a366bdde3b939bc251..0000000000000000000000000000000000000000 --- a/adb/client/main.cpp +++ /dev/null @@ -1,238 +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); }); - }); - - const char* reject_kill_server = getenv("ADB_REJECT_KILL_SERVER"); - if (reject_kill_server && strcmp(reject_kill_server, "1") == 0) { - adb_set_reject_kill_server(true); - } - - const 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. Don't actually - // accept any connections until adb_wait_for_device_initialization finishes below. - while (install_listener(socket_spec, "*smartsocket*", nullptr, INSTALL_LISTENER_DISABLED, - 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(); - - if (ack_reply_fd >= 0) { - // 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 - } - // We don't accept() client connections until this point: this way, clients - // can't see wonky state early in startup even if they're connecting directly - // to the server instead of going through the adb program. - fdevent_run_on_main_thread([] { enable_server_sockets(); }); - }); - 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/mdns_utils.cpp b/adb/client/mdns_utils.cpp deleted file mode 100644 index 8666b18e96b2beda9cf97eb91af98a96361a26b3..0000000000000000000000000000000000000000 --- a/adb/client/mdns_utils.cpp +++ /dev/null @@ -1,77 +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 "client/mdns_utils.h" - -#include - -namespace mdns { - -// .. -std::optional mdns_parse_instance_name(std::string_view name) { - CHECK(!name.empty()); - - // Return the whole name if it doesn't fall under .. or - // . - bool has_local_suffix = false; - // Strip the local suffix, if any - { - std::string local_suffix = ".local"; - local_suffix += android::base::EndsWith(name, ".") ? "." : ""; - - if (android::base::ConsumeSuffix(&name, local_suffix)) { - if (name.empty()) { - return std::nullopt; - } - has_local_suffix = true; - } - } - - std::string transport; - // Strip the transport suffix, if any - { - std::string add_dot = (!has_local_suffix && android::base::EndsWith(name, ".")) ? "." : ""; - std::array transport_suffixes{"._tcp", "._udp"}; - - for (const auto& t : transport_suffixes) { - if (android::base::ConsumeSuffix(&name, t + add_dot)) { - if (name.empty()) { - return std::nullopt; - } - transport = t.substr(1); - break; - } - } - - if (has_local_suffix && transport.empty()) { - return std::nullopt; - } - } - - if (!has_local_suffix && transport.empty()) { - return std::make_optional(name, "", ""); - } - - // Split the service name from the instance name - auto pos = name.rfind("."); - if (pos == 0 || pos == std::string::npos || pos == name.size() - 1) { - return std::nullopt; - } - - return std::make_optional(name.substr(0, pos), name.substr(pos + 1), transport); -} - -} // namespace mdns diff --git a/adb/client/mdns_utils.h b/adb/client/mdns_utils.h deleted file mode 100644 index 40d095ddcc01a0caa8dedd227e3098add7c11fbf..0000000000000000000000000000000000000000 --- a/adb/client/mdns_utils.h +++ /dev/null @@ -1,54 +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 "adb_wifi.h" - -namespace mdns { - -struct MdnsInstance { - std::string instance_name; // "my name" - std::string service_name; // "_adb-tls-connect" - std::string transport_type; // either "_tcp" or "_udp" - - MdnsInstance(std::string_view inst, std::string_view serv, std::string_view trans) - : instance_name(inst), service_name(serv), transport_type(trans) {} -}; - -// This parser is based on https://tools.ietf.org/html/rfc6763#section-4.1 for -// structured service instance names, where the whole name is in the format -// ... -// -// In our case, we ignore portion of the name, which -// we always assume to be ".local", or link-local mDNS. -// -// The string can be in one of the following forms: -// - ...? -// - e.g. "instance._service._tcp.local" (or "...local.") -// - ..? (must contain either "_tcp" or "_udp" at the end) -// - e.g. "instance._service._tcp" (or "..._tcp.) -// - (can contain dots '.') -// - e.g. "myname", "name.", "my.name." -// -// Returns an MdnsInstance with the appropriate fields filled in (instance name is never empty), -// otherwise returns std::nullopt. -std::optional mdns_parse_instance_name(std::string_view name); - -} // namespace mdns diff --git a/adb/client/mdns_utils_test.cpp b/adb/client/mdns_utils_test.cpp deleted file mode 100644 index ec71529576672e96992cfc56d9eeb22e3e910a5b..0000000000000000000000000000000000000000 --- a/adb/client/mdns_utils_test.cpp +++ /dev/null @@ -1,173 +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 "client/mdns_utils.h" - -#include - -namespace mdns { - -TEST(mdns_utils, mdns_parse_instance_name) { - // Just the instance name - { - std::string str = "."; - auto res = mdns_parse_instance_name(str); - ASSERT_TRUE(res.has_value()); - EXPECT_EQ(str, res->instance_name); - EXPECT_TRUE(res->service_name.empty()); - EXPECT_TRUE(res->transport_type.empty()); - } - { - std::string str = "my.name"; - auto res = mdns_parse_instance_name(str); - ASSERT_TRUE(res.has_value()); - EXPECT_EQ(str, res->instance_name); - EXPECT_TRUE(res->service_name.empty()); - EXPECT_TRUE(res->transport_type.empty()); - } - { - std::string str = "my.name."; - auto res = mdns_parse_instance_name(str); - ASSERT_TRUE(res.has_value()); - EXPECT_EQ(str, res->instance_name); - EXPECT_TRUE(res->service_name.empty()); - EXPECT_TRUE(res->transport_type.empty()); - } - - // With "_tcp", "_udp" transport type - for (const std::string_view transport : {"._tcp", "._udp"}) { - { - std::string str = android::base::StringPrintf("%s", transport.data()); - auto res = mdns_parse_instance_name(str); - EXPECT_FALSE(res.has_value()); - } - { - std::string str = android::base::StringPrintf("%s.", transport.data()); - auto res = mdns_parse_instance_name(str); - EXPECT_FALSE(res.has_value()); - } - { - std::string str = android::base::StringPrintf("service%s", transport.data()); - auto res = mdns_parse_instance_name(str); - EXPECT_FALSE(res.has_value()); - } - { - std::string str = android::base::StringPrintf(".service%s", transport.data()); - auto res = mdns_parse_instance_name(str); - EXPECT_FALSE(res.has_value()); - } - { - std::string str = android::base::StringPrintf("service.%s", transport.data()); - auto res = mdns_parse_instance_name(str); - EXPECT_FALSE(res.has_value()); - } - { - std::string str = android::base::StringPrintf("my.service%s", transport.data()); - auto res = mdns_parse_instance_name(str); - ASSERT_TRUE(res.has_value()); - EXPECT_EQ(res->instance_name, "my"); - EXPECT_EQ(res->service_name, "service"); - EXPECT_EQ(res->transport_type, transport.substr(1)); - } - { - std::string str = android::base::StringPrintf("my.service%s.", transport.data()); - auto res = mdns_parse_instance_name(str); - ASSERT_TRUE(res.has_value()); - EXPECT_EQ(res->instance_name, "my"); - EXPECT_EQ(res->service_name, "service"); - EXPECT_EQ(res->transport_type, transport.substr(1)); - } - { - std::string str = android::base::StringPrintf("my..service%s", transport.data()); - auto res = mdns_parse_instance_name(str); - ASSERT_TRUE(res.has_value()); - EXPECT_EQ(res->instance_name, "my."); - EXPECT_EQ(res->service_name, "service"); - EXPECT_EQ(res->transport_type, transport.substr(1)); - } - { - std::string str = android::base::StringPrintf("my.name.service%s.", transport.data()); - auto res = mdns_parse_instance_name(str); - ASSERT_TRUE(res.has_value()); - EXPECT_EQ(res->instance_name, "my.name"); - EXPECT_EQ(res->service_name, "service"); - EXPECT_EQ(res->transport_type, transport.substr(1)); - } - { - std::string str = android::base::StringPrintf("name.service.%s.", transport.data()); - auto res = mdns_parse_instance_name(str); - EXPECT_FALSE(res.has_value()); - } - - // With ".local" domain - { - std::string str = ".local"; - auto res = mdns_parse_instance_name(str); - EXPECT_FALSE(res.has_value()); - } - { - std::string str = ".local."; - auto res = mdns_parse_instance_name(str); - EXPECT_FALSE(res.has_value()); - } - { - std::string str = "name.local"; - auto res = mdns_parse_instance_name(str); - EXPECT_FALSE(res.has_value()); - } - { - std::string str = android::base::StringPrintf("%s.local", transport.data()); - auto res = mdns_parse_instance_name(str); - EXPECT_FALSE(res.has_value()); - } - { - std::string str = android::base::StringPrintf("service%s.local", transport.data()); - auto res = mdns_parse_instance_name(str); - EXPECT_FALSE(res.has_value()); - } - { - std::string str = android::base::StringPrintf("name.service%s.local", transport.data()); - auto res = mdns_parse_instance_name(str); - ASSERT_TRUE(res.has_value()); - EXPECT_EQ(res->instance_name, "name"); - EXPECT_EQ(res->service_name, "service"); - EXPECT_EQ(res->transport_type, transport.substr(1)); - } - { - std::string str = - android::base::StringPrintf("name.service%s.local.", transport.data()); - auto res = mdns_parse_instance_name(str); - ASSERT_TRUE(res.has_value()); - EXPECT_EQ(res->instance_name, "name"); - EXPECT_EQ(res->service_name, "service"); - EXPECT_EQ(res->transport_type, transport.substr(1)); - } - { - std::string str = - android::base::StringPrintf("name.service%s..local.", transport.data()); - auto res = mdns_parse_instance_name(str); - EXPECT_FALSE(res.has_value()); - } - { - std::string str = - android::base::StringPrintf("name.service.%s.local.", transport.data()); - auto res = mdns_parse_instance_name(str); - EXPECT_FALSE(res.has_value()); - } - } -} - -} // namespace mdns diff --git a/adb/client/pairing/pairing_client.cpp b/adb/client/pairing/pairing_client.cpp deleted file mode 100644 index 937a5bd4cb05216d8a14f25ef5a8f9bfd3bff425..0000000000000000000000000000000000000000 --- a/adb/client/pairing/pairing_client.cpp +++ /dev/null @@ -1,173 +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_); - - int osh = cast_handle_to_int(adb_get_os_handle(fd.release())); - 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_local.cpp b/adb/client/transport_local.cpp deleted file mode 100644 index 15a07246615fc80f618fbbc9af47231c8937c0bf..0000000000000000000000000000000000000000 --- a/adb/client/transport_local.cpp +++ /dev/null @@ -1,310 +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 "adb.h" -#include "adb_io.h" -#include "adb_unique_fd.h" -#include "adb_utils.h" -#include "socket_spec.h" -#include "sysdeps/chrono.h" - -// 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 std::unordered_map local_transports - [[clang::no_destroy]] GUARDED_BY(local_transports_lock); - -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 (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)); - } - - 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; -} - -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()); - } - } -} - -void local_init(const std::string& addr) { - D("transport: local client init"); - std::thread(client_socket_thread, addr).detach(); - adb_local_transport_max_port_env_override(); -} - -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()); -} - -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; - - // 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; - } - - // 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/client/transport_mdns.cpp b/adb/client/transport_mdns.cpp deleted file mode 100644 index a0fc9caf44b3707c5c39bc6219b37e9f47f0336a..0000000000000000000000000000000000000000 --- a/adb/client/transport_mdns.cpp +++ /dev/null @@ -1,761 +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 - -#include "adb_client.h" -#include "adb_mdns.h" -#include "adb_trace.h" -#include "adb_utils.h" -#include "adb_wifi.h" -#include "client/mdns_utils.h" -#include "fdevent/fdevent.h" -#include "sysdeps.h" - -static DNSServiceRef service_refs[kNumADBDNSServices]; -static fdevent* service_ref_fdes[kNumADBDNSServices]; -static auto& g_autoconn_whitelist = *new std::unordered_set(); - -static int adb_DNSServiceIndexByName(std::string_view regType) { - for (int i = 0; i < kNumADBDNSServices; ++i) { - if (!strncmp(regType.data(), kADBDNSServices[i], strlen(kADBDNSServices[i]))) { - return i; - } - } - return -1; -} - -static void config_auto_connect_services() { - // ADB_MDNS_AUTO_CONNECT is a comma-delimited list of mdns services - // that are allowed to auto-connect. By default, only allow "adb-tls-connect" - // to auto-connect, since this is filtered down to auto-connect only to paired - // devices. - g_autoconn_whitelist.insert(kADBSecureConnectServiceRefIndex); - const char* srvs = getenv("ADB_MDNS_AUTO_CONNECT"); - if (!srvs) { - return; - } - - if (strcmp(srvs, "0") == 0) { - D("Disabling all auto-connecting"); - g_autoconn_whitelist.clear(); - return; - } - - if (strcmp(srvs, "1") == 0) { - D("Allow all auto-connecting"); - g_autoconn_whitelist.insert(kADBTransportServiceRefIndex); - return; - } - - // Selectively choose which services to allow auto-connect. - // E.g. ADB_MDNS_AUTO_CONNECT=adb,adb-tls-connect would allow - // _adb._tcp and _adb-tls-connnect._tcp services to auto-connect. - auto srvs_list = android::base::Split(srvs, ","); - std::unordered_set new_whitelist; - for (const auto& item : srvs_list) { - auto full_srv = android::base::StringPrintf("_%s._tcp", item.data()); - int idx = adb_DNSServiceIndexByName(full_srv); - if (idx >= 0) { - new_whitelist.insert(idx); - } - } - - if (!new_whitelist.empty()) { - g_autoconn_whitelist = std::move(new_whitelist); - } -} - -static bool adb_DNSServiceShouldAutoConnect(const char* regType, const char* serviceName) { - // Try to auto-connect to any "_adb" or "_adb-tls-connect" services excluding emulator services. - int index = adb_DNSServiceIndexByName(regType); - if (index != kADBTransportServiceRefIndex && index != kADBSecureConnectServiceRefIndex) { - return false; - } - if (g_autoconn_whitelist.find(index) == g_autoconn_whitelist.end()) { - D("Auto-connect for regType '%s' disabled", regType); - return false; - } - // 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 true; -} - -// 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_; - } - - void DestroyServiceRef() { - if (!initialized_) { - return; - } - - // Order matters here! Must destroy the fdevent first since it has a - // reference to |sdRef_|. - fdevent_destroy(fde_); - D("DNSServiceRefDeallocate(sdRef=%p)", sdRef_); - DNSServiceRefDeallocate(sdRef_); - initialized_ = false; - } - - virtual ~AsyncServiceRef() { DestroyServiceRef(); } - - 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 { - D("DNSServiceGetAddrInfo(sdRef=%p, hosttarget=%s)", sdRef_, hosttarget); - 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("%s.%s", serviceName_.c_str(), regType_.c_str()), - &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; - } - - bool AddToServiceRegistry(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 false; - } - - // 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 false; - } - - // Remove any services with the same instance name, as it may be a stale registration. - removeDNSService(regType_.c_str(), serviceName_.c_str()); - - // Add to the service registry before trying to auto-connect, since socket_spec_connect will - // check these registries for the ip address when connecting via mdns instance name. - int adbSecureServiceType = serviceIndex(); - ServiceRegistry* services = nullptr; - switch (adbSecureServiceType) { - case kADBTransportServiceRefIndex: - services = sAdbTransportServices; - break; - case kADBSecurePairingServiceRefIndex: - services = sAdbSecurePairingServices; - break; - case kADBSecureConnectServiceRefIndex: - services = sAdbSecureConnectServices; - break; - default: - LOG(WARNING) << "No registry available for reg_type=[" << regType_ << "]"; - return false; - } - - services->push_back(std::unique_ptr(this)); - - if (adb_DNSServiceShouldAutoConnect(regType_.c_str(), serviceName_.c_str())) { - std::string response; - D("Attempting to connect 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("%s.%s", serviceName_.c_str(), - regType_.c_str()), - &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_); - } - - return true; - } - - int serviceIndex() const { return adb_DNSServiceIndexByName(regType_.c_str()); } - - std::string hostTarget() const { return hosttarget_; } - - std::string serviceName() const { return serviceName_; } - - std::string regType() const { return regType_; } - - std::string ipAddress() const { return ip_addr_; } - - uint16_t port() const { return port_; } - - using ServiceRegistry = std::vector>; - - // unencrypted tcp connections - static ServiceRegistry* sAdbTransportServices; - - static ServiceRegistry* sAdbSecurePairingServices; - static ServiceRegistry* sAdbSecureConnectServices; - - static void initAdbServiceRegistries(); - - static void forEachService(const ServiceRegistry& services, std::string_view hostname, - adb_secure_foreach_service_callback cb); - - static bool connectByServiceName(const ServiceRegistry& services, - const std::string& service_name); - - static void removeDNSService(const char* regType, const char* serviceName); - - 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 -ResolvedService::ServiceRegistry* ResolvedService::sAdbTransportServices = NULL; - -// static -ResolvedService::ServiceRegistry* ResolvedService::sAdbSecurePairingServices = NULL; - -// static -ResolvedService::ServiceRegistry* ResolvedService::sAdbSecureConnectServices = NULL; - -// static -void ResolvedService::initAdbServiceRegistries() { - if (!sAdbTransportServices) { - sAdbTransportServices = new ServiceRegistry; - } - if (!sAdbSecurePairingServices) { - sAdbSecurePairingServices = new ServiceRegistry; - } - if (!sAdbSecureConnectServices) { - sAdbSecureConnectServices = new ServiceRegistry; - } -} - -// static -void ResolvedService::forEachService(const ServiceRegistry& services, - std::string_view wanted_service_name, - adb_secure_foreach_service_callback cb) { - initAdbServiceRegistries(); - - for (const auto& service : services) { - auto service_name = service->serviceName(); - auto reg_type = service->regType(); - auto ip = service->ipAddress(); - auto port = service->port(); - - if (wanted_service_name.empty()) { - cb(service_name.c_str(), reg_type.c_str(), ip.c_str(), port); - } else if (service_name == wanted_service_name) { - cb(service_name.c_str(), reg_type.c_str(), ip.c_str(), port); - } - } -} - -// static -bool ResolvedService::connectByServiceName(const ServiceRegistry& services, - const std::string& service_name) { - initAdbServiceRegistries(); - for (const 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; -} - -// static -void ResolvedService::removeDNSService(const char* regType, const char* serviceName) { - D("%s: regType=[%s] serviceName=[%s]", __func__, regType, serviceName); - int index = adb_DNSServiceIndexByName(regType); - ServiceRegistry* services; - switch (index) { - case kADBTransportServiceRefIndex: - services = sAdbTransportServices; - break; - case kADBSecurePairingServiceRefIndex: - services = sAdbSecurePairingServices; - break; - case kADBSecureConnectServiceRefIndex: - services = sAdbSecureConnectServices; - break; - default: - return; - } - - if (services->empty()) { - return; - } - - std::string sName(serviceName); - services->erase(std::remove_if(services->begin(), services->end(), - [&sName](std::unique_ptr& service) { - return (sName == service->serviceName()); - }), - services->end()); -} - -void adb_secure_foreach_pairing_service(const char* service_name, - adb_secure_foreach_service_callback cb) { - ResolvedService::forEachService(*ResolvedService::sAdbSecurePairingServices, 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, 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("%s: sdRef=%p flags=0x%08x errorCode=%u ttl=%u", __func__, sdRef, flags, errorCode, ttl); - std::unique_ptr data( - reinterpret_cast(context)); - // Only resolve the address once. If the address or port changes, we'll just get another - // registration. - data->DestroyServiceRef(); - - if (errorCode != kDNSServiceErr_NoError) { - D("Got error while looking up ipaddr [%u]", errorCode); - return; - } - - if (flags & kDNSServiceFlagsAdd) { - D("Resolved IP address for [%s]. Adding to service registry.", hostname); - auto* ptr = data.release(); - if (!ptr->AddToServiceRegistry(address)) { - data.reset(ptr); - } - } -} - -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_; -}; - -// 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); - ResolvedService::removeDNSService(regtype, serviceName); - } -} - -void init_mdns_transport_discovery_thread(void) { - config_auto_connect_services(); - std::string res; - std::for_each(g_autoconn_whitelist.begin(), g_autoconn_whitelist.end(), [&](const int& i) { - res += kADBDNSServices[i]; - res += ","; - }); - D("mdns auto-connect whitelist: [%s]", res.data()); - - 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::initAdbServiceRegistries(); - std::thread(init_mdns_transport_discovery_thread).detach(); -} - -std::string mdns_check() { - uint32_t daemon_version; - uint32_t sz = sizeof(daemon_version); - - auto dnserr = DNSServiceGetProperty(kDNSServiceProperty_DaemonVersion, &daemon_version, &sz); - std::string result = "ERROR: mdns daemon unavailable"; - if (dnserr != kDNSServiceErr_NoError) { - return result; - } - - result = android::base::StringPrintf("mdns daemon version [%u]", daemon_version); - return result; -} - -std::string mdns_list_discovered_services() { - std::string result; - auto cb = [&](const char* service_name, const char* reg_type, const char* ip_addr, - uint16_t port) { - result += android::base::StringPrintf("%s\t%s\t%s:%u\n", service_name, reg_type, ip_addr, - port); - }; - - ResolvedService::forEachService(*ResolvedService::sAdbTransportServices, "", cb); - ResolvedService::forEachService(*ResolvedService::sAdbSecureConnectServices, "", cb); - ResolvedService::forEachService(*ResolvedService::sAdbSecurePairingServices, "", cb); - return result; -} - -std::optional mdns_get_connect_service_info(std::string_view name) { - CHECK(!name.empty()); - - // only adb server creates these registries - if (!ResolvedService::sAdbTransportServices && !ResolvedService::sAdbSecureConnectServices) { - return std::nullopt; - } - CHECK(ResolvedService::sAdbTransportServices); - CHECK(ResolvedService::sAdbSecureConnectServices); - - auto mdns_instance = mdns::mdns_parse_instance_name(name); - if (!mdns_instance.has_value()) { - D("Failed to parse mDNS name [%s]", name.data()); - return std::nullopt; - } - - std::optional info; - auto cb = [&](const char* service_name, const char* reg_type, const char* ip_addr, - uint16_t port) { info.emplace(service_name, reg_type, ip_addr, port); }; - - std::string reg_type; - if (!mdns_instance->service_name.empty()) { - reg_type = android::base::StringPrintf("%s.%s", mdns_instance->service_name.data(), - mdns_instance->transport_type.data()); - int index = adb_DNSServiceIndexByName(reg_type); - switch (index) { - case kADBTransportServiceRefIndex: - ResolvedService::forEachService(*ResolvedService::sAdbTransportServices, - mdns_instance->instance_name, cb); - break; - case kADBSecureConnectServiceRefIndex: - ResolvedService::forEachService(*ResolvedService::sAdbSecureConnectServices, - mdns_instance->instance_name, cb); - break; - default: - D("Unknown reg_type [%s]", reg_type.data()); - return std::nullopt; - } - return info; - } - - for (const auto& service : - {ResolvedService::sAdbTransportServices, ResolvedService::sAdbSecureConnectServices}) { - ResolvedService::forEachService(*service, name, cb); - if (info.has_value()) { - return info; - } - } - - return std::nullopt; -} - -std::optional mdns_get_pairing_service_info(std::string_view name) { - CHECK(!name.empty()); - - auto mdns_instance = mdns::mdns_parse_instance_name(name); - if (!mdns_instance.has_value()) { - D("Failed to parse mDNS pairing name [%s]", name.data()); - return std::nullopt; - } - - std::optional info; - auto cb = [&](const char* service_name, const char* reg_type, const char* ip_addr, - uint16_t port) { info.emplace(service_name, reg_type, ip_addr, port); }; - - // Verify it's a pairing service if user explicitly inputs it. - if (!mdns_instance->service_name.empty()) { - auto reg_type = android::base::StringPrintf("%s.%s", mdns_instance->service_name.data(), - mdns_instance->transport_type.data()); - int index = adb_DNSServiceIndexByName(reg_type); - switch (index) { - case kADBSecurePairingServiceRefIndex: - break; - default: - D("Not an adb pairing reg_type [%s]", reg_type.data()); - return std::nullopt; - } - } - - ResolvedService::forEachService(*ResolvedService::sAdbSecurePairingServices, name, cb); - return info; -} 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/compression_utils.h b/adb/compression_utils.h deleted file mode 100644 index a74710823ce769edc09db11acf0d3777e60e3d44..0000000000000000000000000000000000000000 --- a/adb/compression_utils.h +++ /dev/null @@ -1,486 +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 - -#include "types.h" - -enum class DecodeResult { - Error, - Done, - NeedInput, - MoreOutput, -}; - -enum class EncodeResult { - Error, - Done, - NeedInput, - MoreOutput, -}; - -struct Decoder { - void Append(Block&& block) { input_buffer_.append(std::move(block)); } - bool Finish() { - bool old = std::exchange(finished_, true); - if (old) { - LOG(FATAL) << "Decoder::Finish called while already finished?"; - return false; - } - return true; - } - - virtual DecodeResult Decode(std::span* output) = 0; - - protected: - Decoder(std::span output_buffer) : output_buffer_(output_buffer) {} - ~Decoder() = default; - - bool finished_ = false; - IOVector input_buffer_; - std::span output_buffer_; -}; - -struct Encoder { - void Append(Block input) { input_buffer_.append(std::move(input)); } - bool Finish() { - bool old = std::exchange(finished_, true); - if (old) { - LOG(FATAL) << "Decoder::Finish called while already finished?"; - return false; - } - return true; - } - - virtual EncodeResult Encode(Block* output) = 0; - - protected: - explicit Encoder(size_t output_block_size) : output_block_size_(output_block_size) {} - ~Encoder() = default; - - const size_t output_block_size_; - bool finished_ = false; - IOVector input_buffer_; -}; - -struct NullDecoder final : public Decoder { - explicit NullDecoder(std::span output_buffer) : Decoder(output_buffer) {} - - DecodeResult Decode(std::span* output) final { - size_t available_out = output_buffer_.size(); - void* p = output_buffer_.data(); - while (available_out > 0 && !input_buffer_.empty()) { - size_t len = std::min(available_out, input_buffer_.front_size()); - p = mempcpy(p, input_buffer_.front_data(), len); - available_out -= len; - input_buffer_.drop_front(len); - } - *output = std::span(output_buffer_.data(), static_cast(p)); - if (input_buffer_.empty()) { - return finished_ ? DecodeResult::Done : DecodeResult::NeedInput; - } - return DecodeResult::MoreOutput; - } -}; - -struct NullEncoder final : public Encoder { - explicit NullEncoder(size_t output_block_size) : Encoder(output_block_size) {} - - EncodeResult Encode(Block* output) final { - output->clear(); - output->resize(output_block_size_); - - size_t available_out = output->size(); - void* p = output->data(); - - while (available_out > 0 && !input_buffer_.empty()) { - size_t len = std::min(available_out, input_buffer_.front_size()); - p = mempcpy(p, input_buffer_.front_data(), len); - available_out -= len; - input_buffer_.drop_front(len); - } - - output->resize(output->size() - available_out); - - if (input_buffer_.empty()) { - return finished_ ? EncodeResult::Done : EncodeResult::NeedInput; - } - return EncodeResult::MoreOutput; - } -}; - -struct BrotliDecoder final : public Decoder { - explicit BrotliDecoder(std::span output_buffer) - : Decoder(output_buffer), - decoder_(BrotliDecoderCreateInstance(nullptr, nullptr, nullptr), - BrotliDecoderDestroyInstance) {} - - DecodeResult Decode(std::span* output) final { - 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: - // We need to wait for ID_DONE from the other end. - return finished_ ? DecodeResult::Done : DecodeResult::NeedInput; - case BROTLI_DECODER_RESULT_ERROR: - return DecodeResult::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 DecodeResult::NeedInput; - case BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT: - return DecodeResult::MoreOutput; - } - } - - private: - std::unique_ptr decoder_; -}; - -struct BrotliEncoder final : public Encoder { - explicit BrotliEncoder(size_t output_block_size) - : Encoder(output_block_size), - output_block_(output_block_size_), - output_bytes_left_(output_block_size_), - encoder_(BrotliEncoderCreateInstance(nullptr, nullptr, nullptr), - BrotliEncoderDestroyInstance) { - BrotliEncoderSetParameter(encoder_.get(), BROTLI_PARAM_QUALITY, 1); - } - - EncodeResult Encode(Block* output) final { - 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() + (output_block_size_ - 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 EncodeResult::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(output_block_size_ - output_bytes_left_); - *output = std::move(output_block_); - return EncodeResult::Done; - } else if (output_bytes_left_ == 0) { - *output = std::move(output_block_); - output_block_.resize(output_block_size_); - output_bytes_left_ = output_block_size_; - return EncodeResult::MoreOutput; - } else if (input_buffer_.empty()) { - return EncodeResult::NeedInput; - } - } - } - - private: - Block output_block_; - size_t output_bytes_left_; - std::unique_ptr encoder_; -}; - -struct LZ4Decoder final : public Decoder { - explicit LZ4Decoder(std::span output_buffer) - : Decoder(output_buffer), decoder_(nullptr, nullptr) { - LZ4F_dctx* dctx; - if (LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION) != 0) { - LOG(FATAL) << "failed to initialize LZ4 decompression context"; - } - decoder_ = std::unique_ptr( - dctx, LZ4F_freeDecompressionContext); - } - - DecodeResult Decode(std::span* output) final { - size_t available_in = input_buffer_.front_size(); - const char* next_in = input_buffer_.front_data(); - - size_t available_out = output_buffer_.size(); - char* next_out = output_buffer_.data(); - - size_t rc = LZ4F_decompress(decoder_.get(), next_out, &available_out, next_in, - &available_in, nullptr); - if (LZ4F_isError(rc)) { - LOG(ERROR) << "LZ4F_decompress failed: " << LZ4F_getErrorName(rc); - return DecodeResult::Error; - } - - input_buffer_.drop_front(available_in); - - if (rc == 0) { - if (!input_buffer_.empty()) { - LOG(ERROR) << "LZ4 stream hit end before reading all data"; - return DecodeResult::Error; - } - lz4_done_ = true; - } - - *output = std::span(output_buffer_.data(), available_out); - - if (finished_) { - return input_buffer_.empty() && lz4_done_ ? DecodeResult::Done - : DecodeResult::MoreOutput; - } - - return DecodeResult::NeedInput; - } - - private: - bool lz4_done_ = false; - std::unique_ptr decoder_; -}; - -struct LZ4Encoder final : public Encoder { - explicit LZ4Encoder(size_t output_block_size) - : Encoder(output_block_size), encoder_(nullptr, nullptr) { - LZ4F_cctx* cctx; - if (LZ4F_createCompressionContext(&cctx, LZ4F_VERSION) != 0) { - LOG(FATAL) << "failed to initialize LZ4 compression context"; - } - encoder_ = std::unique_ptr( - cctx, LZ4F_freeCompressionContext); - Block header(LZ4F_HEADER_SIZE_MAX); - size_t rc = LZ4F_compressBegin(encoder_.get(), header.data(), header.size(), nullptr); - if (LZ4F_isError(rc)) { - LOG(FATAL) << "LZ4F_compressBegin failed: %s", LZ4F_getErrorName(rc); - } - header.resize(rc); - output_buffer_.append(std::move(header)); - } - - // As an optimization, only emit a block if we have an entire output block ready, or we're done. - bool OutputReady() const { - return output_buffer_.size() >= output_block_size_ || lz4_finalized_; - } - - // TODO: Switch the output type to IOVector to remove a copy? - EncodeResult Encode(Block* output) final { - size_t available_in = input_buffer_.front_size(); - const char* next_in = input_buffer_.front_data(); - - // LZ4 makes no guarantees about being able to recover from trying to compress with an - // insufficiently large output buffer. LZ4F_compressBound tells us how much buffer we - // need to compress a given number of bytes, but the smallest value seems to be bigger - // than SYNC_DATA_MAX, so we need to buffer ourselves. - - // Input size chosen to be a local maximum for LZ4F_compressBound (i.e. the block size). - constexpr size_t max_input_size = 65536; - const size_t encode_block_size = LZ4F_compressBound(max_input_size, nullptr); - - if (available_in != 0) { - if (lz4_finalized_) { - LOG(ERROR) << "LZ4Encoder received data after Finish?"; - return EncodeResult::Error; - } - - available_in = std::min(available_in, max_input_size); - - Block encode_block(encode_block_size); - size_t available_out = encode_block.capacity(); - char* next_out = encode_block.data(); - - size_t rc = LZ4F_compressUpdate(encoder_.get(), next_out, available_out, next_in, - available_in, nullptr); - if (LZ4F_isError(rc)) { - LOG(ERROR) << "LZ4F_compressUpdate failed: " << LZ4F_getErrorName(rc); - return EncodeResult::Error; - } - - input_buffer_.drop_front(available_in); - - available_out -= rc; - next_out += rc; - - encode_block.resize(encode_block_size - available_out); - output_buffer_.append(std::move(encode_block)); - } - - if (finished_ && !lz4_finalized_) { - lz4_finalized_ = true; - - Block final_block(encode_block_size + 4); - size_t rc = LZ4F_compressEnd(encoder_.get(), final_block.data(), final_block.size(), - nullptr); - if (LZ4F_isError(rc)) { - LOG(ERROR) << "LZ4F_compressEnd failed: " << LZ4F_getErrorName(rc); - return EncodeResult::Error; - } - - final_block.resize(rc); - output_buffer_.append(std::move(final_block)); - } - - if (OutputReady()) { - size_t len = std::min(output_block_size_, output_buffer_.size()); - *output = output_buffer_.take_front(len).coalesce(); - } else { - output->clear(); - } - - if (lz4_finalized_ && output_buffer_.empty()) { - return EncodeResult::Done; - } else if (OutputReady()) { - return EncodeResult::MoreOutput; - } - return EncodeResult::NeedInput; - } - - private: - bool lz4_finalized_ = false; - std::unique_ptr encoder_; - IOVector output_buffer_; -}; - -struct ZstdDecoder final : public Decoder { - explicit ZstdDecoder(std::span output_buffer) - : Decoder(output_buffer), decoder_(ZSTD_createDStream(), ZSTD_freeDStream) { - if (!decoder_) { - LOG(FATAL) << "failed to initialize Zstd decompression context"; - } - } - - DecodeResult Decode(std::span* output) final { - ZSTD_inBuffer in; - in.src = input_buffer_.front_data(); - in.size = input_buffer_.front_size(); - in.pos = 0; - - ZSTD_outBuffer out; - out.dst = output_buffer_.data(); - // The standard specifies size() as returning size_t, but our current version of - // libc++ returns a signed value instead. - out.size = static_cast(output_buffer_.size()); - out.pos = 0; - - size_t rc = ZSTD_decompressStream(decoder_.get(), &out, &in); - if (ZSTD_isError(rc)) { - LOG(ERROR) << "ZSTD_decompressStream failed: " << ZSTD_getErrorName(rc); - return DecodeResult::Error; - } - - input_buffer_.drop_front(in.pos); - if (rc == 0) { - if (!input_buffer_.empty()) { - LOG(ERROR) << "Zstd stream hit end before reading all data"; - return DecodeResult::Error; - } - zstd_done_ = true; - } - - *output = std::span(output_buffer_.data(), out.pos); - - if (finished_) { - return input_buffer_.empty() && zstd_done_ ? DecodeResult::Done - : DecodeResult::MoreOutput; - } - return DecodeResult::NeedInput; - } - - private: - bool zstd_done_ = false; - std::unique_ptr decoder_; -}; - -struct ZstdEncoder final : public Encoder { - explicit ZstdEncoder(size_t output_block_size) - : Encoder(output_block_size), encoder_(ZSTD_createCStream(), ZSTD_freeCStream) { - if (!encoder_) { - LOG(FATAL) << "failed to initialize Zstd compression context"; - } - ZSTD_CCtx_setParameter(encoder_.get(), ZSTD_c_compressionLevel, 1); - } - - EncodeResult Encode(Block* output) final { - ZSTD_inBuffer in; - in.src = input_buffer_.front_data(); - in.size = input_buffer_.front_size(); - in.pos = 0; - - output->resize(output_block_size_); - - ZSTD_outBuffer out; - out.dst = output->data(); - out.size = static_cast(output->size()); - out.pos = 0; - - ZSTD_EndDirective end_directive = finished_ ? ZSTD_e_end : ZSTD_e_continue; - size_t rc = ZSTD_compressStream2(encoder_.get(), &out, &in, end_directive); - if (ZSTD_isError(rc)) { - LOG(ERROR) << "ZSTD_compressStream2 failed: " << ZSTD_getErrorName(rc); - return EncodeResult::Error; - } - - input_buffer_.drop_front(in.pos); - output->resize(out.pos); - - if (rc == 0) { - // Zstd finished flushing its data. - if (finished_) { - if (!input_buffer_.empty()) { - LOG(ERROR) << "ZSTD_compressStream2 finished early"; - return EncodeResult::Error; - } - return EncodeResult::Done; - } else { - return input_buffer_.empty() ? EncodeResult::NeedInput : EncodeResult::MoreOutput; - } - } else { - return EncodeResult::MoreOutput; - } - } - - private: - std::unique_ptr encoder_; -}; diff --git a/adb/coverage/.gitignore b/adb/coverage/.gitignore deleted file mode 100644 index b6a2582047095a9a3ecaa5aacac17e2e052c5212..0000000000000000000000000000000000000000 --- a/adb/coverage/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/adbd.profdata -/report diff --git a/adb/coverage/gen_coverage.sh b/adb/coverage/gen_coverage.sh deleted file mode 100755 index 43d45f0d8e4f8e9807fd5216ded7e73a76066917..0000000000000000000000000000000000000000 --- a/adb/coverage/gen_coverage.sh +++ /dev/null @@ -1,119 +0,0 @@ -#!/bin/bash - -set -euxo pipefail - -OUTPUT_DIR=$(dirname "$0") -. "$OUTPUT_DIR"/include.sh - -TRACEDIR=`mktemp -d` - -### Make sure we can connect to the device. - -# Get the device's wlan0 address. -IP_ADDR=$(adb shell ip route get 0.0.0.0 oif wlan0 | sed -En -e 's/.*src (\S+)\s.*/\1/p') -REMOTE_PORT=5555 -REMOTE=$IP_ADDR:$REMOTE_PORT -LOCAL_SERIAL=$(adb shell getprop ro.serialno) - -# Check that we can connect to it. -adb disconnect - -TRANSPORT_ID=$(adb transport-id) -adb tcpip $REMOTE_PORT -adb -t $TRANSPORT_ID wait-for-disconnect - -adb connect $REMOTE - -REMOTE_FETCHED_SERIAL=$(adb -s $REMOTE shell getprop ro.serialno) - -if [[ "$LOCAL_SERIAL" != "$REMOTE_FETCHED_SERIAL" ]]; then - echo "Mismatch: local serial = $LOCAL_SERIAL, remote serial = $REMOTE_FETCHED_SERIAL" - exit 1 -fi - -# Back to USB, and make sure adbd is root. -adb -s $REMOTE usb -adb disconnect $REMOTE - -adb wait-for-device root -adb root -adb wait-for-device - -TRANSPORT_ID=$(adb transport-id) -adb usb -adb -t $TRANSPORT_ID wait-for-disconnect - -adb wait-for-device - -### Run the adb unit tests and fetch traces from them. -mkdir "$TRACEDIR"/test_traces -adb shell rm -rf /data/local/tmp/adb_coverage -adb shell mkdir /data/local/tmp/adb_coverage - -for TEST in $ADB_TESTS; do - adb shell LLVM_PROFILE_FILE=/data/local/tmp/adb_coverage/$TEST.profraw /data/nativetest64/$TEST/$TEST - adb pull /data/local/tmp/adb_coverage/$TEST.profraw "$TRACEDIR"/test_traces/ -done - -adb pull /data/local/tmp/adb_coverage "$TRACEDIR"/test_traces - -# Clear logcat and increase the buffer to something ridiculous so we can fetch the pids of adbd later. -adb shell logcat -c -G128M - -# Turn on extremely verbose logging so as to not count debug logging against us. -adb shell setprop persist.adb.trace_mask 1 - -### Run test_device.py over USB. -TRANSPORT_ID=$(adb transport-id) -adb shell killall adbd -adb -t $TRANSPORT_ID wait-for-disconnect - -adb wait-for-device shell rm -rf "/data/misc/trace/*" /data/local/tmp/adb_coverage/ -"$OUTPUT_DIR"/../test_device.py - -# Do a usb reset to exercise the disconnect code. -adb_usbreset -adb wait-for-device - -# Dump traces from the currently running adbd. -adb shell killall -37 adbd - -echo Waiting for adbd to finish dumping traces -sleep 5 - -# Restart adbd in tcp mode. -TRANSPORT_ID=$(adb transport-id) -adb tcpip $REMOTE_PORT -adb -t $TRANSPORT_ID wait-for-disconnect - -adb connect $REMOTE -adb -s $REMOTE wait-for-device - -# Instead of running test_device.py again, which takes forever, do some I/O back and forth instead. -dd if=/dev/zero bs=1024 count=10240 | adb -s $REMOTE raw sink:10485760 -adb -s $REMOTE raw source:10485760 | dd of=/dev/null bs=1024 count=10240 - -# Dump traces again. -adb disconnect $REMOTE -adb shell killall -37 adbd - -echo Waiting for adbd to finish dumping traces -sleep 5 - -adb pull /data/misc/trace "$TRACEDIR"/ -echo Pulled traces to $TRACEDIR - -# Identify which of the trace files are actually adbd, in case something else exited simultaneously. -ADBD_PIDS=$(adb shell "logcat -d -s adbd --format=process | grep 'adbd started' | cut -c 3-7 | tr -d ' ' | sort | uniq") -mkdir "$TRACEDIR"/adbd_traces - -adb shell 'setprop persist.adb.trace_mask 0; killall adbd' - -IFS=$'\n' -for PID in $ADBD_PIDS; do - cp "$TRACEDIR"/trace/clang-$PID-*.profraw "$TRACEDIR"/adbd_traces 2>/dev/null || true -done -unset IFS - -### Merge the traces. -llvm-profdata merge --output="$OUTPUT_DIR"/adbd.profdata "$TRACEDIR"/adbd_traces/* "$TRACEDIR"/test_traces/* diff --git a/adb/coverage/include.sh b/adb/coverage/include.sh deleted file mode 100644 index 45ebc347514b83b82500807c5c7d18ab72dc55db..0000000000000000000000000000000000000000 --- a/adb/coverage/include.sh +++ /dev/null @@ -1,5 +0,0 @@ -ADB_TESTS="adbd_test adb_crypto_test adb_pairing_auth_test adb_pairing_connection_test adb_tls_connection_test" -ADB_TEST_BINARIES="" -for TEST in $ADB_TESTS; do - ADB_TEST_BINARIES="--object=$ANDROID_PRODUCT_OUT/data/nativetest64/$TEST/$TEST $ADB_TEST_BINARIES" -done diff --git a/adb/coverage/report.sh b/adb/coverage/report.sh deleted file mode 100755 index 257310c6adc461a9c72baf536b708f618bfd4550..0000000000000000000000000000000000000000 --- a/adb/coverage/report.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash - -set -euxo pipefail - -OUTPUT_DIR=$(realpath $(dirname "$0")) -. "$OUTPUT_DIR"/include.sh - -rm -rf "$OUTPUT_DIR"/report - -cd $ANDROID_BUILD_TOP -llvm-cov show --instr-profile="$OUTPUT_DIR"/adbd.profdata \ - $ANDROID_PRODUCT_OUT/apex/com.android.adbd/bin/adbd \ - /proc/self/cwd/system/core/adb \ - $ADB_TEST_BINARIES \ - --show-region-summary=false \ - --format=html -o "$OUTPUT_DIR"/report - -llvm-cov report --instr-profile="$OUTPUT_DIR"/adbd.profdata \ - $ANDROID_PRODUCT_OUT/apex/com.android.adbd/bin/adbd \ - /proc/self/cwd/system/core/adb \ - $ADB_TEST_BINARIES \ - --show-region-summary=false diff --git a/adb/coverage/show.sh b/adb/coverage/show.sh deleted file mode 100755 index 3b2faa3046097133de5de05e91c7d536209d1731..0000000000000000000000000000000000000000 --- a/adb/coverage/show.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash - -set -euxo pipefail - -OUTPUT_DIR=$(realpath $(dirname "$0")) -. "$OUTPUT_DIR"/include.sh - -BASE_PATH=/proc/self/cwd/system/core/adb -PATHS="" -if [[ $# == 0 ]]; then - PATHS=$BASE_PATH -else - for arg in "$@"; do - PATHS="$PATHS $BASE_PATH/$arg" - done -fi - -cd $ANDROID_BUILD_TOP -llvm-cov show --instr-profile="$OUTPUT_DIR"/adbd.profdata \ - $ANDROID_PRODUCT_OUT/apex/com.android.adbd/bin/adbd \ - $PATHS \ - $ADB_TEST_BINARIES diff --git a/adb/crypto/Android.bp b/adb/crypto/Android.bp deleted file mode 100644 index c4052c39b412fc6f26d1e28c9622caee2d4216ae..0000000000000000000000000000000000000000 --- a/adb/crypto/Android.bp +++ /dev/null @@ -1,83 +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: [ - "//bootable/recovery/minadbd:__subpackages__", - "//packages/modules/adb:__subpackages__", - "//system/core/adb:__subpackages__", - ], - - host_supported: true, - recovery_available: true, - - shared_libs: [ - "libadb_protos", - "libadb_sysdeps", - "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", - "libadb_sysdeps", - ], -} 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 6d9ee30546b3e2895322026281df53495962c9ce..0000000000000000000000000000000000000000 --- a/adb/crypto/rsa_2048_key.cpp +++ /dev/null @@ -1,69 +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 -#include - -namespace adb { -namespace crypto { - -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(" "); - out->append(sysdeps::GetLoginNameUTF8()); - out->append("@"); - out->append(sysdeps::GetHostNameUTF8()); - 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 b04105545f297751f06861e5fa112f8ed28d7fc3..0000000000000000000000000000000000000000 --- a/adb/crypto/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_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", - "libadb_sysdeps", - ], - - 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 513b8dd8f2f33811e8e5b055bfe747b49eca4b6e..0000000000000000000000000000000000000000 --- a/adb/daemon/file_sync_service.cpp +++ /dev/null @@ -1,859 +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 - -#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 "compression_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_data(borrowed_fd s, unique_fd fd, uint32_t* timestamp, - CompressionType compression) { - syncmsg msg; - Block buffer(SYNC_DATA_MAX); - std::span buffer_span(buffer.data(), buffer.size()); - std::variant - decoder_storage; - Decoder* decoder = nullptr; - - switch (compression) { - case CompressionType::None: - decoder = &decoder_storage.emplace(buffer_span); - break; - - case CompressionType::Brotli: - decoder = &decoder_storage.emplace(buffer_span); - break; - - case CompressionType::LZ4: - decoder = &decoder_storage.emplace(buffer_span); - break; - - case CompressionType::Zstd: - decoder = &decoder_storage.emplace(buffer_span); - break; - - case CompressionType::Any: - LOG(FATAL) << "unexpected CompressionType::Any"; - } - - while (true) { - if (!ReadFdExactly(s, &msg.data, sizeof(msg.data))) return false; - - if (msg.data.id == ID_DONE) { - *timestamp = msg.data.size; - decoder->Finish(); - } else if (msg.data.id == ID_DATA) { - Block block(msg.data.size); - if (!ReadFdExactly(s, block.data(), msg.data.size)) return false; - decoder->Append(std::move(block)); - } else { - SendSyncFail(s, "invalid data message"); - return false; - } - - while (true) { - std::span output; - DecodeResult result = decoder->Decode(&output); - if (result == DecodeResult::Error) { - SendSyncFailErrno(s, "decompress failed"); - return false; - } - - // fd is -1 if the client is pushing with --dry-run. - if (fd != -1) { - if (!WriteFdExactly(fd, output.data(), output.size())) { - SendSyncFailErrno(s, "write failed"); - return false; - } - } - - if (result == DecodeResult::NeedInput) { - break; - } else if (result == DecodeResult::MoreOutput) { - continue; - } else if (result == DecodeResult::Done) { - return true; - } else { - LOG(FATAL) << "invalid DecodeResult: " << static_cast(result); - } - } - } - - __builtin_unreachable(); -} - -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, - CompressionType compression, bool dry_run, std::vector& buffer, - bool do_unlink) { - syncmsg msg; - unique_fd fd; - - if (!dry_run) { - __android_log_security_bswrite(SEC_TAG_ADB_SEND_FILE, path); - fd.reset(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); - } - - int 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)); - } - } - - if (!handle_send_file_data(s, std::move(fd), timestamp, compression)) { - 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, bool dry_run, - 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 (!dry_run) { - 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, CompressionType compression, - bool dry_run, std::vector& buffer) { - // Don't delete files before copying if they are not "regular" or symlinks. - struct stat st; - bool do_unlink = false; - if (!dry_run) { - 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, dry_run, 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) && !dry_run) { - 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, - compression, dry_run, 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, CompressionType::None, 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 dry_run = false; - std::optional compression; - - uint32_t orig_flags = msg.send_v2_setup.flags; - if (msg.send_v2_setup.flags & kSyncFlagBrotli) { - msg.send_v2_setup.flags &= ~kSyncFlagBrotli; - if (compression) { - SendSyncFail(s, android::base::StringPrintf("multiple compression flags received: %d", - orig_flags)); - return false; - } - compression = CompressionType::Brotli; - } - if (msg.send_v2_setup.flags & kSyncFlagLZ4) { - msg.send_v2_setup.flags &= ~kSyncFlagLZ4; - if (compression) { - SendSyncFail(s, android::base::StringPrintf("multiple compression flags received: %d", - orig_flags)); - return false; - } - compression = CompressionType::LZ4; - } - if (msg.send_v2_setup.flags & kSyncFlagZstd) { - msg.send_v2_setup.flags &= ~kSyncFlagZstd; - if (compression) { - SendSyncFail(s, android::base::StringPrintf("multiple compression flags received: %d", - orig_flags)); - return false; - } - compression = CompressionType::Zstd; - } - if (msg.send_v2_setup.flags & kSyncFlagDryRun) { - msg.send_v2_setup.flags &= ~kSyncFlagDryRun; - dry_run = 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, compression.value_or(CompressionType::None), - dry_run, buffer); -} - -static bool recv_impl(borrowed_fd s, const char* path, CompressionType compression, - 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)); - } - - syncmsg msg; - msg.data.id = ID_DATA; - - std::variant - encoder_storage; - Encoder* encoder; - - switch (compression) { - case CompressionType::None: - encoder = &encoder_storage.emplace(SYNC_DATA_MAX); - break; - - case CompressionType::Brotli: - encoder = &encoder_storage.emplace(SYNC_DATA_MAX); - break; - - case CompressionType::LZ4: - encoder = &encoder_storage.emplace(SYNC_DATA_MAX); - break; - - case CompressionType::Zstd: - encoder = &encoder_storage.emplace(SYNC_DATA_MAX); - break; - - case CompressionType::Any: - LOG(FATAL) << "unexpected CompressionType::Any"; - } - - 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; - EncodeResult result = encoder->Encode(&output); - if (result == EncodeResult::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 == EncodeResult::Done) { - sending = false; - break; - } else if (result == EncodeResult::NeedInput) { - break; - } else if (result == EncodeResult::MoreOutput) { - continue; - } - } - } - - 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, CompressionType::None, 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"; - } - - std::optional compression; - uint32_t orig_flags = msg.recv_v2_setup.flags; - if (msg.recv_v2_setup.flags & kSyncFlagBrotli) { - msg.recv_v2_setup.flags &= ~kSyncFlagBrotli; - if (compression) { - SendSyncFail(s, android::base::StringPrintf("multiple compression flags received: %d", - orig_flags)); - return false; - } - compression = CompressionType::Brotli; - } - if (msg.recv_v2_setup.flags & kSyncFlagLZ4) { - msg.recv_v2_setup.flags &= ~kSyncFlagLZ4; - if (compression) { - SendSyncFail(s, android::base::StringPrintf("multiple compression flags received: %d", - orig_flags)); - return false; - } - compression = CompressionType::LZ4; - } - if (msg.recv_v2_setup.flags & kSyncFlagZstd) { - msg.recv_v2_setup.flags &= ~kSyncFlagZstd; - if (compression) { - SendSyncFail(s, android::base::StringPrintf("multiple compression flags received: %d", - orig_flags)); - return false; - } - compression = CompressionType::Zstd; - } - - 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, compression.value_or(CompressionType::None), 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 adae9f7f46ef437dcbbc57bc27444d24692d0867..0000000000000000000000000000000000000000 --- a/adb/daemon/jdwp_service.cpp +++ /dev/null @@ -1,537 +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 - -#if !defined(__ANDROID_RECOVERY__) -#define TRACE_TAG JDWP - -#include "sysdeps.h" - -#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 "app_processes.pb.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 - **/ - -enum class TrackerKind { - kJdwp, - kApp, -}; - -static void jdwp_process_event(int socket, unsigned events, void* _proc); -static void jdwp_process_list_updated(void); -static void app_process_list_updated(void); - -struct JdwpProcess; -static auto& _jdwp_list = *new std::list>(); - -struct JdwpProcess { - JdwpProcess(unique_fd socket, ProcessInfo process) { - CHECK(process.pid != 0); - - this->socket = socket; - this->process = process; - 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; - ProcessInfo process; - fdevent* fde = nullptr; - - std::vector out_fds; -}; - -// Populate the list of processes for "track-jdwp" service. -static size_t jdwp_process_list(char* buffer, size_t bufferlen) { - std::string temp; - - for (auto& proc : _jdwp_list) { - if (!proc->process.debuggable) continue; - std::string next = std::to_string(proc->process.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(); -} - -// Populate the list of processes for "track-app" service. -// The list is a protobuf message in the binary format for efficiency. -static size_t app_process_list(char* buffer, size_t bufferlen) { - adb::proto::AppProcesses output; // result that's guaranteed to fit in the given buffer - adb::proto::AppProcesses temp; // temporary result that may be longer than the given buffer - std::string serialized_message; - - for (auto& proc : _jdwp_list) { - if (!proc->process.debuggable && !proc->process.profileable) continue; - auto* entry = temp.add_process(); - entry->set_pid(proc->process.pid); - entry->set_debuggable(proc->process.debuggable); - entry->set_profileable(proc->process.profileable); - entry->set_architecture(proc->process.arch_name, proc->process.arch_name_length); - temp.SerializeToString(&serialized_message); - if (serialized_message.size() > bufferlen) { - D("truncating app process list (max len = %zu)", bufferlen); - break; - } - output = temp; - } - output.SerializeToString(&serialized_message); - memcpy(buffer, serialized_message.data(), serialized_message.length()); - return serialized_message.length(); -} - -// Populate the list of processes for either "track-jdwp" or "track-app" services, -// depending on the given kind. -static size_t process_list(TrackerKind kind, char* buffer, size_t bufferlen) { - switch (kind) { - case TrackerKind::kJdwp: - return jdwp_process_list(buffer, bufferlen); - case TrackerKind::kApp: - return app_process_list(buffer, bufferlen); - } -} - -static size_t process_list_msg(TrackerKind kind, 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 = process_list(kind, 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 %" PRId64, proc->process.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 %" PRId64 " failed: %s", proc->process.pid, - strerror(errno)); - goto CloseProcess; - } - - D("sent file descriptor %d to JDWP process %" PRId64, fd, proc->process.pid); - - proc->out_fds.pop_back(); - if (proc->out_fds.empty()) { - fdevent_del(proc->fde, FDE_WRITE); - } - } - - return; - -CloseProcess: - bool debuggable = proc->process.debuggable; - bool profileable = proc->process.profileable; - proc->RemoveFromList(); - if (debuggable) jdwp_process_list_updated(); - if (debuggable || profileable) app_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) { - // Don't allow JDWP connection to a non-debuggable process. - if (!proc->process.debuggable) continue; - if (proc->process.pid == static_cast(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 { - TrackerKind kind; - bool need_initial; - - explicit JdwpTracker(TrackerKind k, bool initial) : kind(k), need_initial(initial) {} -}; - -static auto& _jdwp_trackers = *new std::vector>(); - -static void process_list_updated(TrackerKind kind) { - std::string data; - const int kMaxLength = kind == TrackerKind::kJdwp ? 1024 : 2048; - data.resize(kMaxLength); - data.resize(process_list_msg(kind, &data[0], data.size())); - - for (auto& t : _jdwp_trackers) { - if (t->kind == kind && 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_process_list_updated(void) { - process_list_updated(TrackerKind::kJdwp); -} - -static void app_process_list_updated(void) { - process_list_updated(TrackerKind::kApp); -} - -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(process_list_msg(t->kind, &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; -} - -static asocket* create_process_tracker_service_socket(TrackerKind kind) { - auto t = std::make_unique(kind, true); - 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; - - asocket* result = t.get(); - - _jdwp_trackers.emplace_back(std::move(t)); - - return result; -} - -asocket* create_jdwp_tracker_service_socket() { - return create_process_tracker_service_socket(TrackerKind::kJdwp); -} - -asocket* create_app_tracker_service_socket() { - return create_process_tracker_service_socket(TrackerKind::kApp); -} - -int init_jdwp(void) { - std::thread([]() { - adb_thread_setname("jdwp control"); - adbconnection_listen([](int fd, ProcessInfo process) { - LOG(INFO) << "jdwp connection from " << process.pid; - fdevent_run_on_main_thread([fd, process] { - unique_fd ufd(fd); - auto proc = std::make_unique(std::move(ufd), process); - if (!proc) { - LOG(FATAL) << "failed to allocate JdwpProcess"; - } - _jdwp_list.emplace_back(std::move(proc)); - if (process.debuggable) jdwp_process_list_updated(); - if (process.debuggable || process.profileable) app_process_list_updated(); - }); - }); - }).detach(); - return 0; -} - -#else // !defined(__ANDROID_RECOVERY) -#include "adb.h" - -asocket* create_jdwp_service_socket(void) { - return nullptr; -} - -unique_fd create_jdwp_connection_fd(int pid) { - return {}; -} - -asocket* create_app_tracker_service_socket() { - return nullptr; -} - -asocket* create_jdwp_tracker_service_socket() { - return nullptr; -} - -int init_jdwp() { - return 0; -} - -#endif /* defined(__ANDROID_RECOVERY__) */ -#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 8c41c5e2d3806b4078ca2620d17fc61dd757a099..0000000000000000000000000000000000000000 --- a/adb/daemon/main.cpp +++ /dev/null @@ -1,340 +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"; - } - } - } -} -#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); - } - - LOG(INFO) << "adbd started"; - - 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 c1e766eba424a2487867010f8846780ba975acef..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 += static_cast('0' + val); - } else if (val < 36) { - ret += static_cast('A' + (val - 10)); - } else { - ret += static_cast('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 a9d1fe8442e0e2c7f3adb1e0d78d8fb5bb901faa..0000000000000000000000000000000000000000 --- a/adb/daemon/services.cpp +++ /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. - */ - -#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 (name == "track-app") { - return create_app_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 dbca4adb61e2d12d8e92b018ef370c16f3f9ae7e..0000000000000000000000000000000000000000 --- a/adb/daemon/shell_service.cpp +++ /dev/null @@ -1,917 +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. - auto poll_finished = [](int events) { - // Don't return failure until we've read out all of the fd's incoming data. - return (events & POLLIN) == 0 && - (events & (POLLHUP | POLLRDHUP | POLLERR | POLLNVAL)) != 0; - }; - - if (poll_finished(stdinout_pfd.revents)) { - return &stdinout_sfd_; - } - - if (poll_finished(stderr_pfd.revents)) { - return &stderr_sfd_; - } - - if (poll_finished(protocol_pfd.revents)) { - 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_local.cpp b/adb/daemon/transport_local.cpp deleted file mode 100644 index 9e0b88737dbc9d8973f1128dc846da31a92a8afc..0000000000000000000000000000000000000000 --- a/adb/daemon/transport_local.cpp +++ /dev/null @@ -1,117 +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" - -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"); -} - -unique_fd adb_listen(std::string_view addr, std::string* error) { - return unique_fd{socket_spec_listen(addr, error, nullptr)}; -} - -void local_init(const std::string& addr) { -#if !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 -} - -int init_socket_transport(atransport* t, unique_fd fd, int adb_port, int local) { - t->type = kTransportLocal; - auto fd_connection = std::make_unique(std::move(fd)); - t->SetConnection(std::make_unique(std::move(fd_connection))); - return 0; -} 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 ed5056e68e85a244d1fc938c6b2b99c721d7c657..0000000000000000000000000000000000000000 --- a/adb/fastdeploy/proto/ApkEntry.proto +++ /dev/null @@ -1,25 +0,0 @@ -syntax = "proto3"; - -package com.android.fastdeploy; - -option java_package = "com.android.fastdeploy"; -option java_outer_classname = "ApkEntryProto"; -option java_multiple_files = true; - -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 70cb9b3a6db46f51d2c8779d10d066f0aca5963c..0000000000000000000000000000000000000000 --- a/adb/fdevent/fdevent.cpp +++ /dev/null @@ -1,265 +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" - -#if !defined(__linux__) -#include "fdevent_poll.h" -#endif - -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 bb3af746fc7e6f24a42d6d9ef2c4714c7411c199..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*) = 0; - virtual void Unregister(fdevent*) = 0; - - 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 21c1ba093c829fd28a15f65694447ab0197130eb..0000000000000000000000000000000000000000 --- a/adb/fdevent/fdevent_poll.cpp +++ /dev/null @@ -1,217 +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"; - } -} - -void fdevent_context_poll::Register(fdevent*) {} - -void fdevent_context_poll::Unregister(fdevent*) {} diff --git a/adb/fdevent/fdevent_poll.h b/adb/fdevent/fdevent_poll.h deleted file mode 100644 index 8803e3ec91cb1755b26aad414ecb3fa0dd83e90d..0000000000000000000000000000000000000000 --- a/adb/fdevent/fdevent_poll.h +++ /dev/null @@ -1,66 +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 Register(fdevent* fde) final; - virtual void Unregister(fdevent* fde) final; - - 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 fcbf181dc000c2ca0f1f8a481f49858d6ee5fbe4..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 placeholder 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() { - // placeholder 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 5234c20ae82d25800187706fe9bdea8d601e57ce..0000000000000000000000000000000000000000 --- a/adb/file_sync_protocol.h +++ /dev/null @@ -1,144 +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, - kSyncFlagLZ4 = 2, - kSyncFlagZstd = 4, - kSyncFlagDryRun = 0x8000'0000U, -}; - -enum class CompressionType { - None, - Any, - Brotli, - LZ4, - Zstd, -}; - -// 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 29ae060dbda454e90d1ba3f5ca4413159f02ac37..0000000000000000000000000000000000000000 --- a/adb/libs/adbconnection/Android.bp +++ /dev/null @@ -1,66 +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__", - "//packages/modules/adb/apex:__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", - }, - darwin: { enabled: false }, - }, - 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 7e16148350c0813ec4890d470667db4d48d145db..0000000000000000000000000000000000000000 --- a/adb/libs/adbconnection/adbconnection_client.cpp +++ /dev/null @@ -1,184 +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 - -#include "adbconnection/process_info.h" - -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; - std::optional profileable; - std::optional architecture; - - 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.debuggable; - break; - - case AdbConnectionClientInfoType::profileable: - if (profileable) { - LOG(ERROR) << "multiple profileable entries in AdbConnectionClientInfo, ignoring"; - continue; - } - profileable = info->data.profileable; - break; - - case AdbConnectionClientInfoType::architecture: - if (architecture) { - LOG(ERROR) << "multiple architecture entries in AdbConnectionClientInfo, ignoring"; - continue; - } - architecture = std::string(info->data.architecture.name, info->data.architecture.size); - break; - } - } - - if (!pid) { - LOG(ERROR) << "AdbConnectionClientInfo missing required field pid"; - return nullptr; - } - - if (!debuggable) { - LOG(ERROR) << "AdbConnectionClientInfo missing required field debuggable"; - return nullptr; - } - - if (!profileable) { - LOG(ERROR) << "AdbConnectionClientInfo missing required field profileable"; - return nullptr; - } - - if (!architecture) { - LOG(ERROR) << "AdbConnectionClientInfo missing required field architecture"; - 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) { - if (errno == ECONNREFUSED) { - // On userdebug devices, every Java process is debuggable, so if adbd is explicitly turned - // off, this would spew enormous amounts of red-herring errors. - LOG(DEBUG) << "failed to connect to jdwp control socket, adbd not running?"; - } else { - 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; - } - - ProcessInfo process(*pid, *debuggable, *profileable, *architecture); - rc = TEMP_FAILURE_RETRY(write(ctx->control_socket_.get(), &process, sizeof(process))); - if (rc != sizeof(process)) { - PLOG(ERROR) << "failed to send JDWP process info 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 aac9615edc3e500636c21887e22366c16b99512b..0000000000000000000000000000000000000000 --- a/adb/libs/adbconnection/adbconnection_server.cpp +++ /dev/null @@ -1,128 +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 - -#include "adbconnection/process_info.h" - -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, ProcessInfo process)) { - 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"; - } - - ProcessInfo process; - int rc = TEMP_FAILURE_RETRY(recv(it->get(), &process, sizeof(process), MSG_DONTWAIT)); - if (rc != sizeof(process)) { - LOG(ERROR) << "received data of incorrect size from JDWP client: read " << rc - << ", expected " << sizeof(process); - } else { - callback(it->release(), process); - } - - 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 a74cd36e02df2b3a37bd6a3cb12a57983181bfb9..0000000000000000000000000000000000000000 --- a/adb/libs/adbconnection/include/adbconnection/client.h +++ /dev/null @@ -1,63 +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, - profileable, - architecture, -}; - -struct AdbConnectionClientInfo { - AdbConnectionClientInfoType type; - union { - uint64_t pid; - bool debuggable; - bool profileable; - struct { - const char* name; - size_t size; - } architecture; - } data; -}; - -// Construct a context and connect to adbd. -// Returns null if we fail to connect to adbd. -// Note this is an apex interface as it's loaded by ART. -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/process_info.h b/adb/libs/adbconnection/include/adbconnection/process_info.h deleted file mode 100644 index d22669978e3cff1da153c3dea306ecfc31973b0c..0000000000000000000000000000000000000000 --- a/adb/libs/adbconnection/include/adbconnection/process_info.h +++ /dev/null @@ -1,39 +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 - -struct ProcessInfo { - static constexpr size_t kMaxArchNameLength = 16; - - uint64_t pid; - bool debuggable; - bool profileable; - int32_t arch_name_length; // length of architecture name in bytes - char arch_name[kMaxArchNameLength]; // ISA name, e.g., "arm64" - - ProcessInfo() : pid(0), debuggable(false), profileable(false), arch_name_length(0) {} - - ProcessInfo(uint64_t pid, bool dbg, bool prof, const std::string& arch) - : pid(pid), debuggable(dbg), profileable(prof) { - arch_name_length = std::min(arch.size(), kMaxArchNameLength); - memcpy(arch_name, arch.data(), arch_name_length); - } -}; diff --git a/adb/libs/adbconnection/include/adbconnection/server.h b/adb/libs/adbconnection/include/adbconnection/server.h deleted file mode 100644 index b1059bad49665d74a808974d0b39f92eeb53a9ea..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 - -#include "adbconnection/process_info.h" - -// Note this is NOT an apex interface as it's linked only into adbd. -void adbconnection_listen(void (*callback)(int fd, ProcessInfo process)); 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 806879dd6939e0de11ea4d5ff2a37042bcf3552c..0000000000000000000000000000000000000000 --- a/adb/pairing_auth/Android.bp +++ /dev/null @@ -1,84 +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__", - "//packages/modules/adb:__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 1886885911a4e95a74dbe9cd0f496eaa1082f210..0000000000000000000000000000000000000000 --- a/adb/pairing_connection/Android.bp +++ /dev/null @@ -1,189 +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__", - "//frameworks/base/services:__subpackages__", - "//packages/modules/adb:__subpackages__", - "//system/core/adb:__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__", - "//frameworks/base/services:__subpackages__", - "//packages/modules/adb:__subpackages__", - "//system/core/adb:__subpackages__", - ], - - 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 86b66aaee424dab278749a2bec7360c3ffcdd53a..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, DISABLED_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 ef97208a56a2fcc8e4dee80bb611042c6bdbb495..0000000000000000000000000000000000000000 --- a/adb/proto/Android.bp +++ /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. - -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: [ - "//packages/modules/adb:__subpackages__", - "//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", - ], -} - -cc_defaults { - name: "libapp_processes_protos_defaults", - cflags: [ - "-Wall", - "-Wextra", - "-Wthread-safety", - "-Werror", - ], - - compile_multilib: "both", - - srcs: [ - "app_processes.proto", - ], - target: { - windows: { - compile_multilib: "first", - enabled: true, - }, - }, - - visibility: [ - "//packages/modules/adb:__subpackages__", - "//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", - - apex_available: [ - "com.android.adbd", - "test_com.android.adbd", - ], -} - -cc_library { - name: "libapp_processes_protos_lite", - defaults: ["libapp_processes_protos_defaults"], - - apex_available: ["//apex_available:platform"], - - proto: { - export_proto_headers: true, - type: "lite", - }, - - host_supported: true, - recovery_available: true, -} - -cc_library_host_static { - name: "libapp_processes_protos_full", - defaults: ["libapp_processes_protos_defaults"], - - proto: { - export_proto_headers: true, - type: "full", - }, -} 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/app_processes.proto b/adb/proto/app_processes.proto deleted file mode 100644 index 118364591727b23fd62b70793e4a2db7fe070ba2..0000000000000000000000000000000000000000 --- a/adb/proto/app_processes.proto +++ /dev/null @@ -1,33 +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 = "AppProcessesProto"; - -package adb.proto; - -message ProcessEntry { - int64 pid = 1; - bool debuggable = 2; - bool profileable = 3; - string architecture = 4; -} - -message AppProcesses { - repeated ProcessEntry process = 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 19a9030f2c0f3407e81c26c80425429a1e92a726..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 -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); -} - -static void wait_service(unique_fd fd, std::string serial, TransportId transport_id, - std::string spec) { - std::vector components = android::base::Split(spec, "-"); - if (components.size() < 2) { - SendFail(fd, "short wait-for-: " + spec); - return; - } - - TransportType transport_type; - if (components[0] == "local") { - transport_type = kTransportLocal; - } else if (components[0] == "usb") { - transport_type = kTransportUsb; - } else if (components[0] == "any") { - transport_type = kTransportAny; - } else { - SendFail(fd, "bad wait-for- transport: " + spec); - return; - } - - std::vector states; - for (size_t i = 1; i < components.size(); ++i) { - if (components[i] == "device") { - states.push_back(kCsDevice); - } else if (components[i] == "recovery") { - states.push_back(kCsRecovery); - } else if (components[i] == "rescue") { - states.push_back(kCsRescue); - } else if (components[i] == "sideload") { - states.push_back(kCsSideload); - } else if (components[i] == "bootloader") { - states.push_back(kCsBootloader); - } else if (components[i] == "any") { - states.push_back(kCsAny); - } else if (components[i] == "disconnect") { - states.push_back(kCsOffline); - } else { - SendFail(fd, "bad wait-for- state: " + spec); - return; - } - } - - while (true) { - bool is_ambiguous = false; - std::string error = "unknown error"; - atransport* t = - acquire_one_transport(transport_type, !serial.empty() ? serial.c_str() : nullptr, - transport_id, &is_ambiguous, &error); - - for (const auto& state : states) { - if (state == kCsOffline) { - // Special case for wait-for-disconnect: - // We want to wait for USB devices to completely disappear, but TCP devices can - // go into the offline state, since we automatically reconnect. - if (!t) { - SendOkay(fd); - return; - } else if (!t->GetUsbHandle()) { - SendOkay(fd); - return; - } - } else { - if (t && (state == kCsAny || state == t->GetConnectionState())) { - SendOkay(fd); - return; - } - } - } - - if (is_ambiguous) { - SendFail(fd, error); - return; - } - - // Sleep before retrying. - adb_pollfd pfd = {.fd = fd.get(), .events = POLLIN}; - if (adb_poll(&pfd, 1, 100) != 0) { - // The other end of the socket is closed, probably because the - // client terminated. Bail out. - SendFail(fd, error); - return; - } - } -} -#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::string spec(name); - unique_fd fd = - create_service_thread("wait", std::bind(wait_service, std::placeholders::_1, - std::string(serial), transport_id, spec)); - 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 0623204892370a7c44d7432665446f79c88a9d35..0000000000000000000000000000000000000000 --- a/adb/socket.h +++ /dev/null @@ -1,126 +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); - -#if ADB_HOST -void connect_to_smartsocket(asocket *s); -#endif - -// 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 5cad70d09490d8cd3989da4c728e93393b1e71d4..0000000000000000000000000000000000000000 --- a/adb/socket_spec.cpp +++ /dev/null @@ -1,461 +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 "adb_wifi.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 (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 - // Check if the address is an mdns service we can connect to. - if (auto mdns_info = mdns_get_connect_service_info(address.substr(4)); - mdns_info != std::nullopt) { - fd->reset(network_connect(mdns_info->addr, mdns_info->port, SOCK_STREAM, 0, error)); - if (fd->get() != -1) { - // TODO(joshuaduong): We still show the ip address for the serial. Change it to - // use the mdns instance name, so we can adjust to address changes on - // reconnects. - port_value = mdns_info->port; - if (serial) { - *serial = android::base::StringPrintf("%s.%s", - mdns_info->service_name.c_str(), - mdns_info->service_type.c_str()); - } - } - } else { - 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 e83c34c45e412eef5f3516a81ffe59d462d0f596..0000000000000000000000000000000000000000 --- a/adb/socket_spec_test.cpp +++ /dev/null @@ -1,187 +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_failure) { - std::string hostname, error, serial; - int port; - EXPECT_FALSE(parse_tcp_socket_spec("sneakernet:5037", &hostname, &port, &serial, &error)); - EXPECT_TRUE(error.find("sneakernet") != std::string::npos); -} - -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_connect_failure) { - std::string error, serial; - int port; - unique_fd client_fd; - EXPECT_FALSE(socket_spec_connect(&client_fd, "tcp:", &port, &serial, &error)); - EXPECT_FALSE(socket_spec_connect(&client_fd, "acceptfd:", &port, &serial, &error)); - EXPECT_FALSE(socket_spec_connect(&client_fd, "vsock:", &port, &serial, &error)); - EXPECT_FALSE(socket_spec_connect(&client_fd, "vsock:x", &port, &serial, &error)); - EXPECT_FALSE(socket_spec_connect(&client_fd, "vsock:5", &port, &serial, &error)); - EXPECT_FALSE(socket_spec_connect(&client_fd, "vsock:5:x", &port, &serial, &error)); - EXPECT_FALSE(socket_spec_connect(&client_fd, "sneakernet:", &port, &serial, &error)); -} - -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); - } -} - -TEST(socket_spec, is_socket_spec) { - EXPECT_TRUE(is_socket_spec("tcp:blah")); - EXPECT_TRUE(is_socket_spec("acceptfd:blah")); - EXPECT_TRUE(is_socket_spec("local:blah")); - EXPECT_TRUE(is_socket_spec("localreserved:blah")); -} - -TEST(socket_spec, is_local_socket_spec) { - EXPECT_TRUE(is_local_socket_spec("local:blah")); - EXPECT_TRUE(is_local_socket_spec("tcp:localhost")); - EXPECT_FALSE(is_local_socket_spec("tcp:www.google.com")); -} 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 33b9524182ff0c9a3521a6981dc826a3d53588fb..0000000000000000000000000000000000000000 --- a/adb/sockets.cpp +++ /dev/null @@ -1,920 +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); -} - -#if ADB_HOST -/* 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; -} - -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 - -static int smart_socket_enqueue(asocket* s, apacket::payload_type data) { - std::string_view service; - std::string_view serial; - TransportId transport_id = 0; - TransportType type = kTransportAny; - - 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)); - - 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; - } - - 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 them 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); -} -#endif - -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 7326ab13728f0726463e34b734e4ee41c64367b4..0000000000000000000000000000000000000000 --- a/adb/sysdeps.h +++ /dev/null @@ -1,723 +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(); -} - -static inline int cast_handle_to_int(int fd) { - return fd; -} - -// 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/env.cpp b/adb/sysdeps/env.cpp deleted file mode 100644 index 40587280c199b2ddad2c7497f1a1975ca503d947..0000000000000000000000000000000000000000 --- a/adb/sysdeps/env.cpp +++ /dev/null @@ -1,122 +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 "sysdeps/env.h" - -#ifdef _WIN32 -#include -#include -#endif // _WIN32 - -#include - -namespace adb { -namespace sysdeps { - -std::optional GetEnvironmentVariable(std::string_view var) { - if (var.empty()) { - return std::nullopt; - } - -#ifdef _WIN32 - constexpr size_t kMaxEnvVarSize = 32767; - wchar_t wbuf[kMaxEnvVarSize]; - std::wstring wvar; - if (!android::base::UTF8ToWide(var.data(), &wvar)) { - return std::nullopt; - } - - auto sz = ::GetEnvironmentVariableW(wvar.data(), wbuf, sizeof(wbuf)); - if (sz == 0) { - return std::nullopt; - } - - std::string val; - if (!android::base::WideToUTF8(wbuf, &val)) { - return std::nullopt; - } - - return std::make_optional(val); -#else // !_WIN32 - const char* val = getenv(var.data()); - if (val == nullptr) { - return std::nullopt; - } - - return std::make_optional(std::string(val)); -#endif -} - -#ifdef _WIN32 -constexpr char kHostNameEnvVar[] = "COMPUTERNAME"; -constexpr char kUserNameEnvVar[] = "USERNAME"; -#else -constexpr char kHostNameEnvVar[] = "HOSTNAME"; -constexpr char kUserNameEnvVar[] = "LOGNAME"; -#endif - -std::string GetHostNameUTF8() { - const auto hostName = GetEnvironmentVariable(kHostNameEnvVar); - if (hostName && !hostName->empty()) { - return *hostName; - } - -#ifdef _WIN32 - wchar_t wbuf[MAX_COMPUTERNAME_LENGTH + 1]; - DWORD size = sizeof(wbuf); - if (!GetComputerNameW(wbuf, &size) || size == 0) { - return ""; - } - - std::string name; - if (!android::base::WideToUTF8(wbuf, &name)) { - return ""; - } - - return name; -#else // !_WIN32 - char buf[256]; - return (gethostname(buf, sizeof(buf)) == -1) ? "" : buf; -#endif // _WIN32 -} - -std::string GetLoginNameUTF8() { - const auto userName = GetEnvironmentVariable(kUserNameEnvVar); - if (userName && !userName->empty()) { - return *userName; - } - -#ifdef _WIN32 - wchar_t wbuf[UNLEN + 1]; - DWORD size = sizeof(wbuf); - if (!GetUserNameW(wbuf, &size) || size == 0) { - return ""; - } - - std::string login; - if (!android::base::WideToUTF8(wbuf, &login)) { - return ""; - } - - return login; -#else // !_WIN32 - const char* login = getlogin(); - return login ? login : ""; -#endif // _WIN32 -} - -} // namespace sysdeps -} // namespace adb diff --git a/adb/sysdeps/env.h b/adb/sysdeps/env.h deleted file mode 100644 index b39b675cbcc3b77e4cd659326c96629e300ff3a0..0000000000000000000000000000000000000000 --- a/adb/sysdeps/env.h +++ /dev/null @@ -1,35 +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 - -namespace adb { -namespace sysdeps { - -// Attempts to retrieve the environment variable value for |var|. Returns std::nullopt -// if unset. -std::optional GetEnvironmentVariableUTF8(std::string_view var); - -// Gets the host name of the system. Returns empty string on failure. -std::string GetHostNameUTF8(); -// Gets the current login user. Returns empty string on failure. -std::string GetLoginNameUTF8(); - -} // namespace sysdeps -} // namespace adb diff --git a/adb/sysdeps/errno.cpp b/adb/sysdeps/errno.cpp deleted file mode 100644 index e6af68b4859fe38e1098cd6ace0b85adcd06b0bf..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 architectures). -#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__) -#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 217a6b7f8957324d9cef25aeddad947a6799dcdb..0000000000000000000000000000000000000000 --- a/adb/sysdeps_win32.cpp +++ /dev/null @@ -1,2932 +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); -} - -#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 a32d8757d978f45c9e0b5468c2faedbf274f07bb..0000000000000000000000000000000000000000 --- a/adb/test_adb.py +++ /dev/null @@ -1,812 +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 string -import struct -import subprocess -import sys -import threading -import time -import unittest -import warnings -from importlib import util - -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) - -"""Use 'adb mdns check' to see if mdns discovery is available.""" -def is_adb_mdns_available(): - with adb_server() as server_port: - output = subprocess.check_output(["adb", "-P", str(server_port), - "mdns", "check"]).strip() - return output.startswith(b"mdns daemon version") - -"""Check if we have zeroconf python library installed""" -def is_zeroconf_installed(): - zeroconf_spec = util.find_spec("zeroconf") - return zeroconf_spec is not None - -@contextlib.contextmanager -def zeroconf_context(ipversion): - from zeroconf import Zeroconf - """Context manager for a zeroconf instance - - This creates a zeroconf instance and returns it. - """ - - try: - zeroconf = Zeroconf(ip_version=ipversion) - yield zeroconf - finally: - zeroconf.close() - -@contextlib.contextmanager -def zeroconf_register_service(zeroconf_ctx, info): - """Context manager for a zeroconf service - - Registers a service and unregisters it on cleanup. Returns the ServiceInfo - supplied. - """ - - try: - zeroconf_ctx.register_service(info) - yield info - finally: - zeroconf_ctx.unregister_service(info) - -@contextlib.contextmanager -def zeroconf_register_services(zeroconf_ctx, infos): - """Context manager for multiple zeroconf services - - Registers all services given and unregisters all on cleanup. Returns the ServiceInfo - list supplied. - """ - - try: - for info in infos: - zeroconf_ctx.register_service(info) - yield infos - finally: - for info in infos: - zeroconf_ctx.unregister_service(info) - -"""Should match the service names listed in adb_mdns.h""" -class MdnsTest: - """Tests for adb mdns.""" - @staticmethod - def _mdns_services(port): - output = subprocess.check_output(["adb", "-P", str(port), "mdns", "services"]) - return [x.split("\t") for x in output.decode("utf8").strip().splitlines()[1:]] - - @staticmethod - 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:]] - - - class Base(unittest.TestCase): - @contextlib.contextmanager - def _adb_mdns_connect(self, server_port, mdns_instance, serial, should_connect): - """Context manager for an ADB connection. - - This automatically disconnects when done with the connection. - """ - - output = subprocess.check_output(["adb", "-P", str(server_port), "connect", mdns_instance]) - if should_connect: - self.assertEqual(output.strip(), "connected to {}".format(serial).encode("utf8")) - else: - self.assertTrue(output.startswith("failed to resolve host: '{}'" - .format(mdns_instance).encode("utf8"))) - - try: - yield - finally: - # Perform best-effort disconnection. Discard the output. - subprocess.Popen(["adb", "disconnect", serial], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE).communicate() - - - @unittest.skipIf(not is_zeroconf_installed(), "zeroconf library not installed") - def test_mdns_services_register_unregister(self): - """Ensure that `adb mdns services` correctly adds and removes a service - """ - from zeroconf import IPVersion, ServiceInfo - - with adb_server() as server_port: - output = subprocess.check_output(["adb", "-P", str(server_port), - "mdns", "services"]).strip() - self.assertTrue(output.startswith(b"List of discovered mdns services")) - - """TODO(joshuaduong): Add ipv6 tests once we have it working in adb""" - """Register/Unregister a service""" - with zeroconf_context(IPVersion.V4Only) as zc: - serv_instance = "my_fake_test_service" - serv_type = "_" + self.service_name + "._tcp." - serv_ipaddr = socket.inet_aton("1.2.3.4") - serv_port = 12345 - service_info = ServiceInfo( - serv_type + "local.", - name=serv_instance + "." + serv_type + "local.", - addresses=[serv_ipaddr], - port=serv_port) - with zeroconf_register_service(zc, service_info) as info: - """Give adb some time to register the service""" - time.sleep(1) - self.assertTrue(any((serv_instance in line and serv_type in line) - for line in MdnsTest._mdns_services(server_port))) - - """Give adb some time to unregister the service""" - time.sleep(1) - self.assertFalse(any((serv_instance in line and serv_type in line) - for line in MdnsTest._mdns_services(server_port))) - - @unittest.skipIf(not is_zeroconf_installed(), "zeroconf library not installed") - def test_mdns_services_register_unregister_multiple(self): - """Ensure that `adb mdns services` correctly adds and removes multiple services - """ - from zeroconf import IPVersion, ServiceInfo - - with adb_server() as server_port: - output = subprocess.check_output(["adb", "-P", str(server_port), - "mdns", "services"]).strip() - self.assertTrue(output.startswith(b"List of discovered mdns services")) - - """TODO(joshuaduong): Add ipv6 tests once we have it working in adb""" - """Register/Unregister a service""" - with zeroconf_context(IPVersion.V4Only) as zc: - srvs = { - 'mdns_name': ["testservice0", "testservice1", "testservice2"], - 'mdns_type': "_" + self.service_name + "._tcp.", - 'ipaddr': [ - socket.inet_aton("192.168.0.1"), - socket.inet_aton("10.0.0.255"), - socket.inet_aton("172.16.1.100")], - 'port': [10000, 20000, 65535]} - srv_infos = [] - for i in range(len(srvs['mdns_name'])): - srv_infos.append(ServiceInfo( - srvs['mdns_type'] + "local.", - name=srvs['mdns_name'][i] + "." + srvs['mdns_type'] + "local.", - addresses=[srvs['ipaddr'][i]], - port=srvs['port'][i])) - - """ Register all devices, then unregister""" - with zeroconf_register_services(zc, srv_infos) as infos: - """Give adb some time to register the service""" - time.sleep(1) - for i in range(len(srvs['mdns_name'])): - self.assertTrue(any((srvs['mdns_name'][i] in line and srvs['mdns_type'] in line) - for line in MdnsTest._mdns_services(server_port))) - - """Give adb some time to unregister the service""" - time.sleep(1) - for i in range(len(srvs['mdns_name'])): - self.assertFalse(any((srvs['mdns_name'][i] in line and srvs['mdns_type'] in line) - for line in MdnsTest._mdns_services(server_port))) - - @unittest.skipIf(not is_zeroconf_installed(), "zeroconf library not installed") - def test_mdns_connect(self): - """Ensure that `adb connect` by mdns instance name works (for non-pairing services) - """ - from zeroconf import IPVersion, ServiceInfo - - with adb_server() as server_port: - with zeroconf_context(IPVersion.V4Only) as zc: - serv_instance = "fakeadbd-" + ''.join( - random.choice(string.ascii_letters) for i in range(4)) - serv_type = "_" + self.service_name + "._tcp." - serv_ipaddr = socket.inet_aton("127.0.0.1") - should_connect = self.service_name != "adb-tls-pairing" - with fake_adbd() as (port, _): - service_info = ServiceInfo( - serv_type + "local.", - name=serv_instance + "." + serv_type + "local.", - addresses=[serv_ipaddr], - port=port) - with zeroconf_register_service(zc, service_info) as info: - """Give adb some time to register the service""" - time.sleep(1) - self.assertTrue(any((serv_instance in line and serv_type in line) - for line in MdnsTest._mdns_services(server_port))) - full_name = '.'.join([serv_instance, serv_type]) - with self._adb_mdns_connect(server_port, serv_instance, full_name, - should_connect): - if should_connect: - self.assertEqual(MdnsTest._devices(server_port), - [[full_name, "device"]]) - - """Give adb some time to unregister the service""" - time.sleep(1) - self.assertFalse(any((serv_instance in line and serv_type in line) - for line in MdnsTest._mdns_services(server_port))) - - -@unittest.skipIf(not is_adb_mdns_available(), "mdns feature not available") -class MdnsTestAdb(MdnsTest.Base): - service_name = "adb" - - -@unittest.skipIf(not is_adb_mdns_available(), "mdns feature not available") -class MdnsTestAdbTlsConnect(MdnsTest.Base): - service_name = "adb-tls-connect" - - -@unittest.skipIf(not is_adb_mdns_available(), "mdns feature not available") -class MdnsTestAdbTlsPairing(MdnsTest.Base): - service_name = "adb-tls-pairing" - - -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 a92d4a711df1481e2aa621a61a238f0ab9bcacdc..0000000000000000000000000000000000000000 --- a/adb/test_device.py +++ /dev/null @@ -1,1785 +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): - device = adb.get_device() - - -class AbbTest(DeviceTest): - def test_smoke(self): - abb = subprocess.run(['adb', 'abb'], capture_output=True) - cmd = subprocess.run(['adb', 'shell', 'cmd'], capture_output=True) - - # abb squashes all failures to 1. - self.assertEqual(abb.returncode == 0, cmd.returncode == 0) - self.assertEqual(abb.stdout, cmd.stdout) - self.assertEqual(abb.stderr, cmd.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: - class Base(DeviceTest): - SCRATCH_DIR = '/data/local/tmp' - DEVICE_TEMP_FILE = SCRATCH_DIR + '/adb_test_file' - DEVICE_TEMP_DIR = SCRATCH_DIR + '/adb_test_dir' - - def setUp(self): - self.previous_env = os.environ.get("ADB_COMPRESSION") - os.environ["ADB_COMPRESSION"] = self.compression - - def tearDown(self): - if self.previous_env is None: - del os.environ["ADB_COMPRESSION"] - else: - os.environ["ADB_COMPRESSION"] = self.previous_env - - 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_push_sync_multiple(self): - """Sync multiple host directories 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.shell(['mkdir', '-p', device_dir]) - - host_paths = [os.path.join(temp_dir, x.base_name) for x in temp_files] - device.push(host_paths, 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_push_dry_run_nonexistent_file(self): - """Push with dry run.""" - - for file_size in [8, 1024 * 1024]: - try: - device_dir = posixpath.join(self.DEVICE_TEMP_DIR, 'push_dry_run') - device_file = posixpath.join(device_dir, 'file') - - self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR]) - self.device.shell(['mkdir', '-p', device_dir]) - - host_dir = tempfile.mkdtemp() - host_file = posixpath.join(host_dir, 'file') - - with open(host_file, "w") as f: - f.write('x' * file_size) - - self.device._simple_call(['push', '-n', host_file, device_file]) - rc, _, _ = self.device.shell_nocheck(['[', '-e', device_file, ']']) - self.assertNotEqual(0, rc) - - self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR]) - finally: - if host_dir is not None: - shutil.rmtree(host_dir) - - def test_push_dry_run_existent_file(self): - """Push with dry run.""" - - for file_size in [8, 1024 * 1024]: - try: - device_dir = posixpath.join(self.DEVICE_TEMP_DIR, 'push_dry_run') - device_file = posixpath.join(device_dir, 'file') - - self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR]) - self.device.shell(['mkdir', '-p', device_dir]) - self.device.shell(['echo', 'foo', '>', device_file]) - - host_dir = tempfile.mkdtemp() - host_file = posixpath.join(host_dir, 'file') - - with open(host_file, "w") as f: - f.write('x' * file_size) - - self.device._simple_call(['push', '-n', host_file, device_file]) - stdout, stderr = self.device.shell(['cat', device_file]) - self.assertEqual(stdout.strip(), "foo") - - self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR]) - finally: - if host_dir is not None: - shutil.rmtree(host_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 FileOperationsTestUncompressed(FileOperationsTest.Base): - compression = "none" - - -class FileOperationsTestBrotli(FileOperationsTest.Base): - compression = "brotli" - - -class FileOperationsTestLZ4(FileOperationsTest.Base): - compression = "lz4" - - -class FileOperationsTestZstd(FileOperationsTest.Base): - compression = "zstd" - - -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 1e0054808177a581fc8051fd57e0b80936829216..0000000000000000000000000000000000000000 --- a/adb/tls/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_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__", - "//packages/modules/adb:__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 a7af53cee08d761089091433199bc6b46c70780b..0000000000000000000000000000000000000000 --- a/adb/tools/Android.bp +++ /dev/null @@ -1,59 +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", - ], - }, -} - -cc_binary_host { - name: "adb_usbreset", - - defaults: ["adb_defaults"], - - srcs: [ - "adb_usbreset.cpp", - ], - - static_libs: [ - "libbase", - "libusb", - ], - - stl: "libc++_static", - - dist: { - targets: [ - "sdk", - ], - }, -} diff --git a/adb/tools/adb_usbreset.cpp b/adb/tools/adb_usbreset.cpp deleted file mode 100644 index 6f141bd9229b269b99fe7345a4c9af1c3069a788..0000000000000000000000000000000000000000 --- a/adb/tools/adb_usbreset.cpp +++ /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. - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -struct AllDevices {}; -struct SingleDevice {}; -struct Serial { - std::string_view serial; -}; - -using DeviceSelection = std::variant; - -[[noreturn]] static void Usage(int rc) { - fprintf(stderr, "usage: [ANDROID_SERIAL=SERIAL] usbreset [-d] [-s SERIAL]\n"); - fprintf(stderr, "\t-a --all\t\tReset all connected devices\n"); - fprintf(stderr, "\t-d --device\t\tReset the single connected device\n"); - fprintf(stderr, "\t-s --serial\t\tReset device with specified serial\n"); - exit(rc); -} - -static void SetOption(DeviceSelection* out, DeviceSelection in) { - if (!std::get_if(out)) { - printf("error: multiple device selection options provided\n"); - Usage(1); - } - - *out = in; -} - -static __attribute__((format(printf, 2, 3))) void PrintLibusbError(int err, const char* fmt, ...) { - va_list args; - va_start(args, fmt); - vprintf(fmt, args); - vprintf(fmt, args); - va_end(args); - - printf(": %s", libusb_strerror(static_cast(err))); -} - -static bool IsAdbInterface(const libusb_interface_descriptor* desc) { - return desc->bInterfaceClass == 0xFF && desc->bInterfaceSubClass == 0x42 && - desc->bInterfaceProtocol == 0x1; -} - -int main(int argc, char** argv) { - std::variant selection; - - static constexpr struct option long_opts[] = { - {"all", 0, 0, 'a'}, {"help", 0, 0, 'h'}, {"serial", required_argument, 0, 's'}, - {"device", 0, 0, 'd'}, {0, 0, 0, 0}, - }; - - int opt; - while ((opt = getopt_long(argc, argv, "adhs:", long_opts, nullptr)) != -1) { - if (opt == 'h') { - Usage(0); - } else if (opt == 'a') { - SetOption(&selection, AllDevices{}); - } else if (opt == 's') { - SetOption(&selection, Serial{optarg}); - } else if (opt == 'd') { - SetOption(&selection, Serial{optarg}); - } else { - errx(1, "unknown option: '%c'", opt); - } - } - - if (std::get_if(&selection)) { - const char* env = getenv("ANDROID_SERIAL"); - if (env) { - SetOption(&selection, Serial{env}); - } else { - fprintf(stderr, "adb_usbreset: no device specified\n"); - Usage(1); - } - } - - libusb_context* ctx; - int rc = libusb_init(&ctx); - if (rc != LIBUSB_SUCCESS) { - PrintLibusbError(rc, "error: failed to initialize libusb"); - exit(1); - } - - libusb_device** device_list; - ssize_t device_count = libusb_get_device_list(ctx, &device_list); - if (device_count < 0) { - PrintLibusbError(device_count, "error: failed to list devices"); - exit(1); - } - - std::vector> selected_devices; - for (int i = 0; i < device_count; ++i) { - libusb_device* device = device_list[i]; - libusb_device_descriptor device_desc; - - // Always succeeds for LIBUSB_API_VERSION >= 0x01000102. - libusb_get_device_descriptor(device, &device_desc); - static_assert(LIBUSB_API_VERSION >= 0x01000102); - - libusb_config_descriptor* config_desc; - rc = libusb_get_active_config_descriptor(device, &config_desc); - if (rc != 0) { - PrintLibusbError(rc, "warning: failed to get config descriptor"); - continue; - } - - bool found_adb_interface = false; - for (int i = 0; i < config_desc->bNumInterfaces; ++i) { - if (IsAdbInterface(&config_desc->interface[i].altsetting[0])) { - found_adb_interface = true; - break; - } - } - - if (found_adb_interface) { - libusb_device_handle* device_handle; - rc = libusb_open(device, &device_handle); - if (rc != 0) { - PrintLibusbError(rc, "warning: failed to open device"); - continue; - } - - char buf[128]; - rc = libusb_get_string_descriptor_ascii(device_handle, device_desc.iSerialNumber, - reinterpret_cast(buf), - sizeof(buf)); - - if (rc < 0) { - PrintLibusbError(rc, "warning: failed to get device serial"); - continue; - } - - std::string serial(buf, buf + rc); - if (auto s = std::get_if(&selection)) { - if (s->serial == serial) { - selected_devices.push_back(std::make_pair(std::move(serial), device_handle)); - } - } else { - selected_devices.push_back(std::make_pair(std::move(serial), device_handle)); - } - } - } - - if (selected_devices.empty()) { - errx(1, "no devices match criteria"); - } else if (std::get_if(&selection) && selected_devices.size() != 1) { - errx(1, "more than 1 device connected"); - } - - bool success = true; - for (auto& [serial, device_handle] : selected_devices) { - rc = libusb_reset_device(device_handle); - // libusb_reset_device will try to restore the previous state, and will return - // LIBUSB_ERROR_NOT_FOUND if it can't. - if (rc == 0 || rc == LIBUSB_ERROR_NOT_FOUND) { - printf("%s: successfully reset\n", serial.c_str()); - } else { - PrintLibusbError(rc, "%s: failed to reset", serial.c_str()); - success = false; - } - } - - return !success; -} 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 93b4618342b605f8df46a017ebf694baaede01c2..0000000000000000000000000000000000000000 --- a/adb/transport.cpp +++ /dev/null @@ -1,1542 +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 kFeatureTrackApp = "track_app"; -const char* const kFeatureSendRecv2 = "sendrecv_v2"; -const char* const kFeatureSendRecv2Brotli = "sendrecv_v2_brotli"; -const char* const kFeatureSendRecv2LZ4 = "sendrecv_v2_lz4"; -const char* const kFeatureSendRecv2Zstd = "sendrecv_v2_zstd"; -const char* const kFeatureSendRecv2DryRunSend = "sendrecv_v2_dry_run_send"; - -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 = 3s; - static constexpr const size_t kMaxAttempts = 20; - - // 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()); - - int osh = cast_handle_to_int(adb_get_os_handle(fd_)); -#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); -} - -#if ADB_HOST -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(); -} -#endif - -atransport::~atransport() { -#if ADB_HOST - // If the connection callback had not been run before, run it now. - SetConnectionEstablished(false); -#endif -} - -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() { - static const android::base::NoDestructor features([] { - return FeatureSet{ - kFeatureShell2, - kFeatureCmd, - kFeatureStat2, - kFeatureLs2, - kFeatureFixedPushMkdir, - kFeatureApex, - kFeatureAbb, - kFeatureFixedPushSymlinkTimestamp, - kFeatureAbbExec, - kFeatureRemountShell, - kFeatureTrackApp, - kFeatureSendRecv2, - kFeatureSendRecv2Brotli, - kFeatureSendRecv2LZ4, - kFeatureSendRecv2Zstd, - kFeatureSendRecv2DryRunSend, - // 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(); - } - - return android::base::Split(features_string, ","); -} - -template -static bool contains(const Range& r, const Value& v) { - return std::find(std::begin(r), std::end(r), v) != std::end(r); -} - -bool CanUseFeature(const FeatureSet& feature_set, const std::string& feature) { - return contains(feature_set, feature) && contains(supported_features(), feature); -} - -bool atransport::has_feature(const std::string& feature) const { - return contains(features_, feature); -} - -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(); -} - -#if ADB_HOST -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); -} - -// 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 - -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(); - -#if ADB_HOST - auto waitable = t->connection_waitable(); -#endif - register_transport(t); - - if (local == 1) { - // Do not wait for emulator transports. - return true; - } - -#if ADB_HOST - if (!waitable->WaitForConnection(std::chrono::seconds(10))) { - if (error) *error = ETIMEDOUT; - return false; - } - - if (t->GetConnectionState() == kCsUnauthorized) { - if (error) *error = EPERM; - return false; - } -#endif - - 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(); - } - } - reconnect_handler.CheckForKicked(); -} - -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); -} - -// 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(); - } - - return Key(); -} - -void atransport::ResetKeys() { - keys_.clear(); -} -#endif diff --git a/adb/transport.h b/adb/transport.h deleted file mode 100644 index d59be59c69663398eb1a85c454611698f2f7d0fe..0000000000000000000000000000000000000000 --- a/adb/transport.h +++ /dev/null @@ -1,502 +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" - -// Even though the feature set is used as a set, we only have a dozen or two -// of available features at any moment. Vector works much better in terms of -// both memory usage and performance for these sizes. -using FeatureSet = std::vector; - -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 `track-app` service reporting debuggable/profileable apps. -extern const char* const kFeatureTrackApp; -// adbd supports version 2 of send/recv. -extern const char* const kFeatureSendRecv2; -// adbd supports brotli for send/recv v2. -extern const char* const kFeatureSendRecv2Brotli; -// adbd supports LZ4 for send/recv v2. -extern const char* const kFeatureSendRecv2LZ4; -// adbd supports Zstd for send/recv v2. -extern const char* const kFeatureSendRecv2Zstd; -// adbd supports dry-run send for send/recv v2. -extern const char* const kFeatureSendRecv2DryRunSend; - -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_(nullptr), - reconnect_(std::move(reconnect)) { -#if ADB_HOST - connection_waitable_ = std::make_shared(); -#endif - - // 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(); - -#if ADB_HOST - // 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(); -#endif - - 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 - -#if ADB_HOST - // A sharable object that can be used to wait for the atransport's - // connection to be established. - std::shared_ptr connection_waitable_; -#endif - - // 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); - -#if ADB_HOST -atransport* find_transport(const char* serial); - -void kick_all_tcp_devices(); -#endif - -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_test.cpp b/adb/transport_test.cpp deleted file mode 100644 index 8579ff4c2edac2e8231e7ddc1b8bd6f258787df2..0000000000000000000000000000000000000000 --- a/adb/transport_test.cpp +++ /dev/null @@ -1,187 +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_LE(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); -} - -#if ADB_HOST -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")); - } -} -#endif diff --git a/adb/types.cpp b/adb/types.cpp deleted file mode 100644 index 9cdf32b9320d9796cd0655ddb28e4bf74eb56f1a..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 620aa8eb737e27b889ca1233ece1415d5560c4b3..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_[start_index_].data() + begin_offset_; - } - - size_type front_size() const { - if (chain_.empty()) { - return 0; - } - - return chain_[start_index_].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 41fa1db254fa6db90430e36413f2b3d49cfae3be..0000000000000000000000000000000000000000 --- a/adb/types_test.cpp +++ /dev/null @@ -1,136 +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()); -} - -TEST(IOVector, drop_front) { - IOVector vec; - - vec.append(create_block('x', 2)); - vec.append(create_block('y', 1000)); - ASSERT_EQ(2U, vec.front_size()); - ASSERT_EQ(1002U, vec.size()); - - vec.drop_front(1); - ASSERT_EQ(1U, vec.front_size()); - ASSERT_EQ(1001U, vec.size()); - - vec.drop_front(1); - ASSERT_EQ(1000U, vec.front_size()); - ASSERT_EQ(1000U, vec.size()); -}