Index: chrome/browser/devtools/adb/android_usb_device.cc |
diff --git a/chrome/browser/devtools/adb/android_usb_device.cc b/chrome/browser/devtools/adb/android_usb_device.cc |
index 8af74040e7aa4557c7f405dbc7b6402d744bd979..63b12520ce1d4e45b2e3b19f7d712e359a119763 100644 |
--- a/chrome/browser/devtools/adb/android_usb_device.cc |
+++ b/chrome/browser/devtools/adb/android_usb_device.cc |
@@ -45,7 +45,8 @@ using content::BrowserThread; |
typedef std::vector<scoped_refptr<UsbDevice> > UsbDevices; |
typedef std::set<scoped_refptr<UsbDevice> > UsbDeviceSet; |
-base::LazyInstance<AndroidUsbDevices>::Leaky g_devices = |
+// Stores android wrappers around claimed usb devices on caller thread. |
+base::LazyInstance<std::vector<AndroidUsbDevice*> >::Leaky g_devices = |
LAZY_INSTANCE_INITIALIZER; |
bool IsAndroidInterface( |
@@ -100,7 +101,8 @@ scoped_refptr<AndroidUsbDevice> ClaimInterface( |
return NULL; |
return new AndroidUsbDevice(rsa_key, usb_handle, base::UTF16ToASCII(serial), |
- inbound_address, outbound_address, zero_mask); |
+ inbound_address, outbound_address, zero_mask, |
+ interface_id); |
} |
uint32 Checksum(const std::string& data) { |
@@ -141,8 +143,9 @@ void DumpMessage(bool outgoing, const char* data, size_t length) { |
#endif // 0 |
} |
-void ReleaseInterface(scoped_refptr<UsbDeviceHandle> usb_device) { |
- usb_device->ReleaseInterface(1); |
+void ReleaseInterface(scoped_refptr<UsbDeviceHandle> usb_device, |
+ int interface_id) { |
+ usb_device->ReleaseInterface(interface_id); |
usb_device->Close(); |
} |
@@ -168,21 +171,32 @@ static void RespondWithCountOnUIThread(base::Callback<void(int)> callback, |
} |
static void RespondOnCallerThread(const AndroidUsbDevicesCallback& callback, |
- const AndroidUsbDevices& devices) { |
- callback.Run(devices); |
+ AndroidUsbDevices* new_devices) { |
+ scoped_ptr<AndroidUsbDevices> devices(new_devices); |
+ |
+ // Add raw pointers to the newly claimed devices. |
+ for (AndroidUsbDevices::iterator it = devices->begin(); it != devices->end(); |
+ ++it) { |
+ g_devices.Get().push_back(*it); |
+ } |
+ |
+ // Return all claimed devices. |
+ AndroidUsbDevices result(g_devices.Get().begin(), g_devices.Get().end()); |
+ callback.Run(result); |
} |
static void RespondOnFileThread( |
const AndroidUsbDevicesCallback& callback, |
+ AndroidUsbDevices* devices, |
scoped_refptr<base::MessageLoopProxy> caller_message_loop_proxy) { |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
- // Copy g_devices.Get() on file thread. |
caller_message_loop_proxy->PostTask( |
FROM_HERE, |
- base::Bind(&RespondOnCallerThread, callback, g_devices.Get())); |
+ base::Bind(&RespondOnCallerThread, callback, devices)); |
} |
-static void OpenAndroidDevicesOnFileThread( |
+static void OpenAndroidDeviceOnFileThread( |
+ AndroidUsbDevices* devices, |
crypto::RSAPrivateKey* rsa_key, |
const base::Closure& barrier, |
scoped_refptr<UsbDevice> device, |
@@ -193,11 +207,11 @@ static void OpenAndroidDevicesOnFileThread( |
scoped_refptr<UsbConfigDescriptor> config = device->ListInterfaces(); |
scoped_refptr<UsbDeviceHandle> usb_handle = device->Open(); |
if (usb_handle) { |
- scoped_refptr<AndroidUsbDevice> device = |
+ scoped_refptr<AndroidUsbDevice> android_device = |
ClaimInterface(rsa_key, usb_handle, config->GetInterface(interface_id), |
interface_id); |
- if (device.get()) |
- g_devices.Get().push_back(device); |
+ if (android_device.get()) |
+ devices->push_back(android_device.get()); |
else |
usb_handle->Close(); |
} |
@@ -239,42 +253,16 @@ static void EnumerateOnFileThread( |
if (service != NULL) |
service->GetDevices(&usb_devices); |
- AndroidUsbDevices& devices = g_devices.Get(); |
- |
- // GC Android devices with no actual usb device. |
- AndroidUsbDevices::iterator it = devices.begin(); |
- UsbDeviceSet claimed_devices; |
- while (it != devices.end()) { |
- bool found_device = false; |
- for (UsbDevices::iterator it2 = usb_devices.begin(); |
- it2 != usb_devices.end() && !found_device; ++it2) { |
- UsbDevice* usb_device = it2->get(); |
- AndroidUsbDevice* device = it->get(); |
- if (usb_device == device->usb_device()->device()) { |
- found_device = true; |
- claimed_devices.insert(usb_device); |
- } |
- } |
- |
- if (!found_device) |
- it = devices.erase(it); |
- else |
- ++it; |
- } |
- |
// Add new devices. |
+ AndroidUsbDevices* devices = new AndroidUsbDevices(); |
base::Closure barrier = base::BarrierClosure( |
usb_devices.size(), base::Bind(&RespondOnFileThread, |
callback, |
+ devices, |
caller_message_loop_proxy)); |
for (UsbDevices::iterator it = usb_devices.begin(); it != usb_devices.end(); |
++it) { |
- if (ContainsKey(claimed_devices, it->get())) { |
- barrier.Run(); |
- continue; |
- } |
- |
scoped_refptr<UsbConfigDescriptor> config = (*it)->ListInterfaces(); |
if (!config) { |
barrier.Run(); |
@@ -288,10 +276,10 @@ static void EnumerateOnFileThread( |
// Request permission on Chrome OS. |
#if defined(OS_CHROMEOS) |
- (*it)->RequestUsbAcess(j, base::Bind(&OpenAndroidDevicesOnFileThread, |
- rsa_key, barrier, *it, j)); |
+ (*it)->RequestUsbAcess(j, base::Bind(&OpenAndroidDeviceOnFileThread, |
+ devices, rsa_key, barrier, *it, j)); |
#else |
- OpenAndroidDevicesOnFileThread(rsa_key, barrier, *it, j, true); |
+ OpenAndroidDeviceOnFileThread(devices, rsa_key, barrier, *it, j, true); |
#endif // defined(OS_CHROMEOS) |
has_android_interface = true; |
@@ -313,6 +301,18 @@ void AndroidUsbDevice::CountDevices( |
// static |
void AndroidUsbDevice::Enumerate(crypto::RSAPrivateKey* rsa_key, |
const AndroidUsbDevicesCallback& callback) { |
+ |
+ // Collect devices with closed handles. |
+ for (std::vector<AndroidUsbDevice*>::iterator it = g_devices.Get().begin(); |
+ it != g_devices.Get().end(); ++it) { |
+ if ((*it)->usb_handle_) { |
+ BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, |
+ base::Bind(&AndroidUsbDevice::TerminateIfReleased, *it, |
+ (*it)->usb_handle_)); |
+ } |
+ } |
+ |
+ // Then look for the new devices. |
BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, |
base::Bind(&EnumerateOnFileThread, rsa_key, callback, |
base::MessageLoopProxy::current())); |
@@ -323,18 +323,20 @@ AndroidUsbDevice::AndroidUsbDevice(crypto::RSAPrivateKey* rsa_key, |
const std::string& serial, |
int inbound_address, |
int outbound_address, |
- int zero_mask) |
+ int zero_mask, |
+ int interface_id) |
: message_loop_(NULL), |
rsa_key_(rsa_key->Copy()), |
- usb_device_(usb_device), |
+ usb_handle_(usb_device), |
serial_(serial), |
inbound_address_(inbound_address), |
outbound_address_(outbound_address), |
zero_mask_(zero_mask), |
+ interface_id_(interface_id), |
is_connected_(false), |
signature_sent_(false), |
last_socket_id_(256), |
- terminated_(false) { |
+ weak_factory_(this) { |
} |
void AndroidUsbDevice::InitOnCallerThread() { |
@@ -343,10 +345,13 @@ void AndroidUsbDevice::InitOnCallerThread() { |
message_loop_ = base::MessageLoop::current(); |
Queue(new AdbMessage(AdbMessage::kCommandCNXN, kVersion, kMaxPayload, |
kHostConnectMessage)); |
- ReadHeader(true); |
+ ReadHeader(); |
} |
net::StreamSocket* AndroidUsbDevice::CreateSocket(const std::string& command) { |
+ if (!usb_handle_) |
+ return NULL; |
+ |
uint32 socket_id = ++last_socket_id_; |
sockets_[socket_id] = new AndroidUsbSocket(this, socket_id, command, |
base::Bind(&AndroidUsbDevice::SocketDeleted, this)); |
@@ -367,13 +372,13 @@ void AndroidUsbDevice::Send(uint32 command, |
} |
AndroidUsbDevice::~AndroidUsbDevice() { |
+ DCHECK(message_loop_ == base::MessageLoop::current()); |
Terminate(); |
- usb_device_->AddRef(); |
- BrowserThread::ReleaseSoon(BrowserThread::FILE, FROM_HERE, |
- usb_device_.get()); |
} |
void AndroidUsbDevice::Queue(scoped_refptr<AdbMessage> message) { |
+ DCHECK(message_loop_ == base::MessageLoop::current()); |
+ |
// Queue header. |
std::vector<uint32> header; |
header.push_back(message->command); |
@@ -412,45 +417,51 @@ void AndroidUsbDevice::Queue(scoped_refptr<AdbMessage> message) { |
} |
void AndroidUsbDevice::ProcessOutgoing() { |
- if (outgoing_queue_.empty() || terminated_) |
+ DCHECK(message_loop_ == base::MessageLoop::current()); |
+ |
+ if (outgoing_queue_.empty() || !usb_handle_) |
return; |
BulkMessage message = outgoing_queue_.front(); |
outgoing_queue_.pop(); |
DumpMessage(true, message.first->data(), message.second); |
- usb_device_->BulkTransfer(USB_DIRECTION_OUTBOUND, outbound_address_, |
+ usb_handle_->BulkTransfer(USB_DIRECTION_OUTBOUND, outbound_address_, |
message.first, message.second, kUsbTimeout, |
- base::Bind(&AndroidUsbDevice::OutgoingMessageSent, this)); |
+ base::Bind(&AndroidUsbDevice::OutgoingMessageSent, |
+ weak_factory_.GetWeakPtr())); |
} |
void AndroidUsbDevice::OutgoingMessageSent(UsbTransferStatus status, |
scoped_refptr<net::IOBuffer> buffer, |
size_t result) { |
+ DCHECK(message_loop_ == base::MessageLoop::current()); |
+ |
if (status != USB_TRANSFER_COMPLETED) |
return; |
message_loop_->PostTask(FROM_HERE, |
- base::Bind(&AndroidUsbDevice::ProcessOutgoing, |
- this)); |
+ base::Bind(&AndroidUsbDevice::ProcessOutgoing, this)); |
} |
-void AndroidUsbDevice::ReadHeader(bool initial) { |
- if (terminated_) |
+void AndroidUsbDevice::ReadHeader() { |
+ DCHECK(message_loop_ == base::MessageLoop::current()); |
+ |
+ if (!usb_handle_) |
return; |
- if (!initial && HasOneRef()) |
- return; // Stop polling. |
scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kHeaderSize); |
- usb_device_->BulkTransfer(USB_DIRECTION_INBOUND, inbound_address_, |
+ usb_handle_->BulkTransfer(USB_DIRECTION_INBOUND, inbound_address_, |
buffer, kHeaderSize, kUsbTimeout, |
- base::Bind(&AndroidUsbDevice::ParseHeader, this)); |
+ base::Bind(&AndroidUsbDevice::ParseHeader, |
+ weak_factory_.GetWeakPtr())); |
} |
void AndroidUsbDevice::ParseHeader(UsbTransferStatus status, |
scoped_refptr<net::IOBuffer> buffer, |
size_t result) { |
+ DCHECK(message_loop_ == base::MessageLoop::current()); |
+ |
if (status == USB_TRANSFER_TIMEOUT) { |
message_loop_->PostTask(FROM_HERE, |
- base::Bind(&AndroidUsbDevice::ReadHeader, this, |
- false)); |
+ base::Bind(&AndroidUsbDevice::ReadHeader, this)); |
return; |
} |
@@ -487,11 +498,15 @@ void AndroidUsbDevice::ParseHeader(UsbTransferStatus status, |
void AndroidUsbDevice::ReadBody(scoped_refptr<AdbMessage> message, |
uint32 data_length, |
uint32 data_check) { |
+ DCHECK(message_loop_ == base::MessageLoop::current()); |
+ |
+ if (!usb_handle_) |
+ return; |
scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(data_length); |
- usb_device_->BulkTransfer(USB_DIRECTION_INBOUND, inbound_address_, |
+ usb_handle_->BulkTransfer(USB_DIRECTION_INBOUND, inbound_address_, |
buffer, data_length, kUsbTimeout, |
- base::Bind(&AndroidUsbDevice::ParseBody, this, message, data_length, |
- data_check)); |
+ base::Bind(&AndroidUsbDevice::ParseBody, weak_factory_.GetWeakPtr(), |
+ message, data_length, data_check)); |
} |
void AndroidUsbDevice::ParseBody(scoped_refptr<AdbMessage> message, |
@@ -500,6 +515,8 @@ void AndroidUsbDevice::ParseBody(scoped_refptr<AdbMessage> message, |
UsbTransferStatus status, |
scoped_refptr<net::IOBuffer> buffer, |
size_t result) { |
+ DCHECK(message_loop_ == base::MessageLoop::current()); |
+ |
if (status == USB_TRANSFER_TIMEOUT) { |
message_loop_->PostTask(FROM_HERE, |
base::Bind(&AndroidUsbDevice::ReadBody, this, |
@@ -526,6 +543,8 @@ void AndroidUsbDevice::ParseBody(scoped_refptr<AdbMessage> message, |
} |
void AndroidUsbDevice::HandleIncoming(scoped_refptr<AdbMessage> message) { |
+ DCHECK(message_loop_ == base::MessageLoop::current()); |
+ |
switch (message->command) { |
case AdbMessage::kCommandAUTH: |
{ |
@@ -572,20 +591,40 @@ void AndroidUsbDevice::HandleIncoming(scoped_refptr<AdbMessage> message) { |
default: |
break; |
} |
- ReadHeader(false); |
+ ReadHeader(); |
} |
void AndroidUsbDevice::TransferError(UsbTransferStatus status) { |
+ DCHECK(message_loop_ == base::MessageLoop::current()); |
+ |
message_loop_->PostTask(FROM_HERE, |
- base::Bind(&AndroidUsbDevice::Terminate, |
- this)); |
+ base::Bind(&AndroidUsbDevice::Terminate, this)); |
+} |
+ |
+void AndroidUsbDevice::TerminateIfReleased( |
+ scoped_refptr<UsbDeviceHandle> usb_handle) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
+ if (usb_handle->device()) |
+ return; |
+ message_loop_->PostTask(FROM_HERE, |
+ base::Bind(&AndroidUsbDevice::Terminate, this)); |
} |
void AndroidUsbDevice::Terminate() { |
- if (terminated_) |
+ DCHECK(message_loop_ == base::MessageLoop::current()); |
+ |
+ std::vector<AndroidUsbDevice*>::iterator it = |
+ std::find(g_devices.Get().begin(), g_devices.Get().end(), this); |
+ if (it != g_devices.Get().end()) |
+ g_devices.Get().erase(it); |
+ |
+ if (!usb_handle_) |
return; |
- terminated_ = true; |
+ // Make sure we zero-out handle so that closing connections did not open |
+ // new connections. |
+ scoped_refptr<UsbDeviceHandle> usb_handle = usb_handle_; |
+ usb_handle_ = NULL; |
// Iterate over copy. |
AndroidUsbSockets sockets(sockets_); |
@@ -593,12 +632,15 @@ void AndroidUsbDevice::Terminate() { |
it != sockets.end(); ++it) { |
it->second->Terminated(); |
} |
+ DCHECK(sockets_.empty()); |
BrowserThread::PostTask( |
BrowserThread::FILE, FROM_HERE, |
- base::Bind(&ReleaseInterface, usb_device_)); |
+ base::Bind(&ReleaseInterface, usb_handle, interface_id_)); |
} |
void AndroidUsbDevice::SocketDeleted(uint32 socket_id) { |
+ DCHECK(message_loop_ == base::MessageLoop::current()); |
+ |
sockets_.erase(socket_id); |
} |