Chromium Code Reviews| Index: chrome/browser/devtools/devtools_device_provider.cc |
| diff --git a/chrome/browser/devtools/devtools_device_provider.cc b/chrome/browser/devtools/devtools_device_provider.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..11762462db0e5bf7134aa69526a7d1f374956bcc |
| --- /dev/null |
| +++ b/chrome/browser/devtools/devtools_device_provider.cc |
| @@ -0,0 +1,311 @@ |
| +// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "chrome/browser/devtools/devtools_device_provider.h" |
| + |
| +#include "base/strings/string_util.h" |
| +#include "base/strings/stringprintf.h" |
| +#include "base/threading/thread.h" |
| +#include "chrome/browser/devtools/adb/android_rsa.h" |
| +#include "chrome/browser/devtools/adb/android_usb_device.h" |
| +#include "chrome/browser/devtools/adb_client_socket.h" |
| +#include "net/base/net_errors.h" |
| + |
| +using content::BrowserThread; |
| + |
| +const char kDevToolsAdbBridgeThreadName[] = "Chrome_DevToolsADBThread"; |
| +const char kHostTransportCommand[] = "host:transport:%s|%s"; |
| +const char kHostDevicesCommand[] = "host:devices"; |
| +const char kLocalAbstractCommand[] = "localabstract:%s"; |
| + |
| +const int kAdbPort = 5037; |
| +const int kBufferSize = 16 * 1024; |
| + |
| +// AndroidDevice ------------------------------------------- |
| + |
| +AndroidDevice::AndroidDevice(const std::string& serial) |
| + : serial_(serial) { |
| +} |
| + |
| +void AndroidDevice::HttpQuery( |
| + const std::string& la_name, |
| + const std::string& request, |
| + const CommandCallback& callback) { |
| + OpenSocket(la_name, base::Bind(&AndroidDevice::OnHttpSocketOpened, this, |
| + request, callback)); |
| +} |
| + |
| +void AndroidDevice::HttpUpgrade( |
| + const std::string& la_name, |
| + const std::string& request, |
| + const SocketCallback& callback) { |
| + OpenSocket(la_name, base::Bind(&AndroidDevice::OnHttpSocketOpened2, this, |
| + request, callback)); |
| +} |
| + |
| +AndroidDevice::~AndroidDevice() { |
| +} |
| + |
| +void AndroidDevice::OnHttpSocketOpened( |
| + const std::string& request, |
| + const CommandCallback& callback, |
| + int result, |
| + net::StreamSocket* socket) { |
| + if (result != net::OK) { |
| + callback.Run(result, std::string()); |
| + return; |
| + } |
| + AdbClientSocket::HttpQuery(socket, request, callback); |
| +} |
| + |
| +void AndroidDevice::OnHttpSocketOpened2( |
| + const std::string& request, |
| + const SocketCallback& callback, |
| + int result, |
| + net::StreamSocket* socket) { |
| + if (result != net::OK) { |
| + callback.Run(result, NULL); |
| + return; |
| + } |
| + AdbClientSocket::HttpQuery(socket, request, callback); |
| +} |
| + |
| +// AdbDeviceImpl -------------------------------------------------------------- |
|
Vladislav Kaznacheev
2013/10/17 20:17:37
Please hide *Impl classes in an anonymous namespac
Dmitry Zvorygin
2013/10/21 07:40:29
Done.
|
| + |
| +class AdbDeviceImpl : public AndroidDevice { |
| + public: |
| + explicit AdbDeviceImpl(const std::string& serial); |
| + virtual void RunCommand(const std::string& command, |
| + const CommandCallback& callback) OVERRIDE; |
| + virtual void OpenSocket(const std::string& name, |
| + const SocketCallback& callback) OVERRIDE; |
| + virtual bool IsConnected() OVERRIDE; |
| + |
| + private: |
| + virtual ~AdbDeviceImpl() {} |
| +}; |
| + |
| +AdbDeviceImpl::AdbDeviceImpl(const std::string& serial) |
| + : AndroidDevice(serial) { |
| +} |
| + |
| +void AdbDeviceImpl::RunCommand(const std::string& command, |
| + const CommandCallback& callback) { |
| + std::string query = base::StringPrintf(kHostTransportCommand, |
| + serial().c_str(), command.c_str()); |
| + AdbClientSocket::AdbQuery(kAdbPort, query, callback); |
| +} |
| + |
| +void AdbDeviceImpl::OpenSocket(const std::string& name, |
| + const SocketCallback& callback) { |
| + std::string socket_name = |
| + base::StringPrintf(kLocalAbstractCommand, name.c_str()); |
| + AdbClientSocket::TransportQuery(kAdbPort, serial(), socket_name, callback); |
| +} |
| + |
| +bool AdbDeviceImpl::IsConnected() { |
| + return true; |
| +} |
| + |
| +// DevToolsDeviceProvider --------------------------------------------------- |
| + |
| +DevToolsDeviceProvider::~DevToolsDeviceProvider() { |
| +} |
| + |
| +void DevToolsDeviceProvider::RunCallbackOnUIThread( |
|
Vladislav Kaznacheev
2013/10/17 20:17:37
This method could be static.
More over, it could
Dmitry Zvorygin
2013/10/21 07:40:29
This requires callback to be refcounted, so it act
|
| + const QueryDeviceCallback& callback, |
| + const AndroidDevices& result) { |
| + callback.Run(result); |
| +} |
| + |
| + |
| +// UsbDeviceImpl -------------------------------------------------------------- |
| + |
| +class UsbDeviceImpl : public AndroidDevice { |
| + public: |
| + explicit UsbDeviceImpl(AndroidUsbDevice* device); |
| + virtual void RunCommand(const std::string& command, |
| + const CommandCallback& callback) OVERRIDE; |
| + virtual void OpenSocket(const std::string& name, |
| + const SocketCallback& callback) OVERRIDE; |
| + virtual bool IsConnected() OVERRIDE; |
| + |
| + private: |
| + void OnOpenSocket(const SocketCallback& callback, |
| + net::StreamSocket* socket, |
| + int result); |
| + void OpenedForCommand(const CommandCallback& callback, |
| + net::StreamSocket* socket, |
| + int result); |
| + void OnRead(net::StreamSocket* socket, |
| + scoped_refptr<net::IOBuffer> buffer, |
| + const std::string& data, |
| + const CommandCallback& callback, |
| + int result); |
| + |
| + virtual ~UsbDeviceImpl() {} |
| + scoped_refptr<AndroidUsbDevice> device_; |
| +}; |
| + |
| + |
| +UsbDeviceImpl::UsbDeviceImpl(AndroidUsbDevice* device) |
| + : AndroidDevice(device->serial()), |
| + device_(device) { |
| + device_->InitOnCallerThread(); |
| +} |
| + |
| +void UsbDeviceImpl::RunCommand(const std::string& command, |
| + const CommandCallback& callback) { |
| + net::StreamSocket* socket = device_->CreateSocket(command); |
| + int result = socket->Connect(base::Bind(&UsbDeviceImpl::OpenedForCommand, |
| + this, callback, socket)); |
| + if (result != net::ERR_IO_PENDING) |
| + callback.Run(result, std::string()); |
| +} |
| + |
| +void UsbDeviceImpl::OpenSocket(const std::string& name, |
| + const SocketCallback& callback) { |
| + std::string socket_name = |
| + base::StringPrintf(kLocalAbstractCommand, name.c_str()); |
| + net::StreamSocket* socket = device_->CreateSocket(socket_name); |
| + int result = socket->Connect(base::Bind(&UsbDeviceImpl::OnOpenSocket, this, |
| + callback, socket)); |
| + if (result != net::ERR_IO_PENDING) |
| + callback.Run(result, NULL); |
| +} |
| + |
| +void UsbDeviceImpl::OnOpenSocket(const SocketCallback& callback, |
| + net::StreamSocket* socket, |
| + int result) { |
| + callback.Run(result, result == net::OK ? socket : NULL); |
| +} |
| + |
| +void UsbDeviceImpl::OpenedForCommand(const CommandCallback& callback, |
| + net::StreamSocket* socket, |
| + int result) { |
| + if (result != net::OK) { |
| + callback.Run(result, std::string()); |
| + return; |
| + } |
| + scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kBufferSize); |
| + result = socket->Read(buffer, kBufferSize, |
| + base::Bind(&UsbDeviceImpl::OnRead, this, |
| + socket, buffer, std::string(), callback)); |
| + if (result != net::ERR_IO_PENDING) |
| + OnRead(socket, buffer, std::string(), callback, result); |
| +} |
| + |
| +void UsbDeviceImpl::OnRead(net::StreamSocket* socket, |
| + scoped_refptr<net::IOBuffer> buffer, |
| + const std::string& data, |
| + const CommandCallback& callback, |
| + int result) { |
| + if (result <= 0) { |
| + callback.Run(result, result == 0 ? data : std::string()); |
| + delete socket; |
| + return; |
| + } |
| + |
| + std::string new_data = data + std::string(buffer->data(), result); |
| + result = socket->Read(buffer, kBufferSize, |
| + base::Bind(&UsbDeviceImpl::OnRead, this, |
| + socket, buffer, new_data, callback)); |
| + if (result != net::ERR_IO_PENDING) |
| + OnRead(socket, buffer, new_data, callback, result); |
| +} |
| + |
| +bool UsbDeviceImpl::IsConnected() { |
| + return device_->is_connected(); |
| +} |
| + |
| +// UsbDeviceProvider ------------------------------------------- |
| + |
| +UsbDeviceProvider::UsbDeviceProvider(Profile* profile, |
| + scoped_refptr<RefCountedAdbThread> adb_thread) : adb_thread_(adb_thread) { |
| + rsa_key_.reset(AndroidRSAPrivateKey(profile)); |
| +} |
| + |
| +UsbDeviceProvider::~UsbDeviceProvider() { |
| +} |
| + |
| +void UsbDeviceProvider::QueryDevices(const QueryDeviceCallback& callback) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + AndroidUsbDevice::Enumerate(rsa_key_.get(), |
| + base::Bind(&UsbDeviceProvider::EnumeratedDevices, |
| + this, callback)); |
| +} |
| + |
| +void UsbDeviceProvider::EnumeratedDevices(const QueryDeviceCallback& callback, |
| + const AndroidUsbDevices& devices) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + adb_thread_->message_loop()->PostTask(FROM_HERE, |
| + base::Bind(&UsbDeviceProvider::WrapDevicesOnAdbThread, |
| + this, callback, devices)); |
| +} |
| + |
| +void UsbDeviceProvider::WrapDevicesOnAdbThread( |
| + const QueryDeviceCallback& callback,const AndroidUsbDevices& devices) { |
| + DCHECK_EQ(adb_thread_->message_loop(), base::MessageLoop::current()); |
| + AndroidDevices result; |
| + for (AndroidUsbDevices::const_iterator it = devices.begin(); |
| + it != devices.end(); ++it) |
| + result.push_back(new UsbDeviceImpl(*it)); |
| + |
| + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| + base::Bind(&UsbDeviceProvider::RunCallbackOnUIThread, |
| + this, callback, result)); |
| +} |
| + |
| +// AdbDeviceProvider ------------------------------------------- |
| + |
| +AdbDeviceProvider::AdbDeviceProvider( |
| + scoped_refptr<RefCountedAdbThread> adb_thread) : adb_thread_(adb_thread) { |
| +} |
| + |
| +AdbDeviceProvider::~AdbDeviceProvider() { |
| +} |
| + |
| +void AdbDeviceProvider::QueryDevices(const QueryDeviceCallback& callback) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + |
| + adb_thread_->message_loop()->PostTask( |
| + FROM_HERE, base::Bind(&AdbDeviceProvider::QueryDevicesOnAdbThread, |
| + this, callback)); |
| +} |
| + |
| +void AdbDeviceProvider::QueryDevicesOnAdbThread( |
| + const QueryDeviceCallback& callback) { |
| + DCHECK_EQ(adb_thread_->message_loop(), base::MessageLoop::current()); |
| + |
| + AdbClientSocket::AdbQuery( |
| + kAdbPort, kHostDevicesCommand, |
| + base::Bind(&AdbDeviceProvider::ReceivedAdbDevices, this, callback)); |
| +} |
| + |
| + |
| +void AdbDeviceProvider::ReceivedAdbDevices(const QueryDeviceCallback& callback, |
| + int result_code, |
| + const std::string& response) { |
| + DCHECK_EQ(adb_thread_->message_loop(), base::MessageLoop::current()); |
| + |
| + AndroidDevices result; |
| + |
| + #if defined(DEBUG_DEVTOOLS) |
|
Vladislav Kaznacheev
2013/10/17 20:17:37
Strange ident here and inside the #if
Dmitry Zvorygin
2013/10/21 07:40:29
Done.
|
| + // For desktop remote debugging. |
| + result.push_back(new AdbDeviceImpl("")); |
| + #endif // defined(DEBUG_DEVTOOLS) |
| + |
| + |
| + 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); |
| + result.push_back(new AdbDeviceImpl(tokens[0])); |
| + } |
| + |
| + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| + base::Bind(&AdbDeviceProvider::RunCallbackOnUIThread, |
| + this, callback, result)); |
| +} |