Commit 7f46b8f4 authored by pfeldman@chromium.org's avatar pfeldman@chromium.org

DevTools: request usb permission on ChromeOS.

Review URL: https://chromiumcodereview.appspot.com/23953002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@221460 0039d316-1c4b-4281-b951-d872f2087c98
parent 6278737c
......@@ -6,6 +6,7 @@
#include <set>
#include "base/barrier_closure.h"
#include "base/base64.h"
#include "base/lazy_instance.h"
#include "base/message_loop/message_loop.h"
......@@ -41,17 +42,15 @@ static const char kHostConnectMessage[] = "host::";
using content::BrowserThread;
typedef std::vector<scoped_refptr<UsbDevice> > UsbDevices;
typedef std::set<scoped_refptr<UsbDevice> > UsbDeviceSet;
base::LazyInstance<AndroidUsbDevices>::Leaky g_devices =
LAZY_INSTANCE_INITIALIZER;
scoped_refptr<AndroidUsbDevice> ClaimInterface(
crypto::RSAPrivateKey* rsa_key,
scoped_refptr<UsbDeviceHandle> usb_device,
scoped_refptr<const UsbInterfaceDescriptor> interface,
int interface_id) {
bool IsAndroidInterface(
scoped_refptr<const UsbInterfaceDescriptor> interface) {
if (interface->GetNumAltSettings() == 0)
return NULL;
return false;
scoped_refptr<const UsbInterfaceAltSettingDescriptor> idesc =
interface->GetAltSetting(0);
......@@ -60,8 +59,18 @@ scoped_refptr<AndroidUsbDevice> ClaimInterface(
idesc->GetInterfaceSubclass() != kAdbSubclass ||
idesc->GetInterfaceProtocol() != kAdbProtocol ||
idesc->GetNumEndpoints() != 2) {
return NULL;
return false;
}
return true;
}
scoped_refptr<AndroidUsbDevice> ClaimInterface(
crypto::RSAPrivateKey* rsa_key,
scoped_refptr<UsbDeviceHandle> usb_handle,
scoped_refptr<const UsbInterfaceDescriptor> interface,
int interface_id) {
scoped_refptr<const UsbInterfaceAltSettingDescriptor> idesc =
interface->GetAltSetting(0);
int inbound_address = 0;
int outbound_address = 0;
......@@ -82,14 +91,14 @@ scoped_refptr<AndroidUsbDevice> ClaimInterface(
if (inbound_address == 0 || outbound_address == 0)
return NULL;
if (!usb_device->ClaimInterface(interface_id))
if (!usb_handle->ClaimInterface(interface_id))
return NULL;
base::string16 serial;
if (!usb_device->GetSerial(&serial) || serial.empty())
if (!usb_handle->GetSerial(&serial) || serial.empty())
return NULL;
return new AndroidUsbDevice(rsa_key, usb_device, UTF16ToASCII(serial),
return new AndroidUsbDevice(rsa_key, usb_handle, UTF16ToASCII(serial),
inbound_address, outbound_address, zero_mask);
}
......@@ -151,19 +160,56 @@ AdbMessage::AdbMessage(uint32 command,
AdbMessage::~AdbMessage() {
}
static void RespondOnUIThread(const AndroidUsbDevicesCallback& callback,
const AndroidUsbDevices& devices) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
callback.Run(devices);
}
static void RespondOnFileThread(const AndroidUsbDevicesCallback& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
// Copy g_devices.Get() on file thread.
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&RespondOnUIThread, callback, g_devices.Get()));
}
static void OpenAndroidDevicesOnFileThread(
crypto::RSAPrivateKey* rsa_key,
const base::Closure& barrier,
scoped_refptr<UsbDevice> device,
int interface_id,
bool success) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
if (success) {
scoped_refptr<UsbConfigDescriptor> config = device->ListInterfaces();
scoped_refptr<UsbDeviceHandle> usb_handle = device->Open();
if (usb_handle) {
scoped_refptr<AndroidUsbDevice> device =
ClaimInterface(rsa_key, usb_handle, config->GetInterface(interface_id),
interface_id);
if (device.get())
g_devices.Get().push_back(device);
else
usb_handle->Close();
}
}
barrier.Run();
}
static void EnumerateOnFileThread(crypto::RSAPrivateKey* rsa_key,
AndroidUsbDevices* result) {
const AndroidUsbDevicesCallback& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
UsbService* service = UsbService::GetInstance();
AndroidUsbDevices& devices = g_devices.Get();
UsbDevices usb_devices;
service->GetDevices(&usb_devices);
AndroidUsbDevices& devices = g_devices.Get();
// GC Android devices with no actual usb device.
AndroidUsbDevices::iterator it = devices.begin();
std::set<UsbDevice*> claimed_devices;
UsbDeviceSet claimed_devices;
while (it != devices.end()) {
bool found_device = false;
for (UsbDevices::iterator it2 = usb_devices.begin();
......@@ -183,54 +229,50 @@ static void EnumerateOnFileThread(crypto::RSAPrivateKey* rsa_key,
}
// Add new devices.
base::Closure barrier = base::BarrierClosure(
usb_devices.size(), base::Bind(&RespondOnFileThread, callback));
for (UsbDevices::iterator it = usb_devices.begin(); it != usb_devices.end();
++it) {
if (ContainsKey(claimed_devices, it->get()))
if (ContainsKey(claimed_devices, it->get())) {
barrier.Run();
continue;
}
scoped_refptr<UsbConfigDescriptor> config = (*it)->ListInterfaces();
if (!config)
continue;
scoped_refptr<UsbDeviceHandle> usb_device = (*it)->Open();
if (!usb_device)
if (!config) {
barrier.Run();
continue;
}
bool claimed = false;
bool has_android_interface = false;
for (size_t j = 0; j < config->GetNumInterfaces(); ++j) {
scoped_refptr<AndroidUsbDevice> device =
ClaimInterface(rsa_key, usb_device, config->GetInterface(j), j);
if (device.get()) {
devices.push_back(device);
claimed = true;
}
if (!IsAndroidInterface(config->GetInterface(j)))
continue;
// Request permission on Chrome OS.
#if defined(OS_CHROMEOS)
(*it)->RequestUsbAcess(j, base::Bind(&OpenAndroidDevicesOnFileThread,
rsa_key, barrier, *it, j));
#else
OpenAndroidDevicesOnFileThread(rsa_key, barrier, *it, j, true);
#endif // defined(OS_CHROMEOS)
has_android_interface = true;
break;
}
if (!claimed)
usb_device->Close();
if (!has_android_interface)
barrier.Run();
}
*result = devices;
}
static void InitDevicesOnCallerThread(
AndroidUsbDevices* devices,
const AndroidUsbDevicesCallback& callback) {
for (AndroidUsbDevices::iterator it = devices->begin(); it != devices->end();
++it) {
(*it)->InitOnCallerThread();
}
callback.Run(*devices);
delete devices;
}
// static
void AndroidUsbDevice::Enumerate(crypto::RSAPrivateKey* rsa_key,
const AndroidUsbDevicesCallback& callback) {
AndroidUsbDevices* devices = new AndroidUsbDevices();
BrowserThread::PostTaskAndReply(
BrowserThread::FILE, FROM_HERE,
base::Bind(&EnumerateOnFileThread, rsa_key, devices),
base::Bind(&InitDevicesOnCallerThread, devices, callback));
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
base::Bind(&EnumerateOnFileThread, rsa_key,
callback));
}
AndroidUsbDevice::AndroidUsbDevice(crypto::RSAPrivateKey* rsa_key,
......@@ -283,6 +325,9 @@ void AndroidUsbDevice::Send(uint32 command,
AndroidUsbDevice::~AndroidUsbDevice() {
Terminate();
usb_device_->AddRef();
BrowserThread::ReleaseSoon(BrowserThread::FILE, FROM_HERE,
usb_device_.get());
}
void AndroidUsbDevice::Queue(scoped_refptr<AdbMessage> message) {
......
......@@ -99,6 +99,7 @@ class UsbDeviceImpl : public DevToolsAdbBridge::AndroidDevice {
explicit UsbDeviceImpl(AndroidUsbDevice* device)
: AndroidDevice(device->serial()),
device_(device) {
device_->InitOnCallerThread();
}
virtual void RunCommand(const std::string& command,
......@@ -172,13 +173,20 @@ class AdbPagesCommand : public base::RefCountedThreadSafe<
public:
typedef base::Callback<void(DevToolsAdbBridge::RemoteDevices*)> Callback;
AdbPagesCommand(DevToolsAdbBridge* bridge, const Callback& callback)
AdbPagesCommand(DevToolsAdbBridge* bridge,
crypto::RSAPrivateKey* rsa_key,
const Callback& callback)
: bridge_(bridge),
callback_(callback) {
remote_devices_.reset(new DevToolsAdbBridge::RemoteDevices());
bridge_->GetAdbMessageLoop()->PostTask(FROM_HERE,
base::Bind(&DevToolsAdbBridge::EnumerateUsbDevices, bridge_,
base::Bind(&AdbPagesCommand::ReceivedUsbDevices, this)));
if (CommandLine::ForCurrentProcess()->HasSwitch(
switches::kRemoteDebuggingRawUSB)) {
AndroidUsbDevice::Enumerate(rsa_key,
base::Bind(&AdbPagesCommand::ReceivedUsbDevices, this));
} else {
ReceivedUsbDevices(AndroidUsbDevices());
}
}
private:
......@@ -190,15 +198,41 @@ class AdbPagesCommand : public base::RefCountedThreadSafe<
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
}
void ReceivedUsbDevices(const AndroidDevices& devices) {
void ReceivedUsbDevices(const AndroidUsbDevices& usb_devices) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
bridge_->GetAdbMessageLoop()->PostTask(
FROM_HERE, base::Bind(&AdbPagesCommand::WrapUsbDevices, this,
usb_devices));
}
void WrapUsbDevices(const AndroidUsbDevices& usb_devices) {
DCHECK_EQ(bridge_->GetAdbMessageLoop(), base::MessageLoop::current());
devices_ = devices;
bridge_->EnumerateAdbDevices(
#if defined(DEBUG_DEVTOOLS)
devices_.push_back(new AdbDeviceImpl("")); // For desktop remote debugging.
#endif // defined(DEBUG_DEVTOOLS)
for (AndroidUsbDevices::const_iterator it = usb_devices.begin();
it != usb_devices.end(); ++it) {
devices_.push_back(new UsbDeviceImpl(*it));
}
AdbClientSocket::AdbQuery(
kAdbPort, kHostDevicesCommand,
base::Bind(&AdbPagesCommand::ReceivedAdbDevices, this));
}
void ReceivedAdbDevices(const AndroidDevices& devices) {
devices_.insert(devices_.end(), devices.begin(), devices.end());
void ReceivedAdbDevices(
int result,
const std::string& response) {
DCHECK_EQ(bridge_->GetAdbMessageLoop(), base::MessageLoop::current());
std::vector<std::string> serials;
Tokenize(response, "\n", &serials);
for (size_t i = 0; i < serials.size(); ++i) {
std::vector<std::string> tokens;
Tokenize(serials[i], "\t ", &tokens);
devices_.push_back(new AdbDeviceImpl(tokens[0]));
}
ProcessSerials();
}
......@@ -868,27 +902,6 @@ DevToolsAdbBridge::DevToolsAdbBridge(Profile* profile)
new PortForwardingController(this, profile->GetPrefs()));
}
void DevToolsAdbBridge::EnumerateUsbDevices(
const AndroidDevicesCallback& callback) {
DCHECK_EQ(base::MessageLoop::current(), adb_thread_->message_loop());
if (CommandLine::ForCurrentProcess()->HasSwitch(
switches::kRemoteDebuggingRawUSB)) {
AndroidUsbDevice::Enumerate(rsa_key_.get(),
base::Bind(&DevToolsAdbBridge::ReceivedUsbDevices, this, callback));
} else {
ReceivedUsbDevices(callback, AndroidUsbDevices());
}
}
void DevToolsAdbBridge::EnumerateAdbDevices(
const AndroidDevicesCallback& callback) {
DCHECK_EQ(base::MessageLoop::current(), adb_thread_->message_loop());
AdbClientSocket::AdbQuery(
kAdbPort, kHostDevicesCommand,
base::Bind(&DevToolsAdbBridge::ReceivedAdbDevices, this, callback));
}
void DevToolsAdbBridge::AddListener(Listener* listener) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (listeners_.empty())
......@@ -913,50 +926,14 @@ DevToolsAdbBridge::~DevToolsAdbBridge() {
DCHECK(listeners_.empty());
}
void DevToolsAdbBridge::ReceivedUsbDevices(
const AndroidDevicesCallback& callback,
const AndroidUsbDevices& usb_devices) {
AndroidDevices devices;
#if defined(DEBUG_DEVTOOLS)
devices.push_back(new AdbDeviceImpl("")); // For desktop remote debugging.
#endif // defined(DEBUG_DEVTOOLS)
for (AndroidUsbDevices::const_iterator it = usb_devices.begin();
it != usb_devices.end(); ++it) {
devices.push_back(new UsbDeviceImpl(*it));
}
callback.Run(devices);
}
void DevToolsAdbBridge::ReceivedAdbDevices(
const AndroidDevicesCallback& callback,
int result,
const std::string& response) {
AndroidDevices devices;
if (result != net::OK) {
callback.Run(devices);
return;
}
std::vector<std::string> serials;
Tokenize(response, "\n", &serials);
for (size_t i = 0; i < serials.size(); ++i) {
std::vector<std::string> tokens;
Tokenize(serials[i], "\t ", &tokens);
devices.push_back(new AdbDeviceImpl(tokens[0]));
}
callback.Run(devices);
}
void DevToolsAdbBridge::RequestRemoteDevices() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (!has_message_loop_)
return;
new AdbPagesCommand(
this, base::Bind(&DevToolsAdbBridge::ReceivedRemoteDevices, this));
this, rsa_key_.get(),
base::Bind(&DevToolsAdbBridge::ReceivedRemoteDevices, this));
}
void DevToolsAdbBridge::ReceivedRemoteDevices(RemoteDevices* devices_ptr) {
......
......@@ -266,9 +266,6 @@ class DevToolsAdbBridge
explicit DevToolsAdbBridge(Profile* profile);
void EnumerateUsbDevices(const AndroidDevicesCallback& callback);
void EnumerateAdbDevices(const AndroidDevicesCallback& callback);
void AddListener(Listener* listener);
void RemoveListener(Listener* listener);
......@@ -295,11 +292,6 @@ class DevToolsAdbBridge
};
virtual ~DevToolsAdbBridge();
void ReceivedUsbDevices(const AndroidDevicesCallback& callback,
const AndroidUsbDevices& usb_devices);
void ReceivedAdbDevices(const AndroidDevicesCallback& callback,
int result,
const std::string& response);
void RequestRemoteDevices();
void ReceivedRemoteDevices(RemoteDevices* devices);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment