Add the exception handling logic for TC
[platform/core/connectivity/bluetooth-agent.git] / hid-agent / bluetooth-hid-agent.c
1 /*
2  * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *              http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <signal.h>
22 #include <fcntl.h>
23 #include <aul.h>
24
25 #include "bluetooth-hid-agent.h"
26 #include "bluetooth-hid-manager.h"
27
28 static GMainLoop *gmain_loop;
29 static char *g_obj_path;
30
31 static GDBusConnection *gdbus_conn;
32 static GDBusProxy *profile_gproxy;
33 static guint interface_added_sig_id;
34 static guint interface_removed_sig_id;
35 static guint bluez_device_sig_id;
36 static guint name_owner_sig_id;
37
38 #define BT_HID_SIG_NUM 3
39 #define HID_DEVICE_UUID "00001124-0000-1000-8000-00805f9b43bf"
40 #define DEFAULT_ADAPTER_OBJECT_PATH "/org/bluez/hci0"
41
42 /*Below Inrospection data is exposed to application from agent*/
43 static const gchar hid_agent_introspection_xml[] =
44 "<node name='/'>"
45 "     <interface name='org.tizen.HidApp'>"
46 "               <method name='RegisterApplication'>"
47 "               </method>"
48 "               <method name='UnregisterApplication'>"
49 "               </method>"
50 "               <method name='IsHidConnected'>"
51 "                       <arg type='b' name='connected' direction='out'/>"
52 "               </method>"
53 "               <method name='IsHidConnectable'>"
54 "                       <arg type='b' name='connectable' direction='out'/>"
55 "               </method>"
56 "     </interface>"
57 "</node>";
58
59 static bt_hid_agent_info_t bt_hid_info = {0,};
60 static gboolean is_hid_connected;
61 static gboolean is_hid_connectable;
62 static struct sigaction bt_hid_sigoldact[BT_HID_SIG_NUM];
63 static int bt_hid_sig_to_handle[] = { SIGABRT, SIGSEGV, SIGTERM };
64
65 static void __bt_hid_agent_sigterm_handler(int signo);
66 static GError *__bt_hid_agent_set_error(bt_hid_agent_error_t error);
67
68 static void __on_log_glib(const gchar *log_domain, GLogLevelFlags log_level,
69                 const gchar *msg, gpointer user_data)
70 {
71         ERR_C("%s", msg);
72 }
73
74 static GQuark __bt_hid_agent_error_quark(void)
75 {
76         FN_START;
77         static GQuark quark;
78         if (!quark)
79                 quark = g_quark_from_static_string("hid-agent");
80
81         return quark;
82 }
83
84 static GError *__bt_hid_agent_set_error(bt_hid_agent_error_t error)
85 {
86         ERR("error[%d]", error);
87
88         switch (error) {
89         case BT_HID_AGENT_ERROR_NOT_AVAILABLE:
90                 return g_error_new(BT_HID_AGENT_ERROR, error,
91                                         BT_ERROR_NOT_AVAILABLE);
92         case BT_HID_AGENT_ERROR_NOT_CONNECTED:
93                 return g_error_new(BT_HID_AGENT_ERROR, error,
94                                         BT_ERROR_NOT_CONNECTED);
95         case BT_HID_AGENT_ERROR_CONNECTION_FAILED:
96                 return g_error_new(BT_HID_AGENT_ERROR, error,
97                                         BT_ERROR_NOT_CONNECTION_FAILED);
98         case BT_HID_AGENT_ERROR_BUSY:
99                 return g_error_new(BT_HID_AGENT_ERROR, error,
100                                         BT_ERROR_BUSY);
101         case BT_HID_AGENT_ERROR_INVALID_PARAM:
102                 return g_error_new(BT_HID_AGENT_ERROR, error,
103                                         BT_ERROR_INVALID_PARAM);
104         case BT_HID_AGENT_ERROR_ALREADY_EXIST:
105                 return g_error_new(BT_HID_AGENT_ERROR, error,
106                                         BT_ERROR_ALREADY_EXIST);
107         case BT_HID_AGENT_ERROR_ALREADY_CONNECTED:
108                 return g_error_new(BT_HID_AGENT_ERROR, error,
109                                         BT_ERROR_ALREADY_CONNECTED);
110         case BT_HID_AGENT_ERROR_NO_MEMORY:
111                 return g_error_new(BT_HID_AGENT_ERROR, error,
112                                         BT_ERROR_NO_MEMORY);
113         case BT_HID_AGENT_ERROR_NO_DATA:
114                 return g_error_new(BT_HID_AGENT_ERROR, error,
115                                         BT_ERROR_NO_DATA);
116         case BT_HID_AGENT_ERROR_I_O_ERROR:
117                 return g_error_new(BT_HID_AGENT_ERROR, error,
118                                         BT_ERROR_I_O_ERROR);
119         case BT_HID_AGENT_ERROR_APPLICATION:
120                 return g_error_new(BT_HID_AGENT_ERROR, error,
121                                         BT_ERROR_OPERATION_NOT_AVAILABLE);
122         case BT_HID_AGENT_ERROR_NOT_ALLOWED:
123                 return g_error_new(BT_HID_AGENT_ERROR, error,
124                                         BT_ERROR_OPERATION_NOT_ALLOWED);
125         case BT_HID_AGENT_ERROR_NOT_SUPPORTED:
126                 return g_error_new(BT_HID_AGENT_ERROR, error,
127                                         BT_ERROR_OPERATION_NOT_SUPPORTED);
128         case BT_HID_AGENT_ERROR_INVALID_FILE_DESCRIPTOR:
129                 return g_error_new(BT_HID_AGENT_ERROR, error,
130                                         BT_ERROR_INVALID_FILE_DESCRIPTOR);
131         case BT_HID_AGENT_ERROR_INTERNAL:
132         default:
133                 return g_error_new(BT_HID_AGENT_ERROR, error,
134                                                 BT_ERROR_INTERNAL);
135         }
136 }
137
138 static void __bt_hid_name_owner_changed_cb(GDBusConnection *connection,
139                                         const gchar *sender_name,
140                                         const gchar *object_path,
141                                         const gchar *interface_name,
142                                         const gchar *signal_name,
143                                         GVariant *parameters,
144                                         gpointer user_data)
145 {
146         char *name_owner = NULL;
147         char *old_owner = NULL;
148         char *new_owner = NULL;
149         int ret = 0;
150
151         if (strcasecmp(signal_name, "NameOwnerChanged") == 0) {
152                 g_variant_get(parameters, "(sss)", &name_owner, &old_owner, &new_owner);
153
154                 ret = _bt_hid_register_application(FALSE, name_owner);
155                 if (ret == BT_HID_AGENT_ERROR_NONE) {
156                         if (_bt_hid_get_sender_list() == NULL) {
157                                 is_hid_connectable = FALSE;
158                                 if (name_owner_sig_id > 0) {
159                                         g_dbus_connection_signal_unsubscribe(gdbus_conn,
160                                                                 name_owner_sig_id);
161                                         name_owner_sig_id = 0;
162                                 }
163                         }
164                 }
165         }
166 }
167
168 static void __hid_agent_method(GDBusConnection *connection,
169                             const gchar *sender,
170                             const gchar *object_path,
171                             const gchar *interface_name,
172                             const gchar *method_name,
173                             GVariant *parameters,
174                             GDBusMethodInvocation *context,
175                             gpointer user_data)
176 {
177         INFO("method %s", method_name);
178         int ret = 0;
179         GError *err;
180
181         if (g_strcmp0(method_name, "RegisterApplication") == 0) {
182                 DBG("Sender = %s\n", sender);
183
184                 ret = _bt_hid_register_application(TRUE, sender);
185                 if (ret == BT_HID_AGENT_ERROR_NONE) {
186                         is_hid_connectable = TRUE;
187                         if (name_owner_sig_id == 0) {
188                                 name_owner_sig_id = g_dbus_connection_signal_subscribe(gdbus_conn,
189                                                 NULL, NULL, "NameOwnerChanged", NULL, NULL, 0,
190                                                 __bt_hid_name_owner_changed_cb, NULL, NULL);
191                         }
192                 } else {
193                         goto fail;
194                 }
195
196                 g_dbus_method_invocation_return_value(context, NULL);
197         } else if (g_strcmp0(method_name, "UnregisterApplication") == 0) {
198                 DBG("Sender = %s\n", sender);
199
200                 ret = _bt_hid_register_application(FALSE, sender);
201                 if (ret == BT_HID_AGENT_ERROR_NONE) {
202                         if (_bt_hid_get_sender_list() == NULL) {
203                                 is_hid_connectable = FALSE;
204                                 if (name_owner_sig_id > 0) {
205                                         g_dbus_connection_signal_unsubscribe(gdbus_conn,
206                                                                 name_owner_sig_id);
207                                         name_owner_sig_id = 0;
208                                 }
209                         }
210                 } else {
211                         goto fail;
212                 }
213
214                 g_dbus_method_invocation_return_value(context, NULL);
215         } else if (g_strcmp0(method_name, "IsHidConnected") == 0) {
216                 DBG("Going to call IsHidConnected");
217                 INFO("is_hid_connected : %s",
218                         is_hid_connected ? "Connected" : "Disconnected");
219
220                 g_dbus_method_invocation_return_value(context,
221                                 g_variant_new("(b)", is_hid_connected));
222         } else if (g_strcmp0(method_name, "IsHidConnectable") == 0) {
223                 DBG("Going to call IsHidConnectable");
224                 INFO("is_hid_connectable : %s",
225                         is_hid_connectable ? "Connectable" : "Non-Connectable");
226
227                 g_dbus_method_invocation_return_value(context,
228                                 g_variant_new("(b)", is_hid_connectable));
229         }
230
231         return;
232
233 fail:
234         err = __bt_hid_agent_set_error(ret);
235         g_dbus_method_invocation_return_gerror(context, err);
236         g_error_free(err);
237 }
238
239 static const GDBusInterfaceVTable method_table = {
240         __hid_agent_method,
241         NULL,
242         NULL,
243 };
244
245 static GDBusNodeInfo *__bt_hid_create_method_node_info
246                                         (const gchar *introspection_data)
247 {
248         if (introspection_data == NULL)
249                 return NULL;
250
251         return g_dbus_node_info_new_for_xml(introspection_data, NULL);
252 }
253
254 static GDBusConnection *__bt_hid_get_gdbus_connection(void)
255 {
256         GDBusConnection *local_system_gconn = NULL;
257         GError *err = NULL;
258
259         if (gdbus_conn == NULL) {
260                 gdbus_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
261                 if (!gdbus_conn) {
262                         if (err) {
263                                 ERR("Unable to connect to dbus: %s", err->message);
264                                 g_clear_error(&err);
265                         }
266                         gdbus_conn = NULL;
267                 }
268         } else if (g_dbus_connection_is_closed(gdbus_conn)) {
269                 local_system_gconn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
270
271                 if (!local_system_gconn) {
272                         ERR("Unable to connect to dbus: %s", err->message);
273                         g_clear_error(&err);
274                 }
275
276                 gdbus_conn = local_system_gconn;
277         }
278         return gdbus_conn;
279 }
280
281 static gboolean __bt_hid_register_methods(void)
282 {
283         FN_START;
284         GError *error = NULL;
285         guint object_id;
286         guint owner_id;
287         GDBusNodeInfo *node_info;
288         GDBusConnection *conn;
289
290         owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
291                                 BT_HID_SERVICE_NAME,
292                                 G_BUS_NAME_OWNER_FLAGS_NONE,
293                                 NULL, NULL, NULL,
294                                 NULL, NULL);
295
296         DBG("owner_id is [%d]", owner_id);
297
298         conn = __bt_hid_get_gdbus_connection();
299         if (!conn) {
300                 ERR("Unable to get connection");
301                 return FALSE;
302         }
303
304         node_info = __bt_hid_create_method_node_info(hid_agent_introspection_xml);
305         if (node_info == NULL)
306                 return FALSE;
307
308         object_id = g_dbus_connection_register_object(conn,
309                                                 BT_HID_AGENT_OBJECT_PATH,
310                                                 node_info->interfaces[0],
311                                                 &method_table,
312                                                 NULL, NULL, &error);
313         g_dbus_node_info_unref(node_info);
314         if (object_id == 0) {
315                 if (error != NULL) {
316                         ERR("Failed to register: %s", error->message);
317                         g_error_free(error);
318                 }
319                 return FALSE;
320         }
321
322         FN_END;
323         return TRUE;
324 }
325
326 static GDBusProxy *__bt_hid_gdbus_init_profile_proxy(void)
327 {
328         FN_START;
329
330         GDBusProxy *proxy;
331         GError *err = NULL;
332         GDBusConnection *conn;
333
334         conn = __bt_hid_get_gdbus_connection();
335         if (!conn) {
336                 ERR("Unable to get connection");
337                 return NULL;
338         }
339
340         proxy =  g_dbus_proxy_new_sync(conn,
341                         G_DBUS_PROXY_FLAGS_NONE, NULL,
342                         BLUEZ_SERVICE_NAME, "/org/bluez",
343                         BLUEZ_PROFILE_MGMT_INTERFACE, NULL, &err);
344
345         if (!proxy) {
346                 if (err) {
347                         ERR("Unable to create proxy: %s", err->message);
348                          g_clear_error(&err);
349                 }
350                 return NULL;
351         }
352
353         profile_gproxy = proxy;
354
355         FN_END;
356         return proxy;
357 }
358
359 static GDBusProxy *__bt_hid_gdbus_get_profile_proxy(void)
360 {
361         return (profile_gproxy) ? profile_gproxy :
362                                   __bt_hid_gdbus_init_profile_proxy();
363 }
364
365 static GDBusProxy *__bt_hid_gdbus_get_service_proxy(const gchar *service,
366                                 const gchar *path, const gchar *interface)
367 {
368         FN_START;
369
370         GDBusProxy *proxy;
371         GError *err = NULL;
372         GDBusConnection *conn;
373
374         conn = __bt_hid_get_gdbus_connection();
375         if (!conn) {
376                 ERR("Unable to get connection");
377                 return NULL;
378         }
379
380         proxy =  g_dbus_proxy_new_sync(conn,
381                         G_DBUS_PROXY_FLAGS_NONE, NULL,
382                         service, path,
383                         interface, NULL, &err);
384
385         if (!proxy) {
386                 if (err) {
387                         ERR("Unable to create proxy: %s", err->message);
388                          g_clear_error(&err);
389                 }
390                 return NULL;
391         }
392
393         FN_END;
394         return proxy;
395 }
396
397 static GDBusProxy *__bt_hid_gdbus_get_device_proxy(char *object_path)
398 {
399         GDBusConnection *conn;
400         GError *err = NULL;
401         GDBusProxy *device_gproxy;
402
403         conn = __bt_hid_get_gdbus_connection();
404
405         if (conn == NULL)
406                 return NULL;
407
408         device_gproxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE,
409                                                 NULL, BLUEZ_SERVICE_NAME,
410                                                 object_path,
411                                                 BLUEZ_DEVICE_INTERFACE,
412                                                 NULL, &err);
413
414         if (device_gproxy == NULL && err) {
415                 ERR("Unable to create proxy: %s", err->message);
416                 g_clear_error(&err);
417                 return NULL;
418         }
419
420         return device_gproxy;
421 }
422
423 static int __bt_hid_agent_gdbus_method_send(const char *service,
424                                 GVariant *path, const char *interface,
425                                 const char *method)
426 {
427         FN_START;
428
429         GVariant *ret;
430         GDBusProxy *proxy;
431         GError *error = NULL;
432
433         proxy = __bt_hid_gdbus_get_service_proxy(service, g_obj_path, interface);
434         if (!proxy)
435                 return BT_HID_AGENT_ERROR_INTERNAL;
436
437         ret = g_dbus_proxy_call_sync(proxy,
438                                 method, path,
439                                 G_DBUS_CALL_FLAGS_NONE, -1,
440                                 NULL, &error);
441         if (ret == NULL) {
442                 /* dBUS-RPC is failed */
443                 ERR("dBUS-RPC is failed");
444                 if (error != NULL) {
445                         /* dBUS gives error cause */
446                         ERR("D-Bus API failure: errCode[%x], message[%s]",
447                                error->code, error->message);
448
449                         g_clear_error(&error);
450                 }
451                 g_object_unref(proxy);
452                 return BT_HID_AGENT_ERROR_INTERNAL;
453         }
454
455         g_variant_unref(ret);
456         g_object_unref(proxy);
457
458         return BT_HID_AGENT_ERROR_NONE;
459 }
460
461 static void __bt_hid_agent_sigterm_handler(int signo)
462 {
463         GDBusConnection *conn;
464         int i;
465
466         ERR_C("***** Signal handler came with signal %d *****", signo);
467
468         conn = __bt_hid_get_gdbus_connection();
469         if (!conn) {
470                 ERR("Unable to get G-DBus connection");
471                 goto done;
472         }
473
474         g_dbus_connection_flush(conn, NULL, NULL, NULL);
475         INFO("Flush g_dbus_connection");
476
477 done:
478         if (gmain_loop) {
479                 g_main_loop_quit(gmain_loop);
480                 INFO("Exiting");
481                 gmain_loop = NULL;
482         } else {
483                 INFO_C("Terminating HID agent");
484                 exit(0);
485         }
486
487         if (signo == SIGTERM)
488                 return;
489
490         for (i = 0; i < BT_HID_SIG_NUM; i++)
491                 sigaction(bt_hid_sig_to_handle[i], &(bt_hid_sigoldact[i]), NULL);
492
493         raise(signo);
494 }
495
496 static int __bt_hid_register_profile(const char *uuid,
497                  const char *name, const char *object)
498 {
499         FN_START;
500         GDBusProxy *proxy;
501         GVariant *ret;
502         GError *error = NULL;
503         GVariantBuilder *builder;
504
505         proxy = __bt_hid_gdbus_get_profile_proxy();
506
507         if (proxy == NULL)
508                 return BT_HID_AGENT_ERROR_INTERNAL;
509
510         builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
511
512         g_variant_builder_add(builder, "{sv}",
513                         "Name", g_variant_new("s",
514                         name));
515
516         g_variant_builder_add(builder, "{sv}",
517                         "PSM", g_variant_new("q", 17));
518
519         ret = g_dbus_proxy_call_sync(proxy, "RegisterProfile",
520                                 g_variant_new("(osa{sv})", BT_HID_BLUEZ_OBJECT_PATH,
521                                         HID_DEVICE_UUID, builder),
522                                 G_DBUS_CALL_FLAGS_NONE, -1,
523                                 NULL, &error);
524
525         g_variant_builder_unref(builder);
526
527         if (ret == NULL) {
528                 /* dBUS-RPC is failed */
529                 ERR("dBUS-RPC is failed");
530                 if (error != NULL) {
531                         /* dBUS gives error cause */
532                         ERR("D-Bus API failure: errCode[%x], message[%s]",
533                                 error->code, error->message);
534                         g_clear_error(&error);
535                 }
536                 return BT_HID_AGENT_ERROR_INTERNAL;
537         }
538         g_variant_unref(ret);
539
540         FN_END;
541         return BT_HID_AGENT_ERROR_NONE;
542 }
543
544 static void __bt_hid_agent_register(void)
545 {
546         FN_START;
547         int ret;
548
549         ret = __bt_hid_register_profile(HID_DEVICE_UUID,
550                                         "HID device", BT_HID_BLUEZ_OBJECT_PATH);
551         if (ret)
552                 ERR("Error in register");
553
554         FN_END;
555         return;
556 }
557
558 static void __bt_hid_agent_unregister(void)
559 {
560         FN_START;
561
562         if (g_obj_path) {
563                 __bt_hid_agent_gdbus_method_send(BLUEZ_SERVICE_NAME,
564                                                 g_variant_new("(o)", BT_HID_BLUEZ_OBJECT_PATH),
565                                                 BLUEZ_HID_INTERFACE_NAME,
566                                                 "UnregisterAgent");
567                 g_free(g_obj_path);
568                 g_obj_path = NULL;
569         }
570
571         FN_END;
572         return;
573 }
574
575 static void __bt_hid_agent_filter_cb(GDBusConnection *connection,
576                                                  const gchar *sender_name,
577                                                  const gchar *object_path,
578                                                  const gchar *interface_name,
579                                                  const gchar *signal_name,
580                                                  GVariant *parameters,
581                                                  gpointer user_data)
582 {
583         FN_START;
584         char *path = NULL;
585
586         GVariant *optional_param;
587
588         if (strcasecmp(signal_name, "InterfacesAdded") == 0) {
589
590                 g_variant_get(parameters, "(&o@a{sa{sv}})",
591                                 &path, &optional_param);
592                 if (!path) {
593                         ERR("Invalid adapter path");
594                         return;
595                 }
596
597                 if (strcasecmp(path, DEFAULT_ADAPTER_OBJECT_PATH) == 0) {
598                         g_obj_path = g_strdup(path);
599                         INFO("Adapter Path = [%s]", path);
600                         __bt_hid_agent_register();
601                 }
602         } else if (strcasecmp(signal_name, "InterfacesRemoved") == 0) {
603                 g_variant_get(parameters, "(&o@as)", &path, &optional_param);
604                 if (!path)
605                         __bt_hid_agent_unregister();
606         }
607         FN_END;
608 }
609
610 static void __bt_hid_device_filter_cb(GDBusConnection *connection,
611                                         const gchar *sender_name,
612                                         const gchar *object_path,
613                                         const gchar *interface_name,
614                                         const gchar *signal_name,
615                                         GVariant *parameters,
616                                         gpointer user_data)
617 {
618         DBG("sender_name = %s, object_path = %s", sender_name, object_path);
619
620          if (strcasecmp(signal_name, "ProfileStateChanged") == 0) {
621                 char *profile_uuid = NULL;
622                 bt_hid_state_t state = 0;
623
624                 g_variant_get(parameters, "(&si)", &profile_uuid, &state);
625                 if (g_strcmp0(profile_uuid, HID_DEVICE_UUID) == 0) {
626                         if (state == BT_HID_STATE_CONNECTED) {
627                                 g_free(bt_hid_info.object_path);
628                                 bt_hid_info.object_path = g_strdup(object_path);
629                                 DBG("device : [%s]", bt_hid_info.object_path);
630                         }
631                         _bt_hid_set_profile_state(state);
632                 }
633         }
634 }
635
636 static int __bt_hid_agent_get_adapter_path(GDBusConnection *conn, char *path)
637 {
638         GError *err = NULL;
639         GDBusProxy *manager_proxy = NULL;
640         GVariant *result = NULL;
641         char *adapter_path = NULL;
642
643         if (conn == NULL)
644                 return BT_HID_AGENT_ERROR_INTERNAL;
645
646         manager_proxy =  g_dbus_proxy_new_sync(conn,
647                         G_DBUS_PROXY_FLAGS_NONE, NULL,
648                         BLUEZ_SERVICE_NAME,
649                         "/",
650                         BT_MANAGER_INTERFACE,
651                         NULL, &err);
652
653         if (!manager_proxy) {
654                 ERR("Unable to create proxy: %s", err->message);
655                 goto fail;
656         }
657
658         result = g_dbus_proxy_call_sync(manager_proxy, "DefaultAdapter", NULL,
659                         G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
660         if (!result) {
661                 if (err != NULL)
662                         ERR("Fail to get DefaultAdapter (Error: %s)", err->message);
663                 else
664                         ERR("Fail to get DefaultAdapter");
665
666                 goto fail;
667         }
668
669         if (g_strcmp0(g_variant_get_type_string(result), "(o)")) {
670                 ERR("Incorrect result\n");
671                 goto fail;
672         }
673
674         g_variant_get(result, "(&o)", &adapter_path);
675
676         if (adapter_path == NULL ||
677                 strlen(adapter_path) >= BT_ADAPTER_OBJECT_PATH_MAX) {
678                 ERR("Adapter path is inproper\n");
679                 goto fail;
680         }
681
682         if (path)
683                 g_strlcpy(path, adapter_path, BT_ADAPTER_OBJECT_PATH_MAX);
684
685         if (g_obj_path == NULL) {
686                 g_obj_path = g_strdup(adapter_path);
687                 INFO("Update g_obj_path [%s]", adapter_path);
688         }
689
690         g_variant_unref(result);
691         g_object_unref(manager_proxy);
692
693         return 0;
694
695 fail:
696         g_clear_error(&err);
697
698         if (result)
699                 g_variant_unref(result);
700
701         if (manager_proxy)
702                 g_object_unref(manager_proxy);
703
704         return BT_HID_AGENT_ERROR_INTERNAL;
705
706 }
707
708 static void __bt_hid_agent_dbus_init(void)
709 {
710         GDBusConnection *conn;
711
712         FN_START;
713
714         conn = __bt_hid_get_gdbus_connection();
715         if (conn == NULL) {
716                 ERR("Error in creating the gdbus connection");
717                 return;
718         }
719         if (!__bt_hid_register_methods()) {
720                 ERR("Error in __bt_hid_register_methods");
721                 return;
722         }
723
724         if (!__bt_hid_agent_get_adapter_path(conn, NULL))
725                 __bt_hid_agent_register();
726
727         interface_added_sig_id = g_dbus_connection_signal_subscribe(conn,
728                                 NULL, BT_MANAGER_INTERFACE, BT_INTERFACES_ADDED, NULL, NULL, 0,
729                                 __bt_hid_agent_filter_cb, NULL, NULL);
730
731         interface_removed_sig_id = g_dbus_connection_signal_subscribe(conn,
732                                 NULL, BT_MANAGER_INTERFACE, BT_INTERFACES_REMOVED, NULL, NULL, 0,
733                                 __bt_hid_agent_filter_cb, NULL, NULL);
734
735         bluez_device_sig_id = g_dbus_connection_signal_subscribe(conn,
736                                 NULL, BLUEZ_DEVICE_INTERFACE, NULL, NULL,
737                                 NULL, 0, __bt_hid_device_filter_cb,
738                                 NULL, NULL);
739
740         _bt_hid_set_profile_state(BT_HID_STATE_DISCONNECTED);
741
742         FN_END;
743 }
744
745 static void __bt_hid_agent_dbus_deinit(void)
746 {
747         if (profile_gproxy) {
748                 g_object_unref(profile_gproxy);
749                 profile_gproxy = NULL;
750         }
751
752         if (gdbus_conn) {
753                 if (interface_added_sig_id > 0)
754                         g_dbus_connection_signal_unsubscribe(gdbus_conn,
755                                                 interface_added_sig_id);
756
757                 if (interface_removed_sig_id > 0)
758                         g_dbus_connection_signal_unsubscribe(gdbus_conn,
759                                                 interface_removed_sig_id);
760
761                 if (bluez_device_sig_id > 0)
762                         g_dbus_connection_signal_unsubscribe(gdbus_conn,
763                                                 bluez_device_sig_id);
764
765                 if (name_owner_sig_id > 0)
766                         g_dbus_connection_signal_unsubscribe(gdbus_conn,
767                                                 name_owner_sig_id);
768
769                 interface_added_sig_id = 0;
770                 interface_removed_sig_id = 0;
771                 bluez_device_sig_id = 0;
772                 name_owner_sig_id = 0;
773
774                 g_object_unref(gdbus_conn);
775                 gdbus_conn = NULL;
776         }
777 }
778
779
780
781
782 bt_hid_agent_error_t _bt_hid_disconnect_profile(void)
783 {
784         FN_START;
785         GDBusProxy *proxy = NULL;
786
787         if (bt_hid_info.object_path)
788                 proxy = __bt_hid_gdbus_get_device_proxy(bt_hid_info.object_path);
789
790         if (proxy == NULL) {
791                 ERR("Error while getting proxy");
792                 return BT_HID_AGENT_ERROR_INTERNAL;
793         }
794
795         g_dbus_proxy_call(proxy, "DisconnectProfile",
796                         g_variant_new("(s)", HID_DEVICE_UUID),
797                         G_DBUS_CALL_FLAGS_NONE, 2000,
798                         NULL, NULL, NULL);
799
800         FN_END;
801
802         return BT_HID_AGENT_ERROR_NONE;
803 }
804
805 int main(void)
806 {
807         int i;
808         struct sigaction sa;
809
810
811         INFO_C("### Starting Bluetooth HID agent");
812
813 #if GLIB_VERSION_MIN_REQUIRED < GLIB_VERSION_2_36
814         g_type_init();
815 #endif
816
817         memset(&sa, 0, sizeof(sa));
818         sa.sa_flags = SA_NOCLDSTOP;
819         sa.sa_handler = __bt_hid_agent_sigterm_handler;
820
821         for (i = 0; i < BT_HID_SIG_NUM; i++)
822                 sigaction(bt_hid_sig_to_handle[i], &sa, &(bt_hid_sigoldact[i]));
823
824         g_log_set_default_handler(__on_log_glib, NULL);
825
826         gmain_loop = g_main_loop_new(NULL, FALSE);
827
828         __bt_hid_agent_dbus_init();
829
830         g_main_loop_run(gmain_loop);
831
832         __bt_hid_agent_dbus_deinit();
833
834         if (gmain_loop)
835                 g_main_loop_unref(gmain_loop);
836
837         INFO_C("### Terminating Bluetooth HID agent");
838         return 0;
839 }
840