Fix the bug on TV profile's BT on
[platform/core/connectivity/bluetooth-frwk.git] / bt-core / bt-core-dbus-handler.c
1 /*
2  * Bluetooth-frwk
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact:  Hocheol Seo <hocheol.seo@samsung.com>
7  *               Girishashok Joshi <girish.joshi@samsung.com>
8  *               Chanyeol Park <chanyeol.park@samsung.com>
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *              http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  *
22  */
23
24 #include <gio/gio.h>
25 #include <vconf.h>
26 #include <vconf-keys.h>
27
28 #include "bt-core-adapter.h"
29 #include "bt-core-common.h"
30 #include "bt-core-dbus-handler.h"
31 #include "bt-internal-types.h"
32 #include "bt-core-noti-handler.h"
33 #include "bt-core-main.h"
34
35 #define BT_SERVICE_NAME         "org.projectx.bt"
36 #define BT_SERVICE_PATH         "/org/projectx/bt_service"
37
38 static GDBusConnection *service_gconn;
39 static GDBusProxy *service_gproxy;
40
41 void _bt_core_fill_garray_from_variant(GVariant *var, GArray *param)
42 {
43         char *data;
44         int size;
45
46         size = g_variant_get_size(var);
47         if (size > 0) {
48                 data = (char *)g_variant_get_data(var);
49                 if (data)
50                         param = g_array_append_vals(param, data, size);
51
52         }
53 }
54
55 GDBusConnection * _bt_core_get_gdbus_connection(void)
56 {
57         GError *err = NULL;
58
59         if (service_gconn == NULL)
60                 service_gconn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
61
62         if (!service_gconn) {
63                 if (err) {
64                         BT_ERR("Unable to connect to dbus: %s", err->message);
65                         g_clear_error(&err);
66                 }
67                 return NULL;
68         }
69
70         return service_gconn;
71 }
72
73 static GDBusProxy *__bt_core_gdbus_init_service_proxy(void)
74 {
75         GDBusProxy *proxy;
76         GError *err = NULL;
77         GDBusConnection *conn;
78
79         g_type_init();
80
81         conn = _bt_core_get_gdbus_connection();
82         if (!conn)
83                 return NULL;
84
85         proxy =  g_dbus_proxy_new_sync(conn,
86                         G_DBUS_PROXY_FLAGS_NONE, NULL,
87                         BT_SERVICE_NAME,
88                         BT_SERVICE_PATH,
89                         BT_SERVICE_NAME,
90                         NULL, &err);
91         if (!proxy) {
92                 if (err) {
93                          BT_ERR("Unable to create proxy: %s", err->message);
94                          g_clear_error(&err);
95                 }
96
97                 return NULL;
98         }
99
100         service_gproxy = proxy;
101
102         return proxy;
103 }
104
105 GDBusProxy *_bt_core_gdbus_get_service_proxy(void)
106 {
107         return (service_gproxy) ? service_gproxy : __bt_core_gdbus_init_service_proxy();
108 }
109
110 void _bt_core_gdbus_deinit_proxys(void)
111 {
112         BT_DBG("");
113
114         if (service_gproxy) {
115                 g_object_unref(service_gproxy);
116                 service_gproxy = NULL;
117         }
118
119         if (service_gconn) {
120                 g_object_unref(service_gconn);
121                 service_gconn = NULL;
122         }
123 }
124
125 int _bt_core_service_request(int service_type, int service_function,
126                         GArray *in_param1, GArray *in_param2,
127                         GArray *in_param3, GArray *in_param4,
128                         GArray **out_param1)
129 {
130         GDBusProxy  *proxy;
131         GVariant *ret;
132         GVariant *param1;
133         GVariant *param2;
134         GVariant *param3;
135         GVariant *param4;
136         GVariant *param5;
137
138         int result = BLUETOOTH_ERROR_NONE;
139         GError *error = NULL;
140         GArray *in_param5 = NULL;
141         GArray *out_param2 = NULL;
142
143         proxy = _bt_core_gdbus_get_service_proxy();
144         if (!proxy)
145                 return BLUETOOTH_ERROR_INTERNAL;
146         in_param5 = g_array_new(TRUE, TRUE, sizeof(gchar));
147
148         param1 = g_variant_new_from_data((const GVariantType *)"ay",
149                                 in_param1->data, in_param1->len,
150                                 TRUE, NULL, NULL);
151         param2 = g_variant_new_from_data((const GVariantType *)"ay",
152                                 in_param2->data, in_param2->len,
153                                 TRUE, NULL, NULL);
154         param3 = g_variant_new_from_data((const GVariantType *)"ay",
155                                 in_param3->data, in_param3->len,
156                                 TRUE, NULL, NULL);
157         param4 = g_variant_new_from_data((const GVariantType *)"ay",
158                                 in_param4->data, in_param4->len,
159                                 TRUE, NULL, NULL);
160         param5 = g_variant_new_from_data((const GVariantType *)"ay",
161                                 in_param5->data, in_param5->len,
162                                 TRUE, NULL, NULL);
163
164         ret = g_dbus_proxy_call_sync(proxy, "service_request",
165                                 g_variant_new("(iii@ay@ay@ay@ay@ay)",
166                                         service_type, service_function,
167                                         BT_SYNC_REQ, param1,
168                                         param2, param3,
169                                         param4, param5),
170                                 G_DBUS_CALL_FLAGS_NONE, -1,
171                                 NULL, &error);
172
173         g_array_free(in_param5, TRUE);
174
175         if (ret == NULL) {
176                 /* dBUS-RPC is failed */
177                 BT_ERR("dBUS-RPC is failed");
178
179                 if (error != NULL) {
180                         /* dBUS gives error cause */
181                         BT_ERR("D-Bus API failure: errCode[%x], message[%s]",
182                                error->code, error->message);
183
184                         g_clear_error(&error);
185                 } else {
186                         /* dBUS does not give error cause dBUS-RPC is failed */
187                         BT_ERR("error returned was NULL");
188                 }
189
190                 return BLUETOOTH_ERROR_INTERNAL;
191         }
192
193         param1 = NULL;
194         param2 = NULL;
195
196         g_variant_get(ret, "(@ay@ay)", &param1, &param2);
197
198         if (param1) {
199                 *out_param1 = g_array_new(TRUE, TRUE, sizeof(gchar));
200                 _bt_core_fill_garray_from_variant(param1, *out_param1);
201                 g_variant_unref(param1);
202         }
203
204         if (param2) {
205                 out_param2 = g_array_new(TRUE, TRUE, sizeof(gchar));
206                 _bt_core_fill_garray_from_variant(param2, out_param2);
207                 result = g_array_index(out_param2, int, 0);
208                 g_variant_unref(param2);
209                 g_array_free(out_param2, TRUE);
210         } else {
211                 result = BLUETOOTH_ERROR_INTERNAL;
212         }
213
214         g_variant_unref(ret);
215
216         return result;
217 }
218
219 static const gchar bt_core_introspection_xml[] =
220 "<node name='/'>"
221 "  <interface name='org.projectx.btcore'>"
222 "     <method name='EnableAdapter'>"
223 "     </method>"
224 "     <method name='DisableAdapter'>"
225 "     </method>"
226 "     <method name='RecoverAdapter'>"
227 "     </method>"
228 "     <method name='ResetAdapter'>"
229 "     </method>"
230 "     <method name='EnableAdapterLe'>"
231 "     </method>"
232 "     <method name='DisableAdapterLe'>"
233 "     </method>"
234 "     <method name='EnableCore'>"
235 "     </method>"
236 "     <method name='FactoryTestMode'>"
237 "          <arg type='s' name='type' direction='in'/>"
238 "          <arg type='s' name='arg' direction='in'/>"
239 "          <arg type='i' name='ret' direction='out'/>"
240 "     </method>"
241 " </interface>"
242 "</node>";
243
244 static guint obj_id, sig_id1, sig_id2, sig_id3;
245
246 static void __bt_core_dbus_method(GDBusConnection *connection,
247                         const gchar *sender,
248                         const gchar *object_path,
249                         const gchar *interface_name,
250                         const gchar *method_name,
251                         GVariant *parameters,
252                         GDBusMethodInvocation *invocation,
253                         gpointer user_data)
254 {
255         gboolean ret;
256
257         BT_DBG("method %s", method_name);
258
259         if (g_strcmp0(method_name, "EnableAdapter") == 0) {
260                 ret = _bt_core_enable_adapter();
261         } else if (g_strcmp0(method_name, "DisableAdapter") == 0) {
262                 ret = _bt_core_disable_adapter();
263         } else if (g_strcmp0(method_name, "RecoverAdapter") == 0) {
264                 ret = _bt_core_recover_adapter();
265         } else if (g_strcmp0(method_name, "ResetAdapter") == 0) {
266                 ret = __bt_core_reset_adapter();
267         } else if (g_strcmp0(method_name, "EnableAdapterLe") == 0) {
268                 ret = _bt_core_enable_adapter_le();
269         } else if (g_strcmp0(method_name, "DisableAdapterLe") == 0) {
270                 ret = _bt_core_disable_adapter_le();
271         } else if (g_strcmp0(method_name, "EnableCore") == 0) {
272                 ret = _bt_core_enable_core();
273         } else if (g_strcmp0(method_name, "FactoryTestMode") == 0) {
274                 const char *type = NULL;
275                 const char *arg = NULL;
276
277                 g_variant_get(parameters, "(&s&s)", &type, &arg);
278                 ret = _bt_core_factory_test_mode(type, arg);
279                 g_dbus_method_invocation_return_value(invocation,
280                                 g_variant_new("(i)", ret));
281                  return;
282         } else {
283                 ret = FALSE;
284         }
285
286         if (!ret) {
287                 GQuark quark = g_quark_from_string("bt-core");
288                 GError *err = g_error_new(quark, 0, "Failed");
289                 g_dbus_method_invocation_return_gerror(invocation, err);
290                 g_error_free(err);
291         } else {
292                 g_dbus_method_invocation_return_value(invocation, NULL);
293         }
294
295         BT_DBG("-");
296 }
297
298 static const GDBusInterfaceVTable method_table = {
299         __bt_core_dbus_method,
300         NULL,
301         NULL,
302 };
303
304 static GDBusNodeInfo *__bt_core_create_node_info(
305                                         const gchar *introspection_data)
306 {
307         GError *err = NULL;
308         GDBusNodeInfo *node_info = NULL;
309
310         if (introspection_data == NULL)
311                 return NULL;
312
313         node_info = g_dbus_node_info_new_for_xml(introspection_data, &err);
314
315         if (err) {
316                 BT_ERR("Unable to create node: %s", err->message);
317                 g_clear_error(&err);
318         }
319         return node_info;
320 }
321
322 gboolean __is_interface_and_signal_valid(const gchar *interface_name,
323                                                 const gchar *signal_name)
324 {
325         if (g_strcmp0(interface_name, "org.freedesktop.DBus") &&
326                 g_strcmp0(interface_name, "org.freedesktop.DBus.ObjectManager"))
327                 return FALSE;
328
329         if (g_strcmp0(signal_name, "NameOwnerChanged") &&
330                 g_strcmp0(signal_name, "InterfacesAdded") &&
331                 g_strcmp0(signal_name, "InterfacesRemoved"))
332                 return FALSE;
333
334         return TRUE;
335 }
336
337 static void __handle_name_owner_changed(const char *name)
338 {
339         gboolean flight_mode_status;
340
341         BT_DBG("");
342
343         flight_mode_status = _bt_core_is_flight_mode_enabled();
344
345         if (flight_mode_status == FALSE && _bt_is_flightmode_request() == TRUE) {
346                 BT_DBG("flightmode requested");
347                 return;
348         }
349
350         if ((g_strcmp0(name, "org.bluez") == 0) ||
351                 (g_strcmp0(name, "org.projectx.bt") == 0)) {
352                 BT_DBG("%s is terminated", name);
353                 if (_bt_check_terminating_condition() == TRUE) {
354                         _bt_disable_adapter();
355                         _bt_disable_adapter_le();
356                         _bt_core_terminate();
357                 }
358         }
359 }
360
361 static void __bt_core_event_filter(GDBusConnection *connection,
362                                                  const gchar *sender_name,
363                                                  const gchar *object_path,
364                                                  const gchar *interface_name,
365                                                  const gchar *signal_name,
366                                                  GVariant *parameters,
367                                                  gpointer user_data)
368 {
369         if (!__is_interface_and_signal_valid(interface_name, signal_name))
370                 return;
371
372         if (!g_strcmp0(signal_name, "InterfacesAdded")) {
373                 char *obj_path = NULL;
374                 GVariant *optional_param;
375
376                 g_variant_get(parameters, "(&o@a{sa{sv}})",
377                                                 &obj_path, &optional_param);
378
379                 if (g_strcmp0(obj_path, "/org/bluez/hci0") == 0) {
380                         _bt_core_adapter_added_cb();
381                 }
382         } else if (!g_strcmp0(signal_name, "InterfacesRemoved")) {
383                 char *obj_path = NULL;
384                 GVariant *optional_param;
385
386                 g_variant_get(parameters, "(&o@as)", &obj_path,
387                                                         &optional_param);
388
389                 if (g_strcmp0(obj_path, "/org/bluez/hci0") == 0) {
390                         _bt_core_adapter_removed_cb();
391                 }
392         } else { /* NameOwnerChanged */
393                 const char *name = NULL;
394                 const char *old_owner = NULL;
395                 const char *new_owner = NULL;
396
397                 g_variant_get(parameters, "(&s&s&s)", &name, &old_owner,
398                                                                 &new_owner);
399
400                 if (new_owner != NULL && *new_owner == '\0')
401                         __handle_name_owner_changed(name);
402         }
403 }
404
405 gboolean _bt_core_register_dbus(void)
406 {
407         GError *error = NULL;
408         guint owner_id;
409         GDBusNodeInfo *node_info;
410         gchar *path;
411         GDBusConnection *conn;
412
413         conn = _bt_core_get_gdbus_connection();
414         if (!conn)
415                 return FALSE;
416
417         owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
418                                 BT_CORE_NAME,
419                                 G_BUS_NAME_OWNER_FLAGS_NONE,
420                                 NULL, NULL, NULL,
421                                 NULL, NULL);
422
423         BT_DBG("owner_id is [%d]", owner_id);
424
425         node_info = __bt_core_create_node_info(bt_core_introspection_xml);
426         if (node_info == NULL)
427                 return FALSE;
428
429         path = g_strdup(BT_CORE_PATH);
430         BT_DBG("path is [%s]", path);
431
432         obj_id = g_dbus_connection_register_object(conn, path,
433                                         node_info->interfaces[0],
434                                         &method_table,
435                                         NULL, NULL, &error);
436         if (obj_id == 0) {
437                 BT_ERR("Failed to register: %s", error->message);
438                 g_error_free(error);
439                 g_free(path);
440                 return FALSE;
441         }
442
443         g_free(path);
444
445         sig_id1 = g_dbus_connection_signal_subscribe(conn,
446                                 NULL, "org.freedesktop.DBus",
447                                 "NameOwnerChanged", NULL, NULL, 0,
448                                 __bt_core_event_filter, NULL, NULL);
449         sig_id2 = g_dbus_connection_signal_subscribe(conn,
450                                 NULL, "org.freedesktop.DBus.ObjectManager",
451                                 "InterfacesAdded", NULL, NULL,
452                                 0, __bt_core_event_filter, NULL, NULL);
453         sig_id2 = g_dbus_connection_signal_subscribe(conn,
454                                 NULL, "org.freedesktop.DBus.ObjectManager",
455                                 "InterfacesRemoved", NULL,
456                                 NULL, 0, __bt_core_event_filter, NULL, NULL);
457
458         return TRUE;
459 }
460
461 void  _bt_core_unregister_dbus(void)
462 {
463         GDBusConnection *conn;
464
465         BT_DBG("");
466
467         conn = _bt_core_get_gdbus_connection();
468         if (!conn)
469                 return;
470
471         if (obj_id > 0) {
472                 g_dbus_connection_unregister_object(conn, obj_id);
473                 obj_id = 0;
474         }
475
476         if (sig_id1 > 0) {
477                 g_dbus_connection_signal_unsubscribe(conn, sig_id1);
478                 sig_id1 = 0;
479         }
480         if (sig_id2 > 0) {
481                 g_dbus_connection_signal_unsubscribe(conn, sig_id2);
482                 sig_id2 = 0;
483         }
484         if (sig_id3 > 0) {
485                 g_dbus_connection_signal_unsubscribe(conn, sig_id3);
486                 sig_id3 = 0;
487         }
488 }