1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "extensions/browser/api/hid/hid_api.h" 6 7#include <string> 8#include <vector> 9 10#include "device/core/device_client.h" 11#include "device/hid/hid_connection.h" 12#include "device/hid/hid_device_filter.h" 13#include "device/hid/hid_device_info.h" 14#include "device/hid/hid_service.h" 15#include "extensions/browser/api/api_resource_manager.h" 16#include "extensions/common/api/hid.h" 17#include "net/base/io_buffer.h" 18 19namespace hid = extensions::core_api::hid; 20 21using device::HidConnection; 22using device::HidDeviceFilter; 23using device::HidDeviceInfo; 24using device::HidService; 25 26namespace { 27 28const char kErrorPermissionDenied[] = "Permission to access device was denied."; 29const char kErrorInvalidDeviceId[] = "Invalid HID device ID."; 30const char kErrorFailedToOpenDevice[] = "Failed to open HID device."; 31const char kErrorConnectionNotFound[] = "Connection not established."; 32const char kErrorTransfer[] = "Transfer failed."; 33 34base::Value* PopulateHidConnection(int connection_id, 35 scoped_refptr<HidConnection> connection) { 36 hid::HidConnectInfo connection_value; 37 connection_value.connection_id = connection_id; 38 return connection_value.ToValue().release(); 39} 40 41void ConvertHidDeviceFilter(linked_ptr<hid::DeviceFilter> input, 42 HidDeviceFilter* output) { 43 if (input->vendor_id) { 44 output->SetVendorId(*input->vendor_id); 45 } 46 if (input->product_id) { 47 output->SetProductId(*input->product_id); 48 } 49 if (input->usage_page) { 50 output->SetUsagePage(*input->usage_page); 51 } 52 if (input->usage) { 53 output->SetUsage(*input->usage); 54 } 55} 56 57} // namespace 58 59namespace extensions { 60 61HidAsyncApiFunction::HidAsyncApiFunction() 62 : device_manager_(NULL), connection_manager_(NULL) {} 63 64HidAsyncApiFunction::~HidAsyncApiFunction() {} 65 66bool HidAsyncApiFunction::PrePrepare() { 67#if defined(OS_MACOSX) 68 // Migration from FILE thread to UI thread. OS X gets it first. 69 set_work_thread_id(content::BrowserThread::UI); 70#else 71 // TODO(reillyg): Migrate Linux/CrOS and Windows as well. 72 set_work_thread_id(content::BrowserThread::FILE); 73#endif 74 device_manager_ = HidDeviceManager::Get(browser_context()); 75 DCHECK(device_manager_); 76 connection_manager_ = 77 ApiResourceManager<HidConnectionResource>::Get(browser_context()); 78 DCHECK(connection_manager_); 79 return true; 80} 81 82bool HidAsyncApiFunction::Respond() { return error_.empty(); } 83 84HidConnectionResource* HidAsyncApiFunction::GetHidConnectionResource( 85 int api_resource_id) { 86 return connection_manager_->Get(extension_->id(), api_resource_id); 87} 88 89void HidAsyncApiFunction::RemoveHidConnectionResource(int api_resource_id) { 90 connection_manager_->Remove(extension_->id(), api_resource_id); 91} 92 93void HidAsyncApiFunction::CompleteWithError(const std::string& error) { 94 SetError(error); 95 AsyncWorkCompleted(); 96} 97 98HidGetDevicesFunction::HidGetDevicesFunction() {} 99 100HidGetDevicesFunction::~HidGetDevicesFunction() {} 101 102bool HidGetDevicesFunction::Prepare() { 103 parameters_ = hid::GetDevices::Params::Create(*args_); 104 EXTENSION_FUNCTION_VALIDATE(parameters_.get()); 105 return true; 106} 107 108void HidGetDevicesFunction::AsyncWorkStart() { 109 std::vector<HidDeviceFilter> filters; 110 if (parameters_->options.filters) { 111 filters.resize(parameters_->options.filters->size()); 112 for (size_t i = 0; i < parameters_->options.filters->size(); ++i) { 113 ConvertHidDeviceFilter(parameters_->options.filters->at(i), &filters[i]); 114 } 115 } 116 if (parameters_->options.vendor_id) { 117 HidDeviceFilter legacy_filter; 118 legacy_filter.SetVendorId(*parameters_->options.vendor_id); 119 if (parameters_->options.product_id) { 120 legacy_filter.SetProductId(*parameters_->options.product_id); 121 } 122 filters.push_back(legacy_filter); 123 } 124 125 SetResult(device_manager_->GetApiDevices(extension(), filters).release()); 126 AsyncWorkCompleted(); 127} 128 129HidConnectFunction::HidConnectFunction() {} 130 131HidConnectFunction::~HidConnectFunction() {} 132 133bool HidConnectFunction::Prepare() { 134 parameters_ = hid::Connect::Params::Create(*args_); 135 EXTENSION_FUNCTION_VALIDATE(parameters_.get()); 136 return true; 137} 138 139void HidConnectFunction::AsyncWorkStart() { 140 device::HidDeviceInfo device_info; 141 if (!device_manager_->GetDeviceInfo(parameters_->device_id, &device_info)) { 142 CompleteWithError(kErrorInvalidDeviceId); 143 return; 144 } 145 146 if (!device_manager_->HasPermission(extension(), device_info)) { 147 LOG(WARNING) << "Insufficient permissions to access device."; 148 CompleteWithError(kErrorPermissionDenied); 149 return; 150 } 151 152 HidService* hid_service = device::DeviceClient::Get()->GetHidService(); 153 DCHECK(hid_service); 154 scoped_refptr<HidConnection> connection = 155 hid_service->Connect(device_info.device_id); 156 if (!connection.get()) { 157 CompleteWithError(kErrorFailedToOpenDevice); 158 return; 159 } 160 int connection_id = connection_manager_->Add( 161 new HidConnectionResource(extension_->id(), connection)); 162 SetResult(PopulateHidConnection(connection_id, connection)); 163 AsyncWorkCompleted(); 164} 165 166HidDisconnectFunction::HidDisconnectFunction() {} 167 168HidDisconnectFunction::~HidDisconnectFunction() {} 169 170bool HidDisconnectFunction::Prepare() { 171 parameters_ = hid::Disconnect::Params::Create(*args_); 172 EXTENSION_FUNCTION_VALIDATE(parameters_.get()); 173 return true; 174} 175 176void HidDisconnectFunction::AsyncWorkStart() { 177 int connection_id = parameters_->connection_id; 178 HidConnectionResource* resource = 179 connection_manager_->Get(extension_->id(), connection_id); 180 if (!resource) { 181 CompleteWithError(kErrorConnectionNotFound); 182 return; 183 } 184 connection_manager_->Remove(extension_->id(), connection_id); 185 AsyncWorkCompleted(); 186} 187 188HidReceiveFunction::HidReceiveFunction() {} 189 190HidReceiveFunction::~HidReceiveFunction() {} 191 192bool HidReceiveFunction::Prepare() { 193 parameters_ = hid::Receive::Params::Create(*args_); 194 EXTENSION_FUNCTION_VALIDATE(parameters_.get()); 195 return true; 196} 197 198void HidReceiveFunction::AsyncWorkStart() { 199 int connection_id = parameters_->connection_id; 200 HidConnectionResource* resource = 201 connection_manager_->Get(extension_->id(), connection_id); 202 if (!resource) { 203 CompleteWithError(kErrorConnectionNotFound); 204 return; 205 } 206 207 scoped_refptr<device::HidConnection> connection = resource->connection(); 208 connection->Read(base::Bind(&HidReceiveFunction::OnFinished, this)); 209} 210 211void HidReceiveFunction::OnFinished(bool success, 212 scoped_refptr<net::IOBuffer> buffer, 213 size_t size) { 214 if (!success) { 215 CompleteWithError(kErrorTransfer); 216 return; 217 } 218 219 DCHECK_GE(size, 1u); 220 int report_id = reinterpret_cast<uint8_t*>(buffer->data())[0]; 221 222 scoped_ptr<base::ListValue> result(new base::ListValue()); 223 result->Append(new base::FundamentalValue(report_id)); 224 result->Append( 225 base::BinaryValue::CreateWithCopiedBuffer(buffer->data() + 1, size - 1)); 226 SetResultList(result.Pass()); 227 AsyncWorkCompleted(); 228} 229 230HidSendFunction::HidSendFunction() {} 231 232HidSendFunction::~HidSendFunction() {} 233 234bool HidSendFunction::Prepare() { 235 parameters_ = hid::Send::Params::Create(*args_); 236 EXTENSION_FUNCTION_VALIDATE(parameters_.get()); 237 return true; 238} 239 240void HidSendFunction::AsyncWorkStart() { 241 int connection_id = parameters_->connection_id; 242 HidConnectionResource* resource = 243 connection_manager_->Get(extension_->id(), connection_id); 244 if (!resource) { 245 CompleteWithError(kErrorConnectionNotFound); 246 return; 247 } 248 249 scoped_refptr<net::IOBufferWithSize> buffer( 250 new net::IOBufferWithSize(parameters_->data.size() + 1)); 251 buffer->data()[0] = static_cast<uint8_t>(parameters_->report_id); 252 memcpy( 253 buffer->data() + 1, parameters_->data.c_str(), parameters_->data.size()); 254 resource->connection()->Write( 255 buffer, buffer->size(), base::Bind(&HidSendFunction::OnFinished, this)); 256} 257 258void HidSendFunction::OnFinished(bool success) { 259 if (!success) { 260 CompleteWithError(kErrorTransfer); 261 return; 262 } 263 AsyncWorkCompleted(); 264} 265 266HidReceiveFeatureReportFunction::HidReceiveFeatureReportFunction() {} 267 268HidReceiveFeatureReportFunction::~HidReceiveFeatureReportFunction() {} 269 270bool HidReceiveFeatureReportFunction::Prepare() { 271 parameters_ = hid::ReceiveFeatureReport::Params::Create(*args_); 272 EXTENSION_FUNCTION_VALIDATE(parameters_.get()); 273 return true; 274} 275 276void HidReceiveFeatureReportFunction::AsyncWorkStart() { 277 int connection_id = parameters_->connection_id; 278 HidConnectionResource* resource = 279 connection_manager_->Get(extension_->id(), connection_id); 280 if (!resource) { 281 CompleteWithError(kErrorConnectionNotFound); 282 return; 283 } 284 285 scoped_refptr<device::HidConnection> connection = resource->connection(); 286 connection->GetFeatureReport( 287 static_cast<uint8_t>(parameters_->report_id), 288 base::Bind(&HidReceiveFeatureReportFunction::OnFinished, this)); 289} 290 291void HidReceiveFeatureReportFunction::OnFinished( 292 bool success, 293 scoped_refptr<net::IOBuffer> buffer, 294 size_t size) { 295 if (!success) { 296 CompleteWithError(kErrorTransfer); 297 return; 298 } 299 300 SetResult(base::BinaryValue::CreateWithCopiedBuffer(buffer->data(), size)); 301 AsyncWorkCompleted(); 302} 303 304HidSendFeatureReportFunction::HidSendFeatureReportFunction() {} 305 306HidSendFeatureReportFunction::~HidSendFeatureReportFunction() {} 307 308bool HidSendFeatureReportFunction::Prepare() { 309 parameters_ = hid::SendFeatureReport::Params::Create(*args_); 310 EXTENSION_FUNCTION_VALIDATE(parameters_.get()); 311 return true; 312} 313 314void HidSendFeatureReportFunction::AsyncWorkStart() { 315 int connection_id = parameters_->connection_id; 316 HidConnectionResource* resource = 317 connection_manager_->Get(extension_->id(), connection_id); 318 if (!resource) { 319 CompleteWithError(kErrorConnectionNotFound); 320 return; 321 } 322 323 scoped_refptr<net::IOBufferWithSize> buffer( 324 new net::IOBufferWithSize(parameters_->data.size() + 1)); 325 buffer->data()[0] = static_cast<uint8_t>(parameters_->report_id); 326 memcpy( 327 buffer->data() + 1, parameters_->data.c_str(), parameters_->data.size()); 328 resource->connection()->SendFeatureReport( 329 buffer, 330 buffer->size(), 331 base::Bind(&HidSendFeatureReportFunction::OnFinished, this)); 332} 333 334void HidSendFeatureReportFunction::OnFinished(bool success) { 335 if (!success) { 336 CompleteWithError(kErrorTransfer); 337 return; 338 } 339 AsyncWorkCompleted(); 340} 341 342} // namespace extensions 343