blob: e440b392b75f96e936b5783b363099cc8df31e15 [file] [log] [blame]
// Copyright 2014 The Chromium Authors
// 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 <memory>
#include <utility>
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/ptr_util.h"
#include "base/strings/stringprintf.h"
#include "chrome/browser/devtools/device/usb/android_rsa.h"
#include "chrome/browser/devtools/device/usb/android_usb_device.h"
#include "net/base/completion_repeating_callback.h"
#include "net/base/io_buffer.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(UsbDeviceProvider::SocketCallback callback,
net::StreamSocket* socket_raw,
int result) {
std::unique_ptr<net::StreamSocket> socket(socket_raw);
if (result != net::OK)
socket.reset();
std::move(callback).Run(result, std::move(socket));
}
void OnRead(net::StreamSocket* socket,
scoped_refptr<net::IOBuffer> buffer,
const std::string& data,
UsbDeviceProvider::CommandCallback callback,
int result) {
if (result <= 0) {
std::move(callback).Run(result, result == 0 ? data : std::string());
delete socket;
return;
}
std::string new_data = data + std::string(buffer->data(), result);
auto split_callback = base::SplitOnceCallback(
base::BindOnce(&OnRead, socket, buffer, new_data, std::move(callback)));
result =
socket->Read(buffer.get(), kBufferSize, std::move(split_callback.first));
if (result != net::ERR_IO_PENDING) {
std::move(split_callback.second).Run(result);
}
}
void OpenedForCommand(UsbDeviceProvider::CommandCallback callback,
net::StreamSocket* socket,
int result) {
if (result != net::OK) {
std::move(callback).Run(result, std::string());
return;
}
auto buffer = base::MakeRefCounted<net::IOBufferWithSize>(kBufferSize);
auto split_callback = base::SplitOnceCallback(base::BindOnce(
&OnRead, socket, buffer, std::string(), std::move(callback)));
result =
socket->Read(buffer.get(), kBufferSize, std::move(split_callback.first));
if (result != net::ERR_IO_PENDING) {
std::move(split_callback.second).Run(result);
}
}
void RunCommand(scoped_refptr<AndroidUsbDevice> device,
const std::string& command,
UsbDeviceProvider::CommandCallback callback) {
net::StreamSocket* socket = device->CreateSocket(command);
if (!socket) {
std::move(callback).Run(net::ERR_CONNECTION_FAILED, std::string());
return;
}
auto split_callback = base::SplitOnceCallback(std::move(callback));
int result = socket->Connect(base::BindOnce(
&OpenedForCommand, std::move(split_callback.first), socket));
if (result != net::ERR_IO_PENDING) {
std::move(split_callback.second).Run(result, std::string());
}
}
} // namespace
UsbDeviceProvider::UsbDeviceProvider(Profile* profile)
: rsa_key_(AndroidRSAPrivateKey(profile)) {}
void UsbDeviceProvider::QueryDevices(SerialsCallback callback) {
AndroidUsbDevice::Enumerate(
rsa_key_, base::BindOnce(&UsbDeviceProvider::EnumeratedDevices, this,
std::move(callback)));
}
void UsbDeviceProvider::QueryDeviceInfo(const std::string& serial,
DeviceInfoCallback callback) {
auto it = device_map_.find(serial);
if (it == device_map_.end() || !it->second->is_connected()) {
AndroidDeviceManager::DeviceInfo offline_info;
std::move(callback).Run(offline_info);
return;
}
AndroidDeviceManager::QueryDeviceInfo(base::BindOnce(&RunCommand, it->second),
std::move(callback));
}
void UsbDeviceProvider::OpenSocket(const std::string& serial,
const std::string& name,
SocketCallback callback) {
auto it = device_map_.find(serial);
if (it == device_map_.end()) {
std::move(callback).Run(net::ERR_CONNECTION_FAILED, nullptr);
return;
}
std::string socket_name =
base::StringPrintf(kLocalAbstractCommand, name.c_str());
net::StreamSocket* socket = it->second->CreateSocket(socket_name);
if (!socket) {
std::move(callback).Run(net::ERR_CONNECTION_FAILED, nullptr);
return;
}
auto split_callback = base::SplitOnceCallback(std::move(callback));
int result = socket->Connect(
base::BindOnce(&OnOpenSocket, std::move(split_callback.first), socket));
if (result != net::ERR_IO_PENDING) {
std::move(split_callback.second).Run(result, nullptr);
}
}
void UsbDeviceProvider::ReleaseDevice(const std::string& serial) {
device_map_.erase(serial);
}
UsbDeviceProvider::~UsbDeviceProvider() = default;
void UsbDeviceProvider::EnumeratedDevices(SerialsCallback callback,
const AndroidUsbDevices& devices) {
std::vector<std::string> result;
device_map_.clear();
for (auto it = devices.begin(); it != devices.end(); ++it) {
result.push_back((*it)->serial());
device_map_[(*it)->serial()] = *it;
(*it)->InitOnCallerThread();
}
std::move(callback).Run(std::move(result));
}