Fix directory hierarchy & cmake configuration files
[platform/core/appfw/launchpad.git] / src / launchpad-process-pool / src / launchpad_dbus.c
1 /*
2  * Copyright (c) 2020 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 #define _GNU_SOURCE
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <gio/gio.h>
21 #include <glib.h>
22
23 #include "launchpad_dbus.h"
24 #include "log_private.h"
25
26 #define AUL_DBUS_PATH                   "/aul/dbus_handler"
27 #define AUL_DBUS_SIGNAL_INTERFACE       "org.tizen.aul.signal"
28 #define AUL_DBUS_APPDEAD_SIGNAL         "app_dead"
29 #define AUL_DBUS_APPLAUNCH_SIGNAL       "app_launch"
30
31 #define PENDING_ITEM_INTERVAL           1000
32
33 #define GET_CONNECTION_ERROR_THRESHOLD  10
34 #define GET_CONNECTION_ERROR_MODULO     1000
35 typedef enum {
36         APP_SIGNAL_DEAD,
37         APP_SIGNAL_LAUNCH,
38 } app_signal_e;
39
40 typedef struct pending_item_s {
41         char *app_id;
42         int pid;
43         app_signal_e app_signal;
44 } pending_item_t;
45
46 static GList *__pending_items;
47 static guint __timer;
48 static GDBusConnection *__conn;
49
50 static void __set_pending_item_timer(void);
51
52 static void __destroy_pending_item(gpointer data)
53 {
54         pending_item_t *item = data;
55
56         free(item->app_id);
57         free(item);
58 }
59
60 static pending_item_t *__create_pending_item(const char *app_id,
61                 int pid, app_signal_e app_signal)
62 {
63         pending_item_t *item;
64
65         item = calloc(1, sizeof(pending_item_t));
66         if (!item) {
67                 _E("Out of memory");
68                 return NULL;
69         }
70
71         if (app_id) {
72                 item->app_id = strdup(app_id);
73                 if (!item->app_id) {
74                         _E("Failed to duplicate app ID(%s)", app_id);
75                         __destroy_pending_item(item);
76                         return NULL;
77                 }
78         }
79
80         item->pid = pid;
81         item->app_signal = app_signal;
82
83         return item;
84 }
85
86 static GDBusConnection *__get_connection(void)
87 {
88         GError *error = NULL;
89         static unsigned int error_count = 0;
90
91         if (__conn)
92                 return __conn;
93
94         __conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
95         if (!__conn) {
96                 error_count++;
97                 if (error_count < GET_CONNECTION_ERROR_THRESHOLD ||
98                                 error_count % GET_CONNECTION_ERROR_MODULO == 0) {
99                         _E("g_bus_get_sync() is failed. error(%s)",
100                                 error ? error->message : "Unknown");
101                 }
102
103                 g_clear_error(&error);
104                 return NULL;
105         }
106
107         return __conn;
108 }
109
110 static int __emit_signal(const char *path,
111                 const char *interface,
112                 const char *signal,
113                 GVariant *param)
114 {
115         GDBusConnection *conn;
116         GError *error = NULL;
117         gboolean ret;
118
119         conn = __get_connection();
120         if (!conn)
121                 return -1;
122
123         ret = g_dbus_connection_emit_signal(conn,
124                         NULL,
125                         path,
126                         interface,
127                         signal,
128                         param,
129                         &error);
130         if (ret != TRUE) {
131                 _E("g_dbus_connection_emit_signal() is failed. error(%s)",
132                                 error ? error->message : "Unknown");
133                 g_clear_error(&error);
134                 return -1;
135         }
136
137         ret = g_dbus_connection_flush_sync(conn, NULL, &error);
138         if (ret != TRUE) {
139                 _E("g_dbus_connection_flush_sync() is failed. error(%s)",
140                                 error ? error->message : "Unknown");
141                 g_clear_error(&error);
142                 return -1;
143         }
144
145         return 0;
146 }
147
148 static int __emit_app_launch_signal(int pid, const char *app_id)
149 {
150         int ret;
151
152         ret = __emit_signal(AUL_DBUS_PATH,
153                         AUL_DBUS_SIGNAL_INTERFACE,
154                         AUL_DBUS_APPLAUNCH_SIGNAL,
155                         g_variant_new("(us)", pid, app_id));
156         if (ret < 0)
157                 return ret;
158
159         _D("App launch. pid(%d), app_id(%s)", pid, app_id);
160
161         return 0;
162 }
163
164 static int __emit_app_dead_signal(int pid)
165 {
166         int ret;
167
168         ret = __emit_signal(AUL_DBUS_PATH,
169                         AUL_DBUS_SIGNAL_INTERFACE,
170                         AUL_DBUS_APPDEAD_SIGNAL,
171                         g_variant_new("(u)", pid));
172         if (ret < 0)
173                 return ret;
174
175         _D("App dead. pid(%d)", pid);
176
177         return 0;
178 }
179
180 static gboolean __flush_pending_item(gpointer data)
181 {
182         pending_item_t *item;
183         GList *iter;
184         int ret;
185
186         if (!__pending_items) {
187                 __timer = 0;
188                 return G_SOURCE_REMOVE;
189         }
190
191         iter = __pending_items;
192         while (iter) {
193                 item = (pending_item_t *)iter->data;
194                 if (item->app_signal == APP_SIGNAL_DEAD)
195                         ret = __emit_app_dead_signal(item->pid);
196                 else
197                         ret = __emit_app_launch_signal(item->pid, item->app_id);
198
199                 if (ret < 0)
200                         return G_SOURCE_CONTINUE;
201
202                 iter = g_list_next(iter);
203                 __pending_items = g_list_remove(__pending_items, item);
204                 __destroy_pending_item(item);
205         }
206
207         __timer = 0;
208         return G_SOURCE_REMOVE;
209 }
210
211 static void __set_pending_item_timer(void)
212 {
213         if (__timer)
214                 return;
215
216         __timer = g_timeout_add(PENDING_ITEM_INTERVAL,
217                         __flush_pending_item, NULL);
218 }
219
220 static void __unset_pending_item_timer(void)
221 {
222         if (!__timer)
223                 return;
224
225         g_source_remove(__timer);
226         __timer = 0;
227 }
228
229 int _dbus_send_app_launch_signal(int pid, const char *app_id)
230 {
231         pending_item_t *item;
232         int ret;
233
234         if (pid <= 1 || !app_id) {
235                 _E("Invalid parameter");
236                 return -EINVAL;
237         }
238
239         ret = __emit_app_launch_signal(pid, app_id);
240         if (ret < 0) {
241                 item = __create_pending_item(app_id, pid, APP_SIGNAL_LAUNCH);
242                 if (!item)
243                         return -ENOMEM;
244
245                 _W("Pend app launch signal. pid(%d), app_id(%s)", pid, app_id);
246                 __pending_items = g_list_append(__pending_items, item);
247                 __set_pending_item_timer();
248         }
249
250         return 0;
251 }
252
253 int _dbus_send_app_dead_signal(int pid)
254 {
255         pending_item_t *item;
256         int ret;
257
258         if (pid <= 1) {
259                 _E("Invalid parameter");
260                 return -EINVAL;
261         }
262
263         ret = __emit_app_dead_signal(pid);
264         if (ret < 0) {
265                 item = __create_pending_item(NULL, pid, APP_SIGNAL_DEAD);
266                 if (!item)
267                         return -ENOMEM;
268
269                 _W("Pend app dead signal. pid(%d)", pid);
270                 __pending_items = g_list_append(__pending_items, item);
271                 __set_pending_item_timer();
272         }
273
274         return 0;
275 }
276
277 int _dbus_init(void)
278 {
279         GDBusConnection *conn;
280
281         _D("DBUS_INIT");
282         conn = __get_connection();
283         if (!conn)
284                 return -1;
285
286         return 0;
287 }
288
289 void _dbus_fini(void)
290 {
291         _D("DBUS_FINI");
292         if (__pending_items)
293                 g_list_free_full(__pending_items, __destroy_pending_item);
294
295         __unset_pending_item_timer();
296
297         if (__conn)
298                 g_object_unref(__conn);
299 }