summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
l---------adb/.clang-format1
-rw-r--r--adb/Android.bp821
-rw-r--r--adb/MODULE_LICENSE_APACHE20
-rw-r--r--adb/NOTICE191
-rw-r--r--adb/OVERVIEW.TXT135
-rw-r--r--adb/OWNERS2
-rw-r--r--adb/SERVICES.TXT255
-rw-r--r--adb/SOCKET-ACTIVATION.txt42
-rw-r--r--adb/SYNC.TXT80
-rw-r--r--adb/adb.bash499
-rw-r--r--adb/adb.cpp1359
-rw-r--r--adb/adb.h254
-rw-r--r--adb/adb_auth.h70
-rw-r--r--adb/adb_integration_test_adb.xml29
-rw-r--r--adb/adb_integration_test_device.xml29
-rw-r--r--adb/adb_io.cpp189
-rw-r--r--adb/adb_io.h78
-rw-r--r--adb/adb_io_test.cpp156
-rw-r--r--adb/adb_listeners.cpp237
-rw-r--r--adb/adb_listeners.h46
-rw-r--r--adb/adb_listeners_test.cpp166
-rw-r--r--adb/adb_mdns.h92
-rw-r--r--adb/adb_test.xml37
-rw-r--r--adb/adb_trace.cpp197
-rw-r--r--adb/adb_trace.h62
-rw-r--r--adb/adb_unique_fd.cpp28
-rw-r--r--adb/adb_unique_fd.h39
-rw-r--r--adb/adb_utils.cpp380
-rw-r--r--adb/adb_utils.h129
-rw-r--r--adb/adb_utils_test.cpp235
-rw-r--r--adb/adb_wifi.h37
-rw-r--r--adb/apex/Android.bp55
-rw-r--r--adb/apex/adbd.rc6
-rw-r--r--adb/apex/apex_manifest.json4
-rw-r--r--adb/apex/com.android.adbd.avbpubkeybin1032 -> 0 bytes
-rw-r--r--adb/apex/com.android.adbd.pem51
-rw-r--r--adb/apex/com.android.adbd.pk8bin2374 -> 0 bytes
-rw-r--r--adb/apex/com.android.adbd.x509.pem35
-rw-r--r--adb/apex/test_apex_manifest.json4
-rwxr-xr-xadb/benchmark_device.py156
-rw-r--r--adb/brotli_utils.h144
-rw-r--r--adb/bugreport_test.cpp466
-rw-r--r--adb/client/adb_client.cpp416
-rw-r--r--adb/client/adb_client.h105
-rw-r--r--adb/client/adb_install.cpp995
-rw-r--r--adb/client/adb_install.h28
-rw-r--r--adb/client/adb_wifi.cpp246
-rw-r--r--adb/client/auth.cpp557
-rw-r--r--adb/client/bugreport.cpp286
-rw-r--r--adb/client/bugreport.h50
-rw-r--r--adb/client/commandline.cpp2066
-rw-r--r--adb/client/commandline.h133
-rw-r--r--adb/client/console.cpp181
-rw-r--r--adb/client/fastdeploy.cpp357
-rw-r--r--adb/client/fastdeploy.h39
-rw-r--r--adb/client/fastdeploycallbacks.cpp71
-rw-r--r--adb/client/fastdeploycallbacks.h22
-rw-r--r--adb/client/file_sync_client.cpp1650
-rw-r--r--adb/client/file_sync_client.h29
-rw-r--r--adb/client/incremental.cpp239
-rw-r--r--adb/client/incremental.h37
-rw-r--r--adb/client/incremental_server.cpp716
-rw-r--r--adb/client/incremental_server.h26
-rw-r--r--adb/client/incremental_utils.cpp366
-rw-r--r--adb/client/incremental_utils.h48
-rw-r--r--adb/client/line_printer.cpp138
-rw-r--r--adb/client/line_printer.h53
-rw-r--r--adb/client/main.cpp226
-rw-r--r--adb/client/pairing/pairing_client.cpp177
-rw-r--r--adb/client/pairing/pairing_client.h68
-rw-r--r--adb/client/pairing/tests/pairing_connection_test.cpp473
-rw-r--r--adb/client/pairing/tests/pairing_server.cpp426
-rw-r--r--adb/client/pairing/tests/pairing_server.h70
-rw-r--r--adb/client/transport_mdns.cpp547
-rw-r--r--adb/client/transport_usb.cpp212
-rw-r--r--adb/client/usb.h70
-rw-r--r--adb/client/usb_dispatch.cpp70
-rw-r--r--adb/client/usb_libusb.cpp638
-rw-r--r--adb/client/usb_linux.cpp632
-rw-r--r--adb/client/usb_osx.cpp592
-rw-r--r--adb/client/usb_windows.cpp621
-rw-r--r--adb/crypto/Android.bp80
-rw-r--r--adb/crypto/include/adb/crypto/key.h46
-rw-r--r--adb/crypto/include/adb/crypto/rsa_2048_key.h34
-rw-r--r--adb/crypto/include/adb/crypto/x509_generator.h31
-rw-r--r--adb/crypto/key.cpp47
-rw-r--r--adb/crypto/rsa_2048_key.cpp87
-rw-r--r--adb/crypto/tests/Android.bp41
-rw-r--r--adb/crypto/tests/key_test.cpp70
-rw-r--r--adb/crypto/tests/rsa_2048_key_test.cpp73
-rw-r--r--adb/crypto/tests/x509_generator_test.cpp45
-rw-r--r--adb/crypto/x509_generator.cpp123
-rw-r--r--adb/daemon/abb.cpp114
-rw-r--r--adb/daemon/abb_service.cpp90
-rw-r--r--adb/daemon/adb_wifi.cpp229
-rw-r--r--adb/daemon/auth.cpp382
-rw-r--r--adb/daemon/file_sync_service.cpp816
-rw-r--r--adb/daemon/file_sync_service.h21
-rw-r--r--adb/daemon/framebuffer_service.cpp187
-rw-r--r--adb/daemon/framebuffer_service.h23
-rw-r--r--adb/daemon/jdwp_service.cpp438
-rw-r--r--adb/daemon/logging.cpp89
-rw-r--r--adb/daemon/logging.h33
-rw-r--r--adb/daemon/main.cpp344
-rw-r--r--adb/daemon/mdns.cpp219
-rw-r--r--adb/daemon/mdns.h27
-rw-r--r--adb/daemon/restart_service.cpp72
-rw-r--r--adb/daemon/restart_service.h26
-rw-r--r--adb/daemon/services.cpp335
-rw-r--r--adb/daemon/shell_service.cpp911
-rw-r--r--adb/daemon/shell_service.h55
-rw-r--r--adb/daemon/shell_service_test.cpp320
-rw-r--r--adb/daemon/transport_qemu.cpp144
-rw-r--r--adb/daemon/usb.cpp767
-rw-r--r--adb/daemon/usb_ffs.cpp321
-rw-r--r--adb/daemon/usb_ffs.h22
-rw-r--r--adb/fastdeploy/Android.bp89
-rw-r--r--adb/fastdeploy/AndroidManifest.xml29
-rw-r--r--adb/fastdeploy/AndroidTest.xml40
-rw-r--r--adb/fastdeploy/OWNERS1
-rwxr-xr-xadb/fastdeploy/deployagent/deployagent.sh4
-rw-r--r--adb/fastdeploy/deployagent/src/com/android/fastdeploy/ApkArchive.java193
-rw-r--r--adb/fastdeploy/deployagent/src/com/android/fastdeploy/DeployAgent.java337
-rw-r--r--adb/fastdeploy/deployagent/src/com/android/fastdeploy/PatchFormatException.java35
-rw-r--r--adb/fastdeploy/deployagent/src/com/android/fastdeploy/PatchUtils.java74
-rw-r--r--adb/fastdeploy/deployagent/test/com/android/fastdeploy/ApkArchiveTest.java74
-rw-r--r--adb/fastdeploy/deployagent/test/com/android/fastdeploy/FastDeployTest.java89
-rw-r--r--adb/fastdeploy/deploypatchgenerator/apk_archive.cpp417
-rw-r--r--adb/fastdeploy/deploypatchgenerator/apk_archive.h80
-rw-r--r--adb/fastdeploy/deploypatchgenerator/apk_archive_test.cpp73
-rw-r--r--adb/fastdeploy/deploypatchgenerator/deploy_patch_generator.cpp255
-rw-r--r--adb/fastdeploy/deploypatchgenerator/deploy_patch_generator.h111
-rw-r--r--adb/fastdeploy/deploypatchgenerator/deploy_patch_generator_test.cpp88
-rw-r--r--adb/fastdeploy/deploypatchgenerator/patch_utils.cpp109
-rw-r--r--adb/fastdeploy/deploypatchgenerator/patch_utils.h57
-rw-r--r--adb/fastdeploy/deploypatchgenerator/patch_utils_test.cpp144
-rw-r--r--adb/fastdeploy/proto/ApkEntry.proto26
-rw-r--r--adb/fastdeploy/testdata/helloworld5.apkbin1998764 -> 0 bytes
-rw-r--r--adb/fastdeploy/testdata/helloworld7.apkbin1998764 -> 0 bytes
-rw-r--r--adb/fastdeploy/testdata/rotating_cube-metadata-release.data8
-rw-r--r--adb/fastdeploy/testdata/rotating_cube-release.apkbin1340423 -> 0 bytes
-rw-r--r--adb/fastdeploy/testdata/sample.apkbin2093557 -> 0 bytes
-rw-r--r--adb/fastdeploy/testdata/sample.cdbin49390 -> 0 bytes
-rw-r--r--adb/fdevent/fdevent.cpp262
-rw-r--r--adb/fdevent/fdevent.h160
-rw-r--r--adb/fdevent/fdevent_epoll.cpp200
-rw-r--r--adb/fdevent/fdevent_epoll.h56
-rw-r--r--adb/fdevent/fdevent_poll.cpp213
-rw-r--r--adb/fdevent/fdevent_poll.h63
-rw-r--r--adb/fdevent/fdevent_test.cpp321
-rw-r--r--adb/fdevent/fdevent_test.h99
-rw-r--r--adb/file_sync_protocol.h133
l---------adb/libs/.clang-format1
l---------adb/libs/adbconnection/.clang-format1
-rw-r--r--adb/libs/adbconnection/Android.bp64
-rw-r--r--adb/libs/adbconnection/adbconnection_client.cpp148
-rw-r--r--adb/libs/adbconnection/adbconnection_server.cpp129
-rw-r--r--adb/libs/adbconnection/include/adbconnection/client.h55
-rw-r--r--adb/libs/adbconnection/include/adbconnection/server.h26
-rw-r--r--adb/libs/adbconnection/libadbconnection_client.map.txt25
-rw-r--r--adb/libs/libadbd_fs/Android.bp30
-rw-r--r--adb/libs/libadbd_fs/adbd_fs.cpp30
-rw-r--r--adb/libs/libadbd_fs/include/adbd_fs.h26
-rw-r--r--adb/libs/libadbd_fs/libadbd_fs.map.txt6
-rw-r--r--adb/mdns_test.cpp107
-rw-r--r--adb/pairing_auth/Android.bp83
-rw-r--r--adb/pairing_auth/aes_128_gcm.cpp91
-rw-r--r--adb/pairing_auth/include/adb/pairing/aes_128_gcm.h63
-rw-r--r--adb/pairing_auth/include/adb/pairing/pairing_auth.h186
-rw-r--r--adb/pairing_auth/libadb_pairing_auth.map.txt15
-rw-r--r--adb/pairing_auth/pairing_auth.cpp300
-rw-r--r--adb/pairing_auth/tests/Android.bp38
-rw-r--r--adb/pairing_auth/tests/aes_128_gcm_test.cpp62
-rw-r--r--adb/pairing_auth/tests/pairing_auth_test.cpp330
-rw-r--r--adb/pairing_connection/Android.bp188
-rw-r--r--adb/pairing_connection/include/adb/pairing/pairing_connection.h130
-rw-r--r--adb/pairing_connection/include/adb/pairing/pairing_server.h111
-rw-r--r--adb/pairing_connection/internal/constants.h34
-rw-r--r--adb/pairing_connection/libadb_pairing_connection.map.txt10
-rw-r--r--adb/pairing_connection/libadb_pairing_server.map.txt10
-rw-r--r--adb/pairing_connection/pairing_connection.cpp491
-rw-r--r--adb/pairing_connection/pairing_server.cpp466
-rw-r--r--adb/pairing_connection/tests/Android.bp47
-rw-r--r--adb/pairing_connection/tests/pairing_client.cpp201
-rw-r--r--adb/pairing_connection/tests/pairing_client.h68
-rw-r--r--adb/pairing_connection/tests/pairing_connection_test.cpp500
-rw-r--r--adb/proto/Android.bp73
-rw-r--r--adb/proto/adb_known_hosts.proto32
-rw-r--r--adb/proto/jarjar-rules.txt1
-rw-r--r--adb/proto/key_type.proto26
-rw-r--r--adb/proto/pairing.proto30
-rw-r--r--adb/protocol.txt298
-rw-r--r--adb/security_log_tags.h28
-rw-r--r--adb/services.cpp272
-rw-r--r--adb/services.h32
-rw-r--r--adb/shell_protocol.h118
-rw-r--r--adb/shell_service_protocol.cpp62
-rw-r--r--adb/shell_service_protocol_test.cpp198
-rw-r--r--adb/socket.h123
-rw-r--r--adb/socket_spec.cpp449
-rw-r--r--adb/socket_spec.h35
-rw-r--r--adb/socket_spec_test.cpp154
-rw-r--r--adb/socket_test.cpp386
-rw-r--r--adb/sockets.cpp935
-rw-r--r--adb/sockets.diabin2333 -> 0 bytes
-rw-r--r--adb/sysdeps.h719
-rw-r--r--adb/sysdeps/chrono.h21
-rw-r--r--adb/sysdeps/errno.cpp96
-rw-r--r--adb/sysdeps/errno.h30
-rw-r--r--adb/sysdeps/network.h22
-rw-r--r--adb/sysdeps/posix/network.cpp152
-rw-r--r--adb/sysdeps/stat.h63
-rw-r--r--adb/sysdeps/stat_test.cpp65
-rw-r--r--adb/sysdeps/uio.h43
-rw-r--r--adb/sysdeps/vm_sockets.h49
-rw-r--r--adb/sysdeps/win32/errno.cpp95
-rw-r--r--adb/sysdeps/win32/errno_test.cpp51
-rw-r--r--adb/sysdeps/win32/stat.cpp66
-rw-r--r--adb/sysdeps_test.cpp253
-rw-r--r--adb/sysdeps_unix.cpp92
-rw-r--r--adb/sysdeps_win32.cpp2981
-rw-r--r--adb/sysdeps_win32_test.cpp170
-rwxr-xr-xadb/test_adb.py587
-rwxr-xr-xadb/test_device.py1678
-rw-r--r--adb/tls/Android.bp72
-rw-r--r--adb/tls/adb_ca_list.cpp136
-rw-r--r--adb/tls/include/adb/tls/adb_ca_list.h47
-rw-r--r--adb/tls/include/adb/tls/tls_connection.h126
-rw-r--r--adb/tls/tests/Android.bp42
-rw-r--r--adb/tls/tests/adb_ca_list_test.cpp163
-rw-r--r--adb/tls/tests/tls_connection_test.cpp608
-rw-r--r--adb/tls/tls_connection.cpp394
-rw-r--r--adb/tools/Android.bp36
-rw-r--r--adb/tools/check_ms_os_desc.cpp264
-rwxr-xr-xadb/trace.sh17
-rw-r--r--adb/transport.cpp1534
-rw-r--r--adb/transport.h477
-rw-r--r--adb/transport_benchmark.cpp194
-rw-r--r--adb/transport_fd.cpp241
-rw-r--r--adb/transport_local.cpp389
-rw-r--r--adb/transport_test.cpp185
-rw-r--r--adb/types.cpp204
-rw-r--r--adb/types.h358
-rw-r--r--adb/types_test.cpp119
-rw-r--r--base/Android.bp2
-rw-r--r--init/lmkd_service.cpp2
-rw-r--r--init/reboot.cpp54
-rw-r--r--init/service_list.h1
-rw-r--r--init/test_utils/service_utils.cpp2
-rw-r--r--libstats/pull/Android.bp110
-rw-r--r--libstats/pull/OWNERS7
-rw-r--r--libstats/pull/TEST_MAPPING7
-rw-r--r--libstats/pull/include/stats_pull_atom_callback.h170
-rw-r--r--libstats/pull/libstatspull.map.txt17
-rw-r--r--libstats/pull/libstatspull_test.xml37
-rw-r--r--libstats/pull/stats_pull_atom_callback.cpp260
-rw-r--r--libstats/pull/tests/pull_atom_metadata_test.cpp92
-rw-r--r--libstats/socket/Android.bp124
-rw-r--r--libstats/socket/TEST_MAPPING7
-rw-r--r--libstats/socket/include/stats_buffer_writer.h30
-rw-r--r--libstats/socket/include/stats_event.h164
-rw-r--r--libstats/socket/include/stats_socket.h33
-rw-r--r--libstats/socket/libstatssocket.map.txt20
-rw-r--r--libstats/socket/libstatssocket_test.xml38
-rw-r--r--libstats/socket/stats_buffer_writer.c126
-rw-r--r--libstats/socket/stats_event.c351
-rw-r--r--libstats/socket/stats_socket.c22
-rw-r--r--libstats/socket/statsd_writer.c294
-rw-r--r--libstats/socket/statsd_writer.h47
-rw-r--r--libstats/socket/tests/stats_event_test.cpp460
-rw-r--r--libstats/socket/tests/stats_writer_test.cpp36
-rw-r--r--storaged/include/storaged.h1
-rw-r--r--storaged/storaged.cpp6
273 files changed, 40 insertions, 53617 deletions
diff --git a/adb/.clang-format b/adb/.clang-format
deleted file mode 120000
index 1af4f51dd..000000000
--- 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 dee48bf80..000000000
--- a/adb/Android.bp
+++ /dev/null
@@ -1,821 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-cc_defaults {
- name: "adb_defaults",
-
- cflags: [
- "-Wall",
- "-Wextra",
- "-Werror",
- "-Wexit-time-destructors",
- "-Wno-unused-parameter",
- "-Wno-missing-field-initializers",
- "-Wthread-safety",
- "-Wvla",
- "-DADB_HOST=1", // overridden by adbd_defaults
- "-DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION=1",
- ],
- cpp_std: "experimental",
-
- use_version_lib: true,
- compile_multilib: "first",
-
- target: {
- darwin: {
- host_ldlibs: [
- "-lpthread",
- "-framework CoreFoundation",
- "-framework IOKit",
- "-lobjc",
- ],
- },
-
- windows: {
- cflags: [
- // Define windows.h and tchar.h Unicode preprocessor symbols so that
- // CreateFile(), _tfopen(), etc. map to versions that take wchar_t*, breaking the
- // build if you accidentally pass char*. Fix by calling like:
- // std::wstring path_wide;
- // if (!android::base::UTF8ToWide(path_utf8, &path_wide)) { /* error handling */ }
- // CreateFileW(path_wide.c_str());
- "-DUNICODE=1",
- "-D_UNICODE=1",
-
- // Unlike on Linux, -std=gnu++ doesn't set _GNU_SOURCE on Windows.
- "-D_GNU_SOURCE",
-
- // MinGW hides some things behind _POSIX_SOURCE.
- "-D_POSIX_SOURCE",
-
- // libusb uses __stdcall on a variadic function, which gets ignored.
- "-Wno-ignored-attributes",
-
- // Not supported yet.
- "-Wno-thread-safety",
- ],
-
- host_ldlibs: [
- "-lws2_32",
- "-lgdi32",
- "-luserenv",
- ],
- },
- },
-}
-
-cc_defaults {
- name: "adbd_defaults",
- defaults: ["adb_defaults"],
-
- cflags: ["-UADB_HOST", "-DADB_HOST=0"],
-}
-
-cc_defaults {
- name: "host_adbd_supported",
-
- host_supported: true,
- target: {
- linux: {
- enabled: true,
- host_ldlibs: [
- "-lresolv", // b64_pton
- "-lutil", // forkpty
- ],
- },
- darwin: {
- enabled: false,
- },
- windows: {
- enabled: false,
- },
- },
-}
-
-cc_defaults {
- name: "libadbd_binary_dependencies",
- static_libs: [
- "libadb_crypto",
- "libadb_pairing_connection",
- "libadb_tls_connection",
- "libadbd",
- "libadbd_core",
- "libadbconnection_server",
- "libasyncio",
- "libbrotli",
- "libcutils_sockets",
- "libdiagnose_usb",
- "libmdnssd",
- "libbase",
-
- "libadb_protos",
- ],
-
- shared_libs: [
- "libadbd_auth",
- "libadbd_fs",
- "libcrypto",
- "libcrypto_utils",
- "liblog",
- "libselinux",
- ],
-
- target: {
- recovery: {
- exclude_static_libs: [
- "libadb_pairing_auth",
- "libadb_pairing_connection",
- ],
- },
- },
-}
-
-// libadb
-// =========================================================
-// These files are compiled for both the host and the device.
-libadb_srcs = [
- "adb.cpp",
- "adb_io.cpp",
- "adb_listeners.cpp",
- "adb_trace.cpp",
- "adb_unique_fd.cpp",
- "adb_utils.cpp",
- "fdevent/fdevent.cpp",
- "fdevent/fdevent_poll.cpp",
- "services.cpp",
- "sockets.cpp",
- "socket_spec.cpp",
- "sysdeps/errno.cpp",
- "transport.cpp",
- "transport_fd.cpp",
- "transport_local.cpp",
- "types.cpp",
-]
-
-libadb_posix_srcs = [
- "sysdeps_unix.cpp",
- "sysdeps/posix/network.cpp",
-]
-
-libadb_linux_srcs = [
- "fdevent/fdevent_epoll.cpp",
-]
-
-libadb_test_srcs = [
- "adb_io_test.cpp",
- "adb_listeners_test.cpp",
- "adb_utils_test.cpp",
- "fdevent/fdevent_test.cpp",
- "socket_spec_test.cpp",
- "socket_test.cpp",
- "sysdeps_test.cpp",
- "sysdeps/stat_test.cpp",
- "transport_test.cpp",
- "types_test.cpp",
-]
-
-cc_library_host_static {
- name: "libadb_host",
- defaults: ["adb_defaults"],
-
- srcs: libadb_srcs + [
- "client/auth.cpp",
- "client/adb_wifi.cpp",
- "client/usb_libusb.cpp",
- "client/usb_dispatch.cpp",
- "client/transport_mdns.cpp",
- "client/transport_usb.cpp",
- "client/pairing/pairing_client.cpp",
- ],
-
- generated_headers: ["platform_tools_version"],
-
- target: {
- linux: {
- srcs: ["client/usb_linux.cpp"] + libadb_linux_srcs,
- },
- darwin: {
- srcs: ["client/usb_osx.cpp"],
- },
- not_windows: {
- srcs: libadb_posix_srcs,
- },
- windows: {
- enabled: true,
- srcs: [
- "client/usb_windows.cpp",
- "sysdeps_win32.cpp",
- "sysdeps/win32/errno.cpp",
- "sysdeps/win32/stat.cpp",
- ],
- shared_libs: ["AdbWinApi"],
- },
- },
-
- static_libs: [
- "libadb_crypto",
- "libadb_protos",
- "libadb_pairing_connection",
- "libadb_tls_connection",
- "libbase",
- "libcrypto_utils",
- "libcrypto",
- "libdiagnose_usb",
- "libmdnssd",
- "libusb",
- "libutils",
- "liblog",
- "libcutils",
- "libprotobuf-cpp-lite",
- ],
-}
-
-cc_test_host {
- name: "adb_test",
- defaults: ["adb_defaults"],
- srcs: libadb_test_srcs,
- static_libs: [
- "libadb_crypto_static",
- "libadb_host",
- "libadb_pairing_auth_static",
- "libadb_pairing_connection_static",
- "libadb_protos_static",
- "libadb_tls_connection_static",
- "libbase",
- "libcutils",
- "libcrypto_utils",
- "libcrypto",
- "liblog",
- "libmdnssd",
- "libdiagnose_usb",
- "libprotobuf-cpp-lite",
- "libssl",
- "libusb",
- ],
-
- target: {
- windows: {
- enabled: true,
- ldflags: ["-municode"],
- shared_libs: ["AdbWinApi"],
- },
- },
-}
-
-cc_binary_host {
- name: "adb",
-
- stl: "libc++_static",
- defaults: ["adb_defaults"],
-
- srcs: [
- "client/adb_client.cpp",
- "client/bugreport.cpp",
- "client/commandline.cpp",
- "client/file_sync_client.cpp",
- "client/main.cpp",
- "client/console.cpp",
- "client/adb_install.cpp",
- "client/line_printer.cpp",
- "client/fastdeploy.cpp",
- "client/fastdeploycallbacks.cpp",
- "client/incremental.cpp",
- "client/incremental_server.cpp",
- "client/incremental_utils.cpp",
- "shell_service_protocol.cpp",
- ],
-
- generated_headers: [
- "bin2c_fastdeployagent",
- "bin2c_fastdeployagentscript"
- ],
-
- static_libs: [
- "libadb_crypto",
- "libadb_host",
- "libadb_pairing_auth",
- "libadb_pairing_connection",
- "libadb_protos",
- "libadb_tls_connection",
- "libandroidfw",
- "libbase",
- "libbrotli",
- "libcutils",
- "libcrypto_utils",
- "libcrypto",
- "libfastdeploy_host",
- "libdiagnose_usb",
- "liblog",
- "liblz4",
- "libmdnssd",
- "libprotobuf-cpp-lite",
- "libssl",
- "libusb",
- "libutils",
- "liblog",
- "libziparchive",
- "libz",
- ],
-
- // Don't add anything here, we don't want additional shared dependencies
- // on the host adb tool, and shared libraries that link against libc++
- // will violate ODR
- shared_libs: [],
-
- // Archive adb, adb.exe.
- dist: {
- targets: [
- "dist_files",
- "sdk",
- "win_sdk",
- ],
- },
-
- target: {
- darwin: {
- cflags: [
- "-Wno-sizeof-pointer-memaccess",
- ],
- },
- windows: {
- enabled: true,
- ldflags: ["-municode"],
- shared_libs: ["AdbWinApi"],
- required: [
- "AdbWinUsbApi",
- ],
- },
- },
-}
-
-// libadbd_core contains the common sources to build libadbd and libadbd_services.
-cc_library_static {
- name: "libadbd_core",
- defaults: ["adbd_defaults", "host_adbd_supported"],
- recovery_available: true,
-
- // libminadbd wants both, as it's used to build native tests.
- compile_multilib: "both",
-
- srcs: libadb_srcs + libadb_linux_srcs + libadb_posix_srcs + [
- "daemon/auth.cpp",
- "daemon/jdwp_service.cpp",
- "daemon/logging.cpp",
- "daemon/adb_wifi.cpp",
- ],
-
- generated_headers: ["platform_tools_version"],
-
- static_libs: [
- "libadbconnection_server",
- "libdiagnose_usb",
- ],
-
- shared_libs: [
- "libadb_crypto",
- "libadb_pairing_connection",
- "libadb_protos",
- "libadb_tls_connection",
- "libadbd_auth",
- "libasyncio",
- "libbase",
- "libcrypto",
- "libcrypto_utils",
- "libcutils_sockets",
- "liblog",
- ],
-
- target: {
- android: {
- whole_static_libs: [
- "libqemu_pipe",
- ],
- srcs: [
- "daemon/transport_qemu.cpp",
- "daemon/usb.cpp",
- "daemon/usb_ffs.cpp",
- ]
- },
- recovery: {
- exclude_shared_libs: [
- "libadb_pairing_auth",
- "libadb_pairing_connection",
- ],
- }
- },
-
- apex_available: [
- "//apex_available:platform",
- "com.android.adbd",
- ],
- visibility: [
- "//bootable/recovery/minadbd",
- "//system/core/adb",
- ],
-}
-
-cc_library {
- name: "libadbd_services",
- defaults: ["adbd_defaults", "host_adbd_supported"],
- recovery_available: true,
- compile_multilib: "both",
-
- srcs: [
- "daemon/file_sync_service.cpp",
- "daemon/services.cpp",
- "daemon/shell_service.cpp",
- "shell_service_protocol.cpp",
- ],
-
- cflags: [
- "-D_GNU_SOURCE",
- "-Wno-deprecated-declarations",
- ],
-
- static_libs: [
- "libadbconnection_server",
- "libadbd_core",
- "libbrotli",
- "libdiagnose_usb",
- ],
-
- shared_libs: [
- "libadb_crypto",
- "libadb_pairing_connection",
- "libadb_protos",
- "libadb_tls_connection",
- "libasyncio",
- "libbase",
- "libcrypto_utils",
- "libcutils_sockets",
-
- // APEX dependencies.
- "libadbd_auth",
- "libadbd_fs",
- "libcrypto",
- "liblog",
- ],
-
- target: {
- android: {
- srcs: [
- "daemon/abb_service.cpp",
- "daemon/framebuffer_service.cpp",
- "daemon/mdns.cpp",
- "daemon/restart_service.cpp",
- ],
- shared_libs: [
- "libmdnssd",
- "libselinux",
- ],
- },
- recovery: {
- exclude_srcs: [
- "daemon/abb_service.cpp",
- ],
- exclude_shared_libs: [
- "libadb_pairing_auth",
- "libadb_pairing_connection",
- ],
- },
- },
-
- apex_available: [
- "//apex_available:platform",
- "com.android.adbd",
- ],
- visibility: [
- "//system/core/adb",
- ],
-
-}
-
-cc_library {
- name: "libadbd",
- defaults: ["adbd_defaults", "host_adbd_supported"],
- recovery_available: true,
- apex_available: ["com.android.adbd"],
-
- // avoid getting duplicate symbol of android::build::getbuildnumber().
- use_version_lib: false,
-
- // libminadbd wants both, as it's used to build native tests.
- compile_multilib: "both",
-
- shared_libs: [
- "libadb_crypto",
- "libadb_pairing_connection",
- "libadb_tls_connection",
- "libasyncio",
- "libbase",
- "libcrypto",
- "libcrypto_utils",
- "liblog",
- "libselinux",
-
- // APEX dependencies on the system image.
- "libadbd_auth",
- "libadbd_fs",
- "libadbd_services",
- ],
-
- target: {
- recovery: {
- exclude_shared_libs: [
- "libadb_pairing_auth",
- "libadb_pairing_connection",
- ],
- }
- },
-
- static_libs: [
- "libadbd_core",
- "libbrotli",
- "libcutils_sockets",
- "libdiagnose_usb",
- "libmdnssd",
- ],
-
- visibility: [
- "//bootable/recovery/minadbd",
- "//system/core/adb",
- ],
-}
-
-cc_binary {
- name: "adbd",
- defaults: ["adbd_defaults", "host_adbd_supported", "libadbd_binary_dependencies"],
- recovery_available: true,
- apex_available: ["com.android.adbd"],
-
- srcs: [
- "daemon/main.cpp",
- ],
-
- cflags: [
- "-D_GNU_SOURCE",
- "-Wno-deprecated-declarations",
- ],
-
- strip: {
- keep_symbols: true,
- },
-
- static_libs: [
- "libadbd",
- "libadbd_services",
- "libasyncio",
- "libcap",
- "libminijail",
- "libssl",
- ],
-
- shared_libs: [
- "libadb_protos",
- "libadbd_auth",
- ],
-
- target: {
- recovery: {
- exclude_shared_libs: [
- "libadb_pairing_auth",
- "libadb_pairing_connection",
- ],
- }
- },
-}
-
-phony {
- // Interface between adbd in a module and the system.
- name: "adbd_system_api",
- required: [
- "libadbd_auth",
- "libadbd_fs",
- "abb",
- "reboot",
- "set-verity-state",
- ]
-}
-
-phony {
- name: "adbd_system_api_recovery",
- required: [
- "libadbd_auth",
- "libadbd_fs",
- "reboot.recovery",
- ],
-}
-
-cc_binary {
- name: "abb",
-
- defaults: ["adbd_defaults"],
- stl: "libc++",
- recovery_available: false,
-
- srcs: [
- "daemon/abb.cpp",
- ],
-
- cflags: [
- "-D_GNU_SOURCE",
- "-Wno-deprecated-declarations",
- ],
-
- strip: {
- keep_symbols: true,
- },
-
- static_libs: [
- "libadbd_core",
- "libadbd_services",
- "libcmd",
- ],
-
- shared_libs: [
- "libbase",
- "libbinder",
- "liblog",
- "libutils",
- "libselinux",
- ],
-}
-
-cc_test {
- name: "adbd_test",
-
- defaults: ["adbd_defaults", "libadbd_binary_dependencies"],
-
- recovery_available: false,
- srcs: libadb_test_srcs + [
- "daemon/services.cpp",
- "daemon/shell_service.cpp",
- "daemon/shell_service_test.cpp",
- "shell_service_protocol.cpp",
- "shell_service_protocol_test.cpp",
- "mdns_test.cpp",
- ],
-
- test_config: "adb_test.xml",
-
- shared_libs: [
- "liblog",
- ],
-
- static_libs: [
- "libadbd",
- "libadbd_auth",
- "libbase",
- "libcrypto_utils",
- "libusb",
- ],
- test_suites: ["device-tests", "mts"],
- require_root: true,
-}
-
-python_test_host {
- name: "adb_integration_test_adb",
- main: "test_adb.py",
- srcs: [
- "test_adb.py",
- ],
- test_config: "adb_integration_test_adb.xml",
- test_suites: ["general-tests"],
- version: {
- py2: {
- enabled: false,
- },
- py3: {
- enabled: true,
- },
- },
-}
-
-python_test_host {
- name: "adb_integration_test_device",
- main: "test_device.py",
- srcs: [
- "test_device.py",
- ],
- libs: [
- "adb_py",
- ],
- test_config: "adb_integration_test_device.xml",
- test_suites: ["general-tests"],
- version: {
- py2: {
- enabled: false,
- },
- py3: {
- enabled: true,
- },
- },
-}
-
-// Note: using pipe for xxd to control the variable name generated
-// the default name used by xxd is the path to the input file.
-java_genrule {
- name: "bin2c_fastdeployagent",
- out: ["deployagent.inc"],
- srcs: [":deployagent"],
- cmd: "(echo 'unsigned char kDeployAgent[] = {' && xxd -i <$(in) && echo '};') > $(out)",
-}
-
-genrule {
- name: "bin2c_fastdeployagentscript",
- out: ["deployagentscript.inc"],
- srcs: ["fastdeploy/deployagent/deployagent.sh"],
- cmd: "(echo 'unsigned char kDeployAgentScript[] = {' && xxd -i <$(in) && echo '};') > $(out)",
-}
-
-cc_library_host_static {
- name: "libfastdeploy_host",
- defaults: ["adb_defaults"],
- srcs: [
- "fastdeploy/deploypatchgenerator/apk_archive.cpp",
- "fastdeploy/deploypatchgenerator/deploy_patch_generator.cpp",
- "fastdeploy/deploypatchgenerator/patch_utils.cpp",
- "fastdeploy/proto/ApkEntry.proto",
- ],
- static_libs: [
- "libadb_host",
- "libandroidfw",
- "libbase",
- "libcutils",
- "libcrypto_utils",
- "libcrypto",
- "libdiagnose_usb",
- "liblog",
- "libmdnssd",
- "libusb",
- "libutils",
- "libziparchive",
- "libz",
- ],
- proto: {
- type: "lite",
- export_proto_headers: true,
- },
- target: {
- windows: {
- enabled: true,
- shared_libs: ["AdbWinApi"],
- },
- },
-}
-
-cc_test_host {
- name: "fastdeploy_test",
- defaults: ["adb_defaults"],
- srcs: [
- "fastdeploy/deploypatchgenerator/apk_archive_test.cpp",
- "fastdeploy/deploypatchgenerator/deploy_patch_generator_test.cpp",
- "fastdeploy/deploypatchgenerator/patch_utils_test.cpp",
- ],
- static_libs: [
- "libadb_crypto_static",
- "libadb_host",
- "libadb_pairing_auth_static",
- "libadb_pairing_connection_static",
- "libadb_protos_static",
- "libadb_tls_connection_static",
- "libandroidfw",
- "libbase",
- "libcutils",
- "libcrypto_utils",
- "libcrypto",
- "libdiagnose_usb",
- "libfastdeploy_host",
- "liblog",
- "libmdnssd",
- "libprotobuf-cpp-lite",
- "libssl",
- "libusb",
- "libutils",
- "libziparchive",
- "libz",
- ],
- target: {
- windows: {
- enabled: true,
- shared_libs: ["AdbWinApi"],
- },
- },
- data: [
- "fastdeploy/testdata/rotating_cube-metadata-release.data",
- "fastdeploy/testdata/rotating_cube-release.apk",
- "fastdeploy/testdata/sample.apk",
- "fastdeploy/testdata/sample.cd",
- ],
-}
diff --git a/adb/MODULE_LICENSE_APACHE2 b/adb/MODULE_LICENSE_APACHE2
deleted file mode 100644
index e69de29bb..000000000
--- a/adb/MODULE_LICENSE_APACHE2
+++ /dev/null
diff --git a/adb/NOTICE b/adb/NOTICE
deleted file mode 100644
index 9ffcc0813..000000000
--- a/adb/NOTICE
+++ /dev/null
@@ -1,191 +0,0 @@
-
- Copyright (c) 2006-2009, The Android Open Source Project
- Copyright 2006, Brian Swetland <swetland@frotz.net>
-
- 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 f0b184c99..000000000
--- 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:<serialnumber>' request,
- where '<serialnumber>' is used to identify a given device/emulator; after
- the "OKAY" answer, all further requests made by the client will go
- directly to the corresponding adbd daemon.
-
- The file SERVICES.TXT lists all services currently implemented by ADB.
-
-
- 2. Transports:
-
- An ADB transport models a connection between the ADB server and one device
- or emulator. There are currently two kinds of transports:
-
- - USB transports, for physical devices through USB
-
- - Local transports, for emulators running on the host, connected to
- the server through TCP
-
- In theory, it should be possible to write a local transport that proxies
- a connection between an ADB server and a device/emulator connected to/
- running on another machine. This hasn't been done yet though.
-
- Each transport can carry one or more multiplexed streams between clients
- and the device/emulator they point to. The ADB server must handle
- unexpected transport disconnections (e.g. when a device is physically
- unplugged) properly.
diff --git a/adb/OWNERS b/adb/OWNERS
deleted file mode 100644
index 643b4489f..000000000
--- a/adb/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-jmgao@google.com
-yabinc@google.com
diff --git a/adb/SERVICES.TXT b/adb/SERVICES.TXT
deleted file mode 100644
index 3e18a54e7..000000000
--- 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:<port>
- This is a special query that is sent to the ADB server when a
- new emulator starts up. <port> is a decimal number corresponding
- to the emulator's ADB control port, i.e. the TCP port that the
- emulator will forward automatically to the adbd daemon running
- in the emulator system.
-
- This mechanism allows the ADB server to know when new emulator
- instances start.
-
-host:transport:<serial-number>
- Ask to switch the connection to the device/emulator identified by
- <serial-number>. After the OKAY response, every client request will
- be sent directly to the adbd daemon running on the device.
- (Used to implement the -s option)
-
-host:transport-usb
- Ask to switch the connection to one device connected through USB
- to the host machine. This will fail if there are more than one such
- devices. (Used to implement the -d convenience option)
-
-host:transport-local
- Ask to switch the connection to one emulator connected through TCP.
- This will fail if there is more than one such emulator instance
- running. (Used to implement the -e convenience option)
-
-host:transport-any
- Another host:transport variant. Ask to switch the connection to
- either the device or emulator connect to/running on the host.
- Will fail if there is more than one such device/emulator available.
- (Used when neither -s, -d or -e are provided)
-
-host-serial:<serial-number>:<request>
- This is a special form of query, where the 'host-serial:<serial-number>:'
- prefix can be used to indicate that the client is asking the ADB server
- for information related to a specific device. <request> can be in one
- of the format described below.
-
-host-usb:<request>
- A variant of host-serial used to target the single USB device connected
- to the host. This will fail if there is none or more than one.
-
-host-local:<request>
- A variant of host-serial used to target the single emulator instance
- running on the host. This will fail if there is none or more than one.
-
-host:<request>
- When asking for information related to a device, 'host:' can also be
- interpreted as 'any single device or emulator connected to/running on
- the host'.
-
-<host-prefix>:get-product
- XXX
-
-<host-prefix>:get-serialno
- Returns the serial number of the corresponding device/emulator.
- Note that emulator serial numbers are of the form "emulator-5554"
-
-<host-prefix>:get-devpath
- Returns the device path of the corresponding device/emulator.
-
-<host-prefix>:get-state
- Returns the state of a given device as a string.
-
-<host-prefix>:forward:<local>;<remote>
- Asks the ADB server to forward local connections from <local>
- to the <remote> address on a given device.
-
- There, <host-prefix> can be one of the
- host-serial/host-usb/host-local/host prefixes as described previously
- and indicates which device/emulator to target.
-
- the format of <local> is one of:
-
- tcp:<port> -> TCP connection on localhost:<port>
- local:<path> -> Unix local domain socket on <path>
-
- the format of <remote> is one of:
-
- tcp:<port> -> TCP localhost:<port> on device
- local:<path> -> Unix local domain socket on device
- jdwp:<pid> -> JDWP thread on VM process <pid>
-
- or even any one of the local services described below.
-
-<host-prefix>:forward:norebind:<local>;<remote>
- Same as <host-prefix>:forward:<local>;<remote> except that it will
- fail it there is already a forward connection from <local>.
-
- Used to implement 'adb forward --no-rebind <local> <remote>'
-
-<host-prefix>:killforward:<local>
- Remove any existing forward local connection from <local>.
- This is used to implement 'adb forward --remove <local>'
-
-<host-prefix>:killforward-all
- Remove all forward network connections.
- This is used to implement 'adb forward --remove-all'.
-
-<host-prefix>:list-forward
- List all existing forward connections from this server.
- This returns something that looks like the following:
-
- <hex4>: The length of the payload, as 4 hexadecimal chars.
- <payload>: A series of lines of the following format:
-
- <serial> " " <local> " " <remote> "\n"
-
- Where <serial> is a device serial number.
- <local> is the host-specific endpoint (e.g. tcp:9000).
- <remote> 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:<path>
- 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. <path> is a full
- path from the root of the filesystem.
-
-tcp:<port>
- Tries to connect to tcp port <port> on localhost.
-
-tcp:<port>:<server-name>
- Tries to connect to tcp port <port> on machine <server-name> from
- the device. This can be useful to debug some networking/proxy
- issues that can only be revealed on the device itself.
-
-local:<path>
- Tries to connect to a Unix domain socket <path> on the device
-
-localreserved:<path>
-localabstract:<path>
-localfilesystem:<path>
- Variants of local:<path> that are used to access other Android
- socket namespaces.
-
-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:<pid>
- Connects to the JDWP thread running in the VM of process <pid>.
-
-track-jdwp
- This is used to send the list of JDWP pids periodically to the client.
- The format of the returned data is the following:
-
- <hex4>: the length of all content as a 4-char hexadecimal string
- <content>: a series of ASCII lines of the following format:
- <pid> "\n"
-
- This service is used by DDMS to know which debuggable processes are running
- on the device/emulator.
-
- Note that there is no single-shot service to retrieve the list only once.
-
-sync:
- This starts the file 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:<forward-command>
- This implements the 'adb reverse' feature, i.e. the ability to reverse
- socket connections from a device to the host. <forward-command> is one
- of the forwarding commands that are described above, as in:
-
- list-forward
- forward:<local>;<remote>
- forward:norebind:<local>;<remote>
- killforward-all
- killforward:<local>
-
- Note that in this case, <local> corresponds to the socket on the device
- and <remote> corresponds to the socket on the host.
-
- The output of reverse:list-forward is the same as host:list-forward
- except that <serial> will be just 'host'.
diff --git a/adb/SOCKET-ACTIVATION.txt b/adb/SOCKET-ACTIVATION.txt
deleted file mode 100644
index 4ef62ac9d..000000000
--- 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 4445a7617..000000000
--- 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 b1b3957c0..000000000
--- 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 c3e9731a3..000000000
--- a/adb/adb.cpp
+++ /dev/null
@@ -1,1359 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define TRACE_TAG ADB
-
-#include "sysdeps.h"
-#include "adb.h"
-
-#include <ctype.h>
-#include <errno.h>
-#include <stdarg.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/time.h>
-#include <time.h>
-
-#include <chrono>
-#include <condition_variable>
-#include <mutex>
-#include <string>
-#include <string_view>
-#include <thread>
-#include <vector>
-
-#include <android-base/errors.h>
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <android-base/parsenetaddress.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-#include <build/version.h>
-#include <platform_tools_version.h>
-
-#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 <sys/capability.h>
-#include <sys/mount.h>
-#include <android-base/properties.h>
-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<uint8_t>(p->payload[i]);
- }
- return sum;
-}
-
-apacket* get_apacket(void)
-{
- apacket* p = new apacket();
- if (p == nullptr) {
- LOG(FATAL) << "failed to allocate an apacket";
- }
-
- memset(&p->msg, 0, sizeof(p->msg));
- return p;
-}
-
-void put_apacket(apacket *p)
-{
- delete p;
-}
-
-void handle_online(atransport *t)
-{
- D("adb: online");
- t->online = 1;
- t->SetConnectionEstablished(true);
-}
-
-void handle_offline(atransport *t)
-{
- if (t->GetConnectionState() == kCsOffline) {
- LOG(INFO) << t->serial_name() << ": already offline";
- return;
- }
-
- LOG(INFO) << t->serial_name() << ": offline";
-
- t->SetConnectionState(kCsOffline);
-
- // Close the associated usb
- t->online = 0;
-
- // This is necessary to avoid a race condition that occurred when a transport closes
- // while a client socket is still active.
- close_all_sockets(t);
-
- t->RunDisconnects();
-}
-
-#if DEBUG_PACKETS
-#define DUMPMAX 32
-void print_packet(const char *label, apacket *p)
-{
- const char* tag;
- unsigned count;
-
- switch(p->msg.command){
- case A_SYNC: tag = "SYNC"; break;
- case A_CNXN: tag = "CNXN" ; break;
- case A_OPEN: tag = "OPEN"; break;
- case A_OKAY: tag = "OKAY"; break;
- case A_CLSE: tag = "CLSE"; break;
- case A_WRTE: tag = "WRTE"; break;
- case A_AUTH: tag = "AUTH"; break;
- case A_STLS:
- tag = "STLS";
- break;
- default: tag = "????"; break;
- }
-
- fprintf(stderr, "%s: %s %08x %08x %04x \"",
- label, tag, p->msg.arg0, p->msg.arg1, p->msg.data_length);
- count = p->msg.data_length;
- const char* x = p->payload.data();
- if (count > DUMPMAX) {
- count = DUMPMAX;
- tag = "\n";
- } else {
- tag = "\"\n";
- }
- while (count-- > 0) {
- if ((*x >= ' ') && (*x < 127)) {
- fputc(*x, stderr);
- } else {
- fputc('.', stderr);
- }
- x++;
- }
- fputs(tag, stderr);
-}
-#endif
-
-static void send_ready(unsigned local, unsigned remote, atransport *t)
-{
- D("Calling send_ready");
- apacket *p = get_apacket();
- p->msg.command = A_OKAY;
- p->msg.arg0 = local;
- p->msg.arg1 = remote;
- send_packet(p, t);
-}
-
-static void send_close(unsigned local, unsigned remote, atransport *t)
-{
- D("Calling send_close");
- apacket *p = get_apacket();
- p->msg.command = A_CLSE;
- p->msg.arg0 = local;
- p->msg.arg1 = remote;
- send_packet(p, t);
-}
-
-std::string get_connection_string() {
- std::vector<std::string> 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<std::string> 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<std::string> 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, <data>) */
- 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<FILE, decltype(&fclose)> 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<std::string> lines = android::base::Split(content, "\n");
- int i = lines.size() - 1;
- while (i >= 0 && lines[i] != header) --i;
- while (static_cast<size_t>(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<HANDLE>(
- _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<HANDLE>(
- _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<atransport*(std::string* error)> 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<std::string> pieces = android::base::Split(service, ";");
-
- if (kill_forward) {
- // Check killforward: parameter format: '<local>'
- if (pieces.size() != 1 || pieces[0].empty()) {
- SendFail(reply_fd, android::base::StringPrintf("bad killforward: %s", service));
- return true;
- }
- } else {
- // Check forward: parameter format: '<local>;<remote>'
- if (pieces.size() != 2 || pieces[0].empty() || pieces[1].empty() || pieces[1][0] == '*') {
- SendFail(reply_fd, android::base::StringPrintf("bad forward: %s", service));
- return true;
- }
- }
-
- InstallStatus r;
- int resolved_tcp_port = 0;
- if (kill_forward) {
- r = remove_listener(pieces[0].c_str(), transport);
- } else {
- r = install_listener(pieces[0], pieces[1].c_str(), transport, no_rebind,
- &resolved_tcp_port, &error);
- }
- if (r == INSTALL_STATUS_OK) {
-#if ADB_HOST
- // On the host: 1st OKAY is connect, 2nd OKAY is status.
- SendOkay(reply_fd);
-#endif
- SendOkay(reply_fd);
-
- // If a TCP port was resolved, send the actual port number back.
- if (resolved_tcp_port != 0) {
- SendProtocolString(reply_fd, android::base::StringPrintf("%d", resolved_tcp_port));
- }
-
- return true;
- }
-
- std::string message;
- switch (r) {
- case INSTALL_STATUS_OK: message = "success (!)"; break;
- case INSTALL_STATUS_INTERNAL_ERROR: message = "internal error"; break;
- case INSTALL_STATUS_CANNOT_BIND:
- message = android::base::StringPrintf("cannot bind listener: %s",
- error.c_str());
- break;
- case INSTALL_STATUS_CANNOT_REBIND:
- message = android::base::StringPrintf("cannot rebind existing socket");
- break;
- case INSTALL_STATUS_LISTENER_NOT_FOUND:
- message = android::base::StringPrintf("listener '%s' not found", service);
- break;
- }
- SendFail(reply_fd, message);
- return true;
- }
-
- return false;
-}
-
-#if ADB_HOST
-static int SendOkay(int fd, const std::string& s) {
- SendOkay(fd);
- SendProtocolString(fd, s);
- return 0;
-}
-
-HostRequestResult handle_host_request(std::string_view service, TransportType type,
- const char* serial, TransportId transport_id, int reply_fd,
- asocket* s) {
- if (service == "kill") {
- fprintf(stderr, "adb server killed by remote request\n");
- fflush(stdout);
-
- // Send a reply even though we don't read it anymore, so that old versions
- // of adb that do read it don't spew error messages.
- SendOkay(reply_fd);
-
- // Rely on process exit to close the socket for us.
- exit(0);
- }
-
- LOG(DEBUG) << "handle_host_request(" << service << ")";
-
- // Transport selection:
- if (service.starts_with("transport") || service.starts_with("tport:")) {
- TransportType type = kTransportAny;
-
- std::string serial_storage;
- bool legacy = true;
-
- // New transport selection protocol:
- // This is essentially identical to the previous version, except it returns the selected
- // transport id to the caller as well.
- if (android::base::ConsumePrefix(&service, "tport:")) {
- legacy = false;
- if (android::base::ConsumePrefix(&service, "serial:")) {
- serial_storage = service;
- serial = serial_storage.c_str();
- } else if (service == "usb") {
- type = kTransportUsb;
- } else if (service == "local") {
- type = kTransportLocal;
- } else if (service == "any") {
- type = kTransportAny;
- }
-
- // Selection by id is unimplemented, since you obviously already know the transport id
- // you're connecting to.
- } else {
- if (android::base::ConsumePrefix(&service, "transport-id:")) {
- if (!ParseUint(&transport_id, service)) {
- SendFail(reply_fd, "invalid transport id");
- return HostRequestResult::Handled;
- }
- } else if (service == "transport-usb") {
- type = kTransportUsb;
- } else if (service == "transport-local") {
- type = kTransportLocal;
- } else if (service == "transport-any") {
- type = kTransportAny;
- } else if (android::base::ConsumePrefix(&service, "transport:")) {
- serial_storage = service;
- serial = serial_storage.c_str();
- }
- }
-
- std::string error;
- atransport* t = acquire_one_transport(type, serial, transport_id, nullptr, &error);
- if (t != nullptr) {
- s->transport = t;
- SendOkay(reply_fd);
-
- if (!legacy) {
- // Nothing we can do if this fails.
- WriteFdExactly(reply_fd, &t->id, sizeof(t->id));
- }
-
- return HostRequestResult::SwitchedTransport;
- } else {
- SendFail(reply_fd, error);
- return HostRequestResult::Handled;
- }
- }
-
- // return a list of all connected devices
- if (service == "devices" || service == "devices-l") {
- bool long_listing = service == "devices-l";
- D("Getting device list...");
- std::string device_list = list_transports(long_listing);
- D("Sending device list...");
- SendOkay(reply_fd, device_list);
- return HostRequestResult::Handled;
- }
-
- if (service == "reconnect-offline") {
- std::string response;
- close_usb_devices([&response](const atransport* transport) {
- if (!ConnectionStateIsOnline(transport->GetConnectionState())) {
- response += "reconnecting " + transport->serial_name() + "\n";
- return true;
- }
- return false;
- }, true);
- if (!response.empty()) {
- response.resize(response.size() - 1);
- }
- SendOkay(reply_fd, response);
- return HostRequestResult::Handled;
- }
-
- if (service == "features") {
- std::string error;
- atransport* t =
- s->transport ? s->transport
- : acquire_one_transport(type, serial, transport_id, nullptr, &error);
- if (t != nullptr) {
- SendOkay(reply_fd, FeatureSetToString(t->features()));
- } else {
- SendFail(reply_fd, error);
- }
- return HostRequestResult::Handled;
- }
-
- if (service == "host-features") {
- FeatureSet features = supported_features();
- // Abuse features to report libusb status.
- if (should_use_libusb()) {
- features.insert(kFeatureLibusb);
- }
- features.insert(kFeaturePushSync);
- SendOkay(reply_fd, FeatureSetToString(features));
- return HostRequestResult::Handled;
- }
-
- // remove TCP transport
- if (service.starts_with("disconnect:")) {
- std::string address(service.substr(11));
- if (address.empty()) {
- kick_all_tcp_devices();
- SendOkay(reply_fd, "disconnected everything");
- return HostRequestResult::Handled;
- }
-
- std::string serial;
- std::string host;
- int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
- std::string error;
- if (address.starts_with("vsock:") || address.starts_with("localfilesystem:")) {
- serial = address;
- } else if (!android::base::ParseNetAddress(address, &host, &port, &serial, &error)) {
- SendFail(reply_fd, android::base::StringPrintf("couldn't parse '%s': %s",
- address.c_str(), error.c_str()));
- return HostRequestResult::Handled;
- }
- atransport* t = find_transport(serial.c_str());
- if (t == nullptr) {
- SendFail(reply_fd, android::base::StringPrintf("no such device '%s'", serial.c_str()));
- return HostRequestResult::Handled;
- }
- kick_transport(t);
- SendOkay(reply_fd, android::base::StringPrintf("disconnected %s", address.c_str()));
- return HostRequestResult::Handled;
- }
-
- // Returns our value for ADB_SERVER_VERSION.
- if (service == "version") {
- SendOkay(reply_fd, android::base::StringPrintf("%04x", ADB_SERVER_VERSION));
- return HostRequestResult::Handled;
- }
-
- // These always report "unknown" rather than the actual error, for scripts.
- if (service == "get-serialno") {
- std::string error;
- atransport* t =
- s->transport ? s->transport
- : acquire_one_transport(type, serial, transport_id, nullptr, &error);
- if (t) {
- SendOkay(reply_fd, !t->serial.empty() ? t->serial : "unknown");
- } else {
- SendFail(reply_fd, error);
- }
- return HostRequestResult::Handled;
- }
- if (service == "get-devpath") {
- std::string error;
- atransport* t =
- s->transport ? s->transport
- : acquire_one_transport(type, serial, transport_id, nullptr, &error);
- if (t) {
- SendOkay(reply_fd, !t->devpath.empty() ? t->devpath : "unknown");
- } else {
- SendFail(reply_fd, error);
- }
- return HostRequestResult::Handled;
- }
- if (service == "get-state") {
- std::string error;
- atransport* t =
- s->transport ? s->transport
- : acquire_one_transport(type, serial, transport_id, nullptr, &error);
- if (t) {
- SendOkay(reply_fd, t->connection_state_name());
- } else {
- SendFail(reply_fd, error);
- }
- return HostRequestResult::Handled;
- }
-
- // Indicates a new emulator instance has started.
- if (android::base::ConsumePrefix(&service, "emulator:")) {
- unsigned int port;
- if (!ParseUint(&port, service)) {
- LOG(ERROR) << "received invalid port for emulator: " << service;
- } else {
- local_connect(port);
- }
-
- /* we don't even need to send a reply */
- return HostRequestResult::Handled;
- }
-
- if (service == "reconnect") {
- std::string response;
- atransport* t = s->transport ? s->transport
- : acquire_one_transport(type, serial, transport_id, nullptr,
- &response, true);
- if (t != nullptr) {
- kick_transport(t, true);
- response =
- "reconnecting " + t->serial_name() + " [" + t->connection_state_name() + "]\n";
- }
- SendOkay(reply_fd, response);
- return HostRequestResult::Handled;
- }
-
- // TODO: Switch handle_forward_request to string_view.
- std::string service_str(service);
- auto transport_acquirer = [=](std::string* error) {
- if (s->transport) {
- return s->transport;
- } else {
- std::string error;
- return acquire_one_transport(type, serial, transport_id, nullptr, &error);
- }
- };
- if (handle_forward_request(service_str.c_str(), transport_acquirer, reply_fd)) {
- return HostRequestResult::Handled;
- }
-
- return HostRequestResult::Unhandled;
-}
-
-static auto& init_mutex = *new std::mutex();
-static auto& init_cv = *new std::condition_variable();
-static bool device_scan_complete = false;
-static bool transports_ready = false;
-
-void update_transport_status() {
- bool result = iterate_transports([](const atransport* t) {
- if (t->type == kTransportUsb && t->online != 1) {
- return false;
- }
- return true;
- });
-
- bool ready;
- {
- std::lock_guard<std::mutex> 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<std::mutex> lock(init_mutex);
- if (device_scan_complete) {
- return;
- }
-
- device_scan_complete = true;
- }
-
- update_transport_status();
-}
-
-void adb_wait_for_device_initialization() {
- std::unique_lock<std::mutex> 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 ce12a55f9..000000000
--- a/adb/adb.h
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __ADB_H
-#define __ADB_H
-
-#include <limits.h>
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <string>
-
-#include <android-base/macros.h>
-
-#include "adb_trace.h"
-#include "fdevent/fdevent.h"
-#include "socket.h"
-#include "types.h"
-
-constexpr size_t MAX_PAYLOAD_V1 = 4 * 1024;
-constexpr size_t MAX_PAYLOAD = 1024 * 1024;
-constexpr size_t MAX_FRAMEWORK_PAYLOAD = 64 * 1024;
-
-constexpr size_t LINUX_MAX_SOCKET_SIZE = 4194304;
-
-#define A_SYNC 0x434e5953
-#define A_CNXN 0x4e584e43
-#define A_OPEN 0x4e45504f
-#define A_OKAY 0x59414b4f
-#define A_CLSE 0x45534c43
-#define A_WRTE 0x45545257
-#define A_AUTH 0x48545541
-#define A_STLS 0x534C5453
-
-// ADB protocol version.
-// Version revision:
-// 0x01000000: original
-// 0x01000001: skip checksum (Dec 2017)
-#define A_VERSION_MIN 0x01000000
-#define A_VERSION_SKIP_CHECKSUM 0x01000001
-#define A_VERSION 0x01000001
-
-// Stream-based TLS protocol version
-#define A_STLS_VERSION_MIN 0x01000000
-#define A_STLS_VERSION 0x01000000
-
-// Used for help/version information.
-#define ADB_VERSION_MAJOR 1
-#define ADB_VERSION_MINOR 0
-
-std::string adb_version();
-
-// Increment this when we want to force users to start a new adb server.
-#define ADB_SERVER_VERSION 41
-
-using TransportId = uint64_t;
-class atransport;
-
-uint32_t calculate_apacket_checksum(const apacket* packet);
-
-/* the adisconnect structure is used to record a callback that
-** will be called whenever a transport is disconnected (e.g. by the user)
-** this should be used to cleanup objects that depend on the
-** transport (e.g. remote sockets, listeners, etc...)
-*/
-struct adisconnect {
- void (*func)(void* opaque, atransport* t);
- void* opaque;
-};
-
-// A transport object models the connection to a remote device or emulator there
-// is one transport per connected device/emulator. A "local transport" connects
-// through TCP (for the emulator), while a "usb transport" through USB (for real
-// devices).
-//
-// Note that kTransportHost doesn't really correspond to a real transport
-// object, it's a special value used to indicate that a client wants to connect
-// to a service implemented within the ADB server itself.
-enum TransportType {
- kTransportUsb,
- kTransportLocal,
- kTransportAny,
- kTransportHost,
-};
-
-#define TOKEN_SIZE 20
-
-enum ConnectionState {
- kCsAny = -1,
-
- kCsConnecting = 0, // Haven't received a response from the device yet.
- kCsAuthorizing, // Authorizing with keys from ADB_VENDOR_KEYS.
- kCsUnauthorized, // ADB_VENDOR_KEYS exhausted, fell back to user prompt.
- kCsNoPerm, // Insufficient permissions to communicate with the device.
- kCsOffline,
-
- kCsBootloader,
- kCsDevice,
- kCsHost,
- kCsRecovery,
- kCsSideload,
- kCsRescue,
-};
-
-inline bool ConnectionStateIsOnline(ConnectionState state) {
- switch (state) {
- case kCsBootloader:
- case kCsDevice:
- case kCsHost:
- case kCsRecovery:
- case kCsSideload:
- case kCsRescue:
- return true;
- default:
- return false;
- }
-}
-
-void print_packet(const char* label, apacket* p);
-
-void handle_packet(apacket* p, atransport* t);
-
-int launch_server(const std::string& socket_spec);
-int adb_server_main(int is_daemon, const std::string& socket_spec, int ack_reply_fd);
-
-/* initialize a transport object's func pointers and state */
-int init_socket_transport(atransport* t, unique_fd s, int port, int local);
-
-std::string getEmulatorSerialString(int console_port);
-#if ADB_HOST
-atransport* find_emulator_transport_by_adb_port(int adb_port);
-atransport* find_emulator_transport_by_console_port(int console_port);
-#endif
-
-unique_fd service_to_fd(std::string_view name, atransport* transport);
-#if !ADB_HOST
-unique_fd daemon_service_to_fd(std::string_view name, atransport* transport);
-#endif
-
-#if ADB_HOST
-asocket* host_service_to_socket(std::string_view name, std::string_view serial,
- TransportId transport_id);
-#endif
-
-#if !ADB_HOST
-asocket* daemon_service_to_socket(std::string_view name);
-#endif
-
-#if !ADB_HOST
-unique_fd execute_abb_command(std::string_view command);
-#endif
-
-#if !ADB_HOST
-int init_jdwp(void);
-asocket* create_jdwp_service_socket();
-asocket* create_jdwp_tracker_service_socket();
-unique_fd create_jdwp_connection_fd(int jdwp_pid);
-#endif
-
-bool handle_forward_request(const char* service, atransport* transport, int reply_fd);
-bool handle_forward_request(const char* service,
- std::function<atransport*(std::string* error)> transport_acquirer,
- int reply_fd);
-
-/* packet allocator */
-apacket* get_apacket(void);
-void put_apacket(apacket* p);
-
-// Define it if you want to dump packets.
-#define DEBUG_PACKETS 0
-
-#if !DEBUG_PACKETS
-#define print_packet(tag, p) \
- do { \
- } while (0)
-#endif
-
-#define DEFAULT_ADB_PORT 5037
-
-#define DEFAULT_ADB_LOCAL_TRANSPORT_PORT 5555
-
-#define ADB_CLASS 0xff
-#define ADB_SUBCLASS 0x42
-#define ADB_PROTOCOL 0x1
-
-void local_init(const std::string& addr);
-bool local_connect(int port);
-int local_connect_arbitrary_ports(int console_port, int adb_port, std::string* error);
-
-ConnectionState connection_state(atransport* t);
-
-extern const char* adb_device_banner;
-
-#define CHUNK_SIZE (64 * 1024)
-
-// Argument delimeter for adb abb command.
-#define ABB_ARG_DELIMETER ('\0')
-
-#if !ADB_HOST
-#define USB_FFS_ADB_PATH "/dev/usb-ffs/adb/"
-#define USB_FFS_ADB_EP(x) USB_FFS_ADB_PATH #x
-
-#define USB_FFS_ADB_EP0 USB_FFS_ADB_EP(ep0)
-#define USB_FFS_ADB_OUT USB_FFS_ADB_EP(ep1)
-#define USB_FFS_ADB_IN USB_FFS_ADB_EP(ep2)
-#endif
-
-enum class HostRequestResult {
- Handled,
- SwitchedTransport,
- Unhandled,
-};
-
-HostRequestResult handle_host_request(std::string_view service, TransportType type,
- const char* serial, TransportId transport_id, int reply_fd,
- asocket* s);
-
-void handle_online(atransport* t);
-void handle_offline(atransport* t);
-
-void send_connect(atransport* t);
-void send_tls_request(atransport* t);
-
-void parse_banner(const std::string&, atransport* t);
-
-// On startup, the adb server needs to wait until all of the connected devices are ready.
-// To do this, we need to know when the scan has identified all of the potential new transports, and
-// when each transport becomes ready.
-// TODO: Do this for mDNS as well, instead of just USB?
-
-// We've found all of the transports we potentially care about.
-void adb_notify_device_scan_complete();
-
-// One or more transports have changed status, check to see if we're ready.
-void update_transport_status();
-
-// Wait until device scan has completed and every transport is ready, or a timeout elapses.
-void adb_wait_for_device_initialization();
-
-void usb_init();
-#endif
diff --git a/adb/adb_auth.h b/adb/adb_auth.h
deleted file mode 100644
index 7e858dce4..000000000
--- 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 <deque>
-#include <memory>
-
-#include <openssl/rsa.h>
-
-/* 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<EVP_PKEY> adb_auth_get_user_privkey();
-std::deque<std::shared_ptr<RSA>> 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<STACK_OF(X509_NAME)> 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 e722956b8..000000000
--- a/adb/adb_integration_test_adb.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<configuration description="Config to run adb integration tests">
- <option name="test-suite-tag" value="adb_tests" />
- <option name="test-suite-tag" value="adb_integration" />
- <target_preparer class="com.android.tradefed.targetprep.SemaphoreTokenTargetPreparer">
- <option name="disable" value="false" />
- </target_preparer>
-
- <target_preparer class="com.android.tradefed.targetprep.adb.AdbStopServerPreparer" />
- <test class="com.android.tradefed.testtype.python.PythonBinaryHostTest" >
- <option name="par-file-name" value="adb_integration_test_adb" />
- <option name="inject-android-serial" value="true" />
- <option name="test-timeout" value="2m" />
- </test>
-</configuration>
diff --git a/adb/adb_integration_test_device.xml b/adb/adb_integration_test_device.xml
deleted file mode 100644
index b89237734..000000000
--- a/adb/adb_integration_test_device.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<configuration description="Config to run adb integration tests for device">
- <option name="test-suite-tag" value="adb_tests" />
- <option name="test-suite-tag" value="adb_integration_device" />
- <target_preparer class="com.android.tradefed.targetprep.SemaphoreTokenTargetPreparer">
- <option name="disable" value="false" />
- </target_preparer>
-
- <target_preparer class="com.android.tradefed.targetprep.adb.AdbStopServerPreparer" />
- <test class="com.android.tradefed.testtype.python.PythonBinaryHostTest" >
- <option name="par-file-name" value="adb_integration_test_device" />
- <option name="inject-android-serial" value="true" />
- <option name="test-timeout" value="2m" />
- </test>
-</configuration>
diff --git a/adb/adb_io.cpp b/adb/adb_io.cpp
deleted file mode 100644
index bdb8efa5c..000000000
--- 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 <unistd.h>
-
-#if !ADB_HOST
-#include <sys/socket.h>
-#include <sys/un.h>
-#endif
-
-#include <thread>
-
-#include <android-base/stringprintf.h>
-
-#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<char*>(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<const unsigned char*>(buf), len0);
-
- return true;
-}
-
-bool WriteFdExactly(borrowed_fd fd, const void* buf, size_t len) {
- const char* p = reinterpret_cast<const char*>(buf);
- int r;
-
- VLOG(RWX) << "writex: fd=" << fd.get() << " len=" << len << " "
- << dump_hex(reinterpret_cast<const unsigned char*>(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 962894610..000000000
--- 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 <sys/types.h>
-
-#include <string>
-#include <string_view>
-
-#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 91b73a9a4..000000000
--- 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 <gtest/gtest.h>
-
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <string>
-
-#include <android-base/file.h>
-
-// 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 29909a555..000000000
--- a/adb/adb_listeners.cpp
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "adb_listeners.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <algorithm>
-#include <list>
-#include <memory>
-
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-#include <android-base/thread_annotations.h>
-#include <cutils/sockets.h>
-
-#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<std::unique_ptr<alistener>> ListenerList;
-static ListenerList& listener_list GUARDED_BY(listener_list_mutex) = *new ListenerList();
-
-static void ss_listener_event_func(int _fd, unsigned ev, void *_l) {
- if (ev & FDE_READ) {
- unique_fd fd(adb_socket_accept(_fd, nullptr, nullptr));
- if (fd < 0) return;
-
- int rcv_buf_size = CHUNK_SIZE;
- adb_setsockopt(fd.get(), SOL_SOCKET, SO_RCVBUF, &rcv_buf_size, sizeof(rcv_buf_size));
-
- asocket* s = create_local_socket(std::move(fd));
- if (s) {
- connect_to_smartsocket(s);
- return;
- }
- }
-}
-
-static void listener_event_func(int _fd, unsigned ev, void* _l)
-{
- alistener* listener = reinterpret_cast<alistener*>(_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<std::mutex> 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<std::mutex> 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;
- }
- // <device-serial> " " <local-name> " " <remote-name> "\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<std::mutex> 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<std::mutex> lock(listener_list_mutex);
- auto iter = listener_list.begin();
- while (iter != listener_list.end()) {
- // Never remove smart sockets.
- if ((*iter)->connect_to[0] == '*') {
- ++iter;
- } else {
- iter = listener_list.erase(iter);
- }
- }
-}
-
-void close_smartsockets() EXCLUDES(listener_list_mutex) {
- std::lock_guard<std::mutex> lock(listener_list_mutex);
- auto pred = [](const std::unique_ptr<alistener>& listener) {
- return listener->local_name == "*smartsocket*";
- };
- listener_list.remove_if(pred);
-}
-
-InstallStatus install_listener(const std::string& local_name, const char* connect_to,
- atransport* transport, int no_rebind, int* resolved_tcp_port,
- std::string* error) EXCLUDES(listener_list_mutex) {
- std::lock_guard<std::mutex> lock(listener_list_mutex);
- for (auto& l : listener_list) {
- if (local_name == l->local_name) {
- // Can't repurpose a smartsocket.
- if(l->connect_to[0] == '*') {
- *error = "cannot repurpose smartsocket";
- return INSTALL_STATUS_INTERNAL_ERROR;
- }
-
- // Can't repurpose a listener if 'no_rebind' is true.
- if (no_rebind) {
- *error = "cannot rebind";
- return INSTALL_STATUS_CANNOT_REBIND;
- }
-
- l->connect_to = connect_to;
- if (l->transport != transport) {
- l->transport->RemoveDisconnect(&l->disconnect);
- l->transport = transport;
- l->transport->AddDisconnect(&l->disconnect);
- }
- return INSTALL_STATUS_OK;
- }
- }
-
- auto listener = std::make_unique<alistener>(local_name, connect_to);
-
- int resolved = 0;
- listener->fd = socket_spec_listen(listener->local_name, error, &resolved);
- if (listener->fd < 0) {
- return INSTALL_STATUS_CANNOT_BIND;
- }
-
- // If the caller requested port 0, update the listener name with the resolved port.
- if (resolved != 0) {
- listener->local_name = android::base::StringPrintf("tcp:%d", resolved);
- if (resolved_tcp_port) {
- *resolved_tcp_port = resolved;
- }
- }
-
- close_on_exec(listener->fd);
- if (listener->connect_to == "*smartsocket*") {
- listener->fde = fdevent_create(listener->fd, ss_listener_event_func, listener.get());
- } else {
- listener->fde = fdevent_create(listener->fd, listener_event_func, listener.get());
- }
- fdevent_set(listener->fde, FDE_READ);
-
- listener->transport = transport;
-
- if (transport) {
- listener->disconnect.opaque = listener.get();
- listener->disconnect.func = listener_disconnect;
- transport->AddDisconnect(&listener->disconnect);
- }
-
- listener_list.push_back(std::move(listener));
- return INSTALL_STATUS_OK;
-}
diff --git a/adb/adb_listeners.h b/adb/adb_listeners.h
deleted file mode 100644
index 70a2ee121..000000000
--- a/adb/adb_listeners.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __ADB_LISTENERS_H
-#define __ADB_LISTENERS_H
-
-#include "adb.h"
-
-#include <string>
-
-#include <android-base/macros.h>
-
-// error/status codes for install_listener.
-enum InstallStatus {
- INSTALL_STATUS_OK = 0,
- INSTALL_STATUS_INTERNAL_ERROR = -1,
- INSTALL_STATUS_CANNOT_BIND = -2,
- INSTALL_STATUS_CANNOT_REBIND = -3,
- INSTALL_STATUS_LISTENER_NOT_FOUND = -4,
-};
-
-InstallStatus install_listener(const std::string& local_name, const char* connect_to,
- atransport* transport, int no_rebind, int* resolved_tcp_port,
- std::string* error);
-
-std::string format_listeners();
-
-InstallStatus remove_listener(const char* local_name, atransport* transport);
-void remove_all_listeners(void);
-
-void close_smartsockets();
-
-#endif /* __ADB_LISTENERS_H */
diff --git a/adb/adb_listeners_test.cpp b/adb/adb_listeners_test.cpp
deleted file mode 100644
index a7e2deaf6..000000000
--- 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 <gtest/gtest.h>
-
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-
-#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 "<serial> <source> <dest>\n".
- for (const std::string& line : android::base::Split(format_listeners(), "\n")) {
- std::vector<std::string> 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 31112485b..000000000
--- 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 <android-base/macros.h>
-
-// 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 cc3302d7b..000000000
--- a/adb/adb_test.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<!-- This test config file is auto-generated. -->
-<configuration description="Runs adbd_test.">
- <option name="test-suite-tag" value="apct" />
- <option name="test-suite-tag" value="apct-native" />
-
- <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
- </target_preparer>
-
- <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
- <option name="cleanup" value="true" />
- <option name="push" value="adbd_test->/data/local/tmp/adbd_test" />
- </target_preparer>
-
- <test class="com.android.tradefed.testtype.GTest" >
- <option name="native-test-device-path" value="/data/local/tmp" />
- <option name="module-name" value="adbd_test" />
- </test>
-
- <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
- <option name="mainline-module-package-name" value="com.google.android.adbd" />
- </object>
-</configuration>
diff --git a/adb/adb_trace.cpp b/adb/adb_trace.cpp
deleted file mode 100644
index cea24fe2f..000000000
--- a/adb/adb_trace.cpp
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "sysdeps.h"
-#include "adb_trace.h"
-
-#include <string>
-#include <unordered_map>
-#include <vector>
-
-#include <android-base/logging.h>
-#include <android-base/strings.h>
-
-#include "adb.h"
-
-#if !ADB_HOST
-#include <android-base/properties.h>
-#endif
-
-#if !ADB_HOST
-const char* adb_device_banner = "device";
-#if defined(__ANDROID__)
-static android::base::LogdLogger gLogdLogger;
-#endif
-#else
-const char* adb_device_banner = "host";
-#endif
-
-void AdbLogger(android::base::LogId id, android::base::LogSeverity severity,
- const char* tag, const char* file, unsigned int line,
- const char* message) {
- android::base::StderrLogger(id, severity, tag, file, line, message);
-#if defined(_WIN32)
- // stderr can be buffered on Windows (and setvbuf doesn't seem to work), so explicitly flush.
- fflush(stderr);
-#endif
-
-#if !ADB_HOST && defined(__ANDROID__)
- // Only print logs of INFO or higher to logcat, so that `adb logcat` with adbd tracing on
- // doesn't result in exponential logging.
- if (severity >= android::base::INFO) {
- gLogdLogger(id, severity, tag, file, line, message);
- }
-#endif
-}
-
-
-#if !ADB_HOST
-static std::string get_log_file_name() {
- struct tm now;
- time_t t;
- tzset();
- time(&t);
- localtime_r(&t, &now);
-
- char timestamp[PATH_MAX];
- strftime(timestamp, sizeof(timestamp), "%Y-%m-%d-%H-%M-%S", &now);
-
- return android::base::StringPrintf("/data/adb/adb-%s-%d", timestamp,
- getpid());
-}
-
-void start_device_log(void) {
- int fd = unix_open(get_log_file_name(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0640);
- if (fd == -1) {
- return;
- }
-
- // Redirect stdout and stderr to the log file.
- dup2(fd, STDOUT_FILENO);
- dup2(fd, STDERR_FILENO);
- fprintf(stderr, "--- adb starting (pid %d) ---\n", getpid());
- unix_close(fd);
-}
-#endif
-
-int adb_trace_mask;
-
-std::string get_trace_setting_from_env() {
- const char* setting = getenv("ADB_TRACE");
- if (setting == nullptr) {
- setting = "";
- }
-
- return std::string(setting);
-}
-
-std::string get_trace_setting() {
-#if ADB_HOST
- return get_trace_setting_from_env();
-#else
- return android::base::GetProperty("persist.adb.trace_mask", "");
-#endif
-}
-
-// Split the space separated list of tags from the trace setting and build the
-// trace mask from it. note that '1' and 'all' are special cases to enable all
-// tracing.
-//
-// adb's trace setting comes from the ADB_TRACE environment variable, whereas
-// adbd's comes from the system property persist.adb.trace_mask.
-static void setup_trace_mask() {
- const std::string trace_setting = get_trace_setting();
- if (trace_setting.empty()) {
- return;
- }
-
- std::unordered_map<std::string, int> 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<std::string> 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 3421a0296..000000000
--- 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 <android-base/logging.h>
-#include <android-base/stringprintf.h>
-
-/* 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 dec73bc2e..000000000
--- 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 <errno.h>
-#include <unistd.h>
-
-#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 b6c910a94..000000000
--- 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 <errno.h>
-#include <unistd.h>
-
-#include <android-base/unique_fd.h>
-
-#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<AdbCloser>;
-#else
-using unique_fd = android::base::unique_fd;
-#endif
-
-using android::base::borrowed_fd;
-
-template <typename T>
-int adb_close(const android::base::unique_fd_impl<T>&)
- __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 d1910f1c3..000000000
--- 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 <stdlib.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <algorithm>
-#include <vector>
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/parseint.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-
-#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 <pwd.h>
-#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<const uint8_t*>(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<char> 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 66cba121b..000000000
--- 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 <charconv>
-#include <condition_variable>
-#include <mutex>
-#include <string>
-#include <string_view>
-#include <type_traits>
-#include <vector>
-
-#include <android-base/macros.h>
-
-#include "adb.h"
-#include "adb_unique_fd.h"
-
-void close_stdin();
-
-bool getcwd(std::string* cwd);
-bool directory_exists(const std::string& path);
-
-// Return the user's home directory.
-std::string adb_get_homedir_path();
-
-// Return the adb user directory.
-std::string adb_get_android_dir_path();
-
-bool mkdirs(const std::string& path);
-
-std::string escape_arg(const std::string& s);
-
-std::string dump_hex(const void* ptr, size_t byte_count);
-std::string dump_header(const amessage* msg);
-std::string dump_packet(const char* name, const char* func, const apacket* p);
-
-std::string perror_str(const char* msg);
-
-[[noreturn]] void error_exit(const char* fmt, ...) __attribute__((__format__(__printf__, 1, 2)));
-[[noreturn]] void perror_exit(const char* fmt, ...) __attribute__((__format__(__printf__, 1, 2)));
-
-bool set_file_block_mode(borrowed_fd fd, bool block);
-
-// Given forward/reverse targets, returns true if they look sane. If an error is found, fills
-// |error| and returns false.
-// Currently this only checks "tcp:" targets. Additional checking could be added for other targets
-// if needed.
-bool forward_targets_are_valid(const std::string& source, const std::string& dest,
- std::string* error);
-
-// A thread-safe blocking queue.
-template <typename T>
-class BlockingQueue {
- std::mutex mutex;
- std::condition_variable cv;
- std::vector<T> queue;
-
- public:
- void Push(const T& t) {
- {
- std::unique_lock<std::mutex> lock(mutex);
- queue.push_back(t);
- }
- cv.notify_one();
- }
-
- template <typename Fn>
- void PopAll(Fn fn) {
- std::vector<T> popped;
-
- {
- std::unique_lock<std::mutex> 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 <typename T>
-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 cdca3aa32..000000000
--- 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 <windows.h>
-#include <userenv.h>
-#endif
-
-#include <string>
-
-#include <gtest/gtest.h>
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "sysdeps.h"
-
-#include <android-base/file.h>
-#include <android-base/macros.h>
-
-#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<uint64_t>(UINT32_MAX) + 1), false);
- TestParseUint("0" + std::to_string(static_cast<uint64_t>(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 585748c91..000000000
--- a/adb/adb_wifi.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <string>
-
-#include "adb.h"
-
-#if ADB_HOST
-
-void adb_wifi_init(void);
-void adb_wifi_pair_device(const std::string& host, const std::string& password,
- std::string& response);
-bool adb_wifi_is_known_host(const std::string& host);
-
-#else // !ADB_HOST
-
-struct AdbdAuthContext;
-
-void adbd_wifi_init(AdbdAuthContext* ctx);
-void adbd_wifi_secure_connect(atransport* t);
-
-#endif
diff --git a/adb/apex/Android.bp b/adb/apex/Android.bp
deleted file mode 100644
index ddb17dac1..000000000
--- 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 9cb072bcc..000000000
--- 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 c825b044a..000000000
--- a/adb/apex/apex_manifest.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "name": "com.android.adbd",
- "version": 309999900
-}
diff --git a/adb/apex/com.android.adbd.avbpubkey b/adb/apex/com.android.adbd.avbpubkey
deleted file mode 100644
index 06235bd1f..000000000
--- a/adb/apex/com.android.adbd.avbpubkey
+++ /dev/null
Binary files differ
diff --git a/adb/apex/com.android.adbd.pem b/adb/apex/com.android.adbd.pem
deleted file mode 100644
index 2c9a86079..000000000
--- 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 cdddc3fdf..000000000
--- a/adb/apex/com.android.adbd.pk8
+++ /dev/null
Binary files differ
diff --git a/adb/apex/com.android.adbd.x509.pem b/adb/apex/com.android.adbd.x509.pem
deleted file mode 100644
index bb85c1d11..000000000
--- 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 713197706..000000000
--- 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 4d0cf49a0..000000000
--- a/adb/benchmark_device.py
+++ /dev/null
@@ -1,156 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-import os
-import statistics
-import subprocess
-import tempfile
-import time
-
-import adb
-
-def lock_min(device):
- device.shell_nocheck(["""
- for x in /sys/devices/system/cpu/cpu?/cpufreq; do
- echo userspace > $x/scaling_governor
- cat $x/scaling_min_freq > $x/scaling_setspeed
- done
- """])
-
-def lock_max(device):
- device.shell_nocheck(["""
- for x in /sys/devices/system/cpu/cpu?/cpufreq; do
- echo userspace > $x/scaling_governor
- cat $x/scaling_max_freq > $x/scaling_setspeed
- done
- """])
-
-def unlock(device):
- device.shell_nocheck(["""
- for x in /sys/devices/system/cpu/cpu?/cpufreq; do
- echo ondemand > $x/scaling_governor
- echo sched > $x/scaling_governor
- echo schedutil > $x/scaling_governor
- done
- """])
-
-def harmonic_mean(xs):
- return 1.0 / statistics.mean([1.0 / x for x in xs])
-
-def analyze(name, speeds):
- median = statistics.median(speeds)
- mean = harmonic_mean(speeds)
- stddev = statistics.stdev(speeds)
- msg = "%s: %d runs: median %.2f MiB/s, mean %.2f MiB/s, stddev: %.2f MiB/s"
- print(msg % (name, len(speeds), median, mean, stddev))
-
-def benchmark_sink(device=None, size_mb=100):
- if device == None:
- device = adb.get_device()
-
- speeds = list()
- cmd = device.adb_cmd + ["raw", "sink:%d" % (size_mb * 1024 * 1024)]
-
- with tempfile.TemporaryFile() as tmpfile:
- tmpfile.truncate(size_mb * 1024 * 1024)
-
- for _ in range(0, 10):
- tmpfile.seek(0)
- begin = time.time()
- subprocess.check_call(cmd, stdin=tmpfile)
- end = time.time()
- speeds.append(size_mb / float(end - begin))
-
- analyze("sink %dMiB" % size_mb, speeds)
-
-def benchmark_source(device=None, size_mb=100):
- if device == None:
- device = adb.get_device()
-
- speeds = list()
- cmd = device.adb_cmd + ["raw", "source:%d" % (size_mb * 1024 * 1024)]
-
- with open(os.devnull, 'w') as devnull:
- for _ in range(0, 10):
- begin = time.time()
- subprocess.check_call(cmd, stdout=devnull)
- end = time.time()
- speeds.append(size_mb / float(end - begin))
-
- analyze("source %dMiB" % size_mb, speeds)
-
-def benchmark_push(device=None, file_size_mb=100):
- if device == None:
- device = adb.get_device()
-
- remote_path = "/dev/null"
- local_path = "/tmp/adb_benchmark_temp"
-
- with open(local_path, "wb") as f:
- f.truncate(file_size_mb * 1024 * 1024)
-
- speeds = list()
- for _ in range(0, 10):
- begin = time.time()
- device.push(local=local_path, remote=remote_path)
- end = time.time()
- speeds.append(file_size_mb / float(end - begin))
-
- analyze("push %dMiB" % file_size_mb, speeds)
-
-def benchmark_pull(device=None, file_size_mb=100):
- if device == None:
- device = adb.get_device()
-
- remote_path = "/data/local/tmp/adb_benchmark_temp"
- local_path = "/tmp/adb_benchmark_temp"
-
- device.shell(["dd", "if=/dev/zero", "of=" + remote_path, "bs=1m",
- "count=" + str(file_size_mb)])
- speeds = list()
- for _ in range(0, 10):
- begin = time.time()
- device.pull(remote=remote_path, local=local_path)
- end = time.time()
- speeds.append(file_size_mb / float(end - begin))
-
- analyze("pull %dMiB" % file_size_mb, speeds)
-
-def benchmark_shell(device=None, file_size_mb=100):
- if device == None:
- device = adb.get_device()
-
- speeds = list()
- for _ in range(0, 10):
- begin = time.time()
- device.shell(["dd", "if=/dev/zero", "bs=1m",
- "count=" + str(file_size_mb)])
- end = time.time()
- speeds.append(file_size_mb / float(end - begin))
-
- analyze("shell %dMiB" % file_size_mb, speeds)
-
-def main():
- device = adb.get_device()
- unlock(device)
- benchmark_sink(device)
- benchmark_source(device)
- benchmark_push(device)
- benchmark_pull(device)
-
-if __name__ == "__main__":
- main()
diff --git a/adb/brotli_utils.h b/adb/brotli_utils.h
deleted file mode 100644
index c5be73d0c..000000000
--- a/adb/brotli_utils.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <span>
-
-#include <brotli/decode.h>
-#include <brotli/encode.h>
-
-#include "types.h"
-
-enum class BrotliDecodeResult {
- Error,
- Done,
- NeedInput,
- MoreOutput,
-};
-
-struct BrotliDecoder {
- explicit BrotliDecoder(std::span<char> output_buffer)
- : output_buffer_(output_buffer),
- decoder_(BrotliDecoderCreateInstance(nullptr, nullptr, nullptr),
- BrotliDecoderDestroyInstance) {}
-
- void Append(Block&& block) { input_buffer_.append(std::move(block)); }
-
- BrotliDecodeResult Decode(std::span<char>* output) {
- size_t available_in = input_buffer_.front_size();
- const uint8_t* next_in = reinterpret_cast<const uint8_t*>(input_buffer_.front_data());
-
- size_t available_out = output_buffer_.size();
- uint8_t* next_out = reinterpret_cast<uint8_t*>(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<char>(output_buffer_.data(), bytes_emitted);
-
- switch (r) {
- case BROTLI_DECODER_RESULT_SUCCESS:
- return BrotliDecodeResult::Done;
- case BROTLI_DECODER_RESULT_ERROR:
- return BrotliDecodeResult::Error;
- case BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT:
- // Brotli guarantees as one of its invariants that if it returns NEEDS_MORE_INPUT,
- // it will consume the entire input buffer passed in, so we don't have to worry
- // about bytes left over in the front block with more input remaining.
- return BrotliDecodeResult::NeedInput;
- case BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT:
- return BrotliDecodeResult::MoreOutput;
- }
- }
-
- private:
- IOVector input_buffer_;
- std::span<char> output_buffer_;
- std::unique_ptr<BrotliDecoderState, void (*)(BrotliDecoderState*)> decoder_;
-};
-
-enum class BrotliEncodeResult {
- Error,
- Done,
- NeedInput,
- MoreOutput,
-};
-
-template <size_t OutputBlockSize>
-struct BrotliEncoder {
- explicit BrotliEncoder()
- : output_block_(OutputBlockSize),
- output_bytes_left_(OutputBlockSize),
- encoder_(BrotliEncoderCreateInstance(nullptr, nullptr, nullptr),
- BrotliEncoderDestroyInstance) {
- BrotliEncoderSetParameter(encoder_.get(), BROTLI_PARAM_QUALITY, 1);
- }
-
- void Append(Block input) { input_buffer_.append(std::move(input)); }
- void Finish() { finished_ = true; }
-
- BrotliEncodeResult Encode(Block* output) {
- output->clear();
- while (true) {
- size_t available_in = input_buffer_.front_size();
- const uint8_t* next_in = reinterpret_cast<const uint8_t*>(input_buffer_.front_data());
-
- size_t available_out = output_bytes_left_;
- uint8_t* next_out = reinterpret_cast<uint8_t*>(output_block_.data() +
- (OutputBlockSize - output_bytes_left_));
-
- BrotliEncoderOperation op = BROTLI_OPERATION_PROCESS;
- if (finished_) {
- op = BROTLI_OPERATION_FINISH;
- }
-
- if (!BrotliEncoderCompressStream(encoder_.get(), op, &available_in, &next_in,
- &available_out, &next_out, nullptr)) {
- return BrotliEncodeResult::Error;
- }
-
- size_t bytes_consumed = input_buffer_.front_size() - available_in;
- input_buffer_.drop_front(bytes_consumed);
-
- output_bytes_left_ = available_out;
-
- if (BrotliEncoderIsFinished(encoder_.get())) {
- output_block_.resize(OutputBlockSize - output_bytes_left_);
- *output = std::move(output_block_);
- return BrotliEncodeResult::Done;
- } else if (output_bytes_left_ == 0) {
- *output = std::move(output_block_);
- output_block_.resize(OutputBlockSize);
- output_bytes_left_ = OutputBlockSize;
- return BrotliEncodeResult::MoreOutput;
- } else if (input_buffer_.empty()) {
- return BrotliEncodeResult::NeedInput;
- }
- }
- }
-
- private:
- bool finished_ = false;
- IOVector input_buffer_;
- Block output_block_;
- size_t output_bytes_left_;
- std::unique_ptr<BrotliEncoderState, void (*)(BrotliEncoderState*)> encoder_;
-};
diff --git a/adb/bugreport_test.cpp b/adb/bugreport_test.cpp
deleted file mode 100644
index a6be20368..000000000
--- 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 <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include <android-base/strings.h>
-#include <android-base/test_utils.h>
-
-#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<const char*>& 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<OnStandardStreamsCallbackFunction> {
- 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<OnStandardStreamsCallbackFunction> WriteOnStdout(const std::string& output) {
- return MakeAction(new OnStandardStreamsCallbackAction(kStreamStdout, output));
-}
-
-// Matcher used to emulated StandardStreamsCallbackInterface.OnStderr(buffer,
-// length)
-Action<OnStandardStreamsCallbackFunction> WriteOnStderr(const std::string& output) {
- return MakeAction(new OnStandardStreamsCallbackAction(kStreamStderr, output));
-}
-
-typedef int CallbackDoneFunction(StandardStreamsCallbackInterface*);
-
-class CallbackDoneAction : public ActionInterface<CallbackDoneFunction> {
- 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<CallbackDoneFunction> 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<const char*>& 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 f724cb522..000000000
--- a/adb/client/adb_client.cpp
+++ /dev/null
@@ -1,416 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define TRACE_TAG ADB
-
-#include "sysdeps.h"
-#include "adb_client.h"
-
-#include <errno.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <condition_variable>
-#include <mutex>
-#include <optional>
-#include <string>
-#include <thread>
-#include <vector>
-
-#include <android-base/file.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-#include <android-base/thread_annotations.h>
-#include <cutils/sockets.h>
-
-#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<TransportId> 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<TransportId> transport_result = switch_socket_transport(fd.get(), error);
- if (!transport_result) {
- return -1;
- }
-
- if (transport) {
- *transport = *transport_result;
- }
- }
-
- if (!SendProtocolString(fd.get(), service)) {
- *error = perror_str("write failure during connection");
- return -1;
- }
-
- if (!adb_status(fd.get(), error)) {
- return -1;
- }
-
- D("_adb_connect: return fd %d", fd.get());
- return fd.release();
-}
-
-bool adb_kill_server() {
- D("adb_kill_server");
- std::string reason;
- unique_fd fd;
- if (!socket_spec_connect(&fd, __adb_server_socket_spec, nullptr, nullptr, &reason)) {
- fprintf(stderr, "cannot connect to daemon at %s: %s\n", __adb_server_socket_spec,
- reason.c_str());
- return true;
- }
-
- if (!SendProtocolString(fd.get(), "host:kill")) {
- fprintf(stderr, "error: write failure during connection: %s\n", strerror(errno));
- return false;
- }
-
- // The server might send OKAY, so consume that.
- char buf[4];
- ReadFdExactly(fd.get(), buf, 4);
- // Now that no more data is expected, wait for socket orderly shutdown or error, indicating
- // server death.
- ReadOrderlyShutdown(fd.get());
- return true;
-}
-
-int adb_connect(std::string_view service, std::string* error) {
- return adb_connect(nullptr, service, error);
-}
-
-#if defined(__linux__)
-std::optional<std::string> 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<std::string> 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<char**>(__adb_argv),
- const_cast<char**>(__adb_envp)) == -1) {
- LOG(ERROR) << "failed to exec newer version at " << server_path;
- }
-
- // Fall-through to restarting the server.
- }
- }
- }
-#endif
-
- fprintf(stderr, "adb server version (%d) doesn't match this client (%d); killing...\n",
- version, ADB_SERVER_VERSION);
- adb_kill_server();
- goto start_server;
- }
- }
-
- return true;
-}
-
-bool adb_check_server_version(std::string* error) {
- // Only check the version once per process, since this isn't atomic anyway.
- static std::once_flag once;
- static bool result;
- static std::string* err;
- std::call_once(once, []() {
- err = new std::string();
- result = __adb_check_server_version(err);
- });
- *error = *err;
- return result;
-}
-
-int adb_connect(TransportId* transport, std::string_view service, std::string* error,
- bool force_switch_device) {
- LOG(DEBUG) << "adb_connect: service: " << service;
-
- // Query the adb server's version.
- if (!adb_check_server_version(error)) {
- return -1;
- }
-
- // if the command is start-server, we are done.
- if (service == "host:start-server") {
- return 0;
- }
-
- unique_fd fd(_adb_connect(service, transport, error, force_switch_device));
- if (fd == -1) {
- D("_adb_connect error: %s", error->c_str());
- } else if(fd == -2) {
- fprintf(stderr, "* daemon still not running\n");
- }
- D("adb_connect: return fd %d", fd.get());
-
- return fd.release();
-}
-
-bool adb_command(const std::string& service) {
- std::string error;
- unique_fd fd(adb_connect(service, &error));
- if (fd < 0) {
- fprintf(stderr, "error: %s\n", error.c_str());
- return false;
- }
-
- if (!adb_status(fd.get(), &error)) {
- fprintf(stderr, "error: %s\n", error.c_str());
- return false;
- }
-
- ReadOrderlyShutdown(fd.get());
- return true;
-}
-
-bool adb_query(const std::string& service, std::string* result, std::string* error) {
- D("adb_query: %s", service.c_str());
- unique_fd fd(adb_connect(service, error));
- if (fd < 0) {
- return false;
- }
-
- result->clear();
- if (!ReadProtocolString(fd.get(), result, error)) {
- return false;
- }
-
- ReadOrderlyShutdown(fd.get());
- return true;
-}
-
-std::string format_host_command(const char* command) {
- if (__adb_transport_id) {
- return android::base::StringPrintf("host-transport-id:%" PRIu64 ":%s", __adb_transport_id,
- command);
- } else if (__adb_serial) {
- return android::base::StringPrintf("host-serial:%s:%s", __adb_serial, command);
- }
-
- const char* prefix = "host";
- if (__adb_transport == kTransportUsb) {
- prefix = "host-usb";
- } else if (__adb_transport == kTransportLocal) {
- prefix = "host-local";
- }
- return android::base::StringPrintf("%s:%s", prefix, command);
-}
-
-bool adb_get_feature_set(FeatureSet* feature_set, std::string* error) {
- static FeatureSet* features = nullptr;
- if (!features) {
- std::string result;
- if (adb_query(format_host_command("features"), &result, error)) {
- features = new FeatureSet(StringToFeatureSet(result));
- }
- }
- if (features) {
- *feature_set = *features;
- return true;
- }
- feature_set->clear();
- return false;
-}
diff --git a/adb/client/adb_client.h b/adb/client/adb_client.h
deleted file mode 100644
index 1c6cde77d..000000000
--- a/adb/client/adb_client.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <functional>
-#include <optional>
-#include <string>
-
-#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 <serial> with a <serial>
-// that does not designate an emulator).
-int adb_send_emulator_command(int argc, const char* _Nonnull* _Nonnull argv,
- const char* _Nullable serial);
-
-// Reads a standard adb status response (OKAY|FAIL) and returns true in the
-// event of OKAY, false in the event of FAIL or protocol error.
-bool adb_status(borrowed_fd fd, std::string* _Nonnull error);
-
-// Create a host command corresponding to selected transport type/serial.
-std::string format_host_command(const char* _Nonnull command);
-
-// Get the feature set of the current preferred transport.
-bool adb_get_feature_set(FeatureSet* _Nonnull feature_set, std::string* _Nonnull error);
-
-#if defined(__linux__)
-// Get the path of a file containing the path to the server executable, if the socket spec set via
-// adb_set_socket_spec is a local one.
-std::optional<std::string> 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<void(
- const char* _Nonnull service_name, const char* _Nonnull ip_address, uint16_t port)>;
-
-// 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 f2de0d23d..000000000
--- a/adb/client/adb_install.cpp
+++ /dev/null
@@ -1,995 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "adb_install.h"
-
-#include <fcntl.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <algorithm>
-#include <string>
-#include <string_view>
-#include <vector>
-
-#include <android-base/file.h>
-#include <android-base/parsebool.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-
-#include "adb.h"
-#include "adb_client.h"
-#include "adb_unique_fd.h"
-#include "adb_utils.h"
-#include "client/file_sync_client.h"
-#include "commandline.h"
-#include "fastdeploy.h"
-#include "incremental.h"
-
-using namespace std::literals;
-
-static constexpr int kFastDeployMinApi = 24;
-
-namespace {
-
-enum InstallMode {
- INSTALL_DEFAULT,
- INSTALL_PUSH,
- INSTALL_STREAM,
- INSTALL_INCREMENTAL,
-};
-
-enum class CmdlineOption { None, Enable, Disable };
-}
-
-static bool can_use_feature(const char* feature) {
- FeatureSet features;
- std::string error;
- if (!adb_get_feature_set(&features, &error)) {
- fprintf(stderr, "error: %s\n", error.c_str());
- return false;
- }
- return CanUseFeature(features, feature);
-}
-
-static InstallMode best_install_mode() {
- if (can_use_feature(kFeatureCmd)) {
- return INSTALL_STREAM;
- }
- return INSTALL_PUSH;
-}
-
-static bool is_apex_supported() {
- return can_use_feature(kFeatureApex);
-}
-
-static bool is_abb_exec_supported() {
- return can_use_feature(kFeatureAbbExec);
-}
-
-static int pm_command(int argc, const char** argv) {
- std::string cmd = "pm";
-
- while (argc-- > 0) {
- cmd += " " + escape_arg(*argv++);
- }
-
- return send_shell_command(cmd);
-}
-
-static int uninstall_app_streamed(int argc, const char** argv) {
- // 'adb uninstall' takes the same arguments as 'cmd package uninstall' on device
- std::string cmd = "cmd package";
- while (argc-- > 0) {
- // deny the '-k' option until the remaining data/cache can be removed with adb/UI
- if (strcmp(*argv, "-k") == 0) {
- printf("The -k option uninstalls the application while retaining the "
- "data/cache.\n"
- "At the moment, there is no way to remove the remaining data.\n"
- "You will have to reinstall the application with the same "
- "signature, and fully "
- "uninstall it.\n"
- "If you truly wish to continue, execute 'adb shell cmd package "
- "uninstall -k'.\n");
- return EXIT_FAILURE;
- }
- cmd += " " + escape_arg(*argv++);
- }
-
- return send_shell_command(cmd);
-}
-
-static int uninstall_app_legacy(int argc, const char** argv) {
- /* if the user choose the -k option, we refuse to do it until devices are
- out with the option to uninstall the remaining data somehow (adb/ui) */
- for (int i = 1; i < argc; i++) {
- if (!strcmp(argv[i], "-k")) {
- printf("The -k option uninstalls the application while retaining the "
- "data/cache.\n"
- "At the moment, there is no way to remove the remaining data.\n"
- "You will have to reinstall the application with the same "
- "signature, and fully "
- "uninstall it.\n"
- "If you truly wish to continue, execute 'adb shell pm uninstall "
- "-k'\n.");
- return EXIT_FAILURE;
- }
- }
-
- /* 'adb uninstall' takes the same arguments as 'pm uninstall' on device */
- return pm_command(argc, argv);
-}
-
-int uninstall_app(int argc, const char** argv) {
- if (best_install_mode() == INSTALL_PUSH) {
- return uninstall_app_legacy(argc, argv);
- }
- return uninstall_app_streamed(argc, argv);
-}
-
-static void read_status_line(int fd, char* buf, size_t count) {
- count--;
- while (count > 0) {
- int len = adb_read(fd, buf, count);
- if (len <= 0) {
- break;
- }
-
- buf += len;
- count -= len;
- }
- *buf = '\0';
-}
-
-static unique_fd send_command(const std::vector<std::string>& 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<const char*> 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<std::string> 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<uint64_t>(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<const char*> apk_file = {argv[last_apk]};
- std::string apk_dest = "/data/local/tmp/" + android::base::Basename(argv[last_apk]);
- argv[last_apk] = apk_dest.c_str(); /* destination name, not source location */
-
- if (use_fastdeploy) {
- auto metadata = extract_metadata(apk_file[0]);
- if (metadata.has_value()) {
- auto patchFd = apply_patch_on_device(apk_dest.c_str());
- int status = stream_patch(apk_file[0], std::move(metadata.value()), std::move(patchFd));
-
- result = pm_command(argc, argv);
- delete_device_file(apk_dest);
-
- return status;
- }
- }
-
- if (do_sync_push(apk_file, apk_dest.c_str(), false, true)) {
- result = pm_command(argc, argv);
- delete_device_file(apk_dest);
- }
-
- return result;
-}
-
-template <class TimePoint>
-static int ms_between(TimePoint start, TimePoint end) {
- return std::chrono::duration_cast<std::chrono::milliseconds>(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<InstallMode, std::optional<InstallMode>> 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<std::string> 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<const char*> parse_install_mode(std::vector<const char*> argv,
- InstallMode* install_mode,
- CmdlineOption* incremental_request,
- bool* incremental_wait) {
- *install_mode = INSTALL_DEFAULT;
- *incremental_request = CmdlineOption::None;
- *incremental_wait = false;
-
- std::vector<const char*> 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<const char*> parse_fast_deploy_mode(
- std::vector<const char*> argv, bool* use_fastdeploy,
- FastDeploy_AgentUpdateStrategy* agent_update_strategy) {
- *use_fastdeploy = false;
- *agent_update_strategy = FastDeploy_AgentUpdateDifferentVersion;
-
- std::vector<const char*> 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<std::string> 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<std::string> 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<std::string> 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<std::string> 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<int> session_ids;
-
- // Valid session, now create the individual sessions and stream the APKs
- int success = EXIT_FAILURE;
- std::vector<std::string> 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<std::string> individual_apex_cmd_args;
- if (apex_found) {
- individual_apex_cmd_args = individual_cmd_args;
- individual_apex_cmd_args.emplace_back("--apex");
- }
-
- std::vector<std::string> 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<std::string> 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<std::string> cmd_args = {
- install_cmd,
- "install-write",
- "-S",
- std::to_string(sb.st_size),
- session_id_str,
- android::base::StringPrintf("%d_%s", i, android::base::Basename(file).c_str()),
- "-",
- };
-
- unique_fd local_fd(adb_open(split.c_str(), O_RDONLY | O_CLOEXEC));
- if (local_fd < 0) {
- fprintf(stderr, "adb: failed to open %s: %s\n", split.c_str(), strerror(errno));
- goto finalize_multi_package_session;
- }
-
- std::string error;
- unique_fd remote_fd = send_command(cmd_args, &error);
- if (remote_fd < 0) {
- fprintf(stderr, "adb: connect error for write: %s\n", error.c_str());
- goto finalize_multi_package_session;
- }
-
- if (!copy_to_file(local_fd.get(), remote_fd.get())) {
- fprintf(stderr, "adb: failed to write %s: %s\n", split.c_str(), strerror(errno));
- goto finalize_multi_package_session;
- }
-
- read_status_line(remote_fd.get(), buf, sizeof(buf));
-
- if (strncmp("Success", buf, 7)) {
- fprintf(stderr, "adb: failed to write %s\n", split.c_str());
- fputs(buf, stderr);
- goto finalize_multi_package_session;
- }
- }
- add_session_cmd_args.push_back(std::to_string(session_id));
- }
-
- {
- unique_fd fd = send_command(add_session_cmd_args, &error);
- if (fd < 0) {
- fprintf(stderr, "adb: connect error for install-add-session: %s\n", error.c_str());
- goto finalize_multi_package_session;
- }
- read_status_line(fd.get(), buf, sizeof(buf));
- }
-
- if (strncmp("Success", buf, 7)) {
- fprintf(stderr, "adb: failed to link sessions (%s)\n",
- android::base::Join(add_session_cmd_args, " ").c_str());
- fputs(buf, stderr);
- goto finalize_multi_package_session;
- }
-
- // no failures means we can proceed with the assumption of success
- success = 0;
-
-finalize_multi_package_session:
- // Commit session if we streamed everything okay; otherwise abandon
- std::vector<std::string> 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<std::string> 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) + " </dev/null");
-}
diff --git a/adb/client/adb_install.h b/adb/client/adb_install.h
deleted file mode 100644
index 99466041d..000000000
--- a/adb/client/adb_install.h
+++ /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.
- */
-
-#pragma once
-
-#include <string>
-
-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 fa7102811..000000000
--- a/adb/client/adb_wifi.cpp
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "adb_wifi.h"
-
-#include <fstream>
-#include <random>
-#include <thread>
-
-#include <adb/crypto/key.h>
-#include <adb/crypto/x509_generator.h>
-#include <android-base/file.h>
-#include <android-base/parsenetaddress.h>
-#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<bool> is_valid_;
- PeerInfo peer_info_;
-
- static void OnResult(const PeerInfo* peer_info, void* opaque) {
- CHECK(opaque);
- auto* p = reinterpret_cast<PairingResultWaiter*>(opaque);
- {
- std::lock_guard<std::mutex> 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<uint8_t> stringToUint8(const std::string& str) {
- auto* p8 = reinterpret_cast<const uint8_t*>(str.data());
- return std::vector<uint8_t>(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<TemporaryFile> temp_file(new TemporaryFile(adb_get_android_dir_path()));
- if (temp_file->fd == -1) {
- PLOG(ERROR) << "Failed to open [" << temp_file->path << "] for writing";
- return false;
- }
-
- if (!known_hosts.SerializeToFileDescriptor(temp_file->fd)) {
- LOG(ERROR) << "Unable to write out adb_knowns_hosts";
- return false;
- }
- temp_file->DoNotRemove();
- std::string temp_file_name(temp_file->path);
- temp_file.reset();
-
- // Replace the existing adb_known_hosts with the new one
- if (!SafeReplaceFile(path, temp_file_name.c_str())) {
- LOG(ERROR) << "Failed to replace old adb_known_hosts";
- adb_unlink(temp_file_name.c_str());
- return false;
- }
- chmod(path.c_str(), S_IRUSR | S_IWUSR | S_IRGRP);
-
- return true;
-}
-
-bool adb_wifi_is_known_host(const std::string& host) {
- std::string path = get_user_known_hosts_path();
- if (path.empty()) {
- PLOG(ERROR) << "Error getting user known hosts filename";
- return false;
- }
-
- adb::proto::AdbKnownHosts known_hosts;
- if (!load_known_hosts_from_file(path, known_hosts)) {
- return false;
- }
-
- for (const auto& host_info : known_hosts.host_infos()) {
- if (host == host_info.guid()) {
- return true;
- }
- }
- return false;
-}
-
-void adb_wifi_pair_device(const std::string& host, const std::string& password,
- std::string& response) {
- // Check the address for a valid address and port.
- std::string parsed_host;
- std::string err;
- int port = -1;
- if (!android::base::ParseNetAddress(host, &parsed_host, &port, nullptr, &err)) {
- response = "Failed to parse address for pairing: " + err;
- return;
- }
- if (port <= 0 || port > 65535) {
- response = "Invalid port while parsing address [" + host + "]";
- return;
- }
-
- auto priv_key = adb_auth_get_user_privkey();
- auto x509_cert = GenerateX509Certificate(priv_key.get());
- if (!x509_cert) {
- LOG(ERROR) << "Unable to create X509 certificate for pairing";
- return;
- }
- auto cert_str = X509ToPEMString(x509_cert.get());
- auto priv_str = Key::ToPEMString(priv_key.get());
-
- // Send our public key on pairing success
- PeerInfo system_info = {};
- system_info.type = ADB_RSA_PUB_KEY;
- std::string public_key = adb_auth_get_userkey();
- CHECK_LE(public_key.size(), sizeof(system_info.data) - 1); // -1 for null byte
- memcpy(system_info.data, public_key.data(), public_key.size());
-
- auto pswd8 = stringToUint8(password);
- auto cert8 = stringToUint8(cert_str);
- auto priv8 = stringToUint8(priv_str);
-
- auto client = PairingClient::Create(pswd8, system_info, cert8, priv8);
- if (client == nullptr) {
- response = "Failed: unable to create pairing client.";
- return;
- }
-
- PairingResultWaiter waiter;
- std::unique_lock<std::mutex> lock(waiter.mutex_);
- if (!client->Start(host, waiter.OnResult, &waiter)) {
- response = "Failed: Unable to start pairing client.";
- return;
- }
- waiter.cv_.wait(lock, [&]() { return waiter.is_valid_.has_value(); });
- if (!*(waiter.is_valid_)) {
- response = "Failed: Wrong password or connection was dropped.";
- return;
- }
-
- if (waiter.peer_info_.type != ADB_DEVICE_GUID) {
- response = "Failed: Successfully paired but server returned unknown response=";
- response += waiter.peer_info_.type;
- return;
- }
-
- std::string device_guid = reinterpret_cast<const char*>(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 35264c76f..000000000
--- a/adb/client/auth.cpp
+++ /dev/null
@@ -1,557 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define TRACE_TAG AUTH
-
-#include <dirent.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#if defined(__linux__)
-#include <sys/inotify.h>
-#endif
-
-#include <map>
-#include <mutex>
-#include <set>
-#include <string>
-
-#include <adb/crypto/rsa_2048_key.h>
-#include <adb/crypto/x509_generator.h>
-#include <adb/tls/adb_ca_list.h>
-#include <adb/tls/tls_connection.h>
-#include <android-base/errors.h>
-#include <android-base/file.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-#include <crypto_utils/android_pubkey.h>
-#include <openssl/base64.h>
-#include <openssl/evp.h>
-#include <openssl/objects.h>
-#include <openssl/pem.h>
-#include <openssl/rsa.h>
-#include <openssl/sha.h>
-
-#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<std::string, std::shared_ptr<RSA>>& g_keys =
- *new std::map<std::string, std::shared_ptr<RSA>>;
-static std::map<int, std::string>& g_monitored_paths = *new std::map<int, std::string>;
-
-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<FILE, decltype(&fclose)> 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<unsigned char*>(&result[0]));
- OPENSSL_free(pubkey);
- return result;
-}
-
-static std::shared_ptr<RSA> read_key_file(const std::string& file) {
- std::unique_ptr<FILE, decltype(&fclose)> 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<RSA>(key, RSA_free);
-}
-
-static bool load_key(const std::string& file) {
- std::shared_ptr<RSA> key = read_key_file(file);
- if (!key) {
- return false;
- }
-
- std::lock_guard<std::mutex> lock(g_keys_mutex);
- std::string fingerprint = hash_key(key.get());
- if (g_keys.find(fingerprint) != g_keys.end()) {
- LOG(INFO) << "ignoring already-loaded key: " << file;
- } else {
- LOG(INFO) << "Loaded fingerprint=[" << SHA256BitsToHexString(fingerprint) << "]";
- g_keys[fingerprint] = std::move(key);
- }
- return true;
-}
-
-static bool load_keys(const std::string& path, bool allow_dir = true) {
- LOG(INFO) << "load_keys '" << path << "'...";
-
- struct stat st;
- if (stat(path.c_str(), &st) != 0) {
- PLOG(ERROR) << "failed to stat '" << path << "'";
- return false;
- }
-
- if (S_ISREG(st.st_mode)) {
- return load_key(path);
- } else if (S_ISDIR(st.st_mode)) {
- if (!allow_dir) {
- // inotify isn't recursive. It would break expectations to load keys in nested
- // directories but not monitor them for new keys.
- LOG(WARNING) << "refusing to recurse into directory '" << path << "'";
- return false;
- }
-
- std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(path.c_str()), closedir);
- if (!dir) {
- PLOG(ERROR) << "failed to open directory '" << path << "'";
- return false;
- }
-
- bool result = false;
- while (struct dirent* dent = readdir(dir.get())) {
- std::string name = dent->d_name;
-
- // We can't use dent->d_type here because it's not available on Windows.
- if (name == "." || name == "..") {
- continue;
- }
-
- if (!android::base::EndsWith(name, ".adb_key")) {
- LOG(INFO) << "skipping non-adb_key '" << path << "/" << name << "'";
- continue;
- }
-
- result |= load_key((path + OS_PATH_SEPARATOR + name));
- }
- return result;
- }
-
- LOG(ERROR) << "unexpected type for '" << path << "': 0x" << std::hex << st.st_mode;
- return false;
-}
-
-static std::string get_user_key_path() {
- return adb_get_android_dir_path() + OS_PATH_SEPARATOR + "adbkey";
-}
-
-static bool load_userkey() {
- std::string path = get_user_key_path();
- if (path.empty()) {
- PLOG(ERROR) << "Error getting user key filename";
- return false;
- }
-
- struct stat buf;
- if (stat(path.c_str(), &buf) == -1) {
- LOG(INFO) << "User key '" << path << "' does not exist...";
- if (!generate_key(path)) {
- LOG(ERROR) << "Failed to generate new key";
- return false;
- }
- }
-
- return load_key(path);
-}
-
-static std::set<std::string> get_vendor_keys() {
- const char* adb_keys_path = getenv("ADB_VENDOR_KEYS");
- if (adb_keys_path == nullptr) {
- return std::set<std::string>();
- }
-
- std::set<std::string> result;
- for (const auto& path : android::base::Split(adb_keys_path, ENV_PATH_SEPARATOR_STR)) {
- result.emplace(path);
- }
- return result;
-}
-
-std::deque<std::shared_ptr<RSA>> adb_auth_get_private_keys() {
- std::deque<std::shared_ptr<RSA>> result;
-
- // Copy all the currently known keys.
- std::lock_guard<std::mutex> 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<const uint8_t*>(token), token_size,
- reinterpret_cast<uint8_t*>(&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<RSA> privkey = read_key_file(path);
- if (!privkey) {
- return false;
- }
- return CalculatePublicKey(out, privkey.get());
-}
-
-bssl::UniquePtr<EVP_PKEY> 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> rsa_privkey = read_key_file(path);
- if (!rsa_privkey) {
- return nullptr;
- }
-
- bssl::UniquePtr<EVP_PKEY> 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<inotify_event*>(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<std::string>& 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<RSA> 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<RSA> 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<std::mutex> 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(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 8ca44e8b5..000000000
--- a/adb/client/bugreport.cpp
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define TRACE_TAG ADB
-
-#include "sysdeps.h"
-
-#include "bugreport.h"
-
-#include <string>
-#include <vector>
-
-#include <android-base/file.h>
-#include <android-base/strings.h>
-
-#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<const char*> srcs{src_file_.c_str()};
- SetLineMessage("pulling");
- status_ =
- br_->DoSyncPull(srcs, destination.c_str(), false, line_message_.c_str()) ? 0 : 1;
- if (status_ != 0) {
- fprintf(stderr,
- "Bug report finished but could not be copied to '%s'.\n"
- "Try to run 'adb pull %s <directory>'\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<std::string> invalid_lines_;
-
- // Whether PROGRESS_LINES should be interpreted as progress.
- bool show_progress_;
-
- // Overall process of the operation, as returned by Done().
- int status_;
-
- // Temporary buffer containing the characters read since the last newline (\n).
- std::string line_;
-
- // Last displayed progress.
- // Since dumpstate progress can recede, only forward progress should be displayed
- int last_progress_percentage_;
-
- DISALLOW_COPY_AND_ASSIGN(BugreportStandardStreamsCallback);
-};
-
-int Bugreport::DoIt(int argc, const char** argv) {
- if (argc > 2) error_exit("usage: adb bugreport [PATH]");
-
- // Gets bugreportz version.
- std::string bugz_stdout, bugz_stderr;
- DefaultStandardStreamsCallback version_callback(&bugz_stdout, &bugz_stderr);
- int status = SendShellCommand("bugreportz -v", false, &version_callback);
- std::string bugz_version = android::base::Trim(bugz_stderr);
- std::string bugz_output = android::base::Trim(bugz_stdout);
-
- if (status != 0 || bugz_version.empty()) {
- D("'bugreportz' -v results: status=%d, stdout='%s', stderr='%s'", status,
- bugz_output.c_str(), bugz_version.c_str());
- if (argc == 1) {
- // Device does not support bugreportz: if called as 'adb bugreport', just falls out to
- // the flat-file version.
- fprintf(stderr,
- "Failed to get bugreportz version, which is only available on devices "
- "running Android 7.0 or later.\nTrying a plain-text bug report instead.\n");
- return SendShellCommand("bugreport", false);
- }
-
- // But if user explicitly asked for a zipped bug report, fails instead (otherwise calling
- // 'bugreport' would generate a lot of output the user might not be prepared to handle).
- fprintf(stderr,
- "Failed to get bugreportz version: 'bugreportz -v' returned '%s' (code %d).\n"
- "If the device does not run Android 7.0 or above, try 'adb bugreport' instead.\n",
- bugz_output.c_str(), status);
- return status != 0 ? status : -1;
- }
-
- std::string dest_file, dest_dir;
-
- if (argc == 1) {
- // No args - use current directory
- if (!getcwd(&dest_dir)) {
- perror("adb: getcwd failed");
- return 1;
- }
- } else {
- // Check whether argument is a directory or file
- if (directory_exists(argv[1])) {
- dest_dir = argv[1];
- } else {
- dest_file = argv[1];
- }
- }
-
- if (dest_file.empty()) {
- // Uses a default value until device provides the proper name
- dest_file = "bugreport.zip";
- } else {
- if (!android::base::EndsWithIgnoreCase(dest_file, ".zip")) {
- dest_file += ".zip";
- }
- }
-
- bool show_progress = true;
- std::string bugz_command = "bugreportz -p";
- if (bugz_version == "1.0") {
- // 1.0 does not support progress notifications, so print a disclaimer
- // message instead.
- fprintf(stderr,
- "Bugreport is in progress and it could take minutes to complete.\n"
- "Please be patient and do not cancel or disconnect your device "
- "until it completes.\n");
- show_progress = false;
- bugz_command = "bugreportz";
- }
- BugreportStandardStreamsCallback bugz_callback(dest_dir, dest_file, show_progress, this);
- return SendShellCommand(bugz_command, false, &bugz_callback);
-}
-
-void Bugreport::UpdateProgress(const std::string& message, int progress_percentage) {
- line_printer_.Print(
- android::base::StringPrintf("[%3d%%] %s", progress_percentage, message.c_str()),
- LinePrinter::INFO);
-}
-
-int Bugreport::SendShellCommand(const std::string& command, bool disable_shell_protocol,
- StandardStreamsCallbackInterface* callback) {
- return send_shell_command(command, disable_shell_protocol, callback);
-}
-
-bool Bugreport::DoSyncPull(const std::vector<const char*>& srcs, const char* dst, bool copy_attrs,
- const char* name) {
- return do_sync_pull(srcs, dst, copy_attrs, name);
-}
diff --git a/adb/client/bugreport.h b/adb/client/bugreport.h
deleted file mode 100644
index 413439b74..000000000
--- 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 <vector>
-
-#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<const char*>& 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 ad4e21c4d..000000000
--- a/adb/client/commandline.cpp
+++ /dev/null
@@ -1,2066 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define TRACE_TAG ADB
-
-#include "sysdeps.h"
-
-#include <assert.h>
-#include <ctype.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <stdarg.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <iostream>
-
-#include <memory>
-#include <string>
-#include <thread>
-#include <vector>
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/parseint.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-
-#if !defined(_WIN32)
-#include <signal.h>
-#include <sys/ioctl.h>
-#include <termios.h>
-#include <unistd.h>
-#endif
-
-#include "adb.h"
-#include "adb_auth.h"
-#include "adb_client.h"
-#include "adb_install.h"
-#include "adb_io.h"
-#include "adb_unique_fd.h"
-#include "adb_utils.h"
-#include "bugreport.h"
-#include "client/file_sync_client.h"
-#include "commandline.h"
-#include "fastdeploy.h"
-#include "incremental_server.h"
-#include "services.h"
-#include "shell_protocol.h"
-#include "sysdeps/chrono.h"
-
-extern int gListenAll;
-
-DefaultStandardStreamsCallback DEFAULT_STANDARD_STREAMS_CALLBACK(nullptr, nullptr);
-
-static std::string product_file(const std::string& file) {
- const char* ANDROID_PRODUCT_OUT = getenv("ANDROID_PRODUCT_OUT");
- if (ANDROID_PRODUCT_OUT == nullptr) {
- error_exit("product directory not specified; set $ANDROID_PRODUCT_OUT");
- }
- return std::string{ANDROID_PRODUCT_OUT} + OS_PATH_SEPARATOR_STR + file;
-}
-
-static void help() {
- fprintf(stdout, "%s\n", adb_version().c_str());
- // clang-format off
- fprintf(stdout,
- "global options:\n"
- " -a listen on all network interfaces, not just localhost\n"
- " -d use USB device (error if multiple devices connected)\n"
- " -e use TCP/IP device (error if multiple TCP/IP devices available)\n"
- " -s SERIAL use device with given serial (overrides $ANDROID_SERIAL)\n"
- " -t ID use device with given transport id\n"
- " -H name of adb server host [default=localhost]\n"
- " -P port of adb server [default=5037]\n"
- " -L SOCKET listen on given socket for adb server [default=tcp:localhost:5037]\n"
- "\n"
- "general commands:\n"
- " devices [-l] list connected devices (-l for long output)\n"
- " help show this help message\n"
- " version show version num\n"
- "\n"
- "networking:\n"
- " connect HOST[:PORT] connect to a device via TCP/IP [default port=5555]\n"
- " disconnect [HOST[:PORT]]\n"
- " disconnect from given TCP/IP device [default port=5555], or all\n"
- " pair HOST[:PORT] pair with a device for secure TCP/IP communication\n"
- " forward --list list all forward socket connections\n"
- " forward [--no-rebind] LOCAL REMOTE\n"
- " forward socket connection using:\n"
- " tcp:<port> (<local> may be \"tcp:0\" to pick any open port)\n"
- " localabstract:<unix domain socket name>\n"
- " localreserved:<unix domain socket name>\n"
- " localfilesystem:<unix domain socket name>\n"
- " dev:<character device name>\n"
- " jdwp:<process pid> (remote only)\n"
- " acceptfd:<fd> (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:<port> (<remote> may be \"tcp:0\" to pick any open port)\n"
- " localabstract:<unix domain socket name>\n"
- " localreserved:<unix domain socket name>\n"
- " localfilesystem:<unix domain socket name>\n"
- " reverse --remove REMOTE remove specific reverse socket connection\n"
- " reverse --remove-all remove all reverse socket connections from device\n"
- "\n"
- "file transfer:\n"
- " push [--sync] [-zZ] LOCAL... REMOTE\n"
- " copy local files/directories to device\n"
- " --sync: only push files that are newer on the host than the device\n"
- " -z: enable compression\n"
- " -Z: disable compression\n"
- " pull [-azZ] REMOTE... LOCAL\n"
- " copy files/dirs from device\n"
- " -a: preserve file timestamp and mode\n"
- " -z: enable compression\n"
- " -Z: disable compression\n"
- " sync [-lzZ] [all|data|odm|oem|product|system|system_ext|vendor]\n"
- " sync a local build from $ANDROID_PRODUCT_OUT to the device (default all)\n"
- " -l: list files that would be copied, but don't copy them\n"
- " -z: enable compression\n"
- " -Z: disable compression\n"
- "\n"
- "shell:\n"
- " shell [-e ESCAPE] [-n] [-Tt] [-x] [COMMAND...]\n"
- " run remote shell command (interactive shell if no command given)\n"
- " -e: choose escape character, or \"none\"; default '~'\n"
- " -n: don't read from stdin\n"
- " -T: disable pty allocation\n"
- " -t: allocate a pty if on a tty (-tt: force pty allocation)\n"
- " -x: disable remote exit codes and stdout/stderr separation\n"
- " emu COMMAND run emulator console command\n"
- "\n"
- "app installation (see also `adb shell cmd package help`):\n"
- " install [-lrtsdg] [--instant] PACKAGE\n"
- " push a single package to the device and install it\n"
- " install-multiple [-lrtsdpg] [--instant] PACKAGE...\n"
- " push multiple APKs to the device for a single package and install them\n"
- " install-multi-package [-lrtsdpg] [--instant] PACKAGE...\n"
- " push one or more packages to the device and install them atomically\n"
- " -r: replace existing application\n"
- " -t: allow test packages\n"
- " -d: allow version code downgrade (debuggable packages only)\n"
- " -p: partial application install (install-multiple only)\n"
- " -g: grant all runtime permissions\n"
- " --abi ABI: override platform's default ABI\n"
- " --instant: cause the app to be installed as an ephemeral install app\n"
- " --no-streaming: always push APK to device and invoke Package Manager as separate steps\n"
- " --streaming: force streaming APK directly into Package Manager\n"
- " --fastdeploy: use fast deploy\n"
- " --no-fastdeploy: prevent use of fast deploy\n"
- " --force-agent: force update of deployment agent when using fast deploy\n"
- " --date-check-agent: update deployment agent when local version is newer and using fast deploy\n"
- " --version-check-agent: update deployment agent when local version has different version code and using fast deploy\n"
-#ifndef _WIN32
- " --local-agent: locate agent files from local source build (instead of SDK location)\n"
-#endif
- " (See also `adb shell pm help` for more options.)\n"
- //TODO--installlog <filename>
- " uninstall [-k] PACKAGE\n"
- " remove this app package from the device\n"
- " '-k': keep the data and cache directories\n"
- "\n"
- "debugging:\n"
- " bugreport [PATH]\n"
- " write bugreport to given PATH [default=bugreport.zip];\n"
- " if PATH is a directory, the bug report is saved in that directory.\n"
- " devices that don't support zipped bug reports output to stdout.\n"
- " jdwp list pids of processes hosting a JDWP transport\n"
- " logcat show device log (logcat --help for more)\n"
- "\n"
- "security:\n"
- " disable-verity disable dm-verity checking on userdebug builds\n"
- " enable-verity re-enable dm-verity checking on userdebug builds\n"
- " keygen FILE\n"
- " generate adb public/private key; private key stored in FILE,\n"
- "\n"
- "scripting:\n"
- " wait-for[-TRANSPORT]-STATE\n"
- " wait for device to be in the given state\n"
- " STATE: device, recovery, rescue, sideload, bootloader, or disconnect\n"
- " TRANSPORT: usb, local, or any [default=any]\n"
- " get-state print offline | bootloader | device\n"
- " get-serialno print <serial-number>\n"
- " get-devpath print <device-path>\n"
- " remount [-R]\n"
- " remount partitions read-write. if a reboot is required, -R will\n"
- " will automatically reboot the device.\n"
- " reboot [bootloader|recovery|sideload|sideload-auto-reboot]\n"
- " reboot the device; defaults to booting system image but\n"
- " supports bootloader and recovery too. sideload reboots\n"
- " into recovery and automatically starts sideload mode,\n"
- " sideload-auto-reboot is the same but reboots after sideloading.\n"
- " sideload OTAPACKAGE sideload the given full OTA package\n"
- " root restart adbd with root permissions\n"
- " unroot restart adbd without root permissions\n"
- " usb restart adbd listening on USB\n"
- " tcpip PORT restart adbd listening on TCP on PORT\n"
- "\n"
- "internal debugging:\n"
- " start-server ensure that there is a server running\n"
- " kill-server kill the server if it is running\n"
- " reconnect kick connection from host side to force reconnect\n"
- " reconnect device kick connection from device side to force reconnect\n"
- " reconnect offline reset offline/unauthorized devices to force reconnect\n"
- "\n"
- "environment variables:\n"
- " $ADB_TRACE\n"
- " comma-separated list of debug info to log:\n"
- " all,adb,sockets,packets,rwx,usb,sync,sysdeps,transport,jdwp\n"
- " $ADB_VENDOR_KEYS colon-separated list of keys (files or directories)\n"
- " $ANDROID_SERIAL serial number to connect to (see -s)\n"
- " $ANDROID_LOG_TAGS tags to be used by logcat (see logcat --help)\n"
- " $ADB_LOCAL_TRANSPORT_MAX_PORT max emulator scan port (default 5585, 16 emus)\n"
- );
- // clang-format on
-}
-
-#if defined(_WIN32)
-
-// Implemented in sysdeps_win32.cpp.
-void stdin_raw_init();
-void stdin_raw_restore();
-
-#else
-static termios g_saved_terminal_state;
-
-static void stdin_raw_init() {
- if (tcgetattr(STDIN_FILENO, &g_saved_terminal_state)) return;
-
- termios tio;
- if (tcgetattr(STDIN_FILENO, &tio)) return;
-
- cfmakeraw(&tio);
-
- // No timeout but request at least one character per read.
- tio.c_cc[VTIME] = 0;
- tio.c_cc[VMIN] = 1;
-
- tcsetattr(STDIN_FILENO, TCSAFLUSH, &tio);
-}
-
-static void stdin_raw_restore() {
- tcsetattr(STDIN_FILENO, TCSAFLUSH, &g_saved_terminal_state);
-}
-#endif
-
-int read_and_dump(borrowed_fd fd, bool use_shell_protocol,
- StandardStreamsCallbackInterface* callback) {
- int exit_code = 0;
- if (fd < 0) return exit_code;
-
- std::unique_ptr<ShellProtocol> protocol;
- int length = 0;
-
- char raw_buffer[BUFSIZ];
- char* buffer_ptr = raw_buffer;
- if (use_shell_protocol) {
- protocol = std::make_unique<ShellProtocol>(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<uint8_t>(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<char> 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<ShellProtocol>& 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<const HANDLE>(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<ShellProtocol> 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<StdinReadArgs> args(reinterpret_cast<StdinReadArgs*>(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<std::string> 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<ShellProtocol>(args->write_fd);
- }
-
- if (raw_stdin) stdin_raw_init();
-
-#if !defined(_WIN32)
- // Ensure our process is notified if the local window size changes.
- // We use sigaction(2) to ensure that the SA_RESTART flag is not set,
- // because the whole reason we're sending signals is to unblock the read(2)!
- // That also means we don't need to do anything in the signal handler:
- // the side effect of delivering the signal is all we need.
- struct sigaction sa;
- memset(&sa, 0, sizeof(sa));
- sa.sa_handler = [](int) {};
- sa.sa_flags = 0;
- sigaction(SIGWINCH, &sa, nullptr);
-
- // Now block SIGWINCH in this thread (the main thread) and all threads spawned
- // from it. The stdin read thread will unblock this signal to ensure that it's
- // the thread that receives the signal.
- sigset_t mask;
- sigemptyset(&mask);
- sigaddset(&mask, SIGWINCH);
- pthread_sigmask(SIG_BLOCK, &mask, nullptr);
-#endif
-
- // TODO: combine read_and_dump with stdin_read_thread to make life simpler?
- std::thread(stdin_read_thread_loop, args).detach();
- int exit_code = read_and_dump(fd, use_shell_protocol);
-
- // TODO: properly exit stdin_read_thread_loop and close |fd|.
-
- // TODO: we should probably install signal handlers for this.
- // TODO: can we use atexit? even on Windows?
- if (raw_stdin) stdin_raw_restore();
-
- return exit_code;
-}
-
-static int adb_shell(int argc, const char** argv) {
- FeatureSet features;
- std::string error_message;
- if (!adb_get_feature_set(&features, &error_message)) {
- fprintf(stderr, "error: %s\n", error_message.c_str());
- return 1;
- }
-
- enum PtyAllocationMode { kPtyAuto, kPtyNo, kPtyYes, kPtyDefinitely };
-
- // Defaults.
- char escape_char = '~'; // -e
- bool use_shell_protocol = CanUseFeature(features, kFeatureShell2); // -x
- PtyAllocationMode tty = use_shell_protocol ? kPtyAuto : kPtyDefinitely; // -t/-T
-
- // Parse shell-specific command-line options.
- argv[0] = "adb shell"; // So getopt(3) error messages start "adb shell".
-#ifdef _WIN32
- // fixes "adb shell -l" crash on Windows, b/37284906
- __argv = const_cast<char**>(argv);
-#endif
- optind = 1; // argv[0] is always "shell", so set `optind` appropriately.
- int opt;
- while ((opt = getopt(argc, const_cast<char**>(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<const char*>(argv + optind, argv + argc), ' ');
- }
-
- std::string service_string = ShellServiceString(use_shell_protocol, shell_type_arg, command);
- return RemoteShell(use_shell_protocol, shell_type_arg, escape_char, command.empty(),
- service_string);
-}
-
-static int adb_abb(int argc, const char** argv) {
- FeatureSet features;
- std::string error_message;
- if (!adb_get_feature_set(&features, &error_message)) {
- fprintf(stderr, "error: %s\n", error_message.c_str());
- return 1;
- }
-
- if (!CanUseFeature(features, kFeatureAbb)) {
- error_exit("abb is not supported by the device");
- }
-
- optind = 1; // argv[0] is always "abb", so set `optind` appropriately.
-
- // Defaults.
- constexpr char escape_char = '~'; // -e
- constexpr bool use_shell_protocol = true;
- constexpr auto shell_type_arg = kShellServiceArgRaw;
- constexpr bool empty_command = false;
-
- std::vector<const char*> 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<int>(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<int64_t>(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<int>(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<double>(xfer) / (sb.st_size ? sb.st_size : 1),
- static_cast<int>(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<int64_t>(sb.st_size)) {
- fprintf(stderr,
- "adb: failed to read block %" PRId64 " at offset %" PRId64 ", past end %" PRId64
- "\n",
- block, offset, static_cast<int64_t>(sb.st_size));
- return -1;
- }
-
- size_t to_write = SIDELOAD_HOST_BLOCK_SIZE;
- if ((offset + SIDELOAD_HOST_BLOCK_SIZE) > static_cast<int64_t>(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<int>(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 <ppp options>
- *
- */
-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 <adb service name> [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<std::chrono::milliseconds> timeout = std::nullopt) {
- std::vector<std::string> components = android::base::Split(service, "-");
- if (components.size() < 3 || components.size() > 4) {
- fprintf(stderr, "adb: couldn't parse 'wait-for' command: %s\n", service);
- return false;
- }
-
- TransportType t;
- adb_get_transport(&t, nullptr, nullptr);
-
- // Was the caller vague about what they'd like us to wait for?
- // If so, check they weren't more specific in their choice of transport type.
- if (components.size() == 3) {
- auto it = components.begin() + 2;
- if (t == kTransportUsb) {
- components.insert(it, "usb");
- } else if (t == kTransportLocal) {
- components.insert(it, "local");
- } else {
- components.insert(it, "any");
- }
- } else if (components[2] != "any" && components[2] != "local" && components[2] != "usb") {
- fprintf(stderr, "adb: unknown type %s; expected 'any', 'local', or 'usb'\n",
- components[2].c_str());
- return false;
- }
-
- if (components[3] != "any" && components[3] != "bootloader" && components[3] != "device" &&
- components[3] != "recovery" && components[3] != "rescue" && components[3] != "sideload" &&
- components[3] != "disconnect") {
- fprintf(stderr,
- "adb: unknown state %s; "
- "expected 'any', 'bootloader', 'device', 'recovery', 'rescue', 'sideload', or "
- "'disconnect'\n",
- components[3].c_str());
- return false;
- }
-
- std::string cmd = format_host_command(android::base::Join(components, "-").c_str());
- if (timeout) {
- std::thread([timeout]() {
- std::this_thread::sleep_for(*timeout);
- fprintf(stderr, "timeout expired while waiting for device\n");
- _exit(1);
- }).detach();
- }
- return adb_command(cmd);
-}
-
-static bool adb_root(const char* command) {
- std::string error;
-
- TransportId transport_id;
- unique_fd fd(adb_connect(&transport_id, android::base::StringPrintf("%s:", command), &error));
- if (fd < 0) {
- fprintf(stderr, "adb: unable to connect for %s: %s\n", command, error.c_str());
- return false;
- }
-
- // Figure out whether we actually did anything.
- char buf[256];
- char* cur = buf;
- ssize_t bytes_left = sizeof(buf);
- while (bytes_left > 0) {
- ssize_t bytes_read = adb_read(fd, cur, bytes_left);
- if (bytes_read == 0) {
- break;
- } else if (bytes_read < 0) {
- fprintf(stderr, "adb: error while reading for %s: %s\n", command, strerror(errno));
- return false;
- }
- cur += bytes_read;
- bytes_left -= bytes_read;
- }
-
- if (bytes_left == 0) {
- fprintf(stderr, "adb: unexpected output length for %s\n", command);
- return false;
- }
-
- fwrite(buf, 1, sizeof(buf) - bytes_left, stdout);
- fflush(stdout);
- if (cur != buf && strstr(buf, "restarting") == nullptr) {
- return true;
- }
-
- // Wait for the device to go away.
- TransportType previous_type;
- const char* previous_serial;
- TransportId previous_id;
- adb_get_transport(&previous_type, &previous_serial, &previous_id);
-
- adb_set_transport(kTransportAny, nullptr, transport_id);
- wait_for_device("wait-for-disconnect");
-
- // Wait for the device to come back.
- // If we were using a specific transport ID, there's nothing we can wait for.
- if (previous_id == 0) {
- adb_set_transport(previous_type, previous_serial, 0);
- wait_for_device("wait-for-device", 6000ms);
- }
-
- return true;
-}
-
-int send_shell_command(const std::string& command, bool disable_shell_protocol,
- StandardStreamsCallbackInterface* callback) {
- unique_fd fd;
- bool use_shell_protocol = false;
-
- while (true) {
- bool attempt_connection = true;
-
- // Use shell protocol if it's supported and the caller doesn't explicitly
- // disable it.
- if (!disable_shell_protocol) {
- FeatureSet features;
- std::string error;
- if (adb_get_feature_set(&features, &error)) {
- use_shell_protocol = CanUseFeature(features, kFeatureShell2);
- } else {
- // Device was unreachable.
- attempt_connection = false;
- }
- }
-
- if (attempt_connection) {
- std::string error;
- std::string service_string = ShellServiceString(use_shell_protocol, "", command);
-
- fd.reset(adb_connect(service_string, &error));
- if (fd >= 0) {
- break;
- }
- }
-
- fprintf(stderr, "- waiting for device -\n");
- if (!wait_for_device("wait-for-device")) {
- return 1;
- }
- }
-
- return read_and_dump(fd.get(), use_shell_protocol, callback);
-}
-
-static int logcat(int argc, const char** argv) {
- char* log_tags = getenv("ANDROID_LOG_TAGS");
- std::string quoted = escape_arg(log_tags == nullptr ? "" : log_tags);
-
- std::string cmd = "export ANDROID_LOG_TAGS=\"" + quoted + "\"; exec logcat";
-
- if (!strcmp(argv[0], "longcat")) {
- cmd += " -v long";
- }
-
- --argc;
- ++argv;
- while (argc-- > 0) {
- cmd += " " + escape_arg(*argv++);
- }
-
- return send_shell_command(cmd);
-}
-
-static void write_zeros(int bytes, borrowed_fd fd) {
- int old_stdin_mode = -1;
- int old_stdout_mode = -1;
- std::vector<char> buf(bytes);
-
- D("write_zeros(%d) -> %d", bytes, fd.get());
-
- stdinout_raw_prologue(-1, fd.get(), old_stdin_mode, old_stdout_mode);
-
- if (fd == STDOUT_FILENO) {
- fwrite(buf.data(), 1, bytes, stdout);
- fflush(stdout);
- } else {
- adb_write(fd, buf.data(), bytes);
- }
-
- stdinout_raw_prologue(-1, fd.get(), old_stdin_mode, old_stdout_mode);
-
- D("write_zeros() finished");
-}
-
-static int backup(int argc, const char** argv) {
- fprintf(stdout, "WARNING: adb backup is deprecated and may be removed in a future release\n");
-
- const char* filename = "backup.ab";
-
- /* find, extract, and use any -f argument */
- for (int i = 1; i < argc; i++) {
- if (!strcmp("-f", argv[i])) {
- if (i == argc - 1) error_exit("backup -f passed with no filename");
- filename = argv[i+1];
- for (int j = i+2; j <= argc; ) {
- argv[i++] = argv[j++];
- }
- argc -= 2;
- argv[argc] = nullptr;
- }
- }
-
- // Bare "adb backup" or "adb backup -f filename" are not valid invocations ---
- // a list of packages is required.
- if (argc < 2) error_exit("backup either needs a list of packages or -all/-shared");
-
- adb_unlink(filename);
- unique_fd outFd(adb_creat(filename, 0640));
- if (outFd < 0) {
- fprintf(stderr, "adb: backup unable to create file '%s': %s\n", filename, strerror(errno));
- return EXIT_FAILURE;
- }
-
- std::string cmd = "backup:";
- --argc;
- ++argv;
- while (argc-- > 0) {
- cmd += " " + escape_arg(*argv++);
- }
-
- D("backup. filename=%s cmd=%s", filename, cmd.c_str());
- std::string error;
- unique_fd fd(adb_connect(cmd, &error));
- if (fd < 0) {
- fprintf(stderr, "adb: unable to connect for backup: %s\n", error.c_str());
- return EXIT_FAILURE;
- }
-
- fprintf(stdout, "Now unlock your device and confirm the backup operation...\n");
- fflush(stdout);
-
- copy_to_file(fd.get(), outFd.get());
- return EXIT_SUCCESS;
-}
-
-static int restore(int argc, const char** argv) {
- fprintf(stdout, "WARNING: adb restore is deprecated and may be removed in a future release\n");
-
- if (argc != 2) error_exit("restore requires an argument");
-
- const char* filename = argv[1];
- unique_fd tarFd(adb_open(filename, O_RDONLY));
- if (tarFd < 0) {
- fprintf(stderr, "adb: unable to open file %s: %s\n", filename, strerror(errno));
- return -1;
- }
-
- std::string error;
- unique_fd fd(adb_connect("restore:", &error));
- if (fd < 0) {
- fprintf(stderr, "adb: unable to connect for restore: %s\n", error.c_str());
- return -1;
- }
-
- fprintf(stdout, "Now unlock your device and confirm the restore operation.\n");
- fflush(stdout);
-
- copy_to_file(tarFd.get(), fd.get());
-
- // Provide an in-band EOD marker in case the archive file is malformed
- write_zeros(512 * 2, fd);
-
- // Wait until the other side finishes, or it'll get sent SIGHUP.
- copy_to_file(fd.get(), STDOUT_FILENO);
- return 0;
-}
-
-static void parse_push_pull_args(const char** arg, int narg, std::vector<const char*>* srcs,
- const char** dst, bool* copy_attrs, bool* sync, bool* compressed) {
- *copy_attrs = false;
- const char* adb_compression = getenv("ADB_COMPRESSION");
- if (adb_compression && strcmp(adb_compression, "0") == 0) {
- *compressed = false;
- }
-
- srcs->clear();
- bool ignore_flags = false;
- while (narg > 0) {
- if (ignore_flags || *arg[0] != '-') {
- srcs->push_back(*arg);
- } else {
- if (!strcmp(*arg, "-p")) {
- // Silently ignore for backwards compatibility.
- } else if (!strcmp(*arg, "-a")) {
- *copy_attrs = true;
- } else if (!strcmp(*arg, "-z")) {
- if (compressed != nullptr) {
- *compressed = true;
- }
- } else if (!strcmp(*arg, "-Z")) {
- if (compressed != nullptr) {
- *compressed = false;
- }
- } else if (!strcmp(*arg, "--sync")) {
- if (sync != nullptr) {
- *sync = true;
- }
- } else if (!strcmp(*arg, "--")) {
- ignore_flags = true;
- } else {
- error_exit("unrecognized option '%s'", *arg);
- }
- }
- ++arg;
- --narg;
- }
-
- if (srcs->size() > 1) {
- *dst = srcs->back();
- srcs->pop_back();
- }
-}
-
-static int adb_connect_command(const std::string& command, TransportId* transport = nullptr) {
- std::string error;
- unique_fd fd(adb_connect(transport, command, &error));
- if (fd < 0) {
- fprintf(stderr, "error: %s\n", error.c_str());
- return 1;
- }
- read_and_dump(fd);
- return 0;
-}
-
-static int adb_connect_command_bidirectional(const std::string& command) {
- std::string error;
- unique_fd fd(adb_connect(command, &error));
- if (fd < 0) {
- fprintf(stderr, "error: %s\n", error.c_str());
- return 1;
- }
-
- static constexpr auto forward = [](int src, int sink, bool exit_on_end) {
- char buf[4096];
- while (true) {
- int rc = adb_read(src, buf, sizeof(buf));
- if (rc == 0) {
- if (exit_on_end) {
- exit(0);
- } else {
- adb_shutdown(sink, SHUT_WR);
- }
- return;
- } else if (rc < 0) {
- perror_exit("read failed");
- }
- if (!WriteFdExactly(sink, buf, rc)) {
- perror_exit("write failed");
- }
- }
- };
-
- std::thread read(forward, fd.get(), STDOUT_FILENO, true);
- std::thread write(forward, STDIN_FILENO, fd.get(), false);
- read.join();
- write.join();
- return 0;
-}
-
-static int adb_query_command(const std::string& command) {
- std::string result;
- std::string error;
- if (!adb_query(command, &result, &error)) {
- fprintf(stderr, "error: %s\n", error.c_str());
- return 1;
- }
- printf("%s\n", result.c_str());
- return 0;
-}
-
-// Disallow stdin, stdout, and stderr.
-static bool _is_valid_ack_reply_fd(const int ack_reply_fd) {
-#ifdef _WIN32
- const HANDLE ack_reply_handle = cast_int_to_handle(ack_reply_fd);
- return (GetStdHandle(STD_INPUT_HANDLE) != ack_reply_handle) &&
- (GetStdHandle(STD_OUTPUT_HANDLE) != ack_reply_handle) &&
- (GetStdHandle(STD_ERROR_HANDLE) != ack_reply_handle);
-#else
- return ack_reply_fd > 2;
-#endif
-}
-
-static bool _is_valid_os_fd(int fd) {
- // Disallow invalid FDs and stdin/out/err as well.
- if (fd < 3) {
- return false;
- }
-#ifdef _WIN32
- auto handle = (HANDLE)fd;
- DWORD info = 0;
- if (GetHandleInformation(handle, &info) == 0) {
- return false;
- }
-#else
- int flags = fcntl(fd, F_GETFD);
- if (flags == -1) {
- return false;
- }
-#endif
- return true;
-}
-
-int adb_commandline(int argc, const char** argv) {
- bool no_daemon = false;
- bool is_daemon = false;
- bool is_server = false;
- int r;
- TransportType transport_type = kTransportAny;
- int ack_reply_fd = -1;
-
-#if !defined(_WIN32)
- // We'd rather have EPIPE than SIGPIPE.
- signal(SIGPIPE, SIG_IGN);
-#endif
-
- const char* server_host_str = nullptr;
- const char* server_port_str = nullptr;
- const char* server_socket_str = nullptr;
-
- // We need to check for -d and -e before we look at $ANDROID_SERIAL.
- const char* serial = nullptr;
- TransportId transport_id = 0;
-
- while (argc > 0) {
- if (!strcmp(argv[0], "server")) {
- is_server = true;
- } else if (!strcmp(argv[0], "nodaemon")) {
- no_daemon = true;
- } else if (!strcmp(argv[0], "fork-server")) {
- /* this is a special flag used only when the ADB client launches the ADB Server */
- is_daemon = true;
- } else if (!strcmp(argv[0], "--reply-fd")) {
- if (argc < 2) error_exit("--reply-fd requires an argument");
- const char* reply_fd_str = argv[1];
- argc--;
- argv++;
- ack_reply_fd = strtol(reply_fd_str, nullptr, 10);
- if (!_is_valid_ack_reply_fd(ack_reply_fd)) {
- fprintf(stderr, "adb: invalid reply fd \"%s\"\n", reply_fd_str);
- return 1;
- }
- } else if (!strncmp(argv[0], "-s", 2)) {
- if (isdigit(argv[0][2])) {
- serial = argv[0] + 2;
- } else {
- if (argc < 2 || argv[0][2] != '\0') error_exit("-s requires an argument");
- serial = argv[1];
- argc--;
- argv++;
- }
- } else if (!strncmp(argv[0], "-t", 2)) {
- const char* id;
- if (isdigit(argv[0][2])) {
- id = argv[0] + 2;
- } else {
- id = argv[1];
- argc--;
- argv++;
- }
- transport_id = strtoll(id, const_cast<char**>(&id), 10);
- if (*id != '\0') {
- error_exit("invalid transport id");
- }
- } else if (!strcmp(argv[0], "-d")) {
- transport_type = kTransportUsb;
- } else if (!strcmp(argv[0], "-e")) {
- transport_type = kTransportLocal;
- } else if (!strcmp(argv[0], "-a")) {
- gListenAll = 1;
- } else if (!strncmp(argv[0], "-H", 2)) {
- if (argv[0][2] == '\0') {
- if (argc < 2) error_exit("-H requires an argument");
- server_host_str = argv[1];
- argc--;
- argv++;
- } else {
- server_host_str = argv[0] + 2;
- }
- } else if (!strncmp(argv[0], "-P", 2)) {
- if (argv[0][2] == '\0') {
- if (argc < 2) error_exit("-P requires an argument");
- server_port_str = argv[1];
- argc--;
- argv++;
- } else {
- server_port_str = argv[0] + 2;
- }
- } else if (!strcmp(argv[0], "-L")) {
- if (argc < 2) error_exit("-L requires an argument");
- server_socket_str = argv[1];
- argc--;
- argv++;
- } else {
- /* out of recognized modifiers and flags */
- break;
- }
- argc--;
- argv++;
- }
-
- if ((server_host_str || server_port_str) && server_socket_str) {
- error_exit("-L is incompatible with -H or -P");
- }
-
- // If -L, -H, or -P are specified, ignore environment variables.
- // Otherwise, prefer ADB_SERVER_SOCKET over ANDROID_ADB_SERVER_ADDRESS/PORT.
- if (!server_host_str && !server_port_str && !server_socket_str) {
- server_socket_str = getenv("ADB_SERVER_SOCKET");
- }
-
- if (!server_socket_str) {
- // tcp:1234 and tcp:localhost:1234 are different with -a, so don't default to localhost
- server_host_str = server_host_str ? server_host_str : getenv("ANDROID_ADB_SERVER_ADDRESS");
-
- int server_port = DEFAULT_ADB_PORT;
- server_port_str = server_port_str ? server_port_str : getenv("ANDROID_ADB_SERVER_PORT");
- if (server_port_str && strlen(server_port_str) > 0) {
- if (!android::base::ParseInt(server_port_str, &server_port, 1, 65535)) {
- error_exit(
- "$ANDROID_ADB_SERVER_PORT must be a positive number less than 65535: "
- "got \"%s\"",
- server_port_str);
- }
- }
-
- int rc;
- char* temp;
- if (server_host_str) {
- rc = asprintf(&temp, "tcp:%s:%d", server_host_str, server_port);
- } else {
- rc = asprintf(&temp, "tcp:%d", server_port);
- }
- if (rc < 0) {
- LOG(FATAL) << "failed to allocate server socket specification";
- }
- server_socket_str = temp;
- }
-
- adb_set_socket_spec(server_socket_str);
-
- // If none of -d, -e, or -s were specified, try $ANDROID_SERIAL.
- if (transport_type == kTransportAny && serial == nullptr) {
- serial = getenv("ANDROID_SERIAL");
- }
-
- adb_set_transport(transport_type, serial, transport_id);
-
- if (is_server) {
- if (no_daemon || is_daemon) {
- if (is_daemon && (ack_reply_fd == -1)) {
- fprintf(stderr, "reply fd for adb server to client communication not specified.\n");
- return 1;
- }
- r = adb_server_main(is_daemon, server_socket_str, ack_reply_fd);
- } else {
- r = launch_server(server_socket_str);
- }
- if (r) {
- fprintf(stderr,"* could not start server *\n");
- }
- return r;
- }
-
- if (argc == 0) {
- help();
- return 1;
- }
-
- /* handle wait-for-* prefix */
- if (!strncmp(argv[0], "wait-for-", strlen("wait-for-"))) {
- const char* service = argv[0];
-
- if (!wait_for_device(service)) {
- return 1;
- }
-
- // Allow a command to be run after wait-for-device,
- // e.g. 'adb wait-for-device shell'.
- if (argc == 1) {
- return 0;
- }
-
- /* Fall through */
- argc--;
- argv++;
- }
-
- /* adb_connect() commands */
- if (!strcmp(argv[0], "devices")) {
- const char *listopt;
- if (argc < 2) {
- listopt = "";
- } else if (argc == 2 && !strcmp(argv[1], "-l")) {
- listopt = argv[1];
- } else {
- error_exit("adb devices [-l]");
- }
-
- std::string query = android::base::StringPrintf("host:%s%s", argv[0], listopt);
- std::string error;
- if (!adb_check_server_version(&error)) {
- error_exit("failed to check server version: %s", error.c_str());
- }
- printf("List of devices attached\n");
- return adb_query_command(query);
- }
- else if (!strcmp(argv[0], "connect")) {
- if (argc != 2) error_exit("usage: adb connect HOST[:PORT]");
-
- std::string query = android::base::StringPrintf("host:connect:%s", argv[1]);
- return adb_query_command(query);
- }
- else if (!strcmp(argv[0], "disconnect")) {
- if (argc > 2) error_exit("usage: adb disconnect [HOST[:PORT]]");
-
- std::string query = android::base::StringPrintf("host:disconnect:%s",
- (argc == 2) ? argv[1] : "");
- return adb_query_command(query);
- } else if (!strcmp(argv[0], "abb")) {
- return adb_abb(argc, argv);
- } else if (!strcmp(argv[0], "pair")) {
- if (argc != 2) error_exit("usage: adb pair <host>[:<port>]");
-
- std::string password;
- printf("Enter pairing code: ");
- fflush(stdout);
- if (!std::getline(std::cin, password) || password.empty()) {
- error_exit("No pairing code provided");
- }
- std::string query =
- android::base::StringPrintf("host:pair:%s:%s", password.c_str(), argv[1]);
-
- return adb_query_command(query);
- } else if (!strcmp(argv[0], "emu")) {
- return adb_send_emulator_command(argc, argv, serial);
- } else if (!strcmp(argv[0], "shell")) {
- return adb_shell(argc, argv);
- } else if (!strcmp(argv[0], "exec-in") || !strcmp(argv[0], "exec-out")) {
- int exec_in = !strcmp(argv[0], "exec-in");
-
- if (argc < 2) error_exit("usage: adb %s command", argv[0]);
-
- std::string cmd = "exec:";
- cmd += argv[1];
- argc -= 2;
- argv += 2;
- while (argc-- > 0) {
- cmd += " " + escape_arg(*argv++);
- }
-
- std::string error;
- unique_fd fd(adb_connect(cmd, &error));
- if (fd < 0) {
- fprintf(stderr, "error: %s\n", error.c_str());
- return -1;
- }
-
- if (exec_in) {
- copy_to_file(STDIN_FILENO, fd.get());
- } else {
- copy_to_file(fd.get(), STDOUT_FILENO);
- }
- return 0;
- } else if (!strcmp(argv[0], "kill-server")) {
- return adb_kill_server() ? 0 : 1;
- } else if (!strcmp(argv[0], "sideload")) {
- if (argc != 2) error_exit("sideload requires an argument");
- if (adb_sideload_install(argv[1], false /* rescue_mode */)) {
- return 1;
- } else {
- return 0;
- }
- } else if (!strcmp(argv[0], "rescue")) {
- // adb rescue getprop
- // adb rescue getprop <prop>
- // adb rescue install <filename>
- // adb rescue wipe userdata
- if (argc < 2) error_exit("rescue requires at least one argument");
- if (!strcmp(argv[1], "getprop")) {
- if (argc == 2) {
- return adb_connect_command("rescue-getprop:");
- }
- if (argc == 3) {
- return adb_connect_command(
- android::base::StringPrintf("rescue-getprop:%s", argv[2]));
- }
- error_exit("invalid rescue getprop arguments");
- } else if (!strcmp(argv[1], "install")) {
- if (argc != 3) error_exit("rescue install requires two arguments");
- if (adb_sideload_install(argv[2], true /* rescue_mode */) != 0) {
- return 1;
- }
- } else if (!strcmp(argv[1], "wipe")) {
- if (argc != 3 || strcmp(argv[2], "userdata") != 0) {
- error_exit("invalid rescue wipe arguments");
- }
- return adb_wipe_devices();
- } else {
- error_exit("invalid rescue argument");
- }
- return 0;
- } else if (!strcmp(argv[0], "tcpip")) {
- if (argc != 2) error_exit("tcpip requires an argument");
- int port;
- if (!android::base::ParseInt(argv[1], &port, 1, 65535)) {
- error_exit("tcpip: invalid port: %s", argv[1]);
- }
- return adb_connect_command(android::base::StringPrintf("tcpip:%d", port));
- } else if (!strcmp(argv[0], "remount")) {
- FeatureSet features;
- std::string error;
- if (!adb_get_feature_set(&features, &error)) {
- fprintf(stderr, "error: %s\n", error.c_str());
- return 1;
- }
-
- if (CanUseFeature(features, kFeatureRemountShell)) {
- std::vector<const char*> 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 <host-prefix> 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 <local>
- 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 <local> <remote>
- 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 <local> <remote>
- if (argc != 2) error_exit("forward takes two arguments");
- if (forward_targets_are_valid(argv[0], argv[1], &error_message)) {
- cmd = std::string("forward:") + argv[0] + ";" + argv[1];
- }
- }
-
- if (!error_message.empty()) {
- error_exit("error: %s", error_message.c_str());
- }
-
- unique_fd fd(adb_connect(nullptr, host_prefix + cmd, &error_message, true));
- if (fd < 0 || !adb_status(fd.get(), &error_message)) {
- error_exit("error: %s", error_message.c_str());
- }
-
- // Server or device may optionally return a resolved TCP port number.
- std::string resolved_port;
- if (ReadProtocolString(fd, &resolved_port, &error_message) && !resolved_port.empty()) {
- printf("%s\n", resolved_port.c_str());
- }
-
- ReadOrderlyShutdown(fd);
- return 0;
- }
- /* do_sync_*() commands */
- else if (!strcmp(argv[0], "ls")) {
- if (argc != 2) error_exit("ls requires an argument");
- return do_sync_ls(argv[1]) ? 0 : 1;
- } else if (!strcmp(argv[0], "push")) {
- bool copy_attrs = false;
- bool sync = false;
- bool compressed = true;
- std::vector<const char*> srcs;
- const char* dst = nullptr;
-
- parse_push_pull_args(&argv[1], argc - 1, &srcs, &dst, &copy_attrs, &sync, &compressed);
- if (srcs.empty() || !dst) error_exit("push requires an argument");
- return do_sync_push(srcs, dst, sync, compressed) ? 0 : 1;
- } else if (!strcmp(argv[0], "pull")) {
- bool copy_attrs = false;
- bool compressed = true;
- std::vector<const char*> srcs;
- const char* dst = ".";
-
- parse_push_pull_args(&argv[1], argc - 1, &srcs, &dst, &copy_attrs, nullptr, &compressed);
- if (srcs.empty()) error_exit("pull requires an argument");
- return do_sync_pull(srcs, dst, copy_attrs, compressed) ? 0 : 1;
- } else if (!strcmp(argv[0], "install")) {
- if (argc < 2) error_exit("install requires an argument");
- return install_app(argc, argv);
- } else if (!strcmp(argv[0], "install-multiple")) {
- if (argc < 2) error_exit("install-multiple requires an argument");
- return install_multiple_app(argc, argv);
- } else if (!strcmp(argv[0], "install-multi-package")) {
- if (argc < 2) error_exit("install-multi-package requires an argument");
- return install_multi_package(argc, argv);
- } else if (!strcmp(argv[0], "uninstall")) {
- if (argc < 2) error_exit("uninstall requires an argument");
- return uninstall_app(argc, argv);
- } else if (!strcmp(argv[0], "sync")) {
- std::string src;
- bool list_only = false;
- bool compressed = true;
-
- const char* adb_compression = getenv("ADB_COMPRESSION");
- if (adb_compression && strcmp(adb_compression, "0") == 0) {
- compressed = false;
- }
-
- int opt;
- while ((opt = getopt(argc, const_cast<char**>(argv), "lzZ")) != -1) {
- switch (opt) {
- case 'l':
- list_only = true;
- break;
- case 'z':
- compressed = true;
- break;
- case 'Z':
- compressed = false;
- break;
- default:
- error_exit("usage: adb sync [-lzZ] [PARTITION]");
- }
- }
-
- if (optind == argc) {
- src = "all";
- } else if (optind + 1 == argc) {
- src = argv[optind];
- } else {
- error_exit("usage: adb sync [-lzZ] [PARTITION]");
- }
-
- std::vector<std::string> partitions{"data", "odm", "oem", "product",
- "system", "system_ext", "vendor"};
- bool found = false;
- for (const auto& partition : partitions) {
- if (src == "all" || src == partition) {
- std::string src_dir{product_file(partition)};
- if (!directory_exists(src_dir)) continue;
- found = true;
- if (!do_sync_sync(src_dir, "/" + partition, list_only, compressed)) return 1;
- }
- }
- if (!found) error_exit("don't know how to sync %s partition", src.c_str());
- return 0;
- }
- /* passthrough commands */
- else if (!strcmp(argv[0], "get-state") || !strcmp(argv[0], "get-serialno") ||
- !strcmp(argv[0], "get-devpath")) {
- return adb_query_command(format_host_command(argv[0]));
- }
- /* other commands */
- else if (!strcmp(argv[0], "logcat") || !strcmp(argv[0], "lolcat") ||
- !strcmp(argv[0], "longcat")) {
- return logcat(argc, argv);
- } else if (!strcmp(argv[0], "ppp")) {
- return ppp(argc, argv);
- } else if (!strcmp(argv[0], "start-server")) {
- std::string error;
- const int result = adb_connect("host:start-server", &error);
- if (result < 0) {
- fprintf(stderr, "error: %s\n", error.c_str());
- }
- return result;
- } else if (!strcmp(argv[0], "backup")) {
- return backup(argc, argv);
- } else if (!strcmp(argv[0], "restore")) {
- return restore(argc, argv);
- } else if (!strcmp(argv[0], "keygen")) {
- if (argc != 2) error_exit("keygen requires an argument");
- // Always print key generation information for keygen command.
- adb_trace_enable(AUTH);
- return adb_auth_keygen(argv[1]);
- } else if (!strcmp(argv[0], "pubkey")) {
- if (argc != 2) error_exit("pubkey requires an argument");
- return adb_auth_pubkey(argv[1]);
- } else if (!strcmp(argv[0], "jdwp")) {
- return adb_connect_command("jdwp");
- } else if (!strcmp(argv[0], "track-jdwp")) {
- return adb_connect_command("track-jdwp");
- } else if (!strcmp(argv[0], "track-devices")) {
- if (argc > 2 || (argc == 2 && strcmp(argv[1], "-l"))) {
- error_exit("usage: adb track-devices [-l]");
- }
- return adb_connect_command(argc == 2 ? "host:track-devices-l" : "host:track-devices");
- } else if (!strcmp(argv[0], "raw")) {
- if (argc != 2) {
- error_exit("usage: adb raw SERVICE");
- }
- return adb_connect_command_bidirectional(argv[1]);
- }
-
- /* "adb /?" is a common idiom under Windows */
- else if (!strcmp(argv[0], "--help") || !strcmp(argv[0], "help") || !strcmp(argv[0], "/?")) {
- help();
- return 0;
- } else if (!strcmp(argv[0], "--version") || !strcmp(argv[0], "version")) {
- fprintf(stdout, "%s", adb_version().c_str());
- return 0;
- } else if (!strcmp(argv[0], "features")) {
- // Only list the features common to both the adb client and the device.
- FeatureSet features;
- std::string error;
- if (!adb_get_feature_set(&features, &error)) {
- fprintf(stderr, "error: %s\n", error.c_str());
- return 1;
- }
-
- for (const std::string& name : features) {
- if (CanUseFeature(features, name)) {
- printf("%s\n", name.c_str());
- }
- }
- return 0;
- } else if (!strcmp(argv[0], "host-features")) {
- return adb_query_command("host:host-features");
- } else if (!strcmp(argv[0], "reconnect")) {
- if (argc == 1) {
- return adb_query_command(format_host_command(argv[0]));
- } else if (argc == 2) {
- if (!strcmp(argv[1], "device")) {
- std::string err;
- adb_connect("reconnect", &err);
- return 0;
- } else if (!strcmp(argv[1], "offline")) {
- std::string err;
- return adb_query_command("host:reconnect-offline");
- } else {
- error_exit("usage: adb reconnect [device|offline]");
- }
- }
- } else if (!strcmp(argv[0], "inc-server")) {
- if (argc < 4) {
-#ifdef _WIN32
- error_exit("usage: adb inc-server CONNECTION_HANDLE OUTPUT_HANDLE FILE1 FILE2 ...");
-#else
- error_exit("usage: adb inc-server CONNECTION_FD OUTPUT_FD FILE1 FILE2 ...");
-#endif
- }
- int connection_fd = atoi(argv[1]);
- if (!_is_valid_os_fd(connection_fd)) {
- error_exit("Invalid connection_fd number given: %d", connection_fd);
- }
-
- connection_fd = adb_register_socket(connection_fd);
- close_on_exec(connection_fd);
-
- int output_fd = atoi(argv[2]);
- if (!_is_valid_os_fd(output_fd)) {
- error_exit("Invalid output_fd number given: %d", output_fd);
- }
- output_fd = adb_register_socket(output_fd);
- close_on_exec(output_fd);
- return incremental::serve(connection_fd, output_fd, argc - 3, argv + 3);
- }
-
- error_exit("unknown command %s", argv[0]);
- __builtin_unreachable();
-}
diff --git a/adb/client/commandline.h b/adb/client/commandline.h
deleted file mode 100644
index b9dee5625..000000000
--- 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 <android-base/strings.h>
-
-#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 <typename ContainerT>
-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 d10f4deec..000000000
--- 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 <stdio.h>
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/strings.h>
-#include <cutils/sockets.h>
-
-#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 <token>\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 <auth_token>' to authenticate
- // Android Console: you can find your <auth_token> in
- // '/<path-to-home>/.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 de82e14e5..000000000
--- 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 <string.h>
-#include <algorithm>
-#include <array>
-#include <memory>
-
-#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::milliseconds>(
- std::chrono::steady_clock::now() - start_);
- fprintf(stderr, "%s finished in %lldms\n", label_,
- static_cast<long long>(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<char> sdk_version_output_buffer;
- std::vector<char> 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<const char*> srcs;
- TemporaryFile tf;
- android::base::WriteFully(tf.fd, data, byte_count);
- srcs.push_back(tf.path);
- // On Windows, the file needs to be flushed before pushing to device,
- // but can't be removed until after the push.
- unix_close(tf.release());
-
- if (!do_sync_push(srcs, dst, sync, true)) {
- error_exit("Failed to push fastdeploy agent to device.");
- }
-}
-
-static bool deploy_agent(bool check_time_stamps) {
- REPORT_FUNC_TIME();
-
- push_to_device(kDeployAgent, sizeof(kDeployAgent), kDeviceAgentFile, check_time_stamps);
- push_to_device(kDeployAgentScript, sizeof(kDeployAgentScript), kDeviceAgentScript,
- check_time_stamps);
-
- // on windows the shell script might have lost execute permission
- // so need to set this explicitly
- const char* kChmodCommandPattern = "chmod 777 %s";
- std::string chmod_command =
- android::base::StringPrintf(kChmodCommandPattern, kDeviceAgentScript);
- int ret = send_shell_command(chmod_command);
- if (ret != 0) {
- error_exit("Error executing %s returncode: %d", chmod_command.c_str(), ret);
- }
-
- return true;
-}
-
-static std::string get_string_from_utf16(const char16_t* input, int input_len) {
- ssize_t utf8_length = utf16_to_utf8_length(input, input_len);
- if (utf8_length <= 0) {
- return {};
- }
- std::string utf8;
- utf8.resize(utf8_length);
- utf16_to_utf8(input, input_len, &*utf8.begin(), utf8_length + 1);
- return utf8;
-}
-
-static std::string get_package_name_from_apk(const char* apk_path) {
-#undef open
- std::unique_ptr<android::ZipFileRO> 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<char> 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<char>& 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<APKMetaData> 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<char> dump_out_buffer;
- std::vector<char> 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<unsigned char> apply_output_buffer;
- std::vector<unsigned char> 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 830aeb2ca..000000000
--- 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 <optional>
-#include <string>
-
-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<com::android::fastdeploy::APKMetaData> 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 86ceaa137..000000000
--- 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 <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-
-#include "client/file_sync_client.h"
-#include "commandline.h"
-#include "sysdeps.h"
-
-#include "fastdeploycallbacks.h"
-
-static void appendBuffer(std::vector<char>* buffer, const char* input, int length) {
- if (buffer != NULL) {
- buffer->insert(buffer->end(), input, input + length);
- }
-}
-
-class DeployAgentBufferCallback : public StandardStreamsCallbackInterface {
- public:
- DeployAgentBufferCallback(std::vector<char>* outBuffer, std::vector<char>* 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<char>* mpOutBuffer;
- std::vector<char>* mpErrBuffer;
-};
-
-int capture_shell_command(const char* command, std::vector<char>* outBuffer,
- std::vector<char>* errBuffer) {
- DeployAgentBufferCallback cb(outBuffer, errBuffer);
- return send_shell_command(command, /*disable_shell_protocol=*/false, &cb);
-}
-
-DeployAgentBufferCallback::DeployAgentBufferCallback(std::vector<char>* outBuffer,
- std::vector<char>* 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 4a6fb9915..000000000
--- 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 <vector>
-
-int capture_shell_command(const char* command, std::vector<char>* outBuffer,
- std::vector<char>* errBuffer);
diff --git a/adb/client/file_sync_client.cpp b/adb/client/file_sync_client.cpp
deleted file mode 100644
index e686973db..000000000
--- a/adb/client/file_sync_client.cpp
+++ /dev/null
@@ -1,1650 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "client/file_sync_client.h"
-
-#include <dirent.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <time.h>
-#include <unistd.h>
-#include <utime.h>
-
-#include <chrono>
-#include <deque>
-#include <functional>
-#include <memory>
-#include <sstream>
-#include <string>
-#include <vector>
-
-#include "sysdeps.h"
-
-#include "adb.h"
-#include "adb_client.h"
-#include "adb_io.h"
-#include "adb_utils.h"
-#include "brotli_utils.h"
-#include "file_sync_protocol.h"
-#include "line_printer.h"
-#include "sysdeps/errno.h"
-#include "sysdeps/stat.h"
-
-#include "client/commandline.h"
-
-#include <android-base/file.h>
-#include <android-base/strings.h>
-#include <android-base/stringprintf.h>
-
-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<double> duration;
- duration = std::chrono::steady_clock::now() - start_time;
-
- double s = duration.count();
- if (s == 0) {
- return "";
- }
- double rate = (static_cast<double>(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<int>(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<int>(file_copied_bytes * 100 / file_total_bytes);
- output = android::base::StringPrintf("[%4s] %s: %d%%", overall_percentage_str,
- file.c_str(), file_percentage);
- } else {
- output =
- android::base::StringPrintf("[%4s] %s", overall_percentage_str, file.c_str());
- }
- }
- if (output != last_progress_str) {
- lp.Print(output, LinePrinter::LineType::INFO);
- last_progress_str = std::move(output);
- last_progress_time = now;
- }
- }
-
- void ReportTransferRate(LinePrinter& lp, const std::string& name, TransferDirection direction) {
- const char* direction_str = (direction == TransferDirection::push) ? "pushed" : "pulled";
- std::stringstream ss;
- if (!name.empty()) {
- std::string_view display_name(name);
- char* out = getenv("ANDROID_PRODUCT_OUT");
- if (out) android::base::ConsumePrefix(&display_name, out);
- ss << display_name << ": ";
- }
- ss << files_transferred << " file" << ((files_transferred == 1) ? "" : "s") << " "
- << direction_str << ", " << files_skipped << " skipped.";
- ss << TransferRate();
-
- lp.Print(ss.str(), LinePrinter::LineType::INFO);
- lp.KeepInfoLine();
- }
-};
-
-class SyncConnection {
- public:
- SyncConnection() : acknowledgement_buffer_(sizeof(sync_status) + SYNC_DATA_MAX) {
- acknowledgement_buffer_.resize(0);
- max = SYNC_DATA_MAX; // TODO: decide at runtime.
-
- std::string error;
- if (!adb_get_feature_set(&features_, &error)) {
- Error("failed to get feature set: %s", error.c_str());
- } else {
- have_stat_v2_ = CanUseFeature(features_, kFeatureStat2);
- have_ls_v2_ = CanUseFeature(features_, kFeatureLs2);
- have_sendrecv_v2_ = CanUseFeature(features_, kFeatureSendRecv2);
- have_sendrecv_v2_brotli_ = CanUseFeature(features_, kFeatureSendRecv2Brotli);
- fd.reset(adb_connect("sync:", &error));
- if (fd < 0) {
- Error("connect failed: %s", error.c_str());
- }
- }
- }
-
- ~SyncConnection() {
- if (!IsValid()) return;
-
- if (SendQuit()) {
- // We sent a quit command, so the server should be doing orderly
- // shutdown soon. But if we encountered an error while we were using
- // the connection, the server might still be sending data (before
- // doing orderly shutdown), in which case we won't wait for all of
- // the data nor the coming orderly shutdown. In the common success
- // case, this will wait for the server to do orderly shutdown.
- ReadOrderlyShutdown(fd);
- }
-
- line_printer_.KeepInfoLine();
- }
-
- bool HaveSendRecv2() const { return have_sendrecv_v2_; }
- bool HaveSendRecv2Brotli() const { return have_sendrecv_v2_brotli_; }
-
- const FeatureSet& Features() const { return features_; }
-
- bool IsValid() { return fd >= 0; }
-
- void NewTransfer() {
- current_ledger_.Reset();
- }
-
- void RecordBytesTransferred(size_t bytes) {
- current_ledger_.bytes_transferred += bytes;
- global_ledger_.bytes_transferred += bytes;
- }
-
- void RecordFileSent(std::string from, std::string to) {
- RecordFilesTransferred(1);
- deferred_acknowledgements_.emplace_back(std::move(from), std::move(to));
- }
-
- void RecordFilesTransferred(size_t files) {
- current_ledger_.files_transferred += files;
- global_ledger_.files_transferred += files;
- }
-
- void RecordFilesSkipped(size_t files) {
- current_ledger_.files_skipped += files;
- global_ledger_.files_skipped += files;
- }
-
- void ReportProgress(const std::string& file, uint64_t file_copied_bytes,
- uint64_t file_total_bytes) {
- current_ledger_.ReportProgress(line_printer_, file, file_copied_bytes, file_total_bytes);
- }
-
- void ReportTransferRate(const std::string& file, TransferDirection direction) {
- current_ledger_.ReportTransferRate(line_printer_, file, direction);
- }
-
- void ReportOverallTransferRate(TransferDirection direction) {
- if (current_ledger_ != global_ledger_) {
- global_ledger_.ReportTransferRate(line_printer_, "", direction);
- }
- }
-
- bool SendRequest(int id, const std::string& path) {
- if (path.length() > 1024) {
- Error("SendRequest failed: path too long: %zu", path.length());
- errno = ENAMETOOLONG;
- return false;
- }
-
- // Sending header and payload in a single write makes a noticeable
- // difference to "adb sync" performance.
- std::vector<char> buf(sizeof(SyncRequest) + path.length());
- SyncRequest* req = reinterpret_cast<SyncRequest*>(&buf[0]);
- req->id = id;
- req->path_length = path.length();
- char* data = reinterpret_cast<char*>(req + 1);
- memcpy(data, path.data(), path.length());
- return WriteFdExactly(fd, buf.data(), buf.size());
- }
-
- bool SendSend2(std::string_view path, mode_t mode, bool compressed) {
- if (path.length() > 1024) {
- Error("SendRequest failed: path too long: %zu", path.length());
- errno = ENAMETOOLONG;
- return false;
- }
-
- Block buf;
-
- SyncRequest req;
- req.id = ID_SEND_V2;
- req.path_length = path.length();
-
- syncmsg msg;
- msg.send_v2_setup.id = ID_SEND_V2;
- msg.send_v2_setup.mode = mode;
- msg.send_v2_setup.flags = compressed ? kSyncFlagBrotli : kSyncFlagNone;
-
- buf.resize(sizeof(SyncRequest) + path.length() + sizeof(msg.send_v2_setup));
-
- void* p = buf.data();
-
- p = mempcpy(p, &req, sizeof(SyncRequest));
- p = mempcpy(p, path.data(), path.length());
- p = mempcpy(p, &msg.send_v2_setup, sizeof(msg.send_v2_setup));
-
- return WriteFdExactly(fd, buf.data(), buf.size());
- }
-
- bool SendRecv2(const std::string& path) {
- if (path.length() > 1024) {
- Error("SendRequest failed: path too long: %zu", path.length());
- errno = ENAMETOOLONG;
- return false;
- }
-
- Block buf;
-
- SyncRequest req;
- req.id = ID_RECV_V2;
- req.path_length = path.length();
-
- syncmsg msg;
- msg.recv_v2_setup.id = ID_RECV_V2;
- msg.recv_v2_setup.flags = kSyncFlagBrotli;
-
- buf.resize(sizeof(SyncRequest) + path.length() + sizeof(msg.recv_v2_setup));
-
- void* p = buf.data();
-
- p = mempcpy(p, &req, sizeof(SyncRequest));
- p = mempcpy(p, path.data(), path.length());
- p = mempcpy(p, &msg.recv_v2_setup, sizeof(msg.recv_v2_setup));
-
- return WriteFdExactly(fd, buf.data(), buf.size());
- }
-
- bool SendStat(const std::string& path) {
- if (!have_stat_v2_) {
- errno = ENOTSUP;
- return false;
- }
- return SendRequest(ID_STAT_V2, path);
- }
-
- bool SendLstat(const std::string& path) {
- if (have_stat_v2_) {
- return SendRequest(ID_LSTAT_V2, path);
- } else {
- return SendRequest(ID_LSTAT_V1, path);
- }
- }
-
- bool FinishStat(struct stat* st) {
- syncmsg msg;
-
- memset(st, 0, sizeof(*st));
- if (have_stat_v2_) {
- if (!ReadFdExactly(fd.get(), &msg.stat_v2, sizeof(msg.stat_v2))) {
- PLOG(FATAL) << "protocol fault: failed to read stat response";
- }
-
- if (msg.stat_v2.id != ID_LSTAT_V2 && msg.stat_v2.id != ID_STAT_V2) {
- PLOG(FATAL) << "protocol fault: stat response has wrong message id: "
- << msg.stat_v2.id;
- }
-
- if (msg.stat_v2.error != 0) {
- errno = errno_from_wire(msg.stat_v2.error);
- return false;
- }
-
- st->st_dev = msg.stat_v2.dev;
- st->st_ino = msg.stat_v2.ino;
- st->st_mode = msg.stat_v2.mode;
- st->st_nlink = msg.stat_v2.nlink;
- st->st_uid = msg.stat_v2.uid;
- st->st_gid = msg.stat_v2.gid;
- st->st_size = msg.stat_v2.size;
- st->st_atime = msg.stat_v2.atime;
- st->st_mtime = msg.stat_v2.mtime;
- st->st_ctime = msg.stat_v2.ctime;
- return true;
- } else {
- if (!ReadFdExactly(fd.get(), &msg.stat_v1, sizeof(msg.stat_v1))) {
- PLOG(FATAL) << "protocol fault: failed to read stat response";
- }
-
- if (msg.stat_v1.id != ID_LSTAT_V1) {
- LOG(FATAL) << "protocol fault: stat response has wrong message id: "
- << msg.stat_v1.id;
- }
-
- if (msg.stat_v1.mode == 0 && msg.stat_v1.size == 0 && msg.stat_v1.mtime == 0) {
- // There's no way for us to know what the error was.
- errno = ENOPROTOOPT;
- return false;
- }
-
- st->st_mode = msg.stat_v1.mode;
- st->st_size = msg.stat_v1.size;
- st->st_ctime = msg.stat_v1.mtime;
- st->st_mtime = msg.stat_v1.mtime;
- }
-
- return true;
- }
-
- bool SendLs(const std::string& path) {
- return SendRequest(have_ls_v2_ ? ID_LIST_V2 : ID_LIST_V1, path);
- }
-
- private:
- template <bool v2>
- static bool FinishLsImpl(borrowed_fd fd, const std::function<sync_ls_cb>& callback) {
- using dent_type =
- std::conditional_t<v2, decltype(syncmsg::dent_v2), decltype(syncmsg::dent_v1)>;
-
- 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<sync_ls_cb>& callback) {
- if (have_ls_v2_) {
- return FinishLsImpl<true>(this->fd, callback);
- } else {
- return FinishLsImpl<false>(this->fd, callback);
- }
- }
-
- // Sending header, payload, and footer in a single write makes a huge
- // difference to "adb sync" performance.
- bool SendSmallFile(const std::string& path, mode_t mode, const std::string& lpath,
- const std::string& rpath, unsigned mtime, const char* data,
- size_t data_length) {
- std::string path_and_mode = android::base::StringPrintf("%s,%d", path.c_str(), mode);
- if (path_and_mode.length() > 1024) {
- Error("SendSmallFile failed: path too long: %zu", path_and_mode.length());
- errno = ENAMETOOLONG;
- return false;
- }
-
- std::vector<char> buf(sizeof(SyncRequest) + path_and_mode.length() + sizeof(SyncRequest) +
- data_length + sizeof(SyncRequest));
- char* p = &buf[0];
-
- SyncRequest* req_send = reinterpret_cast<SyncRequest*>(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<SyncRequest*>(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<SyncRequest*>(p);
- req_done->id = ID_DONE;
- req_done->path_length = mtime;
- p += sizeof(SyncRequest);
-
- WriteOrDie(lpath, rpath, &buf[0], (p - &buf[0]));
-
- RecordFileSent(lpath, rpath);
- RecordBytesTransferred(data_length);
- ReportProgress(rpath, data_length, data_length);
- return true;
- }
-
- bool SendLargeFileCompressed(const std::string& path, mode_t mode, const std::string& lpath,
- const std::string& rpath, unsigned mtime) {
- if (!SendSend2(path, mode, true)) {
- Error("failed to send ID_SEND_V2 message '%s': %s", path.c_str(), strerror(errno));
- return false;
- }
-
- struct stat st;
- if (stat(lpath.c_str(), &st) == -1) {
- Error("cannot stat '%s': %s", lpath.c_str(), strerror(errno));
- return false;
- }
-
- uint64_t total_size = st.st_size;
- uint64_t bytes_copied = 0;
-
- unique_fd lfd(adb_open(lpath.c_str(), O_RDONLY | O_CLOEXEC));
- if (lfd < 0) {
- Error("opening '%s' locally failed: %s", lpath.c_str(), strerror(errno));
- return false;
- }
-
- syncsendbuf sbuf;
- sbuf.id = ID_DATA;
-
- BrotliEncoder<SYNC_DATA_MAX> encoder;
- bool sending = true;
- while (sending) {
- Block input(SYNC_DATA_MAX);
- int r = adb_read(lfd.get(), input.data(), input.size());
- if (r < 0) {
- Error("reading '%s' locally failed: %s", lpath.c_str(), strerror(errno));
- return false;
- }
-
- if (r == 0) {
- encoder.Finish();
- } else {
- input.resize(r);
- encoder.Append(std::move(input));
- RecordBytesTransferred(r);
- bytes_copied += r;
- ReportProgress(rpath, bytes_copied, total_size);
- }
-
- while (true) {
- Block output;
- BrotliEncodeResult result = encoder.Encode(&output);
- if (result == BrotliEncodeResult::Error) {
- Error("compressing '%s' locally failed", lpath.c_str());
- return false;
- }
-
- if (!output.empty()) {
- sbuf.size = output.size();
- memcpy(sbuf.data, output.data(), output.size());
- WriteOrDie(lpath, rpath, &sbuf, sizeof(SyncRequest) + output.size());
- }
-
- if (result == BrotliEncodeResult::Done) {
- sending = false;
- break;
- } else if (result == BrotliEncodeResult::NeedInput) {
- break;
- } else if (result == BrotliEncodeResult::MoreOutput) {
- continue;
- }
- }
- }
-
- syncmsg msg;
- msg.data.id = ID_DONE;
- msg.data.size = mtime;
- RecordFileSent(lpath, rpath);
- return WriteOrDie(lpath, rpath, &msg.data, sizeof(msg.data));
- }
-
- bool SendLargeFile(const std::string& path, mode_t mode, const std::string& lpath,
- const std::string& rpath, unsigned mtime, bool compressed) {
- if (compressed && HaveSendRecv2Brotli()) {
- return SendLargeFileCompressed(path, mode, lpath, rpath, mtime);
- }
-
- std::string path_and_mode = android::base::StringPrintf("%s,%d", path.c_str(), mode);
- if (!SendRequest(ID_SEND_V1, path_and_mode)) {
- Error("failed to send ID_SEND_V1 message '%s': %s", path_and_mode.c_str(),
- strerror(errno));
- return false;
- }
-
- struct stat st;
- if (stat(lpath.c_str(), &st) == -1) {
- Error("cannot stat '%s': %s", lpath.c_str(), strerror(errno));
- return false;
- }
-
- uint64_t total_size = st.st_size;
- uint64_t bytes_copied = 0;
-
- unique_fd lfd(adb_open(lpath.c_str(), O_RDONLY | O_CLOEXEC));
- if (lfd < 0) {
- Error("opening '%s' locally failed: %s", lpath.c_str(), strerror(errno));
- return false;
- }
-
- syncsendbuf sbuf;
- sbuf.id = ID_DATA;
-
- while (true) {
- int bytes_read = adb_read(lfd, sbuf.data, max);
- if (bytes_read == -1) {
- Error("reading '%s' locally failed: %s", lpath.c_str(), strerror(errno));
- return false;
- } else if (bytes_read == 0) {
- break;
- }
-
- sbuf.size = bytes_read;
- WriteOrDie(lpath, rpath, &sbuf, sizeof(SyncRequest) + bytes_read);
-
- RecordBytesTransferred(bytes_read);
- bytes_copied += bytes_read;
- ReportProgress(rpath, bytes_copied, total_size);
- }
-
- syncmsg msg;
- msg.data.id = ID_DONE;
- msg.data.size = mtime;
- RecordFileSent(lpath, rpath);
- return WriteOrDie(lpath, rpath, &msg.data, sizeof(msg.data));
- }
-
- bool ReportCopyFailure(const std::string& from, const std::string& to, const syncmsg& msg) {
- std::vector<char> 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<sync_status*>(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<copyinfo>& 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<std::pair<std::string, std::string>> deferred_acknowledgements_;
- Block acknowledgement_buffer_;
- FeatureSet features_;
- bool have_stat_v2_;
- bool have_ls_v2_;
- bool have_sendrecv_v2_;
- bool have_sendrecv_v2_brotli_;
-
- TransferLedger global_ledger_;
- TransferLedger current_ledger_;
- LinePrinter line_printer_;
-
- bool SendQuit() {
- return SendRequest(ID_QUIT, ""); // TODO: add a SendResponse?
- }
-
- bool WriteOrDie(const std::string& from, const std::string& to, const void* data,
- size_t data_length) {
- if (!WriteFdExactly(fd, data, data_length)) {
- if (errno == ECONNRESET) {
- // Assume adbd told us why it was closing the connection, and
- // try to read failure reason from adbd.
- syncmsg msg;
- if (!ReadFdExactly(fd, &msg.status, sizeof(msg.status))) {
- Error("failed to copy '%s' to '%s': no response: %s", from.c_str(), to.c_str(),
- strerror(errno));
- } else if (msg.status.id != ID_FAIL) {
- Error("failed to copy '%s' to '%s': not ID_FAIL: %d", from.c_str(), to.c_str(),
- msg.status.id);
- } else {
- ReportCopyFailure(from, to, msg);
- }
- } else {
- Error("%zu-byte write failed: %s", data_length, strerror(errno));
- }
- _exit(1);
- }
- return true;
- }
-};
-
-static bool sync_ls(SyncConnection& sc, const std::string& path,
- const std::function<sync_ls_cb>& func) {
- return sc.SendLs(path) && sc.FinishLs(func);
-}
-
-static bool sync_stat(SyncConnection& sc, const std::string& path, struct stat* st) {
- return sc.SendStat(path) && sc.FinishStat(st);
-}
-
-static bool sync_lstat(SyncConnection& sc, const std::string& path, struct stat* st) {
- return sc.SendLstat(path) && sc.FinishStat(st);
-}
-
-static bool sync_stat_fallback(SyncConnection& sc, const std::string& path, struct stat* st) {
- if (sync_stat(sc, path, st)) {
- return true;
- }
-
- if (errno != ENOTSUP) {
- return false;
- }
-
- // Try to emulate the parts we can when talking to older adbds.
- bool lstat_result = sync_lstat(sc, path, st);
- if (!lstat_result) {
- return false;
- }
-
- if (S_ISLNK(st->st_mode)) {
- // If the target is a symlink, figure out whether it's a file or a directory.
- // Also, zero out the st_size field, since no one actually cares what the path length is.
- st->st_size = 0;
- std::string dir_path = path;
- dir_path.push_back('/');
- struct stat tmp_st;
-
- st->st_mode &= ~S_IFMT;
- if (sync_lstat(sc, dir_path, &tmp_st)) {
- st->st_mode |= S_IFDIR;
- } else {
- st->st_mode |= S_IFREG;
- }
- }
- return true;
-}
-
-static bool sync_send(SyncConnection& sc, const std::string& lpath, const std::string& rpath,
- unsigned mtime, mode_t mode, bool sync, bool compressed) {
- if (sync) {
- struct stat st;
- if (sync_lstat(sc, rpath, &st)) {
- if (st.st_mtime == static_cast<time_t>(mtime)) {
- sc.RecordFilesSkipped(1);
- return true;
- }
- }
- }
-
- if (S_ISLNK(mode)) {
-#if !defined(_WIN32)
- char buf[PATH_MAX];
- ssize_t data_length = readlink(lpath.c_str(), buf, PATH_MAX - 1);
- if (data_length == -1) {
- sc.Error("readlink '%s' failed: %s", lpath.c_str(), strerror(errno));
- return false;
- }
- buf[data_length++] = '\0';
-
- if (!sc.SendSmallFile(rpath, mode, lpath, rpath, mtime, buf, data_length)) {
- return false;
- }
- return sc.ReadAcknowledgements();
-#endif
- }
-
- struct stat st;
- if (stat(lpath.c_str(), &st) == -1) {
- sc.Error("failed to stat local file '%s': %s", lpath.c_str(), strerror(errno));
- return false;
- }
- if (st.st_size < SYNC_DATA_MAX) {
- std::string data;
- if (!android::base::ReadFileToString(lpath, &data, true)) {
- sc.Error("failed to read all of '%s': %s", lpath.c_str(), strerror(errno));
- return false;
- }
- if (!sc.SendSmallFile(rpath, mode, lpath, rpath, mtime, data.data(), data.size())) {
- return false;
- }
- } else {
- if (!sc.SendLargeFile(rpath, mode, lpath, rpath, mtime, compressed)) {
- return false;
- }
- }
- return sc.ReadAcknowledgements();
-}
-
-static bool sync_recv_v1(SyncConnection& sc, const char* rpath, const char* lpath, const char* name,
- uint64_t expected_size) {
- if (!sc.SendRequest(ID_RECV_V1, rpath)) return false;
-
- adb_unlink(lpath);
- unique_fd lfd(adb_creat(lpath, 0644));
- if (lfd < 0) {
- sc.Error("cannot create '%s': %s", lpath, strerror(errno));
- return false;
- }
-
- uint64_t bytes_copied = 0;
- while (true) {
- syncmsg msg;
- if (!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
- adb_unlink(lpath);
- return false;
- }
-
- if (msg.data.id == ID_DONE) break;
-
- if (msg.data.id != ID_DATA) {
- adb_unlink(lpath);
- sc.ReportCopyFailure(rpath, lpath, msg);
- return false;
- }
-
- if (msg.data.size > sc.max) {
- sc.Error("msg.data.size too large: %u (max %zu)", msg.data.size, sc.max);
- adb_unlink(lpath);
- return false;
- }
-
- char buffer[SYNC_DATA_MAX];
- if (!ReadFdExactly(sc.fd, buffer, msg.data.size)) {
- adb_unlink(lpath);
- return false;
- }
-
- if (!WriteFdExactly(lfd, buffer, msg.data.size)) {
- sc.Error("cannot write '%s': %s", lpath, strerror(errno));
- adb_unlink(lpath);
- return false;
- }
-
- bytes_copied += msg.data.size;
-
- sc.RecordBytesTransferred(msg.data.size);
- sc.ReportProgress(name != nullptr ? name : rpath, bytes_copied, expected_size);
- }
-
- sc.RecordFilesTransferred(1);
- return true;
-}
-
-static bool sync_recv_v2(SyncConnection& sc, const char* rpath, const char* lpath, const char* name,
- uint64_t expected_size) {
- if (!sc.SendRecv2(rpath)) return false;
-
- adb_unlink(lpath);
- unique_fd lfd(adb_creat(lpath, 0644));
- if (lfd < 0) {
- sc.Error("cannot create '%s': %s", lpath, strerror(errno));
- return false;
- }
-
- uint64_t bytes_copied = 0;
-
- Block buffer(SYNC_DATA_MAX);
- BrotliDecoder decoder(std::span(buffer.data(), buffer.size()));
- bool reading = true;
- while (reading) {
- syncmsg msg;
- if (!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
- adb_unlink(lpath);
- return false;
- }
-
- if (msg.data.id == ID_DONE) {
- adb_unlink(lpath);
- sc.Error("unexpected ID_DONE");
- return false;
- }
-
- if (msg.data.id != ID_DATA) {
- adb_unlink(lpath);
- sc.ReportCopyFailure(rpath, lpath, msg);
- return false;
- }
-
- if (msg.data.size > sc.max) {
- sc.Error("msg.data.size too large: %u (max %zu)", msg.data.size, sc.max);
- adb_unlink(lpath);
- return false;
- }
-
- Block block(msg.data.size);
- if (!ReadFdExactly(sc.fd, block.data(), msg.data.size)) {
- adb_unlink(lpath);
- return false;
- }
- decoder.Append(std::move(block));
-
- while (true) {
- std::span<char> output;
- BrotliDecodeResult result = decoder.Decode(&output);
-
- if (result == BrotliDecodeResult::Error) {
- sc.Error("decompress failed");
- adb_unlink(lpath);
- return false;
- }
-
- if (!output.empty()) {
- if (!WriteFdExactly(lfd, output.data(), output.size())) {
- sc.Error("cannot write '%s': %s", lpath, strerror(errno));
- adb_unlink(lpath);
- return false;
- }
- }
-
- bytes_copied += output.size();
-
- sc.RecordBytesTransferred(msg.data.size);
- sc.ReportProgress(name != nullptr ? name : rpath, bytes_copied, expected_size);
-
- if (result == BrotliDecodeResult::NeedInput) {
- break;
- } else if (result == BrotliDecodeResult::MoreOutput) {
- continue;
- } else if (result == BrotliDecodeResult::Done) {
- reading = false;
- break;
- } else {
- LOG(FATAL) << "invalid BrotliDecodeResult: " << static_cast<int>(result);
- }
- }
- }
-
- syncmsg msg;
- if (!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
- sc.Error("failed to read ID_DONE");
- return false;
- }
-
- if (msg.data.id != ID_DONE) {
- sc.Error("unexpected message after transfer: id = %d (expected ID_DONE)", msg.data.id);
- return false;
- }
-
- sc.RecordFilesTransferred(1);
- return true;
-}
-
-static bool sync_recv(SyncConnection& sc, const char* rpath, const char* lpath, const char* name,
- uint64_t expected_size, bool compressed) {
- if (sc.HaveSendRecv2() && compressed) {
- return sync_recv_v2(sc, rpath, lpath, name, expected_size);
- } else {
- return sync_recv_v1(sc, rpath, lpath, name, expected_size);
- }
-}
-
-bool do_sync_ls(const char* path) {
- SyncConnection sc;
- if (!sc.IsValid()) return false;
-
- return sync_ls(sc, path, [](unsigned mode, uint64_t size, uint64_t time, const char* name) {
- printf("%08x %08" PRIx64 " %08" PRIx64 " %s\n", mode, size, time, name);
- });
-}
-
-static bool IsDotOrDotDot(const char* name) {
- return name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'));
-}
-
-static bool local_build_list(SyncConnection& sc, std::vector<copyinfo>* file_list,
- std::vector<std::string>* directory_list, const std::string& lpath,
- const std::string& rpath) {
- std::vector<copyinfo> dirlist;
- std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(lpath.c_str()), closedir);
- if (!dir) {
- sc.Error("cannot open '%s': %s", lpath.c_str(), strerror(errno));
- return false;
- }
-
- bool empty_dir = true;
- dirent* de;
- while ((de = readdir(dir.get()))) {
- if (IsDotOrDotDot(de->d_name)) {
- continue;
- }
-
- empty_dir = false;
- std::string stat_path = lpath + de->d_name;
-
- struct stat st;
- if (lstat(stat_path.c_str(), &st) == -1) {
- sc.Error("cannot lstat '%s': %s", stat_path.c_str(),
- strerror(errno));
- continue;
- }
-
- copyinfo ci(lpath, rpath, de->d_name, st.st_mode);
- if (S_ISDIR(st.st_mode)) {
- dirlist.push_back(ci);
- } else {
- if (!should_push_file(st.st_mode)) {
- sc.Warning("skipping special file '%s' (mode = 0o%o)", lpath.c_str(), st.st_mode);
- ci.skip = true;
- }
- ci.time = st.st_mtime;
- ci.size = st.st_size;
- file_list->push_back(ci);
- }
- }
-
- // Close this directory and recurse.
- dir.reset();
-
- for (const copyinfo& ci : dirlist) {
- directory_list->push_back(ci.rpath);
- local_build_list(sc, file_list, directory_list, ci.lpath, ci.rpath);
- }
-
- return true;
-}
-
-// dirname("//foo") returns "//", so we can't do the obvious `path == "/"`.
-static bool is_root_dir(std::string_view path) {
- for (char c : path) {
- if (c != '/') {
- return false;
- }
- }
- return true;
-}
-
-static bool copy_local_dir_remote(SyncConnection& sc, std::string lpath, std::string rpath,
- bool check_timestamps, bool list_only, bool compressed) {
- sc.NewTransfer();
-
- // Make sure that both directory paths end in a slash.
- // Both paths are known to be nonempty, so we don't need to check.
- ensure_trailing_separators(lpath, rpath);
-
- // Recursively build the list of files to copy.
- std::vector<copyinfo> file_list;
- std::vector<std::string> 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<off_t>(ci.size) && st.st_mtime == ci.time) {
- ci.skip = true;
- }
- }
- }
- }
-
- sc.ComputeExpectedTotalBytes(file_list);
-
- for (const copyinfo& ci : file_list) {
- if (!ci.skip) {
- if (list_only) {
- sc.Println("would push: %s -> %s", ci.lpath.c_str(), ci.rpath.c_str());
- } else {
- if (!sync_send(sc, ci.lpath, ci.rpath, ci.time, ci.mode, false, compressed)) {
- return false;
- }
- }
- } else {
- skipped++;
- }
- }
-
- sc.RecordFilesSkipped(skipped);
- bool success = sc.ReadAcknowledgements(true);
- sc.ReportTransferRate(lpath, TransferDirection::push);
- return success;
-}
-
-bool do_sync_push(const std::vector<const char*>& srcs, const char* dst, bool sync,
- bool compressed) {
- SyncConnection sc;
- if (!sc.IsValid()) return false;
-
- bool success = true;
- bool dst_exists;
- bool dst_isdir;
-
- struct stat st;
- if (sync_stat_fallback(sc, dst, &st)) {
- dst_exists = true;
- dst_isdir = S_ISDIR(st.st_mode);
- } else {
- if (errno == ENOENT || errno == ENOPROTOOPT) {
- dst_exists = false;
- dst_isdir = false;
- } else {
- sc.Error("stat failed when trying to push to %s: %s", dst, strerror(errno));
- return false;
- }
- }
-
- if (!dst_isdir) {
- if (srcs.size() > 1) {
- sc.Error("target '%s' is not a directory", dst);
- return false;
- } else {
- size_t dst_len = strlen(dst);
-
- // A path that ends with a slash doesn't have to be a directory if
- // it doesn't exist yet.
- if (dst[dst_len - 1] == '/' && dst_exists) {
- sc.Error("failed to access '%s': Not a directory", dst);
- return false;
- }
- }
- }
-
- for (const char* src_path : srcs) {
- const char* dst_path = dst;
- struct stat st;
- if (stat(src_path, &st) == -1) {
- sc.Error("cannot stat '%s': %s", src_path, strerror(errno));
- success = false;
- continue;
- }
-
- if (S_ISDIR(st.st_mode)) {
- std::string dst_dir = dst;
-
- // If the destination path existed originally, the source directory
- // should be copied as a child of the destination.
- if (dst_exists) {
- if (!dst_isdir) {
- sc.Error("target '%s' is not a directory", dst);
- return false;
- }
- // dst is a POSIX path, so we don't want to use the sysdeps
- // helpers here.
- if (dst_dir.back() != '/') {
- dst_dir.push_back('/');
- }
- dst_dir.append(android::base::Basename(src_path));
- }
-
- success &= copy_local_dir_remote(sc, src_path, dst_dir, sync, false, compressed);
- continue;
- } else if (!should_push_file(st.st_mode)) {
- sc.Warning("skipping special file '%s' (mode = 0o%o)", src_path, st.st_mode);
- continue;
- }
-
- std::string path_holder;
- if (dst_isdir) {
- // If we're copying a local file to a remote directory,
- // we really want to copy to remote_dir + "/" + local_filename.
- path_holder = dst_path;
- if (path_holder.back() != '/') {
- path_holder.push_back('/');
- }
- path_holder += android::base::Basename(src_path);
- dst_path = path_holder.c_str();
- }
-
- sc.NewTransfer();
- sc.SetExpectedTotalBytes(st.st_size);
- success &= sync_send(sc, src_path, dst_path, st.st_mtime, st.st_mode, sync, compressed);
- sc.ReportTransferRate(src_path, TransferDirection::push);
- }
-
- success &= sc.ReadAcknowledgements(true);
- sc.ReportOverallTransferRate(TransferDirection::push);
- return success;
-}
-
-static bool remote_build_list(SyncConnection& sc, std::vector<copyinfo>* file_list,
- const std::string& rpath, const std::string& lpath) {
- std::vector<copyinfo> dirlist;
- std::vector<copyinfo> linklist;
-
- // Add an entry for the current directory to ensure it gets created before pulling its contents.
- copyinfo ci(android::base::Dirname(lpath), android::base::Dirname(rpath),
- android::base::Basename(lpath), S_IFDIR);
- file_list->push_back(ci);
-
- // Put the files/dirs in rpath on the lists.
- auto callback = [&](unsigned mode, uint64_t size, uint64_t time, const char* name) {
- if (IsDotOrDotDot(name)) {
- return;
- }
-
- copyinfo ci(lpath, rpath, name, mode);
- if (S_ISDIR(mode)) {
- dirlist.push_back(ci);
- } else if (S_ISLNK(mode)) {
- linklist.push_back(ci);
- } else {
- if (!should_pull_file(ci.mode)) {
- sc.Warning("skipping special file '%s' (mode = 0o%o)", ci.rpath.c_str(), ci.mode);
- ci.skip = true;
- }
- ci.time = time;
- ci.size = size;
- file_list->push_back(ci);
- }
- };
-
- if (!sync_ls(sc, rpath.c_str(), callback)) {
- return false;
- }
-
- // Check each symlink we found to see whether it's a file or directory.
- for (copyinfo& link_ci : linklist) {
- struct stat st;
- if (!sync_stat_fallback(sc, link_ci.rpath.c_str(), &st)) {
- sc.Warning("stat failed for path %s: %s", link_ci.rpath.c_str(), strerror(errno));
- continue;
- }
-
- if (S_ISDIR(st.st_mode)) {
- dirlist.emplace_back(std::move(link_ci));
- } else {
- file_list->emplace_back(std::move(link_ci));
- }
- }
-
- // Recurse into each directory we found.
- while (!dirlist.empty()) {
- copyinfo current = dirlist.back();
- dirlist.pop_back();
- if (!remote_build_list(sc, file_list, current.rpath, current.lpath)) {
- return false;
- }
- }
-
- return true;
-}
-
-static int set_time_and_mode(const std::string& lpath, time_t time,
- unsigned int mode) {
- struct utimbuf times = { time, time };
- int r1 = utime(lpath.c_str(), &times);
-
- /* use umask for permissions */
- mode_t mask = umask(0000);
- umask(mask);
- int r2 = chmod(lpath.c_str(), mode & ~mask);
-
- return r1 ? r1 : r2;
-}
-
-static bool copy_remote_dir_local(SyncConnection& sc, std::string rpath, std::string lpath,
- bool copy_attrs, bool compressed) {
- sc.NewTransfer();
-
- // Make sure that both directory paths end in a slash.
- // Both paths are known to be nonempty, so we don't need to check.
- ensure_trailing_separators(lpath, rpath);
-
- // Recursively build the list of files to copy.
- sc.Printf("pull: building file list...");
- std::vector<copyinfo> file_list;
- if (!remote_build_list(sc, &file_list, rpath, lpath)) {
- return false;
- }
-
- sc.ComputeExpectedTotalBytes(file_list);
-
- int skipped = 0;
- for (const copyinfo &ci : file_list) {
- if (!ci.skip) {
- if (S_ISDIR(ci.mode)) {
- // Entry is for an empty directory, create it and continue.
- // TODO(b/25457350): We don't preserve permissions on directories.
- if (!mkdirs(ci.lpath)) {
- sc.Error("failed to create directory '%s': %s",
- ci.lpath.c_str(), strerror(errno));
- return false;
- }
- continue;
- }
-
- if (!sync_recv(sc, ci.rpath.c_str(), ci.lpath.c_str(), nullptr, ci.size, compressed)) {
- return false;
- }
-
- if (copy_attrs && set_time_and_mode(ci.lpath, ci.time, ci.mode)) {
- return false;
- }
- } else {
- skipped++;
- }
- }
-
- sc.RecordFilesSkipped(skipped);
- sc.ReportTransferRate(rpath, TransferDirection::pull);
- return true;
-}
-
-bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst, bool copy_attrs,
- bool compressed, const char* name) {
- SyncConnection sc;
- if (!sc.IsValid()) return false;
-
- bool success = true;
- struct stat st;
- bool dst_exists = true;
-
- if (stat(dst, &st) == -1) {
- dst_exists = false;
-
- // If we're only pulling one path, the destination path might point to
- // a path that doesn't exist yet.
- if (srcs.size() == 1 && errno == ENOENT) {
- // However, its parent must exist.
- struct stat parent_st;
- if (stat(android::base::Dirname(dst).c_str(), &parent_st) == -1) {
- sc.Error("cannot create file/directory '%s': %s", dst, strerror(errno));
- return false;
- }
- } else {
- sc.Error("failed to access '%s': %s", dst, strerror(errno));
- return false;
- }
- }
-
- bool dst_isdir = dst_exists && S_ISDIR(st.st_mode);
- if (!dst_isdir) {
- if (srcs.size() > 1) {
- sc.Error("target '%s' is not a directory", dst);
- return false;
- } else {
- size_t dst_len = strlen(dst);
-
- // A path that ends with a slash doesn't have to be a directory if
- // it doesn't exist yet.
- if (adb_is_separator(dst[dst_len - 1]) && dst_exists) {
- sc.Error("failed to access '%s': Not a directory", dst);
- return false;
- }
- }
- }
-
- for (const char* src_path : srcs) {
- const char* dst_path = dst;
- struct stat src_st;
- if (!sync_stat_fallback(sc, src_path, &src_st)) {
- if (errno == ENOPROTOOPT) {
- sc.Error("remote object '%s' does not exist", src_path);
- } else {
- sc.Error("failed to stat remote object '%s': %s", src_path, strerror(errno));
- }
-
- success = false;
- continue;
- }
-
- bool src_isdir = S_ISDIR(src_st.st_mode);
- if (src_isdir) {
- std::string dst_dir = dst;
-
- // If the destination path existed originally, the source directory
- // should be copied as a child of the destination.
- if (dst_exists) {
- if (!dst_isdir) {
- sc.Error("target '%s' is not a directory", dst);
- return false;
- }
- if (!adb_is_separator(dst_dir.back())) {
- dst_dir.push_back(OS_PATH_SEPARATOR);
- }
- dst_dir.append(android::base::Basename(src_path));
- }
-
- success &= copy_remote_dir_local(sc, src_path, dst_dir, copy_attrs, compressed);
- continue;
- } else if (!should_pull_file(src_st.st_mode)) {
- sc.Warning("skipping special file '%s' (mode = 0o%o)", src_path, src_st.st_mode);
- continue;
- }
-
- std::string path_holder;
- if (dst_isdir) {
- // If we're copying a remote file to a local directory, we
- // really want to copy to local_dir + OS_PATH_SEPARATOR +
- // basename(remote).
- path_holder = android::base::StringPrintf("%s%c%s", dst_path, OS_PATH_SEPARATOR,
- android::base::Basename(src_path).c_str());
- dst_path = path_holder.c_str();
- }
-
- sc.NewTransfer();
- sc.SetExpectedTotalBytes(src_st.st_size);
- if (!sync_recv(sc, src_path, dst_path, name, src_st.st_size, compressed)) {
- success = false;
- continue;
- }
-
- if (copy_attrs && set_time_and_mode(dst_path, src_st.st_mtime, src_st.st_mode) != 0) {
- success = false;
- continue;
- }
- sc.ReportTransferRate(src_path, TransferDirection::pull);
- }
-
- sc.ReportOverallTransferRate(TransferDirection::pull);
- return success;
-}
-
-bool do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only,
- bool compressed) {
- SyncConnection sc;
- if (!sc.IsValid()) return false;
-
- bool success = copy_local_dir_remote(sc, lpath, rpath, true, list_only, compressed);
- if (!list_only) {
- sc.ReportOverallTransferRate(TransferDirection::push);
- }
- return success;
-}
diff --git a/adb/client/file_sync_client.h b/adb/client/file_sync_client.h
deleted file mode 100644
index de3f19245..000000000
--- a/adb/client/file_sync_client.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <string>
-#include <vector>
-
-bool do_sync_ls(const char* path);
-bool do_sync_push(const std::vector<const char*>& srcs, const char* dst, bool sync,
- bool compressed);
-bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst, bool copy_attrs,
- bool compressed, const char* name = nullptr);
-
-bool do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only,
- bool compressed);
diff --git a/adb/client/incremental.cpp b/adb/client/incremental.cpp
deleted file mode 100644
index c8f69c381..000000000
--- a/adb/client/incremental.cpp
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "incremental.h"
-
-#include "incremental_utils.h"
-
-#include <android-base/file.h>
-#include <android-base/stringprintf.h>
-#include <openssl/base64.h>
-
-#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<unique_fd, std::vector<char>> read_signature(Size file_size,
- std::string signature_file,
- bool silent) {
- signature_file += IDSIG;
-
- struct stat st;
- if (stat(signature_file.c_str(), &st)) {
- if (!silent) {
- fprintf(stderr, "Failed to stat signature file %s. Abort.\n", signature_file.c_str());
- }
- return {};
- }
-
- unique_fd fd(adb_open(signature_file.c_str(), O_RDONLY));
- if (fd < 0) {
- if (!silent) {
- fprintf(stderr, "Failed to open signature file: %s. Abort.\n", signature_file.c_str());
- }
- return {};
- }
-
- auto [signature, tree_size] = read_id_sig_headers(fd);
- if (auto expected = verity_tree_size_for_file(file_size); tree_size != expected) {
- if (!silent) {
- fprintf(stderr,
- "Verity tree size mismatch in signature file: %s [was %lld, expected %lld].\n",
- signature_file.c_str(), (long long)tree_size, (long long)expected);
- }
- return {};
- }
-
- return {std::move(fd), std::move(signature)};
-}
-
-// Base64-encode signature bytes. Keeping fd at the position of start of verity tree.
-static std::pair<unique_fd, std::string> read_and_encode_signature(Size file_size,
- std::string signature_file,
- bool silent) {
- auto [fd, signature] = read_signature(file_size, std::move(signature_file), silent);
- if (!fd.ok()) {
- return {};
- }
-
- size_t base64_len = 0;
- if (!EVP_EncodedLength(&base64_len, signature.size())) {
- if (!silent) {
- fprintf(stderr, "Fail to estimate base64 encoded length. Abort.\n");
- }
- return {};
- }
- std::string encoded_signature(base64_len, '\0');
- encoded_signature.resize(EVP_EncodeBlock((uint8_t*)encoded_signature.data(),
- (const uint8_t*)signature.data(), signature.size()));
-
- return {std::move(fd), std::move(encoded_signature)};
-}
-
-// Send install-incremental to the device along with properly configured file descriptors in
-// streaming format. Once connection established, send all fs-verity tree bytes.
-static unique_fd start_install(const Files& files, const Args& passthrough_args, bool silent) {
- std::vector<std::string> command_args{"package", "install-incremental"};
- command_args.insert(command_args.end(), passthrough_args.begin(), passthrough_args.end());
-
- for (int i = 0, size = files.size(); i < size; ++i) {
- const auto& file = files[i];
-
- struct stat st;
- if (stat(file.c_str(), &st)) {
- if (!silent) {
- fprintf(stderr, "Failed to stat input file %s. Abort.\n", file.c_str());
- }
- return {};
- }
-
- auto [signature_fd, signature] = read_and_encode_signature(st.st_size, file, silent);
- if (!signature_fd.ok()) {
- return {};
- }
-
- auto file_desc = StringPrintf("%s:%lld:%d:%s:1", android::base::Basename(file).c_str(),
- (long long)st.st_size, i, signature.c_str());
- command_args.push_back(std::move(file_desc));
- }
-
- std::string error;
- auto connection_fd = unique_fd(send_abb_exec_command(command_args, &error));
- if (connection_fd < 0) {
- if (!silent) {
- fprintf(stderr, "Failed to run: %s, error: %s\n",
- android::base::Join(command_args, " ").c_str(), error.c_str());
- }
- return {};
- }
-
- return connection_fd;
-}
-
-bool can_install(const Files& files) {
- for (const auto& file : files) {
- struct stat st;
- if (stat(file.c_str(), &st)) {
- return false;
- }
-
- auto [fd, _] = read_signature(st.st_size, file, true);
- if (!fd.ok()) {
- return false;
- }
- }
- return true;
-}
-
-std::optional<Process> install(const Files& files, const Args& passthrough_args, bool silent) {
- auto connection_fd = start_install(files, passthrough_args, silent);
- if (connection_fd < 0) {
- if (!silent) {
- fprintf(stderr, "adb: failed to initiate installation on device.\n");
- }
- return {};
- }
-
- std::string adb_path = android::base::GetExecutablePath();
-
- auto osh = adb_get_os_handle(connection_fd.get());
-#ifdef _WIN32
- auto fd_param = std::to_string(reinterpret_cast<intptr_t>(osh));
-#else /* !_WIN32 a.k.a. Unix */
- auto fd_param = std::to_string(osh);
-#endif
-
- // pipe for child process to write output
- int print_fds[2];
- if (adb_socketpair(print_fds) != 0) {
- if (!silent) {
- fprintf(stderr, "Failed to create socket pair for child to print to parent\n");
- }
- return {};
- }
- auto [pipe_read_fd, pipe_write_fd] = print_fds;
- auto pipe_write_fd_param = std::to_string(intptr_t(adb_get_os_handle(pipe_write_fd)));
- close_on_exec(pipe_read_fd);
-
- std::vector<std::string> 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<Process, decltype(killOnExit)> serverKiller(&child, killOnExit);
-
- Result result = wait_for_installation(pipe_read_fd);
- adb_close(pipe_read_fd);
-
- if (result == Result::Success) {
- // adb client exits now but inc-server can continue
- serverKiller.release();
- }
- return child;
-}
-
-Result wait_for_installation(int read_fd) {
- static constexpr int maxMessageSize = 256;
- std::vector<char> 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 40e928aea..000000000
--- 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 <optional>
-#include <string>
-
-#include "sysdeps.h"
-
-namespace incremental {
-
-using Files = std::vector<std::string>;
-using Args = std::vector<std::string_view>;
-
-bool can_install(const Files& files);
-std::optional<Process> 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 bfe18c0b2..000000000
--- a/adb/client/incremental_server.cpp
+++ /dev/null
@@ -1,716 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define TRACE_TAG INCREMENTAL
-
-#include "incremental_server.h"
-
-#include <android-base/endian.h>
-#include <android-base/strings.h>
-#include <inttypes.h>
-#include <lz4.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <array>
-#include <deque>
-#include <fstream>
-#include <thread>
-#include <type_traits>
-#include <unordered_set>
-
-#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<off64_t>(blockIdx) * kBlockSize;
-}
-
-template <typename T>
-static inline constexpr T toBigEndian(T t) {
- using unsigned_type = std::make_unsigned_t<T>;
- if constexpr (std::is_same_v<T, int16_t>) {
- return htobe16(static_cast<unsigned_type>(t));
- } else if constexpr (std::is_same_v<T, int32_t>) {
- return htobe32(static_cast<unsigned_type>(t));
- } else if constexpr (std::is_same_v<T, int64_t>) {
- return htobe64(static_cast<unsigned_type>(t));
- } else {
- return t;
- }
-}
-
-template <typename T>
-static inline constexpr T readBigEndian(void* data) {
- using unsigned_type = std::make_unsigned_t<T>;
- if constexpr (std::is_same_v<T, int16_t>) {
- return static_cast<T>(be16toh(*reinterpret_cast<unsigned_type*>(data)));
- } else if constexpr (std::is_same_v<T, int32_t>) {
- return static_cast<T>(be32toh(*reinterpret_cast<unsigned_type*>(data)));
- } else if constexpr (std::is_same_v<T, int64_t>) {
- return static_cast<T>(be64toh(*reinterpret_cast<unsigned_type*>(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 <size_t Size = kBlockSize>
-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<BlockIdx>& PriorityBlocks() const { return priority_blocks_; }
-
- std::vector<bool> sentBlocks;
- NumBlocks sentBlocksCount = 0;
-
- std::vector<bool> 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<BlockIdx> 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<File> 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<BlockIdx>(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<RequestCommand> 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<TimePoint> startTime, int missesCount, int missesSent);
-
- unique_fd const adb_fd_;
- unique_fd const output_fd_;
- std::vector<File> files_;
-
- // Incoming data buffer.
- std::vector<char> buffer_;
-
- std::deque<PrefetchState> prefetches_;
- int compressed_ = 0, uncompressed_ = 0;
- long long sentSize_ = 0;
-
- static constexpr auto kChunkFlushSize = 31 * kBlockSize;
-
- std::vector<char> 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<RequestCommand> 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<RequestType>(&commandBuf[0]);
- request.file_id = readBigEndian<FileId>(&commandBuf[2]);
- request.block_idx = readBigEndian<BlockIdx>(&commandBuf[4]);
- return request;
-}
-
-bool IncrementalServer::SendTreeBlocksForDataBlock(const FileId fileId, const BlockIdx blockIdx) {
- auto& file = files_[fileId];
- const int32_t data_block_count = numBytesToNumBlocks(file.size);
-
- const int32_t total_nodes_count(file.sentTreeBlocks.size());
- const int32_t leaf_nodes_count = (data_block_count + kHashesPerBlock - 1) / kHashesPerBlock;
-
- const int32_t leaf_nodes_offset = total_nodes_count - leaf_nodes_count;
-
- // Leaf level, sending only 1 block.
- const int32_t leaf_idx = leaf_nodes_offset + blockIdx / kHashesPerBlock;
- if (file.sentTreeBlocks[leaf_idx]) {
- return true;
- }
- if (!SendTreeBlock(fileId, blockIdx, leaf_idx)) {
- return false;
- }
- file.sentTreeBlocks[leaf_idx] = true;
-
- // Non-leaf, sending EVERYTHING. This should be done only once.
- if (leaf_nodes_offset == 0 || file.sentTreeBlocks[0]) {
- return true;
- }
-
- for (int32_t i = 0; i < leaf_nodes_offset; ++i) {
- if (!SendTreeBlock(fileId, blockIdx, i)) {
- return false;
- }
- file.sentTreeBlocks[i] = true;
- }
- return true;
-}
-
-bool IncrementalServer::SendTreeBlock(FileId fileId, int32_t fileBlockIdx, BlockIdx blockIdx) {
- const auto& file = files_[fileId];
-
- BlockBuffer buffer;
- const int64_t bytesRead = file.ReadTreeBlock(blockIdx, buffer.data);
- if (bytesRead <= 0) {
- fprintf(stderr, "Failed to get data for %s.idsig at blockIdx=%d.\n", file.filepath,
- blockIdx);
- return false;
- }
-
- buffer.header.compression_type = kCompressionNone;
- buffer.header.block_type = kTypeHash;
- buffer.header.file_id = toBigEndian(fileId);
- buffer.header.block_size = toBigEndian(int16_t(bytesRead));
- buffer.header.block_idx = toBigEndian(blockIdx);
-
- Send(&buffer, ResponseHeader::responseSizeFor(bytesRead), /*flush=*/false);
-
- return true;
-}
-
-auto IncrementalServer::SendDataBlock(FileId fileId, BlockIdx blockIdx, bool flush) -> SendResult {
- auto& file = files_[fileId];
- if (blockIdx >= static_cast<long>(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<kCompressBound> 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<const char*>(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<int32_t>(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<TimePoint> 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<microseconds>(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<FileId> prefetchedFiles;
- bool doneSent = false;
- int missesCount = 0;
- int missesSent = 0;
-
- using namespace std::chrono;
- std::optional<TimePoint> 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<unique_fd, int64_t> 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<unique_fd, int64_t> open_signature(int64_t file_size, const char* filepath) {
- std::string signature_file(filepath);
- signature_file += IDSIG;
-
- unique_fd fd(adb_open(signature_file.c_str(), O_RDONLY));
- if (fd < 0) {
- error_exit("inc-server: failed to open file '%s'.", signature_file.c_str());
- }
-
- auto [tree_offset, tree_size] = skip_id_sig_headers(fd);
- if (auto expected = verity_tree_size_for_file(file_size); tree_size != expected) {
- error_exit("Verity tree size mismatch in signature file: %s [was %lld, expected %lld].\n",
- signature_file.c_str(), (long long)tree_size, (long long)expected);
- }
-
- int32_t data_block_count = numBytesToNumBlocks(file_size);
- int32_t leaf_nodes_count = (data_block_count + kHashesPerBlock - 1) / kHashesPerBlock;
- D("Verity tree loaded: %s, tree size: %d (%d blocks, %d leafs)", signature_file.c_str(),
- int(tree_size), int(numBytesToNumBlocks(tree_size)), int(leaf_nodes_count));
-
- return {std::move(fd), tree_offset};
-}
-
-bool serve(int connection_fd, int output_fd, int argc, const char** argv) {
- auto connection_ufd = unique_fd(connection_fd);
- auto output_ufd = unique_fd(output_fd);
- if (argc <= 0) {
- error_exit("inc-server: must specify at least one file.");
- }
-
- std::vector<File> 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 55b8215b8..000000000
--- 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 076b7665e..000000000
--- a/adb/client/incremental_utils.cpp
+++ /dev/null
@@ -1,366 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define TRACE_TAG INCREMENTAL
-
-#include "incremental_utils.h"
-
-#include <android-base/endian.h>
-#include <android-base/mapped_file.h>
-#include <android-base/strings.h>
-#include <ziparchive/zip_archive.h>
-#include <ziparchive/zip_writer.h>
-
-#include <cinttypes>
-#include <numeric>
-#include <unordered_set>
-
-#include "adb_io.h"
-#include "adb_trace.h"
-#include "sysdeps.h"
-
-namespace incremental {
-
-static constexpr inline int32_t offsetToBlockIndex(int64_t offset) {
- return (offset & ~(kBlockSize - 1)) >> 12;
-}
-
-Size verity_tree_blocks_for_file(Size fileSize) {
- if (fileSize == 0) {
- return 0;
- }
-
- constexpr int hash_per_block = kBlockSize / kDigestSize;
-
- Size total_tree_block_count = 0;
-
- auto block_count = 1 + (fileSize - 1) / kBlockSize;
- auto hash_block_count = block_count;
- for (auto i = 0; hash_block_count > 1; i++) {
- hash_block_count = (hash_block_count + hash_per_block - 1) / hash_per_block;
- total_tree_block_count += hash_block_count;
- }
- return total_tree_block_count;
-}
-
-Size verity_tree_size_for_file(Size fileSize) {
- return verity_tree_blocks_for_file(fileSize) * kBlockSize;
-}
-
-static inline int32_t read_int32(borrowed_fd fd) {
- int32_t result;
- return ReadFdExactly(fd, &result, sizeof(result)) ? result : -1;
-}
-
-static inline int32_t skip_int(borrowed_fd fd) {
- return adb_lseek(fd, 4, SEEK_CUR);
-}
-
-static inline void append_int(borrowed_fd fd, std::vector<char>* 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<char>* 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<std::vector<char>, int32_t> read_id_sig_headers(borrowed_fd fd) {
- std::vector<char> 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<off64_t, ssize_t> 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 <class T>
-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<int32_t>* 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 <class T>
-static void unduplicate(std::vector<T>& v) {
- std::unordered_set<T> 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<int32_t>(fd, maxEocdOffset - commentLen);
- if (sigBuf == kZipEocdRecSig) {
- commentLenBuf = valueAt<int16_t>(
- fd, maxEocdOffset - commentLen + kZipEocdCommentLengthFieldOffset);
- if (commentLenBuf == commentLen) {
- eocdOffset = maxEocdOffset - commentLen;
- break;
- }
- }
- }
-
- if (eocdOffset < 0) {
- return -1;
- }
-
- off64_t cdLen = static_cast<int64_t>(
- valueAt<int32_t>(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<int64_t>(fd, cdOffset - 2 * sizeof(int64_t)) != APK_SIG_BLOCK_MAGIC_LO ||
- valueAt<int64_t>(fd, cdOffset - sizeof(int64_t)) != APK_SIG_BLOCK_MAGIC_HI) {
- return -1;
- }
- int32_t signerSizeInFooter = valueAt<int32_t>(fd, cdOffset - kApkSigBlockFooterSize);
- off64_t signerBlockOffset = cdOffset - signerSizeInFooter - sizeof(int64_t);
- if (signerBlockOffset < 0) {
- return -1;
- }
- int32_t signerSizeInHeader = valueAt<int32_t>(fd, signerBlockOffset);
- if (signerSizeInFooter != signerSizeInHeader) {
- return -1;
- }
-
- return signerBlockOffset;
-}
-
-static std::vector<int32_t> ZipPriorityBlocks(off64_t signerBlockOffset, Size fileSize) {
- int32_t signerBlockIndex = offsetToBlockIndex(signerBlockOffset);
- int32_t lastBlockIndex = offsetToBlockIndex(fileSize);
- const auto numPriorityBlocks = lastBlockIndex - signerBlockIndex + 1;
-
- std::vector<int32_t> 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<ZipArchiveHandle, std::unique_ptr<android::base::MappedFile>> openZipArchive(
- borrowed_fd fd, Size fileSize) {
-#ifndef __LP64__
- if (fileSize >= INT_MAX) {
- return {openZipArchiveFd(fd), nullptr};
- }
-#endif
- auto mapping =
- android::base::MappedFile::FromOsHandle(adb_get_os_handle(fd), 0, fileSize, PROT_READ);
- if (!mapping) {
- D("%s failed at FromOsHandle: %d", __func__, errno);
- return {};
- }
- ZipArchiveHandle zip;
- if (OpenArchiveFromMemory(mapping->data(), mapping->size(), "apk_mapping", &zip) != 0) {
- D("%s failed at OpenArchiveFromMemory: %d", __func__, errno);
- return {};
- }
- return {zip, std::move(mapping)};
-}
-
-// TODO(b/151676293): avoid using libziparchive as it reads local file headers
-// which causes additional performance cost. Instead, only read from central directory.
-static std::vector<int32_t> InstallationPriorityBlocks(borrowed_fd fd, Size fileSize) {
- auto [zip, _] = openZipArchive(fd, fileSize);
- if (!zip) {
- return {};
- }
-
- void* cookie = nullptr;
- if (StartIteration(zip, &cookie) != 0) {
- D("%s failed at StartIteration: %d", __func__, errno);
- return {};
- }
-
- std::vector<int32_t> installationPriorityBlocks;
- ZipEntry entry;
- std::string_view entryName;
- while (Next(cookie, &entry, &entryName) == 0) {
- if (entryName == "resources.arsc" || entryName == "AndroidManifest.xml" ||
- entryName.starts_with("lib/")) {
- // Full entries are needed for installation
- off64_t entryStartOffset = entry.offset;
- off64_t entryEndOffset =
- entryStartOffset +
- (entry.method == kCompressStored ? entry.uncompressed_length
- : entry.compressed_length) +
- (entry.has_data_descriptor ? 16 /* sizeof(DataDescriptor) */ : 0);
- int32_t startBlockIndex = offsetToBlockIndex(entryStartOffset);
- int32_t endBlockIndex = offsetToBlockIndex(entryEndOffset);
- int32_t numNewBlocks = endBlockIndex - startBlockIndex + 1;
- appendBlocks(startBlockIndex, numNewBlocks, &installationPriorityBlocks);
- D("\tadding to priority blocks: '%.*s'", (int)entryName.size(), entryName.data());
- } else if (entryName == "classes.dex") {
- // Only the head is needed for installation
- int32_t startBlockIndex = offsetToBlockIndex(entry.offset);
- appendBlocks(startBlockIndex, 2, &installationPriorityBlocks);
- D("\tadding to priority blocks: '%.*s'", (int)entryName.size(), entryName.data());
- }
- }
-
- EndIteration(cookie);
- CloseArchive(zip);
- return installationPriorityBlocks;
-}
-
-std::vector<int32_t> 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<int32_t> priorityBlocks = ZipPriorityBlocks(signerOffset, fileSize);
- std::vector<int32_t> 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 fe2914dde..000000000
--- a/adb/client/incremental_utils.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "adb_unique_fd.h"
-
-#include <string>
-#include <string_view>
-#include <utility>
-#include <vector>
-
-#include <stdint.h>
-
-#include <android-base/off64_t.h>
-
-namespace incremental {
-
-using Size = int64_t;
-constexpr int kBlockSize = 4096;
-constexpr int kSha256DigestSize = 32;
-constexpr int kDigestSize = kSha256DigestSize;
-
-constexpr std::string_view IDSIG = ".idsig";
-
-std::vector<int32_t> 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<std::vector<char>, int32_t> read_id_sig_headers(borrowed_fd fd);
-std::pair<off64_t, ssize_t> 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 50c03e81b..000000000
--- 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 <stdio.h>
-#include <stdlib.h>
-#ifdef _WIN32
-#include <windows.h>
-#else
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <termios.h>
-#include <sys/time.h>
-#endif
-
-// Make sure printf is really adb_printf which works for UTF-8 on Windows.
-#include <sysdeps.h>
-
-// Stuff from ninja's util.h that's needed below.
-#include <vector>
-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<size_t>(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<SHORT>(csbi.dwCursorPosition.X + csbi.dwSize.X - 1),
- csbi.dwCursorPosition.Y
- };
- vector<CHAR_INFO> char_data(csbi.dwSize.X);
- for (size_t i = 0; i < static_cast<size_t>(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 4c4c7c6fa..000000000
--- 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 <stddef.h>
-#include <string>
-
-/// 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 78f7b8f20..000000000
--- a/adb/client/main.cpp
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define TRACE_TAG ADB
-
-#include "sysdeps.h"
-
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include <thread>
-
-#include <android-base/errors.h>
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/stringprintf.h>
-
-#include "adb.h"
-#include "adb_auth.h"
-#include "adb_client.h"
-#include "adb_listeners.h"
-#include "adb_utils.h"
-#include "adb_wifi.h"
-#include "client/usb.h"
-#include "commandline.h"
-#include "sysdeps/chrono.h"
-#include "transport.h"
-
-const char** __adb_argv;
-const char** __adb_envp;
-
-static void setup_daemon_logging() {
- const std::string log_file_path(GetLogFilePath());
- int fd = unix_open(log_file_path, O_WRONLY | O_CREAT | O_APPEND, 0640);
- if (fd == -1) {
- PLOG(FATAL) << "cannot open " << log_file_path;
- }
- if (dup2(fd, STDOUT_FILENO) == -1) {
- PLOG(FATAL) << "cannot redirect stdout";
- }
- if (dup2(fd, STDERR_FILENO) == -1) {
- PLOG(FATAL) << "cannot redirect stderr";
- }
- unix_close(fd);
-
- fprintf(stderr, "--- adb starting (pid %d) ---\n", getpid());
- LOG(INFO) << adb_version();
-}
-
-void adb_server_cleanup() {
- // Upon exit, we want to clean up in the following order:
- // 1. close_smartsockets, so that we don't get any new clients
- // 2. kick_all_transports, to avoid writing only part of a packet to a transport.
- // 3. usb_cleanup, to tear down the USB stack.
- close_smartsockets();
- kick_all_transports();
- usb_cleanup();
-}
-
-static void intentionally_leak() {
- void* p = ::operator new(1);
- // The analyzer is upset about this leaking. NOLINTNEXTLINE
- LOG(INFO) << "leaking pointer " << p;
-}
-
-int adb_server_main(int is_daemon, const std::string& socket_spec, int ack_reply_fd) {
-#if defined(_WIN32)
- // adb start-server starts us up with stdout and stderr hooked up to
- // anonymous pipes. When the C Runtime sees this, it makes stderr and
- // stdout buffered, but to improve the chance that error output is seen,
- // unbuffer stdout and stderr just like if we were run at the console.
- // This also keeps stderr unbuffered when it is redirected to adb.log.
- if (is_daemon) {
- if (setvbuf(stdout, nullptr, _IONBF, 0) == -1) {
- PLOG(FATAL) << "cannot make stdout unbuffered";
- }
- if (setvbuf(stderr, nullptr, _IONBF, 0) == -1) {
- PLOG(FATAL) << "cannot make stderr unbuffered";
- }
- }
-
- // TODO: On Ctrl-C, consider trying to kill a starting up adb server (if we're in
- // launch_server) by calling GenerateConsoleCtrlEvent().
-
- // On Windows, SIGBREAK is when Ctrl-Break is pressed or the console window is closed. It should
- // act like Ctrl-C.
- signal(SIGBREAK, [](int) { raise(SIGINT); });
-#endif
- signal(SIGINT, [](int) {
- fdevent_run_on_main_thread([]() { exit(0); });
- });
-
- char* leak = getenv("ADB_LEAK");
- if (leak && strcmp(leak, "1") == 0) {
- intentionally_leak();
- }
-
- if (is_daemon) {
- close_stdin();
- setup_daemon_logging();
- }
-
- atexit(adb_server_cleanup);
-
- init_transport_registration();
- init_reconnect_handler();
-
- adb_wifi_init();
- if (!getenv("ADB_MDNS") || strcmp(getenv("ADB_MDNS"), "0") != 0) {
- init_mdns_transport_discovery();
- }
-
- if (!getenv("ADB_USB") || strcmp(getenv("ADB_USB"), "0") != 0) {
- usb_init();
- } else {
- adb_notify_device_scan_complete();
- }
-
- if (!getenv("ADB_EMU") || strcmp(getenv("ADB_EMU"), "0") != 0) {
- local_init(android::base::StringPrintf("tcp:%d", DEFAULT_ADB_LOCAL_TRANSPORT_PORT));
- }
-
- std::string error;
-
- auto start = std::chrono::steady_clock::now();
-
- // If we told a previous adb server to quit because of version mismatch, we can get to this
- // point before it's finished exiting. Retry for a while to give it some time.
- while (install_listener(socket_spec, "*smartsocket*", nullptr, 0, nullptr, &error) !=
- INSTALL_STATUS_OK) {
- if (std::chrono::steady_clock::now() - start > 0.5s) {
- LOG(FATAL) << "could not install *smartsocket* listener: " << error;
- }
-
- std::this_thread::sleep_for(100ms);
- }
-
- adb_auth_init();
-
- if (is_daemon) {
-#if !defined(_WIN32)
- // Start a new session for the daemon. Do this here instead of after the fork so
- // that a ctrl-c between the "starting server" and "done starting server" messages
- // gets a chance to terminate the server.
- // setsid will fail with EPERM if it's already been a lead process of new session.
- // Ignore such error.
- if (setsid() == -1 && errno != EPERM) {
- PLOG(FATAL) << "setsid() failed";
- }
-#endif
-
- // Wait for the USB scan to complete before notifying the parent that we're up.
- // We need to perform this in a thread, because we would otherwise block the event loop.
- std::thread notify_thread([ack_reply_fd]() {
- adb_wait_for_device_initialization();
-
- // Any error output written to stderr now goes to adb.log. We could
- // keep around a copy of the stderr fd and use that to write any errors
- // encountered by the following code, but that is probably overkill.
-#if defined(_WIN32)
- const HANDLE ack_reply_handle = cast_int_to_handle(ack_reply_fd);
- const CHAR ack[] = "OK\n";
- const DWORD bytes_to_write = arraysize(ack) - 1;
- DWORD written = 0;
- if (!WriteFile(ack_reply_handle, ack, bytes_to_write, &written, NULL)) {
- LOG(FATAL) << "cannot write ACK to handle " << ack_reply_handle
- << android::base::SystemErrorCodeToString(GetLastError());
- }
- if (written != bytes_to_write) {
- LOG(FATAL) << "cannot write " << bytes_to_write << " bytes of ACK: only wrote "
- << written << " bytes";
- }
- CloseHandle(ack_reply_handle);
-#else
- // TODO(danalbert): Can't use SendOkay because we're sending "OK\n", not
- // "OKAY".
- if (!android::base::WriteStringToFd("OK\n", ack_reply_fd)) {
- PLOG(FATAL) << "error writing ACK to fd " << ack_reply_fd;
- }
- unix_close(ack_reply_fd);
-#endif
- });
- notify_thread.detach();
- }
-
-#if defined(__linux__)
- // Write our location to .android/adb.$PORT, so that older clients can exec us.
- std::string path;
- if (!android::base::Readlink("/proc/self/exe", &path)) {
- PLOG(ERROR) << "failed to readlink /proc/self/exe";
- }
-
- std::optional<std::string> 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<const char**>(argv);
- __adb_envp = const_cast<const char**>(envp);
- adb_trace_init(argv);
- return adb_commandline(argc - 1, const_cast<const char**>(argv + 1));
-}
diff --git a/adb/client/pairing/pairing_client.cpp b/adb/client/pairing/pairing_client.cpp
deleted file mode 100644
index 04bbcebd4..000000000
--- a/adb/client/pairing/pairing_client.cpp
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "client/pairing/pairing_client.h"
-
-#include <atomic>
-#include <iomanip>
-#include <mutex>
-#include <sstream>
-#include <thread>
-#include <vector>
-
-#include <android-base/logging.h>
-#include <android-base/parsenetaddress.h>
-#include <android-base/stringprintf.h>
-#include <android-base/thread_annotations.h>
-#include <android-base/unique_fd.h>
-#include <cutils/sockets.h>
-#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<PairingConnectionCtx, ConnectionDeleter>;
-
-class PairingClientImpl : public PairingClient {
- public:
- virtual ~PairingClientImpl();
-
- explicit PairingClientImpl(const Data& pswd, const PeerInfo& peer_info, const Data& cert,
- const Data& priv_key);
-
- // Starts the pairing client. This call is non-blocking. Upon pairing
- // completion, |cb| will be called with the PeerInfo on success,
- // or an empty value on failure.
- //
- // Returns true if PairingClient was successfully started. Otherwise,
- // return false.
- virtual bool Start(std::string_view ip_addr, pairing_client_result_cb cb,
- void* opaque) override;
-
- static void OnPairingResult(const PeerInfo* peer_info, int fd, void* opaque);
-
- private:
- // Setup and start the PairingConnection
- bool StartConnection();
-
- enum class State {
- Ready,
- Running,
- Stopped,
- };
-
- State state_ = State::Ready;
- Data pswd_;
- PeerInfo peer_info_;
- Data cert_;
- Data priv_key_;
- std::string host_;
- int port_;
-
- ConnectionPtr connection_;
- pairing_client_result_cb cb_;
- void* opaque_ = nullptr;
-}; // PairingClientImpl
-
-PairingClientImpl::PairingClientImpl(const Data& pswd, const PeerInfo& peer_info, const Data& cert,
- const Data& priv_key)
- : pswd_(pswd), peer_info_(peer_info), cert_(cert), priv_key_(priv_key) {
- CHECK(!pswd_.empty() && !cert_.empty() && !priv_key_.empty());
-
- state_ = State::Ready;
-}
-
-PairingClientImpl::~PairingClientImpl() {
- // Make sure to kill the PairingConnection before terminating the fdevent
- // looper.
- if (connection_ != nullptr) {
- connection_.reset();
- }
-}
-
-bool PairingClientImpl::Start(std::string_view ip_addr, pairing_client_result_cb cb, void* opaque) {
- CHECK(!ip_addr.empty());
- cb_ = cb;
- opaque_ = opaque;
-
- if (state_ != State::Ready) {
- LOG(ERROR) << "PairingClient already running or finished";
- return false;
- }
-
- // Try to parse the host address
- std::string err;
- CHECK(android::base::ParseNetAddress(std::string(ip_addr), &host_, &port_, nullptr, &err));
- CHECK(port_ > 0 && port_ <= 65535);
-
- if (!StartConnection()) {
- LOG(ERROR) << "Unable to start PairingClient connection";
- state_ = State::Stopped;
- return false;
- }
-
- state_ = State::Running;
- return true;
-}
-
-bool PairingClientImpl::StartConnection() {
- std::string err;
- const int timeout = 10; // seconds
- unique_fd fd(network_connect(host_, port_, SOCK_STREAM, timeout, &err));
- if (fd.get() == -1) {
- LOG(ERROR) << "Failed to start pairing connection client [" << err << "]";
- return false;
- }
- int off = 1;
- adb_setsockopt(fd.get(), IPPROTO_TCP, TCP_NODELAY, &off, sizeof(off));
-
- connection_ = ConnectionPtr(
- pairing_connection_client_new(pswd_.data(), pswd_.size(), &peer_info_, cert_.data(),
- cert_.size(), priv_key_.data(), priv_key_.size()));
- CHECK(connection_);
-
-#ifdef _WIN32
- int osh = cast_handle_to_int(adb_get_os_handle(fd.release()));
-#else
- int osh = adb_get_os_handle(fd.release());
-#endif
- if (!pairing_connection_start(connection_.get(), osh, OnPairingResult, this)) {
- LOG(ERROR) << "PairingClient failed to start the PairingConnection";
- state_ = State::Stopped;
- return false;
- }
-
- return true;
-}
-
-// static
-void PairingClientImpl::OnPairingResult(const PeerInfo* peer_info, int /* fd */, void* opaque) {
- auto* p = reinterpret_cast<PairingClientImpl*>(opaque);
- p->cb_(peer_info, p->opaque_);
-}
-
-} // namespace
-
-// static
-std::unique_ptr<PairingClient> 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<PairingClient>(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 dbd72a549..000000000
--- 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 <stddef.h>
-#include <stdint.h>
-
-#include <functional>
-#include <memory>
-#include <string_view>
-#include <vector>
-
-#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<uint8_t>;
-
- 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<PairingClient> 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 c69c1c2be..000000000
--- 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 <condition_variable>
-#include <mutex>
-#include <thread>
-
-#include <adbwifi/pairing/pairing_server.h>
-#include <android-base/logging.h>
-#include <gtest/gtest.h>
-
-#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<uint8_t> server_pswd,
- const std::vector<uint8_t> client_pswd) {
- std::vector<uint8_t> cert;
- std::vector<uint8_t> key;
- // Include the null-byte as well.
- cert.assign(reinterpret_cast<const uint8_t*>(kTestServerCert.data()),
- reinterpret_cast<const uint8_t*>(kTestServerCert.data()) +
- kTestServerCert.size() + 1);
- key.assign(reinterpret_cast<const uint8_t*>(kTestServerPrivKey.data()),
- reinterpret_cast<const uint8_t*>(kTestServerPrivKey.data()) +
- kTestServerPrivKey.size() + 1);
- server_ = PairingServer::create(server_pswd, server_info_, cert, key, kDefaultPairingPort);
- cert.assign(reinterpret_cast<const uint8_t*>(kTestClientCert.data()),
- reinterpret_cast<const uint8_t*>(kTestClientCert.data()) +
- kTestClientCert.size() + 1);
- key.assign(reinterpret_cast<const uint8_t*>(kTestClientPrivKey.data()),
- reinterpret_cast<const uint8_t*>(kTestClientPrivKey.data()) +
- kTestClientPrivKey.size() + 1);
- client_ = PairingClient::create(client_pswd, client_info_, cert, key, "127.0.0.1");
- }
-
- std::unique_ptr<PairingServer> createServer(const std::vector<uint8_t> pswd) {
- std::vector<uint8_t> cert;
- std::vector<uint8_t> key;
- // Include the null-byte as well.
- cert.assign(reinterpret_cast<const uint8_t*>(kTestServerCert.data()),
- reinterpret_cast<const uint8_t*>(kTestServerCert.data()) +
- kTestServerCert.size() + 1);
- key.assign(reinterpret_cast<const uint8_t*>(kTestServerPrivKey.data()),
- reinterpret_cast<const uint8_t*>(kTestServerPrivKey.data()) +
- kTestServerPrivKey.size() + 1);
- return PairingServer::create(pswd, server_info_, cert, key, kDefaultPairingPort);
- }
-
- std::unique_ptr<PairingClient> createClient(const std::vector<uint8_t> pswd) {
- std::vector<uint8_t> cert;
- std::vector<uint8_t> key;
- // Include the null-byte as well.
- cert.assign(reinterpret_cast<const uint8_t*>(kTestClientCert.data()),
- reinterpret_cast<const uint8_t*>(kTestClientCert.data()) +
- kTestClientCert.size() + 1);
- key.assign(reinterpret_cast<const uint8_t*>(kTestClientPrivKey.data()),
- reinterpret_cast<const uint8_t*>(kTestClientPrivKey.data()) +
- kTestClientPrivKey.size() + 1);
- return PairingClient::create(pswd, client_info_, cert, key, "127.0.0.1");
- }
-
- std::unique_ptr<PairingServer> server_;
- const PeerInfo server_info_ = {
- .name = "my_server_name",
- .guid = "my_server_guid",
- };
- std::unique_ptr<PairingClient> 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<uint8_t> 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<std::mutex> server_lock(server_mutex);
-
- auto server_callback = [&](const PeerInfo* peer_info, const std::vector<uint8_t>* 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<std::mutex> 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<std::mutex> client_lock(client_mutex);
- auto client_callback = [&](const PeerInfo* peer_info, const std::vector<uint8_t>* 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<std::mutex> 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<uint8_t> pswd{0x01, 0x03, 0x05, 0x07};
- std::vector<uint8_t> 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<std::mutex> server_lock(server_mutex);
-
- bool server_got_valid_pairing = true;
- auto server_callback = [&](const PeerInfo* peer_info, const std::vector<uint8_t>* 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<std::mutex> 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<std::mutex> client_lock(client_mutex);
- auto client_callback = [&](const PeerInfo* peer_info, const std::vector<uint8_t>* 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<std::mutex> 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<uint8_t> pswd{0x01, 0x03, 0x05, 0x07};
- std::vector<uint8_t> 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<std::mutex> server_lock(server_mutex);
-
- bool server_got_valid_pairing = true;
- auto server_callback = [&](const PeerInfo* peer_info, const std::vector<uint8_t>* 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<std::mutex> 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<std::unique_ptr<PairingClient>> clients;
- int num_clients_done = 0;
- int test_num_clients = 5;
- std::mutex client_mutex;
- std::condition_variable client_cv;
- std::unique_lock<std::mutex> 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<uint8_t>* cert,
- void* opaque) {
- ASSERT_EQ(nullptr, peer_info);
- ASSERT_EQ(nullptr, cert);
- EXPECT_EQ(nullptr, opaque);
-
- {
- std::lock_guard<std::mutex> 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<uint8_t> pswd{0x01, 0x03, 0x05, 0x07};
- std::vector<uint8_t> 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<std::mutex> server_lock(server_mutex);
-
- bool server_got_valid_pairing = false;
- auto server_callback = [&](const PeerInfo* peer_info, const std::vector<uint8_t>* 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<std::mutex> 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<std::unique_ptr<PairingClient>> clients;
- int num_clients_done = 0;
- int test_num_clients = 5;
- std::mutex client_mutex;
- std::condition_variable client_cv;
- std::unique_lock<std::mutex> client_lock(client_mutex);
- bool got_valid_pairing = false;
- while (clients.size() < test_num_clients) {
- std::unique_ptr<PairingClient> 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<uint8_t>* 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<std::mutex> 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<uint8_t>* cert,
- void* opaque) {
- ASSERT_EQ(nullptr, peer_info);
- ASSERT_EQ(nullptr, cert);
- EXPECT_EQ(nullptr, opaque);
-
- {
- std::lock_guard<std::mutex> 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 9201e7a0e..000000000
--- 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 <sys/epoll.h>
-#include <sys/eventfd.h>
-
-#include <atomic>
-#include <deque>
-#include <iomanip>
-#include <mutex>
-#include <sstream>
-#include <thread>
-#include <tuple>
-#include <unordered_map>
-#include <variant>
-#include <vector>
-
-#include <adbwifi/pairing/pairing_connection.h>
-#include <android-base/logging.h>
-#include <android-base/parsenetaddress.h>
-#include <android-base/thread_annotations.h>
-#include <android-base/unique_fd.h>
-#include <cutils/sockets.h>
-
-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<PairingConnection>;
- using NewConnectionEvent = std::tuple<unique_fd, ConnectionPtr>;
- // <fd, PeerInfo.name, PeerInfo.guid, certificate>
- using ConnectionFinishedEvent = std::tuple<FdVal, std::optional<std::string>,
- std::optional<std::string>, std::optional<Data>>;
- using ConnectionEvent = std::variant<NewConnectionEvent, ConnectionFinishedEvent>;
- // 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<ConnectionEvent> conn_write_queue_ GUARDED_BY(conn_mutex_);
- std::deque<ConnectionEvent> conn_read_queue_;
- // Map of fds to their PairingConnections currently running.
- std::unordered_map<FdVal, ConnectionPtr> 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<std::mutex> 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<std::mutex> 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<NewConnectionEvent>(&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<PairingServerImpl*>(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<std::mutex> 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<ConnectionFinishedEvent>(&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<std::mutex> lock(conn_mutex_);
- conn_write_queue_.push_back(std::move(event));
- }
- conn_cv_.notify_one();
-
- return true;
-}
-
-} // namespace
-
-// static
-std::unique_ptr<PairingServer> 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<PairingServer>(
- 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 6fb51ccf1..000000000
--- 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 <stddef.h>
-#include <stdint.h>
-
-#include <functional>
-#include <memory>
-#include <string_view>
-#include <vector>
-
-#include <adbwifi/pairing/pairing_connection.h>
-
-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<uint8_t>;
-
- 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<PairingServer> create(const Data& pswd, const PeerInfo& peer_info,
- const Data& certificate, const Data& priv_key,
- int port);
-
- protected:
- PairingServer() = default;
-}; // class PairingServer
-
-} // namespace pairing
-} // namespace adbwifi
diff --git a/adb/client/transport_mdns.cpp b/adb/client/transport_mdns.cpp
deleted file mode 100644
index 22b9b1808..000000000
--- a/adb/client/transport_mdns.cpp
+++ /dev/null
@@ -1,547 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define TRACE_TAG TRANSPORT
-
-#include "transport.h"
-
-#ifdef _WIN32
-#include <winsock2.h>
-#else
-#include <arpa/inet.h>
-#endif
-
-#include <memory>
-#include <thread>
-#include <vector>
-
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-#include <dns_sd.h>
-
-#include "adb_client.h"
-#include "adb_mdns.h"
-#include "adb_trace.h"
-#include "adb_utils.h"
-#include "adb_wifi.h"
-#include "fdevent/fdevent.h"
-#include "sysdeps.h"
-
-static DNSServiceRef service_refs[kNumADBDNSServices];
-static fdevent* service_ref_fdes[kNumADBDNSServices];
-
-static int adb_DNSServiceIndexByName(const char* regType) {
- for (int i = 0; i < kNumADBDNSServices; ++i) {
- if (!strncmp(regType, kADBDNSServices[i], strlen(kADBDNSServices[i]))) {
- return i;
- }
- }
- return -1;
-}
-
-static bool adb_DNSServiceShouldConnect(const char* regType, const char* serviceName) {
- int index = adb_DNSServiceIndexByName(regType);
- if (index == kADBTransportServiceRefIndex) {
- // Ignore adb-EMULATOR* service names, as it interferes with the
- // emulator ports that are already connected.
- if (android::base::StartsWith(serviceName, "adb-EMULATOR")) {
- LOG(INFO) << "Ignoring emulator transport service [" << serviceName << "]";
- return false;
- }
- }
- return (index == kADBTransportServiceRefIndex || index == kADBSecureConnectServiceRefIndex);
-}
-
-// Use adb_DNSServiceRefSockFD() instead of calling DNSServiceRefSockFD()
-// directly so that the socket is put through the appropriate compatibility
-// layers to work with the rest of ADB's internal APIs.
-static inline int adb_DNSServiceRefSockFD(DNSServiceRef ref) {
- return adb_register_socket(DNSServiceRefSockFD(ref));
-}
-#define DNSServiceRefSockFD ___xxx_DNSServiceRefSockFD
-
-static void DNSSD_API register_service_ip(DNSServiceRef sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- DNSServiceErrorType errorCode,
- const char* hostname,
- const sockaddr* address,
- uint32_t ttl,
- void* context);
-
-static void pump_service_ref(int /*fd*/, unsigned ev, void* data) {
- DNSServiceRef* ref = reinterpret_cast<DNSServiceRef*>(data);
-
- if (ev & FDE_READ)
- DNSServiceProcessResult(*ref);
-}
-
-class AsyncServiceRef {
- public:
- bool Initialized() {
- return initialized_;
- }
-
- virtual ~AsyncServiceRef() {
- if (!initialized_) {
- return;
- }
-
- // Order matters here! Must destroy the fdevent first since it has a
- // reference to |sdRef_|.
- fdevent_destroy(fde_);
- DNSServiceRefDeallocate(sdRef_);
- }
-
- protected:
- DNSServiceRef sdRef_;
-
- void Initialize() {
- fde_ = fdevent_create(adb_DNSServiceRefSockFD(sdRef_), pump_service_ref, &sdRef_);
- if (fde_ == nullptr) {
- D("Unable to create fdevent");
- return;
- }
- fdevent_set(fde_, FDE_READ);
- initialized_ = true;
- }
-
- private:
- bool initialized_ = false;
- fdevent* fde_;
-};
-
-class ResolvedService : public AsyncServiceRef {
- public:
- virtual ~ResolvedService() = default;
-
- ResolvedService(std::string serviceName, std::string regType, uint32_t interfaceIndex,
- const char* hosttarget, uint16_t port, int version)
- : serviceName_(serviceName),
- regType_(regType),
- hosttarget_(hosttarget),
- port_(port),
- sa_family_(0),
- ip_addr_data_(NULL),
- serviceVersion_(version) {
- memset(ip_addr_, 0, sizeof(ip_addr_));
-
- /* TODO: We should be able to get IPv6 support by adding
- * kDNSServiceProtocol_IPv6 to the flags below. However, when we do
- * this, we get served link-local addresses that are usually useless to
- * connect to. What's more, we seem to /only/ get those and nothing else.
- * If we want IPv6 in the future we'll have to figure out why.
- */
- DNSServiceErrorType ret =
- DNSServiceGetAddrInfo(
- &sdRef_, 0, interfaceIndex,
- kDNSServiceProtocol_IPv4, hosttarget,
- register_service_ip, reinterpret_cast<void*>(this));
-
- if (ret != kDNSServiceErr_NoError) {
- D("Got %d from DNSServiceGetAddrInfo.", ret);
- } else {
- Initialize();
- }
-
- D("Client version: %d Service version: %d\n", clientVersion_, serviceVersion_);
- }
-
- bool ConnectSecureWifiDevice() {
- if (!adb_wifi_is_known_host(serviceName_)) {
- LOG(INFO) << "serviceName=" << serviceName_ << " not in keystore";
- return false;
- }
-
- std::string response;
- connect_device(android::base::StringPrintf(addr_format_.c_str(), ip_addr_, port_),
- &response);
- D("Secure connect to %s regtype %s (%s:%hu) : %s", serviceName_.c_str(), regType_.c_str(),
- ip_addr_, port_, response.c_str());
- return true;
- }
-
- void Connect(const sockaddr* address) {
- sa_family_ = address->sa_family;
-
- if (sa_family_ == AF_INET) {
- ip_addr_data_ = &reinterpret_cast<const sockaddr_in*>(address)->sin_addr;
- addr_format_ = "%s:%hu";
- } else if (sa_family_ == AF_INET6) {
- ip_addr_data_ = &reinterpret_cast<const sockaddr_in6*>(address)->sin6_addr;
- addr_format_ = "[%s]:%hu";
- } else { // Should be impossible
- D("mDNS resolved non-IP address.");
- return;
- }
-
- // Winsock version requires the const cast Because Microsoft.
- if (!inet_ntop(sa_family_, const_cast<void*>(ip_addr_data_), ip_addr_, sizeof(ip_addr_))) {
- D("Could not convert IP address to string.");
- return;
- }
-
- // adb secure service needs to do something different from just
- // connecting here.
- if (adb_DNSServiceShouldConnect(regType_.c_str(), serviceName_.c_str())) {
- std::string response;
- D("Attempting to serviceName=[%s], regtype=[%s] ipaddr=(%s:%hu)", serviceName_.c_str(),
- regType_.c_str(), ip_addr_, port_);
- int index = adb_DNSServiceIndexByName(regType_.c_str());
- if (index == kADBSecureConnectServiceRefIndex) {
- ConnectSecureWifiDevice();
- } else {
- connect_device(android::base::StringPrintf(addr_format_.c_str(), ip_addr_, port_),
- &response);
- D("Connect to %s regtype %s (%s:%hu) : %s", serviceName_.c_str(), regType_.c_str(),
- ip_addr_, port_, response.c_str());
- }
- } else {
- D("Not immediately connecting to serviceName=[%s], regtype=[%s] ipaddr=(%s:%hu)",
- serviceName_.c_str(), regType_.c_str(), ip_addr_, port_);
- }
-
- int adbSecureServiceType = serviceIndex();
- switch (adbSecureServiceType) {
- case kADBSecurePairingServiceRefIndex:
- sAdbSecurePairingServices->push_back(this);
- break;
- case kADBSecureConnectServiceRefIndex:
- sAdbSecureConnectServices->push_back(this);
- break;
- default:
- break;
- }
- }
-
- int serviceIndex() const { return adb_DNSServiceIndexByName(regType_.c_str()); }
-
- std::string hostTarget() const { return hosttarget_; }
-
- std::string serviceName() const { return serviceName_; }
-
- std::string ipAddress() const { return ip_addr_; }
-
- uint16_t port() const { return port_; }
-
- using ServiceRegistry = std::vector<ResolvedService*>;
-
- static ServiceRegistry* sAdbSecurePairingServices;
- static ServiceRegistry* sAdbSecureConnectServices;
-
- static void initAdbSecure();
-
- static void forEachService(const ServiceRegistry& services, const std::string& hostname,
- adb_secure_foreach_service_callback cb);
-
- static bool connectByServiceName(const ServiceRegistry& services,
- const std::string& service_name);
-
- private:
- int clientVersion_ = ADB_SECURE_CLIENT_VERSION;
- std::string addr_format_;
- std::string serviceName_;
- std::string regType_;
- std::string hosttarget_;
- const uint16_t port_;
- int sa_family_;
- const void* ip_addr_data_;
- char ip_addr_[INET6_ADDRSTRLEN];
- int serviceVersion_;
-};
-
-// static
-std::vector<ResolvedService*>* ResolvedService::sAdbSecurePairingServices = NULL;
-
-// static
-std::vector<ResolvedService*>* ResolvedService::sAdbSecureConnectServices = NULL;
-
-// static
-void ResolvedService::initAdbSecure() {
- if (!sAdbSecurePairingServices) {
- sAdbSecurePairingServices = new ServiceRegistry;
- }
- if (!sAdbSecureConnectServices) {
- sAdbSecureConnectServices = new ServiceRegistry;
- }
-}
-
-// static
-void ResolvedService::forEachService(const ServiceRegistry& services,
- const std::string& wanted_service_name,
- adb_secure_foreach_service_callback cb) {
- initAdbSecure();
-
- for (auto service : services) {
- auto service_name = service->serviceName();
- auto ip = service->ipAddress();
- auto port = service->port();
-
- if (wanted_service_name == "") {
- cb(service_name.c_str(), ip.c_str(), port);
- } else if (service_name == wanted_service_name) {
- cb(service_name.c_str(), ip.c_str(), port);
- }
- }
-}
-
-// static
-bool ResolvedService::connectByServiceName(const ServiceRegistry& services,
- const std::string& service_name) {
- initAdbSecure();
- for (auto service : services) {
- if (service_name == service->serviceName()) {
- D("Got service_name match [%s]", service->serviceName().c_str());
- return service->ConnectSecureWifiDevice();
- }
- }
- D("No registered serviceNames matched [%s]", service_name.c_str());
- return false;
-}
-
-void adb_secure_foreach_pairing_service(const char* service_name,
- adb_secure_foreach_service_callback cb) {
- ResolvedService::forEachService(*ResolvedService::sAdbSecurePairingServices,
- service_name ? service_name : "", cb);
-}
-
-void adb_secure_foreach_connect_service(const char* service_name,
- adb_secure_foreach_service_callback cb) {
- ResolvedService::forEachService(*ResolvedService::sAdbSecureConnectServices,
- service_name ? service_name : "", cb);
-}
-
-bool adb_secure_connect_by_service_name(const char* service_name) {
- return ResolvedService::connectByServiceName(*ResolvedService::sAdbSecureConnectServices,
- service_name);
-}
-
-static void DNSSD_API register_service_ip(DNSServiceRef /*sdRef*/,
- DNSServiceFlags /*flags*/,
- uint32_t /*interfaceIndex*/,
- DNSServiceErrorType /*errorCode*/,
- const char* /*hostname*/,
- const sockaddr* address,
- uint32_t /*ttl*/,
- void* context) {
- D("Got IP for service.");
- std::unique_ptr<ResolvedService> data(
- reinterpret_cast<ResolvedService*>(context));
- data->Connect(address);
-
- // For ADB Secure services, keep those ResolvedService's around
- // for later processing with secure connection establishment.
- if (data->serviceIndex() != kADBTransportServiceRefIndex) {
- data.release();
- }
-}
-
-static void DNSSD_API register_resolved_mdns_service(DNSServiceRef sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- DNSServiceErrorType errorCode,
- const char* fullname,
- const char* hosttarget,
- uint16_t port,
- uint16_t txtLen,
- const unsigned char* txtRecord,
- void* context);
-
-class DiscoveredService : public AsyncServiceRef {
- public:
- DiscoveredService(uint32_t interfaceIndex, const char* serviceName, const char* regtype,
- const char* domain)
- : serviceName_(serviceName), regType_(regtype) {
- DNSServiceErrorType ret =
- DNSServiceResolve(&sdRef_, 0, interfaceIndex, serviceName, regtype,
- domain, register_resolved_mdns_service,
- reinterpret_cast<void*>(this));
-
- D("DNSServiceResolve for "
- "interfaceIndex %u "
- "serviceName %s "
- "regtype %s "
- "domain %s "
- ": %d",
- interfaceIndex, serviceName, regtype, domain, ret);
-
- if (ret == kDNSServiceErr_NoError) {
- Initialize();
- }
- }
-
- const char* ServiceName() {
- return serviceName_.c_str();
- }
-
- const char* RegType() { return regType_.c_str(); }
-
- private:
- std::string serviceName_;
- std::string regType_;
-};
-
-static void adb_RemoveDNSService(const char* regType, const char* serviceName) {
- int index = adb_DNSServiceIndexByName(regType);
- ResolvedService::ServiceRegistry* services;
- switch (index) {
- case kADBSecurePairingServiceRefIndex:
- services = ResolvedService::sAdbSecurePairingServices;
- break;
- case kADBSecureConnectServiceRefIndex:
- services = ResolvedService::sAdbSecureConnectServices;
- break;
- default:
- return;
- }
-
- std::string sName(serviceName);
- services->erase(std::remove_if(
- services->begin(), services->end(),
- [&sName](ResolvedService* service) { return (sName == service->serviceName()); }));
-}
-
-// Returns the version the device wanted to advertise,
-// or -1 if parsing fails.
-static int parse_version_from_txt_record(uint16_t txtLen, const unsigned char* txtRecord) {
- if (!txtLen) return -1;
- if (!txtRecord) return -1;
-
- // https://tools.ietf.org/html/rfc6763
- // """
- // 6.1. General Format Rules for DNS TXT Records
- //
- // A DNS TXT record can be up to 65535 (0xFFFF) bytes long. The total
- // length is indicated by the length given in the resource record header
- // in the DNS message. There is no way to tell directly from the data
- // alone how long it is (e.g., there is no length count at the start, or
- // terminating NULL byte at the end).
- // """
-
- // Let's trust the TXT record's length byte
- // Worst case, it wastes 255 bytes
- std::vector<char> 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<int>(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<DiscoveredService> discovered(
- reinterpret_cast<DiscoveredService*>(context));
-
- if (errorCode != kDNSServiceErr_NoError) {
- D("Got error %d resolving service.", errorCode);
- return;
- }
-
- // TODO: Reject certain combinations of invalid or mismatched client and
- // service versions here before creating anything.
- // At the moment, there is nothing to reject, so accept everything
- // as an optimistic default.
- auto serviceVersion = parse_version_from_txt_record(txtLen, txtRecord);
-
- auto resolved = new ResolvedService(discovered->ServiceName(), discovered->RegType(),
- interfaceIndex, hosttarget, ntohs(port), serviceVersion);
-
- if (! resolved->Initialized()) {
- D("Unable to init resolved service");
- delete resolved;
- }
-
- if (flags) { /* Only ever equals MoreComing or 0 */
- D("releasing discovered service");
- discovered.release();
- }
-}
-
-static void DNSSD_API on_service_browsed(DNSServiceRef sdRef, DNSServiceFlags flags,
- uint32_t interfaceIndex, DNSServiceErrorType errorCode,
- const char* serviceName, const char* regtype,
- const char* domain, void* /*context*/) {
- if (errorCode != kDNSServiceErr_NoError) {
- D("Got error %d during mDNS browse.", errorCode);
- DNSServiceRefDeallocate(sdRef);
- int serviceIndex = adb_DNSServiceIndexByName(regtype);
- if (serviceIndex != -1) {
- fdevent_destroy(service_ref_fdes[serviceIndex]);
- }
- return;
- }
-
- if (flags & kDNSServiceFlagsAdd) {
- D("%s: Discover found new serviceName=[%s] regtype=[%s] domain=[%s]", __func__, serviceName,
- regtype, domain);
- auto discovered = new DiscoveredService(interfaceIndex, serviceName, regtype, domain);
- if (!discovered->Initialized()) {
- delete discovered;
- }
- } else {
- D("%s: Discover lost serviceName=[%s] regtype=[%s] domain=[%s]", __func__, serviceName,
- regtype, domain);
- adb_RemoveDNSService(regtype, serviceName);
- }
-}
-
-void init_mdns_transport_discovery_thread(void) {
- int errorCodes[kNumADBDNSServices];
-
- for (int i = 0; i < kNumADBDNSServices; ++i) {
- errorCodes[i] = DNSServiceBrowse(&service_refs[i], 0, 0, kADBDNSServices[i], nullptr,
- on_service_browsed, nullptr);
-
- if (errorCodes[i] != kDNSServiceErr_NoError) {
- D("Got %d browsing for mDNS service %s.", errorCodes[i], kADBDNSServices[i]);
- }
-
- if (errorCodes[i] == kDNSServiceErr_NoError) {
- fdevent_run_on_main_thread([i]() {
- service_ref_fdes[i] = fdevent_create(adb_DNSServiceRefSockFD(service_refs[i]),
- pump_service_ref, &service_refs[i]);
- fdevent_set(service_ref_fdes[i], FDE_READ);
- });
- }
- }
-}
-
-void init_mdns_transport_discovery(void) {
- ResolvedService::initAdbSecure();
- std::thread(init_mdns_transport_discovery_thread).detach();
-}
diff --git a/adb/client/transport_usb.cpp b/adb/client/transport_usb.cpp
deleted file mode 100644
index 777edde0b..000000000
--- 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 <memory>
-
-#include "sysdeps.h"
-#include "transport.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#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<int>(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<size_t>(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<uint32_t>(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<int>(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<UsbConnection>(h);
- t->SetConnection(std::make_unique<BlockingConnectionAdapter>(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 b371788cc..000000000
--- 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 <sys/types.h>
-
-#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 7b97117de..000000000
--- 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 <android-base/logging.h>
-
-#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<libusb::usb_handle*>(h), data, len)
- : native::usb_write(reinterpret_cast<native::usb_handle*>(h), data, len);
-}
-
-int usb_read(usb_handle* h, void* data, int len) {
- return should_use_libusb()
- ? libusb::usb_read(reinterpret_cast<libusb::usb_handle*>(h), data, len)
- : native::usb_read(reinterpret_cast<native::usb_handle*>(h), data, len);
-}
-
-int usb_close(usb_handle* h) {
- return should_use_libusb() ? libusb::usb_close(reinterpret_cast<libusb::usb_handle*>(h))
- : native::usb_close(reinterpret_cast<native::usb_handle*>(h));
-}
-
-void usb_reset(usb_handle* h) {
- should_use_libusb() ? libusb::usb_reset(reinterpret_cast<libusb::usb_handle*>(h))
- : native::usb_reset(reinterpret_cast<native::usb_handle*>(h));
-}
-
-void usb_kick(usb_handle* h) {
- should_use_libusb() ? libusb::usb_kick(reinterpret_cast<libusb::usb_handle*>(h))
- : native::usb_kick(reinterpret_cast<native::usb_handle*>(h));
-}
-
-size_t usb_get_max_packet_size(usb_handle* h) {
- return should_use_libusb()
- ? libusb::usb_get_max_packet_size(reinterpret_cast<libusb::usb_handle*>(h))
- : native::usb_get_max_packet_size(reinterpret_cast<native::usb_handle*>(h));
-}
diff --git a/adb/client/usb_libusb.cpp b/adb/client/usb_libusb.cpp
deleted file mode 100644
index 07cbc9418..000000000
--- 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 <stdint.h>
-#include <stdlib.h>
-
-#include <atomic>
-#include <chrono>
-#include <condition_variable>
-#include <memory>
-#include <mutex>
-#include <string>
-#include <thread>
-#include <unordered_map>
-
-#include <libusb/libusb.h>
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-
-#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<libusb_config_descriptor, ConfigDescriptorDeleter>;
-
-struct DeviceHandleDeleter {
- void operator()(libusb_device_handle* h) {
- libusb_close(h);
- }
-};
-
-using unique_device_handle = std::unique_ptr<libusb_device_handle, DeviceHandleDeleter>;
-
-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<std::mutex> 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<bool> 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<std::string, std::unique_ptr<usb_handle>>();
-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 <iostream>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<std::mutex> 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<unsigned char*>(&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<usb_handle> 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<std::mutex> 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<int> 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<std::mutex> 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<usb_handle> 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<std::pair<libusb_hotplug_event, libusb_device*>>();
-static void hotplug_thread() {
- adb_thread_setname("libusb hotplug");
- while (true) {
- hotplug_queue.PopAll([](std::pair<libusb_hotplug_event, libusb_device*> 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>(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_info*>(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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<unsigned char*>(const_cast<void*>(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<std::mutex> 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<unsigned char*>(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<std::mutex> 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 95b1817dc..000000000
--- 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 <ctype.h>
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/usb/ch9.h>
-#include <linux/usbdevice_fs.h>
-#include <linux/version.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/time.h>
-#include <sys/sysmacros.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <chrono>
-#include <condition_variable>
-#include <list>
-#include <mutex>
-#include <string>
-#include <string_view>
-#include <thread>
-
-#include <android-base/file.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-
-#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<usb_handle*>();
-
-static int is_known_device(std::string_view dev_name) {
- std::lock_guard<std::mutex> 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<std::mutex> 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<DIR, int(*)(DIR*)> 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<DIR, int(*)(DIR*)> 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<std::mutex> 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<void*>(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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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_handle> 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<std::mutex> 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 a93fa3a6b..000000000
--- 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 <CoreFoundation/CoreFoundation.h>
-
-#include <IOKit/IOKitLib.h>
-#include <IOKit/IOCFPlugIn.h>
-#include <IOKit/usb/IOUSBLib.h>
-#include <IOKit/IOMessage.h>
-#include <mach/mach_port.h>
-
-#include <inttypes.h>
-#include <stdio.h>
-
-#include <atomic>
-#include <chrono>
-#include <memory>
-#include <mutex>
-#include <thread>
-#include <vector>
-
-#include <android-base/logging.h>
-#include <android-base/stringprintf.h>
-#include <android-base/thread_annotations.h>
-
-#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<bool> dead;
-
- usb_handle()
- : bulkIn(0),
- bulkOut(0),
- interface(nullptr),
- zero_mask(0),
- max_packet_size(0),
- mark(false),
- dead(false) {}
-};
-
-static std::atomic<bool> usb_inited_flag;
-
-static auto& g_usb_handles_mutex = *new std::mutex();
-static auto& g_usb_handles = *new std::vector<std::unique_ptr<usb_handle>>();
-
-static bool IsKnownDevice(const std::string& devpath) {
- std::lock_guard<std::mutex> 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<std::mutex> 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<usb_handle> handle) {
- handle->mark = true;
- std::lock_guard<std::mutex> lock(g_usb_handles_mutex);
- g_usb_handles.push_back(std::move(handle));
-}
-
-static void AndroidInterfaceAdded(io_iterator_t iterator);
-static std::unique_ptr<usb_handle> 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<usb_handle> 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<usb_handle> CheckInterface(IOUSBInterfaceInterface550** interface,
- UInt16 vendor, UInt16 product) {
- std::unique_ptr<usb_handle> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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 e209230c7..000000000
--- 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 <winsock2.h> // winsock.h *must* be included before windows.h.
-#include <windows.h>
-// clang-format on
-#include <usb100.h>
-#include <winerror.h>
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <algorithm>
-#include <mutex>
-#include <thread>
-
-#include <adb_api.h>
-
-#include <android-base/errors.h>
-
-#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<usb_handle*>& handle_list = *new std::vector<usb_handle*>();
-
-/// 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> lock(usb_lock);
- for (usb_handle* usb : handle_list) {
- usb_kick_locked(usb);
- }
-}
-
-} // namespace native
diff --git a/adb/crypto/Android.bp b/adb/crypto/Android.bp
deleted file mode 100644
index 9d14b030a..000000000
--- a/adb/crypto/Android.bp
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-cc_defaults {
- name: "libadb_crypto_defaults",
- cflags: [
- "-Wall",
- "-Wextra",
- "-Wthread-safety",
- "-Werror",
- ],
-
- compile_multilib: "both",
-
- srcs: [
- "key.cpp",
- "rsa_2048_key.cpp",
- "x509_generator.cpp",
- ],
-
- target: {
- windows: {
- compile_multilib: "first",
- enabled: true,
- },
- },
-
- export_include_dirs: ["include"],
-
- visibility: [
- "//system/core/adb:__subpackages__",
- "//bootable/recovery/minadbd:__subpackages__",
- ],
-
- host_supported: true,
- recovery_available: true,
-
- shared_libs: [
- "libadb_protos",
- "libbase",
- "liblog",
- "libcrypto",
- "libcrypto_utils",
- ],
-}
-
-cc_library {
- name: "libadb_crypto",
- defaults: ["libadb_crypto_defaults"],
-
- apex_available: [
- "com.android.adbd",
- "test_com.android.adbd",
- ],
-}
-
-// For running atest (b/147158681)
-cc_library_static {
- name: "libadb_crypto_static",
- defaults: ["libadb_crypto_defaults"],
-
- apex_available: [
- "//apex_available:platform",
- ],
-
- static_libs: [
- "libadb_protos_static",
- ],
-}
diff --git a/adb/crypto/include/adb/crypto/key.h b/adb/crypto/include/adb/crypto/key.h
deleted file mode 100644
index d9ce69e03..000000000
--- 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 <string>
-
-#include <openssl/evp.h>
-
-#include "key_type.pb.h"
-
-namespace adb {
-namespace crypto {
-
-// Class that represents a public/private key pair.
-class Key {
- public:
- explicit Key(bssl::UniquePtr<EVP_PKEY>&& 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<EVP_PKEY> 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 2983a84c4..000000000
--- 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 <memory>
-#include <optional>
-
-#include "adb/crypto/key.h"
-
-namespace adb {
-namespace crypto {
-
-// Create a new RSA2048 key pair.
-std::optional<Key> 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 a26924312..000000000
--- 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 <openssl/x509v3.h>
-
-namespace adb {
-namespace crypto {
-
-// Generate a X.509 certificate based on the key |pkey|.
-bssl::UniquePtr<X509> 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 4d870069c..000000000
--- 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 <android-base/logging.h>
-#include <openssl/bn.h>
-#include <openssl/pem.h>
-#include <openssl/rsa.h>
-
-namespace adb {
-namespace crypto {
-
-// static
-std::string Key::ToPEMString(EVP_PKEY* pkey) {
- bssl::UniquePtr<BIO> 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 7911af95f..000000000
--- a/adb/crypto/rsa_2048_key.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "adb/crypto/rsa_2048_key.h"
-
-#include <android-base/logging.h>
-#include <crypto_utils/android_pubkey.h>
-#include <openssl/bn.h>
-#include <openssl/rsa.h>
-
-namespace adb {
-namespace crypto {
-
-namespace {
-std::string get_user_info() {
- std::string hostname;
- if (getenv("HOSTNAME")) hostname = getenv("HOSTNAME");
-#if !defined(_WIN32)
- char buf[64];
- if (hostname.empty() && gethostname(buf, sizeof(buf)) != -1) hostname = buf;
-#endif
- if (hostname.empty()) hostname = "unknown";
-
- std::string username;
- if (getenv("LOGNAME")) username = getenv("LOGNAME");
-#if !defined(_WIN32)
- if (username.empty() && getlogin()) username = getlogin();
-#endif
- if (username.empty()) hostname = "unknown";
-
- return " " + username + "@" + hostname;
-}
-
-} // namespace
-
-bool CalculatePublicKey(std::string* out, RSA* private_key) {
- uint8_t binary_key_data[ANDROID_PUBKEY_ENCODED_SIZE];
- if (!android_pubkey_encode(private_key, binary_key_data, sizeof(binary_key_data))) {
- LOG(ERROR) << "Failed to convert to public key";
- return false;
- }
-
- size_t expected_length;
- if (!EVP_EncodedLength(&expected_length, sizeof(binary_key_data))) {
- LOG(ERROR) << "Public key too large to base64 encode";
- return false;
- }
-
- out->resize(expected_length);
- size_t actual_length = EVP_EncodeBlock(reinterpret_cast<uint8_t*>(out->data()), binary_key_data,
- sizeof(binary_key_data));
- out->resize(actual_length);
- out->append(get_user_info());
- return true;
-}
-
-std::optional<Key> CreateRSA2048Key() {
- bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new());
- bssl::UniquePtr<BIGNUM> exponent(BN_new());
- bssl::UniquePtr<RSA> 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>{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 b32dcf731..000000000
--- a/adb/crypto/tests/Android.bp
+++ /dev/null
@@ -1,41 +0,0 @@
-//
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-cc_test {
- name: "adb_crypto_test",
- srcs: [
- "rsa_2048_key_test.cpp",
- "x509_generator_test.cpp",
- ],
-
- compile_multilib: "first",
-
- shared_libs: [
- "libbase",
- "libcrypto",
- "libcrypto_utils",
- "libprotobuf-cpp-lite",
- ],
-
- // Let's statically link them so we don't have to install it onto the
- // system image for testing.
- static_libs: [
- "libadb_crypto_static",
- "libadb_protos_static",
- ],
-
- test_suites: ["device-tests"],
-}
diff --git a/adb/crypto/tests/key_test.cpp b/adb/crypto/tests/key_test.cpp
deleted file mode 100644
index 1feb6e8fb..000000000
--- 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 <gtest/gtest.h>
-
-#include <resolv.h>
-
-#include <adb/crypto/rsa_2048_key.h>
-#include <android-base/logging.h>
-#include <android-base/strings.h>
-#include <crypto_utils/android_pubkey.h>
-#include <openssl/err.h>
-#include <openssl/rsa.h>
-#include <openssl/sha.h>
-
-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: "<pub_key> <host_name>"
- 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<std::string> 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<uint8_t> sig(RSA_size(rsa));
- unsigned sig_len;
- EXPECT_EQ(RSA_sign(NID_sha1, reinterpret_cast<const uint8_t*>(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<const uint8_t*>(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 1d8880e15..000000000
--- 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 <gtest/gtest.h>
-
-#include <resolv.h>
-
-#include <adb/crypto/rsa_2048_key.h>
-#include <android-base/logging.h>
-#include <android-base/strings.h>
-#include <crypto_utils/android_pubkey.h>
-#include <openssl/err.h>
-#include <openssl/rsa.h>
-#include <openssl/sha.h>
-
-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: "<pub_key> <host_name>"
- 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<std::string> 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<uint8_t> sig(RSA_size(rsa));
- unsigned sig_len;
- EXPECT_EQ(RSA_sign(NID_sha1, reinterpret_cast<const uint8_t*>(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<const uint8_t*>(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 281776bd4..000000000
--- 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 <gtest/gtest.h>
-
-#include <adb/crypto/rsa_2048_key.h>
-#include <adb/crypto/x509_generator.h>
-#include <android-base/logging.h>
-#include <android-base/strings.h>
-
-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<std::string> 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 43b815304..000000000
--- 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 <vector>
-
-#include <android-base/logging.h>
-#include <crypto_utils/android_pubkey.h>
-#include <openssl/bn.h>
-#include <openssl/pem.h>
-#include <openssl/rsa.h>
-
-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<char> 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<X509> GenerateX509Certificate(EVP_PKEY* pkey) {
- CHECK(pkey);
- bssl::UniquePtr<X509> 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<const unsigned char*>("US"), -1, -1, 0);
- X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC,
- reinterpret_cast<const unsigned char*>("Android"), -1, -1, 0);
- X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
- reinterpret_cast<const unsigned char*>("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(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 17c25e88b..000000000
--- 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 <sys/wait.h>
-
-#include <android-base/cmsg.h>
-#include <android-base/strings.h>
-#include <cmd.h>
-
-#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<std::string_view> parseCmdArgs(std::string_view args) {
- std::vector<std::string_view> 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 e1df4a591..000000000
--- 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 <android-base/cmsg.h>
-
-namespace {
-
-struct AbbProcess;
-static auto& abbp = *new std::unique_ptr<AbbProcess>(std::make_unique<AbbProcess>());
-
-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 2f9e9b4d0..000000000
--- 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 <unistd.h>
-#include <optional>
-
-#include <adbd_auth.h>
-#include <android-base/properties.h>
-
-#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<bool> success;
- auto callback = [&](bool result) {
- {
- std::lock_guard<std::mutex> 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<uint16_t>(port);
- LOG(INFO) << "adbwifi started on port " << port_;
-
- std::unique_lock<std::mutex> 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<TlsServer*>(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 1a1e4ad62..000000000
--- 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 <resolv.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <algorithm>
-#include <chrono>
-#include <iomanip>
-#include <map>
-#include <memory>
-#include <thread>
-
-#include <adb/crypto/rsa_2048_key.h>
-#include <adb/tls/adb_ca_list.h>
-#include <adbd_auth.h>
-#include <android-base/file.h>
-#include <android-base/no_destructor.h>
-#include <android-base/strings.h>
-#include <crypto_utils/android_pubkey.h>
-#include <openssl/obj_mac.h>
-#include <openssl/rsa.h>
-#include <openssl/sha.h>
-#include <openssl/ssl.h>
-
-#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<std::map<uint32_t, weak_ptr<atransport>>> 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<void*>(id);
-}
-
-static atransport* transport_from_callback_arg(void* id) {
- uint64_t id_u64 = reinterpret_cast<uint64_t>(id);
- if (id_u64 > std::numeric_limits<uint32_t>::max()) {
- LOG(FATAL) << "transport_from_callback_arg called on out of range value: " << id_u64;
- }
-
- uint32_t id_u32 = static_cast<uint32_t>(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<bool(std::string_view public_key)> f) {
- adbd_auth_get_public_keys(
- auth_ctx,
- [](void* opaque, const char* public_key, size_t len) {
- return (*static_cast<decltype(f)*>(opaque))(std::string_view(public_key, len));
- },
- &f);
-}
-
-bssl::UniquePtr<STACK_OF(X509_NAME)> adbd_tls_client_ca_list() {
- if (!auth_required) {
- return nullptr;
- }
-
- bssl::UniquePtr<STACK_OF(X509_NAME)> 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<std::string> 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> 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<const char*>(&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<std::string> 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<const uint8_t*>(token), token_size,
- reinterpret_cast<const uint8_t*>(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> 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<std::string> 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<EVP_PKEY> 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 07f6e65e8..000000000
--- a/adb/daemon/file_sync_service.cpp
+++ /dev/null
@@ -1,816 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define TRACE_TAG SYNC
-
-#include "daemon/file_sync_service.h"
-
-#include "sysdeps.h"
-
-#include <dirent.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <utime.h>
-
-#include <memory>
-#include <optional>
-#include <span>
-#include <string>
-#include <vector>
-
-#include <android-base/file.h>
-#include <android-base/macros.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-
-#include <adbd_fs.h>
-
-// Needed for __android_log_security_bswrite.
-#include <private/android_logger.h>
-
-#if defined(__ANDROID__)
-#include <linux/capability.h>
-#include <selinux/android.h>
-#include <sys/xattr.h>
-#endif
-
-#include "adb.h"
-#include "adb_io.h"
-#include "adb_trace.h"
-#include "adb_utils.h"
-#include "brotli_utils.h"
-#include "file_sync_protocol.h"
-#include "security_log_tags.h"
-#include "sysdeps/errno.h"
-
-using android::base::borrowed_fd;
-using android::base::Dirname;
-using android::base::StringPrintf;
-
-static bool should_use_fs_config(const std::string& path) {
-#if defined(__ANDROID__)
- // TODO: use fs_config to configure permissions on /data too.
- return !android::base::StartsWith(path, "/data/");
-#else
- UNUSED(path);
- return false;
-#endif
-}
-
-static bool update_capabilities(const char* path, uint64_t capabilities) {
-#if defined(__ANDROID__)
- if (capabilities == 0) {
- // Ensure we clean up in case the capabilities weren't 0 in the past.
- removexattr(path, XATTR_NAME_CAPS);
- return true;
- }
-
- vfs_cap_data cap_data = {};
- cap_data.magic_etc = VFS_CAP_REVISION_2 | VFS_CAP_FLAGS_EFFECTIVE;
- cap_data.data[0].permitted = (capabilities & 0xffffffff);
- cap_data.data[0].inheritable = 0;
- cap_data.data[1].permitted = (capabilities >> 32);
- cap_data.data[1].inheritable = 0;
- return setxattr(path, XATTR_NAME_CAPS, &cap_data, sizeof(cap_data), 0) != -1;
-#else
- UNUSED(path, capabilities);
- return true;
-#endif
-}
-
-static bool secure_mkdirs(const std::string& path) {
- if (path[0] != '/') return false;
-
- std::vector<std::string> 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 <bool v2>
-static bool do_list(int s, const char* path) {
- dirent* de;
-
- using MessageType =
- std::conditional_t<v2, decltype(syncmsg::dent_v2), decltype(syncmsg::dent_v1)>;
- MessageType msg;
- uint32_t msg_id;
- if constexpr (v2) {
- msg_id = ID_DENT_V2;
- } else {
- msg_id = ID_DENT_V1;
- }
-
- std::unique_ptr<DIR, int(*)(DIR*)> 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<false>(s, path);
-}
-
-static bool do_list_v2(int s, const char* path) {
- return do_list<true>(s, path);
-}
-
-// Make sure that SendFail from adb_io.cpp isn't accidentally used in this file.
-#pragma GCC poison SendFail
-
-static bool SendSyncFail(borrowed_fd fd, const std::string& reason) {
- D("sync: failure: %s", reason.c_str());
-
- syncmsg msg;
- msg.data.id = ID_FAIL;
- msg.data.size = reason.size();
- return WriteFdExactly(fd, &msg.data, sizeof(msg.data)) && WriteFdExactly(fd, reason);
-}
-
-static bool SendSyncFailErrno(borrowed_fd fd, const std::string& reason) {
- return SendSyncFail(fd, StringPrintf("%s: %s", reason.c_str(), strerror(errno)));
-}
-
-static bool handle_send_file_compressed(borrowed_fd s, unique_fd fd, uint32_t* timestamp) {
- syncmsg msg;
- Block decode_buffer(SYNC_DATA_MAX);
- BrotliDecoder decoder(std::span(decode_buffer.data(), decode_buffer.size()));
- while (true) {
- if (!ReadFdExactly(s, &msg.data, sizeof(msg.data))) return false;
-
- if (msg.data.id != ID_DATA) {
- if (msg.data.id == ID_DONE) {
- *timestamp = msg.data.size;
- return true;
- }
- SendSyncFail(s, "invalid data message");
- return false;
- }
-
- Block block(msg.data.size);
- if (!ReadFdExactly(s, block.data(), msg.data.size)) return false;
- decoder.Append(std::move(block));
-
- while (true) {
- std::span<char> output;
- BrotliDecodeResult result = decoder.Decode(&output);
- if (result == BrotliDecodeResult::Error) {
- SendSyncFailErrno(s, "decompress failed");
- return false;
- }
-
- if (!WriteFdExactly(fd, output.data(), output.size())) {
- SendSyncFailErrno(s, "write failed");
- return false;
- }
-
- if (result == BrotliDecodeResult::NeedInput) {
- break;
- } else if (result == BrotliDecodeResult::MoreOutput) {
- continue;
- } else if (result == BrotliDecodeResult::Done) {
- break;
- } else {
- LOG(FATAL) << "invalid BrotliDecodeResult: " << static_cast<int>(result);
- }
- }
- }
-
- __builtin_unreachable();
-}
-
-static bool handle_send_file_uncompressed(borrowed_fd s, unique_fd fd, uint32_t* timestamp,
- std::vector<char>& buffer) {
- syncmsg msg;
-
- while (true) {
- if (!ReadFdExactly(s, &msg.data, sizeof(msg.data))) return false;
-
- if (msg.data.id != ID_DATA) {
- if (msg.data.id == ID_DONE) {
- *timestamp = msg.data.size;
- return true;
- }
- SendSyncFail(s, "invalid data message");
- return false;
- }
-
- if (msg.data.size > buffer.size()) { // TODO: resize buffer?
- SendSyncFail(s, "oversize data message");
- return false;
- }
- if (!ReadFdExactly(s, &buffer[0], msg.data.size)) return false;
- if (!WriteFdExactly(fd, &buffer[0], msg.data.size)) {
- SendSyncFailErrno(s, "write failed");
- return false;
- }
- }
-}
-
-static bool handle_send_file(borrowed_fd s, const char* path, uint32_t* timestamp, uid_t uid,
- gid_t gid, uint64_t capabilities, mode_t mode, bool compressed,
- std::vector<char>& buffer, bool do_unlink) {
- int rc;
- syncmsg msg;
-
- __android_log_security_bswrite(SEC_TAG_ADB_SEND_FILE, path);
-
- unique_fd fd(adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode));
-
- if (fd < 0 && errno == ENOENT) {
- if (!secure_mkdirs(Dirname(path))) {
- SendSyncFailErrno(s, "secure_mkdirs failed");
- goto fail;
- }
- fd.reset(adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode));
- }
- if (fd < 0 && errno == EEXIST) {
- fd.reset(adb_open_mode(path, O_WRONLY | O_CLOEXEC, mode));
- }
- if (fd < 0) {
- SendSyncFailErrno(s, "couldn't create file");
- goto fail;
- } else {
- if (fchown(fd.get(), uid, gid) == -1) {
- SendSyncFailErrno(s, "fchown failed");
- goto fail;
- }
-
-#if defined(__ANDROID__)
- // Not all filesystems support setting SELinux labels. http://b/23530370.
- selinux_android_restorecon(path, 0);
-#endif
-
- // fchown clears the setuid bit - restore it if present.
- // Ignore the result of calling fchmod. It's not supported
- // by all filesystems, so we don't check for success. b/12441485
- fchmod(fd.get(), mode);
- }
-
- {
- rc = posix_fadvise(fd.get(), 0, 0,
- POSIX_FADV_SEQUENTIAL | POSIX_FADV_NOREUSE | POSIX_FADV_WILLNEED);
- if (rc != 0) {
- D("[ Failed to fadvise: %s ]", strerror(rc));
- }
-
- bool result;
- if (compressed) {
- result = handle_send_file_compressed(s, std::move(fd), timestamp);
- } else {
- result = handle_send_file_uncompressed(s, std::move(fd), timestamp, buffer);
- }
-
- if (!result) {
- goto fail;
- }
-
- if (!update_capabilities(path, capabilities)) {
- SendSyncFailErrno(s, "update_capabilities failed");
- goto fail;
- }
-
- msg.status.id = ID_OKAY;
- msg.status.msglen = 0;
- return WriteFdExactly(s, &msg.status, sizeof(msg.status));
- }
-
-fail:
- // If there's a problem on the device, we'll send an ID_FAIL message and
- // close the socket. Unfortunately the kernel will sometimes throw that
- // data away if the other end keeps writing without reading (which is
- // the case with old versions of adb). To maintain compatibility, keep
- // reading and throwing away ID_DATA packets until the other side notices
- // that we've reported an error.
- while (true) {
- if (!ReadFdExactly(s, &msg.data, sizeof(msg.data))) break;
-
- if (msg.data.id == ID_DONE) {
- break;
- } else if (msg.data.id != ID_DATA) {
- char id[5];
- memcpy(id, &msg.data.id, sizeof(msg.data.id));
- id[4] = '\0';
- D("handle_send_fail received unexpected id '%s' during failure", id);
- break;
- }
-
- if (msg.data.size > buffer.size()) {
- D("handle_send_fail received oversized packet of length '%u' during failure",
- msg.data.size);
- break;
- }
-
- if (!ReadFdExactly(s, &buffer[0], msg.data.size)) break;
- }
-
- if (do_unlink) adb_unlink(path);
- return false;
-}
-
-#if defined(_WIN32)
-extern bool handle_send_link(int s, const std::string& path,
- uint32_t* timestamp, std::vector<char>& buffer)
- __attribute__((error("no symlinks on Windows")));
-#else
-static bool handle_send_link(int s, const std::string& path, uint32_t* timestamp,
- std::vector<char>& buffer) {
- syncmsg msg;
-
- if (!ReadFdExactly(s, &msg.data, sizeof(msg.data))) return false;
-
- if (msg.data.id != ID_DATA) {
- SendSyncFail(s, "invalid data message: expected ID_DATA");
- return false;
- }
-
- unsigned int len = msg.data.size;
- if (len > buffer.size()) { // TODO: resize buffer?
- SendSyncFail(s, "oversize data message");
- return false;
- }
- if (!ReadFdExactly(s, &buffer[0], len)) return false;
-
- std::string buf_link;
- if (!android::base::Readlink(path, &buf_link) || (buf_link != &buffer[0])) {
- adb_unlink(path.c_str());
- auto ret = symlink(&buffer[0], path.c_str());
- if (ret && errno == ENOENT) {
- if (!secure_mkdirs(Dirname(path))) {
- SendSyncFailErrno(s, "secure_mkdirs failed");
- return false;
- }
- ret = symlink(&buffer[0], path.c_str());
- }
- if (ret) {
- SendSyncFailErrno(s, "symlink failed");
- return false;
- }
- }
-
- if (!ReadFdExactly(s, &msg.data, sizeof(msg.data))) return false;
-
- if (msg.data.id == ID_DONE) {
- *timestamp = msg.data.size;
- msg.status.id = ID_OKAY;
- msg.status.msglen = 0;
- if (!WriteFdExactly(s, &msg.status, sizeof(msg.status))) return false;
- } else {
- SendSyncFail(s, "invalid data message: expected ID_DONE");
- return false;
- }
-
- return true;
-}
-#endif
-
-static bool send_impl(int s, const std::string& path, mode_t mode, bool compressed,
- std::vector<char>& buffer) {
- // Don't delete files before copying if they are not "regular" or symlinks.
- struct stat st;
- bool do_unlink = (lstat(path.c_str(), &st) == -1) || S_ISREG(st.st_mode) ||
- (S_ISLNK(st.st_mode) && !S_ISLNK(mode));
- if (do_unlink) {
- adb_unlink(path.c_str());
- }
-
- bool result;
- uint32_t timestamp;
- if (S_ISLNK(mode)) {
- result = handle_send_link(s, path, &timestamp, buffer);
- } else {
- // Copy user permission bits to "group" and "other" permissions.
- mode &= 0777;
- mode |= ((mode >> 3) & 0070);
- mode |= ((mode >> 3) & 0007);
-
- uid_t uid = -1;
- gid_t gid = -1;
- uint64_t capabilities = 0;
- if (should_use_fs_config(path)) {
- adbd_fs_config(path.c_str(), 0, nullptr, &uid, &gid, &mode, &capabilities);
- }
-
- result = handle_send_file(s, path.c_str(), &timestamp, uid, gid, capabilities, mode,
- compressed, buffer, do_unlink);
- }
-
- if (!result) {
- return false;
- }
-
- struct timeval tv[2];
- tv[0].tv_sec = timestamp;
- tv[0].tv_usec = 0;
- tv[1].tv_sec = timestamp;
- tv[1].tv_usec = 0;
- lutimes(path.c_str(), tv);
- return true;
-}
-
-static bool do_send_v1(int s, const std::string& spec, std::vector<char>& buffer) {
- // 'spec' is of the form "/some/path,0755". Break it up.
- size_t comma = spec.find_last_of(',');
- if (comma == std::string::npos) {
- SendSyncFail(s, "missing , in ID_SEND_V1");
- return false;
- }
-
- std::string path = spec.substr(0, comma);
-
- errno = 0;
- mode_t mode = strtoul(spec.substr(comma + 1).c_str(), nullptr, 0);
- if (errno != 0) {
- SendSyncFail(s, "bad mode");
- return false;
- }
-
- return send_impl(s, path, mode, false, buffer);
-}
-
-static bool do_send_v2(int s, const std::string& path, std::vector<char>& buffer) {
- // Read the setup packet.
- syncmsg msg;
- int rc = ReadFdExactly(s, &msg.send_v2_setup, sizeof(msg.send_v2_setup));
- if (rc == 0) {
- LOG(ERROR) << "failed to read send_v2 setup packet: EOF";
- return false;
- } else if (rc < 0) {
- PLOG(ERROR) << "failed to read send_v2 setup packet";
- }
-
- bool compressed = false;
- if (msg.send_v2_setup.flags & kSyncFlagBrotli) {
- msg.send_v2_setup.flags &= ~kSyncFlagBrotli;
- compressed = true;
- }
- if (msg.send_v2_setup.flags) {
- SendSyncFail(s, android::base::StringPrintf("unknown flags: %d", msg.send_v2_setup.flags));
- return false;
- }
-
- errno = 0;
- return send_impl(s, path, msg.send_v2_setup.mode, compressed, buffer);
-}
-
-static bool recv_uncompressed(borrowed_fd s, unique_fd fd, std::vector<char>& buffer) {
- syncmsg msg;
- msg.data.id = ID_DATA;
- std::optional<BrotliEncoder<SYNC_DATA_MAX>> encoder;
- while (true) {
- int r = adb_read(fd.get(), &buffer[0], buffer.size() - sizeof(msg.data));
- if (r <= 0) {
- if (r == 0) break;
- SendSyncFailErrno(s, "read failed");
- return false;
- }
- msg.data.size = r;
-
- if (!WriteFdExactly(s, &msg.data, sizeof(msg.data)) || !WriteFdExactly(s, &buffer[0], r)) {
- return false;
- }
- }
-
- return true;
-}
-
-static bool recv_compressed(borrowed_fd s, unique_fd fd) {
- syncmsg msg;
- msg.data.id = ID_DATA;
-
- BrotliEncoder<SYNC_DATA_MAX> encoder;
-
- bool sending = true;
- while (sending) {
- Block input(SYNC_DATA_MAX);
- int r = adb_read(fd.get(), input.data(), input.size());
- if (r < 0) {
- SendSyncFailErrno(s, "read failed");
- return false;
- }
-
- if (r == 0) {
- encoder.Finish();
- } else {
- input.resize(r);
- encoder.Append(std::move(input));
- }
-
- while (true) {
- Block output;
- BrotliEncodeResult result = encoder.Encode(&output);
- if (result == BrotliEncodeResult::Error) {
- SendSyncFailErrno(s, "compress failed");
- return false;
- }
-
- if (!output.empty()) {
- msg.data.size = output.size();
- if (!WriteFdExactly(s, &msg.data, sizeof(msg.data)) ||
- !WriteFdExactly(s, output.data(), output.size())) {
- return false;
- }
- }
-
- if (result == BrotliEncodeResult::Done) {
- sending = false;
- break;
- } else if (result == BrotliEncodeResult::NeedInput) {
- break;
- } else if (result == BrotliEncodeResult::MoreOutput) {
- continue;
- }
- }
- }
-
- return true;
-}
-
-static bool recv_impl(borrowed_fd s, const char* path, bool compressed, std::vector<char>& buffer) {
- __android_log_security_bswrite(SEC_TAG_ADB_RECV_FILE, path);
-
- unique_fd fd(adb_open(path, O_RDONLY | O_CLOEXEC));
- if (fd < 0) {
- SendSyncFailErrno(s, "open failed");
- return false;
- }
-
- int rc = posix_fadvise(fd.get(), 0, 0, POSIX_FADV_SEQUENTIAL | POSIX_FADV_NOREUSE);
- if (rc != 0) {
- D("[ Failed to fadvise: %s ]", strerror(rc));
- }
-
- bool result;
- if (compressed) {
- result = recv_compressed(s, std::move(fd));
- } else {
- result = recv_uncompressed(s, std::move(fd), buffer);
- }
-
- if (!result) {
- return false;
- }
-
- syncmsg msg;
- msg.data.id = ID_DONE;
- msg.data.size = 0;
- return WriteFdExactly(s, &msg.data, sizeof(msg.data));
-}
-
-static bool do_recv_v1(borrowed_fd s, const char* path, std::vector<char>& buffer) {
- return recv_impl(s, path, false, buffer);
-}
-
-static bool do_recv_v2(borrowed_fd s, const char* path, std::vector<char>& buffer) {
- syncmsg msg;
- // Read the setup packet.
- int rc = ReadFdExactly(s, &msg.recv_v2_setup, sizeof(msg.recv_v2_setup));
- if (rc == 0) {
- LOG(ERROR) << "failed to read recv_v2 setup packet: EOF";
- return false;
- } else if (rc < 0) {
- PLOG(ERROR) << "failed to read recv_v2 setup packet";
- }
-
- bool compressed = false;
- if (msg.recv_v2_setup.flags & kSyncFlagBrotli) {
- msg.recv_v2_setup.flags &= ~kSyncFlagBrotli;
- compressed = true;
- }
- if (msg.recv_v2_setup.flags) {
- SendSyncFail(s, android::base::StringPrintf("unknown flags: %d", msg.recv_v2_setup.flags));
- return false;
- }
-
- return recv_impl(s, path, compressed, buffer);
-}
-
-static const char* sync_id_to_name(uint32_t id) {
- switch (id) {
- case ID_LSTAT_V1:
- return "lstat_v1";
- case ID_LSTAT_V2:
- return "lstat_v2";
- case ID_STAT_V2:
- return "stat_v2";
- case ID_LIST_V1:
- return "list_v1";
- case ID_LIST_V2:
- return "list_v2";
- case ID_SEND_V1:
- return "send_v1";
- case ID_SEND_V2:
- return "send_v2";
- case ID_RECV_V1:
- return "recv_v1";
- case ID_RECV_V2:
- return "recv_v2";
- case ID_QUIT:
- return "quit";
- default:
- return "???";
- }
-}
-
-static bool handle_sync_command(int fd, std::vector<char>& 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<char> 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 f300e7b3a..000000000
--- 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 676f8e9db..000000000
--- 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 <errno.h>
-#include <fcntl.h>
-#include <linux/fb.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#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 bab44be36..000000000
--- 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 b92a7dec0..000000000
--- a/adb/daemon/jdwp_service.cpp
+++ /dev/null
@@ -1,438 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#if !ADB_HOST
-
-#define TRACE_TAG JDWP
-
-#include "sysdeps.h"
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <unistd.h>
-
-#include <list>
-#include <memory>
-#include <thread>
-#include <vector>
-
-#include <adbconnection/server.h>
-#include <android-base/cmsg.h>
-#include <android-base/unique_fd.h>
-
-#include "adb.h"
-#include "adb_io.h"
-#include "adb_unique_fd.h"
-#include "adb_utils.h"
-
-using android::base::borrowed_fd;
-using android::base::unique_fd;
-
-/* here's how these things work.
-
- when adbd starts, it creates a unix server socket
- named @jdwp-control (@ is a shortcut for "first byte is zero"
- to use the private namespace instead of the file system)
-
- when a new JDWP daemon thread starts in a new VM process, it creates
- a connection to @jdwp-control to announce its availability.
-
-
- JDWP thread @jdwp-control
- | |
- |-------------------------------> |
- | hello I'm in process <pid> |
- | |
- | |
-
- 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:<hostport> jdwp:<pid>"
-
- "jdwp:<pid>" is a new forward destination format used to target
- a given JDWP process on the device. when sutch a request arrives,
- adbd does the following:
-
- - first, it calls socketpair() to create a pair of equivalent
- sockets.
-
- - it attaches the first socket in the pair to a local socket
- which is itself attached to the transport's remote socket:
-
-
- - it sends the file descriptor of the second socket directly
- to the JDWP process with the help of sendmsg()
-
-
- JDWP thread @jdwp-control
- | |
- | <----------------------|
- | OK, try this file descriptor |
- | |
- | |
-
- then, the JDWP thread uses this new socket descriptor as its
- pass-through connection to the debugger (and receives the
- JDWP-Handshake message, answers to it, etc...)
-
- this gives the following graphics:
- ____________________________________
- | |
- | ADB Server (host) |
- | |
- Debugger <---> LocalSocket <----> RemoteSocket |
- | ^^ |
- |___________________________||_______|
- ||
- Transport ||
- (TCP for emulator - USB for device) ||
- ||
- ___________________________||_______
- | || |
- | ADBD (device) || |
- | VV |
- JDWP <======> LocalSocket <----> RemoteSocket |
- | |
- |____________________________________|
-
- due to the way adb works, this doesn't need a special socket
- type or fancy handling of socket termination if either the debugger
- or the JDWP process closes the connection.
-
- THIS IS THE SIMPLEST IMPLEMENTATION I COULD FIND, IF YOU HAPPEN
- TO HAVE A BETTER IDEA, LET ME KNOW - Digit
-
-**********************************************************************/
-
-/** JDWP PID List Support Code
- ** for each JDWP process, we record its pid and its connected socket
- **/
-
-static void jdwp_process_event(int socket, unsigned events, void* _proc);
-static void jdwp_process_list_updated(void);
-
-struct JdwpProcess;
-static auto& _jdwp_list = *new std::list<std::unique_ptr<JdwpProcess>>();
-
-struct JdwpProcess {
- JdwpProcess(unique_fd socket, pid_t pid) {
- CHECK(pid != 0);
-
- this->socket = socket;
- this->pid = pid;
- this->fde = fdevent_create(socket.release(), jdwp_process_event, this);
-
- if (!this->fde) {
- LOG(FATAL) << "could not create fdevent for new JDWP process";
- }
- }
-
- ~JdwpProcess() {
- if (this->socket >= 0) {
- adb_shutdown(this->socket);
- this->socket = -1;
- }
-
- if (this->fde) {
- fdevent_destroy(this->fde);
- this->fde = nullptr;
- }
-
- out_fds.clear();
- }
-
- void RemoveFromList() {
- auto pred = [this](const auto& proc) { return proc.get() == this; };
- _jdwp_list.remove_if(pred);
- }
-
- borrowed_fd socket = -1;
- int32_t pid = -1;
- fdevent* fde = nullptr;
-
- std::vector<unique_fd> out_fds;
-};
-
-static size_t jdwp_process_list(char* buffer, size_t bufferlen) {
- std::string temp;
-
- for (auto& proc : _jdwp_list) {
- std::string next = std::to_string(proc->pid) + "\n";
- if (temp.length() + next.length() > bufferlen) {
- D("truncating JDWP process list (max len = %zu)", bufferlen);
- break;
- }
- temp.append(next);
- }
-
- memcpy(buffer, temp.data(), temp.length());
- return temp.length();
-}
-
-static size_t jdwp_process_list_msg(char* buffer, size_t bufferlen) {
- // Message is length-prefixed with 4 hex digits in ASCII.
- static constexpr size_t header_len = 4;
- if (bufferlen < header_len) {
- LOG(FATAL) << "invalid JDWP process list buffer size: " << bufferlen;
- }
-
- char head[header_len + 1];
- size_t len = jdwp_process_list(buffer + header_len, bufferlen - header_len);
- snprintf(head, sizeof head, "%04zx", len);
- memcpy(buffer, head, header_len);
- return len + header_len;
-}
-
-static void jdwp_process_event(int socket, unsigned events, void* _proc) {
- JdwpProcess* proc = reinterpret_cast<JdwpProcess*>(_proc);
- CHECK_EQ(socket, proc->socket.get());
-
- if (events & FDE_READ) {
- // We already have the PID, if we can read from the socket, we've probably hit EOF.
- D("terminating JDWP connection %d", proc->pid);
- goto CloseProcess;
- }
-
- if (events & FDE_WRITE) {
- D("trying to send fd to JDWP process (count = %zu)", proc->out_fds.size());
- CHECK(!proc->out_fds.empty());
-
- int fd = proc->out_fds.back().get();
- if (android::base::SendFileDescriptors(socket, "", 1, fd) != 1) {
- D("sending new file descriptor to JDWP %d failed: %s", proc->pid, strerror(errno));
- goto CloseProcess;
- }
-
- D("sent file descriptor %d to JDWP process %d", fd, proc->pid);
-
- proc->out_fds.pop_back();
- if (proc->out_fds.empty()) {
- fdevent_del(proc->fde, FDE_WRITE);
- }
- }
-
- return;
-
-CloseProcess:
- proc->RemoveFromList();
- jdwp_process_list_updated();
-}
-
-unique_fd create_jdwp_connection_fd(int pid) {
- D("looking for pid %d in JDWP process list", pid);
-
- for (auto& proc : _jdwp_list) {
- if (proc->pid == pid) {
- int fds[2];
-
- if (adb_socketpair(fds) < 0) {
- D("%s: socket pair creation failed: %s", __FUNCTION__, strerror(errno));
- return unique_fd{};
- }
- D("socketpair: (%d,%d)", fds[0], fds[1]);
-
- proc->out_fds.emplace_back(fds[1]);
- if (proc->out_fds.size() == 1) {
- fdevent_add(proc->fde, FDE_WRITE);
- }
-
- return unique_fd{fds[0]};
- }
- }
- D("search failed !!");
- return unique_fd{};
-}
-
-/** "jdwp" local service implementation
- ** this simply returns the list of known JDWP process pids
- **/
-
-struct JdwpSocket : public asocket {
- bool pass = false;
-};
-
-static void jdwp_socket_close(asocket* s) {
- D("LS(%d): closing jdwp socket", s->id);
-
- if (s->peer) {
- D("LS(%d) peer->close()ing peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd);
- s->peer->peer = nullptr;
- s->peer->close(s->peer);
- s->peer = nullptr;
- }
-
- remove_socket(s);
- delete s;
-}
-
-static int jdwp_socket_enqueue(asocket* s, apacket::payload_type) {
- /* you can't write to this asocket */
- D("LS(%d): JDWP socket received data?", s->id);
- s->peer->close(s->peer);
- return -1;
-}
-
-static void jdwp_socket_ready(asocket* s) {
- JdwpSocket* jdwp = (JdwpSocket*)s;
- asocket* peer = jdwp->peer;
-
- /* on the first call, send the list of pids,
- * on the second one, close the connection
- */
- if (!jdwp->pass) {
- apacket::payload_type data;
- data.resize(s->get_max_payload());
- size_t len = jdwp_process_list(&data[0], data.size());
- data.resize(len);
- peer->enqueue(peer, std::move(data));
- jdwp->pass = true;
- } else {
- peer->close(peer);
- }
-}
-
-asocket* create_jdwp_service_socket(void) {
- JdwpSocket* s = new JdwpSocket();
-
- if (!s) {
- LOG(FATAL) << "failed to allocate JdwpSocket";
- }
-
- install_local_socket(s);
-
- s->ready = jdwp_socket_ready;
- s->enqueue = jdwp_socket_enqueue;
- s->close = jdwp_socket_close;
- s->pass = false;
-
- return s;
-}
-
-/** "track-jdwp" local service implementation
- ** this periodically sends the list of known JDWP process pids
- ** to the client...
- **/
-
-struct JdwpTracker : public asocket {
- bool need_initial;
-};
-
-static auto& _jdwp_trackers = *new std::vector<std::unique_ptr<JdwpTracker>>();
-
-static void jdwp_process_list_updated(void) {
- std::string data;
- data.resize(1024);
- data.resize(jdwp_process_list_msg(&data[0], data.size()));
-
- for (auto& t : _jdwp_trackers) {
- if (t->peer) {
- // The tracker might not have been connected yet.
- apacket::payload_type payload(data.begin(), data.end());
- t->peer->enqueue(t->peer, std::move(payload));
- }
- }
-}
-
-static void jdwp_tracker_close(asocket* s) {
- D("LS(%d): destroying jdwp tracker service", s->id);
-
- if (s->peer) {
- D("LS(%d) peer->close()ing peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd);
- s->peer->peer = nullptr;
- s->peer->close(s->peer);
- s->peer = nullptr;
- }
-
- remove_socket(s);
-
- auto pred = [s](const auto& tracker) { return tracker.get() == s; };
- _jdwp_trackers.erase(std::remove_if(_jdwp_trackers.begin(), _jdwp_trackers.end(), pred),
- _jdwp_trackers.end());
-}
-
-static void jdwp_tracker_ready(asocket* s) {
- JdwpTracker* t = (JdwpTracker*)s;
-
- if (t->need_initial) {
- apacket::payload_type data;
- data.resize(s->get_max_payload());
- data.resize(jdwp_process_list_msg(&data[0], data.size()));
- t->need_initial = false;
- s->peer->enqueue(s->peer, std::move(data));
- }
-}
-
-static int jdwp_tracker_enqueue(asocket* s, apacket::payload_type) {
- /* you can't write to this socket */
- D("LS(%d): JDWP tracker received data?", s->id);
- s->peer->close(s->peer);
- return -1;
-}
-
-asocket* create_jdwp_tracker_service_socket(void) {
- auto t = std::make_unique<JdwpTracker>();
- if (!t) {
- LOG(FATAL) << "failed to allocate JdwpTracker";
- }
-
- memset(t.get(), 0, sizeof(asocket));
-
- install_local_socket(t.get());
- D("LS(%d): created new jdwp tracker service", t->id);
-
- t->ready = jdwp_tracker_ready;
- t->enqueue = jdwp_tracker_enqueue;
- t->close = jdwp_tracker_close;
- t->need_initial = true;
-
- asocket* result = t.get();
-
- _jdwp_trackers.emplace_back(std::move(t));
-
- return result;
-}
-
-int init_jdwp(void) {
- std::thread([]() {
- adb_thread_setname("jdwp control");
- adbconnection_listen([](int fd, pid_t pid) {
- LOG(INFO) << "jdwp connection from " << pid;
- fdevent_run_on_main_thread([fd, pid] {
- unique_fd ufd(fd);
- auto proc = std::make_unique<JdwpProcess>(std::move(ufd), pid);
- if (!proc) {
- LOG(FATAL) << "failed to allocate JdwpProcess";
- }
- _jdwp_list.emplace_back(std::move(proc));
- jdwp_process_list_updated();
- });
- });
- }).detach();
- return 0;
-}
-
-#endif /* !ADB_HOST */
diff --git a/adb/daemon/logging.cpp b/adb/daemon/logging.cpp
deleted file mode 100644
index 203c6c73d..000000000
--- 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 <mutex>
-#include <optional>
-#include <string_view>
-
-#include <android-base/no_destructor.h>
-#include <android-base/properties.h>
-#include <android-base/strings.h>
-#include <android-base/thread_annotations.h>
-
-#if defined(__ANDROID__)
-struct LogStatus {
- bool enabled[static_cast<size_t>(adb::LogType::COUNT)];
-
- bool& operator[](adb::LogType type) { return enabled[static_cast<size_t>(type)]; }
-};
-
-using android::base::CachedProperty;
-using android::base::NoDestructor;
-
-static NoDestructor<std::mutex> log_mutex;
-static NoDestructor<CachedProperty> log_property GUARDED_BY(log_mutex)("debug.adbd.logging");
-static std::optional<LogStatus> cached_log_status GUARDED_BY(log_mutex);
-
-static NoDestructor<CachedProperty> persist_log_property
- GUARDED_BY(log_mutex)("persist.debug.adbd.logging");
-static std::optional<LogStatus> 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<LogStatus>* 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<std::mutex> 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 3e28bef31..000000000
--- 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 <android-base/logging.h>
-
-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 7a0f7ffcd..000000000
--- a/adb/daemon/main.cpp
+++ /dev/null
@@ -1,344 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define TRACE_TAG ADB
-
-#include "sysdeps.h"
-
-#if defined(__BIONIC__)
-#include <android/fdsan.h>
-#endif
-
-#include <errno.h>
-#include <getopt.h>
-#include <malloc.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/capability.h>
-#include <sys/prctl.h>
-
-#include <memory>
-#include <vector>
-
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <android-base/properties.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-
-#if defined(__ANDROID__)
-#include <libminijail.h>
-#include <log/log_properties.h>
-#include <scoped_minijail.h>
-
-#include <private/android_filesystem_config.h>
-#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<std::remove_pointer<cap_t>::type, std::function<void(cap_t)>>;
- ScopedCaps caps(cap_get_proc(), &cap_free);
- if (cap_clear_flag(caps.get(), CAP_INHERITABLE) == -1) {
- PLOG(FATAL) << "cap_clear_flag(INHERITABLE) failed";
- }
- if (cap_clear_flag(caps.get(), CAP_EFFECTIVE) == -1) {
- PLOG(FATAL) << "cap_clear_flag(PEMITTED) failed";
- }
- if (cap_clear_flag(caps.get(), CAP_PERMITTED) == -1) {
- PLOG(FATAL) << "cap_clear_flag(PEMITTED) failed";
- }
- if (cap_set_proc(caps.get()) != 0) {
- PLOG(FATAL) << "cap_set_proc() failed";
- }
-
- D("Local port disabled");
- } else {
- // minijail_enter() will abort if any priv-dropping step fails.
- minijail_enter(jail.get());
-
- if (root_seclabel != nullptr) {
- if (selinux_android_setcon(root_seclabel) < 0) {
- LOG(FATAL) << "Could not set SELinux context";
- }
- }
- std::string error;
- std::string local_name =
- android::base::StringPrintf("tcp:%d", server_port);
- if (install_listener(local_name, "*smartsocket*", nullptr, 0, nullptr, &error)) {
- LOG(FATAL) << "Could not install *smartsocket* listener: " << error;
- }
- }
-}
-#endif
-
-static void setup_adb(const std::vector<std::string>& 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<std::string> addrs;
- std::string prop_addr = android::base::GetProperty("service.adb.listen_addrs", "");
- if (prop_addr.empty()) {
- std::string prop_port = android::base::GetProperty("service.adb.tcp.port", "");
- if (prop_port.empty()) {
- prop_port = android::base::GetProperty("persist.adb.tcp.port", "");
- }
-
-#if !defined(__ANDROID__)
- if (prop_port.empty() && getenv("ADBD_PORT")) {
- prop_port = getenv("ADBD_PORT");
- }
-#endif
-
- int port;
- if (sscanf(prop_port.c_str(), "%d", &port) == 1 && port > 0) {
- D("using tcp port=%d", port);
- // Listen on TCP and VSOCK port specified by service.adb.tcp.port property.
- addrs.push_back(android::base::StringPrintf("tcp:%d", port));
- addrs.push_back(android::base::StringPrintf("vsock:%d", port));
- setup_adb(addrs);
- } else if (!is_usb) {
- // Listen on default port.
- addrs.push_back(
- android::base::StringPrintf("tcp:%d", DEFAULT_ADB_LOCAL_TRANSPORT_PORT));
- addrs.push_back(
- android::base::StringPrintf("vsock:%d", DEFAULT_ADB_LOCAL_TRANSPORT_PORT));
- setup_adb(addrs);
- }
- } else {
- addrs = android::base::Split(prop_addr, ",");
- setup_adb(addrs);
- }
-
- D("adbd_main(): pre init_jdwp()");
- init_jdwp();
- D("adbd_main(): post init_jdwp()");
-
- D("Event loop starting");
- fdevent_loop();
-
- return 0;
-}
-
-int main(int argc, char** argv) {
-#if defined(__BIONIC__)
- // Set M_DECAY_TIME so that our allocations aren't immediately purged on free.
- mallopt(M_DECAY_TIME, 1);
-#endif
-
- while (true) {
- static struct option opts[] = {
- {"root_seclabel", required_argument, nullptr, 's'},
- {"device_banner", required_argument, nullptr, 'b'},
- {"version", no_argument, nullptr, 'v'},
- {"logpostfsdata", no_argument, nullptr, 'l'},
- };
-
- int option_index = 0;
- int c = getopt_long(argc, argv, "", opts, &option_index);
- if (c == -1) {
- break;
- }
-
- switch (c) {
-#if defined(__ANDROID__)
- case 's':
- root_seclabel = optarg;
- break;
-#endif
- case 'b':
- adb_device_banner = optarg;
- break;
- case 'v':
- printf("Android Debug Bridge Daemon version %d.%d.%d\n", ADB_VERSION_MAJOR,
- ADB_VERSION_MINOR, ADB_SERVER_VERSION);
- return 0;
- case 'l':
- LOG(ERROR) << "post-fs-data triggered";
- return 0;
- default:
- // getopt already prints "adbd: invalid option -- %c" for us.
- return 1;
- }
- }
-
- close_stdin();
-
- adb_trace_init(argv);
-
- D("Handling main()");
- return adbd_main(DEFAULT_ADB_PORT);
-}
diff --git a/adb/daemon/mdns.cpp b/adb/daemon/mdns.cpp
deleted file mode 100644
index fa692c039..000000000
--- 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 <dns_sd.h>
-#include <endian.h>
-#include <unistd.h>
-
-#include <chrono>
-#include <mutex>
-#include <random>
-#include <thread>
-
-#include <android-base/logging.h>
-#include <android-base/properties.h>
-
-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<std::mutex> 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<char> 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<std::mutex> 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<uint8_t> dist(0, 61);
- for (size_t i = 0; i < len; ++i) {
- uint8_t val = dist(mt);
- if (val < 10) {
- ret += '0' + val;
- } else if (val < 36) {
- ret += 'A' + (val - 10);
- } else {
- ret += 'a' + (val - 36);
- }
- }
- return ret;
-}
-
-static std::string GenerateDeviceGuid() {
- // The format is adb-<serial_no>-<six-random-alphanum>
- 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<std::mutex> lock(mdns_lock);
- return mdns_registered[kADBSecureConnectServiceRefIndex];
-}
diff --git a/adb/daemon/mdns.h b/adb/daemon/mdns.h
deleted file mode 100644
index e7e7a6217..000000000
--- 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 16d262798..000000000
--- 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 <unistd.h>
-
-#include <android-base/logging.h>
-#include <android-base/properties.h>
-#include <android-base/stringprintf.h>
-#include <log/log_properties.h>
-
-#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 19840bd58..000000000
--- 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 6bbf66e8e..000000000
--- a/adb/daemon/services.cpp
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define TRACE_TAG SERVICES
-
-#include "sysdeps.h"
-
-#include <errno.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <unistd.h>
-
-#include <thread>
-
-#include <android-base/file.h>
-#include <android-base/parseint.h>
-#include <android-base/parsenetaddress.h>
-#include <android-base/properties.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-#include <android-base/unique_fd.h>
-#include <cutils/android_reboot.h>
-#include <cutils/sockets.h>
-#include <log/log_properties.h>
-
-#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<ServiceSocket*>(self)->Enqueue(std::move(data));
- };
- this->ready = [](asocket* self) { return static_cast<ServiceSocket*>(self)->Ready(); };
- this->close = [](asocket* self) { return static_cast<ServiceSocket*>(self)->Close(); };
- }
- virtual ~ServiceSocket() = default;
-
- virtual int Enqueue(apacket::payload_type data) { return -1; }
- virtual void Ready() {}
- virtual void Close() {
- if (peer) {
- peer->peer = nullptr;
- if (peer->shutdown) {
- peer->shutdown(peer);
- }
- peer->close(peer);
- }
-
- remove_socket(this);
- delete this;
- }
-};
-
-struct SinkSocket : public ServiceSocket {
- explicit SinkSocket(size_t byte_count) {
- LOG(INFO) << "Creating new SinkSocket with capacity " << byte_count;
- bytes_left_ = byte_count;
- }
-
- virtual ~SinkSocket() { LOG(INFO) << "SinkSocket destroyed"; }
-
- virtual int Enqueue(apacket::payload_type data) override final {
- if (bytes_left_ <= data.size()) {
- // Done reading.
- Close();
- return -1;
- }
-
- bytes_left_ -= data.size();
- return 0;
- }
-
- size_t bytes_left_;
-};
-
-struct SourceSocket : public ServiceSocket {
- explicit SourceSocket(size_t byte_count) {
- LOG(INFO) << "Creating new SourceSocket with capacity " << byte_count;
- bytes_left_ = byte_count;
- }
-
- virtual ~SourceSocket() { LOG(INFO) << "SourceSocket destroyed"; }
-
- void Ready() {
- size_t len = std::min(bytes_left_, get_max_payload());
- if (len == 0) {
- Close();
- return;
- }
-
- Block block(len);
- memset(block.data(), 0, block.size());
- peer->enqueue(peer, std::move(block));
- bytes_left_ -= len;
- }
-
- int Enqueue(apacket::payload_type data) { return -1; }
-
- size_t bytes_left_;
-};
-
-asocket* daemon_service_to_socket(std::string_view name) {
- if (name == "jdwp") {
- return create_jdwp_service_socket();
- } else if (name == "track-jdwp") {
- return create_jdwp_tracker_service_socket();
- } else if (android::base::ConsumePrefix(&name, "sink:")) {
- uint64_t byte_count = 0;
- if (!ParseUint(&byte_count, name)) {
- return nullptr;
- }
- return new SinkSocket(byte_count);
- } else if (android::base::ConsumePrefix(&name, "source:")) {
- uint64_t byte_count = 0;
- if (!ParseUint(&byte_count, name)) {
- return nullptr;
- }
- return new SourceSocket(byte_count);
- }
-
- return nullptr;
-}
-
-unique_fd daemon_service_to_fd(std::string_view name, atransport* transport) {
- ADB_LOG(Service) << "transport " << transport->serial_name() << " opening service " << name;
-
-#if defined(__ANDROID__) && !defined(__ANDROID_RECOVERY__)
- if (name.starts_with("abb:") || name.starts_with("abb_exec:")) {
- return execute_abb_command(name);
- }
-#endif
-
-#if defined(__ANDROID__)
- if (name.starts_with("framebuffer:")) {
- return create_service_thread("fb", framebuffer_service);
- } else if (android::base::ConsumePrefix(&name, "remount:")) {
- std::string cmd = "/system/bin/remount ";
- cmd += name;
- return StartSubprocess(cmd, nullptr, SubprocessType::kRaw, SubprocessProtocol::kNone);
- } else if (android::base::ConsumePrefix(&name, "reboot:")) {
- return reboot_device(std::string(name));
- } else if (name.starts_with("root:")) {
- return create_service_thread("root", restart_root_service);
- } else if (name.starts_with("unroot:")) {
- return create_service_thread("unroot", restart_unroot_service);
- } else if (android::base::ConsumePrefix(&name, "backup:")) {
- std::string cmd = "/system/bin/bu backup ";
- cmd += name;
- return StartSubprocess(cmd, nullptr, SubprocessType::kRaw, SubprocessProtocol::kNone);
- } else if (name.starts_with("restore:")) {
- return StartSubprocess("/system/bin/bu restore", nullptr, SubprocessType::kRaw,
- SubprocessProtocol::kNone);
- } else if (name.starts_with("disable-verity:")) {
- return StartSubprocess("/system/bin/disable-verity", nullptr, SubprocessType::kRaw,
- SubprocessProtocol::kNone);
- } else if (name.starts_with("enable-verity:")) {
- return StartSubprocess("/system/bin/enable-verity", nullptr, SubprocessType::kRaw,
- SubprocessProtocol::kNone);
- } else if (android::base::ConsumePrefix(&name, "tcpip:")) {
- std::string str(name);
-
- int port;
- if (sscanf(str.c_str(), "%d", &port) != 1) {
- return unique_fd{};
- }
- return create_service_thread("tcp",
- std::bind(restart_tcp_service, std::placeholders::_1, port));
- } else if (name.starts_with("usb:")) {
- return create_service_thread("usb", restart_usb_service);
- }
-#endif
-
- if (android::base::ConsumePrefix(&name, "dev:")) {
- return unique_fd{unix_open(name, O_RDWR | O_CLOEXEC)};
- } else if (android::base::ConsumePrefix(&name, "jdwp:")) {
- pid_t pid;
- if (!ParseUint(&pid, name)) {
- return unique_fd{};
- }
- return create_jdwp_connection_fd(pid);
- } else if (android::base::ConsumePrefix(&name, "shell")) {
- return ShellService(name, transport);
- } else if (android::base::ConsumePrefix(&name, "exec:")) {
- return StartSubprocess(std::string(name), nullptr, SubprocessType::kRaw,
- SubprocessProtocol::kNone);
- } else if (name.starts_with("sync:")) {
- return create_service_thread("sync", file_sync_service);
- } else if (android::base::ConsumePrefix(&name, "reverse:")) {
- return reverse_service(name, transport);
- } else if (name == "reconnect") {
- return create_service_thread(
- "reconnect", std::bind(reconnect_service, std::placeholders::_1, transport));
- } else if (name == "spin") {
- return create_service_thread("spin", spin_service);
- }
-
- return unique_fd{};
-}
diff --git a/adb/daemon/shell_service.cpp b/adb/daemon/shell_service.cpp
deleted file mode 100644
index fbfae1e44..000000000
--- a/adb/daemon/shell_service.cpp
+++ /dev/null
@@ -1,911 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// Functionality for launching and managing shell subprocesses.
-//
-// There are two types of subprocesses, PTY or raw. PTY is typically used for
-// an interactive session, raw for non-interactive. There are also two methods
-// of communication with the subprocess, passing raw data or using a simple
-// protocol to wrap packets. The protocol allows separating stdout/stderr and
-// passing the exit code back, but is not backwards compatible.
-// ----------------+--------------------------------------
-// Type Protocol | Exit code? Separate stdout/stderr?
-// ----------------+--------------------------------------
-// PTY No | No No
-// Raw No | No No
-// PTY Yes | Yes No
-// Raw Yes | Yes Yes
-// ----------------+--------------------------------------
-//
-// Non-protocol subprocesses work by passing subprocess stdin/out/err through
-// a single pipe which is registered with a local socket in adbd. The local
-// socket uses the fdevent loop to pass raw data between this pipe and the
-// transport, which then passes data back to the adb client. Cleanup is done by
-// waiting in a separate thread for the subprocesses to exit and then signaling
-// a separate fdevent to close out the local socket from the main loop.
-//
-// ------------------+-------------------------+------------------------------
-// Subprocess | adbd subprocess thread | adbd main fdevent loop
-// ------------------+-------------------------+------------------------------
-// | |
-// stdin/out/err <-----------------------------> LocalSocket
-// | | |
-// | | Block on exit |
-// | | * |
-// v | * |
-// Exit ---> Unblock |
-// | | |
-// | v |
-// | Notify shell exit FD ---> Close LocalSocket
-// ------------------+-------------------------+------------------------------
-//
-// The protocol requires the thread to intercept stdin/out/err in order to
-// wrap/unwrap data with shell protocol packets.
-//
-// ------------------+-------------------------+------------------------------
-// Subprocess | adbd subprocess thread | adbd main fdevent loop
-// ------------------+-------------------------+------------------------------
-// | |
-// stdin/out <---> Protocol <---> LocalSocket
-// stderr ---> Protocol ---> LocalSocket
-// | | |
-// v | |
-// Exit ---> Exit code protocol ---> LocalSocket
-// | | |
-// | v |
-// | Notify shell exit FD ---> Close LocalSocket
-// ------------------+-------------------------+------------------------------
-//
-// An alternate approach is to put the protocol wrapping/unwrapping in the main
-// fdevent loop, which has the advantage of being able to re-use the existing
-// select() code for handling data streams. However, implementation turned out
-// to be more complex due to partial reads and non-blocking I/O so this model
-// was chosen instead.
-
-#define TRACE_TAG SHELL
-
-#include "sysdeps.h"
-
-#include "shell_service.h"
-
-#include <errno.h>
-#include <paths.h>
-#include <pty.h>
-#include <pwd.h>
-#include <termios.h>
-
-#include <memory>
-#include <string>
-#include <thread>
-#include <unordered_map>
-#include <vector>
-
-#include <android-base/logging.h>
-#include <android-base/properties.h>
-#include <android-base/stringprintf.h>
-#include <private/android_logger.h>
-
-#if defined(__ANDROID__)
-#include <selinux/android.h>
-#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> 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<ShellProtocol> 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<std::string, std::string> 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<std::string> 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<const char*> 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<ShellProtocol>(protocol_sfd_);
- output_ = std::make_unique<ShellProtocol>(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> 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<Subprocess*>(userdata);
-
- adb_thread_setname(android::base::StringPrintf("shell svc %d", subprocess->pid()));
-
- D("passing data streams for PID %d", subprocess->pid());
- subprocess->PassDataStreams();
-
- D("deleting Subprocess for PID %d", subprocess->pid());
- delete subprocess;
-}
-
-void Subprocess::PassDataStreams() {
- if (protocol_sfd_ == -1) {
- return;
- }
-
- // Start by trying to read from the protocol FD, stdout, and stderr.
- SubprocessPollfds pfds;
- pfds.stdinout_pfd() = {.fd = stdinout_sfd_.get(), .events = POLLIN};
- pfds.stderr_pfd() = {.fd = stderr_sfd_.get(), .events = POLLIN};
- pfds.protocol_pfd() = {.fd = protocol_sfd_.get(), .events = POLLIN};
-
- // Pass data until the protocol FD or both the subprocess pipes die, at
- // which point we can't pass any more data.
- while (protocol_sfd_ != -1 && (stdinout_sfd_ != -1 || stderr_sfd_ != -1)) {
- unique_fd* dead_sfd = PollLoop(&pfds);
- if (dead_sfd) {
- D("closing FD %d", dead_sfd->get());
- auto it = std::find_if(pfds.begin(), pfds.end(), [=](const adb_pollfd& pfd) {
- return pfd.fd == dead_sfd->get();
- });
- CHECK(it != pfds.end());
- it->fd = -1;
- it->events = 0;
- if (dead_sfd == &protocol_sfd_) {
- // Using SIGHUP is a decent general way to indicate that the
- // controlling process is going away. If specific signals are
- // needed (e.g. SIGINT), pass those through the shell protocol
- // and only fall back on this for unexpected closures.
- D("protocol FD died, sending SIGHUP to pid %d", pid_);
- if (pid_ != -1) {
- kill(pid_, SIGHUP);
- }
-
- // We also need to close the pipes connected to the child process
- // so that if it ignores SIGHUP and continues to write data it
- // won't fill up the pipe and block.
- stdinout_sfd_.reset();
- stderr_sfd_.reset();
- }
- dead_sfd->reset();
- }
- }
-}
-
-unique_fd* Subprocess::PollLoop(SubprocessPollfds* pfds) {
- unique_fd* dead_sfd = nullptr;
- adb_pollfd& stdinout_pfd = pfds->stdinout_pfd();
- adb_pollfd& stderr_pfd = pfds->stderr_pfd();
- adb_pollfd& protocol_pfd = pfds->protocol_pfd();
-
- // Keep calling poll() and passing data until an FD closes/errors.
- while (!dead_sfd) {
- if (adb_poll(pfds->data(), pfds->size(), -1) < 0) {
- if (errno == EINTR) {
- continue;
- } else {
- PLOG(ERROR) << "poll failed, closing subprocess pipes";
- stdinout_sfd_.reset(-1);
- stderr_sfd_.reset(-1);
- return nullptr;
- }
- }
-
- // Read stdout, write to protocol FD.
- if (stdinout_pfd.fd != -1 && (stdinout_pfd.revents & POLLIN)) {
- dead_sfd = PassOutput(&stdinout_sfd_, ShellProtocol::kIdStdout);
- }
-
- // Read stderr, write to protocol FD.
- if (!dead_sfd && stderr_pfd.fd != 1 && (stderr_pfd.revents & POLLIN)) {
- dead_sfd = PassOutput(&stderr_sfd_, ShellProtocol::kIdStderr);
- }
-
- // Read protocol FD, write to stdin.
- if (!dead_sfd && protocol_pfd.fd != -1 && (protocol_pfd.revents & POLLIN)) {
- dead_sfd = PassInput();
- // If we didn't finish writing, block on stdin write.
- if (input_bytes_left_) {
- protocol_pfd.events &= ~POLLIN;
- stdinout_pfd.events |= POLLOUT;
- }
- }
-
- // Continue writing to stdin; only happens if a previous write blocked.
- if (!dead_sfd && stdinout_pfd.fd != -1 && (stdinout_pfd.revents & POLLOUT)) {
- dead_sfd = PassInput();
- // If we finished writing, go back to blocking on protocol read.
- if (!input_bytes_left_) {
- protocol_pfd.events |= POLLIN;
- stdinout_pfd.events &= ~POLLOUT;
- }
- }
-
- // After handling all of the events we've received, check to see if any fds have died.
- if (stdinout_pfd.revents & (POLLHUP | POLLRDHUP | POLLERR | POLLNVAL)) {
- return &stdinout_sfd_;
- }
-
- if (stderr_pfd.revents & (POLLHUP | POLLRDHUP | POLLERR | POLLNVAL)) {
- return &stderr_sfd_;
- }
-
- if (protocol_pfd.revents & (POLLHUP | POLLRDHUP | POLLERR | POLLNVAL)) {
- return &protocol_sfd_;
- }
- } // while (!dead_sfd)
-
- return dead_sfd;
-}
-
-unique_fd* Subprocess::PassInput() {
- // Only read a new packet if we've finished writing the last one.
- if (!input_bytes_left_) {
- if (!input_->Read()) {
- // Read() uses ReadFdExactly() which sets errno to 0 on EOF.
- if (errno != 0) {
- PLOG(ERROR) << "error reading protocol FD " << protocol_sfd_.get();
- }
- return &protocol_sfd_;
- }
-
- if (stdinout_sfd_ != -1) {
- switch (input_->id()) {
- case ShellProtocol::kIdWindowSizeChange:
- int rows, cols, x_pixels, y_pixels;
- if (sscanf(input_->data(), "%dx%d,%dx%d",
- &rows, &cols, &x_pixels, &y_pixels) == 4) {
- winsize ws;
- ws.ws_row = rows;
- ws.ws_col = cols;
- ws.ws_xpixel = x_pixels;
- ws.ws_ypixel = y_pixels;
- ioctl(stdinout_sfd_.get(), TIOCSWINSZ, &ws);
- }
- break;
- case ShellProtocol::kIdStdin:
- input_bytes_left_ = input_->data_length();
- break;
- case ShellProtocol::kIdCloseStdin:
- if (type_ == SubprocessType::kRaw) {
- if (adb_shutdown(stdinout_sfd_, SHUT_WR) == 0) {
- return nullptr;
- }
- PLOG(ERROR) << "failed to shutdown writes to FD " << stdinout_sfd_.get();
- return &stdinout_sfd_;
- } else {
- // PTYs can't close just input, so rather than close the
- // FD and risk losing subprocess output, leave it open.
- // This only happens if the client starts a PTY shell
- // non-interactively which is rare and unsupported.
- // If necessary, the client can manually close the shell
- // with `exit` or by killing the adb client process.
- D("can't close input for PTY FD %d", stdinout_sfd_.get());
- }
- break;
- }
- }
- }
-
- if (input_bytes_left_ > 0) {
- int index = input_->data_length() - input_bytes_left_;
- int bytes = adb_write(stdinout_sfd_, input_->data() + index, input_bytes_left_);
- if (bytes == 0 || (bytes < 0 && errno != EAGAIN)) {
- if (bytes < 0) {
- PLOG(ERROR) << "error reading stdin FD " << stdinout_sfd_.get();
- }
- // stdin is done, mark this packet as finished and we'll just start
- // dumping any further data received from the protocol FD.
- input_bytes_left_ = 0;
- return &stdinout_sfd_;
- } else if (bytes > 0) {
- input_bytes_left_ -= bytes;
- }
- }
-
- return nullptr;
-}
-
-unique_fd* Subprocess::PassOutput(unique_fd* sfd, ShellProtocol::Id id) {
- int bytes = adb_read(*sfd, output_->data(), output_->data_capacity());
- if (bytes == 0 || (bytes < 0 && errno != EAGAIN)) {
- // read() returns EIO if a PTY closes; don't report this as an error,
- // it just means the subprocess completed.
- if (bytes < 0 && !(type_ == SubprocessType::kPty && errno == EIO)) {
- PLOG(ERROR) << "error reading output FD " << sfd->get();
- }
- return sfd;
- }
-
- if (bytes > 0 && !output_->Write(id, bytes)) {
- if (errno != 0) {
- PLOG(ERROR) << "error reading protocol FD " << protocol_sfd_.get();
- }
- return &protocol_sfd_;
- }
-
- return nullptr;
-}
-
-void Subprocess::WaitForExit() {
- int exit_code = 1;
-
- D("waiting for pid %d", pid_);
- while (pid_ != -1) {
- int status;
- if (pid_ == waitpid(pid_, &status, 0)) {
- D("post waitpid (pid=%d) status=%04x", pid_, status);
- if (WIFSIGNALED(status)) {
- exit_code = 0x80 | WTERMSIG(status);
- ADB_LOG(Shell) << "subprocess " << pid_ << " killed by signal " << WTERMSIG(status);
- break;
- } else if (!WIFEXITED(status)) {
- D("subprocess didn't exit");
- break;
- } else if (WEXITSTATUS(status) >= 0) {
- exit_code = WEXITSTATUS(status);
- ADB_LOG(Shell) << "subprocess " << pid_ << " exited with status " << exit_code;
- break;
- }
- }
- }
-
- // If we have an open protocol FD send an exit packet.
- if (protocol_sfd_ != -1) {
- output_->data()[0] = exit_code;
- if (output_->Write(ShellProtocol::kIdExit, 1)) {
- D("wrote the exit code packet: %d", exit_code);
- } else {
- PLOG(ERROR) << "failed to write the exit code packet";
- }
- protocol_sfd_.reset(-1);
- }
-}
-
-} // namespace
-
-// Create a pipe containing the error.
-unique_fd ReportError(SubprocessProtocol protocol, const std::string& message) {
- unique_fd read, write;
- if (!Pipe(&read, &write)) {
- PLOG(ERROR) << "failed to create pipe to report error";
- return unique_fd{};
- }
-
- std::string buf = android::base::StringPrintf("error: %s\n", message.c_str());
- if (protocol == SubprocessProtocol::kShell) {
- ShellProtocol::Id id = ShellProtocol::kIdStderr;
- uint32_t length = buf.length();
- WriteFdExactly(write.get(), &id, sizeof(id));
- WriteFdExactly(write.get(), &length, sizeof(length));
- }
-
- WriteFdExactly(write.get(), buf.data(), buf.length());
-
- if (protocol == SubprocessProtocol::kShell) {
- ShellProtocol::Id id = ShellProtocol::kIdExit;
- uint32_t length = 1;
- char exit_code = 126;
- WriteFdExactly(write.get(), &id, sizeof(id));
- WriteFdExactly(write.get(), &length, sizeof(length));
- WriteFdExactly(write.get(), &exit_code, sizeof(exit_code));
- }
-
- return read;
-}
-
-unique_fd StartSubprocess(std::string name, const char* terminal_type, SubprocessType type,
- SubprocessProtocol protocol) {
- // If we aren't using the shell protocol we must allocate a PTY to properly close the
- // subprocess. PTYs automatically send SIGHUP to the slave-side process when the master side
- // of the PTY closes, which we rely on. If we use a raw pipe, processes that don't read/write,
- // e.g. screenrecord, will never notice the broken pipe and terminate.
- // The shell protocol doesn't require a PTY because it's always monitoring the local socket FD
- // with select() and will send SIGHUP manually to the child process.
- bool make_pty_raw = false;
- if (protocol == SubprocessProtocol::kNone && type == SubprocessType::kRaw) {
- // Disable PTY input/output processing since the client is expecting raw data.
- D("Can't create raw subprocess without shell protocol, using PTY in raw mode instead");
- type = SubprocessType::kPty;
- make_pty_raw = true;
- }
-
- unique_fd error_fd;
- unique_fd fd = StartSubprocess(std::move(name), terminal_type, type, protocol, make_pty_raw,
- protocol, &error_fd);
- if (fd == -1) {
- return error_fd;
- }
- return fd;
-}
-
-unique_fd StartSubprocess(std::string name, const char* terminal_type, SubprocessType type,
- SubprocessProtocol protocol, bool make_pty_raw,
- SubprocessProtocol error_protocol, unique_fd* error_fd) {
- D("starting %s subprocess (protocol=%s, TERM=%s): '%s'",
- type == SubprocessType::kRaw ? "raw" : "PTY",
- protocol == SubprocessProtocol::kNone ? "none" : "shell", terminal_type, name.c_str());
-
- auto subprocess = std::make_unique<Subprocess>(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<Subprocess>(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 030228c7f..000000000
--- 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 <string>
-
-#include "adb_unique_fd.h"
-
-#include <string_view>
-
-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 cdd8dbede..000000000
--- 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 <gtest/gtest.h>
-
-#include <signal.h>
-
-#include <string>
-#include <vector>
-
-#include <android-base/strings.h>
-
-#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<ShellProtocol>(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<std::string>& 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<ShellProtocol>(command_fd_);
- memcpy(write_protocol->data(), "in", 2);
- write_protocol->Write(ShellProtocol::kIdStdin, 2);
- }
-
- std::string stdout, stderr;
- // For in-process commands the exit code is always the default (1).
- EXPECT_EQ(1, ReadShellProtocol(command_fd_, &stdout, &stderr));
- ExpectLinesEqual(stdout, {"out"});
- ExpectLinesEqual(stderr, {"err"});
-}
diff --git a/adb/daemon/transport_qemu.cpp b/adb/daemon/transport_qemu.cpp
deleted file mode 100644
index e458cea7e..000000000
--- 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 <qemu_pipe.h>
-
-#define TRACE_TAG TRANSPORT
-#include "socket_spec.h"
-#include "sysdeps.h"
-#include "transport.h"
-
-#include <android-base/properties.h>
-
-#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 a66387193..000000000
--- a/adb/daemon/usb.cpp
+++ /dev/null
@@ -1,767 +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 <errno.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <linux/usb/functionfs.h>
-#include <sys/eventfd.h>
-
-#include <algorithm>
-#include <array>
-#include <future>
-#include <memory>
-#include <mutex>
-#include <optional>
-#include <vector>
-
-#include <asyncio/AsyncIO.h>
-
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <android-base/properties.h>
-#include <android-base/thread_annotations.h>
-
-#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 <class Payload>
-struct IoBlock {
- bool pending = false;
- struct iocb control = {};
- Payload payload;
-
- TransferId id() const { return TransferId::from_value(control.aio_data); }
-};
-
-using IoReadBlock = IoBlock<Block>;
-using IoWriteBlock = IoBlock<std::shared_ptr<Block>>;
-
-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<void> 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<apacket> packet) override final {
- LOG(DEBUG) << "USB write: " << dump_header(&packet->msg);
- auto header = std::make_shared<Block>(sizeof(packet->msg));
- memcpy(header->data(), &packet->msg, sizeof(packet->msg));
-
- std::lock_guard<std::mutex> 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<Block>(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(), &notify, 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(), &notify, sizeof(notify));
- if (rc < 0) {
- PLOG(FATAL) << "failed to notify worker eventfd to stop UsbFfsConnection";
- }
- CHECK_EQ(static_cast<size_t>(rc), sizeof(notify));
-
- rc = adb_write(monitor_event_fd_.get(), &notify, sizeof(notify));
- if (rc < 0) {
- PLOG(FATAL) << "failed to notify monitor eventfd to stop UsbFfsConnection";
- }
-
- CHECK_EQ(static_cast<size_t>(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<usb_functionfs_event_type>(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<int>(event.u.setup.bRequestType)
- << ", bRequest = " << static_cast<int>(event.u.setup.bRequest)
- << ", wValue = " << static_cast<int>(event.u.setup.wValue)
- << ", wIndex = " << static_cast<int>(event.u.setup.wIndex)
- << ", wLength = " << static_cast<int>(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<std::mutex> 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<uint64_t>(TransferId::read(id));
- block->control.aio_buf = reinterpret_cast<uintptr_t>(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();
- Block payload = std::move(block->payload);
- if (block->payload.size() > bytes_left) {
- HandleError("received too many bytes while waiting for payload");
- return false;
- }
- incoming_payload_.append(std::move(payload));
- }
-
- if (incoming_header_->data_length == incoming_payload_.size()) {
- auto packet = std::make_unique<apacket>();
- 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<std::mutex> lock(write_mutex_);
- auto it =
- std::find_if(write_requests_.begin(), write_requests_.end(), [id](const auto& req) {
- return static_cast<uint64_t>(req.id()) == static_cast<uint64_t>(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<Block> payload, size_t offset, size_t len,
- uint64_t id) {
- auto block = IoWriteBlock();
- block.payload = std::move(payload);
- block.control.aio_data = static_cast<uint64_t>(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<uintptr_t>(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<Block>(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<void*>(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<bool> stopped_;
- std::promise<void> 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<amessage> incoming_header_;
- IOVector incoming_payload_;
-
- std::array<IoReadBlock, kUsbReadQueueDepth> 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<IoWriteBlock> 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<void> destruction_notifier;
- std::future<void> future = destruction_notifier.get_future();
- transport->SetConnection(std::make_unique<UsbFfsConnection>(
- 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 e538ca885..000000000
--- 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 <linux/usb/ch9.h>
-#include <linux/usb/functionfs.h>
-
-#include <android-base/logging.h>
-#include <android-base/properties.h>
-#include <android-base/unique_fd.h>
-
-#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 <size_t PropertyNameLength, size_t PropertyDataLength>
-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 a19d7ccce..000000000
--- 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 <android-base/unique_fd.h>
-
-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 f5893aa19..000000000
--- 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 89dc7451b..000000000
--- a/adb/fastdeploy/AndroidManifest.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.fastdeploytests">
-
- <application android:testOnly="true"
- android:debuggable="true">
- <uses-library android:name="android.test.runner" />
- </application>
-
- <instrumentation
- android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.fastdeploytests"
- android:label="FastDeploy Tests" />
-</manifest> \ No newline at end of file
diff --git a/adb/fastdeploy/AndroidTest.xml b/adb/fastdeploy/AndroidTest.xml
deleted file mode 100644
index 24a72bc85..000000000
--- a/adb/fastdeploy/AndroidTest.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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
- -->
-<configuration description="Runs Device Tests for FastDeploy.">
- <option name="test-suite-tag" value="FastDeployTests"/>
-
- <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
- <option name="cleanup-apks" value="true"/>
- <option name="install-arg" value="-t"/>
- <option name="test-file-name" value="FastDeployTests.apk"/>
- </target_preparer>
-
- <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
- <option name="cleanup" value="false" />
- <option name="push-file" key="sample.apk" value="/data/local/tmp/FastDeployTests/sample.apk" />
- <option name="push-file" key="sample.cd" value="/data/local/tmp/FastDeployTests/sample.cd" />
- </target_preparer>
-
- <test class="com.android.tradefed.testtype.AndroidJUnitTest">
- <option name="package" value="com.android.fastdeploytests"/>
- <option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/>
- </test>
-
- <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
- <option name="jar" value="FastDeployHostTests.jar" />
- </test>
-</configuration>
diff --git a/adb/fastdeploy/OWNERS b/adb/fastdeploy/OWNERS
deleted file mode 100644
index d1458348a..000000000
--- 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 91576ca18..000000000
--- 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 31e05023c..000000000
--- 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 3812307cc..000000000
--- 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 <command> [<args>]\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 <FILE> directs output to FILE, default or - for stdout\n" +
- " -pm <ARGS> directs output to package manager, passes <ARGS> 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 f0655f325..000000000
--- 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 54be26f65..000000000
--- 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 7c2468f52..000000000
--- 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 4aa2f79bb..000000000
--- 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 9da256e24..000000000
--- 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 <inttypes.h>
-
-#include "adb_trace.h"
-#include "sysdeps.h"
-
-#include <android-base/endian.h>
-#include <android-base/mapped_file.h>
-
-#include <openssl/md5.h>
-
-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<long long>(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<android::base::MappedFile> 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<const CentralDirectoryRecord*>(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<long long>(localFileHeaderOffset),
- static_cast<long long>(size_));
- return 0;
- }
-
- FileRegion lfhMapped(fd_, localFileHeaderOffset, sizeof(LocalFileHeader));
- lfh = reinterpret_cast<const LocalFileHeader*>(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<long long>(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<long long>(ddOffset), static_cast<long long>(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<long long>(ddOffset), static_cast<long long>(size_));
- return 0;
- }
-
- dd = reinterpret_cast<const DataDescriptor*>(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<long long>(localFileHeaderOffset),
- static_cast<long long>(dataSize), static_cast<long long>(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 7127800a9..000000000
--- 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 <memory>
-#include <string>
-#include <vector>
-
-#include <adb_unique_fd.h>
-
-#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 554cb570e..000000000
--- 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 <iostream>
-
-#include <gtest/gtest.h>
-
-#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 8aa7da72f..000000000
--- 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 <inttypes.h>
-#include <stdio.h>
-
-#include <algorithm>
-#include <fstream>
-#include <functional>
-#include <iostream>
-#include <sstream>
-#include <string>
-#include <unordered_map>
-
-#include <openssl/md5.h>
-
-#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<SimpleEntry>& 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<SimpleEntry>& 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<long long>(currentSizeOut), static_cast<long long>(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<SimpleEntry> identicalEntries;
- uint64_t totalSize =
- BuildIdenticalEntries(identicalEntries, localApkMetadata, deviceApkMetadata);
- ReportSavings(identicalEntries, totalSize);
- GeneratePatch(identicalEntries, localApkPath, deviceApkPath, output);
-
- return true;
-}
-
-uint64_t DeployPatchGenerator::BuildIdenticalEntries(std::vector<SimpleEntry>& outIdenticalEntries,
- const APKMetaData& localApkMetadata,
- const APKMetaData& deviceApkMetadata) {
- outIdenticalEntries.reserve(
- std::min(localApkMetadata.entries_size(), deviceApkMetadata.entries_size()));
-
- using md5Digest = std::pair<uint64_t, uint64_t>;
- struct md5Hash {
- size_t operator()(const md5Digest& digest) const {
- std::hash<uint64_t> 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<md5Digest, std::vector<const APKEntry*>, 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 fd7eaeee9..000000000
--- 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 <vector>
-
-#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<SimpleEntry>& 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<SimpleEntry>& entriesToUseOnDevice,
- const std::string& localApkPath, const std::string& deviceApkPath,
- android::base::borrowed_fd output);
-
- protected:
- uint64_t BuildIdenticalEntries(std::vector<SimpleEntry>& 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 e4c96eaff..000000000
--- 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 <android-base/file.h>
-#include <gtest/gtest.h>
-#include <stdlib.h>
-#include <string.h>
-#include <string>
-
-#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<DeployPatchGenerator::SimpleEntry> 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 2b00c8016..000000000
--- 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 <stdio.h>
-
-#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 8dc9b9cb2..000000000
--- 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 3ec5ab3e0..000000000
--- 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 <android-base/file.h>
-#include <gtest/gtest.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sstream>
-#include <string>
-
-#include <google/protobuf/util/message_differencer.h>
-
-#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 d84c5a54e..000000000
--- a/adb/fastdeploy/proto/ApkEntry.proto
+++ /dev/null
@@ -1,26 +0,0 @@
-syntax = "proto3";
-
-package com.android.fastdeploy;
-
-option java_package = "com.android.fastdeploy";
-option java_outer_classname = "ApkEntryProto";
-option java_multiple_files = true;
-option optimize_for = LITE_RUNTIME;
-
-message APKDump {
- string name = 1;
- bytes cd = 2;
- bytes signature = 3;
- string absolute_path = 4;
-}
-
-message APKEntry {
- bytes md5 = 1;
- int64 dataOffset = 2;
- int64 dataSize = 3;
-}
-
-message APKMetaData {
- string absolute_path = 1;
- repeated APKEntry entries = 2;
-}
diff --git a/adb/fastdeploy/testdata/helloworld5.apk b/adb/fastdeploy/testdata/helloworld5.apk
deleted file mode 100644
index 4a1539ecd..000000000
--- a/adb/fastdeploy/testdata/helloworld5.apk
+++ /dev/null
Binary files differ
diff --git a/adb/fastdeploy/testdata/helloworld7.apk b/adb/fastdeploy/testdata/helloworld7.apk
deleted file mode 100644
index 82c46df80..000000000
--- a/adb/fastdeploy/testdata/helloworld7.apk
+++ /dev/null
Binary files 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 52352ff71..000000000
--- 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 d47e0ea07..000000000
--- a/adb/fastdeploy/testdata/rotating_cube-release.apk
+++ /dev/null
Binary files differ
diff --git a/adb/fastdeploy/testdata/sample.apk b/adb/fastdeploy/testdata/sample.apk
deleted file mode 100644
index c31620572..000000000
--- a/adb/fastdeploy/testdata/sample.apk
+++ /dev/null
Binary files differ
diff --git a/adb/fastdeploy/testdata/sample.cd b/adb/fastdeploy/testdata/sample.cd
deleted file mode 100644
index 5e5b4d4c8..000000000
--- a/adb/fastdeploy/testdata/sample.cd
+++ /dev/null
Binary files differ
diff --git a/adb/fdevent/fdevent.cpp b/adb/fdevent/fdevent.cpp
deleted file mode 100644
index fd550200f..000000000
--- a/adb/fdevent/fdevent.cpp
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * Copyright 2006, Brian Swetland <swetland@frotz.net>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 <inttypes.h>
-
-#include <android-base/logging.h>
-#include <android-base/stringprintf.h>
-#include <android-base/threads.h>
-
-#include "adb_utils.h"
-#include "fdevent.h"
-#include "fdevent_epoll.h"
-#include "fdevent_poll.h"
-
-using namespace std::chrono_literals;
-using std::chrono::duration_cast;
-
-void invoke_fde(struct fdevent* fde, unsigned events) {
- if (auto f = std::get_if<fd_func>(&fde->func)) {
- (*f)(fde->fd.get(), events, fde->arg);
- } else if (auto f = std::get_if<fd_func2>(&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<fd_func, fd_func2> 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<std::chrono::milliseconds> timeout) {
- CheckMainThread();
- fde->timeout = timeout;
- fde->last_active = std::chrono::steady_clock::now();
-}
-
-std::optional<std::chrono::milliseconds> fdevent_context::CalculatePollDuration() {
- std::optional<std::chrono::milliseconds> 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<std::chrono::milliseconds>(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<fdevent_event>& 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<void()> fn;
- {
- std::lock_guard<std::mutex> 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<void()> fn) {
- {
- std::lock_guard<std::mutex> 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_context> fdevent_create_context() {
-#if defined(__linux__)
- return std::make_unique<fdevent_context_epoll>();
-#else
- return std::make_unique<fdevent_context_poll>();
-#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<std::chrono::milliseconds> timeout) {
- fdevent_get_ambient()->SetTimeout(fde, timeout);
-}
-
-void fdevent_run_on_main_thread(std::function<void()> 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 9fc3b2c0c..000000000
--- 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 <stddef.h>
-#include <stdint.h>
-
-#include <atomic>
-#include <chrono>
-#include <deque>
-#include <functional>
-#include <mutex>
-#include <optional>
-#include <unordered_map>
-#include <variant>
-
-#include <android-base/thread_annotations.h>
-
-#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<std::chrono::milliseconds> timeout;
- std::chrono::steady_clock::time_point last_active;
-
- std::variant<fd_func, fd_func2> 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<fd_func, fd_func2> func, void* arg);
-
- // Deallocate an fdevent object, returning the file descriptor that was owned by it.
- // Note that this calls Set, which is a virtual method, so destructors that call this must be
- // final.
- unique_fd Destroy(fdevent* fde);
-
- protected:
- virtual void Register(fdevent*) {}
- virtual void Unregister(fdevent*) {}
-
- public:
- // Change which events should cause notifications.
- virtual void Set(fdevent* fde, unsigned events) = 0;
- void Add(fdevent* fde, unsigned events);
- void Del(fdevent* fde, unsigned events);
-
- // Set a timeout on an fdevent.
- // If no events are triggered by the timeout, an FDE_TIMEOUT will be generated.
- // Note timeouts are not defused automatically; if a timeout is set on an fdevent, it will
- // trigger repeatedly every |timeout| ms.
- void SetTimeout(fdevent* fde, std::optional<std::chrono::milliseconds> timeout);
-
- protected:
- std::optional<std::chrono::milliseconds> CalculatePollDuration();
- void HandleEvents(const std::vector<fdevent_event>& 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<void()> fn);
-
- // Test-only functionality:
- void TerminateLoop();
- virtual size_t InstalledCount() = 0;
-
- protected:
- // Interrupt the run loop.
- virtual void Interrupt() = 0;
-
- std::optional<uint64_t> main_thread_id_ = std::nullopt;
- std::atomic<bool> terminate_loop_ = false;
-
- protected:
- std::unordered_map<int, fdevent> installed_fdevents_;
-
- private:
- uint64_t fdevent_id_ = 0;
- std::mutex run_queue_mutex_;
- std::deque<std::function<void()>> 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<std::chrono::milliseconds> 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<void()> 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 4ef41d1ee..000000000
--- 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 <sys/epoll.h>
-#include <sys/eventfd.h>
-
-#include <android-base/logging.h>
-#include <android-base/threads.h>
-
-#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<fdevent_event> fde_events;
- std::vector<epoll_event> epoll_events;
- epoll_events.resize(this->installed_fdevents_.size());
-
- while (true) {
- if (terminate_loop_) {
- break;
- }
-
- int rc = -1;
- while (rc == -1) {
- std::optional<std::chrono::milliseconds> 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<fdevent*, unsigned> event_map;
- for (int i = 0; i < rc; ++i) {
- fdevent* fde = static_cast<fdevent*>(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 6214d2e27..000000000
--- 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 <sys/epoll.h>
-
-#include <deque>
-#include <list>
-#include <mutex>
-#include <unordered_map>
-
-#include <android-base/thread_annotations.h>
-
-#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 ac86c08e1..000000000
--- a/adb/fdevent/fdevent_poll.cpp
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define TRACE_TAG FDEVENT
-
-#include "sysdeps.h"
-#include "fdevent_poll.h"
-
-#include <fcntl.h>
-#include <inttypes.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <atomic>
-#include <deque>
-#include <functional>
-#include <list>
-#include <mutex>
-#include <optional>
-#include <unordered_map>
-#include <utility>
-#include <variant>
-#include <vector>
-
-#include <android-base/chrono_utils.h>
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/stringprintf.h>
-#include <android-base/threads.h>
-
-#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<adb_pollfd>& 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<adb_pollfd> pollfds;
- std::vector<fdevent_event> 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<std::chrono::milliseconds> timeout = CalculatePollDuration();
- int timeout_ms;
- if (!timeout) {
- timeout_ms = -1;
- } else {
- timeout_ms = timeout->count();
- }
-
- int ret = adb_poll(pollfds.data(), pollfds.size(), timeout_ms);
- if (ret == -1) {
- PLOG(ERROR) << "poll(), ret = " << ret;
- return;
- }
-
- auto post_poll = std::chrono::steady_clock::now();
-
- for (const auto& pollfd : pollfds) {
- unsigned events = 0;
- if (pollfd.revents & POLLIN) {
- events |= FDE_READ;
- }
- if (pollfd.revents & POLLOUT) {
- events |= FDE_WRITE;
- }
- if (pollfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
- // We fake a read, as the rest of the code assumes that errors will
- // be detected at that point.
- events |= FDE_READ | FDE_ERROR;
- }
-#if defined(__linux__)
- if (pollfd.revents & POLLRDHUP) {
- events |= FDE_READ | FDE_ERROR;
- }
-#endif
-
- auto it = this->installed_fdevents_.find(pollfd.fd);
- CHECK(it != this->installed_fdevents_.end());
- fdevent* fde = &it->second;
-
- if (events == 0) {
- if (fde->timeout) {
- auto deadline = fde->last_active + *fde->timeout;
- if (deadline < post_poll) {
- events |= FDE_TIMEOUT;
- }
- }
- }
-
- if (events != 0) {
- D("%s got events %x", dump_fde(fde).c_str(), events);
- poll_events.push_back({fde, events});
- fde->last_active = post_poll;
- }
- }
- this->HandleEvents(poll_events);
- poll_events.clear();
- }
-
- main_thread_id_.reset();
-}
-
-size_t fdevent_context_poll::InstalledCount() {
- // We always have an installed fde for interrupt.
- return this->installed_fdevents_.size() - 1;
-}
-
-void fdevent_context_poll::Interrupt() {
- int rc = adb_write(this->interrupt_fd_, "", 1);
-
- // It's possible that we get EAGAIN here, if lots of notifications came in while handling.
- if (rc == 0) {
- PLOG(FATAL) << "fdevent interrupt fd was closed?";
- } else if (rc == -1 && errno != EAGAIN) {
- PLOG(FATAL) << "failed to write to fdevent interrupt fd";
- }
-}
diff --git a/adb/fdevent/fdevent_poll.h b/adb/fdevent/fdevent_poll.h
deleted file mode 100644
index 98abab283..000000000
--- a/adb/fdevent/fdevent_poll.h
+++ /dev/null
@@ -1,63 +0,0 @@
-#pragma once
-
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "sysdeps.h"
-
-#include <deque>
-#include <list>
-#include <mutex>
-#include <unordered_map>
-
-#include <android-base/thread_annotations.h>
-
-#include "adb_unique_fd.h"
-#include "fdevent.h"
-
-struct PollNode {
- fdevent* fde;
- adb_pollfd pollfd;
-
- explicit PollNode(fdevent* fde) : fde(fde) {
- memset(&pollfd, 0, sizeof(pollfd));
- pollfd.fd = fde->fd.get();
-
-#if defined(__linux__)
- // Always enable POLLRDHUP, so the host server can take action when some clients disconnect.
- // Then we can avoid leaving many sockets in CLOSE_WAIT state. See http://b/23314034.
- pollfd.events = POLLRDHUP;
-#endif
- }
-};
-
-struct fdevent_context_poll final : public fdevent_context {
- fdevent_context_poll();
- virtual ~fdevent_context_poll();
-
- virtual void Set(fdevent* fde, unsigned events) final;
-
- virtual void Loop() final;
-
- virtual size_t InstalledCount() final;
-
- protected:
- virtual void Interrupt() final;
-
- public:
- unique_fd interrupt_fd_;
- fdevent* interrupt_fde_ = nullptr;
-};
diff --git a/adb/fdevent/fdevent_test.cpp b/adb/fdevent/fdevent_test.cpp
deleted file mode 100644
index e06b3b329..000000000
--- 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 <gtest/gtest.h>
-
-#include <chrono>
-#include <limits>
-#include <memory>
-#include <queue>
-#include <string>
-#include <thread>
-#include <vector>
-
-#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<FdHandler*>(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<FdHandler*>(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<char> 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<std::unique_ptr<FdHandler>> fd_handlers;
- fdevent_run_on_main_thread([&thread_arg, &fd_handlers, use_new_callback]() {
- std::vector<int> read_fds;
- std::vector<int> 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<FdHandler>(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<int> 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<void()> make_appender(std::vector<int>* 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<int> 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<std::pair<TimeoutEvent, std::chrono::steady_clock::time_point>> 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<TimeoutTest*>(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<int> 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<std::chrono::milliseconds>(after - before);
- time_deltas.push_back(diff.count());
- }
-
- std::vector<int> expected = {
- delta.count(),
- delta.count(),
- delta.count() / 2,
- };
-
- std::vector<int> 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 ecda4da97..000000000
--- 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 <gtest/gtest.h>
-
-#include <condition_variable>
-#include <mutex>
-#include <thread>
-
-#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<std::mutex> lock(mutex);
- fdevent_run_on_main_thread([&]() {
- mutex.lock();
- mutex.unlock();
- cv.notify_one();
- });
- cv.wait(lock);
-}
-
-class FdeventTest : public ::testing::Test {
- protected:
- unique_fd dummy;
-
- ~FdeventTest() {
- if (thread_.joinable()) {
- TerminateThread();
- }
- }
-
- static void SetUpTestCase() {
-#if !defined(_WIN32)
- ASSERT_NE(SIG_ERR, signal(SIGPIPE, SIG_IGN));
-#endif
- }
-
- void SetUp() override {
- fdevent_reset();
- ASSERT_EQ(0u, fdevent_installed_count());
- }
-
- // Register a dummy socket used to wake up the fdevent loop to tell it to die.
- void PrepareThread() {
- int dummy_fds[2];
- if (adb_socketpair(dummy_fds) != 0) {
- FAIL() << "failed to create socketpair: " << strerror(errno);
- }
-
- asocket* dummy_socket = create_local_socket(unique_fd(dummy_fds[1]));
- if (!dummy_socket) {
- FAIL() << "failed to create local socket: " << strerror(errno);
- }
- dummy_socket->ready(dummy_socket);
- dummy.reset(dummy_fds[0]);
-
- thread_ = std::thread([]() { fdevent_loop(); });
- WaitForFdeventLoop();
- }
-
- size_t GetAdditionalLocalSocketCount() {
- // dummy socket installed in PrepareThread()
- return 1;
- }
-
- void TerminateThread() {
- fdevent_terminate_loop();
- ASSERT_TRUE(WriteFdExactly(dummy, "", 1));
- thread_.join();
- dummy.reset();
- }
-
- std::thread thread_;
-};
diff --git a/adb/file_sync_protocol.h b/adb/file_sync_protocol.h
deleted file mode 100644
index fd9a5169e..000000000
--- a/adb/file_sync_protocol.h
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#define MKID(a, b, c, d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24))
-
-#define ID_LSTAT_V1 MKID('S', 'T', 'A', 'T')
-#define ID_STAT_V2 MKID('S', 'T', 'A', '2')
-#define ID_LSTAT_V2 MKID('L', 'S', 'T', '2')
-
-#define ID_LIST_V1 MKID('L', 'I', 'S', 'T')
-#define ID_LIST_V2 MKID('L', 'I', 'S', '2')
-#define ID_DENT_V1 MKID('D', 'E', 'N', 'T')
-#define ID_DENT_V2 MKID('D', 'N', 'T', '2')
-
-#define ID_SEND_V1 MKID('S', 'E', 'N', 'D')
-#define ID_SEND_V2 MKID('S', 'N', 'D', '2')
-#define ID_RECV_V1 MKID('R', 'E', 'C', 'V')
-#define ID_RECV_V2 MKID('R', 'C', 'V', '2')
-#define ID_DONE MKID('D', 'O', 'N', 'E')
-#define ID_DATA MKID('D', 'A', 'T', 'A')
-#define ID_OKAY MKID('O', 'K', 'A', 'Y')
-#define ID_FAIL MKID('F', 'A', 'I', 'L')
-#define ID_QUIT MKID('Q', 'U', 'I', 'T')
-
-struct SyncRequest {
- uint32_t id; // ID_STAT, et cetera.
- uint32_t path_length; // <= 1024
- // Followed by 'path_length' bytes of path (not NUL-terminated).
-} __attribute__((packed));
-
-struct __attribute__((packed)) sync_stat_v1 {
- uint32_t id;
- uint32_t mode;
- uint32_t size;
- uint32_t mtime;
-};
-
-struct __attribute__((packed)) sync_stat_v2 {
- uint32_t id;
- uint32_t error;
- uint64_t dev;
- uint64_t ino;
- uint32_t mode;
- uint32_t nlink;
- uint32_t uid;
- uint32_t gid;
- uint64_t size;
- int64_t atime;
- int64_t mtime;
- int64_t ctime;
-};
-
-struct __attribute__((packed)) sync_dent_v1 {
- uint32_t id;
- uint32_t mode;
- uint32_t size;
- uint32_t mtime;
- uint32_t namelen;
-}; // followed by `namelen` bytes of the name.
-
-struct __attribute__((packed)) sync_dent_v2 {
- uint32_t id;
- uint32_t error;
- uint64_t dev;
- uint64_t ino;
- uint32_t mode;
- uint32_t nlink;
- uint32_t uid;
- uint32_t gid;
- uint64_t size;
- int64_t atime;
- int64_t mtime;
- int64_t ctime;
- uint32_t namelen;
-}; // followed by `namelen` bytes of the name.
-
-enum SyncFlag : uint32_t {
- kSyncFlagNone = 0,
- kSyncFlagBrotli = 1,
-};
-
-// send_v1 sent the path in a buffer, followed by a comma and the mode as a string.
-// send_v2 sends just the path in the first request, and then sends another syncmsg (with the
-// same ID!) with details.
-struct __attribute__((packed)) sync_send_v2 {
- uint32_t id;
- uint32_t mode;
- uint32_t flags;
-};
-
-// Likewise, recv_v1 just sent the path without any accompanying data.
-struct __attribute__((packed)) sync_recv_v2 {
- uint32_t id;
- uint32_t flags;
-};
-
-struct __attribute__((packed)) sync_data {
- uint32_t id;
- uint32_t size;
-}; // followed by `size` bytes of data.
-
-struct __attribute__((packed)) sync_status {
- uint32_t id;
- uint32_t msglen;
-}; // followed by `msglen` bytes of error message, if id == ID_FAIL.
-
-union syncmsg {
- sync_stat_v1 stat_v1;
- sync_stat_v2 stat_v2;
- sync_dent_v1 dent_v1;
- sync_dent_v2 dent_v2;
- sync_data data;
- sync_status status;
- sync_send_v2 send_v2_setup;
- sync_recv_v2 recv_v2_setup;
-};
-
-#define SYNC_DATA_MAX (64 * 1024)
diff --git a/adb/libs/.clang-format b/adb/libs/.clang-format
deleted file mode 120000
index e545823f4..000000000
--- 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 e545823f4..000000000
--- 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 ce2ab51ef..000000000
--- a/adb/libs/adbconnection/Android.bp
+++ /dev/null
@@ -1,64 +0,0 @@
-// libadbconnection
-// =========================================================
-// libadbconnection_client/server implement the socket handling for jdwp
-// forwarding and the track-jdwp service.
-cc_library {
- name: "libadbconnection_server",
- srcs: ["adbconnection_server.cpp"],
-
- export_include_dirs: ["include"],
-
- stl: "libc++_static",
- shared_libs: ["liblog"],
- static_libs: ["libbase"],
-
- defaults: ["adbd_defaults", "host_adbd_supported"],
-
- // Avoid getting duplicate symbol of android::build::GetBuildNumber().
- use_version_lib: false,
-
- recovery_available: true,
- apex_available: [
- "com.android.adbd",
- // TODO(b/151398197) remove the below
- "//apex_available:platform",
- ],
- compile_multilib: "both",
-}
-
-cc_library {
- name: "libadbconnection_client",
- srcs: ["adbconnection_client.cpp"],
-
- export_include_dirs: ["include"],
-
- stl: "libc++_static",
- shared_libs: ["liblog"],
- static_libs: ["libbase"],
-
- defaults: ["adbd_defaults"],
- visibility: [
- "//art:__subpackages__",
- "//system/core/adb/apex:__subpackages__",
- ],
- apex_available: [
- "com.android.adbd",
- "test_com.android.adbd",
- ],
-
- // libadbconnection_client doesn't need an embedded build number.
- use_version_lib: false,
-
- target: {
- linux: {
- version_script: "libadbconnection_client.map.txt",
- },
- },
- stubs: {
- symbol_file: "libadbconnection_client.map.txt",
- versions: ["1"],
- },
-
- host_supported: true,
- compile_multilib: "both",
-}
diff --git a/adb/libs/adbconnection/adbconnection_client.cpp b/adb/libs/adbconnection/adbconnection_client.cpp
deleted file mode 100644
index ee48abb03..000000000
--- a/adb/libs/adbconnection/adbconnection_client.cpp
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "adbconnection/client.h"
-
-#include <pwd.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-
-#include <memory>
-#include <optional>
-
-#include <android-base/cmsg.h>
-#include <android-base/logging.h>
-#include <android-base/unique_fd.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<AdbConnectionClientContext>();
-
- std::optional<uint64_t> pid;
- std::optional<bool> debuggable;
-
- for (size_t i = 0; i < info_count; ++i) {
- auto info = info_elems[i];
- switch (info->type) {
- case AdbConnectionClientInfoType::pid:
- if (pid) {
- LOG(ERROR) << "multiple pid entries in AdbConnectionClientInfo, ignoring";
- continue;
- }
- pid = info->data.pid;
- break;
-
- case AdbConnectionClientInfoType::debuggable:
- if (debuggable) {
- LOG(ERROR) << "multiple debuggable entries in AdbConnectionClientInfo, ignoring";
- continue;
- }
- debuggable = info->data.pid;
- break;
- }
- }
-
- if (!pid) {
- LOG(ERROR) << "AdbConnectionClientInfo missing required field pid";
- return nullptr;
- }
-
- if (!debuggable) {
- LOG(ERROR) << "AdbConnectionClientInfo missing required field debuggable";
- return nullptr;
- }
-
- ctx->control_socket_.reset(socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0));
- if (ctx->control_socket_ < 0) {
- PLOG(ERROR) << "failed to create Unix domain socket";
- return nullptr;
- }
-
- struct timeval timeout;
- timeout.tv_sec = 1;
- timeout.tv_usec = 0;
- setsockopt(ctx->control_socket_.get(), SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
-
- sockaddr_un addr = {};
- addr.sun_family = AF_UNIX;
- memcpy(addr.sun_path, kJdwpControlName, sizeof(kJdwpControlName));
- size_t addr_len = offsetof(sockaddr_un, sun_path) + sizeof(kJdwpControlName) - 1;
-
- int rc = connect(ctx->control_socket_.get(), reinterpret_cast<sockaddr*>(&addr), addr_len);
- if (rc != 0) {
- PLOG(ERROR) << "failed to connect to jdwp control socket";
- return nullptr;
- }
-
- bool trusted = SocketPeerIsTrusted(ctx->control_socket_.get());
- if (!trusted) {
- LOG(ERROR) << "adb socket is not trusted, aborting connection";
- return nullptr;
- }
-
- uint32_t pid_u32 = static_cast<uint32_t>(*pid);
- rc = TEMP_FAILURE_RETRY(write(ctx->control_socket_.get(), &pid_u32, sizeof(pid_u32)));
- if (rc != sizeof(pid_u32)) {
- PLOG(ERROR) << "failed to send JDWP process pid to adbd";
- }
-
- return ctx.release();
-}
-
-void adbconnection_client_destroy(AdbConnectionClientContext* ctx) {
- delete ctx;
-}
-
-int adbconnection_client_pollfd(AdbConnectionClientContext* ctx) {
- return ctx->control_socket_.get();
-}
-
-int adbconnection_client_receive_jdwp_fd(AdbConnectionClientContext* ctx) {
- char dummy;
- unique_fd jdwp_fd;
- ssize_t rc = android::base::ReceiveFileDescriptors(ctx->control_socket_, &dummy, 1, &jdwp_fd);
- if (rc != 1) {
- return rc;
- }
- return jdwp_fd.release();
-}
diff --git a/adb/libs/adbconnection/adbconnection_server.cpp b/adb/libs/adbconnection/adbconnection_server.cpp
deleted file mode 100644
index 939da2f64..000000000
--- a/adb/libs/adbconnection/adbconnection_server.cpp
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "adbconnection/server.h"
-
-#include <sys/epoll.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <unistd.h>
-
-#include <algorithm>
-#include <array>
-#include <vector>
-
-#include <android-base/logging.h>
-#include <android-base/unique_fd.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<sockaddr_un*>(0)->sun_path));
-
-// Listen for incoming jdwp clients forever.
-void adbconnection_listen(void (*callback)(int fd, pid_t pid)) {
- sockaddr_un addr = {};
- socklen_t addrlen = JDWP_CONTROL_NAME_LEN + sizeof(addr.sun_family);
-
- addr.sun_family = AF_UNIX;
- memcpy(addr.sun_path, JDWP_CONTROL_NAME, JDWP_CONTROL_NAME_LEN);
-
- unique_fd s(socket(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0));
- if (s < 0) {
- PLOG(ERROR) << "failed to create JDWP control socket";
- return;
- }
-
- if (bind(s.get(), reinterpret_cast<sockaddr*>(&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<unique_fd> pending_connections;
-
- unique_fd epfd(epoll_create1(EPOLL_CLOEXEC));
- std::array<epoll_event, 16> 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(), &register_event) != 0) {
- PLOG(FATAL) << "failed to register JDWP client with epoll";
- }
-
- pending_connections.emplace_back(std::move(client));
- } else {
- // n^2, but the backlog should be short.
- auto it = std::find_if(pending_connections.begin(), pending_connections.end(),
- [&](const unique_fd& fd) { return fd.get() == event.data.fd; });
-
- if (it == pending_connections.end()) {
- LOG(FATAL) << "failed to find JDWP client (" << event.data.fd
- << ") in pending connections";
- }
-
- // Massively oversized buffer: we're expecting an int32_t from the other end.
- char buf[32];
- int rc = TEMP_FAILURE_RETRY(recv(it->get(), buf, sizeof(buf), MSG_DONTWAIT));
- if (rc != 4) {
- LOG(ERROR) << "received data of incorrect size from JDWP client: read " << rc
- << ", expected 4";
- } else {
- int32_t pid;
- memcpy(&pid, buf, sizeof(pid));
- callback(it->release(), static_cast<pid_t>(pid));
- }
-
- if (epoll_ctl(epfd.get(), EPOLL_CTL_DEL, event.data.fd, nullptr) != 0) {
- LOG(FATAL) << "failed to delete fd from JDWP epoll fd";
- }
-
- pending_connections.erase(it);
- }
- }
- }
-}
diff --git a/adb/libs/adbconnection/include/adbconnection/client.h b/adb/libs/adbconnection/include/adbconnection/client.h
deleted file mode 100644
index 692fea00d..000000000
--- a/adb/libs/adbconnection/include/adbconnection/client.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <android-base/unique_fd.h>
-
-extern "C" {
-
-struct AdbConnectionClientContext;
-
-enum AdbConnectionClientInfoType {
- pid,
- debuggable,
-};
-
-struct AdbConnectionClientInfo {
- AdbConnectionClientInfoType type;
- union {
- uint64_t pid;
- bool debuggable;
- } data;
-};
-
-// Construct a context and connect to adbd.
-// Returns null if we fail to connect to adbd.
-AdbConnectionClientContext* adbconnection_client_new(
- const AdbConnectionClientInfo* const* info_elems, size_t info_count);
-
-void adbconnection_client_destroy(AdbConnectionClientContext* ctx);
-
-// Get an fd which can be polled upon to detect when a jdwp socket is available.
-// You do not own this fd. Do not close it.
-int adbconnection_client_pollfd(AdbConnectionClientContext* ctx);
-
-// Receive a jdwp client fd.
-// Ownership is transferred to the caller of this function.
-int adbconnection_client_receive_jdwp_fd(AdbConnectionClientContext* ctx);
-}
diff --git a/adb/libs/adbconnection/include/adbconnection/server.h b/adb/libs/adbconnection/include/adbconnection/server.h
deleted file mode 100644
index 57ca6cdee..000000000
--- 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 <sys/types.h>
-
-#include <android-base/unique_fd.h>
-
-extern "C" {
-
-void adbconnection_listen(void (*callback)(int fd, pid_t pid));
-}
diff --git a/adb/libs/adbconnection/libadbconnection_client.map.txt b/adb/libs/adbconnection/libadbconnection_client.map.txt
deleted file mode 100644
index 153a0e41b..000000000
--- 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 d17814825..000000000
--- 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 8e62d40d1..000000000
--- 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 <adbd_fs.h>
-
-#include <private/fs_config.h>
-
-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 6158d7208..000000000
--- 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 <stdint.h>
-#include <sys/types.h>
-
-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 1454e9639..000000000
--- 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 1f662c1ca..000000000
--- 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 <gtest/gtest.h>
-
-#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 a43f4d034..000000000
--- a/adb/pairing_auth/Android.bp
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright (C) 2020 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-cc_defaults {
- name: "libadb_pairing_auth_defaults",
- cflags: [
- "-Wall",
- "-Wextra",
- "-Wthread-safety",
- "-Werror",
- ],
-
- compile_multilib: "both",
-
- srcs: [
- "aes_128_gcm.cpp",
- "pairing_auth.cpp",
- ],
- target: {
- android: {
- version_script: "libadb_pairing_auth.map.txt",
- },
- windows: {
- compile_multilib: "first",
- enabled: true,
- },
- },
- export_include_dirs: ["include"],
-
- visibility: [
- "//art:__subpackages__",
- "//system/core/adb:__subpackages__",
- ],
-
- // libadb_pairing_auth doesn't need an embedded build number.
- use_version_lib: false,
-
- host_supported: true,
- recovery_available: false,
-
- stl: "libc++_static",
-
- static_libs: ["libbase"],
- shared_libs: [
- "libcrypto",
- "liblog",
- ],
-}
-
-cc_library {
- name: "libadb_pairing_auth",
- defaults: ["libadb_pairing_auth_defaults"],
-
- apex_available: [
- "com.android.adbd",
- ],
-
- stubs: {
- symbol_file: "libadb_pairing_auth.map.txt",
- versions: ["30"],
- },
-}
-
-// For running atest (b/147158681)
-cc_library_static {
- name: "libadb_pairing_auth_static",
- defaults: ["libadb_pairing_auth_defaults"],
-
- apex_available: [
- "//apex_available:platform",
- ],
-}
diff --git a/adb/pairing_auth/aes_128_gcm.cpp b/adb/pairing_auth/aes_128_gcm.cpp
deleted file mode 100644
index 51520d814..000000000
--- 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 <android-base/endian.h>
-#include <android-base/logging.h>
-
-#include <openssl/evp.h>
-#include <openssl/hkdf.h>
-#include <openssl/rand.h>
-
-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<size_t> Aes128Gcm::Encrypt(const uint8_t* in, size_t in_len, uint8_t* out,
- size_t out_len) {
- std::vector<uint8_t> 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<size_t> Aes128Gcm::Decrypt(const uint8_t* in, size_t in_len, uint8_t* out,
- size_t out_len) {
- std::vector<uint8_t> 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 6be585690..000000000
--- 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 <stdint.h>
-
-#include <optional>
-#include <vector>
-
-#include <openssl/aead.h>
-
-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<size_t> 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<size_t> 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 9ef97e260..000000000
--- 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 <stddef.h>
-#include <stdint.h>
-#include <sys/cdefs.h>
-
-#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 fdc15570b..000000000
--- 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 0ac04e691..000000000
--- 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 <android-base/logging.h>
-
-#include <openssl/curve25519.h>
-#include <openssl/mem.h>
-
-#include <iomanip>
-#include <sstream>
-#include <vector>
-
-#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<uint8_t>;
- 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> spake2_ctx_;
- std::unique_ptr<Aes128Gcm> 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<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> 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 213123d59..000000000
--- 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 55689d67a..000000000
--- 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 <gtest/gtest.h>
-
-#include <memory>
-
-#include <adb/pairing/aes_128_gcm.h>
-#include <openssl/rand.h>
-
-namespace adb {
-namespace pairing {
-
-TEST(Aes128GcmTest, init_null_material) {
- std::unique_ptr<Aes128Gcm> cipher;
- ASSERT_DEATH({ cipher.reset(new Aes128Gcm(nullptr, 42)); }, "");
-}
-
-TEST(Aes128GcmTest, init_empty_material) {
- uint8_t material[64];
- std::unique_ptr<Aes128Gcm> 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<const char*>(msg), reinterpret_cast<const char*>(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 fdc07f1f1..000000000
--- 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 <gtest/gtest.h>
-
-#include <adb/pairing/pairing_auth.h>
-#include <android-base/endian.h>
-
-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<PairingAuthCtx, decltype(&PairingAuthDeleter)>;
-
- PairingAuthUniquePtr makeClient(std::vector<uint8_t> pswd) {
- return PairingAuthUniquePtr(pairing_auth_client_new(pswd.data(), pswd.size()),
- PairingAuthDeleter);
- }
-
- PairingAuthUniquePtr makeServer(std::vector<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> pswd(kPswd, kPswd + sizeof(kPswd));
- std::vector<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> pswd{0x4f, 0x5a, 0x01, 0x46};
- auto client = makeClient(pswd);
- std::vector<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> pswd{0x4f, 0x5a, 0x01, 0x46};
- auto client = makeClient(pswd);
- std::vector<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint32_t*>(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<uint32_t*>(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 707161bcb..000000000
--- a/adb/pairing_connection/Android.bp
+++ /dev/null
@@ -1,188 +0,0 @@
-// Copyright (C) 2020 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-cc_defaults {
- name: "libadb_pairing_connection_defaults",
- cflags: [
- "-Wall",
- "-Wextra",
- "-Wthread-safety",
- "-Werror",
- ],
-
- compile_multilib: "both",
-
- srcs: [
- "pairing_connection.cpp",
- ],
- target: {
- android: {
- version_script: "libadb_pairing_connection.map.txt",
- },
- windows: {
- compile_multilib: "first",
- enabled: true,
- },
- },
- export_include_dirs: ["include"],
-
- visibility: [
- "//art:__subpackages__",
- "//system/core/adb:__subpackages__",
- "//frameworks/base/services:__subpackages__",
-
- // This needs to be visible to minadbd, even though it's removed via exclude_shared_libs.
- "//bootable/recovery/minadbd:__subpackages__",
- ],
- apex_available: [
- "com.android.adbd",
- ],
-
- // libadb_pairing_connection doesn't need an embedded build number.
- use_version_lib: false,
-
- stl: "libc++_static",
-
- host_supported: true,
- recovery_available: false,
-
- static_libs: [
- "libbase",
- "libssl",
- ],
- shared_libs: [
- "libcrypto",
- "liblog",
- "libadb_pairing_auth",
- ],
-}
-
-cc_library {
- name: "libadb_pairing_connection",
- defaults: ["libadb_pairing_connection_defaults"],
-
- apex_available: [
- "com.android.adbd",
- ],
-
- stubs: {
- symbol_file: "libadb_pairing_connection.map.txt",
- versions: ["30"],
- },
-
- static_libs: [
- "libadb_protos",
- // Statically link libadb_tls_connection because it is not
- // ABI-stable.
- "libadb_tls_connection",
- "libprotobuf-cpp-lite",
- ],
-}
-
-// For running atest (b/147158681)
-cc_library_static {
- name: "libadb_pairing_connection_static",
- defaults: ["libadb_pairing_connection_defaults"],
-
- apex_available: [
- "//apex_available:platform",
- ],
-
- static_libs: [
- "libadb_protos_static",
- "libprotobuf-cpp-lite",
- "libadb_tls_connection_static",
- ],
-}
-
-cc_defaults {
- name: "libadb_pairing_server_defaults",
- cflags: [
- "-Wall",
- "-Wextra",
- "-Wthread-safety",
- "-Werror",
- ],
-
- compile_multilib: "both",
-
- srcs: [
- "pairing_server.cpp",
- ],
- target: {
- android: {
- version_script: "libadb_pairing_server.map.txt",
- },
- },
- export_include_dirs: ["include"],
-
- visibility: [
- "//art:__subpackages__",
- "//system/core/adb:__subpackages__",
- "//frameworks/base/services:__subpackages__",
- ],
-
- host_supported: true,
- recovery_available: false,
-
- stl: "libc++_static",
-
- static_libs: [
- "libbase",
- ],
- shared_libs: [
- "libcrypto",
- "libcrypto_utils",
- "libcutils",
- "liblog",
- "libadb_pairing_auth",
- "libadb_pairing_connection",
- ],
-}
-
-cc_library {
- name: "libadb_pairing_server",
- defaults: ["libadb_pairing_server_defaults"],
-
- apex_available: [
- "com.android.adbd",
- ],
-
- stubs: {
- symbol_file: "libadb_pairing_server.map.txt",
- versions: ["30"],
- },
-
- static_libs: [
- // Statically link libadb_crypto because it is not
- // ABI-stable.
- "libadb_crypto",
- "libadb_protos",
- ],
-}
-
-// For running atest (b/147158681)
-cc_library_static {
- name: "libadb_pairing_server_static",
- defaults: ["libadb_pairing_server_defaults"],
-
- apex_available: [
- "//apex_available:platform",
- ],
-
- static_libs: [
- "libadb_crypto_static",
- "libadb_protos_static",
- ],
-}
diff --git a/adb/pairing_connection/include/adb/pairing/pairing_connection.h b/adb/pairing_connection/include/adb/pairing/pairing_connection.h
deleted file mode 100644
index 3543b8738..000000000
--- 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 <stddef.h>
-#include <stdint.h>
-#include <sys/cdefs.h>
-
-#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 178a174bd..000000000
--- 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 <stddef.h>
-#include <stdint.h>
-#include <sys/cdefs.h>
-
-#include <functional>
-#include <memory>
-#include <string_view>
-#include <vector>
-
-#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 9a04f174e..000000000
--- 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 abd5f16d4..000000000
--- 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 dc0dc89a3..000000000
--- 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 ffe49a91e..000000000
--- 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 <stddef.h>
-#include <stdint.h>
-
-#include <functional>
-#include <memory>
-#include <string_view>
-#include <thread>
-#include <vector>
-
-#include <adb/pairing/pairing_auth.h>
-#include <adb/tls/tls_connection.h>
-#include <android-base/endian.h>
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <android-base/unique_fd.h>
-
-#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<PairingAuthCtx, PairingAuthDeleter>;
-
-// 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<uint8_t>;
- 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_{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::TlsConnection> 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<const char*>(cert_.data()), cert_.size()),
- std::string_view(reinterpret_cast<const char*>(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<uint8_t> 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<const char*>(&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<uint32_t>(*p);
- return false;
- }
- header->type = *p;
- ++p;
- // Last, the payload size
- header->payload = ntohl(*(reinterpret_cast<uint32_t*>(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<uint8_t>(static_cast<int>(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<uint8_t*>(&expected_type);
- if (actual != expected) {
- LOG(ERROR) << "Unexpected header type (expected=" << static_cast<uint32_t>(expected)
- << " actual=" << static_cast<uint32_t>(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<uint8_t> 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<const char*>(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<uint8_t> buf;
- uint8_t* p = reinterpret_cast<uint8_t*>(&peer_info_);
- buf.assign(p, p + sizeof(peer_info_));
- std::vector<uint8_t> 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<uint8_t>(static_cast<int>(adb::proto::PairingPacket::PEER_INFO));
- out_header.payload = htonl(outbuf.size());
- if (!tls_->WriteFully(
- std::string_view(reinterpret_cast<const char*>(&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<const char*>(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<uint8_t> vec_pswd(pswd, pswd + pswd_len);
- std::vector<uint8_t> vec_x509_cert(x509_cert_pem, x509_cert_pem + x509_size);
- std::vector<uint8_t> 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 7218eacf2..000000000
--- 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 <sys/epoll.h>
-#include <sys/eventfd.h>
-
-#include <atomic>
-#include <deque>
-#include <iomanip>
-#include <mutex>
-#include <sstream>
-#include <thread>
-#include <tuple>
-#include <unordered_map>
-#include <variant>
-#include <vector>
-
-#include <adb/crypto/rsa_2048_key.h>
-#include <adb/crypto/x509_generator.h>
-#include <adb/pairing/pairing_connection.h>
-#include <android-base/logging.h>
-#include <android-base/parsenetaddress.h>
-#include <android-base/thread_annotations.h>
-#include <android-base/unique_fd.h>
-#include <cutils/sockets.h>
-
-#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<uint8_t>;
-
- 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<PairingConnectionCtx, ConnectionDeleter>;
- static ConnectionPtr CreatePairingConnection(const Data& pswd, const PeerInfo& peer_info,
- const Data& cert, const Data& priv_key);
- using NewConnectionEvent = std::tuple<unique_fd, ConnectionPtr>;
- // <fd, PeerInfo.type, PeerInfo.data>
- using ConnectionFinishedEvent = std::tuple<FdVal, uint8_t, std::optional<std::string>>;
- using ConnectionEvent = std::variant<NewConnectionEvent, ConnectionFinishedEvent>;
- // 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<ConnectionEvent> conn_write_queue_ GUARDED_BY(conn_mutex_);
- std::deque<ConnectionEvent> conn_read_queue_;
- // Map of fds to their PairingConnections currently running.
- std::unordered_map<FdVal, ConnectionPtr> 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<std::mutex> 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<PairingServerCtx*>(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<const char*>(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<std::mutex> 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<std::mutex> 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<NewConnectionEvent>(&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<ConnectionFinishedEvent>(&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<char*>(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<std::mutex> 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<uint8_t> vec_pswd(pswd, pswd + pswd_len);
- std::vector<uint8_t> vec_x509_cert(x509_cert_pem, x509_cert_pem + x509_size);
- std::vector<uint8_t> 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<const uint8_t*>(cert_pem.data()), cert_pem.size(),
- reinterpret_cast<const uint8_t*>(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 bf075bcb9..000000000
--- 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 1f3ef5a34..000000000
--- 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 <netdb.h>
-#include <netinet/tcp.h>
-
-#include <atomic>
-#include <iomanip>
-#include <mutex>
-#include <sstream>
-#include <thread>
-#include <vector>
-
-#include <android-base/logging.h>
-#include <android-base/parsenetaddress.h>
-#include <android-base/stringprintf.h>
-#include <android-base/thread_annotations.h>
-#include <android-base/unique_fd.h>
-#include <cutils/sockets.h>
-
-namespace adb {
-namespace pairing {
-
-using android::base::unique_fd;
-
-static void ConnectionDeleter(PairingConnectionCtx* p) {
- pairing_connection_destroy(p);
-}
-using ConnectionPtr = std::unique_ptr<PairingConnectionCtx, decltype(&ConnectionDeleter)>;
-
-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<PairingClientImpl*>(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> 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<PairingClient>(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 be0db5ce4..000000000
--- 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 <stddef.h>
-#include <stdint.h>
-
-#include <functional>
-#include <memory>
-#include <string_view>
-#include <vector>
-
-#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<uint8_t>;
-
- 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<PairingClient> 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 b6e09f190..000000000
--- 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 <chrono>
-#include <condition_variable>
-#include <mutex>
-#include <thread>
-
-#include <adb/pairing/pairing_server.h>
-#include <android-base/logging.h>
-#include <android-base/strings.h>
-#include <gtest/gtest.h>
-
-#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<PairingServerCtx, ServerDeleter>;
-
-struct ResultWaiter {
- std::mutex mutex_;
- std::condition_variable cv_;
- std::optional<bool> is_valid_;
- PeerInfo peer_info_;
-
- static void ResultCallback(const PeerInfo* peer_info, void* opaque) {
- auto* p = reinterpret_cast<ResultWaiter*>(opaque);
- {
- std::unique_lock<std::mutex> 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<uint8_t>& server_pswd,
- const std::vector<uint8_t>& client_pswd) {
- server_ = CreateServer(server_pswd);
- client_ = CreateClient(client_pswd);
- }
-
- ServerPtr CreateServer(const std::vector<uint8_t>& pswd) {
- return CreateServer(pswd, &server_info_, kTestRsa2048ServerCert, kTestRsa2048ServerPrivKey,
- 0);
- }
-
- std::unique_ptr<PairingClient> CreateClient(const std::vector<uint8_t> pswd) {
- std::vector<uint8_t> cert;
- std::vector<uint8_t> key;
- // Include the null-byte as well.
- cert.assign(reinterpret_cast<const uint8_t*>(kTestRsa2048ClientCert.data()),
- reinterpret_cast<const uint8_t*>(kTestRsa2048ClientCert.data()) +
- kTestRsa2048ClientCert.size() + 1);
- key.assign(reinterpret_cast<const uint8_t*>(kTestRsa2048ClientPrivKey.data()),
- reinterpret_cast<const uint8_t*>(kTestRsa2048ClientPrivKey.data()) +
- kTestRsa2048ClientPrivKey.size() + 1);
- return PairingClient::Create(pswd, client_info_, cert, key);
- }
-
- static ServerPtr CreateServer(const std::vector<uint8_t>& 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<const uint8_t*>(cert.data()),
- cert.size(), reinterpret_cast<const uint8_t*>(priv_key.data()), priv_key.size(),
- port));
- }
-
- ServerPtr server_;
- const PeerInfo server_info_ = {
- .type = ADB_DEVICE_GUID,
- .data = "my_server_info",
- };
- std::unique_ptr<PairingClient> 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<uint8_t> pswd{0x01, 0x03, 0x05, 0x07};
- // Bad password
- ASSERT_DEATH(
- {
- pairing_connection_client_new(
- nullptr, pswd.size(), &client_info_,
- reinterpret_cast<const uint8_t*>(kTestRsa2048ClientCert.data()),
- kTestRsa2048ClientCert.size(),
- reinterpret_cast<const uint8_t*>(kTestRsa2048ClientPrivKey.data()),
- kTestRsa2048ClientPrivKey.size());
- },
- "");
- ASSERT_DEATH(
- {
- pairing_connection_client_new(
- pswd.data(), 0, &client_info_,
- reinterpret_cast<const uint8_t*>(kTestRsa2048ClientCert.data()),
- kTestRsa2048ClientCert.size(),
- reinterpret_cast<const uint8_t*>(kTestRsa2048ClientPrivKey.data()),
- kTestRsa2048ClientPrivKey.size());
- },
- "");
-
- // Bad peer_info
- ASSERT_DEATH(
- {
- pairing_connection_client_new(
- pswd.data(), pswd.size(), nullptr,
- reinterpret_cast<const uint8_t*>(kTestRsa2048ClientCert.data()),
- kTestRsa2048ClientCert.size(),
- reinterpret_cast<const uint8_t*>(kTestRsa2048ClientPrivKey.data()),
- kTestRsa2048ClientPrivKey.size());
- },
- "");
-
- // Bad certificate
- ASSERT_DEATH(
- {
- pairing_connection_client_new(
- pswd.data(), pswd.size(), &client_info_, nullptr,
- kTestRsa2048ClientCert.size(),
- reinterpret_cast<const uint8_t*>(kTestRsa2048ClientPrivKey.data()),
- kTestRsa2048ClientPrivKey.size());
- },
- "");
- ASSERT_DEATH(
- {
- pairing_connection_client_new(
- pswd.data(), pswd.size(), &client_info_,
- reinterpret_cast<const uint8_t*>(kTestRsa2048ClientCert.data()), 0,
- reinterpret_cast<const uint8_t*>(kTestRsa2048ClientPrivKey.data()),
- kTestRsa2048ClientPrivKey.size());
- },
- "");
-
- // Bad private key
- ASSERT_DEATH(
- {
- pairing_connection_client_new(
- pswd.data(), pswd.size(), &client_info_,
- reinterpret_cast<const uint8_t*>(kTestRsa2048ClientCert.data()),
- kTestRsa2048ClientCert.size(), nullptr, kTestRsa2048ClientPrivKey.size());
- },
- "");
- ASSERT_DEATH(
- {
- pairing_connection_client_new(
- pswd.data(), pswd.size(), &client_info_,
- reinterpret_cast<const uint8_t*>(kTestRsa2048ClientCert.data()),
- kTestRsa2048ClientCert.size(),
- reinterpret_cast<const uint8_t*>(kTestRsa2048ClientPrivKey.data()), 0);
- },
- "");
-
- // Valid params
- auto client = pairing_connection_client_new(
- pswd.data(), pswd.size(), &client_info_,
- reinterpret_cast<const uint8_t*>(kTestRsa2048ClientCert.data()),
- kTestRsa2048ClientCert.size(),
- reinterpret_cast<const uint8_t*>(kTestRsa2048ClientPrivKey.data()),
- kTestRsa2048ClientPrivKey.size());
- EXPECT_NE(nullptr, client);
-}
-
-TEST_F(AdbPairingConnectionTest, SmokeValidPairing) {
- std::vector<uint8_t> pswd{0x01, 0x03, 0x05, 0x07};
- InitPairing(pswd, pswd);
-
- // Start the server
- ResultWaiter server_waiter;
- std::unique_lock<std::mutex> 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<std::mutex> 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<const char*>(client_waiter.peer_info_.data)),
- strlen(reinterpret_cast<const char*>(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<const char*>(server_waiter.peer_info_.data)),
- strlen(reinterpret_cast<const char*>(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<uint8_t> pswd{0x01, 0x03, 0x05, 0x07};
- std::vector<uint8_t> pswd2{0x01, 0x03, 0x05, 0x06};
- InitPairing(pswd, pswd2);
-
- // Start the server
- ResultWaiter server_waiter;
- std::unique_lock<std::mutex> 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<std::mutex> 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<uint8_t> pswd{0x01, 0x03, 0x05, 0x07};
- std::vector<uint8_t> pswd2{0x01, 0x03, 0x05, 0x06};
-
- // Start the server
- auto server = CreateServer(pswd);
- ResultWaiter server_waiter;
- std::unique_lock<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> global_lock(global_clients_mutex);
- ++num_clients_done;
- }
- global_cv_.notify_one();
- }).detach();
- }
-
- global_cv_.wait(global_clients_lock, [&]() { return num_clients_done == test_num_clients; });
- server_lock.unlock();
- server.reset();
- server_lock.lock();
- ASSERT_TRUE(server_waiter.is_valid_.has_value());
- EXPECT_FALSE(*(server_waiter.is_valid_));
-}
-
-TEST_F(AdbPairingConnectionTest, MultipleClientsOnePass) {
- // Send multiple clients with bad passwords, but send the last one with the
- // correct password.
- std::vector<uint8_t> pswd{0x01, 0x03, 0x05, 0x07};
- std::vector<uint8_t> pswd2{0x01, 0x03, 0x05, 0x06};
-
- // Start the server
- auto server = CreateServer(pswd);
- ResultWaiter server_waiter;
- std::unique_lock<std::mutex> 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<std::mutex> 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<std::mutex> 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<const char*>(client_waiter.peer_info_.data)),
- strlen(reinterpret_cast<const char*>(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<std::mutex> 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<const char*>(server_waiter.peer_info_.data)),
- strlen(reinterpret_cast<const char*>(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 f7cba9522..000000000
--- a/adb/proto/Android.bp
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright (C) 2020 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-cc_defaults {
- name: "libadb_protos_defaults",
- cflags: [
- "-Wall",
- "-Wextra",
- "-Wthread-safety",
- "-Werror",
- ],
-
- compile_multilib: "both",
-
- proto: {
- export_proto_headers: true,
- type: "lite",
- },
- srcs: [
- "adb_known_hosts.proto",
- "key_type.proto",
- "pairing.proto",
- ],
- target: {
- windows: {
- compile_multilib: "first",
- enabled: true,
- },
- },
-
- visibility: [
- "//system/core/adb:__subpackages__",
-
- // This needs to be visible to minadbd, even though it's removed via exclude_shared_libs.
- "//bootable/recovery/minadbd:__subpackages__",
- ],
-
- stl: "libc++_static",
-
- host_supported: true,
- recovery_available: true,
-}
-
-cc_library {
- name: "libadb_protos",
- defaults: ["libadb_protos_defaults"],
-
- apex_available: [
- "com.android.adbd",
- "test_com.android.adbd",
- ],
-}
-
-// For running atest (b/147158681)
-cc_library_static {
- name: "libadb_protos_static",
- defaults: ["libadb_protos_defaults"],
-
- apex_available: [
- "//apex_available:platform",
- ],
-}
diff --git a/adb/proto/adb_known_hosts.proto b/adb/proto/adb_known_hosts.proto
deleted file mode 100644
index 85d1489ff..000000000
--- a/adb/proto/adb_known_hosts.proto
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto3";
-
-option java_package = "com.android.server.adb.protos";
-option java_outer_classname = "AdbKnownHostsProto";
-
-package adb.proto;
-
-// Each known host
-message HostInfo {
- string guid = 1;
-}
-
-// Protobuf definition for the adb_known_hosts.
-message AdbKnownHosts {
- repeated HostInfo host_infos = 1;
-}
diff --git a/adb/proto/jarjar-rules.txt b/adb/proto/jarjar-rules.txt
deleted file mode 100644
index 4e4063706..000000000
--- 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 ed451c511..000000000
--- 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 b0be20e53..000000000
--- 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 75700a4d5..000000000
--- 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 "<systemtype>:<serialno>:<banner>"
-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>:<port>" - host may be omitted to indicate localhost
-* "udp:<host>:<port>" - host may be omitted to indicate localhost
-* "local-dgram:<identifier>"
-* "local-stream:<identifier>"
-* "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......" <CLOSE>
-
-
---- 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 <READY >WRITE <READY >WRITE <READY >WRITE <CLOSE
-
-The far side may choose to issue the READY message as soon as it receives
-a WRITE or it may defer the READY until the write to the local stream
-succeeds. A future version may want to do some level of windowing where
-multiple WRITEs may be sent without requiring individual READY acks.
-
-------------------------------------------------------------------------
-
---- smartsockets -------------------------------------------------------
-
-Port 5037 is used for smart sockets which allow a client on the host
-side to request access to a service in the host adb daemon or in the
-remote (device) daemon. The service is requested by ascii name,
-preceeded by a 4 digit hex length. Upon successful connection an
-"OKAY" response is sent, otherwise a "FAIL" message is returned. Once
-connected the client is talking to that (remote or local) service.
-
-client: <hex4> <service-name>
-server: "OKAY"
-
-client: <hex4> <service-name>
-server: "FAIL" <hex4> <reason>
-
diff --git a/adb/security_log_tags.h b/adb/security_log_tags.h
deleted file mode 100644
index 1d0274494..000000000
--- 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 853d65897..000000000
--- 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 <errno.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <cstring>
-#include <thread>
-
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-#include <cutils/sockets.h>
-
-#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<void(unique_fd)> 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<void(unique_fd)> func) {
- int s[2];
- if (adb_socketpair(s)) {
- printf("cannot create service socket pair\n");
- return unique_fd();
- }
- D("socketpair: (%d,%d)", s[0], s[1]);
-
-#if !ADB_HOST
- if (strcmp(service_name, "sync") == 0) {
- // Set file sync service socket to maximum size
- int max_buf = LINUX_MAX_SOCKET_SIZE;
- adb_setsockopt(s[0], SOL_SOCKET, SO_SNDBUF, &max_buf, sizeof(max_buf));
- adb_setsockopt(s[1], SOL_SOCKET, SO_SNDBUF, &max_buf, sizeof(max_buf));
- }
-#endif // !ADB_HOST
-
- std::thread(service_bootstrap_func, service_name, func, unique_fd(s[1])).detach();
-
- D("service thread started, %d:%d", s[0], s[1]);
- return unique_fd(s[0]);
-}
-
-unique_fd service_to_fd(std::string_view name, atransport* transport) {
- unique_fd ret;
-
- if (is_socket_spec(name)) {
- std::string error;
- if (!socket_spec_connect(&ret, name, nullptr, nullptr, &error)) {
- LOG(ERROR) << "failed to connect to socket '" << name << "': " << error;
- }
- } else {
-#if !ADB_HOST
- ret = daemon_service_to_fd(name, transport);
-#endif
- }
-
- if (ret >= 0) {
- close_on_exec(ret.get());
- }
- return ret;
-}
-
-#if ADB_HOST
-struct state_info {
- TransportType transport_type;
- std::string serial;
- TransportId transport_id;
- ConnectionState state;
-};
-
-static void wait_for_state(unique_fd fd, state_info* sinfo) {
- D("wait_for_state %d", sinfo->state);
-
- while (true) {
- bool is_ambiguous = false;
- std::string error = "unknown error";
- const char* serial = sinfo->serial.length() ? sinfo->serial.c_str() : nullptr;
- atransport* t = acquire_one_transport(sinfo->transport_type, serial, sinfo->transport_id,
- &is_ambiguous, &error);
- if (sinfo->state == kCsOffline) {
- // wait-for-disconnect uses kCsOffline, we don't actually want to wait for 'offline'.
- if (t == nullptr) {
- SendOkay(fd);
- break;
- }
- } else if (t != nullptr &&
- (sinfo->state == kCsAny || sinfo->state == t->GetConnectionState())) {
- SendOkay(fd);
- break;
- }
-
- if (!is_ambiguous) {
- adb_pollfd pfd = {.fd = fd.get(), .events = POLLIN};
- int rc = adb_poll(&pfd, 1, 100);
- if (rc < 0) {
- SendFail(fd, error);
- break;
- } else if (rc > 0 && (pfd.revents & POLLHUP) != 0) {
- // The other end of the socket is closed, probably because the other side was
- // terminated, bail out.
- break;
- }
-
- // Try again...
- } else {
- SendFail(fd, error);
- break;
- }
- }
-
- D("wait_for_state is done");
-}
-
-void connect_emulator(const std::string& port_spec, std::string* response) {
- std::vector<std::string> pieces = android::base::Split(port_spec, ",");
- if (pieces.size() != 2) {
- *response = android::base::StringPrintf("unable to parse '%s' as <console port>,<adb port>",
- port_spec.c_str());
- return;
- }
-
- int console_port = strtol(pieces[0].c_str(), nullptr, 0);
- int adb_port = strtol(pieces[1].c_str(), nullptr, 0);
- if (console_port <= 0 || adb_port <= 0) {
- *response = android::base::StringPrintf("Invalid port numbers: %s", port_spec.c_str());
- return;
- }
-
- // Check if the emulator is already known.
- // Note: There's a small but harmless race condition here: An emulator not
- // present just yet could be registered by another invocation right
- // after doing this check here. However, local_connect protects
- // against double-registration too. From here, a better error message
- // can be produced. In the case of the race condition, the very specific
- // error message won't be shown, but the data doesn't get corrupted.
- atransport* known_emulator = find_emulator_transport_by_adb_port(adb_port);
- if (known_emulator != nullptr) {
- *response = android::base::StringPrintf("Emulator already registered on port %d", adb_port);
- return;
- }
-
- // Preconditions met, try to connect to the emulator.
- std::string error;
- if (!local_connect_arbitrary_ports(console_port, adb_port, &error)) {
- *response = android::base::StringPrintf("Connected to emulator on ports %d,%d",
- console_port, adb_port);
- } else {
- *response = android::base::StringPrintf("Could not connect to emulator on ports %d,%d: %s",
- console_port, adb_port, error.c_str());
- }
-}
-
-static void connect_service(unique_fd fd, std::string host) {
- std::string response;
- if (!strncmp(host.c_str(), "emu:", 4)) {
- connect_emulator(host.c_str() + 4, &response);
- } else {
- connect_device(host, &response);
- }
-
- // Send response for emulator and device
- SendProtocolString(fd.get(), response);
-}
-
-static void pair_service(unique_fd fd, std::string host, std::string password) {
- std::string response;
- adb_wifi_pair_device(host, password, response);
- SendProtocolString(fd.get(), response);
-}
-#endif
-
-#if ADB_HOST
-asocket* host_service_to_socket(std::string_view name, std::string_view serial,
- TransportId transport_id) {
- if (name == "track-devices") {
- return create_device_tracker(false);
- } else if (name == "track-devices-l") {
- return create_device_tracker(true);
- } else if (android::base::ConsumePrefix(&name, "wait-for-")) {
- std::shared_ptr<state_info> sinfo = std::make_shared<state_info>();
- if (sinfo == nullptr) {
- fprintf(stderr, "couldn't allocate state_info: %s", strerror(errno));
- return nullptr;
- }
-
- sinfo->serial = serial;
- sinfo->transport_id = transport_id;
-
- if (android::base::ConsumePrefix(&name, "local")) {
- sinfo->transport_type = kTransportLocal;
- } else if (android::base::ConsumePrefix(&name, "usb")) {
- sinfo->transport_type = kTransportUsb;
- } else if (android::base::ConsumePrefix(&name, "any")) {
- sinfo->transport_type = kTransportAny;
- } else {
- return nullptr;
- }
-
- if (name == "-device") {
- sinfo->state = kCsDevice;
- } else if (name == "-recovery") {
- sinfo->state = kCsRecovery;
- } else if (name == "-rescue") {
- sinfo->state = kCsRescue;
- } else if (name == "-sideload") {
- sinfo->state = kCsSideload;
- } else if (name == "-bootloader") {
- sinfo->state = kCsBootloader;
- } else if (name == "-any") {
- sinfo->state = kCsAny;
- } else if (name == "-disconnect") {
- sinfo->state = kCsOffline;
- } else {
- return nullptr;
- }
-
- unique_fd fd = create_service_thread(
- "wait", [sinfo](unique_fd fd) { wait_for_state(std::move(fd), sinfo.get()); });
- return create_local_socket(std::move(fd));
- } else if (android::base::ConsumePrefix(&name, "connect:")) {
- std::string host(name);
- unique_fd fd = create_service_thread(
- "connect", std::bind(connect_service, std::placeholders::_1, host));
- return create_local_socket(std::move(fd));
- } else if (android::base::ConsumePrefix(&name, "pair:")) {
- const char* divider = strchr(name.data(), ':');
- if (!divider) {
- return nullptr;
- }
- std::string password(name.data(), divider);
- std::string host(divider + 1);
- unique_fd fd = create_service_thread(
- "pair", std::bind(pair_service, std::placeholders::_1, host, password));
- return create_local_socket(std::move(fd));
- }
- return nullptr;
-}
-#endif /* ADB_HOST */
diff --git a/adb/services.h b/adb/services.h
deleted file mode 100644
index 6fc89d71f..000000000
--- 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<void(unique_fd)> func);
-#endif // SERVICES_H_
diff --git a/adb/shell_protocol.h b/adb/shell_protocol.h
deleted file mode 100644
index 4aab8131c..000000000
--- 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 <stdint.h>
-
-#include <android-base/macros.h>
-
-#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 95afaffe7..000000000
--- 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 <string.h>
-
-#include <algorithm>
-
-#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 a10b5c055..000000000
--- 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 <gtest/gtest.h>
-
-#include <signal.h>
-#include <string.h>
-
-#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 4276851d2..000000000
--- a/adb/socket.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __ADB_SOCKET_H
-#define __ADB_SOCKET_H
-
-#include <stddef.h>
-
-#include <deque>
-#include <memory>
-#include <string>
-
-#include "adb_unique_fd.h"
-#include "fdevent/fdevent.h"
-#include "types.h"
-
-class atransport;
-
-/* An asocket represents one half of a connection between a local and
- * remote entity. A local asocket is bound to a file descriptor. A
- * remote asocket is bound to the protocol engine.
- */
-struct asocket {
- /* the unique identifier for this asocket
- */
- unsigned id = 0;
-
- /* flag: set when the socket's peer has closed
- * but packets are still queued for delivery
- */
- int closing = 0;
-
- // flag: set when the socket failed to write, so the socket will not wait to
- // write packets and close directly.
- bool has_write_error = 0;
-
- /* flag: quit adbd when both ends close the
- * local service socket
- */
- int exit_on_close = 0;
-
- // the asocket we are connected to
- asocket* peer = nullptr;
-
- /* For local asockets, the fde is used to bind
- * us to our fd event system. For remote asockets
- * these fields are not used.
- */
- fdevent* fde = nullptr;
- int fd = -1;
-
- // queue of data waiting to be written
- IOVector packet_queue;
-
- std::string smart_socket_data;
-
- /* enqueue is called by our peer when it has data
- * for us. It should return 0 if we can accept more
- * data or 1 if not. If we return 1, we must call
- * peer->ready() when we once again are ready to
- * receive data.
- */
- int (*enqueue)(asocket* s, apacket::payload_type data) = nullptr;
-
- /* ready is called by the peer when it is ready for
- * us to send data via enqueue again
- */
- void (*ready)(asocket* s) = nullptr;
-
- /* shutdown is called by the peer before it goes away.
- * the socket should not do any further calls on its peer.
- * Always followed by a call to close. Optional, i.e. can be NULL.
- */
- void (*shutdown)(asocket* s) = nullptr;
-
- /* close is called by the peer when it has gone away.
- * we are not allowed to make any further calls on the
- * peer once our close method is called.
- */
- void (*close)(asocket* s) = nullptr;
-
- /* A socket is bound to atransport */
- atransport* transport = nullptr;
-
- size_t get_max_payload() const;
-};
-
-asocket *find_local_socket(unsigned local_id, unsigned remote_id);
-void install_local_socket(asocket *s);
-void remove_socket(asocket *s);
-void close_all_sockets(atransport *t);
-
-asocket* create_local_socket(unique_fd fd);
-asocket* create_local_service_socket(std::string_view destination, atransport* transport);
-
-asocket *create_remote_socket(unsigned id, atransport *t);
-void connect_to_remote(asocket* s, std::string_view destination);
-void connect_to_smartsocket(asocket *s);
-
-// Internal functions that are only made available here for testing purposes.
-namespace internal {
-
-#if ADB_HOST
-bool parse_host_service(std::string_view* out_serial, std::string_view* out_command,
- std::string_view service);
-#endif
-
-} // namespace internal
-
-#endif // __ADB_SOCKET_H
diff --git a/adb/socket_spec.cpp b/adb/socket_spec.cpp
deleted file mode 100644
index d17036cec..000000000
--- a/adb/socket_spec.cpp
+++ /dev/null
@@ -1,449 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "socket_spec.h"
-
-#include <limits>
-#include <string>
-#include <string_view>
-#include <unordered_map>
-#include <vector>
-
-#include <android-base/parseint.h>
-#include <android-base/parsenetaddress.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-#include <cutils/sockets.h>
-
-#include "adb.h"
-#include "adb_utils.h"
-#include "sysdeps.h"
-
-using namespace std::string_literals;
-
-using android::base::ConsumePrefix;
-using android::base::StringPrintf;
-
-#if defined(__linux__)
-#define ADB_LINUX 1
-#else
-#define ADB_LINUX 0
-#endif
-
-#if defined(_WIN32)
-#define ADB_WINDOWS 1
-#else
-#define ADB_WINDOWS 0
-#endif
-
-#if ADB_LINUX
-#include <sys/socket.h>
-#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<std::string, LocalSocketType>({
-#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:<port>, parse it ourselves.
- // Otherwise, delegate to android::base::ParseNetAddress.
- if (android::base::ParseInt(&spec[4], &port_value)) {
- // Do the range checking ourselves, because ParseInt rejects 'tcp:65536' and 'tcp:foo:1234'
- // identically.
- if (port_value < 0 || port_value > 65535) {
- *error = StringPrintf("bad port number '%d'", port_value);
- return false;
- }
- } else {
- std::string addr(spec.substr(4));
- port_value = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
-
- // FIXME: ParseNetAddress rejects port 0. This currently doesn't hurt, because listening
- // on an address that isn't 'localhost' is unsupported.
- if (!android::base::ParseNetAddress(addr, &hostname_value, &port_value, serial, error)) {
- return false;
- }
-
- if (port_value == -1) {
- *error = "missing port in specification: ";
- *error += spec;
- return false;
- }
- }
-
- if (hostname) {
- *hostname = std::move(hostname_value);
- }
-
- if (port) {
- *port = port_value;
- }
-
- return true;
-}
-
-int get_host_socket_spec_port(std::string_view spec, std::string* error) {
- int port;
- if (spec.starts_with("tcp:")) {
- if (!parse_tcp_socket_spec(spec, nullptr, &port, nullptr, error)) {
- return -1;
- }
- } else if (spec.starts_with("vsock:")) {
-#if ADB_LINUX
- std::string spec_str(spec);
- std::vector<std::string> fragments = android::base::Split(spec_str, ":");
- if (fragments.size() != 2) {
- *error = "given vsock server socket string was invalid";
- return -1;
- }
- if (!android::base::ParseInt(fragments[1], &port)) {
- *error = "could not parse vsock port";
- errno = EINVAL;
- return -1;
- }
- if (port < 0) {
- *error = "vsock port was negative.";
- errno = EINVAL;
- return -1;
- }
-#else // ADB_LINUX
- *error = "vsock is only supported on linux";
- return -1;
-#endif // ADB_LINUX
- } else {
- *error = "given socket spec string was invalid";
- return -1;
- }
- return port;
-}
-
-static bool tcp_host_is_local(std::string_view hostname) {
- // FIXME
- return hostname.empty() || hostname == "localhost";
-}
-
-bool is_socket_spec(std::string_view spec) {
- for (const auto& it : kLocalSocketTypes) {
- std::string prefix = it.first + ":";
- if (spec.starts_with(prefix)) {
- return true;
- }
- }
- return spec.starts_with("tcp:") || spec.starts_with("acceptfd:");
-}
-
-bool is_local_socket_spec(std::string_view spec) {
- for (const auto& it : kLocalSocketTypes) {
- std::string prefix = it.first + ":";
- if (spec.starts_with(prefix)) {
- return true;
- }
- }
-
- std::string error;
- std::string hostname;
- if (!parse_tcp_socket_spec(spec, &hostname, nullptr, nullptr, &error)) {
- return false;
- }
- return tcp_host_is_local(hostname);
-}
-
-bool socket_spec_connect(unique_fd* fd, std::string_view address, int* port, std::string* serial,
- std::string* error) {
- if (address.starts_with("tcp:")) {
- std::string hostname;
- int port_value = port ? *port : 0;
- if (!parse_tcp_socket_spec(address, &hostname, &port_value, serial, error)) {
- return false;
- }
-
- if (tcp_host_is_local(hostname)) {
- fd->reset(network_loopback_client(port_value, SOCK_STREAM, error));
- } else {
-#if ADB_HOST
- fd->reset(network_connect(hostname, port_value, SOCK_STREAM, 0, error));
-#else
- // Disallow arbitrary connections in adbd.
- *error = "adbd does not support arbitrary tcp connections";
- return false;
-#endif
- }
-
- if (fd->get() > 0) {
- disable_tcp_nagle(fd->get());
- if (port) {
- *port = port_value;
- }
- return true;
- }
- return false;
- } else if (address.starts_with("vsock:")) {
-#if ADB_LINUX
- std::string spec_str(address);
- std::vector<std::string> 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<sockaddr*>(&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<std::string> 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<struct sockaddr*>(&addr), addr_len)) {
- return -1;
- }
- if (listen(serverfd.get(), 4)) {
- return -1;
- }
- if (serverfd >= 0 && resolved_port) {
- if (getsockname(serverfd.get(), reinterpret_cast<sockaddr*>(&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<int>::max()) {
- *error = "invalid fd";
- return -1;
- }
- int fd = static_cast<int>(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 94719c811..000000000
--- 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 <string>
-#include <tuple>
-
-#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 e9d5270ca..000000000
--- a/adb/socket_spec_test.cpp
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "socket_spec.h"
-
-#include <string>
-
-#include <unistd.h>
-
-#include <android-base/file.h>
-#include <android-base/stringprintf.h>
-#include <gtest/gtest.h>
-
-TEST(socket_spec, parse_tcp_socket_spec_just_port) {
- std::string hostname, error, serial;
- int port;
- EXPECT_TRUE(parse_tcp_socket_spec("tcp:5037", &hostname, &port, &serial, &error));
- EXPECT_EQ("", hostname);
- EXPECT_EQ(5037, port);
- EXPECT_EQ("", serial);
-}
-
-TEST(socket_spec, parse_tcp_socket_spec_bad_ports) {
- std::string hostname, error, serial;
- int port;
- EXPECT_FALSE(parse_tcp_socket_spec("tcp:", &hostname, &port, &serial, &error));
- EXPECT_FALSE(parse_tcp_socket_spec("tcp:-1", &hostname, &port, &serial, &error));
- EXPECT_FALSE(parse_tcp_socket_spec("tcp:65536", &hostname, &port, &serial, &error));
-}
-
-TEST(socket_spec, parse_tcp_socket_spec_host_and_port) {
- std::string hostname, error, serial;
- int port;
- EXPECT_TRUE(parse_tcp_socket_spec("tcp:localhost:1234", &hostname, &port, &serial, &error));
- EXPECT_EQ("localhost", hostname);
- EXPECT_EQ(1234, port);
- EXPECT_EQ("localhost:1234", serial);
-}
-
-TEST(socket_spec, parse_tcp_socket_spec_host_no_port) {
- std::string hostname, error, serial;
- int port;
- EXPECT_TRUE(parse_tcp_socket_spec("tcp:localhost", &hostname, &port, &serial, &error));
- EXPECT_EQ("localhost", hostname);
- EXPECT_EQ(5555, port);
- EXPECT_EQ("localhost:5555", serial);
-}
-
-TEST(socket_spec, parse_tcp_socket_spec_host_bad_ports) {
- std::string hostname, error, serial;
- int port;
- EXPECT_FALSE(parse_tcp_socket_spec("tcp:localhost:", &hostname, &port, &serial, &error));
- EXPECT_FALSE(parse_tcp_socket_spec("tcp:localhost:-1", &hostname, &port, &serial, &error));
- EXPECT_FALSE(parse_tcp_socket_spec("tcp:localhost:65536", &hostname, &port, &serial, &error));
-}
-
-TEST(socket_spec, parse_tcp_socket_spec_ipv6_and_port) {
- std::string hostname, error, serial;
- int port;
- EXPECT_TRUE(parse_tcp_socket_spec("tcp:[::1]:1234", &hostname, &port, &serial, &error));
- EXPECT_EQ("::1", hostname);
- EXPECT_EQ(1234, port);
- EXPECT_EQ("[::1]:1234", serial);
-}
-
-TEST(socket_spec, parse_tcp_socket_spec_ipv6_no_port) {
- std::string hostname, error, serial;
- int port;
- EXPECT_TRUE(parse_tcp_socket_spec("tcp:::1", &hostname, &port, &serial, &error));
- EXPECT_EQ("::1", hostname);
- EXPECT_EQ(5555, port);
- EXPECT_EQ("[::1]:5555", serial);
-}
-
-TEST(socket_spec, parse_tcp_socket_spec_ipv6_bad_ports) {
- std::string hostname, error, serial;
- int port;
- EXPECT_FALSE(parse_tcp_socket_spec("tcp:[::1]", &hostname, &port, &serial, &error));
- EXPECT_FALSE(parse_tcp_socket_spec("tcp:[::1]:", &hostname, &port, &serial, &error));
- EXPECT_FALSE(parse_tcp_socket_spec("tcp:[::1]:-1", &hostname, &port, &serial, &error));
-}
-
-TEST(socket_spec, get_host_socket_spec_port) {
- std::string error;
- EXPECT_EQ(5555, get_host_socket_spec_port("tcp:5555", &error));
- EXPECT_EQ(5555, get_host_socket_spec_port("tcp:localhost:5555", &error));
- EXPECT_EQ(5555, get_host_socket_spec_port("tcp:[::1]:5555", &error));
- EXPECT_EQ(5555, get_host_socket_spec_port("vsock:5555", &error));
-}
-
-TEST(socket_spec, get_host_socket_spec_port_no_port) {
- std::string error;
- EXPECT_EQ(5555, get_host_socket_spec_port("tcp:localhost", &error));
- EXPECT_EQ(-1, get_host_socket_spec_port("vsock:localhost", &error));
-}
-
-TEST(socket_spec, get_host_socket_spec_port_bad_ports) {
- std::string error;
- EXPECT_EQ(-1, get_host_socket_spec_port("tcp:65536", &error));
- EXPECT_EQ(-1, get_host_socket_spec_port("tcp:-5", &error));
- EXPECT_EQ(-1, get_host_socket_spec_port("vsock:-5", &error));
- EXPECT_EQ(-1, get_host_socket_spec_port("vsock:5:5555", &error));
-}
-
-TEST(socket_spec, get_host_socket_spec_port_bad_string) {
- std::string error;
- EXPECT_EQ(-1, get_host_socket_spec_port("tcpz:5555", &error));
- EXPECT_EQ(-1, get_host_socket_spec_port("vsockz:5555", &error));
- EXPECT_EQ(-1, get_host_socket_spec_port("abcd:5555", &error));
- EXPECT_EQ(-1, get_host_socket_spec_port("abcd", &error));
-}
-
-TEST(socket_spec, socket_spec_listen_connect_tcp) {
- std::string error, serial;
- int port;
- unique_fd server_fd, client_fd;
- EXPECT_FALSE(socket_spec_connect(&client_fd, "tcp:localhost:7777", &port, &serial, &error));
- server_fd.reset(socket_spec_listen("tcp:7777", &error, &port));
- EXPECT_NE(server_fd.get(), -1);
- EXPECT_TRUE(socket_spec_connect(&client_fd, "tcp:localhost:7777", &port, &serial, &error));
- EXPECT_NE(client_fd.get(), -1);
-}
-
-TEST(socket_spec, socket_spec_listen_connect_localfilesystem) {
- std::string error, serial;
- int port;
- unique_fd server_fd, client_fd;
- TemporaryDir sock_dir;
-
- // Only run this test if the created directory is writable.
- int result = access(sock_dir.path, W_OK);
- if (result == 0) {
- std::string sock_addr =
- android::base::StringPrintf("localfilesystem:%s/af_unix_socket", sock_dir.path);
- EXPECT_FALSE(socket_spec_connect(&client_fd, sock_addr, &port, &serial, &error));
- server_fd.reset(socket_spec_listen(sock_addr, &error, &port));
- EXPECT_NE(server_fd.get(), -1);
- EXPECT_TRUE(socket_spec_connect(&client_fd, sock_addr, &port, &serial, &error));
- EXPECT_NE(client_fd.get(), -1);
- }
-}
diff --git a/adb/socket_test.cpp b/adb/socket_test.cpp
deleted file mode 100644
index 1601ff0ac..000000000
--- 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 <gtest/gtest.h>
-
-#include <array>
-#include <limits>
-#include <queue>
-#include <string>
-#include <thread>
-#include <vector>
-
-#include <unistd.h>
-
-#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<std::array<int, 2>> 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<char> 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:]<serial>[:<port>]:<command> 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 <prefix>:<serial>:<command> 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 423af67f1..000000000
--- a/adb/sockets.cpp
+++ /dev/null
@@ -1,935 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define TRACE_TAG SOCKETS
-
-#include "sysdeps.h"
-
-#include <ctype.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <algorithm>
-#include <chrono>
-#include <mutex>
-#include <string>
-#include <vector>
-
-#include <android-base/strings.h>
-
-#if !ADB_HOST
-#include <android-base/properties.h>
-#include <log/log_properties.h>
-#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<asocket*>();
-
-/* 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<asocket*>();
-
-// 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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> 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<adb_iovec> iov = s->packet_queue.iovecs();
- ssize_t rc = adb_writev(s->fd, iov.data(), iov.size());
- if (rc > 0 && static_cast<size_t>(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<ClosingSocket*>(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<std::recursive_mutex> 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<asocket*>(_s);
- D("LS(%d): event_func(fd=%d(==%d), ev=%04x)", s->id, s->fd, fd, ev);
-
- /* put the FDE_WRITE processing before the FDE_READ
- ** in order to simplify the code.
- */
- if (ev & FDE_WRITE) {
- switch (local_socket_flush_incoming(s)) {
- case SocketFlushResult::Destroyed:
- return;
-
- case SocketFlushResult::TryAgain:
- break;
-
- case SocketFlushResult::Completed:
- s->peer->ready(s->peer);
- break;
- }
- }
-
- if (ev & FDE_READ) {
- if (!local_socket_flush_outgoing(s)) {
- return;
- }
- }
-
- if (ev & FDE_ERROR) {
- /* this should be caught be the next read or write
- ** catching it here means we may skip the last few
- ** bytes of readable data.
- */
- D("LS(%d): FDE_ERROR (fd=%d)", s->id, s->fd);
- return;
- }
-}
-
-asocket* create_local_socket(unique_fd ufd) {
- int fd = ufd.release();
- asocket* s = new asocket();
- s->fd = fd;
- s->enqueue = local_socket_enqueue;
- s->ready = local_socket_ready;
- s->shutdown = nullptr;
- s->close = local_socket_close;
- install_local_socket(s);
-
- s->fde = fdevent_create(fd, local_socket_event_func, s);
- D("LS(%d): created (fd=%d)", s->id, s->fd);
- return s;
-}
-
-asocket* create_local_service_socket(std::string_view name, atransport* transport) {
-#if !ADB_HOST
- if (asocket* s = daemon_service_to_socket(name); s) {
- return s;
- }
-#endif
- unique_fd fd = service_to_fd(name, transport);
- if (fd < 0) {
- return nullptr;
- }
-
- int fd_value = fd.get();
- asocket* s = create_local_socket(std::move(fd));
- LOG(VERBOSE) << "LS(" << s->id << "): bound to '" << name << "' via " << fd_value;
-
-#if !ADB_HOST
- if ((name.starts_with("root:") && getuid() != 0 && __android_log_is_debuggable()) ||
- (name.starts_with("unroot:") && getuid() == 0) || name.starts_with("usb:") ||
- name.starts_with("tcpip:")) {
- D("LS(%d): enabling exit_on_close", s->id);
- s->exit_on_close = 1;
- }
-#endif
-
- return s;
-}
-
-static int remote_socket_enqueue(asocket* s, apacket::payload_type data) {
- D("entered remote_socket_enqueue RS(%d) WRITE fd=%d peer.fd=%d", s->id, s->fd, s->peer->fd);
- apacket* p = get_apacket();
-
- p->msg.command = A_WRTE;
- p->msg.arg0 = s->peer->id;
- p->msg.arg1 = s->id;
-
- if (data.size() > MAX_PAYLOAD) {
- put_apacket(p);
- return -1;
- }
-
- p->payload = std::move(data);
- p->msg.data_length = p->payload.size();
-
- send_packet(p, s->transport);
- return 1;
-}
-
-static void remote_socket_ready(asocket* s) {
- D("entered remote_socket_ready RS(%d) OKAY fd=%d peer.fd=%d", s->id, s->fd, s->peer->fd);
- apacket* p = get_apacket();
- p->msg.command = A_OKAY;
- p->msg.arg0 = s->peer->id;
- p->msg.arg1 = s->id;
- send_packet(p, s->transport);
-}
-
-static void remote_socket_shutdown(asocket* s) {
- D("entered remote_socket_shutdown RS(%d) CLOSE fd=%d peer->fd=%d", s->id, s->fd,
- s->peer ? s->peer->fd : -1);
- apacket* p = get_apacket();
- p->msg.command = A_CLSE;
- if (s->peer) {
- p->msg.arg0 = s->peer->id;
- }
- p->msg.arg1 = s->id;
- send_packet(p, s->transport);
-}
-
-static void remote_socket_close(asocket* s) {
- if (s->peer) {
- s->peer->peer = nullptr;
- D("RS(%d) peer->close()ing peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd);
- s->peer->close(s->peer);
- }
- D("entered remote_socket_close RS(%d) CLOSE fd=%d peer->fd=%d", s->id, s->fd,
- s->peer ? s->peer->fd : -1);
- D("RS(%d): closed", s->id);
- delete s;
-}
-
-// Create a remote socket to exchange packets with a remote service through transport
-// |t|. Where |id| is the socket id of the corresponding service on the other
-// side of the transport (it is allocated by the remote side and _cannot_ be 0).
-// Returns a new non-NULL asocket handle.
-asocket* create_remote_socket(unsigned id, atransport* t) {
- if (id == 0) {
- LOG(FATAL) << "invalid remote socket id (0)";
- }
- asocket* s = new asocket();
- s->id = id;
- s->enqueue = remote_socket_enqueue;
- s->ready = remote_socket_ready;
- s->shutdown = remote_socket_shutdown;
- s->close = remote_socket_close;
- s->transport = t;
-
- D("RS(%d): created", s->id);
- return s;
-}
-
-void connect_to_remote(asocket* s, std::string_view destination) {
- D("Connect_to_remote call RS(%d) fd=%d", s->id, s->fd);
- apacket* p = get_apacket();
-
- LOG(VERBOSE) << "LS(" << s->id << ": connect(" << destination << ")";
- p->msg.command = A_OPEN;
- p->msg.arg0 = s->id;
-
- // adbd used to expect a null-terminated string.
- // Keep doing so to maintain backward compatibility.
- p->payload.resize(destination.size() + 1);
- memcpy(p->payload.data(), destination.data(), destination.size());
- p->payload[destination.size()] = '\0';
- p->msg.data_length = p->payload.size();
-
- CHECK_LE(p->msg.data_length, s->get_max_payload());
-
- send_packet(p, s->transport);
-}
-
-/* this is used by magic sockets to rig local sockets to
- send the go-ahead message when they connect */
-static void local_socket_ready_notify(asocket* s) {
- s->ready = local_socket_ready;
- s->shutdown = nullptr;
- s->close = local_socket_close;
- SendOkay(s->fd);
- s->ready(s);
-}
-
-/* this is used by magic sockets to rig local sockets to
- send the failure message if they are closed before
- connected (to avoid closing them without a status message) */
-static void local_socket_close_notify(asocket* s) {
- s->ready = local_socket_ready;
- s->shutdown = nullptr;
- s->close = local_socket_close;
- SendFail(s->fd, "closed");
- s->close(s);
-}
-
-static unsigned unhex(const char* s, int len) {
- unsigned n = 0, c;
-
- while (len-- > 0) {
- switch ((c = *s++)) {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- c -= '0';
- break;
- case 'a':
- case 'b':
- case 'c':
- case 'd':
- case 'e':
- case 'f':
- c = c - 'a' + 10;
- break;
- case 'A':
- case 'B':
- case 'C':
- case 'D':
- case 'E':
- case 'F':
- c = c - 'A' + 10;
- break;
- default:
- return 0xffffffff;
- }
-
- n = (n << 4) | c;
- }
-
- return n;
-}
-
-#if ADB_HOST
-
-namespace internal {
-
-// Parses a host service string of the following format:
-// * [tcp:|udp:]<serial>[:<port>]:<command>
-// * <prefix>:<serial>:<command>
-// Where <port> must be a base-10 number and <prefix> may be any of {usb,product,model,device}.
-bool parse_host_service(std::string_view* out_serial, std::string_view* out_command,
- std::string_view full_service) {
- if (full_service.empty()) {
- return false;
- }
-
- std::string_view serial;
- std::string_view command = full_service;
- // Remove |count| bytes from the beginning of command and add them to |serial|.
- auto consume = [&full_service, &serial, &command](size_t count) {
- CHECK_LE(count, command.size());
- if (!serial.empty()) {
- CHECK_EQ(serial.data() + serial.size(), command.data());
- }
-
- serial = full_service.substr(0, serial.size() + count);
- command.remove_prefix(count);
- };
-
- // Remove the trailing : from serial, and assign the values to the output parameters.
- auto finish = [out_serial, out_command, &serial, &command] {
- if (serial.empty() || command.empty()) {
- return false;
- }
-
- CHECK_EQ(':', serial.back());
- serial.remove_suffix(1);
-
- *out_serial = serial;
- *out_command = command;
- return true;
- };
-
- static constexpr std::string_view prefixes[] = {
- "usb:", "product:", "model:", "device:", "localfilesystem:"};
- for (std::string_view prefix : prefixes) {
- if (command.starts_with(prefix)) {
- consume(prefix.size());
-
- size_t offset = command.find_first_of(':');
- if (offset == std::string::npos) {
- return false;
- }
- consume(offset + 1);
- return finish();
- }
- }
-
- // For fastboot compatibility, ignore protocol prefixes.
- if (command.starts_with("tcp:") || command.starts_with("udp:")) {
- consume(4);
- if (command.empty()) {
- return false;
- }
- }
- if (command.starts_with("vsock:")) {
- // vsock serials are vsock:cid:port, which have an extra colon compared to tcp.
- size_t next_colon = command.find(':');
- if (next_colon == std::string::npos) {
- return false;
- }
- consume(next_colon + 1);
- }
-
- bool found_address = false;
- if (command[0] == '[') {
- // Read an IPv6 address. `adb connect` creates the serial number from the canonical
- // network address so it will always have the [] delimiters.
- size_t ipv6_end = command.find_first_of(']');
- if (ipv6_end != std::string::npos) {
- consume(ipv6_end + 1);
- if (command.empty()) {
- // Nothing after the IPv6 address.
- return false;
- } else if (command[0] != ':') {
- // Garbage after the IPv6 address.
- return false;
- }
- consume(1);
- found_address = true;
- }
- }
-
- if (!found_address) {
- // Scan ahead to the next colon.
- size_t offset = command.find_first_of(':');
- if (offset == std::string::npos) {
- return false;
- }
- consume(offset + 1);
- }
-
- // We're either at the beginning of a port, or the command itself.
- // Look for a port in between colons.
- size_t next_colon = command.find_first_of(':');
- if (next_colon == std::string::npos) {
- // No colon, we must be at the command.
- return finish();
- }
-
- bool port_valid = true;
- if (command.size() <= next_colon) {
- return false;
- }
-
- std::string_view port = command.substr(0, next_colon);
- for (auto digit : port) {
- if (!isdigit(digit)) {
- // Port isn't a number.
- port_valid = false;
- break;
- }
- }
-
- if (port_valid) {
- consume(next_colon + 1);
- }
- return finish();
-}
-
-} // namespace internal
-
-#endif // ADB_HOST
-
-static int smart_socket_enqueue(asocket* s, apacket::payload_type data) {
-#if ADB_HOST
- std::string_view service;
- std::string_view serial;
- TransportId transport_id = 0;
- TransportType type = kTransportAny;
-#endif
-
- D("SS(%d): enqueue %zu", s->id, data.size());
-
- if (s->smart_socket_data.empty()) {
- // TODO: Make this an IOVector?
- s->smart_socket_data.assign(data.begin(), data.end());
- } else {
- std::copy(data.begin(), data.end(), std::back_inserter(s->smart_socket_data));
- }
-
- /* don't bother if we can't decode the length */
- if (s->smart_socket_data.size() < 4) {
- return 0;
- }
-
- uint32_t len = unhex(s->smart_socket_data.data(), 4);
- if (len == 0 || len > MAX_PAYLOAD) {
- D("SS(%d): bad size (%u)", s->id, len);
- goto fail;
- }
-
- D("SS(%d): len is %u", s->id, len);
- /* can't do anything until we have the full header */
- if ((len + 4) > s->smart_socket_data.size()) {
- D("SS(%d): waiting for %zu more bytes", s->id, len + 4 - s->smart_socket_data.size());
- return 0;
- }
-
- s->smart_socket_data[len + 4] = 0;
-
- D("SS(%d): '%s'", s->id, (char*)(s->smart_socket_data.data() + 4));
-
-#if ADB_HOST
- service = std::string_view(s->smart_socket_data).substr(4);
-
- // TODO: These should be handled in handle_host_request.
- if (android::base::ConsumePrefix(&service, "host-serial:")) {
- // serial number should follow "host:" and could be a host:port string.
- if (!internal::parse_host_service(&serial, &service, service)) {
- LOG(ERROR) << "SS(" << s->id << "): failed to parse host service: " << service;
- goto fail;
- }
- } else if (android::base::ConsumePrefix(&service, "host-transport-id:")) {
- if (!ParseUint(&transport_id, service, &service)) {
- LOG(ERROR) << "SS(" << s->id << "): failed to parse host transport id: " << service;
- return -1;
- }
- if (!android::base::ConsumePrefix(&service, ":")) {
- LOG(ERROR) << "SS(" << s->id << "): host-transport-id without command";
- return -1;
- }
- } else if (android::base::ConsumePrefix(&service, "host-usb:")) {
- type = kTransportUsb;
- } else if (android::base::ConsumePrefix(&service, "host-local:")) {
- type = kTransportLocal;
- } else if (android::base::ConsumePrefix(&service, "host:")) {
- type = kTransportAny;
- } else {
- service = std::string_view{};
- }
-
- if (!service.empty()) {
- asocket* s2;
-
- // Some requests are handled immediately -- in that case the handle_host_request() routine
- // has sent the OKAY or FAIL message and all we have to do is clean up.
- auto host_request_result = handle_host_request(
- service, type, serial.empty() ? nullptr : std::string(serial).c_str(), transport_id,
- s->peer->fd, s);
-
- switch (host_request_result) {
- case HostRequestResult::Handled:
- LOG(VERBOSE) << "SS(" << s->id << "): handled host service '" << service << "'";
- goto fail;
-
- case HostRequestResult::SwitchedTransport:
- D("SS(%d): okay transport", s->id);
- s->smart_socket_data.clear();
- return 0;
-
- case HostRequestResult::Unhandled:
- break;
- }
-
- /* try to find a local service with this name.
- ** if no such service exists, we'll fail out
- ** and tear down here.
- */
- // TODO: Convert to string_view.
- s2 = host_service_to_socket(service, serial, transport_id);
- if (s2 == nullptr) {
- LOG(VERBOSE) << "SS(" << s->id << "): couldn't create host service '" << service << "'";
- SendFail(s->peer->fd, "unknown host service");
- goto fail;
- }
-
- /* we've connected to a local host service,
- ** so we make our peer back into a regular
- ** local socket and bind it to the new local
- ** service socket, acknowledge the successful
- ** connection, and close this smart socket now
- ** that its work is done.
- */
- SendOkay(s->peer->fd);
-
- s->peer->ready = local_socket_ready;
- s->peer->shutdown = nullptr;
- s->peer->close = local_socket_close;
- s->peer->peer = s2;
- s2->peer = s->peer;
- s->peer = nullptr;
- D("SS(%d): okay", s->id);
- s->close(s);
-
- /* initial state is "ready" */
- s2->ready(s2);
- return 0;
- }
-#else /* !ADB_HOST */
- if (s->transport == nullptr) {
- std::string error_msg = "unknown failure";
- s->transport = acquire_one_transport(kTransportAny, nullptr, 0, nullptr, &error_msg);
- if (s->transport == nullptr) {
- SendFail(s->peer->fd, error_msg);
- goto fail;
- }
- }
-#endif
-
- if (!s->transport) {
- SendFail(s->peer->fd, "device offline (no transport)");
- goto fail;
- } else if (!ConnectionStateIsOnline(s->transport->GetConnectionState())) {
- /* if there's no remote we fail the connection
- ** right here and terminate it
- */
- SendFail(s->peer->fd, "device offline (transport offline)");
- goto fail;
- }
-
- /* instrument our peer to pass the success or fail
- ** message back once it connects or closes, then
- ** detach from it, request the connection, and
- ** tear down
- */
- s->peer->ready = local_socket_ready_notify;
- s->peer->shutdown = nullptr;
- s->peer->close = local_socket_close_notify;
- s->peer->peer = nullptr;
- /* give him our transport and upref it */
- s->peer->transport = s->transport;
-
- connect_to_remote(s->peer, std::string_view(s->smart_socket_data).substr(4));
- s->peer = nullptr;
- s->close(s);
- return 1;
-
-fail:
- /* we're going to close our peer as a side-effect, so
- ** return -1 to signal that state to the local socket
- ** who is enqueueing against us
- */
- s->close(s);
- return -1;
-}
-
-static void smart_socket_ready(asocket* s) {
- D("SS(%d): ready", s->id);
-}
-
-static void smart_socket_close(asocket* s) {
- D("SS(%d): closed", s->id);
- if (s->peer) {
- s->peer->peer = nullptr;
- s->peer->close(s->peer);
- s->peer = nullptr;
- }
- delete s;
-}
-
-static asocket* create_smart_socket(void) {
- D("Creating smart socket");
- asocket* s = new asocket();
- s->enqueue = smart_socket_enqueue;
- s->ready = smart_socket_ready;
- s->shutdown = nullptr;
- s->close = smart_socket_close;
-
- D("SS(%d)", s->id);
- return s;
-}
-
-void connect_to_smartsocket(asocket* s) {
- D("Connecting to smart socket");
- asocket* ss = create_smart_socket();
- s->peer = ss;
- ss->peer = s;
- s->ready(s);
-}
-
-size_t asocket::get_max_payload() const {
- size_t max_payload = MAX_PAYLOAD;
- if (transport) {
- max_payload = std::min(max_payload, transport->get_max_payload());
- }
- if (peer && peer->transport) {
- max_payload = std::min(max_payload, peer->transport->get_max_payload());
- }
- return max_payload;
-}
diff --git a/adb/sockets.dia b/adb/sockets.dia
deleted file mode 100644
index c626f20f0..000000000
--- a/adb/sockets.dia
+++ /dev/null
Binary files differ
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
deleted file mode 100644
index 1eed0d20a..000000000
--- a/adb/sysdeps.h
+++ /dev/null
@@ -1,719 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-/* this file contains system-dependent definitions used by ADB
- * they're related to threads, sockets and file descriptors
- */
-
-#ifdef __CYGWIN__
-# undef _WIN32
-#endif
-
-#include <errno.h>
-
-#include <string>
-#include <string_view>
-#include <vector>
-
-// Include this before open/close/unlink are defined as macros below.
-#include <android-base/errors.h>
-#include <android-base/macros.h>
-#include <android-base/off64_t.h>
-#include <android-base/unique_fd.h>
-#include <android-base/utf8.h>
-
-#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<char*>(memcpy(dst, src, n)) + n;
-}
-#endif
-
-#ifdef _WIN32
-
-// Clang-only nullability specifiers
-#define _Nonnull
-#define _Nullable
-
-#include <ctype.h>
-#include <direct.h>
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <io.h>
-#include <process.h>
-#include <stdint.h>
-#include <sys/stat.h>
-#include <utime.h>
-#include <windows.h>
-#include <winsock2.h>
-#include <ws2tcpip.h>
-
-#include <memory> // unique_ptr
-#include <string>
-
-#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<std::string> args,
- std::initializer_list<int> 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<int>(reinterpret_cast<INT_PTR>(h));
-}
-
-inline HANDLE cast_int_to_handle(const int fd) {
- // sign-extend
- return reinterpret_cast<HANDLE>(static_cast<INT_PTR>(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<HANDLE, handle_deleter> unique_handle;
-
-namespace internal {
-
-size_t ParseCompleteUTF8(const char* first, const char* last, std::vector<char>* remaining_bytes);
-
-}
-
-#else /* !_WIN32 a.k.a. Unix */
-
-#include <fcntl.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <poll.h>
-#include <pthread.h>
-#include <signal.h>
-#include <stdarg.h>
-#include <stdint.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include <string>
-
-#include <cutils/sockets.h>
-
-#define OS_PATH_SEPARATORS "/"
-#define OS_PATH_SEPARATOR '/'
-#define OS_PATH_SEPARATOR_STR "/"
-#define ENV_PATH_SEPARATOR_STR ":"
-
-static inline bool adb_is_separator(char c) {
- return c == '/';
-}
-
-static inline int get_fd_flags(borrowed_fd fd) {
- return fcntl(fd.get(), F_GETFD);
-}
-
-static inline void close_on_exec(borrowed_fd fd) {
- int flags = get_fd_flags(fd);
- if (flags >= 0 && (flags & FD_CLOEXEC) == 0) {
- fcntl(fd.get(), F_SETFD, flags | FD_CLOEXEC);
- }
-}
-
-// Open a file and return a file descriptor that may be used with unix_read(),
-// unix_write(), unix_close(), but not adb_read(), adb_write(), adb_close().
-//
-// On Unix, this is based on open(), so the file descriptor is a real OS file
-// descriptor, but the Windows implementation (in sysdeps_win32.cpp) returns a
-// file descriptor that can only be used with C Runtime APIs (which are wrapped
-// by unix_read(), unix_write(), unix_close()). Also, the C Runtime has
-// configurable CR/LF translation which defaults to text mode, but is settable
-// with _setmode().
-static inline int unix_open(std::string_view path, int options, ...) {
- std::string zero_terminated(path.begin(), path.end());
- if ((options & O_CREAT) == 0) {
- return TEMP_FAILURE_RETRY(open(zero_terminated.c_str(), options));
- } else {
- int mode;
- va_list args;
- va_start(args, options);
- mode = va_arg(args, int);
- va_end(args);
- return TEMP_FAILURE_RETRY(open(zero_terminated.c_str(), options, mode));
- }
-}
-
-// Similar to the two-argument adb_open(), but takes a mode parameter for file
-// creation. See adb_open() for more info.
-static inline int adb_open_mode(const char* pathname, int options, int mode) {
- return TEMP_FAILURE_RETRY(open(pathname, options, mode));
-}
-
-// Open a file and return a file descriptor that may be used with adb_read(),
-// adb_write(), adb_close(), but not unix_read(), unix_write(), unix_close().
-//
-// On Unix, this is based on open(), but the Windows implementation (in
-// sysdeps_win32.cpp) uses Windows native file I/O and bypasses the C Runtime
-// and its CR/LF translation. The returned file descriptor should be used with
-// adb_read(), adb_write(), adb_close(), etc.
-static inline int adb_open(const char* pathname, int options) {
- int fd = TEMP_FAILURE_RETRY(open(pathname, options));
- if (fd < 0) return -1;
- close_on_exec(fd);
- return fd;
-}
-#undef open
-#define open ___xxx_open
-
-static inline int adb_shutdown(borrowed_fd fd, int direction = SHUT_RDWR) {
- return shutdown(fd.get(), direction);
-}
-
-#undef shutdown
-#define shutdown ____xxx_shutdown
-
-// Closes a file descriptor that came from adb_open() or adb_open_mode(), but
-// not designed to take a file descriptor from unix_open(). See the comments
-// for adb_open() for more info.
-inline int adb_close(int fd) {
- return close(fd);
-}
-#undef close
-#define close ____xxx_close
-
-// On Windows, ADB has an indirection layer for file descriptors. If we get a
-// Win32 SOCKET object from an external library, we have to map it in to that
-// indirection layer, which this does.
-inline int adb_register_socket(int s) {
- return s;
-}
-
-static inline int adb_gethostname(char* name, size_t len) {
- return gethostname(name, len);
-}
-
-static inline int adb_getlogin_r(char* buf, size_t bufsize) {
- return getlogin_r(buf, bufsize);
-}
-
-static inline int adb_read(borrowed_fd fd, void* buf, size_t len) {
- return TEMP_FAILURE_RETRY(read(fd.get(), buf, len));
-}
-
-static inline int adb_pread(borrowed_fd fd, void* buf, size_t len, off64_t offset) {
-#if defined(__APPLE__)
- return TEMP_FAILURE_RETRY(pread(fd.get(), buf, len, offset));
-#else
- return TEMP_FAILURE_RETRY(pread64(fd.get(), buf, len, offset));
-#endif
-}
-
-// Like unix_read(), but does not handle EINTR.
-static inline int unix_read_interruptible(borrowed_fd fd, void* buf, size_t len) {
- return read(fd.get(), buf, len);
-}
-
-#undef read
-#define read ___xxx_read
-#undef pread
-#define pread ___xxx_pread
-
-static inline int adb_write(borrowed_fd fd, const void* buf, size_t len) {
- return TEMP_FAILURE_RETRY(write(fd.get(), buf, len));
-}
-
-static inline int adb_pwrite(int fd, const void* buf, size_t len, off64_t offset) {
-#if defined(__APPLE__)
- return TEMP_FAILURE_RETRY(pwrite(fd, buf, len, offset));
-#else
- return TEMP_FAILURE_RETRY(pwrite64(fd, buf, len, offset));
-#endif
-}
-
-#undef write
-#define write ___xxx_write
-#undef pwrite
-#define pwrite ___xxx_pwrite
-
-static inline int64_t adb_lseek(borrowed_fd fd, int64_t pos, int where) {
-#if defined(__APPLE__)
- return lseek(fd.get(), pos, where);
-#else
- return lseek64(fd.get(), pos, where);
-#endif
-}
-#undef lseek
-#define lseek ___xxx_lseek
-
-static inline int adb_unlink(const char* path) {
- return unlink(path);
-}
-#undef unlink
-#define unlink ___xxx_unlink
-
-static inline int adb_creat(const char* path, int mode) {
- int fd = TEMP_FAILURE_RETRY(creat(path, mode));
-
- if (fd < 0) return -1;
-
- close_on_exec(fd);
- return fd;
-}
-#undef creat
-#define creat ___xxx_creat
-
-static inline int unix_isatty(borrowed_fd fd) {
- return isatty(fd.get());
-}
-#define isatty ___xxx_isatty
-
-// Helper for network_* functions.
-inline int _fd_set_error_str(int fd, std::string* error) {
- if (fd == -1) {
- *error = strerror(errno);
- }
- return fd;
-}
-
-inline int network_inaddr_any_server(int port, int type, std::string* error) {
- return _fd_set_error_str(socket_inaddr_any_server(port, type), error);
-}
-
-inline int network_local_client(const char* name, int namespace_id, int type, std::string* error) {
- return _fd_set_error_str(socket_local_client(name, namespace_id, type), error);
-}
-
-inline int network_local_server(const char* name, int namespace_id, int type, std::string* error) {
- return _fd_set_error_str(socket_local_server(name, namespace_id, type), error);
-}
-
-int network_connect(const std::string& host, int port, int type, int timeout, std::string* error);
-
-static inline int adb_socket_accept(borrowed_fd serverfd, struct sockaddr* addr,
- socklen_t* addrlen) {
- int fd;
-
- fd = TEMP_FAILURE_RETRY(accept(serverfd.get(), addr, addrlen));
- if (fd >= 0) close_on_exec(fd);
-
- return fd;
-}
-
-#undef accept
-#define accept ___xxx_accept
-
-inline int adb_socket_get_local_port(borrowed_fd fd) {
- return socket_get_local_port(fd.get());
-}
-
-// Operate on a file descriptor returned from unix_open() or a well-known file
-// descriptor such as STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO.
-//
-// On Unix, unix_read(), unix_write(), unix_close() map to adb_read(),
-// adb_write(), adb_close() (which all map to Unix system calls), but the
-// Windows implementations (in the ifdef above and in sysdeps_win32.cpp) call
-// into the C Runtime and its configurable CR/LF translation (which is settable
-// via _setmode()).
-#define unix_read adb_read
-#define unix_write adb_write
-#define unix_lseek adb_lseek
-#define unix_close adb_close
-
-static inline int adb_thread_setname(const std::string& name) {
-#ifdef __APPLE__
- return pthread_setname_np(name.c_str());
-#else
- // Both bionic and glibc's pthread_setname_np fails rather than truncating long strings.
- // glibc doesn't have strlcpy, so we have to fake it.
- char buf[16]; // MAX_TASK_COMM_LEN, but that's not exported by the kernel headers.
- strncpy(buf, name.c_str(), sizeof(buf) - 1);
- buf[sizeof(buf) - 1] = '\0';
- return pthread_setname_np(pthread_self(), buf);
-#endif
-}
-
-static inline int adb_setsockopt(borrowed_fd fd, int level, int optname, const void* optval,
- socklen_t optlen) {
- return setsockopt(fd.get(), level, optname, optval, optlen);
-}
-
-#undef setsockopt
-#define setsockopt ___xxx_setsockopt
-
-static inline int unix_socketpair(int d, int type, int protocol, int sv[2]) {
- return socketpair(d, type, protocol, sv);
-}
-
-static inline int adb_socketpair(int sv[2]) {
- int rc;
-
- rc = unix_socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
- if (rc < 0) return -1;
-
- close_on_exec(sv[0]);
- close_on_exec(sv[1]);
- return 0;
-}
-
-#undef socketpair
-#define socketpair ___xxx_socketpair
-
-typedef struct pollfd adb_pollfd;
-static inline int adb_poll(adb_pollfd* fds, size_t nfds, int timeout) {
- return TEMP_FAILURE_RETRY(poll(fds, nfds, timeout));
-}
-
-#define poll ___xxx_poll
-
-static inline int adb_mkdir(const std::string& path, int mode) {
- return mkdir(path.c_str(), mode);
-}
-
-#undef mkdir
-#define mkdir ___xxx_mkdir
-
-static inline int adb_rename(const char* oldpath, const char* newpath) {
- return rename(oldpath, newpath);
-}
-
-static inline int adb_is_absolute_host_path(const char* path) {
- return path[0] == '/';
-}
-
-static inline int adb_get_os_handle(borrowed_fd fd) {
- return fd.get();
-}
-
-// A very simple wrapper over a launched child process
-class Process {
- public:
- constexpr explicit Process(pid_t pid) : pid_(pid) {}
- constexpr Process(Process&& other) : pid_(std::exchange(other.pid_, -1)) {}
-
- constexpr explicit operator bool() const { return pid_ >= 0; }
-
- void wait() {
- if (*this) {
- int status;
- ::waitpid(pid_, &status, 0);
- pid_ = -1;
- }
- }
- void kill() {
- if (*this) {
- ::kill(pid_, SIGTERM);
- }
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(Process);
-
- pid_t pid_;
-};
-
-Process adb_launch_process(std::string_view executable, std::vector<std::string> args,
- std::initializer_list<int> 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 5c5af7cd6..000000000
--- 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 <chrono>
-
-using namespace std::chrono_literals;
diff --git a/adb/sysdeps/errno.cpp b/adb/sysdeps/errno.cpp
deleted file mode 100644
index 9a37ea2fd..000000000
--- 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 <errno.h>
-
-#include <thread>
-#include <unordered_map>
-#include <utility>
-
-#include "adb.h"
-
-// Use the linux asm-generic values for errno (which are used on all android archs but mips).
-#define ERRNO_VALUES() \
- ERRNO_VALUE(EACCES, 13); \
- ERRNO_VALUE(EEXIST, 17); \
- ERRNO_VALUE(EFAULT, 14); \
- ERRNO_VALUE(EFBIG, 27); \
- ERRNO_VALUE(EINTR, 4); \
- ERRNO_VALUE(EINVAL, 22); \
- ERRNO_VALUE(EIO, 5); \
- ERRNO_VALUE(EISDIR, 21); \
- ERRNO_VALUE(ELOOP, 40); \
- ERRNO_VALUE(EMFILE, 24); \
- ERRNO_VALUE(ENAMETOOLONG, 36); \
- ERRNO_VALUE(ENFILE, 23); \
- ERRNO_VALUE(ENOENT, 2); \
- ERRNO_VALUE(ENOMEM, 12); \
- ERRNO_VALUE(ENOSPC, 28); \
- ERRNO_VALUE(ENOTDIR, 20); \
- ERRNO_VALUE(EOVERFLOW, 75); \
- ERRNO_VALUE(EPERM, 1); \
- ERRNO_VALUE(EROFS, 30); \
- ERRNO_VALUE(ETXTBSY, 26)
-
-// Make sure these values are actually correct.
-#if defined(__linux__) && !defined(__mips__)
-#define ERRNO_VALUE(error_name, wire_value) static_assert((error_name) == (wire_value), "")
-ERRNO_VALUES();
-#undef ERRNO_VALUE
-#endif
-
-static std::unordered_map<int, int>* generate_host_to_wire() {
- auto result = new std::unordered_map<int, int>();
-#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<int, int>* generate_wire_to_host() {
- auto result = new std::unordered_map<int, int>();
-#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<int, int>& host_to_wire = *generate_host_to_wire();
-static std::unordered_map<int, int>& 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 72816b127..000000000
--- 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 <errno.h>
-#include <string.h>
-
-#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 fadd15598..000000000
--- 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 <string>
-
-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 a4d9013d3..000000000
--- 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 <errno.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <sys/socket.h>
-
-#include <string>
-
-#include <android-base/logging.h>
-#include <android-base/stringprintf.h>
-#include <cutils/sockets.h>
-
-#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<sockaddr_in*>(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<sockaddr*>(addr);
-}
-
-static sockaddr* loopback_addr6(sockaddr_storage* addr, socklen_t* addrlen, int port) {
- struct sockaddr_in6* addr6 = reinterpret_cast<sockaddr_in6*>(addr);
- *addrlen = sizeof(*addr6);
-
- addr6->sin6_family = AF_INET6;
- addr6->sin6_addr = in6addr_loopback;
- addr6->sin6_port = htons(port);
- return reinterpret_cast<sockaddr*>(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 ed2cf25fb..000000000
--- 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 <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#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 67155d992..000000000
--- 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 <string>
-
-#include <android-base/file.h>
-#include <gtest/gtest.h>
-
-#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 ced884ba5..000000000
--- 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 <sys/types.h>
-
-#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 <sys/uio.h>
-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 75c5f44af..000000000
--- a/adb/sysdeps/vm_sockets.h
+++ /dev/null
@@ -1,49 +0,0 @@
-#if __BIONIC__
-#include <linux/vm_sockets.h>
-#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 <linux/socket.h>
-#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 a3b9d9b97..000000000
--- 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 <windows.h>
-
-#include <string>
-
-// 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 09ec52c86..000000000
--- 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 <string>
-
-#include <gtest/gtest.h>
-
-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 844c1ce9a..000000000
--- 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 <errno.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <string>
-
-#include <android-base/utf8.h>
-
-// 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 <sys/stat.h>.
-#if defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS == 64)
-#ifdef _USE_32BIT_TIME_T
-#define wstat _wstat32i64
-#else
-#define wstat _wstat64
-#endif
-#else
-// <sys/stat.h> 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 0f4b39c1f..000000000
--- 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 <gtest/gtest.h>
-#include <unistd.h>
-
-#include <atomic>
-#include <condition_variable>
-#include <thread>
-
-#include "adb_io.h"
-#include "sysdeps.h"
-#include "sysdeps/chrono.h"
-
-#if defined(_WIN32)
-#include <windows.h>
-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<int> 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<int> sockets;
- std::vector<adb_pollfd> 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<ssize_t>(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<std::mutex> 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 e56570676..000000000
--- 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<std::string> args,
- std::initializer_list<int> fds_to_inherit) {
- const auto pid = fork();
- if (pid != 0) {
- // parent, includes the case when failed to fork()
- return Process(pid);
- }
- // child
- std::vector<std::string> 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<char*> 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 be82bc0d1..000000000
--- a/adb/sysdeps_win32.cpp
+++ /dev/null
@@ -1,2981 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define TRACE_TAG SYSDEPS
-
-#include "sysdeps.h"
-
-#include <lmcons.h>
-#include <windows.h>
-#include <winsock2.h> /* winsock.h *must* be included before windows.h. */
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <algorithm>
-#include <memory>
-#include <mutex>
-#include <string>
-#include <string_view>
-#include <unordered_map>
-#include <vector>
-
-#include <cutils/sockets.h>
-
-#include <android-base/errors.h>
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-#include <android-base/utf8.h>
-
-#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<std::mutex> 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<std::mutex> 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<struct FHRec_, fh_deleter> 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<size_t>(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<intptr_t>(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<DWORD>(offset);
- overlapped.OffsetHigh = static_cast<DWORD>(offset >> 32);
- DWORD bytes_read;
- if (!::ReadFile(adb_get_os_handle(fd), buf, static_cast<DWORD>(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<int>(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<DWORD>(offset);
- params.OffsetHigh = static_cast<DWORD>(offset >> 32);
- DWORD bytes_written = 0;
- if (!::WriteFile(adb_get_os_handle(fd), buf, len, &bytes_written, &params)) {
- 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<int>(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<const HANDLE>(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<WSAPOLLFD> sockets;
- std::vector<adb_pollfd*> 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<short>(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<char*>(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<const char*>(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<WSABUF*>(const_cast<adb_iovec*>(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<DWORD>(std::numeric_limits<int>::max()), bytes_written);
- return static_cast<int>(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<struct addrinfo, decltype(&freeaddrinfo)> addrinfo(addrinfo_ptr, freeaddrinfo);
- addrinfo_ptr = nullptr;
-
- // TODO: Try all the addresses if there's more than one? This just uses
- // the first. Or, could call WSAConnectByName() (Windows Vista and newer)
- // which tries all addresses, takes a timeout and more.
- SOCKET s = socket(addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol);
- if (s == INVALID_SOCKET) {
- const DWORD err = WSAGetLastError();
- *error = android::base::StringPrintf("cannot create socket: %s",
- android::base::SystemErrorCodeToString(err).c_str());
- D("%s", error->c_str());
- _socket_set_errno(err);
- return -1;
- }
- f->fh_socket = s;
-
- // TODO: Implement timeouts for Windows. Seems like the default in theory
- // (according to http://serverfault.com/a/671453) and in practice is 21 sec.
- if (connect(s, addrinfo->ai_addr, addrinfo->ai_addrlen) == SOCKET_ERROR) {
- // TODO: Use WSAAddressToString or inet_ntop on address.
- const DWORD err = WSAGetLastError();
- *error = android::base::StringPrintf("cannot connect to %s:%s: %s", host.c_str(), port_str,
- android::base::SystemErrorCodeToString(err).c_str());
- D("could not connect to %s:%s:%s: %s", type != SOCK_STREAM ? "udp" : "tcp", host.c_str(),
- port_str, error->c_str());
- _socket_set_errno(err);
- return -1;
- }
-
- const int fd = _fh_to_int(f.get());
- snprintf(f->name, sizeof(f->name), "%d(net-client:%s%d)", fd, type != SOCK_STREAM ? "udp:" : "",
- port);
- D("host '%s' port %d type %s => fd %d", host.c_str(), port, type != SOCK_STREAM ? "udp" : "tcp",
- fd);
- f.release();
- return fd;
-}
-
-int adb_register_socket(SOCKET s) {
- FH f = _fh_alloc(&_fh_socket_class);
- f->fh_socket = s;
- return _fh_to_int(f);
-}
-
-static bool isBlankStr(const char* str) {
- for (; *str != '\0'; ++str) {
- if (!isblank(*str)) {
- return false;
- }
- }
- return true;
-}
-
-int adb_gethostname(char* name, size_t len) {
- const char* computerName = adb_getenv("COMPUTERNAME");
- if (computerName && !isBlankStr(computerName)) {
- strncpy(name, computerName, len);
- name[len - 1] = '\0';
- return 0;
- }
-
- wchar_t buffer[MAX_COMPUTERNAME_LENGTH + 1];
- DWORD size = sizeof(buffer);
- if (!GetComputerNameW(buffer, &size)) {
- return -1;
- }
- std::string name_utf8;
- if (!android::base::WideToUTF8(buffer, &name_utf8)) {
- return -1;
- }
-
- strncpy(name, name_utf8.c_str(), len);
- name[len - 1] = '\0';
- return 0;
-}
-
-int adb_getlogin_r(char* buf, size_t bufsize) {
- wchar_t buffer[UNLEN + 1];
- DWORD len = sizeof(buffer);
- if (!GetUserNameW(buffer, &len)) {
- return -1;
- }
-
- std::string login;
- if (!android::base::WideToUTF8(buffer, &login)) {
- return -1;
- }
-
- strncpy(buf, login.c_str(), bufsize);
- buf[bufsize - 1] = '\0';
- return 0;
-}
-
-#undef accept
-int adb_socket_accept(borrowed_fd serverfd, struct sockaddr* addr, socklen_t* addrlen) {
- FH serverfh = _fh_from_int(serverfd, __func__);
-
- if (!serverfh || serverfh->clazz != &_fh_socket_class) {
- D("adb_socket_accept: invalid fd %d", serverfd.get());
- errno = EBADF;
- return -1;
- }
-
- unique_fh fh(_fh_alloc(&_fh_socket_class));
- if (!fh) {
- PLOG(ERROR) << "adb_socket_accept: failed to allocate accepted socket "
- "descriptor";
- return -1;
- }
-
- fh->fh_socket = accept(serverfh->fh_socket, addr, addrlen);
- if (fh->fh_socket == INVALID_SOCKET) {
- const DWORD err = WSAGetLastError();
- LOG(ERROR) << "adb_socket_accept: accept on fd " << serverfd.get()
- << " failed: " + android::base::SystemErrorCodeToString(err);
- _socket_set_errno(err);
- return -1;
- }
-
- const int fd = _fh_to_int(fh.get());
- snprintf(fh->name, sizeof(fh->name), "%d(accept:%s)", fd, serverfh->name);
- D("adb_socket_accept on fd %d returns fd %d", serverfd.get(), fd);
- fh.release();
- return fd;
-}
-
-int adb_setsockopt(borrowed_fd fd, int level, int optname, const void* optval, socklen_t optlen) {
- FH fh = _fh_from_int(fd, __func__);
-
- if (!fh || fh->clazz != &_fh_socket_class) {
- D("adb_setsockopt: invalid fd %d", fd.get());
- errno = EBADF;
- return -1;
- }
-
- // TODO: Once we can assume Windows Vista or later, if the caller is trying
- // to set SOL_SOCKET, SO_SNDBUF/SO_RCVBUF, ignore it since the OS has
- // auto-tuning.
-
- int result =
- setsockopt(fh->fh_socket, level, optname, reinterpret_cast<const char*>(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<sockaddr*>(&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<sockaddr_in*>(&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<const HANDLE>(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<char>();
-
-// 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<DIR*>(_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<struct dirent*>(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<struct _utimbuf*>(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<char>* 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<char>();
-
- const int saved_errno = errno;
- std::vector<char> combined_buffer;
-
- // Complete UTF-8 sequences that should be immediately written to the console.
- const char* utf8;
- size_t utf8_size;
-
- {
- std::lock_guard<std::mutex> 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<unsigned char>(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<const char*>(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<std::string, char*>();
-
-// 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<int>(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<char*>(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<HANDLE>(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<HANDLE>(osh);
- ::SetHandleInformation(h, HANDLE_FLAG_INHERIT, 0);
-}
-
-Process adb_launch_process(std::string_view executable, std::vector<std::string> args,
- std::initializer_list<int> 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<SetThreadDescription>(
- ::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 183cd5b59..000000000
--- 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 <gtest/gtest.h>
-
-#include "sysdeps.h"
-
-#include <android-base/file.h>
-
-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<char>& expected_remaining_bytes) {
- std::vector<char> 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<std::vector<char>> 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<std::vector<char>> 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<char> 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<char>(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<char>());
- }
-
- // 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<char> 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<char>());
- }
- }
-}
diff --git a/adb/test_adb.py b/adb/test_adb.py
deleted file mode 100755
index c872fb0f7..000000000
--- a/adb/test_adb.py
+++ /dev/null
@@ -1,587 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-"""Tests for the adb program itself.
-
-This differs from things in test_device.py in that there is no API for these
-things. Most of these tests involve specific error messages or the help text.
-"""
-
-import contextlib
-import os
-import random
-import select
-import socket
-import struct
-import subprocess
-import sys
-import threading
-import time
-import unittest
-import warnings
-
-def find_open_port():
- # Find an open port.
- with socket.socket() as s:
- s.bind(("localhost", 0))
- return s.getsockname()[1]
-
-@contextlib.contextmanager
-def fake_adbd(protocol=socket.AF_INET, port=0):
- """Creates a fake ADB daemon that just replies with a CNXN packet."""
-
- serversock = socket.socket(protocol, socket.SOCK_STREAM)
- serversock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- if protocol == socket.AF_INET:
- serversock.bind(("127.0.0.1", port))
- else:
- serversock.bind(("::1", port))
- serversock.listen(1)
-
- # A pipe that is used to signal the thread that it should terminate.
- readsock, writesock = socket.socketpair()
-
- def _adb_packet(command: bytes, arg0: int, arg1: int, data: bytes) -> bytes:
- bin_command = struct.unpack("I", command)[0]
- buf = struct.pack("IIIIII", bin_command, arg0, arg1, len(data), 0,
- bin_command ^ 0xffffffff)
- buf += data
- return buf
-
- def _handle(sock):
- with contextlib.closing(sock) as serversock:
- rlist = [readsock, serversock]
- cnxn_sent = {}
- while True:
- read_ready, _, _ = select.select(rlist, [], [])
- for ready in read_ready:
- if ready == readsock:
- # Closure pipe
- for f in rlist:
- f.close()
- return
- elif ready == serversock:
- # Server socket
- conn, _ = ready.accept()
- rlist.append(conn)
- else:
- # Client socket
- data = ready.recv(1024)
- if not data or data.startswith(b"OPEN"):
- if ready in cnxn_sent:
- del cnxn_sent[ready]
- ready.shutdown(socket.SHUT_RDWR)
- ready.close()
- rlist.remove(ready)
- continue
- if ready in cnxn_sent:
- continue
- cnxn_sent[ready] = True
- ready.sendall(_adb_packet(b"CNXN", 0x01000001, 1024 * 1024,
- b"device::ro.product.name=fakeadb"))
-
- port = serversock.getsockname()[1]
- server_thread = threading.Thread(target=_handle, args=(serversock,))
- server_thread.start()
-
- try:
- yield port, writesock
- finally:
- writesock.close()
- server_thread.join()
-
-
-@contextlib.contextmanager
-def adb_connect(unittest, serial):
- """Context manager for an ADB connection.
-
- This automatically disconnects when done with the connection.
- """
-
- output = subprocess.check_output(["adb", "connect", serial])
- unittest.assertEqual(output.strip(),
- "connected to {}".format(serial).encode("utf8"))
-
- try:
- yield
- finally:
- # Perform best-effort disconnection. Discard the output.
- subprocess.Popen(["adb", "disconnect", serial],
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE).communicate()
-
-
-@contextlib.contextmanager
-def adb_server():
- """Context manager for an ADB server.
-
- This creates an ADB server and returns the port it's listening on.
- """
-
- port = find_open_port()
- read_pipe, write_pipe = os.pipe()
-
- if sys.platform == "win32":
- import msvcrt
- write_handle = msvcrt.get_osfhandle(write_pipe)
- os.set_handle_inheritable(write_handle, True)
- reply_fd = str(write_handle)
- else:
- os.set_inheritable(write_pipe, True)
- reply_fd = str(write_pipe)
-
- proc = subprocess.Popen(["adb", "-L", "tcp:localhost:{}".format(port),
- "fork-server", "server",
- "--reply-fd", reply_fd], close_fds=False)
- try:
- os.close(write_pipe)
- greeting = os.read(read_pipe, 1024)
- assert greeting == b"OK\n", repr(greeting)
- yield port
- finally:
- proc.terminate()
- proc.wait()
-
-
-class CommandlineTest(unittest.TestCase):
- """Tests for the ADB commandline."""
-
- def test_help(self):
- """Make sure we get _something_ out of help."""
- out = subprocess.check_output(
- ["adb", "help"], stderr=subprocess.STDOUT)
- self.assertGreater(len(out), 0)
-
- def test_version(self):
- """Get a version number out of the output of adb."""
- lines = subprocess.check_output(["adb", "version"]).splitlines()
- version_line = lines[0]
- self.assertRegex(
- version_line, rb"^Android Debug Bridge version \d+\.\d+\.\d+$")
- if len(lines) == 2:
- # Newer versions of ADB have a second line of output for the
- # version that includes a specific revision (git SHA).
- revision_line = lines[1]
- self.assertRegex(
- revision_line, rb"^Revision [0-9a-f]{12}-android$")
-
- def test_tcpip_error_messages(self):
- """Make sure 'adb tcpip' parsing is sane."""
- proc = subprocess.Popen(["adb", "tcpip"],
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT)
- out, _ = proc.communicate()
- self.assertEqual(1, proc.returncode)
- self.assertIn(b"requires an argument", out)
-
- proc = subprocess.Popen(["adb", "tcpip", "foo"],
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT)
- out, _ = proc.communicate()
- self.assertEqual(1, proc.returncode)
- self.assertIn(b"invalid port", out)
-
-
-class ServerTest(unittest.TestCase):
- """Tests for the ADB server."""
-
- @staticmethod
- def _read_pipe_and_set_event(pipe, event):
- """Reads a pipe until it is closed, then sets the event."""
- pipe.read()
- event.set()
-
- def test_handle_inheritance(self):
- """Test that launch_server() does not inherit handles.
-
- launch_server() should not let the adb server inherit
- stdin/stdout/stderr handles, which can cause callers of adb.exe to hang.
- This test also runs fine on unix even though the impetus is an issue
- unique to Windows.
- """
- # This test takes 5 seconds to run on Windows: if there is no adb server
- # running on the the port used below, adb kill-server tries to make a
- # TCP connection to a closed port and that takes 1 second on Windows;
- # adb start-server does the same TCP connection which takes another
- # second, and it waits 3 seconds after starting the server.
-
- # Start adb client with redirected stdin/stdout/stderr to check if it
- # passes those redirections to the adb server that it starts. To do
- # this, run an instance of the adb server on a non-default port so we
- # don't conflict with a pre-existing adb server that may already be
- # setup with adb TCP/emulator connections. If there is a pre-existing
- # adb server, this also tests whether multiple instances of the adb
- # server conflict on adb.log.
-
- port = find_open_port()
-
- try:
- # We get warnings for unclosed files for the subprocess's pipes,
- # and it's somewhat cumbersome to close them, so just ignore this.
- warnings.simplefilter("ignore", ResourceWarning)
-
- # Run the adb client and have it start the adb server.
- proc = subprocess.Popen(["adb", "-P", str(port), "start-server"],
- stdin=subprocess.PIPE,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
-
- # Start threads that set events when stdout/stderr are closed.
- stdout_event = threading.Event()
- stdout_thread = threading.Thread(
- target=ServerTest._read_pipe_and_set_event,
- args=(proc.stdout, stdout_event))
- stdout_thread.start()
-
- stderr_event = threading.Event()
- stderr_thread = threading.Thread(
- target=ServerTest._read_pipe_and_set_event,
- args=(proc.stderr, stderr_event))
- stderr_thread.start()
-
- # Wait for the adb client to finish. Once that has occurred, if
- # stdin/stderr/stdout are still open, it must be open in the adb
- # server.
- proc.wait()
-
- # Try to write to stdin which we expect is closed. If it isn't
- # closed, we should get an IOError. If we don't get an IOError,
- # stdin must still be open in the adb server. The adb client is
- # probably letting the adb server inherit stdin which would be
- # wrong.
- with self.assertRaises(IOError):
- proc.stdin.write(b"x")
- proc.stdin.flush()
-
- # Wait a few seconds for stdout/stderr to be closed (in the success
- # case, this won't wait at all). If there is a timeout, that means
- # stdout/stderr were not closed and and they must be open in the adb
- # server, suggesting that the adb client is letting the adb server
- # inherit stdout/stderr which would be wrong.
- self.assertTrue(stdout_event.wait(5), "adb stdout not closed")
- self.assertTrue(stderr_event.wait(5), "adb stderr not closed")
- stdout_thread.join()
- stderr_thread.join()
- finally:
- # If we started a server, kill it.
- subprocess.check_output(["adb", "-P", str(port), "kill-server"],
- stderr=subprocess.STDOUT)
-
- @unittest.skipUnless(
- os.name == "posix",
- "adb doesn't yet support IPv6 on Windows",
- )
- def test_starts_on_ipv6_localhost(self):
- """
- Tests that the server can start up on ::1 and that it's accessible
- """
-
- server_port = find_open_port()
- try:
- subprocess.check_output(
- ["adb", "-L", "tcp:[::1]:{}".format(server_port), "server"],
- stderr=subprocess.STDOUT,
- )
- with fake_adbd() as (port, _):
- with adb_connect(self, serial="localhost:{}".format(port)):
- pass
- finally:
- # If we started a server, kill it.
- subprocess.check_output(
- ["adb", "-P", str(server_port), "kill-server"],
- stderr=subprocess.STDOUT,
- )
-
-
-
-
-class EmulatorTest(unittest.TestCase):
- """Tests for the emulator connection."""
-
- def _reset_socket_on_close(self, sock):
- """Use SO_LINGER to cause TCP RST segment to be sent on socket close."""
- # The linger structure is two shorts on Windows, but two ints on Unix.
- linger_format = "hh" if os.name == "nt" else "ii"
- l_onoff = 1
- l_linger = 0
-
- sock.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER,
- struct.pack(linger_format, l_onoff, l_linger))
- # Verify that we set the linger structure properly by retrieving it.
- linger = sock.getsockopt(socket.SOL_SOCKET, socket.SO_LINGER, 16)
- self.assertEqual((l_onoff, l_linger),
- struct.unpack_from(linger_format, linger))
-
- def test_emu_kill(self):
- """Ensure that adb emu kill works.
-
- Bug: https://code.google.com/p/android/issues/detail?id=21021
- """
- with contextlib.closing(
- socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as listener:
- # Use SO_REUSEADDR so subsequent runs of the test can grab the port
- # even if it is in TIME_WAIT.
- listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- listener.bind(("127.0.0.1", 0))
- listener.listen(4)
- port = listener.getsockname()[1]
-
- # Now that listening has started, start adb emu kill, telling it to
- # connect to our mock emulator.
- proc = subprocess.Popen(
- ["adb", "-s", "emulator-" + str(port), "emu", "kill"],
- stderr=subprocess.STDOUT)
-
- accepted_connection, addr = listener.accept()
- with contextlib.closing(accepted_connection) as conn:
- # If WSAECONNABORTED (10053) is raised by any socket calls,
- # then adb probably isn't reading the data that we sent it.
- conn.sendall(("Android Console: type 'help' for a list "
- "of commands\r\n").encode("utf8"))
- conn.sendall(b"OK\r\n")
-
- with contextlib.closing(conn.makefile()) as connf:
- line = connf.readline()
- if line.startswith("auth"):
- # Ignore the first auth line.
- line = connf.readline()
- self.assertEqual("kill\n", line)
- self.assertEqual("quit\n", connf.readline())
-
- conn.sendall(b"OK: killing emulator, bye bye\r\n")
-
- # Use SO_LINGER to send TCP RST segment to test whether adb
- # ignores WSAECONNRESET on Windows. This happens with the
- # real emulator because it just calls exit() without closing
- # the socket or calling shutdown(SD_SEND). At process
- # termination, Windows sends a TCP RST segment for every
- # open socket that shutdown(SD_SEND) wasn't used on.
- self._reset_socket_on_close(conn)
-
- # Wait for adb to finish, so we can check return code.
- proc.communicate()
-
- # If this fails, adb probably isn't ignoring WSAECONNRESET when
- # reading the response from the adb emu kill command (on Windows).
- self.assertEqual(0, proc.returncode)
-
- def test_emulator_connect(self):
- """Ensure that the emulator can connect.
-
- Bug: http://b/78991667
- """
- with adb_server() as server_port:
- with fake_adbd() as (port, _):
- serial = "emulator-{}".format(port - 1)
- # Ensure that the emulator is not there.
- try:
- subprocess.check_output(["adb", "-P", str(server_port),
- "-s", serial, "get-state"],
- stderr=subprocess.STDOUT)
- self.fail("Device should not be available")
- except subprocess.CalledProcessError as err:
- self.assertEqual(
- err.output.strip(),
- "error: device '{}' not found".format(serial).encode("utf8"))
-
- # Let the ADB server know that the emulator has started.
- with contextlib.closing(
- socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock:
- sock.connect(("localhost", server_port))
- command = "host:emulator:{}".format(port).encode("utf8")
- sock.sendall(b"%04x%s" % (len(command), command))
-
- # Ensure the emulator is there.
- subprocess.check_call(["adb", "-P", str(server_port),
- "-s", serial, "wait-for-device"])
- output = subprocess.check_output(["adb", "-P", str(server_port),
- "-s", serial, "get-state"])
- self.assertEqual(output.strip(), b"device")
-
-
-class ConnectionTest(unittest.TestCase):
- """Tests for adb connect."""
-
- def test_connect_ipv4_ipv6(self):
- """Ensure that `adb connect localhost:1234` will try both IPv4 and IPv6.
-
- Bug: http://b/30313466
- """
- for protocol in (socket.AF_INET, socket.AF_INET6):
- try:
- with fake_adbd(protocol=protocol) as (port, _):
- serial = "localhost:{}".format(port)
- with adb_connect(self, serial):
- pass
- except socket.error:
- print("IPv6 not available, skipping")
- continue
-
- def test_already_connected(self):
- """Ensure that an already-connected device stays connected."""
-
- with fake_adbd() as (port, _):
- serial = "localhost:{}".format(port)
- with adb_connect(self, serial):
- # b/31250450: this always returns 0 but probably shouldn't.
- output = subprocess.check_output(["adb", "connect", serial])
- self.assertEqual(
- output.strip(),
- "already connected to {}".format(serial).encode("utf8"))
-
- @unittest.skip("Currently failing b/123247844")
- def test_reconnect(self):
- """Ensure that a disconnected device reconnects."""
-
- with fake_adbd() as (port, _):
- serial = "localhost:{}".format(port)
- with adb_connect(self, serial):
- # Wait a bit to give adb some time to connect.
- time.sleep(0.25)
-
- output = subprocess.check_output(["adb", "-s", serial,
- "get-state"])
- self.assertEqual(output.strip(), b"device")
-
- # This will fail.
- proc = subprocess.Popen(["adb", "-s", serial, "shell", "true"],
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT)
- output, _ = proc.communicate()
- self.assertEqual(output.strip(), b"error: closed")
-
- subprocess.check_call(["adb", "-s", serial, "wait-for-device"])
-
- output = subprocess.check_output(["adb", "-s", serial,
- "get-state"])
- self.assertEqual(output.strip(), b"device")
-
- # Once we explicitly kick a device, it won't attempt to
- # reconnect.
- output = subprocess.check_output(["adb", "disconnect", serial])
- self.assertEqual(
- output.strip(),
- "disconnected {}".format(serial).encode("utf8"))
- try:
- subprocess.check_output(["adb", "-s", serial, "get-state"],
- stderr=subprocess.STDOUT)
- self.fail("Device should not be available")
- except subprocess.CalledProcessError as err:
- self.assertEqual(
- err.output.strip(),
- "error: device '{}' not found".format(serial).encode("utf8"))
-
-
-class DisconnectionTest(unittest.TestCase):
- """Tests for adb disconnect."""
-
- def test_disconnect(self):
- """Ensure that `adb disconnect` takes effect immediately."""
-
- def _devices(port):
- output = subprocess.check_output(["adb", "-P", str(port), "devices"])
- return [x.split("\t") for x in output.decode("utf8").strip().splitlines()[1:]]
-
- with adb_server() as server_port:
- with fake_adbd() as (port, sock):
- device_name = "localhost:{}".format(port)
- output = subprocess.check_output(["adb", "-P", str(server_port),
- "connect", device_name])
- self.assertEqual(output.strip(),
- "connected to {}".format(device_name).encode("utf8"))
-
-
- self.assertEqual(_devices(server_port), [[device_name, "device"]])
-
- # Send a deliberately malformed packet to make the device go offline.
- packet = struct.pack("IIIIII", 0, 0, 0, 0, 0, 0)
- sock.sendall(packet)
-
- # Wait a bit.
- time.sleep(0.1)
-
- self.assertEqual(_devices(server_port), [[device_name, "offline"]])
-
- # Disconnect the device.
- output = subprocess.check_output(["adb", "-P", str(server_port),
- "disconnect", device_name])
-
- # Wait a bit.
- time.sleep(0.1)
-
- self.assertEqual(_devices(server_port), [])
-
-
-@unittest.skipUnless(sys.platform == "win32", "requires Windows")
-class PowerTest(unittest.TestCase):
- def test_resume_usb_kick(self):
- """Resuming from sleep/hibernate should kick USB devices."""
- try:
- usb_serial = subprocess.check_output(["adb", "-d", "get-serialno"]).strip()
- except subprocess.CalledProcessError:
- # If there are multiple USB devices, we don't have a way to check whether the selected
- # device is USB.
- raise unittest.SkipTest('requires single USB device')
-
- try:
- serial = subprocess.check_output(["adb", "get-serialno"]).strip()
- except subprocess.CalledProcessError:
- # Did you forget to select a device with $ANDROID_SERIAL?
- raise unittest.SkipTest('requires $ANDROID_SERIAL set to a USB device')
-
- # Test only works with USB devices because adb _power_notification_thread does not kick
- # non-USB devices on resume event.
- if serial != usb_serial:
- raise unittest.SkipTest('requires USB device')
-
- # Run an adb shell command in the background that takes a while to complete.
- proc = subprocess.Popen(['adb', 'shell', 'sleep', '5'])
-
- # Wait for startup of adb server's _power_notification_thread.
- time.sleep(0.1)
-
- # Simulate resuming from sleep/hibernation by sending Windows message.
- import ctypes
- from ctypes import wintypes
- HWND_BROADCAST = 0xffff
- WM_POWERBROADCAST = 0x218
- PBT_APMRESUMEAUTOMATIC = 0x12
-
- PostMessageW = ctypes.windll.user32.PostMessageW
- PostMessageW.restype = wintypes.BOOL
- PostMessageW.argtypes = (wintypes.HWND, wintypes.UINT, wintypes.WPARAM, wintypes.LPARAM)
- result = PostMessageW(HWND_BROADCAST, WM_POWERBROADCAST, PBT_APMRESUMEAUTOMATIC, 0)
- if not result:
- raise ctypes.WinError()
-
- # Wait for connection to adb shell to be broken by _power_notification_thread detecting the
- # Windows message.
- start = time.time()
- proc.wait()
- end = time.time()
-
- # If the power event was detected, the adb shell command should be broken very quickly.
- self.assertLess(end - start, 2)
-
-
-def main():
- """Main entrypoint."""
- random.seed(0)
- unittest.main(verbosity=3)
-
-
-if __name__ == "__main__":
- main()
diff --git a/adb/test_device.py b/adb/test_device.py
deleted file mode 100755
index 6a9ff89ef..000000000
--- a/adb/test_device.py
+++ /dev/null
@@ -1,1678 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-#
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-from __future__ import print_function
-
-import contextlib
-import hashlib
-import os
-import posixpath
-import random
-import re
-import shlex
-import shutil
-import signal
-import socket
-import string
-import subprocess
-import sys
-import tempfile
-import threading
-import time
-import unittest
-
-from datetime import datetime
-
-import adb
-
-def requires_root(func):
- def wrapper(self, *args):
- if self.device.get_prop('ro.debuggable') != '1':
- raise unittest.SkipTest('requires rootable build')
-
- was_root = self.device.shell(['id', '-un'])[0].strip() == 'root'
- if not was_root:
- self.device.root()
- self.device.wait()
-
- try:
- func(self, *args)
- finally:
- if not was_root:
- self.device.unroot()
- self.device.wait()
-
- return wrapper
-
-
-def requires_non_root(func):
- def wrapper(self, *args):
- was_root = self.device.shell(['id', '-un'])[0].strip() == 'root'
- if was_root:
- self.device.unroot()
- self.device.wait()
-
- try:
- func(self, *args)
- finally:
- if was_root:
- self.device.root()
- self.device.wait()
-
- return wrapper
-
-
-class DeviceTest(unittest.TestCase):
- def setUp(self):
- self.device = adb.get_device()
-
-
-class AbbTest(DeviceTest):
- def test_smoke(self):
- result = subprocess.run(['adb', 'abb'], capture_output=True)
- self.assertEqual(1, result.returncode)
- expected_output = b"cmd: No service specified; use -l to list all services\n"
- self.assertEqual(expected_output, result.stderr)
-
-class ForwardReverseTest(DeviceTest):
- def _test_no_rebind(self, description, direction_list, direction,
- direction_no_rebind, direction_remove_all):
- msg = direction_list()
- self.assertEqual('', msg.strip(),
- description + ' list must be empty to run this test.')
-
- # Use --no-rebind with no existing binding
- direction_no_rebind('tcp:5566', 'tcp:6655')
- msg = direction_list()
- self.assertTrue(re.search(r'tcp:5566.+tcp:6655', msg))
-
- # Use --no-rebind with existing binding
- with self.assertRaises(subprocess.CalledProcessError):
- direction_no_rebind('tcp:5566', 'tcp:6677')
- msg = direction_list()
- self.assertFalse(re.search(r'tcp:5566.+tcp:6677', msg))
- self.assertTrue(re.search(r'tcp:5566.+tcp:6655', msg))
-
- # Use the absence of --no-rebind with existing binding
- direction('tcp:5566', 'tcp:6677')
- msg = direction_list()
- self.assertFalse(re.search(r'tcp:5566.+tcp:6655', msg))
- self.assertTrue(re.search(r'tcp:5566.+tcp:6677', msg))
-
- direction_remove_all()
- msg = direction_list()
- self.assertEqual('', msg.strip())
-
- def test_forward_no_rebind(self):
- self._test_no_rebind('forward', self.device.forward_list,
- self.device.forward, self.device.forward_no_rebind,
- self.device.forward_remove_all)
-
- def test_reverse_no_rebind(self):
- self._test_no_rebind('reverse', self.device.reverse_list,
- self.device.reverse, self.device.reverse_no_rebind,
- self.device.reverse_remove_all)
-
- def test_forward(self):
- msg = self.device.forward_list()
- self.assertEqual('', msg.strip(),
- 'Forwarding list must be empty to run this test.')
- self.device.forward('tcp:5566', 'tcp:6655')
- msg = self.device.forward_list()
- self.assertTrue(re.search(r'tcp:5566.+tcp:6655', msg))
- self.device.forward('tcp:7788', 'tcp:8877')
- msg = self.device.forward_list()
- self.assertTrue(re.search(r'tcp:5566.+tcp:6655', msg))
- self.assertTrue(re.search(r'tcp:7788.+tcp:8877', msg))
- self.device.forward_remove('tcp:5566')
- msg = self.device.forward_list()
- self.assertFalse(re.search(r'tcp:5566.+tcp:6655', msg))
- self.assertTrue(re.search(r'tcp:7788.+tcp:8877', msg))
- self.device.forward_remove_all()
- msg = self.device.forward_list()
- self.assertEqual('', msg.strip())
-
- def test_forward_old_protocol(self):
- serialno = subprocess.check_output(self.device.adb_cmd + ['get-serialno']).strip()
-
- msg = self.device.forward_list()
- self.assertEqual('', msg.strip(),
- 'Forwarding list must be empty to run this test.')
-
- s = socket.create_connection(("localhost", 5037))
- service = b"host-serial:%s:forward:tcp:5566;tcp:6655" % serialno
- cmd = b"%04x%s" % (len(service), service)
- s.sendall(cmd)
-
- msg = self.device.forward_list()
- self.assertTrue(re.search(r'tcp:5566.+tcp:6655', msg))
-
- self.device.forward_remove_all()
- msg = self.device.forward_list()
- self.assertEqual('', msg.strip())
-
- def test_forward_tcp_port_0(self):
- self.assertEqual('', self.device.forward_list().strip(),
- 'Forwarding list must be empty to run this test.')
-
- try:
- # If resolving TCP port 0 is supported, `adb forward` will print
- # the actual port number.
- port = self.device.forward('tcp:0', 'tcp:8888').strip()
- if not port:
- raise unittest.SkipTest('Forwarding tcp:0 is not available.')
-
- self.assertTrue(re.search(r'tcp:{}.+tcp:8888'.format(port),
- self.device.forward_list()))
- finally:
- self.device.forward_remove_all()
-
- def test_reverse(self):
- msg = self.device.reverse_list()
- self.assertEqual('', msg.strip(),
- 'Reverse forwarding list must be empty to run this test.')
- self.device.reverse('tcp:5566', 'tcp:6655')
- msg = self.device.reverse_list()
- self.assertTrue(re.search(r'tcp:5566.+tcp:6655', msg))
- self.device.reverse('tcp:7788', 'tcp:8877')
- msg = self.device.reverse_list()
- self.assertTrue(re.search(r'tcp:5566.+tcp:6655', msg))
- self.assertTrue(re.search(r'tcp:7788.+tcp:8877', msg))
- self.device.reverse_remove('tcp:5566')
- msg = self.device.reverse_list()
- self.assertFalse(re.search(r'tcp:5566.+tcp:6655', msg))
- self.assertTrue(re.search(r'tcp:7788.+tcp:8877', msg))
- self.device.reverse_remove_all()
- msg = self.device.reverse_list()
- self.assertEqual('', msg.strip())
-
- def test_reverse_tcp_port_0(self):
- self.assertEqual('', self.device.reverse_list().strip(),
- 'Reverse list must be empty to run this test.')
-
- try:
- # If resolving TCP port 0 is supported, `adb reverse` will print
- # the actual port number.
- port = self.device.reverse('tcp:0', 'tcp:8888').strip()
- if not port:
- raise unittest.SkipTest('Reversing tcp:0 is not available.')
-
- self.assertTrue(re.search(r'tcp:{}.+tcp:8888'.format(port),
- self.device.reverse_list()))
- finally:
- self.device.reverse_remove_all()
-
- def test_forward_reverse_echo(self):
- """Send data through adb forward and read it back via adb reverse"""
- forward_port = 12345
- reverse_port = forward_port + 1
- forward_spec = 'tcp:' + str(forward_port)
- reverse_spec = 'tcp:' + str(reverse_port)
- forward_setup = False
- reverse_setup = False
-
- try:
- # listen on localhost:forward_port, connect to remote:forward_port
- self.device.forward(forward_spec, forward_spec)
- forward_setup = True
- # listen on remote:forward_port, connect to localhost:reverse_port
- self.device.reverse(forward_spec, reverse_spec)
- reverse_setup = True
-
- listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- with contextlib.closing(listener):
- # Use SO_REUSEADDR so that subsequent runs of the test can grab
- # the port even if it is in TIME_WAIT.
- listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
-
- # Listen on localhost:reverse_port before connecting to
- # localhost:forward_port because that will cause adb to connect
- # back to localhost:reverse_port.
- listener.bind(('127.0.0.1', reverse_port))
- listener.listen(4)
-
- client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- with contextlib.closing(client):
- # Connect to the listener.
- client.connect(('127.0.0.1', forward_port))
-
- # Accept the client connection.
- accepted_connection, addr = listener.accept()
- with contextlib.closing(accepted_connection) as server:
- data = b'hello'
-
- # Send data into the port setup by adb forward.
- client.sendall(data)
- # Explicitly close() so that server gets EOF.
- client.close()
-
- # Verify that the data came back via adb reverse.
- self.assertEqual(data, server.makefile().read().encode("utf8"))
- finally:
- if reverse_setup:
- self.device.reverse_remove(forward_spec)
- if forward_setup:
- self.device.forward_remove(forward_spec)
-
-
-class ShellTest(DeviceTest):
- def _interactive_shell(self, shell_args, input):
- """Runs an interactive adb shell.
-
- Args:
- shell_args: List of string arguments to `adb shell`.
- input: bytes input to send to the interactive shell.
-
- Returns:
- The remote exit code.
-
- Raises:
- unittest.SkipTest: The device doesn't support exit codes.
- """
- if not self.device.has_shell_protocol():
- raise unittest.SkipTest('exit codes are unavailable on this device')
-
- proc = subprocess.Popen(
- self.device.adb_cmd + ['shell'] + shell_args,
- stdin=subprocess.PIPE, stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- # Closing host-side stdin doesn't trigger a PTY shell to exit so we need
- # to explicitly add an exit command to close the session from the device
- # side, plus the necessary newline to complete the interactive command.
- proc.communicate(input + b'; exit\n')
- return proc.returncode
-
- def test_cat(self):
- """Check that we can at least cat a file."""
- out = self.device.shell(['cat', '/proc/uptime'])[0].strip()
- elements = out.split()
- self.assertEqual(len(elements), 2)
-
- uptime, idle = elements
- self.assertGreater(float(uptime), 0.0)
- self.assertGreater(float(idle), 0.0)
-
- def test_throws_on_failure(self):
- self.assertRaises(adb.ShellError, self.device.shell, ['false'])
-
- def test_output_not_stripped(self):
- out = self.device.shell(['echo', 'foo'])[0]
- self.assertEqual(out, 'foo' + self.device.linesep)
-
- def test_shell_command_length(self):
- # Devices that have shell_v2 should be able to handle long commands.
- if self.device.has_shell_protocol():
- rc, out, err = self.device.shell_nocheck(['echo', 'x' * 16384])
- self.assertEqual(rc, 0)
- self.assertTrue(out == ('x' * 16384 + '\n'))
-
- def test_shell_nocheck_failure(self):
- rc, out, _ = self.device.shell_nocheck(['false'])
- self.assertNotEqual(rc, 0)
- self.assertEqual(out, '')
-
- def test_shell_nocheck_output_not_stripped(self):
- rc, out, _ = self.device.shell_nocheck(['echo', 'foo'])
- self.assertEqual(rc, 0)
- self.assertEqual(out, 'foo' + self.device.linesep)
-
- def test_can_distinguish_tricky_results(self):
- # If result checking on ADB shell is naively implemented as
- # `adb shell <cmd>; 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 (<terminal>, <non-terminal>). True indicates
- the corresponding shell allocated a remote PTY.
- """
- test_cmd = self.device.adb_cmd + ['shell'] + args + ['[ -t 0 ]']
-
- terminal = subprocess.Popen(
- test_cmd, stdin=None,
- stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- terminal.communicate()
-
- non_terminal = subprocess.Popen(
- test_cmd, stdin=subprocess.PIPE,
- stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- non_terminal.communicate()
-
- return (terminal.returncode == 0, non_terminal.returncode == 0)
-
- # -T: never allocate PTY.
- self.assertEqual((False, False), check_pty(['-T']))
-
- # These tests require a new device.
- if self.device.has_shell_protocol() and os.isatty(sys.stdin.fileno()):
- # No args: PTY only if stdin is a terminal and shell is interactive,
- # which is difficult to reliably test from a script.
- self.assertEqual((False, False), check_pty([]))
-
- # -t: PTY if stdin is a terminal.
- self.assertEqual((True, False), check_pty(['-t']))
-
- # -t -t: always allocate PTY.
- self.assertEqual((True, True), check_pty(['-t', '-t']))
-
- # -tt: always allocate PTY, POSIX style (http://b/32216152).
- self.assertEqual((True, True), check_pty(['-tt']))
-
- # -ttt: ssh has weird even/odd behavior with multiple -t flags, but
- # we follow the man page instead.
- self.assertEqual((True, True), check_pty(['-ttt']))
-
- # -ttx: -x and -tt aren't incompatible (though -Tx would be an error).
- self.assertEqual((True, True), check_pty(['-ttx']))
-
- # -Ttt: -tt cancels out -T.
- self.assertEqual((True, True), check_pty(['-Ttt']))
-
- # -ttT: -T cancels out -tt.
- self.assertEqual((False, False), check_pty(['-ttT']))
-
- def test_shell_protocol(self):
- """Tests the shell protocol on the device.
-
- If the device supports shell protocol, this gives us the ability
- to separate stdout/stderr and return the exit code directly.
-
- Bug: http://b/19734861
- """
- if not self.device.has_shell_protocol():
- raise unittest.SkipTest('shell protocol unsupported on this device')
-
- # Shell protocol should be used by default.
- result = self.device.shell_nocheck(
- shlex.split('echo foo; echo bar >&2; exit 17'))
- self.assertEqual(17, result[0])
- self.assertEqual('foo' + self.device.linesep, result[1])
- self.assertEqual('bar' + self.device.linesep, result[2])
-
- self.assertEqual(17, self._interactive_shell([], b'exit 17'))
-
- # -x flag should disable shell protocol.
- result = self.device.shell_nocheck(
- shlex.split('-x echo foo; echo bar >&2; exit 17'))
- self.assertEqual(0, result[0])
- self.assertEqual('foo{0}bar{0}'.format(self.device.linesep), result[1])
- self.assertEqual('', result[2])
-
- self.assertEqual(0, self._interactive_shell(['-x'], b'exit 17'))
-
- def test_non_interactive_sigint(self):
- """Tests that SIGINT in a non-interactive shell kills the process.
-
- This requires the shell protocol in order to detect the broken
- pipe; raw data transfer mode will only see the break once the
- subprocess tries to read or write.
-
- Bug: http://b/23825725
- """
- if not self.device.has_shell_protocol():
- raise unittest.SkipTest('shell protocol unsupported on this device')
-
- # Start a long-running process.
- sleep_proc = subprocess.Popen(
- self.device.adb_cmd + shlex.split('shell echo $$; sleep 60'),
- stdin=subprocess.PIPE, stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT)
- remote_pid = sleep_proc.stdout.readline().strip().decode("utf8")
- self.assertIsNone(sleep_proc.returncode, 'subprocess terminated early')
- proc_query = shlex.split('ps {0} | grep {0}'.format(remote_pid))
-
- # Verify that the process is running, send signal, verify it stopped.
- self.device.shell(proc_query)
- os.kill(sleep_proc.pid, signal.SIGINT)
- sleep_proc.communicate()
-
- # It can take some time for the process to receive the signal and die.
- end_time = time.time() + 3
- while self.device.shell_nocheck(proc_query)[0] != 1:
- self.assertFalse(time.time() > end_time,
- 'subprocess failed to terminate in time')
-
- def test_non_interactive_stdin(self):
- """Tests that non-interactive shells send stdin."""
- if not self.device.has_shell_protocol():
- raise unittest.SkipTest('non-interactive stdin unsupported '
- 'on this device')
-
- # Test both small and large inputs.
- small_input = b'foo'
- characters = [c.encode("utf8") for c in string.ascii_letters + string.digits]
- large_input = b'\n'.join(characters)
-
-
- for input in (small_input, large_input):
- proc = subprocess.Popen(self.device.adb_cmd + ['shell', 'cat'],
- stdin=subprocess.PIPE,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- stdout, stderr = proc.communicate(input)
- self.assertEqual(input.splitlines(), stdout.splitlines())
- self.assertEqual(b'', stderr)
-
- def test_sighup(self):
- """Ensure that SIGHUP gets sent upon non-interactive ctrl-c"""
- log_path = "/data/local/tmp/adb_signal_test.log"
-
- # Clear the output file.
- self.device.shell_nocheck(["echo", ">", log_path])
-
- script = """
- trap "echo SIGINT > {path}; exit 0" SIGINT
- trap "echo SIGHUP > {path}; exit 0" SIGHUP
- echo Waiting
- read
- """.format(path=log_path)
-
- script = ";".join([x.strip() for x in script.strip().splitlines()])
-
- process = self.device.shell_popen([script], kill_atexit=False,
- stdin=subprocess.PIPE,
- stdout=subprocess.PIPE)
-
- self.assertEqual(b"Waiting\n", process.stdout.readline())
- process.send_signal(signal.SIGINT)
- process.wait()
-
- # Waiting for the local adb to finish is insufficient, since it hangs
- # up immediately.
- time.sleep(1)
-
- stdout, _ = self.device.shell(["cat", log_path])
- self.assertEqual(stdout.strip(), "SIGHUP")
-
- def test_exit_stress(self):
- """Hammer `adb shell exit 42` with multiple threads."""
- thread_count = 48
- result = dict()
- def hammer(thread_idx, thread_count, result):
- success = True
- for i in range(thread_idx, 240, thread_count):
- ret = subprocess.call(['adb', 'shell', 'exit {}'.format(i)])
- if ret != i % 256:
- success = False
- break
- result[thread_idx] = success
-
- threads = []
- for i in range(thread_count):
- thread = threading.Thread(target=hammer, args=(i, thread_count, result))
- thread.start()
- threads.append(thread)
- for thread in threads:
- thread.join()
- for i, success in result.items():
- self.assertTrue(success)
-
- def disabled_test_parallel(self):
- """Spawn a bunch of `adb shell` instances in parallel.
-
- This was broken historically due to the use of select, which only works
- for fds that are numerically less than 1024.
-
- Bug: http://b/141955761"""
-
- n_procs = 2048
- procs = dict()
- for i in range(0, n_procs):
- procs[i] = subprocess.Popen(
- ['adb', 'shell', 'read foo; echo $foo; read rc; exit $rc'],
- stdin=subprocess.PIPE,
- stdout=subprocess.PIPE
- )
-
- for i in range(0, n_procs):
- procs[i].stdin.write("%d\n" % i)
-
- for i in range(0, n_procs):
- response = procs[i].stdout.readline()
- assert(response == "%d\n" % i)
-
- for i in range(0, n_procs):
- procs[i].stdin.write("%d\n" % (i % 256))
-
- for i in range(0, n_procs):
- assert(procs[i].wait() == i % 256)
-
-
-class ArgumentEscapingTest(DeviceTest):
- def test_shell_escaping(self):
- """Make sure that argument escaping is somewhat sane."""
-
- # http://b/19734868
- # Note that this actually matches ssh(1)'s behavior --- it's
- # converted to `sh -c echo hello; echo world` which sh interprets
- # as `sh -c echo` (with an argument to that shell of "hello"),
- # and then `echo world` back in the first shell.
- result = self.device.shell(
- shlex.split("sh -c 'echo hello; echo world'"))[0]
- result = result.splitlines()
- self.assertEqual(['', 'world'], result)
- # If you really wanted "hello" and "world", here's what you'd do:
- result = self.device.shell(
- shlex.split(r'echo hello\;echo world'))[0].splitlines()
- self.assertEqual(['hello', 'world'], result)
-
- # http://b/15479704
- result = self.device.shell(shlex.split("'true && echo t'"))[0].strip()
- self.assertEqual('t', result)
- result = self.device.shell(
- shlex.split("sh -c 'true && echo t'"))[0].strip()
- self.assertEqual('t', result)
-
- # http://b/20564385
- result = self.device.shell(shlex.split('FOO=a BAR=b echo t'))[0].strip()
- self.assertEqual('t', result)
- result = self.device.shell(
- shlex.split(r'echo -n 123\;uname'))[0].strip()
- self.assertEqual('123Linux', result)
-
- def test_install_argument_escaping(self):
- """Make sure that install argument escaping works."""
- # http://b/20323053, http://b/3090932.
- for file_suffix in (b'-text;ls;1.apk', b"-Live Hold'em.apk"):
- tf = tempfile.NamedTemporaryFile('wb', suffix=file_suffix,
- delete=False)
- tf.close()
-
- # Installing bogus .apks fails if the device supports exit codes.
- try:
- output = self.device.install(tf.name.decode("utf8"))
- except subprocess.CalledProcessError as e:
- output = e.output
-
- self.assertIn(file_suffix, output)
- os.remove(tf.name)
-
-
-class RootUnrootTest(DeviceTest):
- def _test_root(self):
- message = self.device.root()
- if 'adbd cannot run as root in production builds' in message:
- return
- self.device.wait()
- self.assertEqual('root', self.device.shell(['id', '-un'])[0].strip())
-
- def _test_unroot(self):
- self.device.unroot()
- self.device.wait()
- self.assertEqual('shell', self.device.shell(['id', '-un'])[0].strip())
-
- def test_root_unroot(self):
- """Make sure that adb root and adb unroot work, using id(1)."""
- if self.device.get_prop('ro.debuggable') != '1':
- raise unittest.SkipTest('requires rootable build')
-
- original_user = self.device.shell(['id', '-un'])[0].strip()
- try:
- if original_user == 'root':
- self._test_unroot()
- self._test_root()
- elif original_user == 'shell':
- self._test_root()
- self._test_unroot()
- finally:
- if original_user == 'root':
- self.device.root()
- else:
- self.device.unroot()
- self.device.wait()
-
-
-class TcpIpTest(DeviceTest):
- def test_tcpip_failure_raises(self):
- """adb tcpip requires a port.
-
- Bug: http://b/22636927
- """
- self.assertRaises(
- subprocess.CalledProcessError, self.device.tcpip, '')
- self.assertRaises(
- subprocess.CalledProcessError, self.device.tcpip, 'foo')
-
-
-class SystemPropertiesTest(DeviceTest):
- def test_get_prop(self):
- self.assertEqual(self.device.get_prop('init.svc.adbd'), 'running')
-
- @requires_root
- def test_set_prop(self):
- prop_name = 'foo.bar'
- self.device.shell(['setprop', prop_name, '""'])
-
- self.device.set_prop(prop_name, 'qux')
- self.assertEqual(
- self.device.shell(['getprop', prop_name])[0].strip(), 'qux')
-
-
-def compute_md5(string):
- hsh = hashlib.md5()
- hsh.update(string)
- return hsh.hexdigest()
-
-
-def get_md5_prog(device):
- """Older platforms (pre-L) had the name md5 rather than md5sum."""
- try:
- device.shell(['md5sum', '/proc/uptime'])
- return 'md5sum'
- except adb.ShellError:
- return 'md5'
-
-
-class HostFile(object):
- def __init__(self, handle, checksum):
- self.handle = handle
- self.checksum = checksum
- self.full_path = handle.name
- self.base_name = os.path.basename(self.full_path)
-
-
-class DeviceFile(object):
- def __init__(self, checksum, full_path):
- self.checksum = checksum
- self.full_path = full_path
- self.base_name = posixpath.basename(self.full_path)
-
-
-def make_random_host_files(in_dir, num_files):
- min_size = 1 * (1 << 10)
- max_size = 16 * (1 << 10)
-
- files = []
- for _ in range(num_files):
- file_handle = tempfile.NamedTemporaryFile(dir=in_dir, delete=False)
-
- size = random.randrange(min_size, max_size, 1024)
- rand_str = os.urandom(size)
- file_handle.write(rand_str)
- file_handle.flush()
- file_handle.close()
-
- md5 = compute_md5(rand_str)
- files.append(HostFile(file_handle, md5))
- return files
-
-
-def make_random_device_files(device, in_dir, num_files, prefix='device_tmpfile'):
- min_size = 1 * (1 << 10)
- max_size = 16 * (1 << 10)
-
- files = []
- for file_num in range(num_files):
- size = random.randrange(min_size, max_size, 1024)
-
- base_name = prefix + str(file_num)
- full_path = posixpath.join(in_dir, base_name)
-
- device.shell(['dd', 'if=/dev/urandom', 'of={}'.format(full_path),
- 'bs={}'.format(size), 'count=1'])
- dev_md5, _ = device.shell([get_md5_prog(device), full_path])[0].split()
-
- files.append(DeviceFile(dev_md5, full_path))
- return files
-
-
-class FileOperationsTest(DeviceTest):
- SCRATCH_DIR = '/data/local/tmp'
- DEVICE_TEMP_FILE = SCRATCH_DIR + '/adb_test_file'
- DEVICE_TEMP_DIR = SCRATCH_DIR + '/adb_test_dir'
-
- def _verify_remote(self, checksum, remote_path):
- dev_md5, _ = self.device.shell([get_md5_prog(self.device),
- remote_path])[0].split()
- self.assertEqual(checksum, dev_md5)
-
- def _verify_local(self, checksum, local_path):
- with open(local_path, 'rb') as host_file:
- host_md5 = compute_md5(host_file.read())
- self.assertEqual(host_md5, checksum)
-
- def test_push(self):
- """Push a randomly generated file to specified device."""
- kbytes = 512
- tmp = tempfile.NamedTemporaryFile(mode='wb', delete=False)
- rand_str = os.urandom(1024 * kbytes)
- tmp.write(rand_str)
- tmp.close()
-
- self.device.shell(['rm', '-rf', self.DEVICE_TEMP_FILE])
- self.device.push(local=tmp.name, remote=self.DEVICE_TEMP_FILE)
-
- self._verify_remote(compute_md5(rand_str), self.DEVICE_TEMP_FILE)
- self.device.shell(['rm', '-f', self.DEVICE_TEMP_FILE])
-
- os.remove(tmp.name)
-
- def test_push_dir(self):
- """Push a randomly generated directory of files to the device."""
- self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
- self.device.shell(['mkdir', self.DEVICE_TEMP_DIR])
-
- try:
- host_dir = tempfile.mkdtemp()
-
- # Make sure the temp directory isn't setuid, or else adb will complain.
- os.chmod(host_dir, 0o700)
-
- # Create 32 random files.
- temp_files = make_random_host_files(in_dir=host_dir, num_files=32)
- self.device.push(host_dir, self.DEVICE_TEMP_DIR)
-
- for temp_file in temp_files:
- remote_path = posixpath.join(self.DEVICE_TEMP_DIR,
- os.path.basename(host_dir),
- temp_file.base_name)
- self._verify_remote(temp_file.checksum, remote_path)
- self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
- finally:
- if host_dir is not None:
- shutil.rmtree(host_dir)
-
- def disabled_test_push_empty(self):
- """Push an empty directory to the device."""
- self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
- self.device.shell(['mkdir', self.DEVICE_TEMP_DIR])
-
- try:
- host_dir = tempfile.mkdtemp()
-
- # Make sure the temp directory isn't setuid, or else adb will complain.
- os.chmod(host_dir, 0o700)
-
- # Create an empty directory.
- empty_dir_path = os.path.join(host_dir, 'empty')
- os.mkdir(empty_dir_path);
-
- self.device.push(empty_dir_path, self.DEVICE_TEMP_DIR)
-
- remote_path = os.path.join(self.DEVICE_TEMP_DIR, "empty")
- test_empty_cmd = ["[", "-d", remote_path, "]"]
- rc, _, _ = self.device.shell_nocheck(test_empty_cmd)
-
- self.assertEqual(rc, 0)
- self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
- finally:
- if host_dir is not None:
- shutil.rmtree(host_dir)
-
- @unittest.skipIf(sys.platform == "win32", "symlinks require elevated privileges on windows")
- def test_push_symlink(self):
- """Push a symlink.
-
- Bug: http://b/31491920
- """
- try:
- host_dir = tempfile.mkdtemp()
-
- # Make sure the temp directory isn't setuid, or else adb will
- # complain.
- os.chmod(host_dir, 0o700)
-
- with open(os.path.join(host_dir, 'foo'), 'w') as f:
- f.write('foo')
-
- symlink_path = os.path.join(host_dir, 'symlink')
- os.symlink('foo', symlink_path)
-
- self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
- self.device.shell(['mkdir', self.DEVICE_TEMP_DIR])
- self.device.push(symlink_path, self.DEVICE_TEMP_DIR)
- rc, out, _ = self.device.shell_nocheck(
- ['cat', posixpath.join(self.DEVICE_TEMP_DIR, 'symlink')])
- self.assertEqual(0, rc)
- self.assertEqual(out.strip(), 'foo')
- finally:
- if host_dir is not None:
- shutil.rmtree(host_dir)
-
- def test_multiple_push(self):
- """Push multiple files to the device in one adb push command.
-
- Bug: http://b/25324823
- """
-
- self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
- self.device.shell(['mkdir', self.DEVICE_TEMP_DIR])
-
- try:
- host_dir = tempfile.mkdtemp()
-
- # Create some random files and a subdirectory containing more files.
- temp_files = make_random_host_files(in_dir=host_dir, num_files=4)
-
- subdir = os.path.join(host_dir, 'subdir')
- os.mkdir(subdir)
- subdir_temp_files = make_random_host_files(in_dir=subdir,
- num_files=4)
-
- paths = [x.full_path for x in temp_files]
- paths.append(subdir)
- self.device._simple_call(['push'] + paths + [self.DEVICE_TEMP_DIR])
-
- for temp_file in temp_files:
- remote_path = posixpath.join(self.DEVICE_TEMP_DIR,
- temp_file.base_name)
- self._verify_remote(temp_file.checksum, remote_path)
-
- for subdir_temp_file in subdir_temp_files:
- remote_path = posixpath.join(self.DEVICE_TEMP_DIR,
- # BROKEN: http://b/25394682
- # 'subdir';
- temp_file.base_name)
- self._verify_remote(temp_file.checksum, remote_path)
-
-
- self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
- finally:
- if host_dir is not None:
- shutil.rmtree(host_dir)
-
- @requires_non_root
- def test_push_error_reporting(self):
- """Make sure that errors that occur while pushing a file get reported
-
- Bug: http://b/26816782
- """
- with tempfile.NamedTemporaryFile() as tmp_file:
- tmp_file.write(b'\0' * 1024 * 1024)
- tmp_file.flush()
- try:
- self.device.push(local=tmp_file.name, remote='/system/')
- self.fail('push should not have succeeded')
- except subprocess.CalledProcessError as e:
- output = e.output
-
- self.assertTrue(b'Permission denied' in output or
- b'Read-only file system' in output)
-
- @requires_non_root
- def test_push_directory_creation(self):
- """Regression test for directory creation.
-
- Bug: http://b/110953234
- """
- with tempfile.NamedTemporaryFile() as tmp_file:
- tmp_file.write(b'\0' * 1024 * 1024)
- tmp_file.flush()
- remote_path = self.DEVICE_TEMP_DIR + '/test_push_directory_creation'
- self.device.shell(['rm', '-rf', remote_path])
-
- remote_path += '/filename'
- self.device.push(local=tmp_file.name, remote=remote_path)
-
- def disabled_test_push_multiple_slash_root(self):
- """Regression test for pushing to //data/local/tmp.
-
- Bug: http://b/141311284
-
- Disabled because this broken on the adbd side as well: b/141943968
- """
- with tempfile.NamedTemporaryFile() as tmp_file:
- tmp_file.write('\0' * 1024 * 1024)
- tmp_file.flush()
- remote_path = '/' + self.DEVICE_TEMP_DIR + '/test_push_multiple_slash_root'
- self.device.shell(['rm', '-rf', remote_path])
- self.device.push(local=tmp_file.name, remote=remote_path)
-
- def _test_pull(self, remote_file, checksum):
- tmp_write = tempfile.NamedTemporaryFile(mode='wb', delete=False)
- tmp_write.close()
- self.device.pull(remote=remote_file, local=tmp_write.name)
- with open(tmp_write.name, 'rb') as tmp_read:
- host_contents = tmp_read.read()
- host_md5 = compute_md5(host_contents)
- self.assertEqual(checksum, host_md5)
- os.remove(tmp_write.name)
-
- @requires_non_root
- def test_pull_error_reporting(self):
- self.device.shell(['touch', self.DEVICE_TEMP_FILE])
- self.device.shell(['chmod', 'a-rwx', self.DEVICE_TEMP_FILE])
-
- try:
- output = self.device.pull(remote=self.DEVICE_TEMP_FILE, local='x')
- except subprocess.CalledProcessError as e:
- output = e.output
-
- self.assertIn(b'Permission denied', output)
-
- self.device.shell(['rm', '-f', self.DEVICE_TEMP_FILE])
-
- def test_pull(self):
- """Pull a randomly generated file from specified device."""
- kbytes = 512
- self.device.shell(['rm', '-rf', self.DEVICE_TEMP_FILE])
- cmd = ['dd', 'if=/dev/urandom',
- 'of={}'.format(self.DEVICE_TEMP_FILE), 'bs=1024',
- 'count={}'.format(kbytes)]
- self.device.shell(cmd)
- dev_md5, _ = self.device.shell(
- [get_md5_prog(self.device), self.DEVICE_TEMP_FILE])[0].split()
- self._test_pull(self.DEVICE_TEMP_FILE, dev_md5)
- self.device.shell_nocheck(['rm', self.DEVICE_TEMP_FILE])
-
- def test_pull_dir(self):
- """Pull a randomly generated directory of files from the device."""
- try:
- host_dir = tempfile.mkdtemp()
-
- self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
- self.device.shell(['mkdir', '-p', self.DEVICE_TEMP_DIR])
-
- # Populate device directory with random files.
- temp_files = make_random_device_files(
- self.device, in_dir=self.DEVICE_TEMP_DIR, num_files=32)
-
- self.device.pull(remote=self.DEVICE_TEMP_DIR, local=host_dir)
-
- for temp_file in temp_files:
- host_path = os.path.join(
- host_dir, posixpath.basename(self.DEVICE_TEMP_DIR),
- temp_file.base_name)
- self._verify_local(temp_file.checksum, host_path)
-
- self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
- finally:
- if host_dir is not None:
- shutil.rmtree(host_dir)
-
- def test_pull_dir_symlink(self):
- """Pull a directory into a symlink to a directory.
-
- Bug: http://b/27362811
- """
- if os.name != 'posix':
- raise unittest.SkipTest('requires POSIX')
-
- try:
- host_dir = tempfile.mkdtemp()
- real_dir = os.path.join(host_dir, 'dir')
- symlink = os.path.join(host_dir, 'symlink')
- os.mkdir(real_dir)
- os.symlink(real_dir, symlink)
-
- self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
- self.device.shell(['mkdir', '-p', self.DEVICE_TEMP_DIR])
-
- # Populate device directory with random files.
- temp_files = make_random_device_files(
- self.device, in_dir=self.DEVICE_TEMP_DIR, num_files=32)
-
- self.device.pull(remote=self.DEVICE_TEMP_DIR, local=symlink)
-
- for temp_file in temp_files:
- host_path = os.path.join(
- real_dir, posixpath.basename(self.DEVICE_TEMP_DIR),
- temp_file.base_name)
- self._verify_local(temp_file.checksum, host_path)
-
- self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
- finally:
- if host_dir is not None:
- shutil.rmtree(host_dir)
-
- def test_pull_dir_symlink_collision(self):
- """Pull a directory into a colliding symlink to directory."""
- if os.name != 'posix':
- raise unittest.SkipTest('requires POSIX')
-
- try:
- host_dir = tempfile.mkdtemp()
- real_dir = os.path.join(host_dir, 'real')
- tmp_dirname = os.path.basename(self.DEVICE_TEMP_DIR)
- symlink = os.path.join(host_dir, tmp_dirname)
- os.mkdir(real_dir)
- os.symlink(real_dir, symlink)
-
- self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
- self.device.shell(['mkdir', '-p', self.DEVICE_TEMP_DIR])
-
- # Populate device directory with random files.
- temp_files = make_random_device_files(
- self.device, in_dir=self.DEVICE_TEMP_DIR, num_files=32)
-
- self.device.pull(remote=self.DEVICE_TEMP_DIR, local=host_dir)
-
- for temp_file in temp_files:
- host_path = os.path.join(real_dir, temp_file.base_name)
- self._verify_local(temp_file.checksum, host_path)
-
- self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
- finally:
- if host_dir is not None:
- shutil.rmtree(host_dir)
-
- def test_pull_dir_nonexistent(self):
- """Pull a directory of files from the device to a nonexistent path."""
- try:
- host_dir = tempfile.mkdtemp()
- dest_dir = os.path.join(host_dir, 'dest')
-
- self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
- self.device.shell(['mkdir', '-p', self.DEVICE_TEMP_DIR])
-
- # Populate device directory with random files.
- temp_files = make_random_device_files(
- self.device, in_dir=self.DEVICE_TEMP_DIR, num_files=32)
-
- self.device.pull(remote=self.DEVICE_TEMP_DIR, local=dest_dir)
-
- for temp_file in temp_files:
- host_path = os.path.join(dest_dir, temp_file.base_name)
- self._verify_local(temp_file.checksum, host_path)
-
- self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
- finally:
- if host_dir is not None:
- shutil.rmtree(host_dir)
-
- # selinux prevents adbd from accessing symlinks on /data/local/tmp.
- def disabled_test_pull_symlink_dir(self):
- """Pull a symlink to a directory of symlinks to files."""
- try:
- host_dir = tempfile.mkdtemp()
-
- remote_dir = posixpath.join(self.DEVICE_TEMP_DIR, 'contents')
- remote_links = posixpath.join(self.DEVICE_TEMP_DIR, 'links')
- remote_symlink = posixpath.join(self.DEVICE_TEMP_DIR, 'symlink')
-
- self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
- self.device.shell(['mkdir', '-p', remote_dir, remote_links])
- self.device.shell(['ln', '-s', remote_links, remote_symlink])
-
- # Populate device directory with random files.
- temp_files = make_random_device_files(
- self.device, in_dir=remote_dir, num_files=32)
-
- for temp_file in temp_files:
- self.device.shell(
- ['ln', '-s', '../contents/{}'.format(temp_file.base_name),
- posixpath.join(remote_links, temp_file.base_name)])
-
- self.device.pull(remote=remote_symlink, local=host_dir)
-
- for temp_file in temp_files:
- host_path = os.path.join(
- host_dir, 'symlink', temp_file.base_name)
- self._verify_local(temp_file.checksum, host_path)
-
- self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
- finally:
- if host_dir is not None:
- shutil.rmtree(host_dir)
-
- def test_pull_empty(self):
- """Pull a directory containing an empty directory from the device."""
- try:
- host_dir = tempfile.mkdtemp()
-
- remote_empty_path = posixpath.join(self.DEVICE_TEMP_DIR, 'empty')
- self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
- self.device.shell(['mkdir', '-p', remote_empty_path])
-
- self.device.pull(remote=remote_empty_path, local=host_dir)
- self.assertTrue(os.path.isdir(os.path.join(host_dir, 'empty')))
- finally:
- if host_dir is not None:
- shutil.rmtree(host_dir)
-
- def test_multiple_pull(self):
- """Pull a randomly generated directory of files from the device."""
-
- try:
- host_dir = tempfile.mkdtemp()
-
- subdir = posixpath.join(self.DEVICE_TEMP_DIR, 'subdir')
- self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
- self.device.shell(['mkdir', '-p', subdir])
-
- # Create some random files and a subdirectory containing more files.
- temp_files = make_random_device_files(
- self.device, in_dir=self.DEVICE_TEMP_DIR, num_files=4)
-
- subdir_temp_files = make_random_device_files(
- self.device, in_dir=subdir, num_files=4, prefix='subdir_')
-
- paths = [x.full_path for x in temp_files]
- paths.append(subdir)
- self.device._simple_call(['pull'] + paths + [host_dir])
-
- for temp_file in temp_files:
- local_path = os.path.join(host_dir, temp_file.base_name)
- self._verify_local(temp_file.checksum, local_path)
-
- for subdir_temp_file in subdir_temp_files:
- local_path = os.path.join(host_dir,
- 'subdir',
- subdir_temp_file.base_name)
- self._verify_local(subdir_temp_file.checksum, local_path)
-
- self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
- finally:
- if host_dir is not None:
- shutil.rmtree(host_dir)
-
- def verify_sync(self, device, temp_files, device_dir):
- """Verifies that a list of temp files was synced to the device."""
- # Confirm that every file on the device mirrors that on the host.
- for temp_file in temp_files:
- device_full_path = posixpath.join(
- device_dir, temp_file.base_name)
- dev_md5, _ = device.shell(
- [get_md5_prog(self.device), device_full_path])[0].split()
- self.assertEqual(temp_file.checksum, dev_md5)
-
- def test_sync(self):
- """Sync a host directory to the data partition."""
-
- try:
- base_dir = tempfile.mkdtemp()
-
- # Create mirror device directory hierarchy within base_dir.
- full_dir_path = base_dir + self.DEVICE_TEMP_DIR
- os.makedirs(full_dir_path)
-
- # Create 32 random files within the host mirror.
- temp_files = make_random_host_files(
- in_dir=full_dir_path, num_files=32)
-
- # Clean up any stale files on the device.
- device = adb.get_device() # pylint: disable=no-member
- device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
-
- old_product_out = os.environ.get('ANDROID_PRODUCT_OUT')
- os.environ['ANDROID_PRODUCT_OUT'] = base_dir
- device.sync('data')
- if old_product_out is None:
- del os.environ['ANDROID_PRODUCT_OUT']
- else:
- os.environ['ANDROID_PRODUCT_OUT'] = old_product_out
-
- self.verify_sync(device, temp_files, self.DEVICE_TEMP_DIR)
-
- #self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
- finally:
- if base_dir is not None:
- shutil.rmtree(base_dir)
-
- def test_push_sync(self):
- """Sync a host directory to a specific path."""
-
- try:
- temp_dir = tempfile.mkdtemp()
- temp_files = make_random_host_files(in_dir=temp_dir, num_files=32)
-
- device_dir = posixpath.join(self.DEVICE_TEMP_DIR, 'sync_src_dst')
-
- # Clean up any stale files on the device.
- device = adb.get_device() # pylint: disable=no-member
- device.shell(['rm', '-rf', device_dir])
-
- device.push(temp_dir, device_dir, sync=True)
-
- self.verify_sync(device, temp_files, device_dir)
-
- self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
- finally:
- if temp_dir is not None:
- shutil.rmtree(temp_dir)
-
- def test_unicode_paths(self):
- """Ensure that we can support non-ASCII paths, even on Windows."""
- name = u'로보카 í´ë¦¬'
-
- self.device.shell(['rm', '-f', '/data/local/tmp/adb-test-*'])
- remote_path = u'/data/local/tmp/adb-test-{}'.format(name)
-
- ## push.
- tf = tempfile.NamedTemporaryFile('wb', suffix=name, delete=False)
- tf.close()
- self.device.push(tf.name, remote_path)
- os.remove(tf.name)
- self.assertFalse(os.path.exists(tf.name))
-
- # Verify that the device ended up with the expected UTF-8 path
- output = self.device.shell(
- ['ls', '/data/local/tmp/adb-test-*'])[0].strip()
- self.assertEqual(remote_path, output)
-
- # pull.
- self.device.pull(remote_path, tf.name)
- self.assertTrue(os.path.exists(tf.name))
- os.remove(tf.name)
- self.device.shell(['rm', '-f', '/data/local/tmp/adb-test-*'])
-
-
-class DeviceOfflineTest(DeviceTest):
- def _get_device_state(self, serialno):
- output = subprocess.check_output(self.device.adb_cmd + ['devices'])
- for line in output.split('\n'):
- m = re.match('(\S+)\s+(\S+)', line)
- if m and m.group(1) == serialno:
- return m.group(2)
- return None
-
- def disabled_test_killed_when_pushing_a_large_file(self):
- """
- While running adb push with a large file, kill adb server.
- Occasionally the device becomes offline. Because the device is still
- reading data without realizing that the adb server has been restarted.
- Test if we can bring the device online automatically now.
- http://b/32952319
- """
- serialno = subprocess.check_output(self.device.adb_cmd + ['get-serialno']).strip()
- # 1. Push a large file
- file_path = 'tmp_large_file'
- try:
- fh = open(file_path, 'w')
- fh.write('\0' * (100 * 1024 * 1024))
- fh.close()
- subproc = subprocess.Popen(self.device.adb_cmd + ['push', file_path, '/data/local/tmp'])
- time.sleep(0.1)
- # 2. Kill the adb server
- subprocess.check_call(self.device.adb_cmd + ['kill-server'])
- subproc.terminate()
- finally:
- try:
- os.unlink(file_path)
- except:
- pass
- # 3. See if the device still exist.
- # Sleep to wait for the adb server exit.
- time.sleep(0.5)
- # 4. The device should be online
- self.assertEqual(self._get_device_state(serialno), 'device')
-
- def disabled_test_killed_when_pulling_a_large_file(self):
- """
- While running adb pull with a large file, kill adb server.
- Occasionally the device can't be connected. Because the device is trying to
- send a message larger than what is expected by the adb server.
- Test if we can bring the device online automatically now.
- """
- serialno = subprocess.check_output(self.device.adb_cmd + ['get-serialno']).strip()
- file_path = 'tmp_large_file'
- try:
- # 1. Create a large file on device.
- self.device.shell(['dd', 'if=/dev/zero', 'of=/data/local/tmp/tmp_large_file',
- 'bs=1000000', 'count=100'])
- # 2. Pull the large file on host.
- subproc = subprocess.Popen(self.device.adb_cmd +
- ['pull','/data/local/tmp/tmp_large_file', file_path])
- time.sleep(0.1)
- # 3. Kill the adb server
- subprocess.check_call(self.device.adb_cmd + ['kill-server'])
- subproc.terminate()
- finally:
- try:
- os.unlink(file_path)
- except:
- pass
- # 4. See if the device still exist.
- # Sleep to wait for the adb server exit.
- time.sleep(0.5)
- self.assertEqual(self._get_device_state(serialno), 'device')
-
-
- def test_packet_size_regression(self):
- """Test for http://b/37783561
-
- Receiving packets of a length divisible by 512 but not 1024 resulted in
- the adb client waiting indefinitely for more input.
- """
- # The values that trigger things are 507 (512 - 5 bytes from shell protocol) + 1024*n
- # Probe some surrounding values as well, for the hell of it.
- for base in [512] + list(range(1024, 1024 * 16, 1024)):
- for offset in [-6, -5, -4]:
- length = base + offset
- cmd = ['dd', 'if=/dev/zero', 'bs={}'.format(length), 'count=1', '2>/dev/null;'
- 'echo', 'foo']
- rc, stdout, _ = self.device.shell_nocheck(cmd)
-
- self.assertEqual(0, rc)
-
- # Output should be '\0' * length, followed by "foo\n"
- self.assertEqual(length, len(stdout) - 4)
- self.assertEqual(stdout, "\0" * length + "foo\n")
-
- def test_zero_packet(self):
- """Test for http://b/113070258
-
- Make sure that we don't blow up when sending USB transfers that line up
- exactly with the USB packet size.
- """
-
- local_port = int(self.device.forward("tcp:0", "tcp:12345"))
- try:
- for size in [512, 1024]:
- def listener():
- cmd = ["echo foo | nc -l -p 12345; echo done"]
- rc, stdout, stderr = self.device.shell_nocheck(cmd)
-
- thread = threading.Thread(target=listener)
- thread.start()
-
- # Wait a bit to let the shell command start.
- time.sleep(0.25)
-
- sock = socket.create_connection(("localhost", local_port))
- with contextlib.closing(sock):
- bytesWritten = sock.send(b"a" * size)
- self.assertEqual(size, bytesWritten)
- readBytes = sock.recv(4096)
- self.assertEqual(b"foo\n", readBytes)
-
- thread.join()
- finally:
- self.device.forward_remove("tcp:{}".format(local_port))
-
-
-class SocketTest(DeviceTest):
- def test_socket_flush(self):
- """Test that we handle socket closure properly.
-
- If we're done writing to a socket, closing before the other end has
- closed will send a TCP_RST if we have incoming data queued up, which
- may result in data that we've written being discarded.
-
- Bug: http://b/74616284
- """
- s = socket.create_connection(("localhost", 5037))
-
- def adb_length_prefixed(string):
- encoded = string.encode("utf8")
- result = b"%04x%s" % (len(encoded), encoded)
- return result
-
- if "ANDROID_SERIAL" in os.environ:
- transport_string = "host:transport:" + os.environ["ANDROID_SERIAL"]
- else:
- transport_string = "host:transport-any"
-
- s.sendall(adb_length_prefixed(transport_string))
- response = s.recv(4)
- self.assertEqual(b"OKAY", response)
-
- shell_string = "shell:sleep 0.5; dd if=/dev/zero bs=1m count=1 status=none; echo foo"
- s.sendall(adb_length_prefixed(shell_string))
-
- response = s.recv(4)
- self.assertEqual(b"OKAY", response)
-
- # Spawn a thread that dumps garbage into the socket until failure.
- def spam():
- buf = b"\0" * 16384
- try:
- while True:
- s.sendall(buf)
- except Exception as ex:
- print(ex)
-
- thread = threading.Thread(target=spam)
- thread.start()
-
- time.sleep(1)
-
- received = b""
- while True:
- read = s.recv(512)
- if len(read) == 0:
- break
- received += read
-
- self.assertEqual(1024 * 1024 + len("foo\n"), len(received))
- thread.join()
-
-
-if sys.platform == "win32":
- # From https://stackoverflow.com/a/38749458
- import os
- import contextlib
- import msvcrt
- import ctypes
- from ctypes import wintypes
-
- kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
-
- GENERIC_READ = 0x80000000
- GENERIC_WRITE = 0x40000000
- FILE_SHARE_READ = 1
- FILE_SHARE_WRITE = 2
- CONSOLE_TEXTMODE_BUFFER = 1
- INVALID_HANDLE_VALUE = wintypes.HANDLE(-1).value
- STD_OUTPUT_HANDLE = wintypes.DWORD(-11)
- STD_ERROR_HANDLE = wintypes.DWORD(-12)
-
- def _check_zero(result, func, args):
- if not result:
- raise ctypes.WinError(ctypes.get_last_error())
- return args
-
- def _check_invalid(result, func, args):
- if result == INVALID_HANDLE_VALUE:
- raise ctypes.WinError(ctypes.get_last_error())
- return args
-
- if not hasattr(wintypes, 'LPDWORD'): # Python 2
- wintypes.LPDWORD = ctypes.POINTER(wintypes.DWORD)
- wintypes.PSMALL_RECT = ctypes.POINTER(wintypes.SMALL_RECT)
-
- class COORD(ctypes.Structure):
- _fields_ = (('X', wintypes.SHORT),
- ('Y', wintypes.SHORT))
-
- class CONSOLE_SCREEN_BUFFER_INFOEX(ctypes.Structure):
- _fields_ = (('cbSize', wintypes.ULONG),
- ('dwSize', COORD),
- ('dwCursorPosition', COORD),
- ('wAttributes', wintypes.WORD),
- ('srWindow', wintypes.SMALL_RECT),
- ('dwMaximumWindowSize', COORD),
- ('wPopupAttributes', wintypes.WORD),
- ('bFullscreenSupported', wintypes.BOOL),
- ('ColorTable', wintypes.DWORD * 16))
- def __init__(self, *args, **kwds):
- super(CONSOLE_SCREEN_BUFFER_INFOEX, self).__init__(
- *args, **kwds)
- self.cbSize = ctypes.sizeof(self)
-
- PCONSOLE_SCREEN_BUFFER_INFOEX = ctypes.POINTER(
- CONSOLE_SCREEN_BUFFER_INFOEX)
- LPSECURITY_ATTRIBUTES = wintypes.LPVOID
-
- kernel32.GetStdHandle.errcheck = _check_invalid
- kernel32.GetStdHandle.restype = wintypes.HANDLE
- kernel32.GetStdHandle.argtypes = (
- wintypes.DWORD,) # _In_ nStdHandle
-
- kernel32.CreateConsoleScreenBuffer.errcheck = _check_invalid
- kernel32.CreateConsoleScreenBuffer.restype = wintypes.HANDLE
- kernel32.CreateConsoleScreenBuffer.argtypes = (
- wintypes.DWORD, # _In_ dwDesiredAccess
- wintypes.DWORD, # _In_ dwShareMode
- LPSECURITY_ATTRIBUTES, # _In_opt_ lpSecurityAttributes
- wintypes.DWORD, # _In_ dwFlags
- wintypes.LPVOID) # _Reserved_ lpScreenBufferData
-
- kernel32.GetConsoleScreenBufferInfoEx.errcheck = _check_zero
- kernel32.GetConsoleScreenBufferInfoEx.argtypes = (
- wintypes.HANDLE, # _In_ hConsoleOutput
- PCONSOLE_SCREEN_BUFFER_INFOEX) # _Out_ lpConsoleScreenBufferInfo
-
- kernel32.SetConsoleScreenBufferInfoEx.errcheck = _check_zero
- kernel32.SetConsoleScreenBufferInfoEx.argtypes = (
- wintypes.HANDLE, # _In_ hConsoleOutput
- PCONSOLE_SCREEN_BUFFER_INFOEX) # _In_ lpConsoleScreenBufferInfo
-
- kernel32.SetConsoleWindowInfo.errcheck = _check_zero
- kernel32.SetConsoleWindowInfo.argtypes = (
- wintypes.HANDLE, # _In_ hConsoleOutput
- wintypes.BOOL, # _In_ bAbsolute
- wintypes.PSMALL_RECT) # _In_ lpConsoleWindow
-
- kernel32.FillConsoleOutputCharacterW.errcheck = _check_zero
- kernel32.FillConsoleOutputCharacterW.argtypes = (
- wintypes.HANDLE, # _In_ hConsoleOutput
- wintypes.WCHAR, # _In_ cCharacter
- wintypes.DWORD, # _In_ nLength
- COORD, # _In_ dwWriteCoord
- wintypes.LPDWORD) # _Out_ lpNumberOfCharsWritten
-
- kernel32.ReadConsoleOutputCharacterW.errcheck = _check_zero
- kernel32.ReadConsoleOutputCharacterW.argtypes = (
- wintypes.HANDLE, # _In_ hConsoleOutput
- wintypes.LPWSTR, # _Out_ lpCharacter
- wintypes.DWORD, # _In_ nLength
- COORD, # _In_ dwReadCoord
- wintypes.LPDWORD) # _Out_ lpNumberOfCharsRead
-
- @contextlib.contextmanager
- def allocate_console():
- allocated = kernel32.AllocConsole()
- try:
- yield allocated
- finally:
- if allocated:
- kernel32.FreeConsole()
-
- @contextlib.contextmanager
- def console_screen(ncols=None, nrows=None):
- info = CONSOLE_SCREEN_BUFFER_INFOEX()
- new_info = CONSOLE_SCREEN_BUFFER_INFOEX()
- nwritten = (wintypes.DWORD * 1)()
- hStdOut = kernel32.GetStdHandle(STD_OUTPUT_HANDLE)
- kernel32.GetConsoleScreenBufferInfoEx(
- hStdOut, ctypes.byref(info))
- if ncols is None:
- ncols = info.dwSize.X
- if nrows is None:
- nrows = info.dwSize.Y
- elif nrows > 9999:
- raise ValueError('nrows must be 9999 or less')
- fd_screen = None
- hScreen = kernel32.CreateConsoleScreenBuffer(
- GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- None, CONSOLE_TEXTMODE_BUFFER, None)
- try:
- fd_screen = msvcrt.open_osfhandle(
- hScreen, os.O_RDWR | os.O_BINARY)
- kernel32.GetConsoleScreenBufferInfoEx(
- hScreen, ctypes.byref(new_info))
- new_info.dwSize = COORD(ncols, nrows)
- new_info.srWindow = wintypes.SMALL_RECT(
- Left=0, Top=0, Right=(ncols - 1),
- Bottom=(info.srWindow.Bottom - info.srWindow.Top))
- kernel32.SetConsoleScreenBufferInfoEx(
- hScreen, ctypes.byref(new_info))
- kernel32.SetConsoleWindowInfo(hScreen, True,
- ctypes.byref(new_info.srWindow))
- kernel32.FillConsoleOutputCharacterW(
- hScreen, u'\0', ncols * nrows, COORD(0,0), nwritten)
- kernel32.SetConsoleActiveScreenBuffer(hScreen)
- try:
- yield fd_screen
- finally:
- kernel32.SetConsoleScreenBufferInfoEx(
- hStdOut, ctypes.byref(info))
- kernel32.SetConsoleWindowInfo(hStdOut, True,
- ctypes.byref(info.srWindow))
- kernel32.SetConsoleActiveScreenBuffer(hStdOut)
- finally:
- if fd_screen is not None:
- os.close(fd_screen)
- else:
- kernel32.CloseHandle(hScreen)
-
- def read_screen(fd):
- hScreen = msvcrt.get_osfhandle(fd)
- csbi = CONSOLE_SCREEN_BUFFER_INFOEX()
- kernel32.GetConsoleScreenBufferInfoEx(
- hScreen, ctypes.byref(csbi))
- ncols = csbi.dwSize.X
- pos = csbi.dwCursorPosition
- length = ncols * pos.Y + pos.X + 1
- buf = (ctypes.c_wchar * length)()
- n = (wintypes.DWORD * 1)()
- kernel32.ReadConsoleOutputCharacterW(
- hScreen, buf, length, COORD(0,0), n)
- lines = [buf[i:i+ncols].rstrip(u'\0')
- for i in range(0, n[0], ncols)]
- return u'\n'.join(lines)
-
-@unittest.skipUnless(sys.platform == "win32", "requires Windows")
-class WindowsConsoleTest(DeviceTest):
- def test_unicode_output(self):
- """Test Unicode command line parameters and Unicode console window output.
-
- Bug: https://issuetracker.google.com/issues/111972753
- """
- # If we don't have a console window, allocate one. This isn't necessary if we're already
- # being run from a console window, which is typical.
- with allocate_console() as allocated_console:
- # Create a temporary console buffer and switch to it. We could also pass a parameter of
- # ncols=len(unicode_string), but it causes the window to flash as it is resized and
- # likely unnecessary given the typical console window size.
- with console_screen(nrows=1000) as screen:
- unicode_string = u'로보카 í´ë¦¬'
- # Run adb and allow it to detect that stdout is a console, not a pipe, by using
- # device.shell_popen() which does not use a pipe, unlike device.shell().
- process = self.device.shell_popen(['echo', '"' + unicode_string + '"'])
- process.wait()
- # Read what was written by adb to the temporary console buffer.
- console_output = read_screen(screen)
- self.assertEqual(unicode_string, console_output)
-
-
-def main():
- random.seed(0)
- if len(adb.get_devices()) > 0:
- suite = unittest.TestLoader().loadTestsFromName(__name__)
- unittest.TextTestRunner(verbosity=3).run(suite)
- else:
- print('Test suite must be run with attached devices')
-
-
-if __name__ == '__main__':
- main()
diff --git a/adb/tls/Android.bp b/adb/tls/Android.bp
deleted file mode 100644
index e5204f343..000000000
--- a/adb/tls/Android.bp
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright (C) 2020 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-cc_defaults {
- name: "libadb_tls_connection_defaults",
- cflags: [
- "-Wall",
- "-Wextra",
- "-Wthread-safety",
- "-Werror",
- ],
-
- compile_multilib: "both",
-
- srcs: [
- "adb_ca_list.cpp",
- "tls_connection.cpp",
- ],
- target: {
- windows: {
- compile_multilib: "first",
- enabled: true,
- },
- },
- export_include_dirs: ["include"],
-
- host_supported: true,
- recovery_available: true,
-
- visibility: [
- "//bootable/recovery/minadbd:__subpackages__",
- "//system/core/adb:__subpackages__",
- ],
-
- shared_libs: [
- "libbase",
- "libcrypto",
- "liblog",
- "libssl",
- ],
-}
-
-cc_library {
- name: "libadb_tls_connection",
- defaults: ["libadb_tls_connection_defaults"],
-
- apex_available: [
- "com.android.adbd",
- "test_com.android.adbd",
- ],
-}
-
-// For running atest (b/147158681)
-cc_library_static {
- name: "libadb_tls_connection_static",
- defaults: ["libadb_tls_connection_defaults"],
-
- apex_available: [
- "//apex_available:platform",
- ],
-}
diff --git a/adb/tls/adb_ca_list.cpp b/adb/tls/adb_ca_list.cpp
deleted file mode 100644
index 36afe4209..000000000
--- 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 <iomanip>
-#include <sstream>
-#include <vector>
-
-#include <android-base/logging.h>
-#include <android-base/strings.h>
-#include <openssl/ssl.h>
-
-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<unsigned char*>(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<std::string> 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<char> 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<X509_NAME> CreateCAIssuerFromEncodedKey(std::string_view key) {
- // "O=AdbKey-0;CN=<key>;"
- CHECK(!key.empty());
-
- std::string identifier = kAdbKeyIdentifierV0;
- bssl::UniquePtr<X509_NAME> name(X509_NAME_new());
- CHECK(X509_NAME_add_entry_by_NID_const(name.get(), kAdbKeyIdentifierNid, MBSTRING_ASC,
- reinterpret_cast<const uint8_t*>(identifier.data()),
- identifier.size(), -1, 0));
-
- CHECK(X509_NAME_add_entry_by_NID_const(name.get(), kAdbKeyValueNid, MBSTRING_ASC,
- reinterpret_cast<const uint8_t*>(key.data()), key.size(),
- -1, 0));
- return name;
-}
-
-// Parses a CA issuer and returns the encoded key, if any.
-std::optional<std::string> 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<size_t>(SHA256_DIGEST_LENGTH));
- std::stringstream ss;
- auto* u8 = reinterpret_cast<const uint8_t*>(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<uint16_t>(u8[i]);
- }
- return ss.str();
-}
-
-std::optional<std::string> 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<char>(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 a1ab9a779..000000000
--- 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 <openssl/base.h>
-#include <optional>
-#include <string>
-
-// 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<X509_NAME> CreateCAIssuerFromEncodedKey(std::string_view key);
-
-// Parses a CA issuer and returns the encoded key, if any. On failure, returns
-// nullopt.
-std::optional<std::string> 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<std::string> 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 bc5b98abf..000000000
--- 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 <stddef.h>
-#include <stdint.h>
-
-#include <string_view>
-#include <vector>
-
-#include <android-base/unique_fd.h>
-#include <openssl/ssl.h>
-#include <openssl/x509.h>
-
-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<int(X509_STORE_CTX*)>;
- using SetCertCb = std::function<int(SSL*)>;
-
- 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<uint8_t> 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<uint8_t> 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<TlsConnection> 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 198de58da..000000000
--- 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 c727e5f1a..000000000
--- 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 <gtest/gtest.h>
-
-#include <adb/tls/adb_ca_list.h>
-#include <android-base/logging.h>
-#include <android-base/strings.h>
-#include <openssl/ssl.h>
-
-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<std::string> 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 27bc1c928..000000000
--- 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 <thread>
-
-#include <gtest/gtest.h>
-
-#include <adb/crypto/rsa_2048_key.h>
-#include <adb/crypto/x509_generator.h>
-#include <adb/tls/adb_ca_list.h>
-#include <adb/tls/tls_connection.h>
-#include <android-base/logging.h>
-#include <android-base/strings.h>
-#include <android-base/unique_fd.h>
-#include <openssl/ssl.h>
-
-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<uint8_t> val;
-};
-using CAIssuer = std::vector<CAIssuerField>;
-static std::vector<CAIssuer> 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<STACK_OF(X509_NAME)> GetCAIssuerList() {
- bssl::UniquePtr<STACK_OF(X509_NAME)> ret(sk_X509_NAME_new_null());
- for (auto& issuer : kCAIssuers) {
- bssl::UniquePtr<X509_NAME> 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<uint8_t> msg_{0xff, 0xab, 0x32, 0xf6, 0x12, 0x56};
- std::unique_ptr<TlsConnection> server_;
- std::unique_ptr<TlsConnection> 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<const char*>(msg_.data()), msg_.size())));
- // Try with overloaded ReadFully
- std::vector<uint8_t> 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<const char*>(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<const char*>(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<const char*>(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<const char*>(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<const char*>(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<const char*>(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<const char*>(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<const char*>(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<const char*>(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<char*>(buf), buf_size),
- attr.val.size());
- std::vector<uint8_t> 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<STACK_OF(X509_NAME)> 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 853cdac08..000000000
--- 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 <algorithm>
-#include <vector>
-
-#include <android-base/logging.h>
-#include <android-base/strings.h>
-#include <openssl/err.h>
-#include <openssl/ssl.h>
-
-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<uint8_t> ExportKeyingMaterial(size_t length) override;
- void EnableClientPostHandshakeCheck(bool enable) override;
- TlsError DoHandshake() override;
- std::vector<uint8_t> ReadFully(size_t size) override;
- bool ReadFully(void* buf, size_t size) override;
- bool WriteFully(std::string_view data) override;
-
- static bssl::UniquePtr<EVP_PKEY> EvpPkeyFromPEM(std::string_view pem);
- static bssl::UniquePtr<CRYPTO_BUFFER> 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<X509> X509FromBuffer(bssl::UniquePtr<CRYPTO_BUFFER> buffer);
- static const char* SSLErrorString();
- void Invalidate();
- TlsError GetFailureReason(int err);
- const char* RoleToString() { return role_ == Role::Server ? kServerRoleStr : kClientRoleStr; }
-
- Role role_;
- bssl::UniquePtr<EVP_PKEY> priv_key_;
- bssl::UniquePtr<CRYPTO_BUFFER> cert_;
-
- bssl::UniquePtr<STACK_OF(X509_NAME)> ca_list_;
- bssl::UniquePtr<SSL_CTX> ssl_ctx_;
- bssl::UniquePtr<SSL> ssl_;
- std::vector<bssl::UniquePtr<X509>> 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<EVP_PKEY> TlsConnectionImpl::EvpPkeyFromPEM(std::string_view pem) {
- bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(pem.data(), pem.size()));
- return bssl::UniquePtr<EVP_PKEY>(PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr));
-}
-
-// static
-bssl::UniquePtr<CRYPTO_BUFFER> TlsConnectionImpl::BufferFromPEM(std::string_view pem) {
- bssl::UniquePtr<BIO> 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>(CRYPTO_BUFFER_new(data, data_len, nullptr));
- OPENSSL_free(data);
- return ret;
-}
-
-// static
-bssl::UniquePtr<X509> TlsConnectionImpl::X509FromBuffer(bssl::UniquePtr<CRYPTO_BUFFER> buffer) {
- if (!buffer) {
- return nullptr;
- }
- return bssl::UniquePtr<X509>(X509_parse_from_buffer(buffer.get()));
-}
-
-// static
-int TlsConnectionImpl::SSLSetCertVerifyCb(X509_STORE_CTX* ctx, void* opaque) {
- auto* p = reinterpret_cast<TlsConnectionImpl*>(opaque);
- return p->cert_verify_cb_(ctx);
-}
-
-// static
-int TlsConnectionImpl::SSLSetCertCb(SSL* ssl, void* opaque) {
- auto* p = reinterpret_cast<TlsConnectionImpl*>(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<uint8_t> TlsConnectionImpl::ExportKeyingMaterial(size_t length) {
- if (ssl_.get() == nullptr) {
- return {};
- }
-
- std::vector<uint8_t> 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<STACK_OF(X509_NAME)> 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<CRYPTO_BUFFER*> 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<uint8_t> TlsConnectionImpl::ReadFully(size_t size) {
- std::vector<uint8_t> 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<uint8_t*>(buf);
- while (size > 0) {
- int bytes_read =
- SSL_read(ssl_.get(), p8 + offset, std::min(static_cast<size_t>(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<size_t>(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> 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<TlsConnectionImpl>(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<CRYPTO_BUFFER*> 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 71e32b78f..000000000
--- a/adb/tools/Android.bp
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-cc_binary_host {
- name: "check_ms_os_desc",
-
- defaults: ["adb_defaults"],
-
- srcs: [
- "check_ms_os_desc.cpp",
- ],
-
- static_libs: [
- "libbase",
- "libusb",
- ],
-
- stl: "libc++_static",
-
- dist: {
- targets: [
- "sdk",
- ],
- },
-}
diff --git a/adb/tools/check_ms_os_desc.cpp b/adb/tools/check_ms_os_desc.cpp
deleted file mode 100644
index 8e858094a..000000000
--- 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 <err.h>
-#include <stdio.h>
-#include <unistd.h>
-
-#include <optional>
-#include <string>
-#include <vector>
-
-#include <libusb/libusb.h>
-
-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<std::vector<uint8_t>> get_descriptor(libusb_device_handle* handle,
- uint8_t type, uint8_t index,
- uint16_t length) {
- std::vector<uint8_t> 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<std::string> 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<uint8_t*>(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<uint8_t> 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<size_t>(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<std::string> 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 49e50264f..000000000
--- 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 fe286dee4..000000000
--- a/adb/transport.cpp
+++ /dev/null
@@ -1,1534 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define TRACE_TAG TRANSPORT
-
-#include "sysdeps.h"
-
-#include "transport.h"
-
-#include <ctype.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <algorithm>
-#include <deque>
-#include <list>
-#include <memory>
-#include <mutex>
-#include <set>
-#include <thread>
-
-#include <adb/crypto/rsa_2048_key.h>
-#include <adb/crypto/x509_generator.h>
-#include <adb/tls/tls_connection.h>
-#include <android-base/logging.h>
-#include <android-base/parsenetaddress.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-#include <android-base/thread_annotations.h>
-
-#include <diagnose_usb.h>
-
-#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<TransportId, atransport*>
-static auto& transport_list = *new std::list<atransport*>();
-static auto& pending_list = *new std::list<atransport*>();
-
-static auto& transport_lock = *new std::recursive_mutex();
-
-const char* const kFeatureShell2 = "shell_v2";
-const char* const kFeatureCmd = "cmd";
-const char* const kFeatureStat2 = "stat_v2";
-const char* const kFeatureLs2 = "ls_v2";
-const char* const kFeatureLibusb = "libusb";
-const char* const kFeaturePushSync = "push_sync";
-const char* const kFeatureApex = "apex";
-const char* const kFeatureFixedPushMkdir = "fixed_push_mkdir";
-const char* const kFeatureAbb = "abb";
-const char* const kFeatureFixedPushSymlinkTimestamp = "fixed_push_symlink_timestamp";
-const char* const kFeatureAbbExec = "abb_exec";
-const char* const kFeatureRemountShell = "remount_shell";
-const char* const kFeatureSendRecv2 = "sendrecv_v2";
-const char* const kFeatureSendRecv2Brotli = "sendrecv_v2_brotli";
-
-namespace {
-
-#if ADB_HOST
-// Tracks and handles atransport*s that are attempting reconnection.
-class ReconnectHandler {
- public:
- ReconnectHandler() = default;
- ~ReconnectHandler() = default;
-
- // Starts the ReconnectHandler thread.
- void Start();
-
- // Requests the ReconnectHandler thread to stop.
- void Stop();
-
- // Adds the atransport* to the queue of reconnect attempts.
- void TrackTransport(atransport* transport);
-
- // Wake up the ReconnectHandler thread to have it check for kicked transports.
- void CheckForKicked();
-
- private:
- // The main thread loop.
- void Run();
-
- // Tracks a reconnection attempt.
- struct ReconnectAttempt {
- atransport* transport;
- std::chrono::steady_clock::time_point reconnect_time;
- size_t attempts_left;
-
- bool operator<(const ReconnectAttempt& rhs) const {
- if (reconnect_time == rhs.reconnect_time) {
- return reinterpret_cast<uintptr_t>(transport) <
- reinterpret_cast<uintptr_t>(rhs.transport);
- }
- return reconnect_time < rhs.reconnect_time;
- }
- };
-
- // Only retry for up to one minute.
- static constexpr const std::chrono::seconds kDefaultTimeout = 10s;
- static constexpr const size_t kMaxAttempts = 6;
-
- // Protects all members.
- std::mutex reconnect_mutex_;
- bool running_ GUARDED_BY(reconnect_mutex_) = true;
- std::thread handler_thread_;
- std::condition_variable reconnect_cv_;
- std::set<ReconnectAttempt> 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<std::mutex> lock(reconnect_mutex_);
- running_ = false;
- }
- reconnect_cv_.notify_one();
- handler_thread_.join();
-
- // Drain the queue to free all resources.
- std::lock_guard<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<TransportId> next(1);
- return next++;
-}
-
-void Connection::Reset() {
- LOG(INFO) << "Connection::Reset(): stopping";
- Stop();
-}
-
-BlockingConnectionAdapter::BlockingConnectionAdapter(std::unique_ptr<BlockingConnection> connection)
- : underlying_(std::move(connection)) {}
-
-BlockingConnectionAdapter::~BlockingConnectionAdapter() {
- LOG(INFO) << "BlockingConnectionAdapter(" << this->transport_name_ << "): destructing";
- Stop();
-}
-
-void BlockingConnectionAdapter::Start() {
- std::lock_guard<std::mutex> 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<std::mutex> 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<apacket> 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<apacket>();
- 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<apacket> packet) {
- {
- std::lock_guard<std::mutex> 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<const char*>(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(EVP_PKEY_new());
- if (!EVP_PKEY_set1_RSA(evp_pkey.get(), key)) {
- LOG(ERROR) << "EVP_PKEY_set1_RSA failed";
- return false;
- }
- auto x509 = GenerateX509Certificate(evp_pkey.get());
- auto x509_str = X509ToPEMString(x509.get());
- auto evp_str = Key::ToPEMString(evp_pkey.get());
-#ifdef _WIN32
- int osh = cast_handle_to_int(adb_get_os_handle(fd_));
-#else
- int osh = adb_get_os_handle(fd_);
-#endif
-
-#if ADB_HOST
- tls_ = TlsConnection::Create(TlsConnection::Role::Client, x509_str, evp_str, osh);
-#else
- tls_ = TlsConnection::Create(TlsConnection::Role::Server, x509_str, evp_str, osh);
-#endif
- CHECK(tls_);
-#if ADB_HOST
- // TLS 1.3 gives the client no message if the server rejected the
- // certificate. This will enable a check in the tls connection to check
- // whether the client certificate got rejected. Note that this assumes
- // that, on handshake success, the server speaks first.
- tls_->EnableClientPostHandshakeCheck(true);
- // Add callback to set the certificate when server issues the
- // CertificateRequest.
- tls_->SetCertificateCallback(adb_tls_set_certificate);
- // Allow any server certificate
- tls_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; });
-#else
- // Add callback to check certificate against a list of known public keys
- tls_->SetCertVerifyCallback(
- [auth_key](X509_STORE_CTX* ctx) { return adbd_tls_verify_cert(ctx, auth_key); });
- // Add the list of allowed client CA issuers
- auto ca_list = adbd_tls_client_ca_list();
- tls_->SetClientCAList(ca_list.get());
-#endif
-
- auto err = tls_->DoHandshake();
- if (err == TlsError::Success) {
- return true;
- }
-
- tls_.reset();
- return false;
-}
-
-void FdConnection::Close() {
- adb_shutdown(fd_.get());
- fd_.reset();
-}
-
-void send_packet(apacket* p, atransport* t) {
- p->msg.magic = p->msg.command ^ 0xffffffff;
- // compute a checksum for connection/auth packets for compatibility reasons
- if (t->get_protocol_version() >= A_VERSION_SKIP_CHECKSUM) {
- p->msg.data_check = 0;
- } else {
- p->msg.data_check = calculate_apacket_checksum(p);
- }
-
- VLOG(TRANSPORT) << dump_packet(t->serial.c_str(), "to remote", p);
-
- if (t == nullptr) {
- LOG(FATAL) << "Transport is null";
- }
-
- if (t->Write(p) != 0) {
- D("%s: failed to enqueue packet, closing transport", t->serial.c_str());
- t->Kick();
- }
-}
-
-void kick_transport(atransport* t, bool reset) {
- std::lock_guard<std::recursive_mutex> 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<std::recursive_mutex> 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<int>(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<device_tracker*>(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<bool(const atransport*)> fn) {
- std::lock_guard<std::recursive_mutex> 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<std::recursive_mutex> 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<apacket> 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<std::recursive_mutex> 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<std::recursive_mutex> lock(transport_lock);
- for (auto t : transport_list) {
- t->Kick();
- }
-}
-
-void kick_all_tcp_tls_transports() {
- std::lock_guard<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> lock(transport_lock);
- LOG(INFO) << "destroying transport " << t->serial_name();
- t->connection()->Stop();
-#if ADB_HOST
- if (t->IsTcpDevice() && !t->kicked()) {
- D("transport: %s destroy (attempting reconnection)", t->serial.c_str());
-
- // We need to clear the transport's keys, so that on the next connection, it tries
- // again from the beginning.
- t->ResetKeys();
- reconnect_handler.TrackTransport(t);
- return;
- }
-#endif
-
- D("transport: %s destroy (kicking and closing)", t->serial.c_str());
- remove_transport(t);
-}
-
-static int qual_match(const std::string& to_test, const char* prefix, const std::string& qual,
- bool sanitize_qual) {
- if (to_test.empty()) /* Return true if both the qual and to_test are empty strings. */
- return qual.empty();
-
- if (qual.empty()) return 0;
-
- const char* ptr = to_test.c_str();
- if (prefix) {
- while (*prefix) {
- if (*prefix++ != *ptr++) return 0;
- }
- }
-
- for (char ch : qual) {
- if (sanitize_qual && !isalnum(ch)) ch = '_';
- if (ch != *ptr++) return 0;
- }
-
- /* Everything matched so far. Return true if *ptr is a NUL. */
- return !*ptr;
-}
-
-atransport* acquire_one_transport(TransportType type, const char* serial, TransportId transport_id,
- bool* is_ambiguous, std::string* error_out,
- bool accept_any_state) {
- atransport* result = nullptr;
-
- if (transport_id != 0) {
- *error_out =
- android::base::StringPrintf("no device with transport id '%" PRIu64 "'", transport_id);
- } else if (serial) {
- *error_out = android::base::StringPrintf("device '%s' not found", serial);
- } else if (type == kTransportLocal) {
- *error_out = "no emulators found";
- } else if (type == kTransportAny) {
- *error_out = "no devices/emulators found";
- } else {
- *error_out = "no devices found";
- }
-
- std::unique_lock<std::recursive_mutex> 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<std::mutex> 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<std::mutex> lock(mutex_);
- if (connection_established_ready_) return;
- connection_established_ready_ = true;
- connection_established_ = success;
- D("connection established with %d", success);
- }
- cv_.notify_one();
-}
-
-atransport::~atransport() {
- // If the connection callback had not been run before, run it now.
- SetConnectionEstablished(false);
-}
-
-int atransport::Write(apacket* p) {
- return this->connection()->Write(std::unique_ptr<apacket>(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> connection) {
- std::lock_guard<std::mutex> lock(mutex_);
- connection_ = std::shared_ptr<Connection>(std::move(connection));
-}
-
-std::string atransport::connection_state_name() const {
- ConnectionState state = GetConnectionState();
- switch (state) {
- case kCsOffline:
- return "offline";
- case kCsBootloader:
- return "bootloader";
- case kCsDevice:
- return "device";
- case kCsHost:
- return "host";
- case kCsRecovery:
- return "recovery";
- case kCsRescue:
- return "rescue";
- case kCsNoPerm:
- return UsbNoPermissionsShortHelpText();
- case kCsSideload:
- return "sideload";
- case kCsUnauthorized:
- return "unauthorized";
- case kCsAuthorizing:
- return "authorizing";
- case kCsConnecting:
- return "connecting";
- default:
- return "unknown";
- }
-}
-
-void atransport::update_version(int version, size_t payload) {
- protocol_version = std::min(version, A_VERSION);
- max_payload = std::min(payload, MAX_PAYLOAD);
-}
-
-int atransport::get_protocol_version() const {
- return protocol_version;
-}
-
-int atransport::get_tls_version() const {
- return tls_version;
-}
-
-size_t atransport::get_max_payload() const {
- return max_payload;
-}
-
-const FeatureSet& supported_features() {
- // Local static allocation to avoid global non-POD variables.
- static const FeatureSet* features = new FeatureSet{
- kFeatureShell2,
- kFeatureCmd,
- kFeatureStat2,
- kFeatureLs2,
- kFeatureFixedPushMkdir,
- kFeatureApex,
- kFeatureAbb,
- kFeatureFixedPushSymlinkTimestamp,
- kFeatureAbbExec,
- kFeatureRemountShell,
- kFeatureSendRecv2,
- kFeatureSendRecv2Brotli,
- // Increment ADB_SERVER_VERSION when adding a feature that adbd needs
- // to know about. Otherwise, the client can be stuck running an old
- // version of the server even after upgrading their copy of adb.
- // (http://b/24370690)
- };
-
- return *features;
-}
-
-std::string FeatureSetToString(const FeatureSet& features) {
- return android::base::Join(features, ',');
-}
-
-FeatureSet StringToFeatureSet(const std::string& features_string) {
- if (features_string.empty()) {
- return FeatureSet();
- }
-
- auto names = android::base::Split(features_string, ",");
- return FeatureSet(names.begin(), names.end());
-}
-
-bool CanUseFeature(const FeatureSet& feature_set, const std::string& feature) {
- return feature_set.count(feature) > 0 && supported_features().count(feature) > 0;
-}
-
-bool atransport::has_feature(const std::string& feature) const {
- return features_.count(feature) > 0;
-}
-
-void atransport::SetFeatures(const std::string& features_string) {
- features_ = StringToFeatureSet(features_string);
-}
-
-void atransport::AddDisconnect(adisconnect* disconnect) {
- disconnects_.push_back(disconnect);
-}
-
-void atransport::RemoveDisconnect(adisconnect* disconnect) {
- disconnects_.remove(disconnect);
-}
-
-void atransport::RunDisconnects() {
- for (const auto& disconnect : disconnects_) {
- disconnect->func(disconnect->opaque, this);
- }
- disconnects_.clear();
-}
-
-bool atransport::MatchesTarget(const std::string& target) const {
- if (!serial.empty()) {
- if (target == serial) {
- return true;
- } else if (type == kTransportLocal) {
- // Local transports can match [tcp:|udp:]<hostname>[:port].
- const char* local_target_ptr = target.c_str();
-
- // For fastboot compatibility, ignore protocol prefixes.
- if (android::base::StartsWith(target, "tcp:") ||
- android::base::StartsWith(target, "udp:")) {
- local_target_ptr += 4;
- }
-
- // Parse our |serial| and the given |target| to check if the hostnames and ports match.
- std::string serial_host, error;
- int serial_port = -1;
- if (android::base::ParseNetAddress(serial, &serial_host, &serial_port, nullptr, &error)) {
- // |target| may omit the port to default to ours.
- std::string target_host;
- int target_port = serial_port;
- if (android::base::ParseNetAddress(local_target_ptr, &target_host, &target_port,
- nullptr, &error) &&
- serial_host == target_host && serial_port == target_port) {
- return true;
- }
- }
- }
- }
-
- return (target == devpath) || qual_match(target, "product:", product, false) ||
- qual_match(target, "model:", model, true) ||
- qual_match(target, "device:", device, false);
-}
-
-void atransport::SetConnectionEstablished(bool success) {
- connection_waitable_->SetConnectionEstablished(success);
-}
-
-ReconnectResult atransport::Reconnect() {
- return reconnect_(this);
-}
-
-#if ADB_HOST
-
-// We use newline as our delimiter, make sure to never output it.
-static std::string sanitize(std::string str, bool alphanumeric) {
- auto pred = alphanumeric ? [](const char c) { return !isalnum(c); }
- : [](const char c) { return c == '\n'; };
- std::replace_if(str.begin(), str.end(), pred, '_');
- return str;
-}
-
-static void append_transport_info(std::string* result, const char* key, const std::string& value,
- bool alphanumeric) {
- if (value.empty()) {
- return;
- }
-
- *result += ' ';
- *result += key;
- *result += sanitize(value, alphanumeric);
-}
-
-static void append_transport(const atransport* t, std::string* result, bool long_listing) {
- std::string serial = t->serial;
- if (serial.empty()) {
- serial = "(no serial number)";
- }
-
- if (!long_listing) {
- *result += serial;
- *result += '\t';
- *result += t->connection_state_name();
- } else {
- android::base::StringAppendF(result, "%-22s %s", serial.c_str(),
- t->connection_state_name().c_str());
-
- append_transport_info(result, "", t->devpath, false);
- append_transport_info(result, "product:", t->product, false);
- append_transport_info(result, "model:", t->model, true);
- append_transport_info(result, "device:", t->device, false);
-
- // Put id at the end, so that anyone parsing the output here can always find it by scanning
- // backwards from newlines, even with hypothetical devices named 'transport_id:1'.
- *result += " transport_id:";
- *result += std::to_string(t->id);
- }
- *result += '\n';
-}
-
-std::string list_transports(bool long_listing) {
- std::lock_guard<std::recursive_mutex> 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<bool(const atransport*)> predicate, bool reset) {
- std::lock_guard<std::recursive_mutex> lock(transport_lock);
- for (auto& t : transport_list) {
- if (predicate(t)) {
- if (reset) {
- t->Reset();
- } else {
- t->Kick();
- }
- }
- }
-}
-
-/* hack for osx */
-void close_usb_devices(bool reset) {
- close_usb_devices([](const atransport*) { return true; }, reset);
-}
-#endif // ADB_HOST
-
-bool register_socket_transport(unique_fd s, std::string serial, int port, int local,
- atransport::ReconnectCallback reconnect, bool use_tls, int* error) {
- atransport* t = new atransport(std::move(reconnect), kCsOffline);
- t->use_tls = use_tls;
-
- D("transport: %s init'ing for socket %d, on port %d", serial.c_str(), s.get(), port);
- if (init_socket_transport(t, std::move(s), port, local) < 0) {
- delete t;
- if (error) *error = errno;
- return false;
- }
-
- std::unique_lock<std::recursive_mutex> lock(transport_lock);
- for (const auto& transport : pending_list) {
- if (serial == transport->serial) {
- VLOG(TRANSPORT) << "socket transport " << transport->serial
- << " is already in pending_list and fails to register";
- delete t;
- if (error) *error = EALREADY;
- return false;
- }
- }
-
- for (const auto& transport : transport_list) {
- if (serial == transport->serial) {
- VLOG(TRANSPORT) << "socket transport " << transport->serial
- << " is already in transport_list and fails to register";
- delete t;
- if (error) *error = EALREADY;
- return false;
- }
- }
-
- t->serial = std::move(serial);
- pending_list.push_front(t);
-
- lock.unlock();
-
- auto waitable = t->connection_waitable();
- register_transport(t);
-
- if (local == 1) {
- // Do not wait for emulator transports.
- return true;
- }
-
- if (!waitable->WaitForConnection(std::chrono::seconds(10))) {
- if (error) *error = ETIMEDOUT;
- return false;
- }
-
- if (t->GetConnectionState() == kCsUnauthorized) {
- if (error) *error = EPERM;
- return false;
- }
-
- return true;
-}
-
-#if ADB_HOST
-atransport* find_transport(const char* serial) {
- atransport* result = nullptr;
-
- std::lock_guard<std::recursive_mutex> 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<std::recursive_mutex> lock(transport_lock);
- for (auto& t : transport_list) {
- if (t->IsTcpDevice()) {
- // Kicking breaks the read_transport thread of this transport out of any read, then
- // the read_transport thread will notify the main thread to make this transport
- // offline. Then the main thread will notify the write_transport thread to exit.
- // Finally, this transport will be closed and freed in the main thread.
- t->Kick();
- }
- }
-#if ADB_HOST
- reconnect_handler.CheckForKicked();
-#endif
-}
-
-#endif
-
-#if ADB_HOST
-void register_usb_transport(usb_handle* usb, const char* serial, const char* devpath,
- unsigned writeable) {
- atransport* t = new atransport(writeable ? kCsOffline : kCsNoPerm);
-
- D("transport: %p init'ing for usb_handle %p (sn='%s')", t, usb, serial ? serial : "");
- init_usb_transport(t, usb);
- if (serial) {
- t->serial = serial;
- }
-
- if (devpath) {
- t->devpath = devpath;
- }
-
- {
- std::lock_guard<std::recursive_mutex> lock(transport_lock);
- pending_list.push_front(t);
- }
-
- register_transport(t);
-}
-#endif
-
-#if ADB_HOST
-// This should only be used for transports with connection_state == kCsNoPerm.
-void unregister_usb_transport(usb_handle* usb) {
- std::lock_guard<std::recursive_mutex> 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<RSA> atransport::Key() {
- if (keys_.empty()) {
- return nullptr;
- }
-
- std::shared_ptr<RSA> result = keys_[0];
- return result;
-}
-
-std::shared_ptr<RSA> atransport::NextKey() {
- if (keys_.empty()) {
- LOG(INFO) << "fetching keys for transport " << this->serial_name();
- keys_ = adb_auth_get_private_keys();
-
- // We should have gotten at least one key: the one that's automatically generated.
- CHECK(!keys_.empty());
- } else {
- keys_.pop_front();
- }
-
- std::shared_ptr<RSA> result = keys_[0];
- return result;
-}
-
-void atransport::ResetKeys() {
- keys_.clear();
-}
-#endif
diff --git a/adb/transport.h b/adb/transport.h
deleted file mode 100644
index 26d804b3f..000000000
--- a/adb/transport.h
+++ /dev/null
@@ -1,477 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __TRANSPORT_H
-#define __TRANSPORT_H
-
-#include <sys/types.h>
-
-#include <atomic>
-#include <chrono>
-#include <condition_variable>
-#include <deque>
-#include <functional>
-#include <list>
-#include <memory>
-#include <mutex>
-#include <optional>
-#include <string>
-#include <string_view>
-#include <thread>
-#include <unordered_set>
-
-#include <android-base/macros.h>
-#include <android-base/thread_annotations.h>
-#include <openssl/rsa.h>
-
-#include "adb.h"
-#include "adb_unique_fd.h"
-#include "types.h"
-
-typedef std::unordered_set<std::string> FeatureSet;
-
-namespace adb {
-namespace tls {
-
-class TlsConnection;
-
-} // namespace tls
-} // namespace adb
-
-const FeatureSet& supported_features();
-
-// Encodes and decodes FeatureSet objects into human-readable strings.
-std::string FeatureSetToString(const FeatureSet& features);
-FeatureSet StringToFeatureSet(const std::string& features_string);
-
-// Returns true if both local features and |feature_set| support |feature|.
-bool CanUseFeature(const FeatureSet& feature_set, const std::string& feature);
-
-// Do not use any of [:;=,] in feature strings, they have special meaning
-// in the connection banner.
-extern const char* const kFeatureShell2;
-// The 'cmd' command is available
-extern const char* const kFeatureCmd;
-extern const char* const kFeatureStat2;
-extern const char* const kFeatureLs2;
-// The server is running with libusb enabled.
-extern const char* const kFeatureLibusb;
-// adbd supports `push --sync`.
-extern const char* const kFeaturePushSync;
-// adbd supports installing .apex packages.
-extern const char* const kFeatureApex;
-// adbd has b/110953234 fixed.
-extern const char* const kFeatureFixedPushMkdir;
-// adbd supports android binder bridge (abb) in interactive mode using shell protocol.
-extern const char* const kFeatureAbb;
-// adbd supports abb using raw pipe.
-extern const char* const kFeatureAbbExec;
-// adbd properly updates symlink timestamps on push.
-extern const char* const kFeatureFixedPushSymlinkTimestamp;
-// Implement `adb remount` via shelling out to /system/bin/remount.
-extern const char* const kFeatureRemountShell;
-// adbd supports version 2 of send/recv.
-extern const char* const kFeatureSendRecv2;
-// adbd supports brotli for send/recv v2.
-extern const char* const kFeatureSendRecv2Brotli;
-
-TransportId NextTransportId();
-
-// Abstraction for a non-blocking packet transport.
-struct Connection {
- Connection() = default;
- virtual ~Connection() = default;
-
- void SetTransportName(std::string transport_name) {
- transport_name_ = std::move(transport_name);
- }
-
- using ReadCallback = std::function<bool(Connection*, std::unique_ptr<apacket>)>;
- 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(Connection*, const std::string&)>;
- void SetErrorCallback(ErrorCallback callback) {
- CHECK(!error_callback_);
- error_callback_ = callback;
- }
-
- virtual bool Write(std::unique_ptr<apacket> 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<Connection> 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<BlockingConnection> connection);
-
- virtual ~BlockingConnectionAdapter();
-
- virtual bool Write(std::unique_ptr<apacket> 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<BlockingConnection> underlying_;
- std::thread read_thread_ GUARDED_BY(mutex_);
- std::thread write_thread_ GUARDED_BY(mutex_);
-
- std::deque<std::unique_ptr<apacket>> 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<adb::tls::TlsConnection> 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<atransport> {
- 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<ReconnectResult(atransport*)>;
-
- atransport(ReconnectCallback reconnect, ConnectionState state)
- : id(NextTransportId()),
- kicked_(false),
- connection_state_(state),
- connection_waitable_(std::make_shared<ConnectionWaitable>()),
- connection_(nullptr),
- reconnect_(std::move(reconnect)) {
- // Initialize protocol to min version for compatibility with older versions.
- // Version will be updated post-connect.
- protocol_version = A_VERSION_MIN;
- max_payload = MAX_PAYLOAD;
- }
- atransport(ConnectionState state = kCsOffline)
- : atransport([](atransport*) { return ReconnectResult::Abort; }, state) {}
- ~atransport();
-
- int Write(apacket* p);
- void Reset();
- void Kick();
- bool kicked() const { return kicked_; }
-
- // ConnectionState can be read by all threads, but can only be written in the main thread.
- ConnectionState GetConnectionState() const;
- void SetConnectionState(ConnectionState state);
-
- void SetConnection(std::unique_ptr<Connection> connection);
- std::shared_ptr<Connection> connection() {
- std::lock_guard<std::mutex> 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<uint64_t> auth_id;
-#endif
-
- bool IsTcpDevice() const { return type == kTransportLocal; }
-
-#if ADB_HOST
- // The current key being authorized.
- std::shared_ptr<RSA> Key();
- std::shared_ptr<RSA> NextKey();
- void ResetKeys();
-#endif
-
- char token[TOKEN_SIZE] = {};
- size_t failed_auth_attempts = 0;
-
- std::string serial_name() const { return !serial.empty() ? serial : "<unknown>"; }
- std::string connection_state_name() const;
-
- void update_version(int version, size_t payload);
- int get_protocol_version() const;
- size_t get_max_payload() const;
-
- const FeatureSet& features() const {
- return features_;
- }
-
- bool has_feature(const std::string& feature) const;
-
- // Loads the transport's feature set from the given string.
- void SetFeatures(const std::string& features_string);
-
- void AddDisconnect(adisconnect* disconnect);
- void RemoveDisconnect(adisconnect* disconnect);
- void RunDisconnects();
-
- // Returns true if |target| matches this transport. A matching |target| can be any of:
- // * <serial>
- // * <devpath>
- // * product:<product>
- // * model:<model>
- // * device:<device>
- //
- // If this is a local transport, serial will also match [tcp:|udp:]<hostname>[: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<ConnectionWaitable> connection_waitable() { return connection_waitable_; }
-
- // Attempts to reconnect with the underlying Connection.
- ReconnectResult Reconnect();
-
- private:
- std::atomic<bool> 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<adisconnect*> disconnects_;
-
- std::atomic<ConnectionState> connection_state_;
-#if ADB_HOST
- std::deque<std::shared_ptr<RSA>> keys_;
-#endif
-
- // A sharable object that can be used to wait for the atransport's
- // connection to be established.
- std::shared_ptr<ConnectionWaitable> connection_waitable_;
-
- // The underlying connection object.
- std::shared_ptr<Connection> 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<bool(const atransport*)> fn);
-
-void init_reconnect_handler(void);
-void init_transport_registration(void);
-void init_mdns_transport_discovery(void);
-std::string list_transports(bool long_listing);
-atransport* find_transport(const char* serial);
-void kick_all_tcp_devices();
-void kick_all_transports();
-void kick_all_tcp_tls_transports();
-#if !ADB_HOST
-void kick_all_transports_by_auth_key(std::string_view auth_key);
-#endif
-
-void register_transport(atransport* transport);
-
-#if ADB_HOST
-void init_usb_transport(atransport* t, usb_handle* usb);
-void register_usb_transport(usb_handle* h, const char* serial, const char* devpath,
- unsigned writeable);
-
-// This should only be used for transports with connection_state == kCsNoPerm.
-void unregister_usb_transport(usb_handle* usb);
-#endif
-
-/* Connect to a network address and register it as a device */
-void connect_device(const std::string& address, std::string* response);
-
-/* cause new transports to be init'd and added to the list */
-bool register_socket_transport(unique_fd s, std::string serial, int port, int local,
- atransport::ReconnectCallback reconnect, bool use_tls,
- int* error = nullptr);
-
-bool check_header(apacket* p, atransport* t);
-
-void close_usb_devices(bool reset = false);
-void close_usb_devices(std::function<bool(const atransport*)> 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<unique_fd(std::string_view, std::string*)> 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 022808f29..000000000
--- 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 <malloc.h>
-#include <stdio.h>
-
-#include <android-base/logging.h>
-#include <benchmark/benchmark.h>
-
-#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 <typename ConnectionType>
-std::unique_ptr<Connection> MakeConnection(unique_fd fd);
-
-template <>
-std::unique_ptr<Connection> MakeConnection<FdConnection>(unique_fd fd) {
- auto fd_connection = std::make_unique<FdConnection>(std::move(fd));
- return std::make_unique<BlockingConnectionAdapter>(std::move(fd_connection));
-}
-
-template <>
-std::unique_ptr<Connection> MakeConnection<NonblockingFdConnection>(unique_fd fd) {
- return Connection::FromFd(std::move(fd));
-}
-
-template <typename ConnectionType>
-void BM_Connection_Unidirectional(benchmark::State& state) {
- int fds[2];
- if (adb_socketpair(fds) != 0) {
- LOG(FATAL) << "failed to create socketpair";
- }
-
- auto client = MakeConnection<ConnectionType>(unique_fd(fds[0]));
- auto server = MakeConnection<ConnectionType>(unique_fd(fds[1]));
-
- std::atomic<size_t> received_bytes;
-
- client->SetReadCallback([](Connection*, std::unique_ptr<apacket>) -> bool { return true; });
- server->SetReadCallback([&received_bytes](Connection*, std::unique_ptr<apacket> 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<apacket> packet = std::make_unique<apacket>();
- 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<int64_t>(state.iterations()) * state.range(0));
-
- client->Stop();
- server->Stop();
-}
-
-ADB_CONNECTION_BENCHMARK(BM_Connection_Unidirectional);
-
-enum class ThreadPolicy {
- MainThread,
- SameThread,
-};
-
-template <typename ConnectionType, enum ThreadPolicy Policy>
-void BM_Connection_Echo(benchmark::State& state) {
- int fds[2];
- if (adb_socketpair(fds) != 0) {
- LOG(FATAL) << "failed to create socketpair";
- }
-
- auto client = MakeConnection<ConnectionType>(unique_fd(fds[0]));
- auto server = MakeConnection<ConnectionType>(unique_fd(fds[1]));
-
- std::atomic<size_t> received_bytes;
-
- fdevent_reset();
- std::thread fdevent_thread([]() { fdevent_loop(); });
-
- client->SetReadCallback([&received_bytes](Connection*, std::unique_ptr<apacket> packet) -> bool {
- received_bytes += packet->payload.size();
- return true;
- });
-
- static const auto handle_packet = [](Connection* connection, std::unique_ptr<apacket> packet) {
- connection->Write(std::move(packet));
- };
-
- server->SetReadCallback([](Connection* connection, std::unique_ptr<apacket> packet) -> bool {
- if (Policy == ThreadPolicy::MainThread) {
- auto raw_packet = packet.release();
- fdevent_run_on_main_thread([connection, raw_packet]() {
- std::unique_ptr<apacket> 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<apacket> packet = std::make_unique<apacket>();
- 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<int64_t>(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 b9b4f42b9..000000000
--- 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 <stdint.h>
-
-#include <deque>
-#include <memory>
-#include <mutex>
-#include <string>
-#include <thread>
-
-#include <android-base/logging.h>
-#include <android-base/stringprintf.h>
-#include <android-base/thread_annotations.h>
-
-#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<std::mutex> lock(run_mutex_);
- running_ = value;
- }
-
- bool IsRunning() {
- std::lock_guard<std::mutex> 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<std::mutex> 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<std::mutex> 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<amessage>();
- 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<apacket>();
- 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<int>(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<apacket> packet) final {
- std::lock_guard<std::mutex> lock(write_mutex_);
- const char* header_begin = reinterpret_cast<const char*>(&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<bool> started_;
- std::mutex run_mutex_;
- bool running_ GUARDED_BY(run_mutex_);
-
- std::unique_ptr<amessage> 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> Connection::FromFd(unique_fd fd) {
- return std::make_unique<NonblockingFdConnection>(std::move(fd));
-}
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
deleted file mode 100644
index 5ec8e1665..000000000
--- a/adb/transport_local.cpp
+++ /dev/null
@@ -1,389 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define TRACE_TAG TRANSPORT
-
-#include "sysdeps.h"
-#include "transport.h"
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-
-#include <condition_variable>
-#include <functional>
-#include <memory>
-#include <mutex>
-#include <thread>
-#include <unordered_map>
-#include <vector>
-
-#include <android-base/parsenetaddress.h>
-#include <android-base/stringprintf.h>
-#include <android-base/thread_annotations.h>
-#include <cutils/sockets.h>
-
-#if !ADB_HOST
-#include <android-base/properties.h>
-#endif
-
-#include "adb.h"
-#include "adb_io.h"
-#include "adb_unique_fd.h"
-#include "adb_utils.h"
-#include "socket_spec.h"
-#include "sysdeps/chrono.h"
-
-#if ADB_HOST
-
-// Android Wear has been using port 5601 in all of its documentation/tooling,
-// but we search for emulators on ports [5554, 5555 + ADB_LOCAL_TRANSPORT_MAX].
-// Avoid stomping on their port by restricting the active scanning range.
-// Once emulators self-(re-)register, they'll have to avoid 5601 in their own way.
-static int adb_local_transport_max_port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT + 16 * 2 - 1;
-
-static std::mutex& local_transports_lock = *new std::mutex();
-
-static void adb_local_transport_max_port_env_override() {
- const char* env_max_s = getenv("ADB_LOCAL_TRANSPORT_MAX_PORT");
- if (env_max_s != nullptr) {
- size_t env_max;
- if (ParseUint(&env_max, env_max_s, nullptr) && env_max < 65536) {
- // < DEFAULT_ADB_LOCAL_TRANSPORT_PORT harmlessly mimics ADB_EMU=0
- adb_local_transport_max_port = env_max;
- D("transport: ADB_LOCAL_TRANSPORT_MAX_PORT read as %d", adb_local_transport_max_port);
- } else {
- D("transport: ADB_LOCAL_TRANSPORT_MAX_PORT '%s' invalid or >= 65536, so ignored",
- env_max_s);
- }
- }
-}
-
-// We keep a map from emulator port to transport.
-// TODO: weak_ptr?
-static auto& local_transports GUARDED_BY(local_transports_lock) =
- *new std::unordered_map<int, atransport*>();
-#endif /* ADB_HOST */
-
-bool local_connect(int port) {
- std::string dummy;
- return local_connect_arbitrary_ports(port - 1, port, &dummy) == 0;
-}
-
-void connect_device(const std::string& address, std::string* response) {
- if (address.empty()) {
- *response = "empty address";
- return;
- }
-
- D("connection requested to '%s'", address.c_str());
- unique_fd fd;
- int port;
- std::string serial, prefix_addr;
-
- // If address does not match any socket type, it should default to TCP.
- if (address.starts_with("vsock:") || address.starts_with("localfilesystem:")) {
- prefix_addr = address;
- } else {
- prefix_addr = "tcp:" + address;
- }
-
- socket_spec_connect(&fd, prefix_addr, &port, &serial, response);
- if (fd.get() == -1) {
- return;
- }
- auto reconnect = [prefix_addr](atransport* t) {
- std::string response;
- unique_fd fd;
- int port;
- std::string serial;
- socket_spec_connect(&fd, prefix_addr, &port, &serial, &response);
- if (fd == -1) {
- D("reconnect failed: %s", response.c_str());
- return ReconnectResult::Retry;
- }
- // This invokes the part of register_socket_transport() that needs to be
- // invoked if the atransport* has already been setup. This eventually
- // calls atransport->SetConnection() with a newly created Connection*
- // that will in turn send the CNXN packet.
- return init_socket_transport(t, std::move(fd), port, 0) >= 0 ? ReconnectResult::Success
- : ReconnectResult::Retry;
- };
-
- int error;
- if (!register_socket_transport(std::move(fd), serial, port, 0, std::move(reconnect), false,
- &error)) {
- if (error == EALREADY) {
- *response = android::base::StringPrintf("already connected to %s", serial.c_str());
- } else if (error == EPERM) {
- *response = android::base::StringPrintf("failed to authenticate to %s", serial.c_str());
- } else {
- *response = android::base::StringPrintf("failed to connect to %s", serial.c_str());
- }
- } else {
- *response = android::base::StringPrintf("connected to %s", serial.c_str());
- }
-}
-
-
-int local_connect_arbitrary_ports(int console_port, int adb_port, std::string* error) {
- unique_fd fd;
-
-#if ADB_HOST
- if (find_emulator_transport_by_adb_port(adb_port) != nullptr ||
- find_emulator_transport_by_console_port(console_port) != nullptr) {
- return -1;
- }
-
- const char *host = getenv("ADBHOST");
- if (host) {
- fd.reset(network_connect(host, adb_port, SOCK_STREAM, 0, error));
- }
-#endif
- if (fd < 0) {
- fd.reset(network_loopback_client(adb_port, SOCK_STREAM, error));
- }
-
- if (fd >= 0) {
- D("client: connected on remote on fd %d", fd.get());
- close_on_exec(fd.get());
- disable_tcp_nagle(fd.get());
- std::string serial = getEmulatorSerialString(console_port);
- if (register_socket_transport(
- std::move(fd), std::move(serial), adb_port, 1,
- [](atransport*) { return ReconnectResult::Abort; }, false)) {
- return 0;
- }
- }
- return -1;
-}
-
-#if ADB_HOST
-
-static void PollAllLocalPortsForEmulator() {
- // Try to connect to any number of running emulator instances.
- for (int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT; port <= adb_local_transport_max_port;
- port += 2) {
- local_connect(port); // Note, uses port and port-1, so '=max_port' is OK.
- }
-}
-
-// Retry the disconnected local port for 60 times, and sleep 1 second between two retries.
-static constexpr uint32_t LOCAL_PORT_RETRY_COUNT = 60;
-static constexpr auto LOCAL_PORT_RETRY_INTERVAL = 1s;
-
-struct RetryPort {
- int port;
- uint32_t retry_count;
-};
-
-// Retry emulators just kicked.
-static std::vector<RetryPort>& retry_ports = *new std::vector<RetryPort>;
-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<RetryPort> ports;
- // Collect retry ports.
- {
- std::unique_lock<std::mutex> 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<RetryPort> 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<std::mutex> lock(retry_ports_lock);
- retry_ports.insert(retry_ports.end(), next_ports.begin(), next_ports.end());
- }
- }
-}
-
-#else // !ADB_HOST
-
-void server_socket_thread(std::function<unique_fd(std::string_view, std::string*)> listen_func,
- std::string_view addr) {
- adb_thread_setname("server socket");
-
- unique_fd serverfd;
- std::string error;
-
- while (serverfd == -1) {
- errno = 0;
- serverfd = listen_func(addr, &error);
- if (errno == EAFNOSUPPORT || errno == EINVAL || errno == EPROTONOSUPPORT) {
- D("unrecoverable error: '%s'", error.c_str());
- return;
- } else if (serverfd < 0) {
- D("server: cannot bind socket yet: %s", error.c_str());
- std::this_thread::sleep_for(1s);
- continue;
- }
- close_on_exec(serverfd.get());
- }
-
- while (true) {
- D("server: trying to get new connection from fd %d", serverfd.get());
- unique_fd fd(adb_socket_accept(serverfd, nullptr, nullptr));
- if (fd >= 0) {
- D("server: new connection on fd %d", fd.get());
- close_on_exec(fd.get());
- disable_tcp_nagle(fd.get());
- std::string serial = android::base::StringPrintf("host-%d", fd.get());
- // We don't care about port value in "register_socket_transport" as it is used
- // only from ADB_HOST. "server_socket_thread" is never called from ADB_HOST.
- register_socket_transport(
- std::move(fd), std::move(serial), 0, 1,
- [](atransport*) { return ReconnectResult::Abort; }, false);
- }
- }
- D("transport: server_socket_thread() exiting");
-}
-
-#endif
-
-#if !ADB_HOST
-unique_fd adb_listen(std::string_view addr, std::string* error) {
- return unique_fd{socket_spec_listen(addr, error, nullptr)};
-}
-#endif
-
-void local_init(const std::string& addr) {
-#if ADB_HOST
- D("transport: local client init");
- std::thread(client_socket_thread, addr).detach();
- adb_local_transport_max_port_env_override();
-#elif !defined(__ANDROID__)
- // Host adbd.
- D("transport: local server init");
- std::thread(server_socket_thread, adb_listen, addr).detach();
-#else
- D("transport: local server init");
- // For the adbd daemon in the system image we need to distinguish
- // between the device, and the emulator.
- if (addr.starts_with("tcp:") && use_qemu_goldfish()) {
- std::thread(qemu_socket_thread, addr).detach();
- } else {
- std::thread(server_socket_thread, adb_listen, addr).detach();
- }
-#endif // !ADB_HOST
-}
-
-#if ADB_HOST
-struct EmulatorConnection : public FdConnection {
- EmulatorConnection(unique_fd fd, int local_port)
- : FdConnection(std::move(fd)), local_port_(local_port) {}
-
- ~EmulatorConnection() {
- VLOG(TRANSPORT) << "remote_close, local_port = " << local_port_;
- std::unique_lock<std::mutex> 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<std::mutex> 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<std::mutex> lock(local_transports_lock);
- return find_emulator_transport_by_adb_port_locked(adb_port);
-}
-
-atransport* find_emulator_transport_by_console_port(int console_port) {
- return find_transport(getEmulatorSerialString(console_port).c_str());
-}
-#endif
-
-std::string getEmulatorSerialString(int console_port) {
- return android::base::StringPrintf("emulator-%d", console_port);
-}
-
-int init_socket_transport(atransport* t, unique_fd fd, int adb_port, int local) {
- int fail = 0;
-
- t->type = kTransportLocal;
-
-#if ADB_HOST
- // Emulator connection.
- if (local) {
- auto emulator_connection = std::make_unique<EmulatorConnection>(std::move(fd), adb_port);
- t->SetConnection(
- std::make_unique<BlockingConnectionAdapter>(std::move(emulator_connection)));
- std::lock_guard<std::mutex> lock(local_transports_lock);
- atransport* existing_transport = find_emulator_transport_by_adb_port_locked(adb_port);
- if (existing_transport != nullptr) {
- D("local transport for port %d already registered (%p)?", adb_port, existing_transport);
- fail = -1;
- } else {
- local_transports[adb_port] = t;
- }
-
- return fail;
- }
-#endif
-
- // Regular tcp connection.
- auto fd_connection = std::make_unique<FdConnection>(std::move(fd));
- t->SetConnection(std::make_unique<BlockingConnectionAdapter>(std::move(fd_connection)));
- return fail;
-}
diff --git a/adb/transport_test.cpp b/adb/transport_test.cpp
deleted file mode 100644
index 00beb3a2b..000000000
--- a/adb/transport_test.cpp
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "transport.h"
-
-#include <gtest/gtest.h>
-
-#include "adb.h"
-#include "fdevent/fdevent_test.h"
-
-struct TransportTest : public FdeventTest {};
-
-static void DisconnectFunc(void* arg, atransport*) {
- int* count = reinterpret_cast<int*>(arg);
- ++*count;
-}
-
-TEST_F(TransportTest, RunDisconnects) {
- atransport t;
- // RunDisconnects() can be called with an empty atransport.
- t.RunDisconnects();
-
- int count = 0;
- adisconnect disconnect;
- disconnect.func = DisconnectFunc;
- disconnect.opaque = &count;
- t.AddDisconnect(&disconnect);
- t.RunDisconnects();
- ASSERT_EQ(1, count);
-
- // disconnect should have been removed automatically.
- t.RunDisconnects();
- ASSERT_EQ(1, count);
-
- count = 0;
- t.AddDisconnect(&disconnect);
- t.RemoveDisconnect(&disconnect);
- t.RunDisconnects();
- ASSERT_EQ(0, count);
-}
-
-TEST_F(TransportTest, SetFeatures) {
- atransport t;
- ASSERT_EQ(0U, t.features().size());
-
- t.SetFeatures(FeatureSetToString(FeatureSet{"foo"}));
- ASSERT_EQ(1U, t.features().size());
- ASSERT_TRUE(t.has_feature("foo"));
-
- t.SetFeatures(FeatureSetToString(FeatureSet{"foo", "bar"}));
- ASSERT_EQ(2U, t.features().size());
- ASSERT_TRUE(t.has_feature("foo"));
- ASSERT_TRUE(t.has_feature("bar"));
-
- t.SetFeatures(FeatureSetToString(FeatureSet{"foo", "bar", "foo"}));
- ASSERT_EQ(2U, t.features().size());
- ASSERT_TRUE(t.has_feature("foo"));
- ASSERT_TRUE(t.has_feature("bar"));
-
- t.SetFeatures(FeatureSetToString(FeatureSet{"bar", "baz"}));
- ASSERT_EQ(2U, t.features().size());
- ASSERT_FALSE(t.has_feature("foo"));
- ASSERT_TRUE(t.has_feature("bar"));
- ASSERT_TRUE(t.has_feature("baz"));
-
- t.SetFeatures("");
- ASSERT_EQ(0U, t.features().size());
-}
-
-TEST_F(TransportTest, parse_banner_no_features) {
- atransport t;
-
- parse_banner("host::", &t);
-
- ASSERT_EQ(0U, t.features().size());
- ASSERT_EQ(kCsHost, t.GetConnectionState());
-
- ASSERT_EQ(std::string(), t.product);
- ASSERT_EQ(std::string(), t.model);
- ASSERT_EQ(std::string(), t.device);
-}
-
-TEST_F(TransportTest, parse_banner_product_features) {
- atransport t;
-
- const char banner[] =
- "host::ro.product.name=foo;ro.product.model=bar;ro.product.device=baz;";
- parse_banner(banner, &t);
-
- ASSERT_EQ(kCsHost, t.GetConnectionState());
-
- ASSERT_EQ(0U, t.features().size());
-
- ASSERT_EQ(std::string("foo"), t.product);
- ASSERT_EQ(std::string("bar"), t.model);
- ASSERT_EQ(std::string("baz"), t.device);
-}
-
-TEST_F(TransportTest, parse_banner_features) {
- atransport t;
- const char banner[] =
- "host::ro.product.name=foo;ro.product.model=bar;ro.product.device=baz;"
- "features=woodly,doodly";
- parse_banner(banner, &t);
-
- ASSERT_EQ(kCsHost, t.GetConnectionState());
-
- ASSERT_EQ(2U, t.features().size());
- ASSERT_TRUE(t.has_feature("woodly"));
- ASSERT_TRUE(t.has_feature("doodly"));
-
- ASSERT_EQ(std::string("foo"), t.product);
- ASSERT_EQ(std::string("bar"), t.model);
- ASSERT_EQ(std::string("baz"), t.device);
-}
-
-TEST_F(TransportTest, test_matches_target) {
- std::string serial = "foo";
- std::string devpath = "/path/to/bar";
- std::string product = "test_product";
- std::string model = "test_model";
- std::string device = "test_device";
-
- atransport t;
- t.serial = &serial[0];
- t.devpath = &devpath[0];
- t.product = &product[0];
- t.model = &model[0];
- t.device = &device[0];
-
- // These tests should not be affected by the transport type.
- for (TransportType type : {kTransportAny, kTransportLocal}) {
- t.type = type;
-
- EXPECT_TRUE(t.MatchesTarget(serial));
- EXPECT_TRUE(t.MatchesTarget(devpath));
- EXPECT_TRUE(t.MatchesTarget("product:" + product));
- EXPECT_TRUE(t.MatchesTarget("model:" + model));
- EXPECT_TRUE(t.MatchesTarget("device:" + device));
-
- // Product, model, and device don't match without the prefix.
- EXPECT_FALSE(t.MatchesTarget(product));
- EXPECT_FALSE(t.MatchesTarget(model));
- EXPECT_FALSE(t.MatchesTarget(device));
- }
-}
-
-TEST_F(TransportTest, test_matches_target_local) {
- std::string serial = "100.100.100.100:5555";
-
- atransport t;
- t.serial = &serial[0];
-
- // Network address matching should only be used for local transports.
- for (TransportType type : {kTransportAny, kTransportLocal}) {
- t.type = type;
- bool should_match = (type == kTransportLocal);
-
- EXPECT_EQ(should_match, t.MatchesTarget("100.100.100.100"));
- EXPECT_EQ(should_match, t.MatchesTarget("tcp:100.100.100.100"));
- EXPECT_EQ(should_match, t.MatchesTarget("tcp:100.100.100.100:5555"));
- EXPECT_EQ(should_match, t.MatchesTarget("udp:100.100.100.100"));
- EXPECT_EQ(should_match, t.MatchesTarget("udp:100.100.100.100:5555"));
-
- // Wrong protocol, hostname, or port should never match.
- EXPECT_FALSE(t.MatchesTarget("100.100.100"));
- EXPECT_FALSE(t.MatchesTarget("100.100.100.100:"));
- EXPECT_FALSE(t.MatchesTarget("100.100.100.100:-1"));
- EXPECT_FALSE(t.MatchesTarget("100.100.100.100:5554"));
- EXPECT_FALSE(t.MatchesTarget("abc:100.100.100.100"));
- }
-}
diff --git a/adb/types.cpp b/adb/types.cpp
deleted file mode 100644
index 26b77ab62..000000000
--- 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<size_t>(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<const IOVector*>(this)->coalesce<>();
-}
-
-std::vector<adb_iovec> IOVector::iovecs() const {
- std::vector<adb_iovec> result;
- result.reserve(chain_.size() - start_index_);
- iterate_blocks([&result](const char* data, size_t len) {
- adb_iovec iov;
- iov.iov_base = const_cast<char*>(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 deca7eafb..000000000
--- 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 <string.h>
-
-#include <algorithm>
-#include <memory>
-#include <utility>
-#include <vector>
-
-#include <android-base/logging.h>
-
-#include "fdevent/fdevent.h"
-#include "sysdeps/uio.h"
-
-// Essentially std::vector<char>, except without zero initialization or reallocation.
-struct Block {
- using iterator = char*;
-
- Block() = default;
-
- explicit Block(size_t size) { allocate(size); }
-
- template <typename Iterator>
- 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 <typename InputIt>
- 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<char[]> data_;
- size_t capacity_ = 0;
- size_t size_ = 0;
-};
-
-struct amessage {
- uint32_t command; /* command identifier constant */
- uint32_t arg0; /* first argument */
- uint32_t arg1; /* second argument */
- uint32_t data_length; /* length of payload (0 is allowed) */
- uint32_t data_check; /* checksum of data payload */
- uint32_t magic; /* command ^ 0xffffffff */
-};
-
-struct apacket {
- using payload_type = Block;
- amessage msg;
- payload_type payload;
-};
-
-struct IOVector {
- using value_type = char;
- using block_type = Block;
- using size_type = size_t;
-
- IOVector() = default;
-
- explicit IOVector(block_type&& block) { append(std::move(block)); }
-
- IOVector(const IOVector& copy) = delete;
- IOVector(IOVector&& move) noexcept : IOVector() { *this = std::move(move); }
-
- IOVector& operator=(const IOVector& copy) = delete;
- IOVector& operator=(IOVector&& move) noexcept;
-
- const value_type* front_data() const {
- if (chain_.empty()) {
- return nullptr;
- }
-
- return chain_.front().data() + begin_offset_;
- }
-
- size_type front_size() const {
- if (chain_.empty()) {
- return 0;
- }
-
- return chain_.front().size() - begin_offset_;
- }
-
- size_type size() const { return chain_length_ - begin_offset_; }
- bool empty() const { return size() == 0; }
-
- // Return the last block so the caller can still reuse its allocated capacity
- // or it can be simply ignored.
- block_type clear();
-
- void drop_front(size_type len);
-
- // Split the first |len| bytes out of this chain into its own.
- IOVector take_front(size_type len);
-
- // Add a nonempty block to the chain.
- void append(block_type&& block) {
- if (block.size() == 0) {
- return;
- }
- CHECK_NE(0ULL, block.size());
- chain_length_ += block.size();
- chain_.emplace_back(std::move(block));
- }
-
- void trim_front();
-
- private:
- void trim_chain_front();
-
- // Drop the front block from the chain, and update chain_length_ appropriately.
- void pop_front_block();
-
- // Iterate over the blocks with a callback with an operator()(const char*, size_t).
- template <typename Fn>
- 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 <typename CollectionType = block_type>
- 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 <typename FunctionType>
- 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<adb_iovec> 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<block_type> 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 <typename T>
-struct enable_weak_from_this;
-
-template <typename T>
-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 (&copy == 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>;
- T* ptr_ = nullptr;
-};
-
-template <typename T>
-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<T> weak() { return weak_ptr<T>(static_cast<T*>(this)); }
-
- void schedule_deletion() {
- fdevent_run_on_main_thread([this]() { delete this; });
- }
-
- private:
- friend struct weak_ptr<T>;
- std::vector<weak_ptr<T>*> weak_ptrs_;
-};
diff --git a/adb/types_test.cpp b/adb/types_test.cpp
deleted file mode 100644
index 2c99f9512..000000000
--- a/adb/types_test.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <gtest/gtest.h>
-
-#include <memory>
-#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 <typename T>
-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());
-}
diff --git a/base/Android.bp b/base/Android.bp
index 4556f9bf1..3d96e4209 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -108,6 +108,7 @@ cc_defaults {
enabled: true,
},
},
+ min_sdk_version: "29",
}
cc_library {
@@ -133,7 +134,6 @@ cc_library {
"//apex_available:anyapex",
"//apex_available:platform",
],
- min_sdk_version: "29",
}
cc_library_static {
diff --git a/init/lmkd_service.cpp b/init/lmkd_service.cpp
index dd1ab4d61..c982925ad 100644
--- a/init/lmkd_service.cpp
+++ b/init/lmkd_service.cpp
@@ -79,7 +79,7 @@ static bool UnregisterProcess(pid_t pid) {
}
static void RegisterServices(pid_t exclude_pid) {
- for (const auto& service : ServiceList::GetInstance().services()) {
+ for (const auto& service : ServiceList::GetInstance()) {
auto svc = service.get();
if (svc->oom_score_adjust() != DEFAULT_OOM_SCORE_ADJUST) {
// skip if process is excluded or not yet forked (pid==0)
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 23a07aa64..a4fb08e0b 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -85,12 +85,11 @@ static bool shutting_down = false;
static const std::set<std::string> kDebuggingServices{"tombstoned", "logd", "adbd", "console"};
-static std::vector<Service*> GetDebuggingServices(bool only_post_data) {
- std::vector<Service*> ret;
- ret.reserve(kDebuggingServices.size());
+static std::set<std::string> GetPostDataDebuggingServices() {
+ std::set<std::string> ret;
for (const auto& s : ServiceList::GetInstance()) {
- if (kDebuggingServices.count(s->name()) && (!only_post_data || s->is_post_data())) {
- ret.push_back(s.get());
+ if (kDebuggingServices.count(s->name()) && s->is_post_data()) {
+ ret.insert(s->name());
}
}
return ret;
@@ -503,13 +502,18 @@ static Result<void> KillZramBackingDevice() {
// Stops given services, waits for them to be stopped for |timeout| ms.
// If terminate is true, then SIGTERM is sent to services, otherwise SIGKILL is sent.
-static void StopServices(const std::vector<Service*>& services, std::chrono::milliseconds timeout,
+// Note that services are stopped in order given by |ServiceList::services_in_shutdown_order|
+// function.
+static void StopServices(const std::set<std::string>& services, std::chrono::milliseconds timeout,
bool terminate) {
LOG(INFO) << "Stopping " << services.size() << " services by sending "
<< (terminate ? "SIGTERM" : "SIGKILL");
std::vector<pid_t> pids;
pids.reserve(services.size());
- for (const auto& s : services) {
+ for (const auto& s : ServiceList::GetInstance().services_in_shutdown_order()) {
+ if (services.count(s->name()) == 0) {
+ continue;
+ }
if (s->pid() > 0) {
pids.push_back(s->pid());
}
@@ -529,12 +533,12 @@ static void StopServices(const std::vector<Service*>& services, std::chrono::mil
// Like StopServices, but also logs all the services that failed to stop after the provided timeout.
// Returns number of violators.
-static int StopServicesAndLogViolations(const std::vector<Service*>& services,
+static int StopServicesAndLogViolations(const std::set<std::string>& services,
std::chrono::milliseconds timeout, bool terminate) {
StopServices(services, timeout, terminate);
int still_running = 0;
- for (const auto& s : services) {
- if (s->IsRunning()) {
+ for (const auto& s : ServiceList::GetInstance()) {
+ if (s->IsRunning() && services.count(s->name())) {
LOG(ERROR) << "[service-misbehaving] : service '" << s->name() << "' is still running "
<< timeout.count() << "ms after receiving "
<< (terminate ? "SIGTERM" : "SIGKILL");
@@ -608,8 +612,7 @@ static void DoReboot(unsigned int cmd, const std::string& reason, const std::str
// watchdogd is a vendor specific component but should be alive to complete shutdown safely.
const std::set<std::string> to_starts{"watchdogd"};
- std::vector<Service*> stop_first;
- stop_first.reserve(ServiceList::GetInstance().services().size());
+ std::set<std::string> stop_first;
for (const auto& s : ServiceList::GetInstance()) {
if (kDebuggingServices.count(s->name())) {
// keep debugging tools until non critical ones are all gone.
@@ -627,7 +630,7 @@ static void DoReboot(unsigned int cmd, const std::string& reason, const std::str
<< "': " << result.error();
}
} else {
- stop_first.push_back(s.get());
+ stop_first.insert(s->name());
}
}
@@ -690,7 +693,7 @@ static void DoReboot(unsigned int cmd, const std::string& reason, const std::str
LOG(INFO) << "vold not running, skipping vold shutdown";
}
// logcat stopped here
- StopServices(GetDebuggingServices(false /* only_post_data */), 0ms, false /* SIGKILL */);
+ StopServices(kDebuggingServices, 0ms, false /* SIGKILL */);
// 4. sync, try umount, and optionally run fsck for user shutdown
{
Timer sync_timer;
@@ -779,17 +782,17 @@ static Result<void> DoUserspaceReboot() {
sub_reason = "resetprop";
return Error() << "Failed to reset sys.powerctl property";
}
- std::vector<Service*> stop_first;
+ std::set<std::string> stop_first;
// Remember the services that were enabled. We will need to manually enable them again otherwise
// triggers like class_start won't restart them.
- std::vector<Service*> were_enabled;
- stop_first.reserve(ServiceList::GetInstance().services().size());
+ std::set<std::string> were_enabled;
for (const auto& s : ServiceList::GetInstance().services_in_shutdown_order()) {
if (s->is_post_data() && !kDebuggingServices.count(s->name())) {
- stop_first.push_back(s);
+ stop_first.insert(s->name());
}
+ // TODO(ioffe): we should also filter out temporary services here.
if (s->is_post_data() && s->IsEnabled()) {
- were_enabled.push_back(s);
+ were_enabled.insert(s->name());
}
}
{
@@ -817,8 +820,9 @@ static Result<void> DoUserspaceReboot() {
sub_reason = "vold_reset";
return result;
}
- if (int r = StopServicesAndLogViolations(GetDebuggingServices(true /* only_post_data */),
- sigkill_timeout, false /* SIGKILL */);
+ const auto& debugging_services = GetPostDataDebuggingServices();
+ if (int r = StopServicesAndLogViolations(debugging_services, sigkill_timeout,
+ false /* SIGKILL */);
r > 0) {
sub_reason = "sigkill_debug";
// TODO(b/135984674): store information about offending services for debugging.
@@ -847,9 +851,11 @@ static Result<void> DoUserspaceReboot() {
return false;
});
// Re-enable services
- for (const auto& s : were_enabled) {
- LOG(INFO) << "Re-enabling service '" << s->name() << "'";
- s->Enable();
+ for (const auto& s : ServiceList::GetInstance()) {
+ if (were_enabled.count(s->name())) {
+ LOG(INFO) << "Re-enabling service '" << s->name() << "'";
+ s->Enable();
+ }
}
ServiceList::GetInstance().ResetState();
LeaveShutdown();
diff --git a/init/service_list.h b/init/service_list.h
index 3b9018bc0..555da258a 100644
--- a/init/service_list.h
+++ b/init/service_list.h
@@ -66,7 +66,6 @@ class ServiceList {
auto begin() const { return services_.begin(); }
auto end() const { return services_.end(); }
- const std::vector<std::unique_ptr<Service>>& services() const { return services_; }
const std::vector<Service*> services_in_shutdown_order() const;
void MarkPostData();
diff --git a/init/test_utils/service_utils.cpp b/init/test_utils/service_utils.cpp
index ae68679bd..6426ed9fd 100644
--- a/init/test_utils/service_utils.cpp
+++ b/init/test_utils/service_utils.cpp
@@ -44,7 +44,7 @@ android::base::Result<ServiceInterfacesMap> GetOnDeviceServiceInterfacesMap() {
}
ServiceInterfacesMap result;
- for (const auto& service : service_list.services()) {
+ for (const auto& service : service_list) {
// Create an entry for all services, including services that may not
// have any declared interfaces.
result[service->name()] = service->interfaces();
diff --git a/libstats/pull/Android.bp b/libstats/pull/Android.bp
deleted file mode 100644
index a8b4a4faf..000000000
--- a/libstats/pull/Android.bp
+++ /dev/null
@@ -1,110 +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.
-//
-
-// ==========================================================
-// Native library to register a pull atom callback with statsd
-// ==========================================================
-cc_defaults {
- name: "libstatspull_defaults",
- srcs: [
- "stats_pull_atom_callback.cpp",
- ],
- cflags: [
- "-Wall",
- "-Werror",
- ],
- export_include_dirs: ["include"],
- shared_libs: [
- "libbinder_ndk",
- "liblog",
- "libstatssocket",
- ],
- static_libs: [
- "libutils",
- "statsd-aidl-ndk_platform",
- ],
-}
-cc_library_shared {
- name: "libstatspull",
- defaults: [
- "libstatspull_defaults"
- ],
- // enumerate stable entry points for APEX use
- stubs: {
- symbol_file: "libstatspull.map.txt",
- versions: [
- "30",
- ],
- },
- apex_available: [
- "com.android.os.statsd",
- "test_com.android.os.statsd",
- ],
-
- stl: "libc++_static",
-
- // TODO(b/151102177): Enable it when the build error is fixed.
- header_abi_checker: {
- enabled: false,
- },
-}
-
-// ONLY USE IN TESTS.
-cc_library_static {
- name: "libstatspull_private",
- defaults: [
- "libstatspull_defaults",
- ],
- visibility: [
- "//frameworks/base/apex/statsd/tests/libstatspull",
- ],
-}
-
-// Note: These unit tests only test PullAtomMetadata.
-// For full E2E tests of libstatspull, use LibStatsPullTests
-cc_test {
- name: "libstatspull_test",
- srcs: [
- "tests/pull_atom_metadata_test.cpp",
- ],
- shared_libs: [
- "libstatspull",
- "libstatssocket",
- ],
- test_suites: ["general-tests", "mts"],
- test_config: "libstatspull_test.xml",
-
- //TODO(b/153588990): Remove when the build system properly separates
- //32bit and 64bit architectures.
- compile_multilib: "both",
- multilib: {
- lib64: {
- suffix: "64",
- },
- lib32: {
- suffix: "32",
- },
- },
- cflags: [
- "-Wall",
- "-Werror",
- "-Wno-missing-field-initializers",
- "-Wno-unused-variable",
- "-Wno-unused-function",
- "-Wno-unused-parameter",
- ],
- require_root: true,
-}
diff --git a/libstats/pull/OWNERS b/libstats/pull/OWNERS
deleted file mode 100644
index 7855774a7..000000000
--- a/libstats/pull/OWNERS
+++ /dev/null
@@ -1,7 +0,0 @@
-joeo@google.com
-muhammadq@google.com
-ruchirr@google.com
-singhtejinder@google.com
-tsaichristine@google.com
-yaochen@google.com
-yro@google.com
diff --git a/libstats/pull/TEST_MAPPING b/libstats/pull/TEST_MAPPING
deleted file mode 100644
index 76f4f0271..000000000
--- a/libstats/pull/TEST_MAPPING
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "presubmit" : [
- {
- "name" : "libstatspull_test"
- }
- ]
-} \ No newline at end of file
diff --git a/libstats/pull/include/stats_pull_atom_callback.h b/libstats/pull/include/stats_pull_atom_callback.h
deleted file mode 100644
index 17df58435..000000000
--- a/libstats/pull/include/stats_pull_atom_callback.h
+++ /dev/null
@@ -1,170 +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 <stats_event.h>
-
-#include <stdbool.h>
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * Opaque struct representing the metadata for registering an AStatsManager_PullAtomCallback.
- */
-struct AStatsManager_PullAtomMetadata;
-typedef struct AStatsManager_PullAtomMetadata AStatsManager_PullAtomMetadata;
-
-/**
- * Allocate and initialize new PullAtomMetadata.
- *
- * Must call AStatsManager_PullAtomMetadata_release to free the memory.
- */
-AStatsManager_PullAtomMetadata* AStatsManager_PullAtomMetadata_obtain();
-
-/**
- * Frees the memory held by this PullAtomMetadata
- *
- * After calling this, the PullAtomMetadata must not be used or modified in any way.
- */
-void AStatsManager_PullAtomMetadata_release(AStatsManager_PullAtomMetadata* metadata);
-
-/**
- * Set the cool down time of the pull in milliseconds. If two successive pulls are issued
- * within the cool down, a cached version of the first will be used for the second. The minimum
- * allowed cool down is one second.
- */
-void AStatsManager_PullAtomMetadata_setCoolDownMillis(AStatsManager_PullAtomMetadata* metadata,
- int64_t cool_down_millis);
-
-/**
- * Get the cool down time of the pull in milliseconds.
- */
-int64_t AStatsManager_PullAtomMetadata_getCoolDownMillis(AStatsManager_PullAtomMetadata* metadata);
-
-/**
- * Set the maximum time the pull can take in milliseconds.
- * The maximum allowed timeout is 10 seconds.
- */
-void AStatsManager_PullAtomMetadata_setTimeoutMillis(AStatsManager_PullAtomMetadata* metadata,
- int64_t timeout_millis);
-
-/**
- * Get the maximum time the pull can take in milliseconds.
- */
-int64_t AStatsManager_PullAtomMetadata_getTimeoutMillis(AStatsManager_PullAtomMetadata* metadata);
-
-/**
- * Set the additive fields of this pulled atom.
- *
- * This is only applicable for atoms which have a uid field. When tasks are run in
- * isolated processes, the data will be attributed to the host uid. Additive fields
- * will be combined when the non-additive fields are the same.
- */
-void AStatsManager_PullAtomMetadata_setAdditiveFields(AStatsManager_PullAtomMetadata* metadata,
- int32_t* additive_fields, int32_t num_fields);
-
-/**
- * Get the number of additive fields for this pulled atom. This is intended to be called before
- * AStatsManager_PullAtomMetadata_getAdditiveFields to determine the size of the array.
- */
-int32_t AStatsManager_PullAtomMetadata_getNumAdditiveFields(
- AStatsManager_PullAtomMetadata* metadata);
-
-/**
- * Get the additive fields of this pulled atom.
- *
- * \param fields an output parameter containing the additive fields for this PullAtomMetadata.
- * Fields is an array and it is assumed that it is at least as large as the number of
- * additive fields, which can be obtained by calling
- * AStatsManager_PullAtomMetadata_getNumAdditiveFields.
- */
-void AStatsManager_PullAtomMetadata_getAdditiveFields(AStatsManager_PullAtomMetadata* metadata,
- int32_t* fields);
-
-/**
- * Return codes for the result of a pull.
- */
-typedef int32_t AStatsManager_PullAtomCallbackReturn;
-enum {
- // Value indicating that this pull was successful and that the result should be used.
- AStatsManager_PULL_SUCCESS = 0,
- // Value indicating that this pull was unsuccessful and that the result should not be used.
- AStatsManager_PULL_SKIP = 1,
-};
-
-/**
- * Opaque struct representing a list of AStatsEvent objects.
- */
-struct AStatsEventList;
-typedef struct AStatsEventList AStatsEventList;
-
-/**
- * Appends and returns an AStatsEvent to the end of the AStatsEventList.
- *
- * If an AStatsEvent is obtained in this manner, the memory is internally managed and
- * AStatsEvent_release does not need to be called. The lifetime of the AStatsEvent is that of the
- * AStatsEventList.
- *
- * The AStatsEvent does still need to be built by calling AStatsEvent_build.
- */
-AStatsEvent* AStatsEventList_addStatsEvent(AStatsEventList* pull_data);
-
-/**
- * Callback interface for pulling atoms requested by the stats service.
- *
- * \param atom_tag the tag of the atom to pull.
- * \param data an output parameter in which the caller should fill the results of the pull. This
- * param cannot be NULL and it's lifetime is as long as the execution of the callback.
- * It must not be accessed or modified after returning from the callback.
- * \param cookie the opaque pointer passed in AStatsManager_registerPullAtomCallback.
- * \return AStatsManager_PULL_SUCCESS if the pull was successful, or AStatsManager_PULL_SKIP if not.
- */
-typedef AStatsManager_PullAtomCallbackReturn (*AStatsManager_PullAtomCallback)(
- int32_t atom_tag, AStatsEventList* data, void* cookie);
-/**
- * Sets a callback for an atom when that atom is to be pulled. The stats service will
- * invoke the callback when the stats service determines that this atom needs to be
- * pulled.
- *
- * Requires the REGISTER_STATS_PULL_ATOM permission.
- *
- * \param atom_tag The tag of the atom for this pull atom callback.
- * \param metadata Optional metadata specifying the timeout, cool down time, and
- * additive fields for mapping isolated to host uids.
- * This param is nullable, in which case defaults will be used.
- * \param callback The callback to be invoked when the stats service pulls the atom.
- * \param cookie A pointer that will be passed back to the callback.
- * It has no meaning to statsd.
- */
-void AStatsManager_setPullAtomCallback(int32_t atom_tag, AStatsManager_PullAtomMetadata* metadata,
- AStatsManager_PullAtomCallback callback, void* cookie);
-
-/**
- * Clears a callback for an atom when that atom is to be pulled. Note that any ongoing
- * pulls will still occur.
- *
- * Requires the REGISTER_STATS_PULL_ATOM permission.
- *
- * \param atomTag The tag of the atom of which to unregister
- */
-void AStatsManager_clearPullAtomCallback(int32_t atom_tag);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/libstats/pull/libstatspull.map.txt b/libstats/pull/libstatspull.map.txt
deleted file mode 100644
index e0e851a15..000000000
--- a/libstats/pull/libstatspull.map.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-LIBSTATSPULL {
- global:
- AStatsManager_PullAtomMetadata_obtain; # apex # introduced=30
- AStatsManager_PullAtomMetadata_release; # apex # introduced=30
- AStatsManager_PullAtomMetadata_setCoolDownMillis; # apex # introduced=30
- AStatsManager_PullAtomMetadata_getCoolDownMillis; # apex # introduced=30
- AStatsManager_PullAtomMetadata_setTimeoutMillis; # apex # introduced=30
- AStatsManager_PullAtomMetadata_getTimeoutMillis; # apex # introduced=30
- AStatsManager_PullAtomMetadata_setAdditiveFields; # apex # introduced=30
- AStatsManager_PullAtomMetadata_getNumAdditiveFields; # apex # introduced=30
- AStatsManager_PullAtomMetadata_getAdditiveFields; # apex # introduced=30
- AStatsEventList_addStatsEvent; # apex # introduced=30
- AStatsManager_setPullAtomCallback; # apex # introduced=30
- AStatsManager_clearPullAtomCallback; # apex # introduced=30
- local:
- *;
-};
diff --git a/libstats/pull/libstatspull_test.xml b/libstats/pull/libstatspull_test.xml
deleted file mode 100644
index 233fc1f18..000000000
--- a/libstats/pull/libstatspull_test.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<configuration description="Runs libstatspull_test.">
- <option name="test-suite-tag" value="apct" />
- <option name="test-suite-tag" value="apct-native" />
- <option name="test-suite-tag" value="mts" />
-
- <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
-
- <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
- <option name="cleanup" value="true" />
- <option name="push" value="libstatspull_test->/data/local/tmp/libstatspull_test" />
- <option name="append-bitness" value="true" />
- </target_preparer>
-
- <test class="com.android.tradefed.testtype.GTest" >
- <option name="native-test-device-path" value="/data/local/tmp" />
- <option name="module-name" value="libstatspull_test" />
- </test>
-
- <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
- <option name="mainline-module-package-name" value="com.google.android.os.statsd" />
- </object>
-</configuration>
diff --git a/libstats/pull/stats_pull_atom_callback.cpp b/libstats/pull/stats_pull_atom_callback.cpp
deleted file mode 100644
index 478cae760..000000000
--- a/libstats/pull/stats_pull_atom_callback.cpp
+++ /dev/null
@@ -1,260 +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 <map>
-#include <thread>
-#include <vector>
-
-#include <stats_event.h>
-#include <stats_pull_atom_callback.h>
-
-#include <aidl/android/os/BnPullAtomCallback.h>
-#include <aidl/android/os/IPullAtomResultReceiver.h>
-#include <aidl/android/os/IStatsd.h>
-#include <aidl/android/util/StatsEventParcel.h>
-#include <android/binder_auto_utils.h>
-#include <android/binder_ibinder.h>
-#include <android/binder_manager.h>
-
-using Status = ::ndk::ScopedAStatus;
-using aidl::android::os::BnPullAtomCallback;
-using aidl::android::os::IPullAtomResultReceiver;
-using aidl::android::os::IStatsd;
-using aidl::android::util::StatsEventParcel;
-using ::ndk::SharedRefBase;
-
-struct AStatsEventList {
- std::vector<AStatsEvent*> data;
-};
-
-AStatsEvent* AStatsEventList_addStatsEvent(AStatsEventList* pull_data) {
- AStatsEvent* event = AStatsEvent_obtain();
- pull_data->data.push_back(event);
- return event;
-}
-
-static const int64_t DEFAULT_COOL_DOWN_MILLIS = 1000LL; // 1 second.
-static const int64_t DEFAULT_TIMEOUT_MILLIS = 2000LL; // 2 seconds.
-
-struct AStatsManager_PullAtomMetadata {
- int64_t cool_down_millis;
- int64_t timeout_millis;
- std::vector<int32_t> additive_fields;
-};
-
-AStatsManager_PullAtomMetadata* AStatsManager_PullAtomMetadata_obtain() {
- AStatsManager_PullAtomMetadata* metadata = new AStatsManager_PullAtomMetadata();
- metadata->cool_down_millis = DEFAULT_COOL_DOWN_MILLIS;
- metadata->timeout_millis = DEFAULT_TIMEOUT_MILLIS;
- metadata->additive_fields = std::vector<int32_t>();
- return metadata;
-}
-
-void AStatsManager_PullAtomMetadata_release(AStatsManager_PullAtomMetadata* metadata) {
- delete metadata;
-}
-
-void AStatsManager_PullAtomMetadata_setCoolDownMillis(AStatsManager_PullAtomMetadata* metadata,
- int64_t cool_down_millis) {
- metadata->cool_down_millis = cool_down_millis;
-}
-
-int64_t AStatsManager_PullAtomMetadata_getCoolDownMillis(AStatsManager_PullAtomMetadata* metadata) {
- return metadata->cool_down_millis;
-}
-
-void AStatsManager_PullAtomMetadata_setTimeoutMillis(AStatsManager_PullAtomMetadata* metadata,
- int64_t timeout_millis) {
- metadata->timeout_millis = timeout_millis;
-}
-
-int64_t AStatsManager_PullAtomMetadata_getTimeoutMillis(AStatsManager_PullAtomMetadata* metadata) {
- return metadata->timeout_millis;
-}
-
-void AStatsManager_PullAtomMetadata_setAdditiveFields(AStatsManager_PullAtomMetadata* metadata,
- int32_t* additive_fields,
- int32_t num_fields) {
- metadata->additive_fields.assign(additive_fields, additive_fields + num_fields);
-}
-
-int32_t AStatsManager_PullAtomMetadata_getNumAdditiveFields(
- AStatsManager_PullAtomMetadata* metadata) {
- return metadata->additive_fields.size();
-}
-
-void AStatsManager_PullAtomMetadata_getAdditiveFields(AStatsManager_PullAtomMetadata* metadata,
- int32_t* fields) {
- std::copy(metadata->additive_fields.begin(), metadata->additive_fields.end(), fields);
-}
-
-class StatsPullAtomCallbackInternal : public BnPullAtomCallback {
- public:
- StatsPullAtomCallbackInternal(const AStatsManager_PullAtomCallback callback, void* cookie,
- const int64_t coolDownMillis, const int64_t timeoutMillis,
- const std::vector<int32_t> additiveFields)
- : mCallback(callback),
- mCookie(cookie),
- mCoolDownMillis(coolDownMillis),
- mTimeoutMillis(timeoutMillis),
- mAdditiveFields(additiveFields) {}
-
- Status onPullAtom(int32_t atomTag,
- const std::shared_ptr<IPullAtomResultReceiver>& resultReceiver) override {
- AStatsEventList statsEventList;
- int successInt = mCallback(atomTag, &statsEventList, mCookie);
- bool success = successInt == AStatsManager_PULL_SUCCESS;
-
- // Convert stats_events into StatsEventParcels.
- std::vector<StatsEventParcel> parcels;
- for (int i = 0; i < statsEventList.data.size(); i++) {
- size_t size;
- uint8_t* buffer = AStatsEvent_getBuffer(statsEventList.data[i], &size);
-
- StatsEventParcel p;
- // vector.assign() creates a copy, but this is inevitable unless
- // stats_event.h/c uses a vector as opposed to a buffer.
- p.buffer.assign(buffer, buffer + size);
- parcels.push_back(std::move(p));
- }
-
- Status status = resultReceiver->pullFinished(atomTag, success, parcels);
- if (!status.isOk()) {
- std::vector<StatsEventParcel> emptyParcels;
- resultReceiver->pullFinished(atomTag, /*success=*/false, emptyParcels);
- }
- for (int i = 0; i < statsEventList.data.size(); i++) {
- AStatsEvent_release(statsEventList.data[i]);
- }
- return Status::ok();
- }
-
- int64_t getCoolDownMillis() const { return mCoolDownMillis; }
- int64_t getTimeoutMillis() const { return mTimeoutMillis; }
- const std::vector<int32_t>& getAdditiveFields() const { return mAdditiveFields; }
-
- private:
- const AStatsManager_PullAtomCallback mCallback;
- void* mCookie;
- const int64_t mCoolDownMillis;
- const int64_t mTimeoutMillis;
- const std::vector<int32_t> mAdditiveFields;
-};
-
-static std::mutex pullAtomMutex;
-static std::shared_ptr<IStatsd> sStatsd = nullptr;
-
-static std::map<int32_t, std::shared_ptr<StatsPullAtomCallbackInternal>> mPullers;
-static std::shared_ptr<IStatsd> getStatsService();
-
-static void binderDied(void* /*cookie*/) {
- {
- std::lock_guard<std::mutex> lock(pullAtomMutex);
- sStatsd = nullptr;
- }
-
- std::shared_ptr<IStatsd> statsService = getStatsService();
- if (statsService == nullptr) {
- return;
- }
-
- // Since we do not want to make an IPC with the lock held, we first create a
- // copy of the data with the lock held before iterating through the map.
- std::map<int32_t, std::shared_ptr<StatsPullAtomCallbackInternal>> pullersCopy;
- {
- std::lock_guard<std::mutex> lock(pullAtomMutex);
- pullersCopy = mPullers;
- }
- for (const auto& it : pullersCopy) {
- statsService->registerNativePullAtomCallback(it.first, it.second->getCoolDownMillis(),
- it.second->getTimeoutMillis(),
- it.second->getAdditiveFields(), it.second);
- }
-}
-
-static ::ndk::ScopedAIBinder_DeathRecipient sDeathRecipient(
- AIBinder_DeathRecipient_new(binderDied));
-
-static std::shared_ptr<IStatsd> getStatsService() {
- std::lock_guard<std::mutex> lock(pullAtomMutex);
- if (!sStatsd) {
- // Fetch statsd
- ::ndk::SpAIBinder binder(AServiceManager_getService("stats"));
- sStatsd = IStatsd::fromBinder(binder);
- if (sStatsd) {
- AIBinder_linkToDeath(binder.get(), sDeathRecipient.get(), /*cookie=*/nullptr);
- }
- }
- return sStatsd;
-}
-
-void registerStatsPullAtomCallbackBlocking(int32_t atomTag,
- std::shared_ptr<StatsPullAtomCallbackInternal> cb) {
- const std::shared_ptr<IStatsd> statsService = getStatsService();
- if (statsService == nullptr) {
- // Statsd not available
- return;
- }
-
- statsService->registerNativePullAtomCallback(
- atomTag, cb->getCoolDownMillis(), cb->getTimeoutMillis(), cb->getAdditiveFields(), cb);
-}
-
-void unregisterStatsPullAtomCallbackBlocking(int32_t atomTag) {
- const std::shared_ptr<IStatsd> statsService = getStatsService();
- if (statsService == nullptr) {
- // Statsd not available
- return;
- }
-
- statsService->unregisterNativePullAtomCallback(atomTag);
-}
-
-void AStatsManager_setPullAtomCallback(int32_t atom_tag, AStatsManager_PullAtomMetadata* metadata,
- AStatsManager_PullAtomCallback callback, void* cookie) {
- int64_t coolDownMillis =
- metadata == nullptr ? DEFAULT_COOL_DOWN_MILLIS : metadata->cool_down_millis;
- int64_t timeoutMillis = metadata == nullptr ? DEFAULT_TIMEOUT_MILLIS : metadata->timeout_millis;
-
- std::vector<int32_t> additiveFields;
- if (metadata != nullptr) {
- additiveFields = metadata->additive_fields;
- }
-
- std::shared_ptr<StatsPullAtomCallbackInternal> callbackBinder =
- SharedRefBase::make<StatsPullAtomCallbackInternal>(callback, cookie, coolDownMillis,
- timeoutMillis, additiveFields);
-
- {
- std::lock_guard<std::mutex> lg(pullAtomMutex);
- // Always add to the map. If statsd is dead, we will add them when it comes back.
- mPullers[atom_tag] = callbackBinder;
- }
-
- std::thread registerThread(registerStatsPullAtomCallbackBlocking, atom_tag, callbackBinder);
- registerThread.detach();
-}
-
-void AStatsManager_clearPullAtomCallback(int32_t atom_tag) {
- {
- std::lock_guard<std::mutex> lg(pullAtomMutex);
- // Always remove the puller from our map.
- // If statsd is down, we will not register it when it comes back.
- mPullers.erase(atom_tag);
- }
- std::thread unregisterThread(unregisterStatsPullAtomCallbackBlocking, atom_tag);
- unregisterThread.detach();
-}
diff --git a/libstats/pull/tests/pull_atom_metadata_test.cpp b/libstats/pull/tests/pull_atom_metadata_test.cpp
deleted file mode 100644
index abc8e47af..000000000
--- a/libstats/pull/tests/pull_atom_metadata_test.cpp
+++ /dev/null
@@ -1,92 +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 <gtest/gtest.h>
-
-#include <stats_pull_atom_callback.h>
-
-namespace {
-
-static const int64_t DEFAULT_COOL_DOWN_MILLIS = 1000LL; // 1 second.
-static const int64_t DEFAULT_TIMEOUT_MILLIS = 2000LL; // 2 seconds.
-
-} // anonymous namespace
-
-TEST(AStatsManager_PullAtomMetadataTest, TestEmpty) {
- AStatsManager_PullAtomMetadata* metadata = AStatsManager_PullAtomMetadata_obtain();
- EXPECT_EQ(AStatsManager_PullAtomMetadata_getCoolDownMillis(metadata), DEFAULT_COOL_DOWN_MILLIS);
- EXPECT_EQ(AStatsManager_PullAtomMetadata_getTimeoutMillis(metadata), DEFAULT_TIMEOUT_MILLIS);
- EXPECT_EQ(AStatsManager_PullAtomMetadata_getNumAdditiveFields(metadata), 0);
- AStatsManager_PullAtomMetadata_release(metadata);
-}
-
-TEST(AStatsManager_PullAtomMetadataTest, TestSetTimeoutMillis) {
- int64_t timeoutMillis = 500;
- AStatsManager_PullAtomMetadata* metadata = AStatsManager_PullAtomMetadata_obtain();
- AStatsManager_PullAtomMetadata_setTimeoutMillis(metadata, timeoutMillis);
- EXPECT_EQ(AStatsManager_PullAtomMetadata_getCoolDownMillis(metadata), DEFAULT_COOL_DOWN_MILLIS);
- EXPECT_EQ(AStatsManager_PullAtomMetadata_getTimeoutMillis(metadata), timeoutMillis);
- EXPECT_EQ(AStatsManager_PullAtomMetadata_getNumAdditiveFields(metadata), 0);
- AStatsManager_PullAtomMetadata_release(metadata);
-}
-
-TEST(AStatsManager_PullAtomMetadataTest, TestSetCoolDownMillis) {
- int64_t coolDownMillis = 10000;
- AStatsManager_PullAtomMetadata* metadata = AStatsManager_PullAtomMetadata_obtain();
- AStatsManager_PullAtomMetadata_setCoolDownMillis(metadata, coolDownMillis);
- EXPECT_EQ(AStatsManager_PullAtomMetadata_getCoolDownMillis(metadata), coolDownMillis);
- EXPECT_EQ(AStatsManager_PullAtomMetadata_getTimeoutMillis(metadata), DEFAULT_TIMEOUT_MILLIS);
- EXPECT_EQ(AStatsManager_PullAtomMetadata_getNumAdditiveFields(metadata), 0);
- AStatsManager_PullAtomMetadata_release(metadata);
-}
-
-TEST(AStatsManager_PullAtomMetadataTest, TestSetAdditiveFields) {
- const int numFields = 3;
- int inputFields[numFields] = {2, 4, 6};
- AStatsManager_PullAtomMetadata* metadata = AStatsManager_PullAtomMetadata_obtain();
- AStatsManager_PullAtomMetadata_setAdditiveFields(metadata, inputFields, numFields);
- EXPECT_EQ(AStatsManager_PullAtomMetadata_getCoolDownMillis(metadata), DEFAULT_COOL_DOWN_MILLIS);
- EXPECT_EQ(AStatsManager_PullAtomMetadata_getTimeoutMillis(metadata), DEFAULT_TIMEOUT_MILLIS);
- EXPECT_EQ(AStatsManager_PullAtomMetadata_getNumAdditiveFields(metadata), numFields);
- int outputFields[numFields];
- AStatsManager_PullAtomMetadata_getAdditiveFields(metadata, outputFields);
- for (int i = 0; i < numFields; i++) {
- EXPECT_EQ(inputFields[i], outputFields[i]);
- }
- AStatsManager_PullAtomMetadata_release(metadata);
-}
-
-TEST(AStatsManager_PullAtomMetadataTest, TestSetAllElements) {
- int64_t timeoutMillis = 500;
- int64_t coolDownMillis = 10000;
- const int numFields = 3;
- int inputFields[numFields] = {2, 4, 6};
-
- AStatsManager_PullAtomMetadata* metadata = AStatsManager_PullAtomMetadata_obtain();
- AStatsManager_PullAtomMetadata_setTimeoutMillis(metadata, timeoutMillis);
- AStatsManager_PullAtomMetadata_setCoolDownMillis(metadata, coolDownMillis);
- AStatsManager_PullAtomMetadata_setAdditiveFields(metadata, inputFields, numFields);
-
- EXPECT_EQ(AStatsManager_PullAtomMetadata_getCoolDownMillis(metadata), coolDownMillis);
- EXPECT_EQ(AStatsManager_PullAtomMetadata_getTimeoutMillis(metadata), timeoutMillis);
- EXPECT_EQ(AStatsManager_PullAtomMetadata_getNumAdditiveFields(metadata), numFields);
- int outputFields[numFields];
- AStatsManager_PullAtomMetadata_getAdditiveFields(metadata, outputFields);
- for (int i = 0; i < numFields; i++) {
- EXPECT_EQ(inputFields[i], outputFields[i]);
- }
- AStatsManager_PullAtomMetadata_release(metadata);
-}
diff --git a/libstats/socket/Android.bp b/libstats/socket/Android.bp
deleted file mode 100644
index bf79ea244..000000000
--- a/libstats/socket/Android.bp
+++ /dev/null
@@ -1,124 +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.
-//
-
-// =========================================================================
-// Native library to write stats log to statsd socket on Android R and later
-// =========================================================================
-cc_defaults {
- name: "libstatssocket_defaults",
- srcs: [
- "stats_buffer_writer.c",
- "stats_event.c",
- "stats_socket.c",
- "statsd_writer.c",
- ],
- export_include_dirs: ["include"],
- static_libs: [
- "libcutils", // does not expose a stable C API
- ],
- cflags: [
- "-Wall",
- "-Werror",
- ],
-}
-
-cc_library {
- name: "libstatssocket",
- defaults: [
- "libstatssocket_defaults",
- ],
- host_supported: true,
- target: {
- // On android, libstatssocket should only be linked as a shared lib
- android: {
- static: {
- enabled: false,
- },
- },
- host: {
- shared: {
- enabled: false,
- },
- },
- },
- stl: "libc++_static",
-
- // enumerate stable entry points for APEX use
- stubs: {
- symbol_file: "libstatssocket.map.txt",
- versions: [
- "30",
- ],
- },
- apex_available: [
- "com.android.os.statsd",
- "test_com.android.os.statsd",
- ],
-}
-
-//TODO (b/149842105): Figure out if there is a better solution for this.
-cc_test_library {
- name: "libstatssocket_private",
- defaults: [
- "libstatssocket_defaults",
- ],
- visibility: [
- "//frameworks/base/apex/statsd/tests/libstatspull",
- "//frameworks/base/cmds/statsd",
- ],
-}
-
-cc_library_headers {
- name: "libstatssocket_headers",
- export_include_dirs: ["include"],
- host_supported: true,
- apex_available: ["com.android.resolv"],
- min_sdk_version: "29",
-}
-
-cc_test {
- name: "libstatssocket_test",
- srcs: [
- "tests/stats_event_test.cpp",
- "tests/stats_writer_test.cpp",
- ],
- cflags: [
- "-Wall",
- "-Werror",
- ],
- static_libs: [
- "libgmock",
- "libstatssocket_private",
- ],
- shared_libs: [
- "libcutils",
- "libutils",
- ],
- test_suites: ["device-tests", "mts"],
- test_config: "libstatssocket_test.xml",
- //TODO(b/153588990): Remove when the build system properly separates.
- //32bit and 64bit architectures.
- compile_multilib: "both",
- multilib: {
- lib64: {
- suffix: "64",
- },
- lib32: {
- suffix: "32",
- },
- },
- require_root: true,
-}
diff --git a/libstats/socket/TEST_MAPPING b/libstats/socket/TEST_MAPPING
deleted file mode 100644
index 0224998f5..000000000
--- a/libstats/socket/TEST_MAPPING
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "presubmit" : [
- {
- "name" : "libstatssocket_test"
- }
- ]
-} \ No newline at end of file
diff --git a/libstats/socket/include/stats_buffer_writer.h b/libstats/socket/include/stats_buffer_writer.h
deleted file mode 100644
index 5b41f0e04..000000000
--- a/libstats/socket/include/stats_buffer_writer.h
+++ /dev/null
@@ -1,30 +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 <stddef.h>
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif // __CPLUSPLUS
-void stats_log_close();
-int stats_log_is_closed();
-int write_buffer_to_statsd(void* buffer, size_t size, uint32_t atomId);
-#ifdef __cplusplus
-}
-#endif // __CPLUSPLUS
diff --git a/libstats/socket/include/stats_event.h b/libstats/socket/include/stats_event.h
deleted file mode 100644
index 3d3baf9cf..000000000
--- a/libstats/socket/include/stats_event.h
+++ /dev/null
@@ -1,164 +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.
- */
-
-#ifndef ANDROID_STATS_LOG_STATS_EVENT_H
-#define ANDROID_STATS_LOG_STATS_EVENT_H
-
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdint.h>
-
-/*
- * Functionality to build and store the buffer sent over the statsd socket.
- * This code defines and encapsulates the socket protocol.
- *
- * Usage:
- * AStatsEvent* event = AStatsEvent_obtain();
- *
- * AStatsEvent_setAtomId(event, atomId);
- * AStatsEvent_addBoolAnnotation(event, 5, false); // atom-level annotation
- * AStatsEvent_writeInt32(event, 24);
- * AStatsEvent_addBoolAnnotation(event, 1, true); // annotation for preceding atom field
- * AStatsEvent_addInt32Annotation(event, 2, 128);
- * AStatsEvent_writeFloat(event, 2.0);
- *
- * AStatsEvent_write(event);
- * AStatsEvent_release(event);
- *
- * Note that calls to add atom fields and annotations should be made in the
- * order that they are defined in the atom.
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif // __CPLUSPLUS
-
-/**
- * Opaque struct use to represent a StatsEvent. It builds and stores the data that is sent to
- * statsd.
- */
-struct AStatsEvent;
-typedef struct AStatsEvent AStatsEvent;
-
-/**
- * Returns a new AStatsEvent. If you call this function, you must call AStatsEvent_release to free
- * the allocated memory.
- */
-AStatsEvent* AStatsEvent_obtain();
-
-/**
- * Builds and finalizes the AStatsEvent for a pulled event.
- * This should only be called for pulled AStatsEvents.
- *
- * After this function, the StatsEvent must not be modified in any way other than calling release or
- * write.
- *
- * Build can be called multiple times without error.
- * If the event has been built before, this function is a no-op.
- */
-void AStatsEvent_build(AStatsEvent* event);
-
-/**
- * Writes the StatsEvent to the stats log.
- *
- * After calling this, AStatsEvent_release must be called,
- * and is the only function that can be safely called.
- */
-int AStatsEvent_write(AStatsEvent* event);
-
-/**
- * Frees the memory held by this StatsEvent.
- *
- * After calling this, the StatsEvent must not be used or modified in any way.
- */
-void AStatsEvent_release(AStatsEvent* event);
-
-/**
- * Sets the atom id for this StatsEvent.
- *
- * This function should be called immediately after AStatsEvent_obtain. It may
- * be called additional times as well, but subsequent calls will have no effect.
- **/
-void AStatsEvent_setAtomId(AStatsEvent* event, uint32_t atomId);
-
-/**
- * Writes an int32_t field to this StatsEvent.
- **/
-void AStatsEvent_writeInt32(AStatsEvent* event, int32_t value);
-
-/**
- * Writes an int64_t field to this StatsEvent.
- **/
-void AStatsEvent_writeInt64(AStatsEvent* event, int64_t value);
-
-/**
- * Writes a float field to this StatsEvent.
- **/
-void AStatsEvent_writeFloat(AStatsEvent* event, float value);
-
-/**
- * Write a bool field to this StatsEvent.
- **/
-void AStatsEvent_writeBool(AStatsEvent* event, bool value);
-
-/**
- * Write a byte array field to this StatsEvent.
- **/
-void AStatsEvent_writeByteArray(AStatsEvent* event, const uint8_t* buf, size_t numBytes);
-
-/**
- * Write a string field to this StatsEvent.
- *
- * The string must be null-terminated.
- **/
-void AStatsEvent_writeString(AStatsEvent* event, const char* value);
-
-/**
- * Write an attribution chain field to this StatsEvent.
- *
- * The sizes of uids and tags must be equal. The AttributionNode at position i is
- * made up of uids[i] and tags[i].
- *
- * \param uids array of uids in the attribution chain.
- * \param tags array of tags in the attribution chain. Each tag must be null-terminated.
- * \param numNodes the number of AttributionNodes in the attribution chain. This is the length of
- * the uids and the tags.
- **/
-void AStatsEvent_writeAttributionChain(AStatsEvent* event, const uint32_t* uids,
- const char* const* tags, uint8_t numNodes);
-
-/**
- * Write a bool annotation for the previous field written.
- **/
-void AStatsEvent_addBoolAnnotation(AStatsEvent* event, uint8_t annotationId, bool value);
-
-/**
- * Write an integer annotation for the previous field written.
- **/
-void AStatsEvent_addInt32Annotation(AStatsEvent* event, uint8_t annotationId, int32_t value);
-
-// Internal/test APIs. Should not be exposed outside of the APEX.
-void AStatsEvent_overwriteTimestamp(AStatsEvent* event, uint64_t timestampNs);
-uint32_t AStatsEvent_getAtomId(AStatsEvent* event);
-// Size is an output parameter.
-uint8_t* AStatsEvent_getBuffer(AStatsEvent* event, size_t* size);
-uint32_t AStatsEvent_getErrors(AStatsEvent* event);
-
-#ifdef __cplusplus
-}
-#endif // __CPLUSPLUS
-
-#endif // ANDROID_STATS_LOG_STATS_EVENT_H
diff --git a/libstats/socket/include/stats_socket.h b/libstats/socket/include/stats_socket.h
deleted file mode 100644
index 5a75fc021..000000000
--- a/libstats/socket/include/stats_socket.h
+++ /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.
- */
-
-#pragma once
-
-/**
- * Helpers to manage the statsd socket.
- **/
-
-#ifdef __cplusplus
-extern "C" {
-#endif // __CPLUSPLUS
-
-/**
- * Closes the statsd socket file descriptor.
- **/
-void AStatsSocket_close();
-#ifdef __cplusplus
-}
-#endif // __CPLUSPLUS
diff --git a/libstats/socket/libstatssocket.map.txt b/libstats/socket/libstatssocket.map.txt
deleted file mode 100644
index 5c1390419..000000000
--- a/libstats/socket/libstatssocket.map.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-LIBSTATSSOCKET {
- global:
- AStatsEvent_obtain; # apex # introduced=30
- AStatsEvent_build; # apex # introduced=30
- AStatsEvent_write; # apex # introduced=30
- AStatsEvent_release; # apex # introduced=30
- AStatsEvent_setAtomId; # apex # introduced=30
- AStatsEvent_writeInt32; # apex # introduced=30
- AStatsEvent_writeInt64; # apex # introduced=30
- AStatsEvent_writeFloat; # apex # introduced=30
- AStatsEvent_writeBool; # apex # introduced=30
- AStatsEvent_writeByteArray; # apex # introduced=30
- AStatsEvent_writeString; # apex # introduced=30
- AStatsEvent_writeAttributionChain; # apex # introduced=30
- AStatsEvent_addBoolAnnotation; # apex # introduced=30
- AStatsEvent_addInt32Annotation; # apex # introduced=30
- AStatsSocket_close; # apex # introduced=30
- local:
- *;
-};
diff --git a/libstats/socket/libstatssocket_test.xml b/libstats/socket/libstatssocket_test.xml
deleted file mode 100644
index d2694d1dd..000000000
--- a/libstats/socket/libstatssocket_test.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<configuration description="Runs libstatssocket_test.">
- <option name="test-suite-tag" value="apct" />
- <option name="test-suite-tag" value="apct-native" />
- <option name="test-suite-tag" value="mts" />
-
- <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
-
- <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
- <option name="cleanup" value="true" />
- <option name="push" value="libstatssocket_test->/data/local/tmp/libstatssocket_test" />
- <option name="append-bitness" value="true" />
- </target_preparer>
-
- <test class="com.android.tradefed.testtype.GTest" >
- <option name="native-test-device-path" value="/data/local/tmp" />
- <option name="module-name" value="libstatssocket_test" />
- </test>
-
- <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
- <option name="mainline-module-package-name" value="com.google.android.os.statsd" />
- </object>
-</configuration>
-
diff --git a/libstats/socket/stats_buffer_writer.c b/libstats/socket/stats_buffer_writer.c
deleted file mode 100644
index 549acdc8e..000000000
--- a/libstats/socket/stats_buffer_writer.c
+++ /dev/null
@@ -1,126 +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/stats_buffer_writer.h"
-#ifdef __ANDROID__
-#include <cutils/properties.h>
-#endif
-#include <errno.h>
-#include <sys/time.h>
-#include <sys/uio.h>
-#include "statsd_writer.h"
-
-static const uint32_t kStatsEventTag = 1937006964;
-
-extern struct android_log_transport_write statsdLoggerWrite;
-
-static int __write_to_statsd_init(struct iovec* vec, size_t nr);
-static int (*__write_to_statsd)(struct iovec* vec, size_t nr) = __write_to_statsd_init;
-
-void note_log_drop(int error, int atomId) {
- statsdLoggerWrite.noteDrop(error, atomId);
-}
-
-void stats_log_close() {
- statsd_writer_init_lock();
- __write_to_statsd = __write_to_statsd_init;
- if (statsdLoggerWrite.close) {
- (*statsdLoggerWrite.close)();
- }
- statsd_writer_init_unlock();
-}
-
-int stats_log_is_closed() {
- return statsdLoggerWrite.isClosed && (*statsdLoggerWrite.isClosed)();
-}
-
-int write_buffer_to_statsd(void* buffer, size_t size, uint32_t atomId) {
- int ret = 1;
-
- struct iovec vecs[2];
- vecs[0].iov_base = (void*)&kStatsEventTag;
- vecs[0].iov_len = sizeof(kStatsEventTag);
- vecs[1].iov_base = buffer;
- vecs[1].iov_len = size;
-
- ret = __write_to_statsd(vecs, 2);
-
- if (ret < 0) {
- note_log_drop(ret, atomId);
- }
-
- return ret;
-}
-
-static int __write_to_stats_daemon(struct iovec* vec, size_t nr) {
- int save_errno;
- struct timespec ts;
- size_t len, i;
-
- for (len = i = 0; i < nr; ++i) {
- len += vec[i].iov_len;
- }
- if (!len) {
- return -EINVAL;
- }
-
- save_errno = errno;
-#if defined(__ANDROID__)
- clock_gettime(CLOCK_REALTIME, &ts);
-#else
- struct timeval tv;
- gettimeofday(&tv, NULL);
- ts.tv_sec = tv.tv_sec;
- ts.tv_nsec = tv.tv_usec * 1000;
-#endif
-
- int ret = (int)(*statsdLoggerWrite.write)(&ts, vec, nr);
- errno = save_errno;
- return ret;
-}
-
-static int __write_to_statsd_initialize_locked() {
- if (!statsdLoggerWrite.open || ((*statsdLoggerWrite.open)() < 0)) {
- if (statsdLoggerWrite.close) {
- (*statsdLoggerWrite.close)();
- return -ENODEV;
- }
- }
- return 1;
-}
-
-static int __write_to_statsd_init(struct iovec* vec, size_t nr) {
- int ret, save_errno = errno;
-
- statsd_writer_init_lock();
-
- if (__write_to_statsd == __write_to_statsd_init) {
- ret = __write_to_statsd_initialize_locked();
- if (ret < 0) {
- statsd_writer_init_unlock();
- errno = save_errno;
- return ret;
- }
-
- __write_to_statsd = __write_to_stats_daemon;
- }
-
- statsd_writer_init_unlock();
-
- ret = __write_to_statsd(vec, nr);
- errno = save_errno;
- return ret;
-}
diff --git a/libstats/socket/stats_event.c b/libstats/socket/stats_event.c
deleted file mode 100644
index f3e808756..000000000
--- a/libstats/socket/stats_event.c
+++ /dev/null
@@ -1,351 +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/stats_event.h"
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include "stats_buffer_writer.h"
-
-#define LOGGER_ENTRY_MAX_PAYLOAD 4068
-// Max payload size is 4 bytes less as 4 bytes are reserved for stats_eventTag.
-// See android_util_Stats_Log.cpp
-#define MAX_PUSH_EVENT_PAYLOAD (LOGGER_ENTRY_MAX_PAYLOAD - 4)
-
-#define MAX_PULL_EVENT_PAYLOAD (50 * 1024) // 50 KB
-
-/* POSITIONS */
-#define POS_NUM_ELEMENTS 1
-#define POS_TIMESTAMP (POS_NUM_ELEMENTS + sizeof(uint8_t))
-#define POS_ATOM_ID (POS_TIMESTAMP + sizeof(uint8_t) + sizeof(uint64_t))
-
-/* LIMITS */
-#define MAX_ANNOTATION_COUNT 15
-#define MAX_BYTE_VALUE 127 // parsing side requires that lengths fit in 7 bits
-
-/* ERRORS */
-#define ERROR_NO_TIMESTAMP 0x1
-#define ERROR_NO_ATOM_ID 0x2
-#define ERROR_OVERFLOW 0x4
-#define ERROR_ATTRIBUTION_CHAIN_TOO_LONG 0x8
-#define ERROR_TOO_MANY_KEY_VALUE_PAIRS 0x10
-#define ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD 0x20
-#define ERROR_INVALID_ANNOTATION_ID 0x40
-#define ERROR_ANNOTATION_ID_TOO_LARGE 0x80
-#define ERROR_TOO_MANY_ANNOTATIONS 0x100
-#define ERROR_TOO_MANY_FIELDS 0x200
-#define ERROR_INVALID_VALUE_TYPE 0x400
-#define ERROR_STRING_NOT_NULL_TERMINATED 0x800
-#define ERROR_ATOM_ID_INVALID_POSITION 0x2000
-
-/* TYPE IDS */
-#define INT32_TYPE 0x00
-#define INT64_TYPE 0x01
-#define STRING_TYPE 0x02
-#define LIST_TYPE 0x03
-#define FLOAT_TYPE 0x04
-#define BOOL_TYPE 0x05
-#define BYTE_ARRAY_TYPE 0x06
-#define OBJECT_TYPE 0x07
-#define KEY_VALUE_PAIRS_TYPE 0x08
-#define ATTRIBUTION_CHAIN_TYPE 0x09
-#define ERROR_TYPE 0x0F
-
-// The AStatsEvent struct holds the serialized encoding of an event
-// within a buf. Also includes other required fields.
-struct AStatsEvent {
- uint8_t* buf;
- // Location of last field within the buf. Here, field denotes either a
- // metadata field (e.g. timestamp) or an atom field.
- size_t lastFieldPos;
- // Number of valid bytes within the buffer.
- size_t numBytesWritten;
- uint32_t numElements;
- uint32_t atomId;
- uint32_t errors;
- bool built;
- size_t bufSize;
-};
-
-static int64_t get_elapsed_realtime_ns() {
- struct timespec t;
- t.tv_sec = t.tv_nsec = 0;
- clock_gettime(CLOCK_BOOTTIME, &t);
- return (int64_t)t.tv_sec * 1000000000LL + t.tv_nsec;
-}
-
-AStatsEvent* AStatsEvent_obtain() {
- AStatsEvent* event = malloc(sizeof(AStatsEvent));
- event->lastFieldPos = 0;
- event->numBytesWritten = 2; // reserve first 2 bytes for root event type and number of elements
- event->numElements = 0;
- event->atomId = 0;
- event->errors = 0;
- event->built = false;
- event->bufSize = MAX_PUSH_EVENT_PAYLOAD;
- event->buf = (uint8_t*)calloc(event->bufSize, 1);
-
- event->buf[0] = OBJECT_TYPE;
- AStatsEvent_writeInt64(event, get_elapsed_realtime_ns()); // write the timestamp
-
- return event;
-}
-
-void AStatsEvent_release(AStatsEvent* event) {
- free(event->buf);
- free(event);
-}
-
-void AStatsEvent_setAtomId(AStatsEvent* event, uint32_t atomId) {
- if (event->atomId != 0) return;
- if (event->numElements != 1) {
- event->errors |= ERROR_ATOM_ID_INVALID_POSITION;
- return;
- }
-
- event->atomId = atomId;
- AStatsEvent_writeInt32(event, atomId);
-}
-
-// Overwrites the timestamp populated in AStatsEvent_obtain with a custom
-// timestamp. Should only be called from test code.
-void AStatsEvent_overwriteTimestamp(AStatsEvent* event, uint64_t timestampNs) {
- memcpy(&event->buf[POS_TIMESTAMP + sizeof(uint8_t)], &timestampNs, sizeof(timestampNs));
- // Do not increment numElements because we already accounted for the timestamp
- // within AStatsEvent_obtain.
-}
-
-// Side-effect: modifies event->errors if the buffer would overflow
-static bool overflows(AStatsEvent* event, size_t size) {
- const size_t totalBytesNeeded = event->numBytesWritten + size;
- if (totalBytesNeeded > MAX_PULL_EVENT_PAYLOAD) {
- event->errors |= ERROR_OVERFLOW;
- return true;
- }
-
- // Expand buffer if needed.
- if (event->bufSize < MAX_PULL_EVENT_PAYLOAD && totalBytesNeeded > event->bufSize) {
- do {
- event->bufSize *= 2;
- } while (event->bufSize <= totalBytesNeeded);
-
- if (event->bufSize > MAX_PULL_EVENT_PAYLOAD) {
- event->bufSize = MAX_PULL_EVENT_PAYLOAD;
- }
-
- event->buf = (uint8_t*)realloc(event->buf, event->bufSize);
- }
- return false;
-}
-
-// Side-effect: all append functions increment event->numBytesWritten if there is
-// sufficient space within the buffer to place the value
-static void append_byte(AStatsEvent* event, uint8_t value) {
- if (!overflows(event, sizeof(value))) {
- event->buf[event->numBytesWritten] = value;
- event->numBytesWritten += sizeof(value);
- }
-}
-
-static void append_bool(AStatsEvent* event, bool value) {
- append_byte(event, (uint8_t)value);
-}
-
-static void append_int32(AStatsEvent* event, int32_t value) {
- if (!overflows(event, sizeof(value))) {
- memcpy(&event->buf[event->numBytesWritten], &value, sizeof(value));
- event->numBytesWritten += sizeof(value);
- }
-}
-
-static void append_int64(AStatsEvent* event, int64_t value) {
- if (!overflows(event, sizeof(value))) {
- memcpy(&event->buf[event->numBytesWritten], &value, sizeof(value));
- event->numBytesWritten += sizeof(value);
- }
-}
-
-static void append_float(AStatsEvent* event, float value) {
- if (!overflows(event, sizeof(value))) {
- memcpy(&event->buf[event->numBytesWritten], &value, sizeof(value));
- event->numBytesWritten += sizeof(float);
- }
-}
-
-static void append_byte_array(AStatsEvent* event, const uint8_t* buf, size_t size) {
- if (!overflows(event, size)) {
- memcpy(&event->buf[event->numBytesWritten], buf, size);
- event->numBytesWritten += size;
- }
-}
-
-// Side-effect: modifies event->errors if buf is not properly null-terminated
-static void append_string(AStatsEvent* event, const char* buf) {
- size_t size = strnlen(buf, MAX_PULL_EVENT_PAYLOAD);
- if (size == MAX_PULL_EVENT_PAYLOAD) {
- event->errors |= ERROR_STRING_NOT_NULL_TERMINATED;
- return;
- }
-
- append_int32(event, size);
- append_byte_array(event, (uint8_t*)buf, size);
-}
-
-static void start_field(AStatsEvent* event, uint8_t typeId) {
- event->lastFieldPos = event->numBytesWritten;
- append_byte(event, typeId);
- event->numElements++;
-}
-
-void AStatsEvent_writeInt32(AStatsEvent* event, int32_t value) {
- start_field(event, INT32_TYPE);
- append_int32(event, value);
-}
-
-void AStatsEvent_writeInt64(AStatsEvent* event, int64_t value) {
- start_field(event, INT64_TYPE);
- append_int64(event, value);
-}
-
-void AStatsEvent_writeFloat(AStatsEvent* event, float value) {
- start_field(event, FLOAT_TYPE);
- append_float(event, value);
-}
-
-void AStatsEvent_writeBool(AStatsEvent* event, bool value) {
- start_field(event, BOOL_TYPE);
- append_bool(event, value);
-}
-
-void AStatsEvent_writeByteArray(AStatsEvent* event, const uint8_t* buf, size_t numBytes) {
- start_field(event, BYTE_ARRAY_TYPE);
- append_int32(event, numBytes);
- append_byte_array(event, buf, numBytes);
-}
-
-// Value is assumed to be encoded using UTF8
-void AStatsEvent_writeString(AStatsEvent* event, const char* value) {
- start_field(event, STRING_TYPE);
- append_string(event, value);
-}
-
-// Tags are assumed to be encoded using UTF8
-void AStatsEvent_writeAttributionChain(AStatsEvent* event, const uint32_t* uids,
- const char* const* tags, uint8_t numNodes) {
- if (numNodes > MAX_BYTE_VALUE) {
- event->errors |= ERROR_ATTRIBUTION_CHAIN_TOO_LONG;
- return;
- }
-
- start_field(event, ATTRIBUTION_CHAIN_TYPE);
- append_byte(event, numNodes);
-
- for (uint8_t i = 0; i < numNodes; i++) {
- append_int32(event, uids[i]);
- append_string(event, tags[i]);
- }
-}
-
-// Side-effect: modifies event->errors if field has too many annotations
-static void increment_annotation_count(AStatsEvent* event) {
- uint8_t fieldType = event->buf[event->lastFieldPos] & 0x0F;
- uint32_t oldAnnotationCount = (event->buf[event->lastFieldPos] & 0xF0) >> 4;
- uint32_t newAnnotationCount = oldAnnotationCount + 1;
-
- if (newAnnotationCount > MAX_ANNOTATION_COUNT) {
- event->errors |= ERROR_TOO_MANY_ANNOTATIONS;
- return;
- }
-
- event->buf[event->lastFieldPos] = (((uint8_t)newAnnotationCount << 4) & 0xF0) | fieldType;
-}
-
-void AStatsEvent_addBoolAnnotation(AStatsEvent* event, uint8_t annotationId, bool value) {
- if (event->numElements < 2) {
- event->errors |= ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD;
- return;
- } else if (annotationId > MAX_BYTE_VALUE) {
- event->errors |= ERROR_ANNOTATION_ID_TOO_LARGE;
- return;
- }
-
- append_byte(event, annotationId);
- append_byte(event, BOOL_TYPE);
- append_bool(event, value);
- increment_annotation_count(event);
-}
-
-void AStatsEvent_addInt32Annotation(AStatsEvent* event, uint8_t annotationId, int32_t value) {
- if (event->numElements < 2) {
- event->errors |= ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD;
- return;
- } else if (annotationId > MAX_BYTE_VALUE) {
- event->errors |= ERROR_ANNOTATION_ID_TOO_LARGE;
- return;
- }
-
- append_byte(event, annotationId);
- append_byte(event, INT32_TYPE);
- append_int32(event, value);
- increment_annotation_count(event);
-}
-
-uint32_t AStatsEvent_getAtomId(AStatsEvent* event) {
- return event->atomId;
-}
-
-uint8_t* AStatsEvent_getBuffer(AStatsEvent* event, size_t* size) {
- if (size) *size = event->numBytesWritten;
- return event->buf;
-}
-
-uint32_t AStatsEvent_getErrors(AStatsEvent* event) {
- return event->errors;
-}
-
-static void build_internal(AStatsEvent* event, const bool push) {
- if (event->numElements > MAX_BYTE_VALUE) event->errors |= ERROR_TOO_MANY_FIELDS;
- if (0 == event->atomId) event->errors |= ERROR_NO_ATOM_ID;
- if (push && event->numBytesWritten > MAX_PUSH_EVENT_PAYLOAD) event->errors |= ERROR_OVERFLOW;
-
- // If there are errors, rewrite buffer.
- if (event->errors) {
- // Discard everything after the atom id (including atom-level
- // annotations). This leaves only two elements (timestamp and atom id).
- event->numElements = 2;
- // Reset number of atom-level annotations to 0.
- event->buf[POS_ATOM_ID] = INT32_TYPE;
- // Now, write errors to the buffer immediately after the atom id.
- event->numBytesWritten = POS_ATOM_ID + sizeof(uint8_t) + sizeof(uint32_t);
- start_field(event, ERROR_TYPE);
- append_int32(event, event->errors);
- }
-
- event->buf[POS_NUM_ELEMENTS] = event->numElements;
-}
-
-void AStatsEvent_build(AStatsEvent* event) {
- if (event->built) return;
-
- build_internal(event, false /* push */);
-
- event->built = true;
-}
-
-int AStatsEvent_write(AStatsEvent* event) {
- build_internal(event, true /* push */);
- return write_buffer_to_statsd(event->buf, event->numBytesWritten, event->atomId);
-}
diff --git a/libstats/socket/stats_socket.c b/libstats/socket/stats_socket.c
deleted file mode 100644
index 09f8967b0..000000000
--- a/libstats/socket/stats_socket.c
+++ /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.
- */
-
-#include "include/stats_socket.h"
-#include "stats_buffer_writer.h"
-
-void AStatsSocket_close() {
- stats_log_close();
-}
diff --git a/libstats/socket/statsd_writer.c b/libstats/socket/statsd_writer.c
deleted file mode 100644
index 73b7a7e71..000000000
--- a/libstats/socket/statsd_writer.c
+++ /dev/null
@@ -1,294 +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 "statsd_writer.h"
-
-#include <cutils/fs.h>
-#include <cutils/sockets.h>
-#include <cutils/threads.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <poll.h>
-#include <private/android_filesystem_config.h>
-#include <private/android_logger.h>
-#include <stdarg.h>
-#include <stdatomic.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <sys/un.h>
-#include <time.h>
-#include <unistd.h>
-
-static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
-static atomic_int dropped = 0;
-static atomic_int log_error = 0;
-static atomic_int atom_tag = 0;
-
-void statsd_writer_init_lock() {
- /*
- * If we trigger a signal handler in the middle of locked activity and the
- * signal handler logs a message, we could get into a deadlock state.
- */
- pthread_mutex_lock(&log_init_lock);
-}
-
-int statd_writer_trylock() {
- return pthread_mutex_trylock(&log_init_lock);
-}
-
-void statsd_writer_init_unlock() {
- pthread_mutex_unlock(&log_init_lock);
-}
-
-static int statsdAvailable();
-static int statsdOpen();
-static void statsdClose();
-static int statsdWrite(struct timespec* ts, struct iovec* vec, size_t nr);
-static void statsdNoteDrop();
-static int statsdIsClosed();
-
-struct android_log_transport_write statsdLoggerWrite = {
- .name = "statsd",
- .sock = -EBADF,
- .available = statsdAvailable,
- .open = statsdOpen,
- .close = statsdClose,
- .write = statsdWrite,
- .noteDrop = statsdNoteDrop,
- .isClosed = statsdIsClosed,
-};
-
-/* log_init_lock assumed */
-static int statsdOpen() {
- int i, ret = 0;
-
- i = atomic_load(&statsdLoggerWrite.sock);
- if (i < 0) {
- int flags = SOCK_DGRAM;
-#ifdef SOCK_CLOEXEC
- flags |= SOCK_CLOEXEC;
-#endif
-#ifdef SOCK_NONBLOCK
- flags |= SOCK_NONBLOCK;
-#endif
- int sock = TEMP_FAILURE_RETRY(socket(PF_UNIX, flags, 0));
- if (sock < 0) {
- ret = -errno;
- } else {
- int sndbuf = 1 * 1024 * 1024; // set max send buffer size 1MB
- socklen_t bufLen = sizeof(sndbuf);
- // SO_RCVBUF does not have an effect on unix domain socket, but SO_SNDBUF does.
- // Proceed to connect even setsockopt fails.
- setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sndbuf, bufLen);
- struct sockaddr_un un;
- memset(&un, 0, sizeof(struct sockaddr_un));
- un.sun_family = AF_UNIX;
- strcpy(un.sun_path, "/dev/socket/statsdw");
-
- if (TEMP_FAILURE_RETRY(
- connect(sock, (struct sockaddr*)&un, sizeof(struct sockaddr_un))) < 0) {
- ret = -errno;
- switch (ret) {
- case -ENOTCONN:
- case -ECONNREFUSED:
- case -ENOENT:
- i = atomic_exchange(&statsdLoggerWrite.sock, ret);
- /* FALLTHRU */
- default:
- break;
- }
- close(sock);
- } else {
- ret = atomic_exchange(&statsdLoggerWrite.sock, sock);
- if ((ret >= 0) && (ret != sock)) {
- close(ret);
- }
- ret = 0;
- }
- }
- }
-
- return ret;
-}
-
-static void __statsdClose(int negative_errno) {
- int sock = atomic_exchange(&statsdLoggerWrite.sock, negative_errno);
- if (sock >= 0) {
- close(sock);
- }
-}
-
-static void statsdClose() {
- __statsdClose(-EBADF);
-}
-
-static int statsdAvailable() {
- if (atomic_load(&statsdLoggerWrite.sock) < 0) {
- if (access("/dev/socket/statsdw", W_OK) == 0) {
- return 0;
- }
- return -EBADF;
- }
- return 1;
-}
-
-static void statsdNoteDrop(int error, int tag) {
- atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed);
- atomic_exchange_explicit(&log_error, error, memory_order_relaxed);
- atomic_exchange_explicit(&atom_tag, tag, memory_order_relaxed);
-}
-
-static int statsdIsClosed() {
- if (atomic_load(&statsdLoggerWrite.sock) < 0) {
- return 1;
- }
- return 0;
-}
-
-static int statsdWrite(struct timespec* ts, struct iovec* vec, size_t nr) {
- ssize_t ret;
- int sock;
- static const unsigned headerLength = 1;
- struct iovec newVec[nr + headerLength];
- android_log_header_t header;
- size_t i, payloadSize;
-
- sock = atomic_load(&statsdLoggerWrite.sock);
- if (sock < 0) switch (sock) {
- case -ENOTCONN:
- case -ECONNREFUSED:
- case -ENOENT:
- break;
- default:
- return -EBADF;
- }
- /*
- * struct {
- * // what we provide to socket
- * android_log_header_t header;
- * // caller provides
- * union {
- * struct {
- * char prio;
- * char payload[];
- * } string;
- * struct {
- * uint32_t tag
- * char payload[];
- * } binary;
- * };
- * };
- */
-
- header.tid = gettid();
- header.realtime.tv_sec = ts->tv_sec;
- header.realtime.tv_nsec = ts->tv_nsec;
-
- newVec[0].iov_base = (unsigned char*)&header;
- newVec[0].iov_len = sizeof(header);
-
- // If we dropped events before, try to tell statsd.
- if (sock >= 0) {
- int32_t snapshot = atomic_exchange_explicit(&dropped, 0, memory_order_relaxed);
- if (snapshot) {
- android_log_event_long_t buffer;
- header.id = LOG_ID_STATS;
- // store the last log error in the tag field. This tag field is not used by statsd.
- buffer.header.tag = atomic_load(&log_error);
- buffer.payload.type = EVENT_TYPE_LONG;
- // format:
- // |atom_tag|dropped_count|
- int64_t composed_long = atomic_load(&atom_tag);
- // Send 2 int32's via an int64.
- composed_long = ((composed_long << 32) | ((int64_t)snapshot));
- buffer.payload.data = composed_long;
-
- newVec[headerLength].iov_base = &buffer;
- newVec[headerLength].iov_len = sizeof(buffer);
-
- ret = TEMP_FAILURE_RETRY(writev(sock, newVec, 2));
- if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
- atomic_fetch_add_explicit(&dropped, snapshot, memory_order_relaxed);
- }
- }
- }
-
- header.id = LOG_ID_STATS;
-
- for (payloadSize = 0, i = headerLength; i < nr + headerLength; i++) {
- newVec[i].iov_base = vec[i - headerLength].iov_base;
- payloadSize += newVec[i].iov_len = vec[i - headerLength].iov_len;
-
- if (payloadSize > LOGGER_ENTRY_MAX_PAYLOAD) {
- newVec[i].iov_len -= payloadSize - LOGGER_ENTRY_MAX_PAYLOAD;
- if (newVec[i].iov_len) {
- ++i;
- }
- break;
- }
- }
-
- /*
- * The write below could be lost, but will never block.
- *
- * ENOTCONN occurs if statsd has died.
- * ENOENT occurs if statsd is not running and socket is missing.
- * ECONNREFUSED occurs if we can not reconnect to statsd.
- * EAGAIN occurs if statsd is overloaded.
- */
- if (sock < 0) {
- ret = sock;
- } else {
- ret = TEMP_FAILURE_RETRY(writev(sock, newVec, i));
- if (ret < 0) {
- ret = -errno;
- }
- }
- switch (ret) {
- case -ENOTCONN:
- case -ECONNREFUSED:
- case -ENOENT:
- if (statd_writer_trylock()) {
- return ret; /* in a signal handler? try again when less stressed
- */
- }
- __statsdClose(ret);
- ret = statsdOpen();
- statsd_writer_init_unlock();
-
- if (ret < 0) {
- return ret;
- }
-
- ret = TEMP_FAILURE_RETRY(writev(atomic_load(&statsdLoggerWrite.sock), newVec, i));
- if (ret < 0) {
- ret = -errno;
- }
- /* FALLTHRU */
- default:
- break;
- }
-
- if (ret > (ssize_t)sizeof(header)) {
- ret -= sizeof(header);
- }
-
- return ret;
-}
diff --git a/libstats/socket/statsd_writer.h b/libstats/socket/statsd_writer.h
deleted file mode 100644
index 562bda5df..000000000
--- a/libstats/socket/statsd_writer.h
+++ /dev/null
@@ -1,47 +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.
- */
-
-#ifndef ANDROID_STATS_LOG_STATS_WRITER_H
-#define ANDROID_STATS_LOG_STATS_WRITER_H
-
-#include <pthread.h>
-#include <stdatomic.h>
-#include <sys/socket.h>
-
-/**
- * Internal lock should not be exposed. This is bad design.
- * TODO: rewrite it in c++ code and encapsulate the functionality in a
- * StatsdWriter class.
- */
-void statsd_writer_init_lock();
-int statsd_writer_init_trylock();
-void statsd_writer_init_unlock();
-
-struct android_log_transport_write {
- const char* name; /* human name to describe the transport */
- atomic_int sock;
- int (*available)(); /* Does not cause resources to be taken */
- int (*open)(); /* can be called multiple times, reusing current resources */
- void (*close)(); /* free up resources */
- /* write log to transport, returns number of bytes propagated, or -errno */
- int (*write)(struct timespec* ts, struct iovec* vec, size_t nr);
- /* note one log drop */
- void (*noteDrop)(int error, int tag);
- /* checks if the socket is closed */
- int (*isClosed)();
-};
-
-#endif // ANDROID_STATS_LOG_STATS_WRITER_H
diff --git a/libstats/socket/tests/stats_event_test.cpp b/libstats/socket/tests/stats_event_test.cpp
deleted file mode 100644
index 9a1fac89f..000000000
--- a/libstats/socket/tests/stats_event_test.cpp
+++ /dev/null
@@ -1,460 +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 "stats_event.h"
-#include <gtest/gtest.h>
-#include <utils/SystemClock.h>
-
-// Keep in sync with stats_event.c. Consider moving to separate header file to avoid duplication.
-/* ERRORS */
-#define ERROR_NO_TIMESTAMP 0x1
-#define ERROR_NO_ATOM_ID 0x2
-#define ERROR_OVERFLOW 0x4
-#define ERROR_ATTRIBUTION_CHAIN_TOO_LONG 0x8
-#define ERROR_TOO_MANY_KEY_VALUE_PAIRS 0x10
-#define ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD 0x20
-#define ERROR_INVALID_ANNOTATION_ID 0x40
-#define ERROR_ANNOTATION_ID_TOO_LARGE 0x80
-#define ERROR_TOO_MANY_ANNOTATIONS 0x100
-#define ERROR_TOO_MANY_FIELDS 0x200
-#define ERROR_INVALID_VALUE_TYPE 0x400
-#define ERROR_STRING_NOT_NULL_TERMINATED 0x800
-#define ERROR_ATOM_ID_INVALID_POSITION 0x2000
-
-/* TYPE IDS */
-#define INT32_TYPE 0x00
-#define INT64_TYPE 0x01
-#define STRING_TYPE 0x02
-#define LIST_TYPE 0x03
-#define FLOAT_TYPE 0x04
-#define BOOL_TYPE 0x05
-#define BYTE_ARRAY_TYPE 0x06
-#define OBJECT_TYPE 0x07
-#define KEY_VALUE_PAIRS_TYPE 0x08
-#define ATTRIBUTION_CHAIN_TYPE 0x09
-#define ERROR_TYPE 0x0F
-
-using std::string;
-using std::vector;
-
-// Side-effect: this function moves the start of the buffer past the read value
-template <class T>
-T readNext(uint8_t** buffer) {
- T value;
- if ((reinterpret_cast<uintptr_t>(*buffer) % alignof(T)) == 0) {
- value = *(T*)(*buffer);
- } else {
- memcpy(&value, *buffer, sizeof(T));
- }
- *buffer += sizeof(T);
- return value;
-}
-
-void checkTypeHeader(uint8_t** buffer, uint8_t typeId, uint8_t numAnnotations = 0) {
- uint8_t typeHeader = (numAnnotations << 4) | typeId;
- EXPECT_EQ(readNext<uint8_t>(buffer), typeHeader);
-}
-
-template <class T>
-void checkScalar(uint8_t** buffer, T expectedValue) {
- EXPECT_EQ(readNext<T>(buffer), expectedValue);
-}
-
-void checkString(uint8_t** buffer, const string& expectedString) {
- uint32_t size = readNext<uint32_t>(buffer);
- string parsedString((char*)(*buffer), size);
- EXPECT_EQ(parsedString, expectedString);
- *buffer += size; // move buffer past string we just read
-}
-
-void checkByteArray(uint8_t** buffer, const vector<uint8_t>& expectedByteArray) {
- uint32_t size = readNext<uint32_t>(buffer);
- vector<uint8_t> parsedByteArray(*buffer, *buffer + size);
- EXPECT_EQ(parsedByteArray, expectedByteArray);
- *buffer += size; // move buffer past byte array we just read
-}
-
-template <class T>
-void checkAnnotation(uint8_t** buffer, uint8_t annotationId, uint8_t typeId, T annotationValue) {
- EXPECT_EQ(readNext<uint8_t>(buffer), annotationId);
- EXPECT_EQ(readNext<uint8_t>(buffer), typeId);
- checkScalar<T>(buffer, annotationValue);
-}
-
-void checkMetadata(uint8_t** buffer, uint8_t numElements, int64_t startTime, int64_t endTime,
- uint32_t atomId, uint8_t numAtomLevelAnnotations = 0) {
- // All events start with OBJECT_TYPE id.
- checkTypeHeader(buffer, OBJECT_TYPE);
-
- // We increment by 2 because the number of elements listed in the
- // serialization accounts for the timestamp and atom id as well.
- checkScalar(buffer, static_cast<uint8_t>(numElements + 2));
-
- // Check timestamp
- checkTypeHeader(buffer, INT64_TYPE);
- int64_t timestamp = readNext<int64_t>(buffer);
- EXPECT_GE(timestamp, startTime);
- EXPECT_LE(timestamp, endTime);
-
- // Check atom id
- checkTypeHeader(buffer, INT32_TYPE, numAtomLevelAnnotations);
- checkScalar(buffer, atomId);
-}
-
-TEST(StatsEventTest, TestScalars) {
- uint32_t atomId = 100;
- int32_t int32Value = -5;
- int64_t int64Value = -2 * android::elapsedRealtimeNano();
- float floatValue = 2.0;
- bool boolValue = false;
-
- int64_t startTime = android::elapsedRealtimeNano();
- AStatsEvent* event = AStatsEvent_obtain();
- AStatsEvent_setAtomId(event, atomId);
- AStatsEvent_writeInt32(event, int32Value);
- AStatsEvent_writeInt64(event, int64Value);
- AStatsEvent_writeFloat(event, floatValue);
- AStatsEvent_writeBool(event, boolValue);
- AStatsEvent_build(event);
- int64_t endTime = android::elapsedRealtimeNano();
-
- size_t bufferSize;
- uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
- uint8_t* bufferEnd = buffer + bufferSize;
-
- checkMetadata(&buffer, /*numElements=*/4, startTime, endTime, atomId);
-
- // check int32 element
- checkTypeHeader(&buffer, INT32_TYPE);
- checkScalar(&buffer, int32Value);
-
- // check int64 element
- checkTypeHeader(&buffer, INT64_TYPE);
- checkScalar(&buffer, int64Value);
-
- // check float element
- checkTypeHeader(&buffer, FLOAT_TYPE);
- checkScalar(&buffer, floatValue);
-
- // check bool element
- checkTypeHeader(&buffer, BOOL_TYPE);
- checkScalar(&buffer, boolValue);
-
- EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
- EXPECT_EQ(AStatsEvent_getErrors(event), 0);
- AStatsEvent_release(event);
-}
-
-TEST(StatsEventTest, TestStrings) {
- uint32_t atomId = 100;
- string str = "test_string";
-
- int64_t startTime = android::elapsedRealtimeNano();
- AStatsEvent* event = AStatsEvent_obtain();
- AStatsEvent_setAtomId(event, atomId);
- AStatsEvent_writeString(event, str.c_str());
- AStatsEvent_build(event);
- int64_t endTime = android::elapsedRealtimeNano();
-
- size_t bufferSize;
- uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
- uint8_t* bufferEnd = buffer + bufferSize;
-
- checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId);
-
- checkTypeHeader(&buffer, STRING_TYPE);
- checkString(&buffer, str);
-
- EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
- EXPECT_EQ(AStatsEvent_getErrors(event), 0);
- AStatsEvent_release(event);
-}
-
-TEST(StatsEventTest, TestByteArrays) {
- uint32_t atomId = 100;
- vector<uint8_t> message = {'b', 'y', 't', '\0', 'e', 's'};
-
- int64_t startTime = android::elapsedRealtimeNano();
- AStatsEvent* event = AStatsEvent_obtain();
- AStatsEvent_setAtomId(event, atomId);
- AStatsEvent_writeByteArray(event, message.data(), message.size());
- AStatsEvent_build(event);
- int64_t endTime = android::elapsedRealtimeNano();
-
- size_t bufferSize;
- uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
- uint8_t* bufferEnd = buffer + bufferSize;
-
- checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId);
-
- checkTypeHeader(&buffer, BYTE_ARRAY_TYPE);
- checkByteArray(&buffer, message);
-
- EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
- EXPECT_EQ(AStatsEvent_getErrors(event), 0);
- AStatsEvent_release(event);
-}
-
-TEST(StatsEventTest, TestAttributionChains) {
- uint32_t atomId = 100;
-
- uint8_t numNodes = 50;
- uint32_t uids[numNodes];
- vector<string> tags(numNodes); // storage that cTag elements point to
- const char* cTags[numNodes];
- for (int i = 0; i < (int)numNodes; i++) {
- uids[i] = i;
- tags.push_back("test" + std::to_string(i));
- cTags[i] = tags[i].c_str();
- }
-
- int64_t startTime = android::elapsedRealtimeNano();
- AStatsEvent* event = AStatsEvent_obtain();
- AStatsEvent_setAtomId(event, atomId);
- AStatsEvent_writeAttributionChain(event, uids, cTags, numNodes);
- AStatsEvent_build(event);
- int64_t endTime = android::elapsedRealtimeNano();
-
- size_t bufferSize;
- uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
- uint8_t* bufferEnd = buffer + bufferSize;
-
- checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId);
-
- checkTypeHeader(&buffer, ATTRIBUTION_CHAIN_TYPE);
- checkScalar(&buffer, numNodes);
- for (int i = 0; i < numNodes; i++) {
- checkScalar(&buffer, uids[i]);
- checkString(&buffer, tags[i]);
- }
-
- EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
- EXPECT_EQ(AStatsEvent_getErrors(event), 0);
- AStatsEvent_release(event);
-}
-
-TEST(StatsEventTest, TestFieldAnnotations) {
- uint32_t atomId = 100;
-
- // first element information
- bool boolValue = false;
- uint8_t boolAnnotation1Id = 1;
- uint8_t boolAnnotation2Id = 2;
- bool boolAnnotation1Value = true;
- int32_t boolAnnotation2Value = 3;
-
- // second element information
- float floatValue = -5.0;
- uint8_t floatAnnotation1Id = 3;
- uint8_t floatAnnotation2Id = 4;
- int32_t floatAnnotation1Value = 8;
- bool floatAnnotation2Value = false;
-
- int64_t startTime = android::elapsedRealtimeNano();
- AStatsEvent* event = AStatsEvent_obtain();
- AStatsEvent_setAtomId(event, atomId);
- AStatsEvent_writeBool(event, boolValue);
- AStatsEvent_addBoolAnnotation(event, boolAnnotation1Id, boolAnnotation1Value);
- AStatsEvent_addInt32Annotation(event, boolAnnotation2Id, boolAnnotation2Value);
- AStatsEvent_writeFloat(event, floatValue);
- AStatsEvent_addInt32Annotation(event, floatAnnotation1Id, floatAnnotation1Value);
- AStatsEvent_addBoolAnnotation(event, floatAnnotation2Id, floatAnnotation2Value);
- AStatsEvent_build(event);
- int64_t endTime = android::elapsedRealtimeNano();
-
- size_t bufferSize;
- uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
- uint8_t* bufferEnd = buffer + bufferSize;
-
- checkMetadata(&buffer, /*numElements=*/2, startTime, endTime, atomId);
-
- // check first element
- checkTypeHeader(&buffer, BOOL_TYPE, /*numAnnotations=*/2);
- checkScalar(&buffer, boolValue);
- checkAnnotation(&buffer, boolAnnotation1Id, BOOL_TYPE, boolAnnotation1Value);
- checkAnnotation(&buffer, boolAnnotation2Id, INT32_TYPE, boolAnnotation2Value);
-
- // check second element
- checkTypeHeader(&buffer, FLOAT_TYPE, /*numAnnotations=*/2);
- checkScalar(&buffer, floatValue);
- checkAnnotation(&buffer, floatAnnotation1Id, INT32_TYPE, floatAnnotation1Value);
- checkAnnotation(&buffer, floatAnnotation2Id, BOOL_TYPE, floatAnnotation2Value);
-
- EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
- EXPECT_EQ(AStatsEvent_getErrors(event), 0);
- AStatsEvent_release(event);
-}
-
-TEST(StatsEventTest, TestAtomLevelAnnotations) {
- uint32_t atomId = 100;
- // atom-level annotation information
- uint8_t boolAnnotationId = 1;
- uint8_t int32AnnotationId = 2;
- bool boolAnnotationValue = false;
- int32_t int32AnnotationValue = 5;
-
- float fieldValue = -3.5;
-
- int64_t startTime = android::elapsedRealtimeNano();
- AStatsEvent* event = AStatsEvent_obtain();
- AStatsEvent_setAtomId(event, atomId);
- AStatsEvent_addBoolAnnotation(event, boolAnnotationId, boolAnnotationValue);
- AStatsEvent_addInt32Annotation(event, int32AnnotationId, int32AnnotationValue);
- AStatsEvent_writeFloat(event, fieldValue);
- AStatsEvent_build(event);
- int64_t endTime = android::elapsedRealtimeNano();
-
- size_t bufferSize;
- uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
- uint8_t* bufferEnd = buffer + bufferSize;
-
- checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId,
- /*numAtomLevelAnnotations=*/2);
-
- // check atom-level annotations
- checkAnnotation(&buffer, boolAnnotationId, BOOL_TYPE, boolAnnotationValue);
- checkAnnotation(&buffer, int32AnnotationId, INT32_TYPE, int32AnnotationValue);
-
- // check first element
- checkTypeHeader(&buffer, FLOAT_TYPE);
- checkScalar(&buffer, fieldValue);
-
- EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
- EXPECT_EQ(AStatsEvent_getErrors(event), 0);
- AStatsEvent_release(event);
-}
-
-TEST(StatsEventTest, TestNoAtomIdError) {
- AStatsEvent* event = AStatsEvent_obtain();
- // Don't set the atom id in order to trigger the error.
- AStatsEvent_build(event);
-
- uint32_t errors = AStatsEvent_getErrors(event);
- EXPECT_EQ(errors & ERROR_NO_ATOM_ID, ERROR_NO_ATOM_ID);
-
- AStatsEvent_release(event);
-}
-
-TEST(StatsEventTest, TestPushOverflowError) {
- const char* str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
- const int writeCount = 120; // Number of times to write str in the event.
-
- AStatsEvent* event = AStatsEvent_obtain();
- AStatsEvent_setAtomId(event, 100);
-
- // Add str to the event 120 times. Each str takes >35 bytes so this will
- // overflow the 4068 byte buffer.
- // We want to keep writeCount less than 127 to avoid hitting
- // ERROR_TOO_MANY_FIELDS.
- for (int i = 0; i < writeCount; i++) {
- AStatsEvent_writeString(event, str);
- }
- AStatsEvent_write(event);
-
- uint32_t errors = AStatsEvent_getErrors(event);
- EXPECT_EQ(errors & ERROR_OVERFLOW, ERROR_OVERFLOW);
-
- AStatsEvent_release(event);
-}
-
-TEST(StatsEventTest, TestPullOverflowError) {
- const uint32_t atomId = 10100;
- const vector<uint8_t> bytes(430 /* number of elements */, 1 /* value of each element */);
- const int writeCount = 120; // Number of times to write bytes in the event.
-
- AStatsEvent* event = AStatsEvent_obtain();
- AStatsEvent_setAtomId(event, atomId);
-
- // Add bytes to the event 120 times. Size of bytes is 430 so this will
- // overflow the 50 KB pulled event buffer.
- // We want to keep writeCount less than 127 to avoid hitting
- // ERROR_TOO_MANY_FIELDS.
- for (int i = 0; i < writeCount; i++) {
- AStatsEvent_writeByteArray(event, bytes.data(), bytes.size());
- }
- AStatsEvent_build(event);
-
- uint32_t errors = AStatsEvent_getErrors(event);
- EXPECT_EQ(errors & ERROR_OVERFLOW, ERROR_OVERFLOW);
-
- AStatsEvent_release(event);
-}
-
-TEST(StatsEventTest, TestLargePull) {
- const uint32_t atomId = 100;
- const string str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
- const int writeCount = 120; // Number of times to write str in the event.
- const int64_t startTime = android::elapsedRealtimeNano();
-
- AStatsEvent* event = AStatsEvent_obtain();
- AStatsEvent_setAtomId(event, atomId);
-
- // Add str to the event 120 times.
- // We want to keep writeCount less than 127 to avoid hitting
- // ERROR_TOO_MANY_FIELDS.
- for (int i = 0; i < writeCount; i++) {
- AStatsEvent_writeString(event, str.c_str());
- }
- AStatsEvent_build(event);
- int64_t endTime = android::elapsedRealtimeNano();
-
- size_t bufferSize;
- uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
- uint8_t* bufferEnd = buffer + bufferSize;
-
- checkMetadata(&buffer, writeCount, startTime, endTime, atomId);
-
- // Check all instances of str have been written.
- for (int i = 0; i < writeCount; i++) {
- checkTypeHeader(&buffer, STRING_TYPE);
- checkString(&buffer, str);
- }
-
- EXPECT_EQ(buffer, bufferEnd); // Ensure that we have read the entire buffer.
- EXPECT_EQ(AStatsEvent_getErrors(event), 0);
- AStatsEvent_release(event);
-}
-
-TEST(StatsEventTest, TestAtomIdInvalidPositionError) {
- AStatsEvent* event = AStatsEvent_obtain();
- AStatsEvent_writeInt32(event, 0);
- AStatsEvent_setAtomId(event, 100);
- AStatsEvent_writeBool(event, true);
- AStatsEvent_build(event);
-
- uint32_t errors = AStatsEvent_getErrors(event);
- EXPECT_EQ(errors & ERROR_ATOM_ID_INVALID_POSITION, ERROR_ATOM_ID_INVALID_POSITION);
-
- AStatsEvent_release(event);
-}
-
-TEST(StatsEventTest, TestOverwriteTimestamp) {
- uint32_t atomId = 100;
- int64_t expectedTimestamp = 0x123456789;
- AStatsEvent* event = AStatsEvent_obtain();
- AStatsEvent_setAtomId(event, atomId);
- AStatsEvent_overwriteTimestamp(event, expectedTimestamp);
- AStatsEvent_build(event);
-
- uint8_t* buffer = AStatsEvent_getBuffer(event, NULL);
-
- // Make sure that the timestamp is being overwritten.
- checkMetadata(&buffer, /*numElements=*/0, /*startTime=*/expectedTimestamp,
- /*endTime=*/expectedTimestamp, atomId);
-
- EXPECT_EQ(AStatsEvent_getErrors(event), 0);
- AStatsEvent_release(event);
-}
diff --git a/libstats/socket/tests/stats_writer_test.cpp b/libstats/socket/tests/stats_writer_test.cpp
deleted file mode 100644
index 749599ff3..000000000
--- a/libstats/socket/tests/stats_writer_test.cpp
+++ /dev/null
@@ -1,36 +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 <gtest/gtest.h>
-#include "stats_buffer_writer.h"
-#include "stats_event.h"
-#include "stats_socket.h"
-
-TEST(StatsWriterTest, TestSocketClose) {
- AStatsEvent* event = AStatsEvent_obtain();
- AStatsEvent_setAtomId(event, 100);
- AStatsEvent_writeInt32(event, 5);
- int successResult = AStatsEvent_write(event);
- AStatsEvent_release(event);
-
- // In the case of a successful write, we return the number of bytes written.
- EXPECT_GT(successResult, 0);
- EXPECT_FALSE(stats_log_is_closed());
-
- AStatsSocket_close();
-
- EXPECT_TRUE(stats_log_is_closed());
-}
diff --git a/storaged/include/storaged.h b/storaged/include/storaged.h
index 6f9204879..79b5d41ac 100644
--- a/storaged/include/storaged.h
+++ b/storaged/include/storaged.h
@@ -86,6 +86,7 @@ class storaged_t : public android::hardware::health::V2_0::IHealthInfoCallback,
sp<android::hardware::health::V2_0::IHealth> health;
unique_ptr<storage_info_t> storage_info;
static const uint32_t current_version;
+ Mutex proto_lock;
unordered_map<userid_t, bool> proto_loaded;
void load_proto(userid_t user_id);
char* prepare_proto(userid_t user_id, StoragedProto* proto);
diff --git a/storaged/storaged.cpp b/storaged/storaged.cpp
index 573b8c563..b7aa89ff7 100644
--- a/storaged/storaged.cpp
+++ b/storaged/storaged.cpp
@@ -162,6 +162,8 @@ storaged_t::storaged_t(void) {
}
void storaged_t::add_user_ce(userid_t user_id) {
+ Mutex::Autolock _l(proto_lock);
+
if (!proto_loaded[user_id]) {
load_proto(user_id);
proto_loaded[user_id] = true;
@@ -169,6 +171,8 @@ void storaged_t::add_user_ce(userid_t user_id) {
}
void storaged_t::remove_user_ce(userid_t user_id) {
+ Mutex::Autolock _l(proto_lock);
+
proto_loaded[user_id] = false;
mUidm.clear_user_history(user_id);
RemoveFileIfExists(proto_path(user_id), nullptr);
@@ -298,6 +302,8 @@ void storaged_t::flush_proto(userid_t user_id, StoragedProto* proto) {
}
void storaged_t::flush_protos(unordered_map<int, StoragedProto>* protos) {
+ Mutex::Autolock _l(proto_lock);
+
for (auto& it : *protos) {
/*
* Don't flush proto if we haven't attempted to load it from file.