Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chromeos / dbus / bluetooth_le_advertisement_service_provider.cc
blobe598322932e710330e36c161c0814b03a1b11642
1 // Copyright 2015 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 "chromeos/dbus/bluetooth_le_advertisement_service_provider.h"
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/memory/ref_counted.h"
10 #include "base/stl_util.h"
11 #include "base/threading/platform_thread.h"
12 #include "chromeos/dbus/dbus_thread_manager.h"
13 #include "chromeos/dbus/fake_bluetooth_le_advertisement_service_provider.h"
14 #include "dbus/exported_object.h"
15 #include "dbus/message.h"
16 #include "third_party/cros_system_api/dbus/service_constants.h"
18 namespace chromeos {
20 namespace {
21 const char kErrorInvalidArgs[] = "org.freedesktop.DBus.Error.InvalidArgs";
22 } // namespace
24 // The BluetoothAdvertisementServiceProvider implementation used in production.
25 class BluetoothAdvertisementServiceProviderImpl
26 : public BluetoothLEAdvertisementServiceProvider {
27 public:
28 BluetoothAdvertisementServiceProviderImpl(
29 dbus::Bus* bus,
30 const dbus::ObjectPath& object_path,
31 Delegate* delegate,
32 AdvertisementType type,
33 scoped_ptr<UUIDList> service_uuids,
34 scoped_ptr<ManufacturerData> manufacturer_data,
35 scoped_ptr<UUIDList> solicit_uuids,
36 scoped_ptr<ServiceData> service_data)
37 : origin_thread_id_(base::PlatformThread::CurrentId()),
38 bus_(bus),
39 delegate_(delegate),
40 type_(type),
41 service_uuids_(service_uuids.Pass()),
42 manufacturer_data_(manufacturer_data.Pass()),
43 solicit_uuids_(solicit_uuids.Pass()),
44 service_data_(service_data.Pass()),
45 weak_ptr_factory_(this) {
46 DCHECK(bus);
47 DCHECK(delegate);
49 VLOG(1) << "Creating Bluetooth Advertisement: " << object_path_.value();
51 object_path_ = object_path;
52 exported_object_ = bus_->GetExportedObject(object_path_);
54 // Export Bluetooth Advertisement interface methods.
55 exported_object_->ExportMethod(
56 bluetooth_advertisement::kBluetoothAdvertisementInterface,
57 bluetooth_advertisement::kRelease,
58 base::Bind(&BluetoothAdvertisementServiceProviderImpl::Release,
59 weak_ptr_factory_.GetWeakPtr()),
60 base::Bind(&BluetoothAdvertisementServiceProviderImpl::OnExported,
61 weak_ptr_factory_.GetWeakPtr()));
63 // Export dbus property methods.
64 exported_object_->ExportMethod(
65 dbus::kDBusPropertiesInterface, dbus::kDBusPropertiesGet,
66 base::Bind(&BluetoothAdvertisementServiceProviderImpl::Get,
67 weak_ptr_factory_.GetWeakPtr()),
68 base::Bind(&BluetoothAdvertisementServiceProviderImpl::OnExported,
69 weak_ptr_factory_.GetWeakPtr()));
71 exported_object_->ExportMethod(
72 dbus::kDBusPropertiesInterface, dbus::kDBusPropertiesGetAll,
73 base::Bind(&BluetoothAdvertisementServiceProviderImpl::GetAll,
74 weak_ptr_factory_.GetWeakPtr()),
75 base::Bind(&BluetoothAdvertisementServiceProviderImpl::OnExported,
76 weak_ptr_factory_.GetWeakPtr()));
79 ~BluetoothAdvertisementServiceProviderImpl() override {
80 VLOG(1) << "Cleaning up Bluetooth Advertisement: " << object_path_.value();
82 // Unregister the object path so we can reuse with a new agent.
83 bus_->UnregisterExportedObject(object_path_);
86 private:
87 // Returns true if the current thread is on the origin thread.
88 bool OnOriginThread() {
89 return base::PlatformThread::CurrentId() == origin_thread_id_;
92 // Called by dbus:: when this advertisement is unregistered from the Bluetooth
93 // daemon, generally by our request.
94 void Release(dbus::MethodCall* method_call,
95 dbus::ExportedObject::ResponseSender response_sender) {
96 DCHECK(OnOriginThread());
97 DCHECK(delegate_);
99 delegate_->Released();
102 // Called by dbus:: when the Bluetooth daemon fetches a single property of
103 // the descriptor.
104 void Get(dbus::MethodCall* method_call,
105 dbus::ExportedObject::ResponseSender response_sender) {
106 VLOG(2) << "BluetoothAdvertisementServiceProvider::Get: "
107 << object_path_.value();
108 DCHECK(OnOriginThread());
110 dbus::MessageReader reader(method_call);
112 std::string interface_name;
113 std::string property_name;
114 if (!reader.PopString(&interface_name) ||
115 !reader.PopString(&property_name) || reader.HasMoreData()) {
116 scoped_ptr<dbus::ErrorResponse> error_response =
117 dbus::ErrorResponse::FromMethodCall(method_call, kErrorInvalidArgs,
118 "Expected 'ss'.");
119 response_sender.Run(error_response.Pass());
120 return;
123 // Only the advertisement interface is supported.
124 if (interface_name !=
125 bluetooth_advertisement::kBluetoothAdvertisementInterface) {
126 scoped_ptr<dbus::ErrorResponse> error_response =
127 dbus::ErrorResponse::FromMethodCall(
128 method_call, kErrorInvalidArgs,
129 "No such interface: '" + interface_name + "'.");
130 response_sender.Run(error_response.Pass());
131 return;
134 scoped_ptr<dbus::Response> response =
135 dbus::Response::FromMethodCall(method_call);
136 dbus::MessageWriter writer(response.get());
137 dbus::MessageWriter variant_writer(NULL);
139 if (property_name == bluetooth_advertisement::kTypeProperty) {
140 writer.OpenVariant("s", &variant_writer);
141 if (type_ == ADVERTISEMENT_TYPE_BROADCAST) {
142 variant_writer.AppendString("broadcast");
143 } else {
144 variant_writer.AppendString("peripheral");
146 } else if ((property_name ==
147 bluetooth_advertisement::kServiceUUIDsProperty) &&
148 service_uuids_) {
149 writer.OpenVariant("as", &variant_writer);
150 variant_writer.AppendArrayOfStrings(*service_uuids_);
151 } else if ((property_name ==
152 bluetooth_advertisement::kSolicitUUIDsProperty) &&
153 solicit_uuids_) {
154 writer.OpenVariant("as", &variant_writer);
155 variant_writer.AppendArrayOfStrings(*solicit_uuids_);
156 } else if ((property_name ==
157 bluetooth_advertisement::kManufacturerDataProperty) &&
158 manufacturer_data_) {
159 writer.OpenVariant("o", &variant_writer);
160 AppendManufacturerDataVariant(&variant_writer);
161 } else if ((property_name ==
162 bluetooth_advertisement::kServiceDataProperty) &&
163 service_data_) {
164 writer.OpenVariant("o", &variant_writer);
165 AppendServiceDataVariant(&variant_writer);
166 } else {
167 scoped_ptr<dbus::ErrorResponse> error_response =
168 dbus::ErrorResponse::FromMethodCall(
169 method_call, kErrorInvalidArgs,
170 "No such property: '" + property_name + "'.");
171 response_sender.Run(error_response.Pass());
174 writer.CloseContainer(&variant_writer);
175 response_sender.Run(response.Pass());
178 // Called by dbus:: when the Bluetooth daemon fetches all properties of the
179 // descriptor.
180 void GetAll(dbus::MethodCall* method_call,
181 dbus::ExportedObject::ResponseSender response_sender) {
182 VLOG(2) << "BluetoothAdvertisementServiceProvider::GetAll: "
183 << object_path_.value();
184 DCHECK(OnOriginThread());
186 dbus::MessageReader reader(method_call);
188 std::string interface_name;
189 if (!reader.PopString(&interface_name) || reader.HasMoreData()) {
190 scoped_ptr<dbus::ErrorResponse> error_response =
191 dbus::ErrorResponse::FromMethodCall(method_call, kErrorInvalidArgs,
192 "Expected 's'.");
193 response_sender.Run(error_response.Pass());
194 return;
197 // Only the advertisement interface is supported.
198 if (interface_name !=
199 bluetooth_advertisement::kBluetoothAdvertisementInterface) {
200 scoped_ptr<dbus::ErrorResponse> error_response =
201 dbus::ErrorResponse::FromMethodCall(
202 method_call, kErrorInvalidArgs,
203 "No such interface: '" + interface_name + "'.");
204 response_sender.Run(error_response.Pass());
205 return;
208 response_sender.Run(CreateGetAllResponse(method_call).Pass());
211 // Called by dbus:: when a method is exported.
212 void OnExported(const std::string& interface_name,
213 const std::string& method_name,
214 bool success) {
215 LOG_IF(WARNING, !success) << "Failed to export " << interface_name << "."
216 << method_name;
219 // Helper for populating the DBus response with the advertisement data.
220 scoped_ptr<dbus::Response> CreateGetAllResponse(
221 dbus::MethodCall* method_call) {
222 VLOG(2) << "Descriptor value obtained from delegate. Responding to "
223 << "GetAll.";
225 scoped_ptr<dbus::Response> response =
226 dbus::Response::FromMethodCall(method_call);
228 dbus::MessageWriter writer(response.get());
229 dbus::MessageWriter array_writer(NULL);
231 writer.OpenArray("{sv}", &array_writer);
233 AppendType(&array_writer);
234 AppendServiceUUIDs(&array_writer);
235 AppendManufacturerData(&array_writer);
236 AppendSolicitUUIDs(&array_writer);
237 AppendServiceData(&array_writer);
239 writer.CloseContainer(&array_writer);
240 return response;
243 // Called by the Delegate in response to a successful method call to get the
244 // descriptor value.
245 void OnGet(dbus::MethodCall* method_call,
246 dbus::ExportedObject::ResponseSender response_sender,
247 const std::vector<uint8>& value) {
248 VLOG(2) << "Returning descriptor value obtained from delegate.";
249 scoped_ptr<dbus::Response> response =
250 dbus::Response::FromMethodCall(method_call);
251 dbus::MessageWriter writer(response.get());
252 dbus::MessageWriter variant_writer(NULL);
254 writer.OpenVariant("ay", &variant_writer);
255 variant_writer.AppendArrayOfBytes(value.data(), value.size());
256 writer.CloseContainer(&variant_writer);
258 response_sender.Run(response.Pass());
261 void AppendArrayVariantOfStrings(dbus::MessageWriter* dict_writer,
262 const UUIDList& strings) {
263 dbus::MessageWriter strings_array_variant(nullptr);
264 dict_writer->OpenVariant("as", &strings_array_variant);
265 strings_array_variant.AppendArrayOfStrings(strings);
266 dict_writer->CloseContainer(&strings_array_variant);
269 void AppendType(dbus::MessageWriter* array_writer) {
270 dbus::MessageWriter dict_entry_writer(NULL);
271 array_writer->OpenDictEntry(&dict_entry_writer);
272 dict_entry_writer.AppendString(bluetooth_advertisement::kTypeProperty);
273 if (type_ == ADVERTISEMENT_TYPE_BROADCAST) {
274 dict_entry_writer.AppendVariantOfString("broadcast");
275 } else {
276 dict_entry_writer.AppendVariantOfString("peripheral");
278 array_writer->CloseContainer(&dict_entry_writer);
281 void AppendServiceUUIDs(dbus::MessageWriter* array_writer) {
282 if (!service_uuids_)
283 return;
284 dbus::MessageWriter dict_entry_writer(NULL);
285 array_writer->OpenDictEntry(&dict_entry_writer);
286 dict_entry_writer.AppendString(
287 bluetooth_advertisement::kServiceUUIDsProperty);
288 AppendArrayVariantOfStrings(&dict_entry_writer, *service_uuids_);
289 array_writer->CloseContainer(&dict_entry_writer);
292 void AppendManufacturerData(dbus::MessageWriter* array_writer) {
293 if (!manufacturer_data_)
294 return;
295 dbus::MessageWriter dict_entry_writer(NULL);
296 array_writer->OpenDictEntry(&dict_entry_writer);
297 dict_entry_writer.AppendString(
298 bluetooth_advertisement::kManufacturerDataProperty);
299 dbus::MessageWriter variant_writer(NULL);
300 dict_entry_writer.OpenVariant("a{qay}", &variant_writer);
301 AppendManufacturerDataVariant(&variant_writer);
302 dict_entry_writer.CloseContainer(&variant_writer);
303 array_writer->CloseContainer(&dict_entry_writer);
306 void AppendSolicitUUIDs(dbus::MessageWriter* array_writer) {
307 if (!solicit_uuids_)
308 return;
309 dbus::MessageWriter dict_entry_writer(NULL);
310 array_writer->OpenDictEntry(&dict_entry_writer);
311 dict_entry_writer.AppendString(
312 bluetooth_advertisement::kSolicitUUIDsProperty);
313 AppendArrayVariantOfStrings(&dict_entry_writer, *solicit_uuids_);
314 array_writer->CloseContainer(&dict_entry_writer);
317 void AppendServiceData(dbus::MessageWriter* array_writer) {
318 if (!service_data_)
319 return;
320 dbus::MessageWriter dict_entry_writer(NULL);
321 array_writer->OpenDictEntry(&dict_entry_writer);
322 dict_entry_writer.AppendString(
323 bluetooth_advertisement::kServiceDataProperty);
324 dbus::MessageWriter variant_writer(NULL);
325 dict_entry_writer.OpenVariant("a{say}", &variant_writer);
326 AppendServiceDataVariant(&variant_writer);
327 dict_entry_writer.CloseContainer(&variant_writer);
328 array_writer->CloseContainer(&dict_entry_writer);
331 void AppendManufacturerDataVariant(dbus::MessageWriter* writer) {
332 DCHECK(manufacturer_data_);
333 dbus::MessageWriter array_writer(NULL);
334 writer->OpenArray("{qay}", &array_writer);
335 for (const auto& m : *manufacturer_data_) {
336 dbus::MessageWriter entry_writer(NULL);
338 array_writer.OpenDictEntry(&entry_writer);
340 entry_writer.AppendUint32(m.first);
341 entry_writer.AppendArrayOfBytes(vector_as_array(&m.second),
342 m.second.size());
344 array_writer.CloseContainer(&entry_writer);
346 writer->CloseContainer(&array_writer);
349 void AppendServiceDataVariant(dbus::MessageWriter* writer) {
350 DCHECK(service_data_);
351 dbus::MessageWriter array_writer(NULL);
352 writer->OpenArray("{say}", &array_writer);
353 for (const auto& m : *service_data_) {
354 dbus::MessageWriter entry_writer(NULL);
356 array_writer.OpenDictEntry(&entry_writer);
358 entry_writer.AppendString(m.first);
359 entry_writer.AppendArrayOfBytes(vector_as_array(&m.second),
360 m.second.size());
362 array_writer.CloseContainer(&entry_writer);
364 writer->CloseContainer(&array_writer);
367 // Origin thread (i.e. the UI thread in production).
368 base::PlatformThreadId origin_thread_id_;
370 // D-Bus bus object is exported on, not owned by this object and must
371 // outlive it.
372 dbus::Bus* bus_;
374 // All incoming method calls are passed on to the Delegate and a callback
375 // passed to generate the reply. |delegate_| is generally the object that
376 // owns this one, and must outlive it.
377 Delegate* delegate_;
379 // Advertisement data that needs to be provided to BlueZ when requested.
380 AdvertisementType type_;
381 scoped_ptr<UUIDList> service_uuids_;
382 scoped_ptr<ManufacturerData> manufacturer_data_;
383 scoped_ptr<UUIDList> solicit_uuids_;
384 scoped_ptr<ServiceData> service_data_;
386 // D-Bus object we are exporting, owned by this object.
387 scoped_refptr<dbus::ExportedObject> exported_object_;
389 // Weak pointer factory for generating 'this' pointers that might live longer
390 // than we do.
391 // Note: This should remain the last member so it'll be destroyed and
392 // invalidate its weak pointers before any other members are destroyed.
393 base::WeakPtrFactory<BluetoothAdvertisementServiceProviderImpl>
394 weak_ptr_factory_;
396 DISALLOW_COPY_AND_ASSIGN(BluetoothAdvertisementServiceProviderImpl);
399 BluetoothLEAdvertisementServiceProvider::
400 BluetoothLEAdvertisementServiceProvider() {
403 BluetoothLEAdvertisementServiceProvider::
404 ~BluetoothLEAdvertisementServiceProvider() {
407 // static
408 scoped_ptr<BluetoothLEAdvertisementServiceProvider>
409 BluetoothLEAdvertisementServiceProvider::Create(
410 dbus::Bus* bus,
411 const dbus::ObjectPath& object_path,
412 Delegate* delegate,
413 AdvertisementType type,
414 scoped_ptr<UUIDList> service_uuids,
415 scoped_ptr<ManufacturerData> manufacturer_data,
416 scoped_ptr<UUIDList> solicit_uuids,
417 scoped_ptr<ServiceData> service_data) {
418 if (!DBusThreadManager::Get()->IsUsingStub(DBusClientBundle::BLUETOOTH)) {
419 return make_scoped_ptr(new BluetoothAdvertisementServiceProviderImpl(
420 bus, object_path, delegate, type, service_uuids.Pass(),
421 manufacturer_data.Pass(), solicit_uuids.Pass(), service_data.Pass()));
422 } else {
423 return make_scoped_ptr(
424 new FakeBluetoothLEAdvertisementServiceProvider(object_path, delegate));
428 } // namespace chromeos