1 /*
2 * Copyright (C) 2016 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 "usb_libusb.h"
18
19 #include "android-base/logging.h"
20
21 #include "adb_trace.h"
22 #include "client/detach.h"
23 #include "client/usb_libusb_inhouse_hotplug.h"
24 #include "usb.h"
25
26 using namespace std::chrono_literals;
27
28 using android::base::ScopedLockAssertion;
29
LibUsbConnection(std::unique_ptr<LibUsbDevice> device)30 LibUsbConnection::LibUsbConnection(std::unique_ptr<LibUsbDevice> device)
31 : device_(std::move(device)) {}
32
Init()33 void LibUsbConnection::Init() {
34 detached_ = attached_devices.ShouldStartDetached(const_cast<LibUsbConnection&>(*this));
35 VLOG(USB) << "Device " << device_->GetSerial() << " created detached=" << detached_;
36 }
37
~LibUsbConnection()38 LibUsbConnection::~LibUsbConnection() {
39 VLOG(USB) << "LibUsbConnection(" << Serial() << "): destructing";
40 Stop();
41 }
42
OnError(const std::string & reason)43 void LibUsbConnection::OnError(const std::string& reason) {
44 std::call_once(this->error_flag_, [this, reason]() {
45 // When a Windows machine goes to sleep it powers off all its USB host controllers to save
46 // energy. When the machine awakens, it powers them up which causes all the endpoints
47 // to be closed (which generates a read/write failure leading to us Close()ing the device).
48 // The USB device also briefly goes away and comes back with the exact same properties
49 // (including address). This makes in-house hotplug miss device reconnection upon wakeup. To
50 // solve that we remove ourselves from the set of known devices.
51 libusb_inhouse_hotplug::report_error(*this);
52
53 transport_->HandleError(reason);
54 });
55 }
56
HandleStop(const std::string & reason)57 void LibUsbConnection::HandleStop(const std::string& reason) {
58 // If we are detached, we should not report an error condition to the transport
59 // layer. If a connection is detached it has merely been requested to stop transmitting and
60 // release its resources.
61 if (detached_) {
62 VLOG(USB) << "Not reporting error '" << reason << "' because device " << transport_->serial
63 << " is detached";
64 } else {
65 OnError(reason);
66 }
67 }
68
Start()69 bool LibUsbConnection::Start() {
70 VLOG(USB) << "LibUsbConnection::Start()";
71 std::lock_guard<std::mutex> lock(mutex_);
72 if (running_) {
73 VLOG(USB) << "LibUsbConnection(" << Serial() << "): already started";
74 }
75
76 if (!device_->Open()) {
77 VLOG(USB) << "Unable to start " << Serial() << ": Failed to open device";
78 return false;
79 }
80
81 StartReadThread();
82 StartWriteThread();
83
84 running_ = true;
85 return true;
86 }
87
StartReadThread()88 void LibUsbConnection::StartReadThread() {
89 read_thread_ = std::thread([this]() {
90 LOG(INFO) << Serial() << ": read thread spawning";
91 while (true) {
92 auto packet = std::make_unique<apacket>();
93 if (!device_->Read(packet.get())) {
94 PLOG(INFO) << Serial() << ": read failed";
95 break;
96 }
97
98 bool got_stls_cmd = false;
99 if (packet->msg.command == A_STLS) {
100 got_stls_cmd = true;
101 }
102
103 transport_->HandleRead(std::move(packet));
104
105 // If we received the STLS packet, we are about to perform the TLS
106 // handshake. So this read thread must stop and resume after the
107 // handshake completes otherwise this will interfere in the process.
108 if (got_stls_cmd) {
109 LOG(INFO) << Serial() << ": Received STLS packet. Stopping read thread.";
110 break;
111 }
112 }
113 HandleStop("read thread stopped");
114 });
115 }
116
StartWriteThread()117 void LibUsbConnection::StartWriteThread() {
118 write_thread_ = std::thread([this]() {
119 LOG(INFO) << Serial() << ": write thread spawning";
120 while (true) {
121 std::unique_lock<std::mutex> lock(mutex_);
122 ScopedLockAssertion assume_locked(mutex_);
123 cv_write_.wait(lock, [this]() REQUIRES(mutex_) {
124 return !this->running_ || !this->write_queue_.empty();
125 });
126
127 if (!this->running_) {
128 break;
129 }
130
131 std::unique_ptr<apacket> packet = std::move(this->write_queue_.front());
132 this->write_queue_.pop_front();
133 lock.unlock();
134
135 if (!this->device_->Write(packet.get())) {
136 break;
137 }
138 }
139 HandleStop("write thread stopped");
140 });
141 }
142
DoTlsHandshake(RSA * key,std::string * auth_key)143 bool LibUsbConnection::DoTlsHandshake(RSA* key, std::string* auth_key) {
144 LOG(WARNING) << "TlsHandshake is not supported by libusb backen";
145 return false;
146 }
147
Reset()148 void LibUsbConnection::Reset() {
149 {
150 std::lock_guard<std::mutex> lock(mutex_);
151 if (!running_) {
152 LOG(INFO) << "LibUsbConnection(" << Serial() << "): not running";
153 return;
154 }
155 }
156
157 LOG(INFO) << "LibUsbConnection(" << Serial() << "): RESET";
158 this->device_->Reset();
159 Stop();
160 }
161
Stop()162 void LibUsbConnection::Stop() {
163 {
164 std::lock_guard<std::mutex> lock(mutex_);
165
166 if (!running_) {
167 LOG(INFO) << "LibUsbConnection(" << Serial() << ") Stop: not running";
168 return;
169 }
170
171 running_ = false;
172 }
173
174 LOG(INFO) << "LibUsbConnection(" << Serial() << "): stopping";
175
176 this->device_->Close();
177 this->cv_write_.notify_one();
178
179 // Move the threads out into locals with the lock taken, and then unlock to let them exit.
180 std::thread read_thread;
181 std::thread write_thread;
182
183 {
184 std::lock_guard<std::mutex> lock(mutex_);
185 read_thread = std::move(read_thread_);
186 write_thread = std::move(write_thread_);
187 }
188
189 read_thread.join();
190 write_thread.join();
191
192 HandleStop("stop requested");
193 {
194 std::lock_guard<std::mutex> lock(mutex_);
195 write_queue_.clear();
196 }
197 }
198
Write(std::unique_ptr<apacket> packet)199 bool LibUsbConnection::Write(std::unique_ptr<apacket> packet) {
200 {
201 std::lock_guard<std::mutex> lock(this->mutex_);
202 write_queue_.emplace_back(std::move(packet));
203 }
204
205 cv_write_.notify_one();
206 return true;
207 }
208
NegotiatedSpeedMbps()209 uint64_t LibUsbConnection::NegotiatedSpeedMbps() {
210 return device_->NegotiatedSpeedMbps();
211 }
212
MaxSpeedMbps()213 uint64_t LibUsbConnection::MaxSpeedMbps() {
214 return device_->MaxSpeedMbps();
215 }
216
SupportsDetach() const217 bool LibUsbConnection::SupportsDetach() const {
218 return true;
219 }
220
Attach(std::string *)221 bool LibUsbConnection::Attach(std::string*) {
222 VLOG(USB) << "LibUsbConnection::Attach";
223
224 if (!detached_) {
225 VLOG(USB) << "Already attached";
226 return true;
227 }
228
229 detached_ = false;
230 return Start();
231 }
232
Detach(std::string *)233 bool LibUsbConnection::Detach(std::string*) {
234 VLOG(USB) << "LibUsbConnection::Detach";
235 if (detached_) {
236 VLOG(USB) << "Already detached";
237 return true;
238 }
239
240 detached_ = true;
241 Stop();
242 return true;
243 }
244
IsDetached()245 bool LibUsbConnection::IsDetached() {
246 return detached_;
247 }
248
GetSessionId() const249 uint64_t LibUsbConnection::GetSessionId() const {
250 return device_->GetSessionId().id;
251 }
252