1 /*
2 * Copyright (C) 2017 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 #include <algorithm>
17 #include <memory>
18 #include <gflags/gflags.h>
19
20 #include "common/libs/fs/shared_select.h"
21 #include "host/commands/virtual_usb_manager/vadb/usb_cmd_attach.h"
22 #include "host/commands/virtual_usb_manager/vadb/usb_cmd_control_transfer.h"
23 #include "host/commands/virtual_usb_manager/vadb/usb_cmd_data_transfer.h"
24 #include "host/commands/virtual_usb_manager/vadb/usb_cmd_device_list.h"
25 #include "host/commands/virtual_usb_manager/vadb/usb_cmd_heartbeat.h"
26 #include "host/commands/virtual_usb_manager/vadb/virtual_adb_client.h"
27
28 DEFINE_bool(debug_adb_client, false, "Turn on verbose logging in the virtual_adb_client.cpp");
29
30 #define VLOG(X) if (FLAGS_debug_adb_client) LOG(VERBOSE)
31
32 namespace vadb {
33 namespace {
34 constexpr int kHeartbeatTimeoutSeconds = 3;
35 } // namespace
36
VirtualADBClient(usbip::DevicePool * pool,cvd::SharedFD fd,int vhci_port,const std::string & usbip_socket_name)37 VirtualADBClient::VirtualADBClient(usbip::DevicePool* pool, cvd::SharedFD fd,
38 int vhci_port,
39 const std::string& usbip_socket_name)
40 : pool_{pool}, fd_{fd}, vhci_{vhci_port, usbip_socket_name} {
41 CHECK(vhci_.Init());
42 timer_ = cvd::SharedFD::TimerFD(CLOCK_MONOTONIC, 0);
43 SendHeartbeat();
44 }
45
RegisterDevice(const usb_forward::DeviceInfo & dev,const std::vector<usb_forward::InterfaceInfo> & ifaces)46 void VirtualADBClient::RegisterDevice(
47 const usb_forward::DeviceInfo& dev,
48 const std::vector<usb_forward::InterfaceInfo>& ifaces) {
49 auto d = std::unique_ptr<usbip::Device>(new usbip::Device);
50 d->vendor_id = dev.vendor_id;
51 d->product_id = dev.product_id;
52 d->dev_version = dev.dev_version;
53 d->dev_class = dev.dev_class;
54 d->dev_subclass = dev.dev_subclass;
55 d->dev_protocol = dev.dev_protocol;
56 d->speed = dev.speed;
57 d->configurations_count = dev.num_configurations;
58 d->configuration_number = dev.cur_configuration;
59
60 for (const auto& iface : ifaces) {
61 d->interfaces.push_back(usbip::Device::Interface{
62 iface.if_class, iface.if_subclass, iface.if_protocol});
63 }
64
65 uint8_t bus_id = dev.bus_id;
66 uint8_t dev_id = dev.dev_id;
67
68 d->handle_attach = [this, bus_id, dev_id]() -> bool {
69 return HandleAttach(bus_id, dev_id);
70 };
71
72 d->handle_control_transfer =
73 [this, bus_id, dev_id](
74 const usbip::CmdRequest& r, uint32_t deadline,
75 std::vector<uint8_t> data,
76 usbip::Device::AsyncTransferReadyCB callback) -> bool {
77 return HandleDeviceControlRequest(bus_id, dev_id, r, deadline,
78 std::move(data), std::move(callback));
79 };
80
81 d->handle_data_transfer =
82 [this, bus_id, dev_id](
83 uint8_t endpoint, bool is_host_to_device, uint32_t deadline,
84 std::vector<uint8_t> data,
85 usbip::Device::AsyncTransferReadyCB callback) -> bool {
86 return HandleDeviceDataRequest(bus_id, dev_id, endpoint, is_host_to_device,
87 deadline, std::move(data),
88 std::move(callback));
89 };
90
91 pool_->AddDevice(usbip::DevicePool::BusDevNumber{bus_id, dev_id},
92 std::move(d));
93
94 // Attach this device.
95 HandleAttach(bus_id, dev_id);
96 }
97
PopulateRemoteDevices()98 bool VirtualADBClient::PopulateRemoteDevices() {
99 return ExecuteCommand(std::unique_ptr<USBCommand>(new USBCmdDeviceList(
100 [this](const usb_forward::DeviceInfo& info,
101 const std::vector<usb_forward::InterfaceInfo>& ifaces) {
102 RegisterDevice(info, ifaces);
103 })));
104 }
105
HandleDeviceControlRequest(uint8_t bus_id,uint8_t dev_id,const usbip::CmdRequest & r,uint32_t timeout,std::vector<uint8_t> data,usbip::Device::AsyncTransferReadyCB callback)106 bool VirtualADBClient::HandleDeviceControlRequest(
107 uint8_t bus_id, uint8_t dev_id, const usbip::CmdRequest& r,
108 uint32_t timeout, std::vector<uint8_t> data,
109 usbip::Device::AsyncTransferReadyCB callback) {
110 return ExecuteCommand(std::unique_ptr<USBCommand>(new USBCmdControlTransfer(
111 bus_id, dev_id, r.type, r.cmd, r.value, r.index, timeout, std::move(data),
112 std::move(callback))));
113 }
114
HandleDeviceDataRequest(uint8_t bus_id,uint8_t dev_id,uint8_t endpoint,bool is_host_to_device,uint32_t deadline,std::vector<uint8_t> data,usbip::Device::AsyncTransferReadyCB callback)115 bool VirtualADBClient::HandleDeviceDataRequest(
116 uint8_t bus_id, uint8_t dev_id, uint8_t endpoint, bool is_host_to_device,
117 uint32_t deadline, std::vector<uint8_t> data,
118 usbip::Device::AsyncTransferReadyCB callback) {
119 return ExecuteCommand(std::unique_ptr<USBCommand>(
120 new USBCmdDataTransfer(bus_id, dev_id, endpoint, is_host_to_device,
121 deadline, std::move(data), std::move(callback))));
122 }
123
HandleAttach(uint8_t bus_id,uint8_t dev_id)124 bool VirtualADBClient::HandleAttach(uint8_t bus_id, uint8_t dev_id) {
125 return ExecuteCommand(
126 std::unique_ptr<USBCommand>(new USBCmdAttach(bus_id, dev_id)));
127 }
128
SendHeartbeat()129 bool VirtualADBClient::SendHeartbeat() {
130 VLOG(1) << "Sending heartbeat...";
131 struct itimerspec spec {};
132 spec.it_value.tv_sec = kHeartbeatTimeoutSeconds;
133 timer_->TimerSet(0, &spec, nullptr);
134
135 heartbeat_tag_ = tag_;
136
137 return ExecuteCommand(std::unique_ptr<USBCommand>(
138 new USBCmdHeartbeat([this](bool success) { HandleHeartbeat(success); })));
139 }
140
HandleHeartbeat(bool is_ready)141 void VirtualADBClient::HandleHeartbeat(bool is_ready) {
142 VLOG(1) << "Remote server status: " << is_ready;
143 if (is_ready && !is_remote_server_ready_) {
144 LOG(INFO) << "Remote server is now ready.";
145 PopulateRemoteDevices();
146 vhci_.TriggerAttach();
147 } else if (is_remote_server_ready_ && !is_ready) {
148 vhci_.TriggerDetach();
149 LOG(WARNING) << "Remote server connection lost.";
150 // It makes perfect sense to cancel all outstanding USB requests, as device
151 // is not going to answer any of these anyway.
152 for (const auto& pair : commands_) {
153 pair.second->OnResponse(false, fd_);
154 }
155 commands_.clear();
156 }
157 is_remote_server_ready_ = is_ready;
158 }
159
HandleHeartbeatTimeout()160 bool VirtualADBClient::HandleHeartbeatTimeout() {
161 uint64_t timer_result;
162 timer_->Read(&timer_result, sizeof(timer_result));
163
164 auto iter = commands_.find(heartbeat_tag_);
165 if (iter != commands_.end()) {
166 // Make sure to erase the value from list of commands prior to running
167 // callback. Particularly important for heartbeat, which cancels all
168 // outstanding USB commands (including self, if found), if device goes
169 // away (eg. reboots).
170 auto command = std::move(iter->second);
171 commands_.erase(iter);
172 command->OnResponse(false, fd_);
173 }
174
175 return SendHeartbeat();
176 }
177
ExecuteCommand(std::unique_ptr<USBCommand> cmd)178 bool VirtualADBClient::ExecuteCommand(std::unique_ptr<USBCommand> cmd) {
179 uint32_t this_tag = tag_;
180 tag_++;
181 usb_forward::RequestHeader hdr{cmd->Command(), this_tag};
182 if (fd_->Write(&hdr, sizeof(hdr)) != sizeof(hdr)) {
183 LOG(ERROR) << "Could not contact USB Forwarder: " << fd_->StrError();
184 return false;
185 }
186
187 if (!cmd->OnRequest(fd_)) return false;
188
189 commands_[this_tag] = std::move(cmd);
190 return true;
191 }
192
193 // BeforeSelect is Called right before Select() to populate interesting
194 // SharedFDs.
BeforeSelect(cvd::SharedFDSet * fd_read) const195 void VirtualADBClient::BeforeSelect(cvd::SharedFDSet* fd_read) const {
196 fd_read->Set(fd_);
197 fd_read->Set(timer_);
198 }
199
200 // AfterSelect is Called right after Select() to detect and respond to changes
201 // on affected SharedFDs.
202 // Return value indicates whether this client is still valid.
AfterSelect(const cvd::SharedFDSet & fd_read)203 bool VirtualADBClient::AfterSelect(const cvd::SharedFDSet& fd_read) {
204 if (fd_read.IsSet(timer_)) {
205 HandleHeartbeatTimeout();
206 }
207 if (fd_read.IsSet(fd_)) {
208 usb_forward::ResponseHeader rhdr;
209 if (fd_->Read(&rhdr, sizeof(rhdr)) != sizeof(rhdr)) {
210 LOG(ERROR) << "Could not read from USB Forwarder: " << fd_->StrError();
211 // TODO(ender): it is very likely the connection has been dropped by QEmu.
212 // Should we cancel all pending commands now?
213 return false;
214 }
215
216 auto iter = commands_.find(rhdr.tag);
217 if (iter == commands_.end()) {
218 // This is likely a late heartbeat response, but could very well be any of
219 // the remaining commands.
220 LOG(INFO) << "Received response for discarded tag " << rhdr.tag;
221 } else {
222 // Make sure to erase the value from list of commands prior to running
223 // callback. Particularly important for heartbeat, which cancels all
224 // outstanding USB commands (including self, if found), if device goes
225 // away (eg. reboots).
226 auto command = std::move(iter->second);
227 commands_.erase(iter);
228 command->OnResponse(rhdr.status == usb_forward::StatusSuccess, fd_);
229 }
230 }
231
232 return true;
233 }
234
235 } // namespace vadb
236