• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "chrome/browser/devtools/adb/android_usb_device.h"
6 
7 #include <set>
8 
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"
26 
27 namespace {
28 
29 const size_t kHeaderSize = 24;
30 
31 const int kAdbClass = 0xff;
32 const int kAdbSubclass = 0x42;
33 const int kAdbProtocol = 0x1;
34 
35 const int kUsbTimeout = 0;
36 
37 const uint32 kMaxPayload = 4096;
38 const uint32 kVersion = 0x01000000;
39 
40 static const char kHostConnectMessage[] = "host::";
41 
42 using content::BrowserThread;
43 
44 typedef std::vector<scoped_refptr<UsbDevice> > UsbDevices;
45 typedef std::set<scoped_refptr<UsbDevice> > UsbDeviceSet;
46 
47 base::LazyInstance<AndroidUsbDevices>::Leaky g_devices =
48     LAZY_INSTANCE_INITIALIZER;
49 
IsAndroidInterface(scoped_refptr<const UsbInterfaceDescriptor> interface)50 bool IsAndroidInterface(
51     scoped_refptr<const UsbInterfaceDescriptor> interface) {
52   if (interface->GetNumAltSettings() == 0)
53     return false;
54 
55   scoped_refptr<const UsbInterfaceAltSettingDescriptor> idesc =
56       interface->GetAltSetting(0);
57 
58   if (idesc->GetInterfaceClass() != kAdbClass ||
59       idesc->GetInterfaceSubclass() != kAdbSubclass ||
60       idesc->GetInterfaceProtocol() != kAdbProtocol ||
61       idesc->GetNumEndpoints() != 2) {
62     return false;
63   }
64   return true;
65 }
66 
ClaimInterface(crypto::RSAPrivateKey * rsa_key,scoped_refptr<UsbDeviceHandle> usb_handle,scoped_refptr<const UsbInterfaceDescriptor> interface,int interface_id)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);
74 
75   int inbound_address = 0;
76   int outbound_address = 0;
77   int zero_mask = 0;
78 
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;
89   }
90 
91   if (inbound_address == 0 || outbound_address == 0)
92     return NULL;
93 
94   if (!usb_handle->ClaimInterface(interface_id))
95     return NULL;
96 
97   base::string16 serial;
98   if (!usb_handle->GetSerial(&serial) || serial.empty())
99     return NULL;
100 
101   return new AndroidUsbDevice(rsa_key, usb_handle, UTF16ToASCII(serial),
102                               inbound_address, outbound_address, zero_mask);
103 }
104 
Checksum(const std::string & data)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;
112 }
113 
DumpMessage(bool outgoing,const char * data,size_t length)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 += " ";
123     }
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 += ".";
129     }
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 += ".";
137     }
138   }
139   LOG(ERROR) << (outgoing ? "[out] " : "[ in] ") << result;
140 #endif  // 0
141 }
142 
ReleaseInterface(scoped_refptr<UsbDeviceHandle> usb_device)143 void ReleaseInterface(scoped_refptr<UsbDeviceHandle> usb_device) {
144   usb_device->ReleaseInterface(1);
145   usb_device->Close();
146 }
147 
148 }  // namespace
149 
AdbMessage(uint32 command,uint32 arg0,uint32 arg1,const std::string & body)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) {
158 }
159 
~AdbMessage()160 AdbMessage::~AdbMessage() {
161 }
162 
RespondWithCountOnUIThread(base::Callback<void (int)> callback,int count)163 static void RespondWithCountOnUIThread(base::Callback<void(int)> callback,
164                                        int count) {
165   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
166   callback.Run(count);
167 }
168 
RespondOnUIThread(const AndroidUsbDevicesCallback & callback,const AndroidUsbDevices & devices)169 static void RespondOnUIThread(const AndroidUsbDevicesCallback& callback,
170                               const AndroidUsbDevices& devices) {
171   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
172   callback.Run(devices);
173 }
174 
RespondOnFileThread(const AndroidUsbDevicesCallback & callback)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()));
181 }
182 
OpenAndroidDevicesOnFileThread(crypto::RSAPrivateKey * rsa_key,const base::Closure & barrier,scoped_refptr<UsbDevice> device,int interface_id,bool success)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();
201     }
202   }
203   barrier.Run();
204 }
205 
CountOnFileThread(const base::Callback<void (int)> & callback)206 static void CountOnFileThread(
207     const base::Callback<void(int)>& callback) {
208   UsbService* service = UsbService::GetInstance();
209   UsbDevices usb_devices;
210   service->GetDevices(&usb_devices);
211   int device_count = 0;
212   for (UsbDevices::iterator it = usb_devices.begin(); it != usb_devices.end();
213        ++it) {
214     scoped_refptr<UsbConfigDescriptor> config = (*it)->ListInterfaces();
215     if (!config)
216       continue;
217 
218     for (size_t j = 0; j < config->GetNumInterfaces(); ++j) {
219       if (IsAndroidInterface(config->GetInterface(j)))
220         ++device_count;
221     }
222   }
223   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
224                           base::Bind(&RespondWithCountOnUIThread, callback,
225                                      device_count));
226 }
227 
EnumerateOnFileThread(crypto::RSAPrivateKey * rsa_key,const AndroidUsbDevicesCallback & callback)228 static void EnumerateOnFileThread(crypto::RSAPrivateKey* rsa_key,
229                                   const AndroidUsbDevicesCallback& callback) {
230   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
231 
232   UsbService* service = UsbService::GetInstance();
233   UsbDevices usb_devices;
234   service->GetDevices(&usb_devices);
235 
236   AndroidUsbDevices& devices = g_devices.Get();
237 
238   // GC Android devices with no actual usb device.
239   AndroidUsbDevices::iterator it = devices.begin();
240   UsbDeviceSet claimed_devices;
241   while (it != devices.end()) {
242     bool found_device = false;
243     for (UsbDevices::iterator it2 = usb_devices.begin();
244          it2 != usb_devices.end() && !found_device; ++it2) {
245       UsbDevice* usb_device = it2->get();
246       AndroidUsbDevice* device = it->get();
247       if (usb_device == device->usb_device()->device()) {
248         found_device = true;
249         claimed_devices.insert(usb_device);
250       }
251     }
252 
253     if (!found_device)
254       it = devices.erase(it);
255     else
256       ++it;
257   }
258 
259   // Add new devices.
260   base::Closure barrier = base::BarrierClosure(
261       usb_devices.size(), base::Bind(&RespondOnFileThread, callback));
262 
263   for (UsbDevices::iterator it = usb_devices.begin(); it != usb_devices.end();
264        ++it) {
265     if (ContainsKey(claimed_devices, it->get())) {
266       barrier.Run();
267       continue;
268     }
269 
270     scoped_refptr<UsbConfigDescriptor> config = (*it)->ListInterfaces();
271     if (!config) {
272       barrier.Run();
273       continue;
274     }
275 
276     bool has_android_interface = false;
277     for (size_t j = 0; j < config->GetNumInterfaces(); ++j) {
278       if (!IsAndroidInterface(config->GetInterface(j)))
279         continue;
280 
281       // Request permission on Chrome OS.
282 #if defined(OS_CHROMEOS)
283       (*it)->RequestUsbAcess(j, base::Bind(&OpenAndroidDevicesOnFileThread,
284                                            rsa_key, barrier, *it, j));
285 #else
286       OpenAndroidDevicesOnFileThread(rsa_key, barrier, *it, j, true);
287 #endif  // defined(OS_CHROMEOS)
288 
289       has_android_interface = true;
290       break;
291     }
292     if (!has_android_interface)
293       barrier.Run();
294   }
295 }
296 
297 // static
CountDevices(const base::Callback<void (int)> & callback)298 void AndroidUsbDevice::CountDevices(
299     const base::Callback<void(int)>& callback) {
300   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
301   BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
302                           base::Bind(&CountOnFileThread, callback));
303 }
304 
305 // static
Enumerate(crypto::RSAPrivateKey * rsa_key,const AndroidUsbDevicesCallback & callback)306 void AndroidUsbDevice::Enumerate(crypto::RSAPrivateKey* rsa_key,
307                                  const AndroidUsbDevicesCallback& callback) {
308   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
309   BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
310                           base::Bind(&EnumerateOnFileThread, rsa_key,
311                                      callback));
312 }
313 
AndroidUsbDevice(crypto::RSAPrivateKey * rsa_key,scoped_refptr<UsbDeviceHandle> usb_device,const std::string & serial,int inbound_address,int outbound_address,int zero_mask)314 AndroidUsbDevice::AndroidUsbDevice(crypto::RSAPrivateKey* rsa_key,
315                                    scoped_refptr<UsbDeviceHandle> usb_device,
316                                    const std::string& serial,
317                                    int inbound_address,
318                                    int outbound_address,
319                                    int zero_mask)
320     : message_loop_(NULL),
321       rsa_key_(rsa_key->Copy()),
322       usb_device_(usb_device),
323       serial_(serial),
324       inbound_address_(inbound_address),
325       outbound_address_(outbound_address),
326       zero_mask_(zero_mask),
327       is_connected_(false),
328       signature_sent_(false),
329       last_socket_id_(256),
330       terminated_(false) {
331 }
332 
InitOnCallerThread()333 void AndroidUsbDevice::InitOnCallerThread() {
334   if (message_loop_)
335     return;
336   message_loop_ = base::MessageLoop::current();
337   Queue(new AdbMessage(AdbMessage::kCommandCNXN, kVersion, kMaxPayload,
338                        kHostConnectMessage));
339   ReadHeader(true);
340 }
341 
CreateSocket(const std::string & command)342 net::StreamSocket* AndroidUsbDevice::CreateSocket(const std::string& command) {
343   uint32 socket_id = ++last_socket_id_;
344   sockets_[socket_id] = new AndroidUsbSocket(this, socket_id, command,
345       base::Bind(&AndroidUsbDevice::SocketDeleted, this));
346   return sockets_[socket_id];
347 }
348 
Send(uint32 command,uint32 arg0,uint32 arg1,const std::string & body)349 void AndroidUsbDevice::Send(uint32 command,
350                             uint32 arg0,
351                             uint32 arg1,
352                             const std::string& body) {
353   scoped_refptr<AdbMessage> m = new AdbMessage(command, arg0, arg1, body);
354   // Delay open request if not yet connected.
355   if (!is_connected_) {
356     pending_messages_.push_back(m);
357     return;
358   }
359   Queue(m);
360 }
361 
~AndroidUsbDevice()362 AndroidUsbDevice::~AndroidUsbDevice() {
363   Terminate();
364   usb_device_->AddRef();
365   BrowserThread::ReleaseSoon(BrowserThread::FILE, FROM_HERE,
366                              usb_device_.get());
367 }
368 
Queue(scoped_refptr<AdbMessage> message)369 void AndroidUsbDevice::Queue(scoped_refptr<AdbMessage> message) {
370   // Queue header.
371   std::vector<uint32> header;
372   header.push_back(message->command);
373   header.push_back(message->arg0);
374   header.push_back(message->arg1);
375   bool append_zero = true;
376   if (message->body.empty())
377     append_zero = false;
378   if (message->command == AdbMessage::kCommandAUTH &&
379       message->arg0 == AdbMessage::kAuthSignature)
380     append_zero = false;
381   if (message->command == AdbMessage::kCommandWRTE)
382     append_zero = false;
383 
384   size_t body_length = message->body.length() + (append_zero ? 1 : 0);
385   header.push_back(body_length);
386   header.push_back(Checksum(message->body));
387   header.push_back(message->command ^ 0xffffffff);
388   scoped_refptr<net::IOBuffer> header_buffer = new net::IOBuffer(kHeaderSize);
389   memcpy(header_buffer.get()->data(), &header[0], kHeaderSize);
390   outgoing_queue_.push(std::make_pair(header_buffer, kHeaderSize));
391 
392   // Queue body.
393   if (!message->body.empty()) {
394     scoped_refptr<net::IOBuffer> body_buffer = new net::IOBuffer(body_length);
395     memcpy(body_buffer->data(), message->body.data(), message->body.length());
396     if (append_zero)
397       body_buffer->data()[body_length - 1] = 0;
398     outgoing_queue_.push(std::make_pair(body_buffer, body_length));
399     if (zero_mask_ && (body_length & zero_mask_) == 0) {
400       // Send a zero length packet.
401       outgoing_queue_.push(std::make_pair(body_buffer, 0));
402     }
403   }
404   ProcessOutgoing();
405 }
406 
ProcessOutgoing()407 void AndroidUsbDevice::ProcessOutgoing() {
408   if (outgoing_queue_.empty() || terminated_)
409     return;
410 
411   BulkMessage message = outgoing_queue_.front();
412   outgoing_queue_.pop();
413   DumpMessage(true, message.first->data(), message.second);
414   usb_device_->BulkTransfer(USB_DIRECTION_OUTBOUND, outbound_address_,
415       message.first, message.second, kUsbTimeout,
416       base::Bind(&AndroidUsbDevice::OutgoingMessageSent, this));
417 }
418 
OutgoingMessageSent(UsbTransferStatus status,scoped_refptr<net::IOBuffer> buffer,size_t result)419 void AndroidUsbDevice::OutgoingMessageSent(UsbTransferStatus status,
420                                            scoped_refptr<net::IOBuffer> buffer,
421                                            size_t result) {
422   if (status != USB_TRANSFER_COMPLETED)
423     return;
424   message_loop_->PostTask(FROM_HERE,
425                           base::Bind(&AndroidUsbDevice::ProcessOutgoing,
426                                      this));
427 }
428 
ReadHeader(bool initial)429 void AndroidUsbDevice::ReadHeader(bool initial) {
430   if (terminated_)
431     return;
432   if (!initial && HasOneRef())
433     return;  // Stop polling.
434   scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kHeaderSize);
435   usb_device_->BulkTransfer(USB_DIRECTION_INBOUND, inbound_address_,
436       buffer, kHeaderSize, kUsbTimeout,
437       base::Bind(&AndroidUsbDevice::ParseHeader, this));
438 }
439 
ParseHeader(UsbTransferStatus status,scoped_refptr<net::IOBuffer> buffer,size_t result)440 void AndroidUsbDevice::ParseHeader(UsbTransferStatus status,
441                                    scoped_refptr<net::IOBuffer> buffer,
442                                    size_t result) {
443   if (status == USB_TRANSFER_TIMEOUT) {
444     message_loop_->PostTask(FROM_HERE,
445                             base::Bind(&AndroidUsbDevice::ReadHeader, this,
446                                        false));
447     return;
448   }
449 
450   if (status != USB_TRANSFER_COMPLETED || result != kHeaderSize) {
451     TransferError(status);
452     return;
453   }
454 
455   DumpMessage(false, buffer->data(), result);
456   std::vector<uint32> header(6);
457   memcpy(&header[0], buffer->data(), result);
458   scoped_refptr<AdbMessage> message =
459       new AdbMessage(header[0], header[1], header[2], "");
460   uint32 data_length = header[3];
461   uint32 data_check = header[4];
462   uint32 magic = header[5];
463   if ((message->command ^ 0xffffffff) != magic) {
464     TransferError(USB_TRANSFER_ERROR);
465     return;
466   }
467 
468   if (data_length == 0) {
469     message_loop_->PostTask(FROM_HERE,
470                             base::Bind(&AndroidUsbDevice::HandleIncoming, this,
471                                        message));
472     return;
473   }
474 
475   message_loop_->PostTask(FROM_HERE,
476                           base::Bind(&AndroidUsbDevice::ReadBody, this,
477                                      message, data_length, data_check));
478 }
479 
ReadBody(scoped_refptr<AdbMessage> message,uint32 data_length,uint32 data_check)480 void AndroidUsbDevice::ReadBody(scoped_refptr<AdbMessage> message,
481                                 uint32 data_length,
482                                 uint32 data_check) {
483   scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(data_length);
484   usb_device_->BulkTransfer(USB_DIRECTION_INBOUND, inbound_address_,
485       buffer, data_length, kUsbTimeout,
486       base::Bind(&AndroidUsbDevice::ParseBody, this, message, data_length,
487                  data_check));
488 }
489 
ParseBody(scoped_refptr<AdbMessage> message,uint32 data_length,uint32 data_check,UsbTransferStatus status,scoped_refptr<net::IOBuffer> buffer,size_t result)490 void AndroidUsbDevice::ParseBody(scoped_refptr<AdbMessage> message,
491                                  uint32 data_length,
492                                  uint32 data_check,
493                                  UsbTransferStatus status,
494                                  scoped_refptr<net::IOBuffer> buffer,
495                                  size_t result) {
496   if (status == USB_TRANSFER_TIMEOUT) {
497     message_loop_->PostTask(FROM_HERE,
498                             base::Bind(&AndroidUsbDevice::ReadBody, this,
499                             message, data_length, data_check));
500     return;
501   }
502 
503   if (status != USB_TRANSFER_COMPLETED ||
504       static_cast<uint32>(result) != data_length) {
505     TransferError(status);
506     return;
507   }
508 
509   DumpMessage(false, buffer->data(), data_length);
510   message->body = std::string(buffer->data(), result);
511   if (Checksum(message->body) != data_check) {
512     TransferError(USB_TRANSFER_ERROR);
513     return;
514   }
515 
516   message_loop_->PostTask(FROM_HERE,
517                           base::Bind(&AndroidUsbDevice::HandleIncoming, this,
518                                      message));
519 }
520 
HandleIncoming(scoped_refptr<AdbMessage> message)521 void AndroidUsbDevice::HandleIncoming(scoped_refptr<AdbMessage> message) {
522   switch (message->command) {
523     case AdbMessage::kCommandAUTH:
524       {
525         DCHECK_EQ(message->arg0, static_cast<uint32>(AdbMessage::kAuthToken));
526         if (signature_sent_) {
527           Queue(new AdbMessage(AdbMessage::kCommandAUTH,
528                                AdbMessage::kAuthRSAPublicKey, 0,
529                                AndroidRSAPublicKey(rsa_key_.get())));
530         } else {
531           signature_sent_ = true;
532           std::string signature = AndroidRSASign(rsa_key_.get(), message->body);
533           if (!signature.empty()) {
534             Queue(new AdbMessage(AdbMessage::kCommandAUTH,
535                                  AdbMessage::kAuthSignature, 0,
536                                  signature));
537           } else {
538             Queue(new AdbMessage(AdbMessage::kCommandAUTH,
539                                  AdbMessage::kAuthRSAPublicKey, 0,
540                                  AndroidRSAPublicKey(rsa_key_.get())));
541           }
542         }
543       }
544       break;
545     case AdbMessage::kCommandCNXN:
546       {
547         is_connected_ = true;
548         PendingMessages pending;
549         pending.swap(pending_messages_);
550         for (PendingMessages::iterator it = pending.begin();
551              it != pending.end(); ++it) {
552           Queue(*it);
553         }
554       }
555       break;
556     case AdbMessage::kCommandOKAY:
557     case AdbMessage::kCommandWRTE:
558     case AdbMessage::kCommandCLSE:
559       {
560         AndroidUsbSockets::iterator it = sockets_.find(message->arg1);
561         if (it != sockets_.end())
562           it->second->HandleIncoming(message);
563       }
564       break;
565     default:
566       break;
567   }
568   ReadHeader(false);
569 }
570 
TransferError(UsbTransferStatus status)571 void AndroidUsbDevice::TransferError(UsbTransferStatus status) {
572   message_loop_->PostTask(FROM_HERE,
573                           base::Bind(&AndroidUsbDevice::Terminate,
574                                      this));
575 }
576 
Terminate()577 void AndroidUsbDevice::Terminate() {
578   if (terminated_)
579     return;
580 
581   terminated_ = true;
582 
583   // Iterate over copy.
584   AndroidUsbSockets sockets(sockets_);
585   for (AndroidUsbSockets::iterator it = sockets.begin();
586        it != sockets.end(); ++it) {
587     it->second->Terminated();
588   }
589 
590   BrowserThread::PostTask(
591       BrowserThread::FILE, FROM_HERE,
592       base::Bind(&ReleaseInterface, usb_device_));
593 }
594 
SocketDeleted(uint32 socket_id)595 void AndroidUsbDevice::SocketDeleted(uint32 socket_id) {
596   sockets_.erase(socket_id);
597 }
598