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 "chrome/browser/extensions/api/hid/hid_api.h" 6 7 #include <string> 8 #include <vector> 9 10 #include "chrome/common/extensions/api/hid.h" 11 #include "device/hid/hid_connection.h" 12 #include "device/hid/hid_device_info.h" 13 #include "device/hid/hid_service.h" 14 #include "extensions/browser/api/api_resource_manager.h" 15 #include "extensions/common/permissions/permissions_data.h" 16 #include "extensions/common/permissions/usb_device_permission.h" 17 #include "net/base/io_buffer.h" 18 19 namespace hid = extensions::api::hid; 20 21 using device::HidConnection; 22 using device::HidDeviceInfo; 23 using device::HidService; 24 25 namespace { 26 27 const char kErrorPermissionDenied[] = "Permission to access device was denied."; 28 const char kErrorInvalidDeviceId[] = "Invalid HID device ID."; 29 const char kErrorFailedToOpenDevice[] = "Failed to open HID device."; 30 const char kErrorConnectionNotFound[] = "Connection not established."; 31 const char kErrorTransfer[] = "Transfer failed."; 32 33 base::Value* PopulateHidConnection(int connection_id, 34 scoped_refptr<HidConnection> connection) { 35 hid::HidConnectInfo connection_value; 36 connection_value.connection_id = connection_id; 37 return connection_value.ToValue().release(); 38 } 39 40 } // namespace 41 42 namespace extensions { 43 44 HidAsyncApiFunction::HidAsyncApiFunction() 45 : device_manager_(NULL), connection_manager_(NULL) {} 46 47 HidAsyncApiFunction::~HidAsyncApiFunction() {} 48 49 bool HidAsyncApiFunction::PrePrepare() { 50 device_manager_ = HidDeviceManager::Get(browser_context()); 51 DCHECK(device_manager_); 52 connection_manager_ = 53 ApiResourceManager<HidConnectionResource>::Get(browser_context()); 54 DCHECK(connection_manager_); 55 set_work_thread_id(content::BrowserThread::FILE); 56 return true; 57 } 58 59 bool HidAsyncApiFunction::Respond() { return error_.empty(); } 60 61 HidConnectionResource* HidAsyncApiFunction::GetHidConnectionResource( 62 int api_resource_id) { 63 return connection_manager_->Get(extension_->id(), api_resource_id); 64 } 65 66 void HidAsyncApiFunction::RemoveHidConnectionResource(int api_resource_id) { 67 connection_manager_->Remove(extension_->id(), api_resource_id); 68 } 69 70 void HidAsyncApiFunction::CompleteWithError(const std::string& error) { 71 SetError(error); 72 AsyncWorkCompleted(); 73 } 74 75 HidGetDevicesFunction::HidGetDevicesFunction() {} 76 77 HidGetDevicesFunction::~HidGetDevicesFunction() {} 78 79 bool HidGetDevicesFunction::Prepare() { 80 parameters_ = hid::GetDevices::Params::Create(*args_); 81 EXTENSION_FUNCTION_VALIDATE(parameters_.get()); 82 return true; 83 } 84 85 void HidGetDevicesFunction::AsyncWorkStart() { 86 const uint16_t vendor_id = parameters_->options.vendor_id; 87 const uint16_t product_id = parameters_->options.product_id; 88 UsbDevicePermission::CheckParam param( 89 vendor_id, product_id, UsbDevicePermissionData::UNSPECIFIED_INTERFACE); 90 if (!GetExtension()->permissions_data()->CheckAPIPermissionWithParam( 91 APIPermission::kUsbDevice, ¶m)) { 92 LOG(WARNING) << "Insufficient permissions to access device."; 93 CompleteWithError(kErrorPermissionDenied); 94 return; 95 } 96 97 SetResult(device_manager_->GetApiDevices(vendor_id, product_id).release()); 98 AsyncWorkCompleted(); 99 } 100 101 HidConnectFunction::HidConnectFunction() {} 102 103 HidConnectFunction::~HidConnectFunction() {} 104 105 bool HidConnectFunction::Prepare() { 106 parameters_ = hid::Connect::Params::Create(*args_); 107 EXTENSION_FUNCTION_VALIDATE(parameters_.get()); 108 return true; 109 } 110 111 void HidConnectFunction::AsyncWorkStart() { 112 device::HidDeviceInfo device_info; 113 if (!device_manager_->GetDeviceInfo(parameters_->device_id, &device_info)) { 114 CompleteWithError(kErrorInvalidDeviceId); 115 return; 116 } 117 118 UsbDevicePermission::CheckParam param( 119 device_info.vendor_id, 120 device_info.product_id, 121 UsbDevicePermissionData::UNSPECIFIED_INTERFACE); 122 if (!GetExtension()->permissions_data()->CheckAPIPermissionWithParam( 123 APIPermission::kUsbDevice, ¶m)) { 124 LOG(WARNING) << "Insufficient permissions to access device."; 125 CompleteWithError(kErrorPermissionDenied); 126 return; 127 } 128 129 HidService* hid_service = HidService::GetInstance(); 130 DCHECK(hid_service); 131 scoped_refptr<HidConnection> connection = 132 hid_service->Connect(device_info.device_id); 133 if (!connection) { 134 CompleteWithError(kErrorFailedToOpenDevice); 135 return; 136 } 137 int connection_id = connection_manager_->Add( 138 new HidConnectionResource(extension_->id(), connection)); 139 SetResult(PopulateHidConnection(connection_id, connection)); 140 AsyncWorkCompleted(); 141 } 142 143 HidDisconnectFunction::HidDisconnectFunction() {} 144 145 HidDisconnectFunction::~HidDisconnectFunction() {} 146 147 bool HidDisconnectFunction::Prepare() { 148 parameters_ = hid::Disconnect::Params::Create(*args_); 149 EXTENSION_FUNCTION_VALIDATE(parameters_.get()); 150 return true; 151 } 152 153 void HidDisconnectFunction::AsyncWorkStart() { 154 int connection_id = parameters_->connection_id; 155 HidConnectionResource* resource = 156 connection_manager_->Get(extension_->id(), connection_id); 157 if (!resource) { 158 CompleteWithError(kErrorConnectionNotFound); 159 return; 160 } 161 connection_manager_->Remove(extension_->id(), connection_id); 162 AsyncWorkCompleted(); 163 } 164 165 HidReceiveFunction::HidReceiveFunction() {} 166 167 HidReceiveFunction::~HidReceiveFunction() {} 168 169 bool HidReceiveFunction::Prepare() { 170 parameters_ = hid::Receive::Params::Create(*args_); 171 EXTENSION_FUNCTION_VALIDATE(parameters_.get()); 172 return true; 173 } 174 175 void HidReceiveFunction::AsyncWorkStart() { 176 int connection_id = parameters_->connection_id; 177 HidConnectionResource* resource = 178 connection_manager_->Get(extension_->id(), connection_id); 179 if (!resource) { 180 CompleteWithError(kErrorConnectionNotFound); 181 return; 182 } 183 184 buffer_ = new net::IOBufferWithSize(parameters_->size); 185 resource->connection()->Read( 186 buffer_, base::Bind(&HidReceiveFunction::OnFinished, this)); 187 } 188 189 void HidReceiveFunction::OnFinished(bool success, size_t bytes) { 190 if (!success) { 191 CompleteWithError(kErrorTransfer); 192 return; 193 } 194 195 SetResult(base::BinaryValue::CreateWithCopiedBuffer(buffer_->data(), bytes)); 196 AsyncWorkCompleted(); 197 } 198 199 HidSendFunction::HidSendFunction() {} 200 201 HidSendFunction::~HidSendFunction() {} 202 203 bool HidSendFunction::Prepare() { 204 parameters_ = hid::Send::Params::Create(*args_); 205 EXTENSION_FUNCTION_VALIDATE(parameters_.get()); 206 return true; 207 } 208 209 void HidSendFunction::AsyncWorkStart() { 210 int connection_id = parameters_->connection_id; 211 HidConnectionResource* resource = 212 connection_manager_->Get(extension_->id(), connection_id); 213 if (!resource) { 214 CompleteWithError(kErrorConnectionNotFound); 215 return; 216 } 217 218 scoped_refptr<net::IOBufferWithSize> buffer( 219 new net::IOBufferWithSize(parameters_->data.size())); 220 memcpy(buffer->data(), parameters_->data.c_str(), parameters_->data.size()); 221 resource->connection()->Write(static_cast<uint8_t>(parameters_->report_id), 222 buffer, 223 base::Bind(&HidSendFunction::OnFinished, this)); 224 } 225 226 void HidSendFunction::OnFinished(bool success, size_t bytes) { 227 if (!success) { 228 CompleteWithError(kErrorTransfer); 229 return; 230 } 231 AsyncWorkCompleted(); 232 } 233 234 HidReceiveFeatureReportFunction::HidReceiveFeatureReportFunction() {} 235 236 HidReceiveFeatureReportFunction::~HidReceiveFeatureReportFunction() {} 237 238 bool HidReceiveFeatureReportFunction::Prepare() { 239 parameters_ = hid::ReceiveFeatureReport::Params::Create(*args_); 240 EXTENSION_FUNCTION_VALIDATE(parameters_.get()); 241 return true; 242 } 243 244 void HidReceiveFeatureReportFunction::AsyncWorkStart() { 245 int connection_id = parameters_->connection_id; 246 HidConnectionResource* resource = 247 connection_manager_->Get(extension_->id(), connection_id); 248 if (!resource) { 249 CompleteWithError(kErrorConnectionNotFound); 250 return; 251 } 252 buffer_ = new net::IOBufferWithSize(parameters_->size); 253 resource->connection()->GetFeatureReport( 254 static_cast<uint8_t>(parameters_->report_id), 255 buffer_, 256 base::Bind(&HidReceiveFeatureReportFunction::OnFinished, this)); 257 } 258 259 void HidReceiveFeatureReportFunction::OnFinished(bool success, size_t bytes) { 260 if (!success) { 261 CompleteWithError(kErrorTransfer); 262 return; 263 } 264 265 SetResult(base::BinaryValue::CreateWithCopiedBuffer(buffer_->data(), bytes)); 266 AsyncWorkCompleted(); 267 } 268 269 HidSendFeatureReportFunction::HidSendFeatureReportFunction() {} 270 271 HidSendFeatureReportFunction::~HidSendFeatureReportFunction() {} 272 273 bool HidSendFeatureReportFunction::Prepare() { 274 parameters_ = hid::SendFeatureReport::Params::Create(*args_); 275 EXTENSION_FUNCTION_VALIDATE(parameters_.get()); 276 return true; 277 } 278 279 void HidSendFeatureReportFunction::AsyncWorkStart() { 280 int connection_id = parameters_->connection_id; 281 HidConnectionResource* resource = 282 connection_manager_->Get(extension_->id(), connection_id); 283 if (!resource) { 284 CompleteWithError(kErrorConnectionNotFound); 285 return; 286 } 287 scoped_refptr<net::IOBufferWithSize> buffer( 288 new net::IOBufferWithSize(parameters_->data.size())); 289 resource->connection()->SendFeatureReport( 290 static_cast<uint8_t>(parameters_->report_id), 291 buffer, 292 base::Bind(&HidSendFeatureReportFunction::OnFinished, this)); 293 } 294 295 void HidSendFeatureReportFunction::OnFinished(bool success, size_t bytes) { 296 if (!success) { 297 CompleteWithError(kErrorTransfer); 298 return; 299 } 300 AsyncWorkCompleted(); 301 } 302 303 } // namespace extensions 304