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
PopulateHidConnection(int connection_id,scoped_refptr<HidConnection> connection)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
ConvertHidDeviceFilter(linked_ptr<hid::DeviceFilter> input,HidDeviceFilter * output)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
HidAsyncApiFunction()61 HidAsyncApiFunction::HidAsyncApiFunction()
62 : device_manager_(NULL), connection_manager_(NULL) {}
63
~HidAsyncApiFunction()64 HidAsyncApiFunction::~HidAsyncApiFunction() {}
65
PrePrepare()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
Respond()82 bool HidAsyncApiFunction::Respond() { return error_.empty(); }
83
GetHidConnectionResource(int api_resource_id)84 HidConnectionResource* HidAsyncApiFunction::GetHidConnectionResource(
85 int api_resource_id) {
86 return connection_manager_->Get(extension_->id(), api_resource_id);
87 }
88
RemoveHidConnectionResource(int api_resource_id)89 void HidAsyncApiFunction::RemoveHidConnectionResource(int api_resource_id) {
90 connection_manager_->Remove(extension_->id(), api_resource_id);
91 }
92
CompleteWithError(const std::string & error)93 void HidAsyncApiFunction::CompleteWithError(const std::string& error) {
94 SetError(error);
95 AsyncWorkCompleted();
96 }
97
HidGetDevicesFunction()98 HidGetDevicesFunction::HidGetDevicesFunction() {}
99
~HidGetDevicesFunction()100 HidGetDevicesFunction::~HidGetDevicesFunction() {}
101
Prepare()102 bool HidGetDevicesFunction::Prepare() {
103 parameters_ = hid::GetDevices::Params::Create(*args_);
104 EXTENSION_FUNCTION_VALIDATE(parameters_.get());
105 return true;
106 }
107
AsyncWorkStart()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
HidConnectFunction()129 HidConnectFunction::HidConnectFunction() {}
130
~HidConnectFunction()131 HidConnectFunction::~HidConnectFunction() {}
132
Prepare()133 bool HidConnectFunction::Prepare() {
134 parameters_ = hid::Connect::Params::Create(*args_);
135 EXTENSION_FUNCTION_VALIDATE(parameters_.get());
136 return true;
137 }
138
AsyncWorkStart()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
HidDisconnectFunction()166 HidDisconnectFunction::HidDisconnectFunction() {}
167
~HidDisconnectFunction()168 HidDisconnectFunction::~HidDisconnectFunction() {}
169
Prepare()170 bool HidDisconnectFunction::Prepare() {
171 parameters_ = hid::Disconnect::Params::Create(*args_);
172 EXTENSION_FUNCTION_VALIDATE(parameters_.get());
173 return true;
174 }
175
AsyncWorkStart()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
HidReceiveFunction()188 HidReceiveFunction::HidReceiveFunction() {}
189
~HidReceiveFunction()190 HidReceiveFunction::~HidReceiveFunction() {}
191
Prepare()192 bool HidReceiveFunction::Prepare() {
193 parameters_ = hid::Receive::Params::Create(*args_);
194 EXTENSION_FUNCTION_VALIDATE(parameters_.get());
195 return true;
196 }
197
AsyncWorkStart()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
OnFinished(bool success,scoped_refptr<net::IOBuffer> buffer,size_t size)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
HidSendFunction()230 HidSendFunction::HidSendFunction() {}
231
~HidSendFunction()232 HidSendFunction::~HidSendFunction() {}
233
Prepare()234 bool HidSendFunction::Prepare() {
235 parameters_ = hid::Send::Params::Create(*args_);
236 EXTENSION_FUNCTION_VALIDATE(parameters_.get());
237 return true;
238 }
239
AsyncWorkStart()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
OnFinished(bool success)258 void HidSendFunction::OnFinished(bool success) {
259 if (!success) {
260 CompleteWithError(kErrorTransfer);
261 return;
262 }
263 AsyncWorkCompleted();
264 }
265
HidReceiveFeatureReportFunction()266 HidReceiveFeatureReportFunction::HidReceiveFeatureReportFunction() {}
267
~HidReceiveFeatureReportFunction()268 HidReceiveFeatureReportFunction::~HidReceiveFeatureReportFunction() {}
269
Prepare()270 bool HidReceiveFeatureReportFunction::Prepare() {
271 parameters_ = hid::ReceiveFeatureReport::Params::Create(*args_);
272 EXTENSION_FUNCTION_VALIDATE(parameters_.get());
273 return true;
274 }
275
AsyncWorkStart()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
OnFinished(bool success,scoped_refptr<net::IOBuffer> buffer,size_t size)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
HidSendFeatureReportFunction()304 HidSendFeatureReportFunction::HidSendFeatureReportFunction() {}
305
~HidSendFeatureReportFunction()306 HidSendFeatureReportFunction::~HidSendFeatureReportFunction() {}
307
Prepare()308 bool HidSendFeatureReportFunction::Prepare() {
309 parameters_ = hid::SendFeatureReport::Params::Create(*args_);
310 EXTENSION_FUNCTION_VALIDATE(parameters_.get());
311 return true;
312 }
313
AsyncWorkStart()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
OnFinished(bool success)334 void HidSendFeatureReportFunction::OnFinished(bool success) {
335 if (!success) {
336 CompleteWithError(kErrorTransfer);
337 return;
338 }
339 AsyncWorkCompleted();
340 }
341
342 } // namespace extensions
343