Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / devtools / adb / android_usb_device.cc
blobe5b5ab8ca9b103fde857b914ecf09093a5404655
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/devtools/adb/android_usb_device.h"
7 #include <set>
9 #include "base/barrier_closure.h"
10 #include "base/base64.h"
11 #include "base/lazy_instance.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/stl_util.h"
14 #include "base/strings/string_util.h"
15 #include "base/strings/stringprintf.h"
16 #include "chrome/browser/devtools/adb/android_rsa.h"
17 #include "chrome/browser/devtools/adb/android_usb_socket.h"
18 #include "chrome/browser/usb/usb_device.h"
19 #include "chrome/browser/usb/usb_interface.h"
20 #include "chrome/browser/usb/usb_service.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "crypto/rsa_private_key.h"
23 #include "net/base/ip_endpoint.h"
24 #include "net/base/net_errors.h"
25 #include "net/socket/stream_socket.h"
27 namespace {
29 const size_t kHeaderSize = 24;
31 const int kAdbClass = 0xff;
32 const int kAdbSubclass = 0x42;
33 const int kAdbProtocol = 0x1;
35 const int kUsbTimeout = 0;
37 const uint32 kMaxPayload = 4096;
38 const uint32 kVersion = 0x01000000;
40 static const char kHostConnectMessage[] = "host::";
42 using content::BrowserThread;
44 typedef std::vector<scoped_refptr<UsbDevice> > UsbDevices;
45 typedef std::set<scoped_refptr<UsbDevice> > UsbDeviceSet;
47 base::LazyInstance<AndroidUsbDevices>::Leaky g_devices =
48 LAZY_INSTANCE_INITIALIZER;
50 bool IsAndroidInterface(
51 scoped_refptr<const UsbInterfaceDescriptor> interface) {
52 if (interface->GetNumAltSettings() == 0)
53 return false;
55 scoped_refptr<const UsbInterfaceAltSettingDescriptor> idesc =
56 interface->GetAltSetting(0);
58 if (idesc->GetInterfaceClass() != kAdbClass ||
59 idesc->GetInterfaceSubclass() != kAdbSubclass ||
60 idesc->GetInterfaceProtocol() != kAdbProtocol ||
61 idesc->GetNumEndpoints() != 2) {
62 return false;
64 return true;
67 scoped_refptr<AndroidUsbDevice> ClaimInterface(
68 crypto::RSAPrivateKey* rsa_key,
69 scoped_refptr<UsbDeviceHandle> usb_handle,
70 scoped_refptr<const UsbInterfaceDescriptor> interface,
71 int interface_id) {
72 scoped_refptr<const UsbInterfaceAltSettingDescriptor> idesc =
73 interface->GetAltSetting(0);
75 int inbound_address = 0;
76 int outbound_address = 0;
77 int zero_mask = 0;
79 for (size_t i = 0; i < idesc->GetNumEndpoints(); ++i) {
80 scoped_refptr<const UsbEndpointDescriptor> edesc =
81 idesc->GetEndpoint(i);
82 if (edesc->GetTransferType() != USB_TRANSFER_BULK)
83 continue;
84 if (edesc->GetDirection() == USB_DIRECTION_INBOUND)
85 inbound_address = edesc->GetAddress();
86 else
87 outbound_address = edesc->GetAddress();
88 zero_mask = edesc->GetMaximumPacketSize() - 1;
91 if (inbound_address == 0 || outbound_address == 0)
92 return NULL;
94 if (!usb_handle->ClaimInterface(interface_id))
95 return NULL;
97 base::string16 serial;
98 if (!usb_handle->GetSerial(&serial) || serial.empty())
99 return NULL;
101 return new AndroidUsbDevice(rsa_key, usb_handle, UTF16ToASCII(serial),
102 inbound_address, outbound_address, zero_mask);
105 uint32 Checksum(const std::string& data) {
106 unsigned char* x = (unsigned char*)data.data();
107 int count = data.length();
108 uint32 sum = 0;
109 while (count-- > 0)
110 sum += *x++;
111 return sum;
114 void DumpMessage(bool outgoing, const char* data, size_t length) {
115 #if 0
116 std::string result = "";
117 if (length == kHeaderSize) {
118 for (size_t i = 0; i < 24; ++i) {
119 result += base::StringPrintf("%02x",
120 data[i] > 0 ? data[i] : (data[i] + 0x100) & 0xFF);
121 if ((i + 1) % 4 == 0)
122 result += " ";
124 for (size_t i = 0; i < 24; ++i) {
125 if (data[i] >= 0x20 && data[i] <= 0x7E)
126 result += data[i];
127 else
128 result += ".";
130 } else {
131 result = base::StringPrintf("%d: ", (int)length);
132 for (size_t i = 0; i < length; ++i) {
133 if (data[i] >= 0x20 && data[i] <= 0x7E)
134 result += data[i];
135 else
136 result += ".";
139 LOG(ERROR) << (outgoing ? "[out] " : "[ in] ") << result;
140 #endif // 0
143 void ReleaseInterface(scoped_refptr<UsbDeviceHandle> usb_device) {
144 usb_device->ReleaseInterface(1);
145 usb_device->Close();
148 } // namespace
150 AdbMessage::AdbMessage(uint32 command,
151 uint32 arg0,
152 uint32 arg1,
153 const std::string& body)
154 : command(command),
155 arg0(arg0),
156 arg1(arg1),
157 body(body) {
160 AdbMessage::~AdbMessage() {
163 static void RespondWithCountOnUIThread(base::Callback<void(int)> callback,
164 int count) {
165 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
166 callback.Run(count);
169 static void RespondOnUIThread(const AndroidUsbDevicesCallback& callback,
170 const AndroidUsbDevices& devices) {
171 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
172 callback.Run(devices);
175 static void RespondOnFileThread(const AndroidUsbDevicesCallback& callback) {
176 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
177 // Copy g_devices.Get() on file thread.
178 BrowserThread::PostTask(
179 BrowserThread::UI, FROM_HERE,
180 base::Bind(&RespondOnUIThread, callback, g_devices.Get()));
183 static void OpenAndroidDevicesOnFileThread(
184 crypto::RSAPrivateKey* rsa_key,
185 const base::Closure& barrier,
186 scoped_refptr<UsbDevice> device,
187 int interface_id,
188 bool success) {
189 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
190 if (success) {
191 scoped_refptr<UsbConfigDescriptor> config = device->ListInterfaces();
192 scoped_refptr<UsbDeviceHandle> usb_handle = device->Open();
193 if (usb_handle) {
194 scoped_refptr<AndroidUsbDevice> device =
195 ClaimInterface(rsa_key, usb_handle, config->GetInterface(interface_id),
196 interface_id);
197 if (device.get())
198 g_devices.Get().push_back(device);
199 else
200 usb_handle->Close();
203 barrier.Run();
206 static void CountOnFileThread(
207 const base::Callback<void(int)>& callback) {
208 UsbService* service = UsbService::GetInstance();
209 UsbDevices usb_devices;
210 if (service != NULL)
211 service->GetDevices(&usb_devices);
212 int device_count = 0;
213 for (UsbDevices::iterator it = usb_devices.begin(); it != usb_devices.end();
214 ++it) {
215 scoped_refptr<UsbConfigDescriptor> config = (*it)->ListInterfaces();
216 if (!config)
217 continue;
219 for (size_t j = 0; j < config->GetNumInterfaces(); ++j) {
220 if (IsAndroidInterface(config->GetInterface(j)))
221 ++device_count;
224 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
225 base::Bind(&RespondWithCountOnUIThread, callback,
226 device_count));
229 static void EnumerateOnFileThread(crypto::RSAPrivateKey* rsa_key,
230 const AndroidUsbDevicesCallback& callback) {
231 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
233 UsbService* service = UsbService::GetInstance();
234 UsbDevices usb_devices;
235 if (service != NULL)
236 service->GetDevices(&usb_devices);
238 AndroidUsbDevices& devices = g_devices.Get();
240 // GC Android devices with no actual usb device.
241 AndroidUsbDevices::iterator it = devices.begin();
242 UsbDeviceSet claimed_devices;
243 while (it != devices.end()) {
244 bool found_device = false;
245 for (UsbDevices::iterator it2 = usb_devices.begin();
246 it2 != usb_devices.end() && !found_device; ++it2) {
247 UsbDevice* usb_device = it2->get();
248 AndroidUsbDevice* device = it->get();
249 if (usb_device == device->usb_device()->device()) {
250 found_device = true;
251 claimed_devices.insert(usb_device);
255 if (!found_device)
256 it = devices.erase(it);
257 else
258 ++it;
261 // Add new devices.
262 base::Closure barrier = base::BarrierClosure(
263 usb_devices.size(), base::Bind(&RespondOnFileThread, callback));
265 for (UsbDevices::iterator it = usb_devices.begin(); it != usb_devices.end();
266 ++it) {
267 if (ContainsKey(claimed_devices, it->get())) {
268 barrier.Run();
269 continue;
272 scoped_refptr<UsbConfigDescriptor> config = (*it)->ListInterfaces();
273 if (!config) {
274 barrier.Run();
275 continue;
278 bool has_android_interface = false;
279 for (size_t j = 0; j < config->GetNumInterfaces(); ++j) {
280 if (!IsAndroidInterface(config->GetInterface(j)))
281 continue;
283 // Request permission on Chrome OS.
284 #if defined(OS_CHROMEOS)
285 (*it)->RequestUsbAcess(j, base::Bind(&OpenAndroidDevicesOnFileThread,
286 rsa_key, barrier, *it, j));
287 #else
288 OpenAndroidDevicesOnFileThread(rsa_key, barrier, *it, j, true);
289 #endif // defined(OS_CHROMEOS)
291 has_android_interface = true;
292 break;
294 if (!has_android_interface)
295 barrier.Run();
299 // static
300 void AndroidUsbDevice::CountDevices(
301 const base::Callback<void(int)>& callback) {
302 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
303 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
304 base::Bind(&CountOnFileThread, callback));
307 // static
308 void AndroidUsbDevice::Enumerate(crypto::RSAPrivateKey* rsa_key,
309 const AndroidUsbDevicesCallback& callback) {
310 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
311 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
312 base::Bind(&EnumerateOnFileThread, rsa_key,
313 callback));
316 AndroidUsbDevice::AndroidUsbDevice(crypto::RSAPrivateKey* rsa_key,
317 scoped_refptr<UsbDeviceHandle> usb_device,
318 const std::string& serial,
319 int inbound_address,
320 int outbound_address,
321 int zero_mask)
322 : message_loop_(NULL),
323 rsa_key_(rsa_key->Copy()),
324 usb_device_(usb_device),
325 serial_(serial),
326 inbound_address_(inbound_address),
327 outbound_address_(outbound_address),
328 zero_mask_(zero_mask),
329 is_connected_(false),
330 signature_sent_(false),
331 last_socket_id_(256),
332 terminated_(false) {
335 void AndroidUsbDevice::InitOnCallerThread() {
336 if (message_loop_)
337 return;
338 message_loop_ = base::MessageLoop::current();
339 Queue(new AdbMessage(AdbMessage::kCommandCNXN, kVersion, kMaxPayload,
340 kHostConnectMessage));
341 ReadHeader(true);
344 net::StreamSocket* AndroidUsbDevice::CreateSocket(const std::string& command) {
345 uint32 socket_id = ++last_socket_id_;
346 sockets_[socket_id] = new AndroidUsbSocket(this, socket_id, command,
347 base::Bind(&AndroidUsbDevice::SocketDeleted, this));
348 return sockets_[socket_id];
351 void AndroidUsbDevice::Send(uint32 command,
352 uint32 arg0,
353 uint32 arg1,
354 const std::string& body) {
355 scoped_refptr<AdbMessage> m = new AdbMessage(command, arg0, arg1, body);
356 // Delay open request if not yet connected.
357 if (!is_connected_) {
358 pending_messages_.push_back(m);
359 return;
361 Queue(m);
364 AndroidUsbDevice::~AndroidUsbDevice() {
365 Terminate();
366 usb_device_->AddRef();
367 BrowserThread::ReleaseSoon(BrowserThread::FILE, FROM_HERE,
368 usb_device_.get());
371 void AndroidUsbDevice::Queue(scoped_refptr<AdbMessage> message) {
372 // Queue header.
373 std::vector<uint32> header;
374 header.push_back(message->command);
375 header.push_back(message->arg0);
376 header.push_back(message->arg1);
377 bool append_zero = true;
378 if (message->body.empty())
379 append_zero = false;
380 if (message->command == AdbMessage::kCommandAUTH &&
381 message->arg0 == AdbMessage::kAuthSignature)
382 append_zero = false;
383 if (message->command == AdbMessage::kCommandWRTE)
384 append_zero = false;
386 size_t body_length = message->body.length() + (append_zero ? 1 : 0);
387 header.push_back(body_length);
388 header.push_back(Checksum(message->body));
389 header.push_back(message->command ^ 0xffffffff);
390 scoped_refptr<net::IOBuffer> header_buffer = new net::IOBuffer(kHeaderSize);
391 memcpy(header_buffer.get()->data(), &header[0], kHeaderSize);
392 outgoing_queue_.push(std::make_pair(header_buffer, kHeaderSize));
394 // Queue body.
395 if (!message->body.empty()) {
396 scoped_refptr<net::IOBuffer> body_buffer = new net::IOBuffer(body_length);
397 memcpy(body_buffer->data(), message->body.data(), message->body.length());
398 if (append_zero)
399 body_buffer->data()[body_length - 1] = 0;
400 outgoing_queue_.push(std::make_pair(body_buffer, body_length));
401 if (zero_mask_ && (body_length & zero_mask_) == 0) {
402 // Send a zero length packet.
403 outgoing_queue_.push(std::make_pair(body_buffer, 0));
406 ProcessOutgoing();
409 void AndroidUsbDevice::ProcessOutgoing() {
410 if (outgoing_queue_.empty() || terminated_)
411 return;
413 BulkMessage message = outgoing_queue_.front();
414 outgoing_queue_.pop();
415 DumpMessage(true, message.first->data(), message.second);
416 usb_device_->BulkTransfer(USB_DIRECTION_OUTBOUND, outbound_address_,
417 message.first, message.second, kUsbTimeout,
418 base::Bind(&AndroidUsbDevice::OutgoingMessageSent, this));
421 void AndroidUsbDevice::OutgoingMessageSent(UsbTransferStatus status,
422 scoped_refptr<net::IOBuffer> buffer,
423 size_t result) {
424 if (status != USB_TRANSFER_COMPLETED)
425 return;
426 message_loop_->PostTask(FROM_HERE,
427 base::Bind(&AndroidUsbDevice::ProcessOutgoing,
428 this));
431 void AndroidUsbDevice::ReadHeader(bool initial) {
432 if (terminated_)
433 return;
434 if (!initial && HasOneRef())
435 return; // Stop polling.
436 scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kHeaderSize);
437 usb_device_->BulkTransfer(USB_DIRECTION_INBOUND, inbound_address_,
438 buffer, kHeaderSize, kUsbTimeout,
439 base::Bind(&AndroidUsbDevice::ParseHeader, this));
442 void AndroidUsbDevice::ParseHeader(UsbTransferStatus status,
443 scoped_refptr<net::IOBuffer> buffer,
444 size_t result) {
445 if (status == USB_TRANSFER_TIMEOUT) {
446 message_loop_->PostTask(FROM_HERE,
447 base::Bind(&AndroidUsbDevice::ReadHeader, this,
448 false));
449 return;
452 if (status != USB_TRANSFER_COMPLETED || result != kHeaderSize) {
453 TransferError(status);
454 return;
457 DumpMessage(false, buffer->data(), result);
458 std::vector<uint32> header(6);
459 memcpy(&header[0], buffer->data(), result);
460 scoped_refptr<AdbMessage> message =
461 new AdbMessage(header[0], header[1], header[2], "");
462 uint32 data_length = header[3];
463 uint32 data_check = header[4];
464 uint32 magic = header[5];
465 if ((message->command ^ 0xffffffff) != magic) {
466 TransferError(USB_TRANSFER_ERROR);
467 return;
470 if (data_length == 0) {
471 message_loop_->PostTask(FROM_HERE,
472 base::Bind(&AndroidUsbDevice::HandleIncoming, this,
473 message));
474 return;
477 message_loop_->PostTask(FROM_HERE,
478 base::Bind(&AndroidUsbDevice::ReadBody, this,
479 message, data_length, data_check));
482 void AndroidUsbDevice::ReadBody(scoped_refptr<AdbMessage> message,
483 uint32 data_length,
484 uint32 data_check) {
485 scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(data_length);
486 usb_device_->BulkTransfer(USB_DIRECTION_INBOUND, inbound_address_,
487 buffer, data_length, kUsbTimeout,
488 base::Bind(&AndroidUsbDevice::ParseBody, this, message, data_length,
489 data_check));
492 void AndroidUsbDevice::ParseBody(scoped_refptr<AdbMessage> message,
493 uint32 data_length,
494 uint32 data_check,
495 UsbTransferStatus status,
496 scoped_refptr<net::IOBuffer> buffer,
497 size_t result) {
498 if (status == USB_TRANSFER_TIMEOUT) {
499 message_loop_->PostTask(FROM_HERE,
500 base::Bind(&AndroidUsbDevice::ReadBody, this,
501 message, data_length, data_check));
502 return;
505 if (status != USB_TRANSFER_COMPLETED ||
506 static_cast<uint32>(result) != data_length) {
507 TransferError(status);
508 return;
511 DumpMessage(false, buffer->data(), data_length);
512 message->body = std::string(buffer->data(), result);
513 if (Checksum(message->body) != data_check) {
514 TransferError(USB_TRANSFER_ERROR);
515 return;
518 message_loop_->PostTask(FROM_HERE,
519 base::Bind(&AndroidUsbDevice::HandleIncoming, this,
520 message));
523 void AndroidUsbDevice::HandleIncoming(scoped_refptr<AdbMessage> message) {
524 switch (message->command) {
525 case AdbMessage::kCommandAUTH:
527 DCHECK_EQ(message->arg0, static_cast<uint32>(AdbMessage::kAuthToken));
528 if (signature_sent_) {
529 Queue(new AdbMessage(AdbMessage::kCommandAUTH,
530 AdbMessage::kAuthRSAPublicKey, 0,
531 AndroidRSAPublicKey(rsa_key_.get())));
532 } else {
533 signature_sent_ = true;
534 std::string signature = AndroidRSASign(rsa_key_.get(), message->body);
535 if (!signature.empty()) {
536 Queue(new AdbMessage(AdbMessage::kCommandAUTH,
537 AdbMessage::kAuthSignature, 0,
538 signature));
539 } else {
540 Queue(new AdbMessage(AdbMessage::kCommandAUTH,
541 AdbMessage::kAuthRSAPublicKey, 0,
542 AndroidRSAPublicKey(rsa_key_.get())));
546 break;
547 case AdbMessage::kCommandCNXN:
549 is_connected_ = true;
550 PendingMessages pending;
551 pending.swap(pending_messages_);
552 for (PendingMessages::iterator it = pending.begin();
553 it != pending.end(); ++it) {
554 Queue(*it);
557 break;
558 case AdbMessage::kCommandOKAY:
559 case AdbMessage::kCommandWRTE:
560 case AdbMessage::kCommandCLSE:
562 AndroidUsbSockets::iterator it = sockets_.find(message->arg1);
563 if (it != sockets_.end())
564 it->second->HandleIncoming(message);
566 break;
567 default:
568 break;
570 ReadHeader(false);
573 void AndroidUsbDevice::TransferError(UsbTransferStatus status) {
574 message_loop_->PostTask(FROM_HERE,
575 base::Bind(&AndroidUsbDevice::Terminate,
576 this));
579 void AndroidUsbDevice::Terminate() {
580 if (terminated_)
581 return;
583 terminated_ = true;
585 // Iterate over copy.
586 AndroidUsbSockets sockets(sockets_);
587 for (AndroidUsbSockets::iterator it = sockets.begin();
588 it != sockets.end(); ++it) {
589 it->second->Terminated();
592 BrowserThread::PostTask(
593 BrowserThread::FILE, FROM_HERE,
594 base::Bind(&ReleaseInterface, usb_device_));
597 void AndroidUsbDevice::SocketDeleted(uint32 socket_id) {
598 sockets_.erase(socket_id);