1 /* Copyright (c) 2013 The Chromium OS 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
6 #include <dbus/dbus.h>
7 #include <errno.h>
8 #include <stdint.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <syslog.h>
12
13 #include "cras_bt_constants.h"
14 #include "cras_bt_manager.h"
15 #include "cras_bt_adapter.h"
16 #include "cras_bt_device.h"
17 #include "cras_bt_endpoint.h"
18 #include "cras_bt_log.h"
19 #include "cras_bt_player.h"
20 #include "cras_bt_profile.h"
21 #include "cras_bt_transport.h"
22 #include "cras_bt_battery_provider.h"
23 #include "utlist.h"
24
25 struct cras_bt_event_log *btlog;
26
cras_bt_interface_added(DBusConnection * conn,const char * object_path,const char * interface_name,DBusMessageIter * properties_array_iter)27 static void cras_bt_interface_added(DBusConnection *conn,
28 const char *object_path,
29 const char *interface_name,
30 DBusMessageIter *properties_array_iter)
31 {
32 if (strcmp(interface_name, BLUEZ_INTERFACE_ADAPTER) == 0) {
33 struct cras_bt_adapter *adapter;
34
35 adapter = cras_bt_adapter_get(object_path);
36 if (adapter) {
37 cras_bt_adapter_update_properties(
38 adapter, properties_array_iter, NULL);
39 } else {
40 BTLOG(btlog, BT_ADAPTER_ADDED, 0, 0);
41 adapter = cras_bt_adapter_create(conn, object_path);
42 if (adapter) {
43 cras_bt_adapter_update_properties(
44 adapter, properties_array_iter, NULL);
45
46 syslog(LOG_INFO, "Bluetooth Adapter: %s added",
47 cras_bt_adapter_address(adapter));
48 } else {
49 syslog(LOG_WARNING,
50 "Failed to create Bluetooth Adapter: %s",
51 object_path);
52 }
53 }
54
55 } else if (strcmp(interface_name, BLUEZ_INTERFACE_MEDIA) == 0) {
56 struct cras_bt_adapter *adapter;
57
58 adapter = cras_bt_adapter_get(object_path);
59 if (adapter) {
60 cras_bt_register_endpoints(conn, adapter);
61 cras_bt_register_player(conn, adapter);
62
63 syslog(LOG_INFO,
64 "Bluetooth Endpoint and/or Player: %s added",
65 cras_bt_adapter_address(adapter));
66 } else {
67 syslog(LOG_WARNING,
68 "Failed to create Bluetooth Endpoint and/or Player: %s",
69 object_path);
70 }
71
72 } else if (strcmp(interface_name, BLUEZ_PROFILE_MGMT_INTERFACE) == 0) {
73 cras_bt_register_profiles(conn);
74
75 syslog(LOG_INFO, "Bluetooth Profile Manager added");
76
77 } else if (strcmp(interface_name, BLUEZ_INTERFACE_DEVICE) == 0) {
78 struct cras_bt_device *device;
79
80 device = cras_bt_device_get(object_path);
81 if (device) {
82 cras_bt_device_update_properties(
83 device, properties_array_iter, NULL);
84 } else {
85 device = cras_bt_device_create(conn, object_path);
86 if (device) {
87 cras_bt_device_update_properties(
88 device, properties_array_iter, NULL);
89
90 syslog(LOG_INFO, "Bluetooth Device: %s added",
91 cras_bt_device_address(device));
92 } else {
93 syslog(LOG_WARNING,
94 "Failed to create Bluetooth Device: %s",
95 object_path);
96 }
97 }
98
99 } else if (strcmp(interface_name, BLUEZ_INTERFACE_MEDIA_TRANSPORT) ==
100 0) {
101 struct cras_bt_transport *transport;
102
103 transport = cras_bt_transport_get(object_path);
104 if (transport) {
105 cras_bt_transport_update_properties(
106 transport, properties_array_iter, NULL);
107 } else {
108 transport = cras_bt_transport_create(conn, object_path);
109 if (transport) {
110 cras_bt_transport_update_properties(
111 transport, properties_array_iter, NULL);
112
113 syslog(LOG_INFO,
114 "Bluetooth Transport: %s added",
115 cras_bt_transport_object_path(
116 transport));
117 } else {
118 syslog(LOG_WARNING,
119 "Failed to create Bluetooth Transport: "
120 "%s",
121 object_path);
122 }
123 }
124 } else if (strcmp(interface_name,
125 BLUEZ_INTERFACE_BATTERY_PROVIDER_MANAGER) == 0) {
126 struct cras_bt_adapter *adapter;
127 int ret;
128
129 syslog(LOG_INFO,
130 "Bluetooth Battery Provider Manager available");
131
132 adapter = cras_bt_adapter_get(object_path);
133 if (adapter) {
134 syslog(LOG_INFO,
135 "Registering Battery Provider for adapter %s",
136 cras_bt_adapter_address(adapter));
137 ret = cras_bt_register_battery_provider(conn, adapter);
138 if (ret != 0) {
139 syslog(LOG_ERR,
140 "Error registering Battery Provider "
141 "for adapter %s: %s",
142 cras_bt_adapter_address(adapter),
143 strerror(-ret));
144 }
145 } else {
146 syslog(LOG_WARNING,
147 "Adapter not available when trying to create "
148 "Battery Provider");
149 }
150 }
151 }
152
cras_bt_interface_removed(DBusConnection * conn,const char * object_path,const char * interface_name)153 static void cras_bt_interface_removed(DBusConnection *conn,
154 const char *object_path,
155 const char *interface_name)
156 {
157 if (strcmp(interface_name, BLUEZ_INTERFACE_ADAPTER) == 0) {
158 struct cras_bt_adapter *adapter;
159
160 BTLOG(btlog, BT_ADAPTER_REMOVED, 0, 0);
161 adapter = cras_bt_adapter_get(object_path);
162 if (adapter) {
163 syslog(LOG_INFO, "Bluetooth Adapter: %s removed",
164 cras_bt_adapter_address(adapter));
165 cras_bt_adapter_destroy(adapter);
166 }
167
168 } else if (strcmp(interface_name, BLUEZ_INTERFACE_DEVICE) == 0) {
169 struct cras_bt_device *device;
170
171 device = cras_bt_device_get(object_path);
172 if (device) {
173 syslog(LOG_INFO, "Bluetooth Device: %s removed",
174 cras_bt_device_address(device));
175 cras_bt_device_remove(device);
176 }
177
178 } else if (strcmp(interface_name, BLUEZ_INTERFACE_MEDIA_TRANSPORT) ==
179 0) {
180 struct cras_bt_transport *transport;
181
182 transport = cras_bt_transport_get(object_path);
183 if (transport) {
184 syslog(LOG_INFO, "Bluetooth Transport: %s removed",
185 cras_bt_transport_object_path(transport));
186 cras_bt_transport_remove(transport);
187 }
188 } else if (strcmp(interface_name,
189 BLUEZ_INTERFACE_BATTERY_PROVIDER_MANAGER) == 0) {
190 syslog(LOG_INFO, "Bluetooth Battery Provider Manager removed");
191 cras_bt_battery_provider_reset();
192 }
193 }
194
cras_bt_update_properties(DBusConnection * conn,const char * object_path,const char * interface_name,DBusMessageIter * properties_array_iter,DBusMessageIter * invalidated_array_iter)195 static void cras_bt_update_properties(DBusConnection *conn,
196 const char *object_path,
197 const char *interface_name,
198 DBusMessageIter *properties_array_iter,
199 DBusMessageIter *invalidated_array_iter)
200 {
201 if (strcmp(interface_name, BLUEZ_INTERFACE_ADAPTER) == 0) {
202 struct cras_bt_adapter *adapter;
203
204 adapter = cras_bt_adapter_get(object_path);
205 if (adapter) {
206 cras_bt_adapter_update_properties(
207 adapter, properties_array_iter,
208 invalidated_array_iter);
209 }
210
211 } else if (strcmp(interface_name, BLUEZ_INTERFACE_DEVICE) == 0) {
212 struct cras_bt_device *device;
213
214 device = cras_bt_device_get(object_path);
215 if (device) {
216 cras_bt_device_update_properties(
217 device, properties_array_iter,
218 invalidated_array_iter);
219 }
220
221 } else if (strcmp(interface_name, BLUEZ_INTERFACE_MEDIA_TRANSPORT) ==
222 0) {
223 struct cras_bt_transport *transport;
224
225 transport = cras_bt_transport_get(object_path);
226 if (transport) {
227 cras_bt_transport_update_properties(
228 transport, properties_array_iter,
229 invalidated_array_iter);
230 }
231 }
232 }
233
234 /* Destroys all bt related stuff. The reset functions must be called in
235 * reverse order of the adapter -> device -> profile(s) hierarchy.
236 */
cras_bt_reset()237 static void cras_bt_reset()
238 {
239 BTLOG(btlog, BT_RESET, 0, 0);
240 cras_bt_endpoint_reset();
241 cras_bt_transport_reset();
242 cras_bt_profile_reset();
243 cras_bt_device_reset();
244 cras_bt_adapter_reset();
245 }
246
cras_bt_on_get_managed_objects(DBusPendingCall * pending_call,void * data)247 static void cras_bt_on_get_managed_objects(DBusPendingCall *pending_call,
248 void *data)
249 {
250 DBusConnection *conn = (DBusConnection *)data;
251 DBusMessage *reply;
252 DBusMessageIter message_iter, object_array_iter;
253
254 reply = dbus_pending_call_steal_reply(pending_call);
255 dbus_pending_call_unref(pending_call);
256
257 if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
258 syslog(LOG_WARNING, "GetManagedObjects returned error: %s",
259 dbus_message_get_error_name(reply));
260 dbus_message_unref(reply);
261 return;
262 }
263
264 if (!dbus_message_has_signature(reply, "a{oa{sa{sv}}}")) {
265 syslog(LOG_WARNING, "Bad GetManagedObjects reply received");
266 dbus_message_unref(reply);
267 return;
268 }
269
270 dbus_message_iter_init(reply, &message_iter);
271 dbus_message_iter_recurse(&message_iter, &object_array_iter);
272
273 while (dbus_message_iter_get_arg_type(&object_array_iter) !=
274 DBUS_TYPE_INVALID) {
275 DBusMessageIter object_dict_iter, interface_array_iter;
276 const char *object_path;
277
278 dbus_message_iter_recurse(&object_array_iter,
279 &object_dict_iter);
280
281 dbus_message_iter_get_basic(&object_dict_iter, &object_path);
282 dbus_message_iter_next(&object_dict_iter);
283
284 dbus_message_iter_recurse(&object_dict_iter,
285 &interface_array_iter);
286
287 while (dbus_message_iter_get_arg_type(&interface_array_iter) !=
288 DBUS_TYPE_INVALID) {
289 DBusMessageIter interface_dict_iter;
290 DBusMessageIter properties_array_iter;
291 const char *interface_name;
292
293 dbus_message_iter_recurse(&interface_array_iter,
294 &interface_dict_iter);
295
296 dbus_message_iter_get_basic(&interface_dict_iter,
297 &interface_name);
298 dbus_message_iter_next(&interface_dict_iter);
299
300 dbus_message_iter_recurse(&interface_dict_iter,
301 &properties_array_iter);
302
303 cras_bt_interface_added(conn, object_path,
304 interface_name,
305 &properties_array_iter);
306
307 dbus_message_iter_next(&interface_array_iter);
308 }
309
310 dbus_message_iter_next(&object_array_iter);
311 }
312
313 dbus_message_unref(reply);
314 }
315
cras_bt_get_managed_objects(DBusConnection * conn)316 static int cras_bt_get_managed_objects(DBusConnection *conn)
317 {
318 DBusMessage *method_call;
319 DBusPendingCall *pending_call;
320
321 method_call =
322 dbus_message_new_method_call(BLUEZ_SERVICE, "/",
323 DBUS_INTERFACE_OBJECT_MANAGER,
324 "GetManagedObjects");
325 if (!method_call)
326 return -ENOMEM;
327
328 pending_call = NULL;
329 if (!dbus_connection_send_with_reply(conn, method_call, &pending_call,
330 DBUS_TIMEOUT_USE_DEFAULT)) {
331 dbus_message_unref(method_call);
332 return -ENOMEM;
333 }
334
335 dbus_message_unref(method_call);
336 if (!pending_call)
337 return -EIO;
338
339 if (!dbus_pending_call_set_notify(
340 pending_call, cras_bt_on_get_managed_objects, conn, NULL)) {
341 dbus_pending_call_cancel(pending_call);
342 dbus_pending_call_unref(pending_call);
343 return -ENOMEM;
344 }
345
346 return 0;
347 }
348
cras_bt_handle_name_owner_changed(DBusConnection * conn,DBusMessage * message,void * arg)349 static DBusHandlerResult cras_bt_handle_name_owner_changed(DBusConnection *conn,
350 DBusMessage *message,
351 void *arg)
352 {
353 DBusError dbus_error;
354 const char *service_name, *old_owner, *new_owner;
355
356 if (!dbus_message_is_signal(message, DBUS_INTERFACE_DBUS,
357 "NameOwnerChanged"))
358 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
359
360 dbus_error_init(&dbus_error);
361 if (!dbus_message_get_args(message, &dbus_error, DBUS_TYPE_STRING,
362 &service_name, DBUS_TYPE_STRING, &old_owner,
363 DBUS_TYPE_STRING, &new_owner,
364 DBUS_TYPE_INVALID)) {
365 syslog(LOG_WARNING, "Bad NameOwnerChanged signal received: %s",
366 dbus_error.message);
367 dbus_error_free(&dbus_error);
368 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
369 }
370
371 syslog(LOG_INFO, "Bluetooth daemon disconnected from the bus.");
372 cras_bt_reset();
373
374 if (strlen(new_owner) > 0)
375 cras_bt_get_managed_objects(conn);
376
377 return DBUS_HANDLER_RESULT_HANDLED;
378 }
379
cras_bt_handle_interfaces_added(DBusConnection * conn,DBusMessage * message,void * arg)380 static DBusHandlerResult cras_bt_handle_interfaces_added(DBusConnection *conn,
381 DBusMessage *message,
382 void *arg)
383 {
384 DBusMessageIter message_iter, interface_array_iter;
385 const char *object_path;
386
387 if (!dbus_message_is_signal(message, DBUS_INTERFACE_OBJECT_MANAGER,
388 "InterfacesAdded"))
389 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
390
391 if (!dbus_message_has_signature(message, "oa{sa{sv}}")) {
392 syslog(LOG_WARNING, "Bad InterfacesAdded signal received");
393 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
394 }
395
396 dbus_message_iter_init(message, &message_iter);
397
398 dbus_message_iter_get_basic(&message_iter, &object_path);
399 dbus_message_iter_next(&message_iter);
400
401 dbus_message_iter_recurse(&message_iter, &interface_array_iter);
402
403 while (dbus_message_iter_get_arg_type(&interface_array_iter) !=
404 DBUS_TYPE_INVALID) {
405 DBusMessageIter interface_dict_iter, properties_array_iter;
406 const char *interface_name;
407
408 dbus_message_iter_recurse(&interface_array_iter,
409 &interface_dict_iter);
410
411 dbus_message_iter_get_basic(&interface_dict_iter,
412 &interface_name);
413 dbus_message_iter_next(&interface_dict_iter);
414
415 dbus_message_iter_recurse(&interface_dict_iter,
416 &properties_array_iter);
417
418 cras_bt_interface_added(conn, object_path, interface_name,
419 &properties_array_iter);
420
421 dbus_message_iter_next(&interface_array_iter);
422 }
423
424 return DBUS_HANDLER_RESULT_HANDLED;
425 }
426
cras_bt_handle_interfaces_removed(DBusConnection * conn,DBusMessage * message,void * arg)427 static DBusHandlerResult cras_bt_handle_interfaces_removed(DBusConnection *conn,
428 DBusMessage *message,
429 void *arg)
430 {
431 DBusMessageIter message_iter, interface_array_iter;
432 const char *object_path;
433
434 if (!dbus_message_is_signal(message, DBUS_INTERFACE_OBJECT_MANAGER,
435 "InterfacesRemoved"))
436 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
437
438 if (!dbus_message_has_signature(message, "oas")) {
439 syslog(LOG_WARNING, "Bad InterfacesRemoved signal received");
440 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
441 }
442
443 dbus_message_iter_init(message, &message_iter);
444
445 dbus_message_iter_get_basic(&message_iter, &object_path);
446 dbus_message_iter_next(&message_iter);
447
448 dbus_message_iter_recurse(&message_iter, &interface_array_iter);
449
450 while (dbus_message_iter_get_arg_type(&interface_array_iter) !=
451 DBUS_TYPE_INVALID) {
452 const char *interface_name;
453
454 dbus_message_iter_get_basic(&interface_array_iter,
455 &interface_name);
456
457 cras_bt_interface_removed(conn, object_path, interface_name);
458
459 dbus_message_iter_next(&interface_array_iter);
460 }
461
462 return DBUS_HANDLER_RESULT_HANDLED;
463 }
464
cras_bt_handle_properties_changed(DBusConnection * conn,DBusMessage * message,void * arg)465 static DBusHandlerResult cras_bt_handle_properties_changed(DBusConnection *conn,
466 DBusMessage *message,
467 void *arg)
468 {
469 DBusMessageIter message_iter, properties_array_iter;
470 DBusMessageIter invalidated_array_iter;
471 const char *object_path, *interface_name;
472
473 if (!dbus_message_is_signal(message, DBUS_INTERFACE_PROPERTIES,
474 "PropertiesChanged"))
475 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
476
477 if (!dbus_message_has_signature(message, "sa{sv}as")) {
478 syslog(LOG_WARNING, "Bad PropertiesChanged signal received");
479 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
480 }
481
482 object_path = dbus_message_get_path(message);
483
484 dbus_message_iter_init(message, &message_iter);
485
486 dbus_message_iter_get_basic(&message_iter, &interface_name);
487 dbus_message_iter_next(&message_iter);
488
489 dbus_message_iter_recurse(&message_iter, &properties_array_iter);
490 dbus_message_iter_next(&message_iter);
491
492 dbus_message_iter_recurse(&message_iter, &invalidated_array_iter);
493
494 cras_bt_update_properties(conn, object_path, interface_name,
495 &properties_array_iter,
496 &invalidated_array_iter);
497
498 return DBUS_HANDLER_RESULT_HANDLED;
499 }
500
cras_bt_start(DBusConnection * conn)501 void cras_bt_start(DBusConnection *conn)
502 {
503 DBusError dbus_error;
504
505 btlog = cras_bt_event_log_init();
506
507 dbus_error_init(&dbus_error);
508
509 /* Inform the bus daemon which signals we wish to receive. */
510 dbus_bus_add_match(conn,
511 "type='signal',"
512 "sender='" DBUS_SERVICE_DBUS "',"
513 "interface='" DBUS_INTERFACE_DBUS "',"
514 "member='NameOwnerChanged',"
515 "arg0='" BLUEZ_SERVICE "'",
516 &dbus_error);
517 if (dbus_error_is_set(&dbus_error))
518 goto add_match_error;
519
520 dbus_bus_add_match(conn,
521 "type='signal',"
522 "sender='" BLUEZ_SERVICE "',"
523 "interface='" DBUS_INTERFACE_OBJECT_MANAGER "',"
524 "member='InterfacesAdded'",
525 &dbus_error);
526 if (dbus_error_is_set(&dbus_error))
527 goto add_match_error;
528
529 dbus_bus_add_match(conn,
530 "type='signal',"
531 "sender='" BLUEZ_SERVICE "',"
532 "interface='" DBUS_INTERFACE_OBJECT_MANAGER "',"
533 "member='InterfacesRemoved'",
534 &dbus_error);
535 if (dbus_error_is_set(&dbus_error))
536 goto add_match_error;
537
538 dbus_bus_add_match(conn,
539 "type='signal',"
540 "sender='" BLUEZ_SERVICE "',"
541 "interface='" DBUS_INTERFACE_PROPERTIES "',"
542 "member='PropertiesChanged'",
543 &dbus_error);
544 if (dbus_error_is_set(&dbus_error))
545 goto add_match_error;
546
547 /* Install filter functions to handle the signals we receive. */
548 if (!dbus_connection_add_filter(conn, cras_bt_handle_name_owner_changed,
549 NULL, NULL))
550 goto add_filter_error;
551
552 if (!dbus_connection_add_filter(conn, cras_bt_handle_interfaces_added,
553 NULL, NULL))
554 goto add_filter_error;
555
556 if (!dbus_connection_add_filter(conn, cras_bt_handle_interfaces_removed,
557 NULL, NULL))
558 goto add_filter_error;
559
560 if (!dbus_connection_add_filter(conn, cras_bt_handle_properties_changed,
561 NULL, NULL))
562 goto add_filter_error;
563
564 cras_bt_get_managed_objects(conn);
565 return;
566
567 add_match_error:
568 syslog(LOG_WARNING, "Couldn't setup Bluetooth device monitoring: %s",
569 dbus_error.message);
570 dbus_error_free(&dbus_error);
571 cras_bt_stop(conn);
572 return;
573
574 add_filter_error:
575 syslog(LOG_WARNING, "Couldn't setup Bluetooth device monitoring: %s",
576 strerror(ENOMEM));
577 cras_bt_stop(conn);
578 return;
579 }
580
cras_bt_stop(DBusConnection * conn)581 void cras_bt_stop(DBusConnection *conn)
582 {
583 cras_bt_reset();
584
585 dbus_bus_remove_match(conn,
586 "type='signal',"
587 "sender='" DBUS_SERVICE_DBUS "',"
588 "interface='" DBUS_INTERFACE_DBUS "',"
589 "member='NameOwnerChanged',"
590 "arg0='" BLUEZ_SERVICE "'",
591 NULL);
592 dbus_bus_remove_match(conn,
593 "type='signal',"
594 "sender='" BLUEZ_SERVICE "',"
595 "interface='" DBUS_INTERFACE_OBJECT_MANAGER "',"
596 "member='InterfacesAdded'",
597 NULL);
598 dbus_bus_remove_match(conn,
599 "type='signal',"
600 "sender='" BLUEZ_SERVICE "',"
601 "interface='" DBUS_INTERFACE_OBJECT_MANAGER "',"
602 "member='InterfacesRemoved'",
603 NULL);
604 dbus_bus_remove_match(conn,
605 "type='signal',"
606 "sender='" BLUEZ_SERVICE "',"
607 "interface='" DBUS_INTERFACE_PROPERTIES "',"
608 "member='PropertiesChanged'",
609 NULL);
610
611 dbus_connection_remove_filter(conn, cras_bt_handle_name_owner_changed,
612 NULL);
613 dbus_connection_remove_filter(conn, cras_bt_handle_interfaces_added,
614 NULL);
615 dbus_connection_remove_filter(conn, cras_bt_handle_interfaces_removed,
616 NULL);
617 dbus_connection_remove_filter(conn, cras_bt_handle_properties_changed,
618 NULL);
619 }
620