Don't preload rarely seen large images
[chromium-blink-merge.git] / chromeos / dbus / bluetooth_le_advertisement_service_provider.cc
bloba4aca3a8b4835bc0df4e5f7203cd141f655fc925
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 AppendType(dbus::MessageWriter* array_writer) {
262 dbus::MessageWriter dict_entry_writer(NULL);
263 array_writer->OpenDictEntry(&dict_entry_writer);
264 dict_entry_writer.AppendString(bluetooth_advertisement::kTypeProperty);
265 if (type_ == ADVERTISEMENT_TYPE_BROADCAST) {
266 dict_entry_writer.AppendString("broadcast");
267 } else {
268 dict_entry_writer.AppendString("peripheral");
270 array_writer->CloseContainer(&dict_entry_writer);
273 void AppendServiceUUIDs(dbus::MessageWriter* array_writer) {
274 dbus::MessageWriter dict_entry_writer(NULL);
275 array_writer->OpenDictEntry(&dict_entry_writer);
276 dict_entry_writer.AppendString(
277 bluetooth_advertisement::kServiceUUIDsProperty);
278 dict_entry_writer.AppendArrayOfStrings(*service_uuids_);
279 array_writer->CloseContainer(&dict_entry_writer);
282 void AppendManufacturerData(dbus::MessageWriter* array_writer) {
283 dbus::MessageWriter dict_entry_writer(NULL);
284 array_writer->OpenDictEntry(&dict_entry_writer);
285 dict_entry_writer.AppendString(
286 bluetooth_advertisement::kManufacturerDataProperty);
287 dbus::MessageWriter variant_writer(NULL);
288 dict_entry_writer.OpenVariant("a{qay}", &variant_writer);
289 AppendManufacturerDataVariant(&variant_writer);
290 dict_entry_writer.CloseContainer(&variant_writer);
291 array_writer->CloseContainer(&dict_entry_writer);
294 void AppendSolicitUUIDs(dbus::MessageWriter* array_writer) {
295 dbus::MessageWriter dict_entry_writer(NULL);
296 array_writer->OpenDictEntry(&dict_entry_writer);
297 dict_entry_writer.AppendString(
298 bluetooth_advertisement::kSolicitUUIDsProperty);
299 dict_entry_writer.AppendArrayOfStrings(*solicit_uuids_);
300 array_writer->CloseContainer(&dict_entry_writer);
303 void AppendServiceData(dbus::MessageWriter* array_writer) {
304 dbus::MessageWriter dict_entry_writer(NULL);
305 array_writer->OpenDictEntry(&dict_entry_writer);
306 dict_entry_writer.AppendString(
307 bluetooth_advertisement::kServiceDataProperty);
308 dbus::MessageWriter variant_writer(NULL);
309 dict_entry_writer.OpenVariant("a{say}", &variant_writer);
310 AppendServiceDataVariant(&variant_writer);
311 dict_entry_writer.CloseContainer(&variant_writer);
312 array_writer->CloseContainer(&dict_entry_writer);
315 void AppendManufacturerDataVariant(dbus::MessageWriter* writer) {
316 dbus::MessageWriter array_writer(NULL);
317 writer->OpenArray("{qay}", &array_writer);
318 for (const auto& m : *manufacturer_data_) {
319 dbus::MessageWriter entry_writer(NULL);
321 array_writer.OpenDictEntry(&entry_writer);
323 entry_writer.AppendUint32(m.first);
324 entry_writer.AppendArrayOfBytes(vector_as_array(&m.second),
325 m.second.size());
327 array_writer.CloseContainer(&entry_writer);
329 writer->CloseContainer(&array_writer);
332 void AppendServiceDataVariant(dbus::MessageWriter* writer) {
333 dbus::MessageWriter array_writer(NULL);
334 writer->OpenArray("{say}", &array_writer);
335 for (const auto& m : *service_data_) {
336 dbus::MessageWriter entry_writer(NULL);
338 array_writer.OpenDictEntry(&entry_writer);
340 entry_writer.AppendString(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 // Origin thread (i.e. the UI thread in production).
350 base::PlatformThreadId origin_thread_id_;
352 // D-Bus bus object is exported on, not owned by this object and must
353 // outlive it.
354 dbus::Bus* bus_;
356 // All incoming method calls are passed on to the Delegate and a callback
357 // passed to generate the reply. |delegate_| is generally the object that
358 // owns this one, and must outlive it.
359 Delegate* delegate_;
361 // Advertisement data that needs to be provided to BlueZ when requested.
362 AdvertisementType type_;
363 scoped_ptr<UUIDList> service_uuids_;
364 scoped_ptr<ManufacturerData> manufacturer_data_;
365 scoped_ptr<UUIDList> solicit_uuids_;
366 scoped_ptr<ServiceData> service_data_;
368 // D-Bus object we are exporting, owned by this object.
369 scoped_refptr<dbus::ExportedObject> exported_object_;
371 // Weak pointer factory for generating 'this' pointers that might live longer
372 // than we do.
373 // Note: This should remain the last member so it'll be destroyed and
374 // invalidate its weak pointers before any other members are destroyed.
375 base::WeakPtrFactory<BluetoothAdvertisementServiceProviderImpl>
376 weak_ptr_factory_;
378 DISALLOW_COPY_AND_ASSIGN(BluetoothAdvertisementServiceProviderImpl);
381 BluetoothLEAdvertisementServiceProvider::
382 BluetoothLEAdvertisementServiceProvider() {
385 BluetoothLEAdvertisementServiceProvider::
386 ~BluetoothLEAdvertisementServiceProvider() {
389 // static
390 scoped_ptr<BluetoothLEAdvertisementServiceProvider>
391 BluetoothLEAdvertisementServiceProvider::Create(
392 dbus::Bus* bus,
393 const dbus::ObjectPath& object_path,
394 Delegate* delegate,
395 AdvertisementType type,
396 scoped_ptr<UUIDList> service_uuids,
397 scoped_ptr<ManufacturerData> manufacturer_data,
398 scoped_ptr<UUIDList> solicit_uuids,
399 scoped_ptr<ServiceData> service_data) {
400 if (!DBusThreadManager::Get()->IsUsingStub(DBusClientBundle::BLUETOOTH)) {
401 return make_scoped_ptr(new BluetoothAdvertisementServiceProviderImpl(
402 bus, object_path, delegate, type, service_uuids.Pass(),
403 manufacturer_data.Pass(), solicit_uuids.Pass(), service_data.Pass()));
404 } else {
405 return make_scoped_ptr(
406 new FakeBluetoothLEAdvertisementServiceProvider(object_path, delegate));
410 } // namespace chromeos