| // Copyright 2014 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/device/usb/usb_device_provider.h" |
| |
| #include "base/strings/stringprintf.h" |
| #include "chrome/browser/devtools/device/adb/adb_device_info_query.h" |
| #include "chrome/browser/devtools/device/usb/android_rsa.h" |
| #include "chrome/browser/devtools/device/usb/android_usb_device.h" |
| #include "crypto/rsa_private_key.h" |
| #include "net/base/net_errors.h" |
| #include "net/socket/stream_socket.h" |
| |
| namespace { |
| |
| const char kLocalAbstractCommand[] = "localabstract:%s"; |
| |
| const int kBufferSize = 16 * 1024; |
| |
| void OnOpenSocket(const UsbDeviceProvider::SocketCallback& callback, |
| net::StreamSocket* socket, |
| int result) { |
| callback.Run(result, result == net::OK ? socket : NULL); |
| } |
| |
| void OnRead(net::StreamSocket* socket, |
| scoped_refptr<net::IOBuffer> buffer, |
| const std::string& data, |
| const UsbDeviceProvider::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(&OnRead, socket, buffer, new_data, callback)); |
| if (result != net::ERR_IO_PENDING) |
| OnRead(socket, buffer, new_data, callback, result); |
| } |
| |
| void OpenedForCommand(const UsbDeviceProvider::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(&OnRead, socket, buffer, std::string(), callback)); |
| if (result != net::ERR_IO_PENDING) |
| OnRead(socket, buffer, std::string(), callback, result); |
| } |
| |
| void RunCommand(scoped_refptr<AndroidUsbDevice> device, |
| const std::string& command, |
| const UsbDeviceProvider::CommandCallback& callback) { |
| net::StreamSocket* socket = device->CreateSocket(command); |
| if (!socket) { |
| callback.Run(net::ERR_CONNECTION_FAILED, std::string()); |
| return; |
| } |
| int result = socket->Connect(base::Bind(&OpenedForCommand, callback, socket)); |
| if (result != net::ERR_IO_PENDING) |
| callback.Run(result, std::string()); |
| } |
| |
| } // namespace |
| |
| // static |
| void UsbDeviceProvider::CountDevices( |
| const base::Callback<void(int)>& callback) { |
| AndroidUsbDevice::CountDevices(callback); |
| } |
| |
| UsbDeviceProvider::UsbDeviceProvider(Profile* profile){ |
| rsa_key_.reset(AndroidRSAPrivateKey(profile)); |
| } |
| |
| void UsbDeviceProvider::QueryDevices(const SerialsCallback& callback) { |
| AndroidUsbDevice::Enumerate( |
| rsa_key_.get(), |
| base::Bind(&UsbDeviceProvider::EnumeratedDevices, this, callback)); |
| } |
| |
| void UsbDeviceProvider::QueryDeviceInfo(const std::string& serial, |
| const DeviceInfoCallback& callback) { |
| UsbDeviceMap::iterator it = device_map_.find(serial); |
| if (it == device_map_.end() || !it->second->is_connected()) { |
| AndroidDeviceManager::DeviceInfo offline_info; |
| callback.Run(offline_info); |
| return; |
| } |
| AdbDeviceInfoQuery::Start(base::Bind(&RunCommand, it->second), callback); |
| } |
| |
| void UsbDeviceProvider::OpenSocket(const std::string& serial, |
| const std::string& name, |
| const SocketCallback& callback) { |
| UsbDeviceMap::iterator it = device_map_.find(serial); |
| if (it == device_map_.end()) { |
| callback.Run(net::ERR_CONNECTION_FAILED, NULL); |
| return; |
| } |
| std::string socket_name = |
| base::StringPrintf(kLocalAbstractCommand, name.c_str()); |
| net::StreamSocket* socket = it->second->CreateSocket(socket_name); |
| if (!socket) { |
| callback.Run(net::ERR_CONNECTION_FAILED, NULL); |
| return; |
| } |
| int result = socket->Connect(base::Bind(&OnOpenSocket, callback, socket)); |
| if (result != net::ERR_IO_PENDING) |
| callback.Run(result, NULL); |
| } |
| |
| void UsbDeviceProvider::ReleaseDevice(const std::string& serial) { |
| device_map_.erase(serial); |
| } |
| |
| UsbDeviceProvider::~UsbDeviceProvider() { |
| } |
| |
| void UsbDeviceProvider::EnumeratedDevices(const SerialsCallback& callback, |
| const AndroidUsbDevices& devices) { |
| std::vector<std::string> result; |
| device_map_.clear(); |
| for (AndroidUsbDevices::const_iterator it = devices.begin(); |
| it != devices.end(); ++it) { |
| result.push_back((*it)->serial()); |
| device_map_[(*it)->serial()] = *it; |
| (*it)->InitOnCallerThread(); |
| } |
| callback.Run(result); |
| } |
| |