Josh Gao | 0560feb | 2019-01-22 19:36:15 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2019 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | // Include qemu_pipe.h before sysdeps, since it has inlined references to open, read, write. |
| 18 | #include <qemu_pipe.h> |
| 19 | |
| 20 | #define TRACE_TAG TRANSPORT |
Jason Jeremy Iman | 8461387 | 2019-07-19 12:44:39 +0900 | [diff] [blame] | 21 | #include "socket_spec.h" |
Josh Gao | 0560feb | 2019-01-22 19:36:15 -0800 | [diff] [blame] | 22 | #include "sysdeps.h" |
| 23 | #include "transport.h" |
| 24 | |
| 25 | #include <android-base/properties.h> |
| 26 | |
| 27 | #include "adb_io.h" |
| 28 | #include "adb_trace.h" |
| 29 | #include "adb_unique_fd.h" |
| 30 | |
| 31 | /* A worker thread that monitors host connections, and registers a transport for |
| 32 | * every new host connection. This thread replaces server_socket_thread on |
| 33 | * condition that adbd daemon runs inside the emulator, and emulator uses QEMUD |
| 34 | * pipe to communicate with adbd daemon inside the guest. This is done in order |
| 35 | * to provide more robust communication channel between ADB host and guest. The |
| 36 | * main issue with server_socket_thread approach is that it runs on top of TCP, |
| 37 | * and thus is sensitive to network disruptions. For instance, the |
| 38 | * ConnectionManager may decide to reset all network connections, in which case |
| 39 | * the connection between ADB host and guest will be lost. To make ADB traffic |
| 40 | * independent from the network, we use here 'adb' QEMUD service to transfer data |
| 41 | * between the host, and the guest. See external/qemu/android/adb-*.* that |
| 42 | * implements the emulator's side of the protocol. Another advantage of using |
| 43 | * QEMUD approach is that ADB will be up much sooner, since it doesn't depend |
| 44 | * anymore on network being set up. |
| 45 | * The guest side of the protocol contains the following phases: |
| 46 | * - Connect with adb QEMUD service. In this phase a handle to 'adb' QEMUD service |
| 47 | * is opened, and it becomes clear whether or not emulator supports that |
| 48 | * protocol. |
| 49 | * - Wait for the ADB host to create connection with the guest. This is done by |
| 50 | * sending an 'accept' request to the adb QEMUD service, and waiting on |
| 51 | * response. |
| 52 | * - When new ADB host connection is accepted, the connection with adb QEMUD |
| 53 | * service is registered as the transport, and a 'start' request is sent to the |
| 54 | * adb QEMUD service, indicating that the guest is ready to receive messages. |
| 55 | * Note that the guest will ignore messages sent down from the emulator before |
| 56 | * the transport registration is completed. That's why we need to send the |
| 57 | * 'start' request after the transport is registered. |
| 58 | */ |
Jason Jeremy Iman | 8461387 | 2019-07-19 12:44:39 +0900 | [diff] [blame] | 59 | void qemu_socket_thread(std::string_view addr) { |
Josh Gao | 0560feb | 2019-01-22 19:36:15 -0800 | [diff] [blame] | 60 | /* 'accept' request to the adb QEMUD service. */ |
| 61 | static const char _accept_req[] = "accept"; |
| 62 | /* 'start' request to the adb QEMUD service. */ |
| 63 | static const char _start_req[] = "start"; |
| 64 | /* 'ok' reply from the adb QEMUD service. */ |
| 65 | static const char _ok_resp[] = "ok"; |
| 66 | |
| 67 | char tmp[256]; |
| 68 | char con_name[32]; |
| 69 | |
| 70 | adb_thread_setname("qemu socket"); |
| 71 | D("transport: qemu_socket_thread() starting"); |
| 72 | |
Jason Jeremy Iman | 8461387 | 2019-07-19 12:44:39 +0900 | [diff] [blame] | 73 | std::string error; |
| 74 | int port = get_host_socket_spec_port(addr, &error); |
| 75 | if (port == -1) { |
| 76 | port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT; |
| 77 | } |
| 78 | |
Josh Gao | 0560feb | 2019-01-22 19:36:15 -0800 | [diff] [blame] | 79 | /* adb QEMUD service connection request. */ |
| 80 | snprintf(con_name, sizeof(con_name), "pipe:qemud:adb:%d", port); |
| 81 | |
| 82 | /* Connect to the adb QEMUD service. */ |
| 83 | unique_fd fd(qemu_pipe_open(con_name)); |
| 84 | if (fd < 0) { |
| 85 | /* This could be an older version of the emulator, that doesn't |
| 86 | * implement adb QEMUD service. Fall back to the old TCP way. */ |
| 87 | D("adb service is not available. Falling back to TCP socket."); |
Jason Jeremy Iman | 8461387 | 2019-07-19 12:44:39 +0900 | [diff] [blame] | 88 | std::thread(server_socket_thread, adb_listen, addr).detach(); |
Josh Gao | 0560feb | 2019-01-22 19:36:15 -0800 | [diff] [blame] | 89 | return; |
| 90 | } |
| 91 | |
| 92 | while (true) { |
| 93 | /* |
| 94 | * Wait till the host creates a new connection. |
| 95 | */ |
| 96 | |
| 97 | /* Send the 'accept' request. */ |
| 98 | if (WriteFdExactly(fd.get(), _accept_req, strlen(_accept_req))) { |
| 99 | /* Wait for the response. In the response we expect 'ok' on success, |
| 100 | * or 'ko' on failure. */ |
| 101 | if (!ReadFdExactly(fd.get(), tmp, 2) || memcmp(tmp, _ok_resp, 2)) { |
| 102 | D("Accepting ADB host connection has failed."); |
| 103 | } else { |
| 104 | /* Host is connected. Register the transport, and start the |
| 105 | * exchange. */ |
| 106 | std::string serial = android::base::StringPrintf("host-%d", fd.get()); |
| 107 | WriteFdExactly(fd.get(), _start_req, strlen(_start_req)); |
| 108 | register_socket_transport(std::move(fd), std::move(serial), port, 1, |
| 109 | [](atransport*) { return ReconnectResult::Abort; }); |
| 110 | } |
| 111 | |
| 112 | /* Prepare for accepting of the next ADB host connection. */ |
| 113 | fd.reset(qemu_pipe_open(con_name)); |
| 114 | if (fd < 0) { |
| 115 | D("adb service become unavailable."); |
| 116 | return; |
| 117 | } |
| 118 | } else { |
| 119 | D("Unable to send the '%s' request to ADB service.", _accept_req); |
| 120 | return; |
| 121 | } |
| 122 | } |
| 123 | D("transport: qemu_socket_thread() exiting"); |
| 124 | return; |
| 125 | } |
| 126 | |
| 127 | // If adbd is running inside the emulator, it will normally use QEMUD pipe (aka |
| 128 | // goldfish) as the transport. This can either be explicitly set by the |
| 129 | // service.adb.transport property, or be inferred from ro.kernel.qemu that is |
| 130 | // set to "1" for ranchu/goldfish. |
| 131 | bool use_qemu_goldfish() { |
| 132 | // Legacy way to detect if adbd should use the goldfish pipe is to check for |
| 133 | // ro.kernel.qemu, keep that behaviour for backward compatibility. |
| 134 | if (android::base::GetBoolProperty("ro.kernel.qemu", false)) { |
| 135 | return true; |
| 136 | } |
| 137 | // If service.adb.transport is present and is set to "goldfish", use the |
| 138 | // QEMUD pipe. |
| 139 | if (android::base::GetProperty("service.adb.transport", "") == "goldfish") { |
| 140 | return true; |
| 141 | } |
| 142 | return false; |
| 143 | } |