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