Fix lcov option for lcov 2.0
[platform/core/appfw/librua.git] / src / rua_dbus.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 #include <stdio.h>
18 #include <stdlib.h>
19
20 #include <glib.h>
21 #include <gio/gio.h>
22 #include <dlog.h>
23 #include <sqlite3.h>
24
25 #include "rua.h"
26 #include "rua_dbus.h"
27 #include "rua_private.h"
28
29 #define RUA_INTERFACE "org.tizen.rua"
30 #define RUA_PATH "/org/tizen/rua"
31 #define RUA_SIGNAL_DATA_UPDATE "dataupdate"
32
33 struct cb_data {
34         int callback_id;
35         rua_history_update_cb callback;
36         void *user_data;
37 };
38
39 static GDBusConnection *conn;
40 static guint s_id;
41
42 static gint atomic_callback_id;
43 static GHashTable *callback_hash_table;
44
45 static void __foreach_callback(gpointer key, gpointer value,
46                 gpointer user_data);
47 static void __signal_handler(GDBusConnection *connection,
48                                         const gchar *sender_name,
49                                         const gchar *object_path,
50                                         const gchar *interface_name,
51                                         const gchar *signal_name,
52                                         GVariant *parameters,
53                                         gpointer user_data);
54 static void __rua_dbus_init(void);
55 static void __rua_dbus_exit(void);
56
57 int rua_dbus_send_update_signal(update_type type)
58 {
59         __rua_dbus_init();
60         GError *err = NULL;
61
62         if (g_dbus_connection_emit_signal(conn,
63                                 NULL,
64                                 RUA_PATH,
65                                 RUA_INTERFACE,
66                                 RUA_SIGNAL_DATA_UPDATE,
67                                 g_variant_new("(i)", type),
68                                 &err) == FALSE) {
69                 if (err != NULL) {
70                         LOGE("g_dbus_connection_emit_signal() is failed. %s",
71                                         err->message);
72                         g_clear_error(&err);
73                 } else {
74                         LOGE("g_dbus_connection_emit_signal() is failed");
75                 }
76                 __rua_dbus_exit();
77                 return -1;
78         }
79
80         if (g_dbus_connection_flush_sync(conn, NULL, &err) == FALSE) {
81                 if (err != NULL) {
82                         LOGE("g_dbus_connection_flush_sync() is failed. %s",
83                                         err->message);
84                         g_clear_error(&err);
85                 } else {
86                         LOGE("g_dbus_connection_emit_signal() is failed");
87                 }
88                 __rua_dbus_exit();
89                 return -1;
90         }
91
92         g_clear_error(&err);
93
94         __rua_dbus_exit();
95
96         return 0;
97 }
98
99 int rua_dbus_signal_subscribe(rua_history_update_cb callback,
100                 void *user_data, int *callback_id)
101 {
102         struct cb_data *cd = NULL;
103
104         if (s_id == 0) {
105                 __rua_dbus_init();
106
107                 s_id = g_dbus_connection_signal_subscribe(conn,
108                                 NULL,
109                                 RUA_INTERFACE,
110                                 RUA_SIGNAL_DATA_UPDATE,
111                                 RUA_PATH,
112                                 NULL,
113                                 G_DBUS_SIGNAL_FLAGS_NONE,
114                                 __signal_handler,
115                                 NULL,
116                                 NULL);
117
118                 if (s_id == 0) {
119                         LOGE("g_dbus_connection_signal_subscribe() is failed.");
120                         __rua_dbus_exit();
121                         return -1;
122                 }
123
124                 if (!callback_hash_table) {
125                         callback_hash_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
126                                         NULL, free);
127                         if (!callback_hash_table) {
128                                 LOGE("out of memory : g_hash_table_new() is failed");
129                                 __rua_dbus_exit();
130                                 return -1;
131                         }
132                 }
133         }
134
135         cd = (struct cb_data *)malloc(sizeof(struct cb_data));
136         if (!cd) {
137                 LOGE("out of memory : malloc() is failed");
138                 return -1;
139         }
140
141         g_atomic_int_inc(&atomic_callback_id);
142
143         cd->callback = callback;
144         cd->user_data = user_data;
145         cd->callback_id = atomic_callback_id;
146
147         g_hash_table_insert(callback_hash_table,
148                         GINT_TO_POINTER(cd->callback_id), (gpointer)cd);
149
150         *callback_id = cd->callback_id;
151
152         return 0;
153 }
154
155 int rua_dbus_signal_unsubscribe(int callback_id)
156 {
157         gboolean result = FALSE;
158         guint table_size = 0;
159
160         result = g_hash_table_remove(callback_hash_table, GINT_TO_POINTER(callback_id));
161         if (!result) {
162                 LOGE("g_hash_table_remove failed(%d is wrong)", callback_id);
163                 return -1;
164         }
165
166         table_size = g_hash_table_size(callback_hash_table);
167         if (s_id && table_size == 0) {
168                 g_dbus_connection_signal_unsubscribe(conn, s_id);
169                 g_hash_table_destroy(callback_hash_table);
170                 __rua_dbus_exit();
171                 callback_hash_table = NULL;
172                 s_id = 0;
173         }
174
175         return 0;
176 }
177
178 static void __foreach_callback(gpointer key, gpointer value,
179                 gpointer user_data)
180 {
181         char **table = NULL;
182         int nrows = 0;
183         int ncols = 0;
184         int r = 0;
185
186         struct cb_data *cd = (struct cb_data *)value;
187
188         r = rua_history_load_db(&table, &nrows, &ncols);
189         if (r == -1)
190                 return;
191
192         if (cd->callback)
193                 cd->callback(table, nrows, ncols, cd->user_data);
194
195         sqlite3_free_table(table);
196 }
197
198 static void __signal_handler(GDBusConnection *connection,
199                                         const gchar *sender_name,
200                                         const gchar *object_path,
201                                         const gchar *interface_name,
202                                         const gchar *signal_name,
203                                         GVariant *parameters,
204                                         gpointer user_data)
205 {
206         int update_type;
207
208         LOGI("__signal_handler");
209         if (g_strcmp0(signal_name, RUA_SIGNAL_DATA_UPDATE))
210                 return;
211
212         g_variant_get(parameters, "(i)", &update_type);
213
214         g_hash_table_foreach(callback_hash_table, __foreach_callback, NULL);
215 }
216
217 static void __rua_dbus_init(void)
218 {
219         GError *err = NULL;
220
221         if (conn)
222                 return;
223
224         conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
225         if (conn)
226                 return;
227
228         if (err != NULL) {
229                 LOGE("g_bus_get_sync() is failed. %s", err->message);
230                 g_error_free(err);
231         } else {
232                 LOGE("g_bus_get_sync() is failed.");
233         }
234 }
235
236 static void __rua_dbus_exit(void)
237 {
238         if (conn) {
239                 g_object_unref(conn);
240                 conn = NULL;
241         }
242 }