1 // Copyright (c) 2012 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.
5 #include "chrome/browser/extensions/api/bluetooth/bluetooth_api.h"
9 #include "base/memory/ref_counted.h"
10 #include "chrome/browser/extensions/api/bluetooth/bluetooth_api_factory.h"
11 #include "chrome/browser/extensions/api/bluetooth/bluetooth_api_utils.h"
12 #include "chrome/browser/extensions/api/bluetooth/bluetooth_event_router.h"
13 #include "chrome/browser/extensions/event_names.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/common/extensions/api/bluetooth.h"
16 #include "chrome/common/extensions/api/bluetooth/bluetooth_manifest_data.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "device/bluetooth/bluetooth_adapter.h"
19 #include "device/bluetooth/bluetooth_device.h"
20 #include "device/bluetooth/bluetooth_out_of_band_pairing_data.h"
21 #include "device/bluetooth/bluetooth_profile.h"
22 #include "device/bluetooth/bluetooth_service_record.h"
23 #include "device/bluetooth/bluetooth_socket.h"
24 #include "device/bluetooth/bluetooth_utils.h"
25 #include "extensions/browser/event_router.h"
26 #include "extensions/browser/extension_system.h"
27 #include "extensions/common/permissions/permissions_data.h"
28 #include "net/base/io_buffer.h"
30 using device::BluetoothAdapter;
31 using device::BluetoothDevice;
32 using device::BluetoothProfile;
33 using device::BluetoothServiceRecord;
34 using device::BluetoothSocket;
38 extensions::ExtensionBluetoothEventRouter* GetEventRouter(Profile* profile) {
39 return extensions::BluetoothAPI::Get(profile)->bluetooth_event_router();
46 const char kCouldNotGetLocalOutOfBandPairingData[] =
47 "Could not get local Out Of Band Pairing Data";
48 const char kCouldNotSetOutOfBandPairingData[] =
49 "Could not set Out Of Band Pairing Data";
50 const char kFailedToConnect[] = "Connection failed";
51 const char kInvalidDevice[] = "Invalid device";
52 const char kInvalidUuid[] = "Invalid UUID";
53 const char kPermissionDenied[] = "Permission to add profile denied.";
54 const char kProfileAlreadyRegistered[] =
55 "This profile has already been registered";
56 const char kProfileNotFound[] = "Profile not found: invalid uuid";
57 const char kProfileRegistrationFailed[] = "Profile registration failed";
58 const char kServiceDiscoveryFailed[] = "Service discovery failed";
59 const char kSocketNotFoundError[] = "Socket not found: invalid socket id";
60 const char kStartDiscoveryFailed[] = "Starting discovery failed";
61 const char kStopDiscoveryFailed[] = "Failed to stop discovery";
65 namespace AddProfile = extensions::api::bluetooth::AddProfile;
66 namespace bluetooth = extensions::api::bluetooth;
67 namespace Connect = extensions::api::bluetooth::Connect;
68 namespace Disconnect = extensions::api::bluetooth::Disconnect;
69 namespace GetDevices = extensions::api::bluetooth::GetDevices;
70 namespace GetProfiles = extensions::api::bluetooth::GetProfiles;
71 namespace GetServices = extensions::api::bluetooth::GetServices;
72 namespace Read = extensions::api::bluetooth::Read;
73 namespace RemoveProfile = extensions::api::bluetooth::RemoveProfile;
74 namespace SetOutOfBandPairingData =
75 extensions::api::bluetooth::SetOutOfBandPairingData;
76 namespace Write = extensions::api::bluetooth::Write;
78 namespace extensions {
81 BluetoothAPI* BluetoothAPI::Get(Profile* profile) {
82 return BluetoothAPIFactory::GetForProfile(profile);
85 BluetoothAPI::BluetoothAPI(Profile* profile) : profile_(profile) {
86 ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
87 this, bluetooth::OnAdapterStateChanged::kEventName);
90 BluetoothAPI::~BluetoothAPI() {
93 ExtensionBluetoothEventRouter* BluetoothAPI::bluetooth_event_router() {
94 if (!bluetooth_event_router_)
95 bluetooth_event_router_.reset(new ExtensionBluetoothEventRouter(profile_));
97 return bluetooth_event_router_.get();
100 void BluetoothAPI::Shutdown() {
101 ExtensionSystem::Get(profile_)->event_router()->UnregisterObserver(this);
104 void BluetoothAPI::OnListenerAdded(const EventListenerInfo& details) {
105 if (bluetooth_event_router()->IsBluetoothSupported())
106 bluetooth_event_router()->OnListenerAdded();
109 void BluetoothAPI::OnListenerRemoved(const EventListenerInfo& details) {
110 if (bluetooth_event_router()->IsBluetoothSupported())
111 bluetooth_event_router()->OnListenerRemoved();
116 BluetoothAddProfileFunction::BluetoothAddProfileFunction() {
119 bool BluetoothAddProfileFunction::RunImpl() {
120 scoped_ptr<AddProfile::Params> params(AddProfile::Params::Create(*args_));
121 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
123 if (!BluetoothDevice::IsUUIDValid(params->profile.uuid)) {
124 SetError(kInvalidUuid);
128 BluetoothPermissionRequest param(params->profile.uuid);
129 if (!BluetoothManifestData::CheckRequest(GetExtension(), param)) {
130 error_ = kPermissionDenied;
134 uuid_ = device::bluetooth_utils::CanonicalUuid(params->profile.uuid);
136 if (GetEventRouter(GetProfile())->HasProfile(uuid_)) {
137 SetError(kProfileAlreadyRegistered);
141 BluetoothProfile::Options options;
142 if (params->profile.name.get())
143 options.name = *params->profile.name.get();
144 if (params->profile.channel.get())
145 options.channel = *params->profile.channel.get();
146 if (params->profile.psm.get())
147 options.psm = *params->profile.psm.get();
148 if (params->profile.require_authentication.get()) {
149 options.require_authentication =
150 *params->profile.require_authentication.get();
152 if (params->profile.require_authorization.get()) {
153 options.require_authorization =
154 *params->profile.require_authorization.get();
156 if (params->profile.auto_connect.get())
157 options.auto_connect = *params->profile.auto_connect.get();
158 if (params->profile.version.get())
159 options.version = *params->profile.version.get();
160 if (params->profile.features.get())
161 options.features = *params->profile.features.get();
165 base::Bind(&BluetoothAddProfileFunction::OnProfileRegistered, this));
170 void BluetoothAddProfileFunction::RegisterProfile(
171 const BluetoothProfile::Options& options,
172 const BluetoothProfile::ProfileCallback& callback) {
173 BluetoothProfile::Register(uuid_, options, callback);
176 void BluetoothAddProfileFunction::OnProfileRegistered(
177 BluetoothProfile* bluetooth_profile) {
178 if (!bluetooth_profile) {
179 SetError(kProfileRegistrationFailed);
184 if (GetEventRouter(GetProfile())->HasProfile(uuid_)) {
185 bluetooth_profile->Unregister();
186 SetError(kProfileAlreadyRegistered);
191 bluetooth_profile->SetConnectionCallback(
192 base::Bind(&ExtensionBluetoothEventRouter::DispatchConnectionEvent,
193 base::Unretained(GetEventRouter(GetProfile())),
196 GetEventRouter(GetProfile())->AddProfile(
197 uuid_, extension_id(), bluetooth_profile);
201 bool BluetoothRemoveProfileFunction::RunImpl() {
202 scoped_ptr<RemoveProfile::Params> params(
203 RemoveProfile::Params::Create(*args_));
205 if (!BluetoothDevice::IsUUIDValid(params->profile.uuid)) {
206 SetError(kInvalidUuid);
211 device::bluetooth_utils::CanonicalUuid(params->profile.uuid);
213 if (!GetEventRouter(GetProfile())->HasProfile(uuid)) {
214 SetError(kProfileNotFound);
218 GetEventRouter(GetProfile())->RemoveProfile(uuid);
222 // TODO(youngki): Implement.
223 bool BluetoothGetProfilesFunction::DoWork(
224 scoped_refptr<device::BluetoothAdapter> adapter) {
225 scoped_ptr<GetProfiles::Params> params(GetProfiles::Params::Create(*args_));
226 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
227 const bluetooth::GetProfilesOptions& options = params->options;
229 BluetoothDevice* device = adapter->GetDevice(options.device.address);
231 SetError(kInvalidDevice);
236 BluetoothDevice::ServiceList service_list = device->GetServices();
238 base::ListValue* profiles = new base::ListValue;
239 for (BluetoothDevice::ServiceList::const_iterator iter = service_list.begin();
240 iter != service_list.end();
242 bluetooth::Profile api_profile;
243 api_profile.uuid = *iter;
244 profiles->Append(api_profile.ToValue().release());
253 bool BluetoothGetAdapterStateFunction::DoWork(
254 scoped_refptr<BluetoothAdapter> adapter) {
255 bluetooth::AdapterState state;
256 PopulateAdapterState(*adapter.get(), &state);
257 SetResult(state.ToValue().release());
262 BluetoothGetDevicesFunction::BluetoothGetDevicesFunction()
263 : device_events_sent_(0) {}
265 void BluetoothGetDevicesFunction::DispatchDeviceSearchResult(
266 const BluetoothDevice& device) {
267 bluetooth::Device extension_device;
268 bluetooth::BluetoothDeviceToApiDevice(device, &extension_device);
269 GetEventRouter(GetProfile())->DispatchDeviceEvent(
270 extensions::event_names::kBluetoothOnDeviceSearchResult,
273 device_events_sent_++;
276 void BluetoothGetDevicesFunction::FinishDeviceSearch() {
277 scoped_ptr<base::ListValue> args(new base::ListValue());
278 scoped_ptr<base::DictionaryValue> info(new base::DictionaryValue());
279 info->SetInteger("expectedEventCount", device_events_sent_);
280 args->Append(info.release());
282 scoped_ptr<extensions::Event> event(new extensions::Event(
283 extensions::event_names::kBluetoothOnDeviceSearchFinished, args.Pass()));
284 extensions::ExtensionSystem::Get(GetProfile())
286 ->BroadcastEvent(event.Pass());
291 bool BluetoothGetDevicesFunction::DoWork(
292 scoped_refptr<BluetoothAdapter> adapter) {
293 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
295 scoped_ptr<GetDevices::Params> params(GetDevices::Params::Create(*args_));
296 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
297 const bluetooth::GetDevicesOptions& options = params->options;
300 if (options.profile.get() != NULL) {
301 uuid = options.profile->uuid;
302 if (!BluetoothDevice::IsUUIDValid(uuid)) {
303 SetError(kInvalidUuid);
309 BluetoothAdapter::DeviceList devices = adapter->GetDevices();
310 for (BluetoothAdapter::DeviceList::const_iterator iter = devices.begin();
311 iter != devices.end();
313 const BluetoothDevice* device = *iter;
315 if (uuid.empty() || device->ProvidesServiceWithUUID(uuid))
316 DispatchDeviceSearchResult(*device);
319 FinishDeviceSearch();
324 void BluetoothGetServicesFunction::GetServiceRecordsCallback(
325 base::ListValue* services,
326 const BluetoothDevice::ServiceRecordList& records) {
327 for (BluetoothDevice::ServiceRecordList::const_iterator i = records.begin();
328 i != records.end(); ++i) {
329 const BluetoothServiceRecord& record = **i;
330 bluetooth::ServiceRecord api_record;
331 api_record.name = record.name();
332 if (!record.uuid().empty())
333 api_record.uuid.reset(new std::string(record.uuid()));
334 services->Append(api_record.ToValue().release());
340 void BluetoothGetServicesFunction::OnErrorCallback() {
341 SetError(kServiceDiscoveryFailed);
345 bool BluetoothGetServicesFunction::DoWork(
346 scoped_refptr<BluetoothAdapter> adapter) {
347 scoped_ptr<GetServices::Params> params(GetServices::Params::Create(*args_));
348 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
349 const bluetooth::GetServicesOptions& options = params->options;
351 BluetoothDevice* device = adapter->GetDevice(options.device_address);
353 SetError(kInvalidDevice);
358 base::ListValue* services = new base::ListValue;
361 device->GetServiceRecords(
362 base::Bind(&BluetoothGetServicesFunction::GetServiceRecordsCallback,
365 base::Bind(&BluetoothGetServicesFunction::OnErrorCallback,
371 void BluetoothConnectFunction::OnSuccessCallback() {
375 void BluetoothConnectFunction::OnErrorCallback() {
376 SetError(kFailedToConnect);
380 bool BluetoothConnectFunction::DoWork(scoped_refptr<BluetoothAdapter> adapter) {
381 scoped_ptr<Connect::Params> params(Connect::Params::Create(*args_));
382 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
383 const bluetooth::ConnectOptions& options = params->options;
385 if (!BluetoothDevice::IsUUIDValid(options.profile.uuid)) {
386 SetError(kInvalidUuid);
391 BluetoothDevice* device = adapter->GetDevice(options.device.address);
393 SetError(kInvalidDevice);
398 std::string uuid = device::bluetooth_utils::CanonicalUuid(
399 options.profile.uuid);
401 BluetoothProfile* bluetooth_profile =
402 GetEventRouter(GetProfile())->GetProfile(uuid);
403 if (!bluetooth_profile) {
404 SetError(kProfileNotFound);
409 device->ConnectToProfile(
411 base::Bind(&BluetoothConnectFunction::OnSuccessCallback, this),
412 base::Bind(&BluetoothConnectFunction::OnErrorCallback, this));
417 bool BluetoothDisconnectFunction::RunImpl() {
418 scoped_ptr<Disconnect::Params> params(Disconnect::Params::Create(*args_));
419 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
420 const bluetooth::DisconnectOptions& options = params->options;
421 return GetEventRouter(GetProfile())->ReleaseSocket(options.socket.id);
424 BluetoothReadFunction::BluetoothReadFunction() : success_(false) {}
425 BluetoothReadFunction::~BluetoothReadFunction() {}
427 bool BluetoothReadFunction::Prepare() {
428 scoped_ptr<Read::Params> params(Read::Params::Create(*args_));
429 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
430 const bluetooth::ReadOptions& options = params->options;
432 socket_ = GetEventRouter(GetProfile())->GetSocket(options.socket.id);
433 if (socket_.get() == NULL) {
434 SetError(kSocketNotFoundError);
442 void BluetoothReadFunction::Work() {
443 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
448 scoped_refptr<net::GrowableIOBuffer> buffer(new net::GrowableIOBuffer);
449 success_ = socket_->Receive(buffer.get());
451 SetResult(base::BinaryValue::CreateWithCopiedBuffer(buffer->StartOfBuffer(),
454 SetError(socket_->GetLastErrorMessage());
457 bool BluetoothReadFunction::Respond() {
461 BluetoothWriteFunction::BluetoothWriteFunction()
463 data_to_write_(NULL) {
466 BluetoothWriteFunction::~BluetoothWriteFunction() {}
468 bool BluetoothWriteFunction::Prepare() {
469 // TODO(bryeung): update to new-style parameter passing when ArrayBuffer
471 base::DictionaryValue* options;
472 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &options));
474 base::DictionaryValue* socket;
475 EXTENSION_FUNCTION_VALIDATE(options->GetDictionary("socket", &socket));
478 EXTENSION_FUNCTION_VALIDATE(socket->GetInteger("id", &socket_id));
480 socket_ = GetEventRouter(GetProfile())->GetSocket(socket_id);
481 if (socket_.get() == NULL) {
482 SetError(kSocketNotFoundError);
486 base::BinaryValue* tmp_data;
487 EXTENSION_FUNCTION_VALIDATE(options->GetBinary("data", &tmp_data));
488 data_to_write_ = tmp_data;
491 return socket_.get() != NULL;
494 void BluetoothWriteFunction::Work() {
495 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
497 if (socket_.get() == NULL)
500 scoped_refptr<net::WrappedIOBuffer> wrapped_io_buffer(
501 new net::WrappedIOBuffer(data_to_write_->GetBuffer()));
502 scoped_refptr<net::DrainableIOBuffer> drainable_io_buffer(
503 new net::DrainableIOBuffer(wrapped_io_buffer.get(),
504 data_to_write_->GetSize()));
505 success_ = socket_->Send(drainable_io_buffer.get());
507 if (drainable_io_buffer->BytesConsumed() > 0)
508 SetResult(new base::FundamentalValue(
509 drainable_io_buffer->BytesConsumed()));
513 SetError(socket_->GetLastErrorMessage());
517 bool BluetoothWriteFunction::Respond() {
521 void BluetoothSetOutOfBandPairingDataFunction::OnSuccessCallback() {
525 void BluetoothSetOutOfBandPairingDataFunction::OnErrorCallback() {
526 SetError(kCouldNotSetOutOfBandPairingData);
530 bool BluetoothSetOutOfBandPairingDataFunction::DoWork(
531 scoped_refptr<BluetoothAdapter> adapter) {
532 // TODO(bryeung): update to new-style parameter passing when ArrayBuffer
534 base::DictionaryValue* options;
535 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &options));
537 EXTENSION_FUNCTION_VALIDATE(options->GetString("deviceAddress", &address));
539 BluetoothDevice* device = adapter->GetDevice(address);
541 SetError(kInvalidDevice);
546 if (options->HasKey("data")) {
547 base::DictionaryValue* data_in;
548 EXTENSION_FUNCTION_VALIDATE(options->GetDictionary("data", &data_in));
550 device::BluetoothOutOfBandPairingData data_out;
552 base::BinaryValue* tmp_data;
553 EXTENSION_FUNCTION_VALIDATE(data_in->GetBinary("hash", &tmp_data));
554 EXTENSION_FUNCTION_VALIDATE(
555 tmp_data->GetSize() == device::kBluetoothOutOfBandPairingDataSize);
556 memcpy(data_out.hash,
557 reinterpret_cast<uint8_t*>(tmp_data->GetBuffer()),
558 device::kBluetoothOutOfBandPairingDataSize);
560 EXTENSION_FUNCTION_VALIDATE(data_in->GetBinary("randomizer", &tmp_data));
561 EXTENSION_FUNCTION_VALIDATE(
562 tmp_data->GetSize() == device::kBluetoothOutOfBandPairingDataSize);
563 memcpy(data_out.randomizer,
564 reinterpret_cast<uint8_t*>(tmp_data->GetBuffer()),
565 device::kBluetoothOutOfBandPairingDataSize);
567 device->SetOutOfBandPairingData(
569 base::Bind(&BluetoothSetOutOfBandPairingDataFunction::OnSuccessCallback,
571 base::Bind(&BluetoothSetOutOfBandPairingDataFunction::OnErrorCallback,
574 device->ClearOutOfBandPairingData(
575 base::Bind(&BluetoothSetOutOfBandPairingDataFunction::OnSuccessCallback,
577 base::Bind(&BluetoothSetOutOfBandPairingDataFunction::OnErrorCallback,
584 void BluetoothGetLocalOutOfBandPairingDataFunction::ReadCallback(
585 const device::BluetoothOutOfBandPairingData& data) {
586 base::BinaryValue* hash = base::BinaryValue::CreateWithCopiedBuffer(
587 reinterpret_cast<const char*>(data.hash),
588 device::kBluetoothOutOfBandPairingDataSize);
589 base::BinaryValue* randomizer = base::BinaryValue::CreateWithCopiedBuffer(
590 reinterpret_cast<const char*>(data.randomizer),
591 device::kBluetoothOutOfBandPairingDataSize);
593 // TODO(bryeung): convert to bluetooth::OutOfBandPairingData
594 // when ArrayBuffer support within objects is completed.
595 base::DictionaryValue* result = new base::DictionaryValue();
596 result->Set("hash", hash);
597 result->Set("randomizer", randomizer);
604 void BluetoothGetLocalOutOfBandPairingDataFunction::ErrorCallback() {
605 SetError(kCouldNotGetLocalOutOfBandPairingData);
609 bool BluetoothGetLocalOutOfBandPairingDataFunction::DoWork(
610 scoped_refptr<BluetoothAdapter> adapter) {
611 adapter->ReadLocalOutOfBandPairingData(
612 base::Bind(&BluetoothGetLocalOutOfBandPairingDataFunction::ReadCallback,
614 base::Bind(&BluetoothGetLocalOutOfBandPairingDataFunction::ErrorCallback,
620 void BluetoothStartDiscoveryFunction::OnSuccessCallback() {
624 void BluetoothStartDiscoveryFunction::OnErrorCallback() {
625 SetError(kStartDiscoveryFailed);
626 GetEventRouter(GetProfile())->SetResponsibleForDiscovery(false);
628 GetEventRouter(GetProfile())->OnListenerRemoved();
631 bool BluetoothStartDiscoveryFunction::DoWork(
632 scoped_refptr<BluetoothAdapter> adapter) {
633 GetEventRouter(GetProfile())->SetSendDiscoveryEvents(true);
635 // If this profile is already discovering devices, there should be nothing
637 if (!GetEventRouter(GetProfile())->IsResponsibleForDiscovery()) {
638 GetEventRouter(GetProfile())->SetResponsibleForDiscovery(true);
639 GetEventRouter(GetProfile())->OnListenerAdded();
640 adapter->StartDiscovering(
641 base::Bind(&BluetoothStartDiscoveryFunction::OnSuccessCallback, this),
642 base::Bind(&BluetoothStartDiscoveryFunction::OnErrorCallback, this));
648 void BluetoothStopDiscoveryFunction::OnSuccessCallback() {
650 GetEventRouter(GetProfile())->OnListenerRemoved();
653 void BluetoothStopDiscoveryFunction::OnErrorCallback() {
654 SetError(kStopDiscoveryFailed);
655 GetEventRouter(GetProfile())->SetResponsibleForDiscovery(true);
657 GetEventRouter(GetProfile())->OnListenerRemoved();
660 bool BluetoothStopDiscoveryFunction::DoWork(
661 scoped_refptr<BluetoothAdapter> adapter) {
662 GetEventRouter(GetProfile())->SetSendDiscoveryEvents(false);
663 if (GetEventRouter(GetProfile())->IsResponsibleForDiscovery()) {
664 adapter->StopDiscovering(
665 base::Bind(&BluetoothStopDiscoveryFunction::OnSuccessCallback, this),
666 base::Bind(&BluetoothStopDiscoveryFunction::OnErrorCallback, this));
673 } // namespace extensions