4 * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
24 #include <vconf-keys.h>
26 #include <dbus/dbus-glib.h>
27 #include <dbus/dbus.h>
31 #include "bt-internal-types.h"
33 static GMainLoop *main_loop = NULL;
34 static DBusGConnection *conn = NULL;
36 #ifdef __TIZEN_MOBILE__
44 static bt_status_t adapter_status = BT_DEACTIVATED;
46 static void __bt_core_set_status(bt_status_t status)
48 adapter_status = status;
51 static bt_status_t __bt_core_get_status(void)
53 return adapter_status;
57 static void __bt_core_terminate(void)
60 g_main_loop_quit(main_loop);
62 BT_DBG("Terminating bt-core daemon");
67 static gboolean bt_core_enable_adapter(BtCore *agent,
68 DBusGMethodInvocation *context);
70 static gboolean bt_core_disable_adapter(BtCore *agent,
71 DBusGMethodInvocation *context);
73 static gboolean bt_core_reset_adapter(BtCore *agent,
74 DBusGMethodInvocation *context);
76 #include "bt_core_glue.h"
78 GType bt_core_get_type (void);
81 G_DEFINE_TYPE(BtCore, bt_core, G_TYPE_OBJECT);
83 /*This is part of platform provided code skeleton for client server model*/
84 static void bt_core_class_init (BtCoreClass *bt_core_class)
86 dbus_g_object_type_install_info(G_TYPE_FROM_CLASS(bt_core_class),
87 &dbus_glib_bt_core_object_info);
90 /*This is part of platform provided code skeleton for client server model*/
91 static void bt_core_init (BtCore *core)
98 BT_CORE_ERROR_TIMEOUT,
101 #define BT_CORE_ERROR (bt_core_error_quark())
103 static GQuark bt_core_error_quark(void)
105 static GQuark quark = 0;
107 quark = g_quark_from_static_string("BtCore");
112 #define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
114 static GError *bt_core_error(BtCoreError error, const char *err_msg)
116 return g_error_new(BT_CORE_ERROR, error, err_msg, NULL);
119 static DBusGProxy *_bt_get_connman_proxy(void)
124 conn = dbus_g_bus_get(DBUS_BUS_SYSTEM, NULL);
125 retv_if(conn == NULL, NULL);
128 proxy = dbus_g_proxy_new_for_name(conn,
130 CONNMAN_BLUETOOTH_TECHNOLOGY_PATH,
131 CONNMAN_BLUETOTOH_TECHNOLOGY_INTERFACE);
132 retv_if(proxy == NULL, NULL);
137 static int _bt_power_adapter(gboolean powered)
139 GValue state = { 0 };
140 GError *error = NULL;
143 proxy = _bt_get_connman_proxy();
144 retv_if(proxy == NULL, BLUETOOTH_ERROR_INTERNAL);
146 g_value_init(&state, G_TYPE_BOOLEAN);
147 g_value_set_boolean(&state, powered);
149 BT_DBG("set power property state: %d to connman", powered);
151 dbus_g_proxy_call(proxy, "SetProperty", &error,
152 G_TYPE_STRING, "Powered",
153 G_TYPE_VALUE, &state,
154 G_TYPE_INVALID, G_TYPE_INVALID);
157 BT_ERR("Powered set err:[%s]", error->message);
159 g_value_unset(&state);
160 return BLUETOOTH_ERROR_INTERNAL;
162 return BLUETOOTH_ERROR_NONE;
165 static int __bt_enable_adapter(void)
168 #ifdef __TIZEN_MOBILE__
171 __bt_core_set_status(BT_ACTIVATING);
173 ret = system("/usr/etc/bluetooth/bt-stack-up.sh &");
175 BT_DBG("running script failed");
176 ret = system("/usr/etc/bluetooth/bt-dev-end.sh &");
177 __bt_core_set_status(BT_DEACTIVATED);
181 _bt_power_adapter(TRUE);
186 static int __bt_disable_adapter(void)
190 #ifdef __TIZEN_MOBILE__
191 __bt_core_set_status(BT_DEACTIVATING);
193 if (system("/usr/etc/bluetooth/bt-stack-down.sh &") < 0) {
194 BT_DBG("running script failed");
195 __bt_core_set_status(BT_ACTIVATED);
199 _bt_power_adapter(FALSE);
201 __bt_core_terminate();
205 static gboolean bt_core_enable_adapter(BtCore *agent,
206 DBusGMethodInvocation *context)
208 char *sender = dbus_g_method_get_sender(context);
214 ret = __bt_enable_adapter();
216 GError *error = bt_core_error(BT_CORE_ERROR_REJECT,
217 "Activation failed");
218 dbus_g_method_return_error(context, error);
223 dbus_g_method_return(context);
230 static gboolean bt_core_disable_adapter(BtCore *agent,
231 DBusGMethodInvocation *context)
233 char *sender = dbus_g_method_get_sender(context);
239 ret = __bt_disable_adapter();
241 GError *error = bt_core_error(BT_CORE_ERROR_REJECT,
242 "Deactivation failed");
243 dbus_g_method_return_error(context, error);
248 dbus_g_method_return(context);
255 static int __bt_reset_adapter(void)
257 /* Forcely terminate */
258 if (system("/usr/etc/bluetooth/bt-reset-env.sh &") < 0) {
259 BT_DBG("running script failed");
261 __bt_core_terminate();
265 static gboolean bt_core_reset_adapter(BtCore *agent,
266 DBusGMethodInvocation *context)
268 char *sender = dbus_g_method_get_sender(context);
274 ret = __bt_reset_adapter();
276 GError *error = bt_core_error(BT_CORE_ERROR_REJECT,
277 "Deactivation failed");
278 dbus_g_method_return_error(context, error);
283 dbus_g_method_return(context);
290 static int __bt_core_get_object_path(DBusMessage *msg, char **path)
292 DBusMessageIter item_iter;
294 dbus_message_iter_init(msg, &item_iter);
296 if (dbus_message_iter_get_arg_type(&item_iter)
297 != DBUS_TYPE_OBJECT_PATH) {
298 BT_ERR("This is bad format dbus\n");
299 return BLUETOOTH_ERROR_INTERNAL;
302 dbus_message_iter_get_basic(&item_iter, path);
305 return BLUETOOTH_ERROR_INTERNAL;
307 return BLUETOOTH_ERROR_NONE;
310 static int __bt_core_get_owner_info(DBusMessage *msg, char **name,
311 char **previous, char **current)
313 DBusMessageIter item_iter;
315 dbus_message_iter_init(msg, &item_iter);
317 if (dbus_message_iter_get_arg_type(&item_iter)
318 != DBUS_TYPE_STRING) {
319 BT_ERR("This is bad format dbus\n");
320 return BLUETOOTH_ERROR_INTERNAL;
323 dbus_message_iter_get_basic(&item_iter, name);
326 return BLUETOOTH_ERROR_INTERNAL;
328 dbus_message_iter_next(&item_iter);
330 if (dbus_message_iter_get_arg_type(&item_iter)
331 != DBUS_TYPE_STRING) {
332 BT_ERR("This is bad format dbus\n");
333 return BLUETOOTH_ERROR_INTERNAL;
336 dbus_message_iter_get_basic(&item_iter, previous);
338 if (*previous == NULL)
339 return BLUETOOTH_ERROR_INTERNAL;
341 dbus_message_iter_next(&item_iter);
343 if (dbus_message_iter_get_arg_type(&item_iter)
344 != DBUS_TYPE_STRING) {
345 BT_ERR("This is bad format dbus\n");
346 return BLUETOOTH_ERROR_INTERNAL;
349 dbus_message_iter_get_basic(&item_iter, current);
351 if (*current == NULL)
352 return BLUETOOTH_ERROR_INTERNAL;
354 return BLUETOOTH_ERROR_NONE;
357 static DBusHandlerResult __bt_core_event_filter(DBusConnection *conn,
358 DBusMessage *msg, void *data)
360 char *object_path = NULL;
361 const char *member = dbus_message_get_member(msg);
363 if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_SIGNAL)
364 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
367 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
369 if (strcasecmp(member, "InterfacesAdded") == 0) {
370 if (__bt_core_get_object_path(msg, &object_path)) {
371 BT_ERR("Fail to get the path");
372 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
374 #ifdef __TIZEN_MOBILE__
375 if (strcasecmp(object_path, "/org/bluez/hci0") == 0) {
376 __bt_core_set_status(BT_ACTIVATED);
379 } else if (strcasecmp(member, "InterfacesRemoved") == 0) {
380 if (__bt_core_get_object_path(msg, &object_path)) {
381 BT_ERR("Fail to get the path");
382 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
385 if (strcasecmp(object_path, "/org/bluez/hci0") == 0) {
386 #ifdef __TIZEN_MOBILE__
387 __bt_core_set_status(BT_DEACTIVATED);
389 __bt_core_terminate();
391 } else if (strcasecmp(member, "NameOwnerChanged") == 0) {
393 char *previous = NULL;
394 char *current = NULL;
396 if (__bt_core_get_owner_info(msg, &name, &previous, ¤t)) {
397 BT_ERR("Fail to get the owner info");
398 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
401 if (*current != '\0')
402 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
404 if (strcasecmp(name, "org.bluez") == 0) {
405 BT_DBG("Bluetoothd is terminated");
406 __bt_disable_adapter();
407 __bt_core_terminate();
408 } else if (strcasecmp(name, "org.projectx.bt") == 0) {
409 BT_DBG("bt-service is terminated abnormally");
410 __bt_disable_adapter();
414 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
417 static DBusGProxy *__bt_core_register_event_filter(DBusGConnection *g_conn,
420 DBusError dbus_error;
421 DBusConnection *conn;
429 conn = dbus_g_connection_get_connection(g_conn);
433 proxy = dbus_g_proxy_new_for_name(g_conn, DBUS_SERVICE_DBUS,
434 DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS);
436 BT_ERR("proxy is NULL");
440 if (!dbus_g_proxy_call(proxy, "RequestName", &err, G_TYPE_STRING,
441 BT_CORE_NAME, G_TYPE_UINT, 0, G_TYPE_INVALID,
442 G_TYPE_UINT, &result, G_TYPE_INVALID)) {
444 BT_ERR("RequestName RPC failed[%s]\n", err->message);
447 g_object_unref(proxy);
451 if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
452 BT_ERR("Failed to get the primary well-known name.\n");
453 g_object_unref(proxy);
457 if (!dbus_connection_add_filter(conn, __bt_core_event_filter,
459 BT_ERR("Fail to add filter");
460 g_object_unref(proxy);
464 dbus_error_init(&dbus_error);
466 dbus_bus_add_match(conn,
467 "type='signal',interface='org.freedesktop.DBus'"
468 ",member='NameOwnerChanged'",
471 if (dbus_error_is_set(&dbus_error)) {
472 BT_ERR("Fail to add match: %s\n", dbus_error.message);
473 dbus_error_free(&dbus_error);
474 g_object_unref(proxy);
478 dbus_bus_add_match(conn,
479 "type='signal',interface='org.freedesktop.DBus.ObjectManager'"
480 ",member='InterfacesAdded'",
483 if (dbus_error_is_set(&dbus_error)) {
484 BT_ERR("Fail to add match: %s\n", dbus_error.message);
485 dbus_error_free(&dbus_error);
486 g_object_unref(proxy);
490 dbus_bus_add_match(conn,
491 "type='signal',interface='org.freedesktop.DBus.ObjectManager'"
492 ",member='InterfacesRemoved'",
495 if (dbus_error_is_set(&dbus_error)) {
496 BT_ERR("Fail to add match: %s\n", dbus_error.message);
497 dbus_error_free(&dbus_error);
498 g_object_unref(proxy);
502 dbus_g_connection_register_g_object(g_conn, BT_CORE_PATH,
508 static void __bt_unregister_event_filter(DBusGConnection *g_conn,
510 DBusGProxy *dbus_proxy)
512 DBusConnection *conn;
514 if (g_conn == NULL ||
516 dbus_proxy == NULL) {
517 BT_ERR("Invalid parameter");
521 conn = dbus_g_connection_get_connection(g_conn);
523 dbus_connection_remove_filter(conn, __bt_core_event_filter, NULL);
525 dbus_g_connection_unregister_g_object(g_conn, G_OBJECT(bt_core));
527 g_object_unref(bt_core);
528 g_object_unref(dbus_proxy);
531 static void __bt_core_sigterm_handler(int signo)
533 BT_DBG("Got the signal: %d", signo);
535 __bt_core_terminate();
540 GError *error = NULL;
542 DBusGProxy *dbus_proxy = NULL;
547 conn = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
549 BT_ERR("ERROR: Can't get on system bus [%s]", error->message);
554 bt_core = g_object_new(BT_CORE_TYPE, NULL);
555 if (bt_core == NULL) {
556 BT_ERR("bt_service is NULL");
560 dbus_proxy = __bt_core_register_event_filter(conn, bt_core);
562 BT_ERR("__bt_core_register_event_filter failed");
563 g_object_unref(bt_core);
568 main_loop = g_main_loop_new(NULL, FALSE);
570 memset(&sa, 0, sizeof(sa));
571 sa.sa_handler = __bt_core_sigterm_handler;
572 sigaction(SIGINT, &sa, NULL);
573 sigaction(SIGTERM, &sa, NULL);
575 g_main_loop_run(main_loop);
578 __bt_unregister_event_filter(conn, bt_core, dbus_proxy);
581 g_main_loop_unref(main_loop);
583 dbus_g_connection_unref(conn);