• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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