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 19 namespace hid = extensions::core_api::hid; 20 21 using device::HidConnection; 22 using device::HidDeviceFilter; 23 using device::HidDeviceInfo; 24 using device::HidService; 25 26 namespace { 27 28 const char kErrorPermissionDenied[] = "Permission to access device was denied."; 29 const char kErrorInvalidDeviceId[] = "Invalid HID device ID."; 30 const char kErrorFailedToOpenDevice[] = "Failed to open HID device."; 31 const char kErrorConnectionNotFound[] = "Connection not established."; 32 const char kErrorTransfer[] = "Transfer failed."; 33 34 base::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 41 void 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 59 namespace extensions { 60 61 HidAsyncApiFunction::HidAsyncApiFunction() 62 : device_manager_(NULL), connection_manager_(NULL) {} 63 64 HidAsyncApiFunction::~HidAsyncApiFunction() {} 65 66 bool 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 82 bool HidAsyncApiFunction::Respond() { return error_.empty(); } 83 84 HidConnectionResource* HidAsyncApiFunction::GetHidConnectionResource( 85 int api_resource_id) { 86 return connection_manager_->Get(extension_->id(), api_resource_id); 87 } 88 89 void HidAsyncApiFunction::RemoveHidConnectionResource(int api_resource_id) { 90 connection_manager_->Remove(extension_->id(), api_resource_id); 91 } 92 93 void HidAsyncApiFunction::CompleteWithError(const std::string& error) { 94 SetError(error); 95 AsyncWorkCompleted(); 96 } 97 98 HidGetDevicesFunction::HidGetDevicesFunction() {} 99 100 HidGetDevicesFunction::~HidGetDevicesFunction() {} 101 102 bool HidGetDevicesFunction::Prepare() { 103 parameters_ = hid::GetDevices::Params::Create(*args_); 104 EXTENSION_FUNCTION_VALIDATE(parameters_.get()); 105 return true; 106 } 107 108 void 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 129 HidConnectFunction::HidConnectFunction() {} 130 131 HidConnectFunction::~HidConnectFunction() {} 132 133 bool HidConnectFunction::Prepare() { 134 parameters_ = hid::Connect::Params::Create(*args_); 135 EXTENSION_FUNCTION_VALIDATE(parameters_.get()); 136 return true; 137 } 138 139 void 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 166 HidDisconnectFunction::HidDisconnectFunction() {} 167 168 HidDisconnectFunction::~HidDisconnectFunction() {} 169 170 bool HidDisconnectFunction::Prepare() { 171 parameters_ = hid::Disconnect::Params::Create(*args_); 172 EXTENSION_FUNCTION_VALIDATE(parameters_.get()); 173 return true; 174 } 175 176 void 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 188 HidReceiveFunction::HidReceiveFunction() {} 189 190 HidReceiveFunction::~HidReceiveFunction() {} 191 192 bool HidReceiveFunction::Prepare() { 193 parameters_ = hid::Receive::Params::Create(*args_); 194 EXTENSION_FUNCTION_VALIDATE(parameters_.get()); 195 return true; 196 } 197 198 void 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 211 void 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 230 HidSendFunction::HidSendFunction() {} 231 232 HidSendFunction::~HidSendFunction() {} 233 234 bool HidSendFunction::Prepare() { 235 parameters_ = hid::Send::Params::Create(*args_); 236 EXTENSION_FUNCTION_VALIDATE(parameters_.get()); 237 return true; 238 } 239 240 void 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 258 void HidSendFunction::OnFinished(bool success) { 259 if (!success) { 260 CompleteWithError(kErrorTransfer); 261 return; 262 } 263 AsyncWorkCompleted(); 264 } 265 266 HidReceiveFeatureReportFunction::HidReceiveFeatureReportFunction() {} 267 268 HidReceiveFeatureReportFunction::~HidReceiveFeatureReportFunction() {} 269 270 bool HidReceiveFeatureReportFunction::Prepare() { 271 parameters_ = hid::ReceiveFeatureReport::Params::Create(*args_); 272 EXTENSION_FUNCTION_VALIDATE(parameters_.get()); 273 return true; 274 } 275 276 void 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 291 void 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 304 HidSendFeatureReportFunction::HidSendFeatureReportFunction() {} 305 306 HidSendFeatureReportFunction::~HidSendFeatureReportFunction() {} 307 308 bool HidSendFeatureReportFunction::Prepare() { 309 parameters_ = hid::SendFeatureReport::Params::Create(*args_); 310 EXTENSION_FUNCTION_VALIDATE(parameters_.get()); 311 return true; 312 } 313 314 void 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 334 void HidSendFeatureReportFunction::OnFinished(bool success) { 335 if (!success) { 336 CompleteWithError(kErrorTransfer); 337 return; 338 } 339 AsyncWorkCompleted(); 340 } 341 342 } // namespace extensions 343