2 * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 #include <sys/types.h>
26 #include "launchpad_common.h"
27 #include "launchpad_signal.h"
29 #define AUL_DBUS_PATH "/aul/dbus_handler"
30 #define AUL_DBUS_SIGNAL_INTERFACE "org.tizen.aul.signal"
31 #define AUL_DBUS_APPDEAD_SIGNAL "app_dead"
32 #define AUL_DBUS_APPLAUNCH_SIGNAL "app_launch"
33 #define PENDING_SIGNAL_INTERVAL 1000
40 struct pending_signal {
46 static GDBusConnection *bus;
47 static sigset_t oldmask;
48 static GList *pending_signal_list;
49 static guint timeout_handle;
51 static int __send_app_dead_signal(int dead_pid);
52 static int __send_app_launch_signal(int launch_pid, const char *app_id);
54 static struct pending_signal *__create_pending_signal(const char *appid,
55 const int pid, const int signal)
57 struct pending_signal *handle;
59 handle = (struct pending_signal *)calloc(1,
60 sizeof(struct pending_signal));
67 handle->appid = strdup(appid);
68 if (handle->appid == NULL) {
76 handle->signal = signal;
81 static void __destroy_pending_signal(struct pending_signal *handle)
91 static gboolean __flush_pending_signal(gpointer data)
93 struct pending_signal *handle;
97 if (pending_signal_list == NULL) {
102 iter = g_list_first(pending_signal_list);
104 handle = (struct pending_signal *)iter->data;
105 iter = g_list_next(iter);
107 if (handle->signal == APP_DEAD) {
108 ret = __send_app_dead_signal(handle->pid);
110 ret = __send_app_launch_signal(handle->pid,
116 pending_signal_list = g_list_remove(pending_signal_list,
118 __destroy_pending_signal(handle);
127 static void __socket_garbage_collector(void)
130 struct dirent *dentry = NULL;
131 char tmp[MAX_LOCAL_BUFSZ];
133 snprintf(tmp, sizeof(tmp), "/run/aul/apps/%d", getuid());
138 while ((dentry = readdir(dp)) != NULL) {
139 if (!isdigit(dentry->d_name[0]))
142 snprintf(tmp, MAX_LOCAL_BUFSZ, "/proc/%s", dentry->d_name);
143 if (access(tmp, F_OK) < 0) { /* Flawfinder: ignore */
144 _delete_sock_path(atoi(dentry->d_name), getuid());
151 static int __send_app_dead_signal(int dead_pid)
155 /* send over session dbus for other applications */
157 bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
159 _E("Failed to connect to the D-BUS daemon: %s",
166 if (g_dbus_connection_emit_signal(bus,
169 AUL_DBUS_SIGNAL_INTERFACE,
170 AUL_DBUS_APPDEAD_SIGNAL,
171 g_variant_new("(u)", dead_pid),
173 _E("g_dbus_connection_emit_signal() is failed: %s",
179 if (g_dbus_connection_flush_sync(bus, NULL, &err) == FALSE) {
180 _E("g_dbus_connection_flush_sync() is failed: %s",
186 _D("send_app_dead_signal_dbus done (pid=%d)", dead_pid);
191 static int __send_app_launch_signal(int launch_pid, const char *app_id)
197 bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
199 _E("Failed to connect to the D-BUS daemon: %s",
206 param = g_variant_new("(us)", launch_pid, app_id);
207 if (g_dbus_connection_emit_signal(bus,
210 AUL_DBUS_SIGNAL_INTERFACE,
211 AUL_DBUS_APPLAUNCH_SIGNAL,
214 _E("g_dbus_connection_emit_signal() is failed: %s",
220 if (g_dbus_connection_flush_sync(bus, NULL, &err) == FALSE) {
221 _E("g_dbus_connection_flush_sync() is failed: %s",
227 _D("send_app_launch_signal_dbus done (pid=%d)", launch_pid);
232 int _signal_send_app_launch_signal(int launch_pid, const char *app_id)
235 struct pending_signal *handle;
237 ret = __send_app_launch_signal(launch_pid, app_id);
239 handle = __create_pending_signal(app_id, launch_pid,
241 pending_signal_list = g_list_append(pending_signal_list,
243 if (timeout_handle == 0) {
244 timeout_handle = g_timeout_add(PENDING_SIGNAL_INTERVAL,
245 __flush_pending_signal, NULL);
253 static int __sigchild_action(pid_t dead_pid)
256 struct pending_signal *handle;
261 ret = __send_app_dead_signal(dead_pid);
263 handle = __create_pending_signal(NULL, dead_pid, APP_DEAD);
264 pending_signal_list = g_list_append(pending_signal_list,
266 if (timeout_handle == 0) {
267 timeout_handle = g_timeout_add(PENDING_SIGNAL_INTERVAL,
268 __flush_pending_signal, NULL);
272 _delete_sock_path(dead_pid, getuid());
273 __socket_garbage_collector();
278 void _signal_process_sigchld(struct signalfd_siginfo *info)
284 child_pgid = getpgid(info->ssi_pid);
285 _D("dead_pid = %d pgid = %d signo = %d status = %d", info->ssi_pid,
286 child_pgid, info->ssi_signo, info->ssi_status);
288 while ((child_pid = waitpid(-1, &status, WNOHANG)) > 0) {
289 if (child_pid == child_pgid)
290 killpg(child_pgid, SIGKILL);
291 __sigchild_action(child_pid);
295 int _signal_init(void)
298 GError *error = NULL;
300 bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
302 _E("Failed to connect to the D-BUS daemon: %s", error->message);
306 for (i = 0; i < _NSIG; i++) {
308 /* controlled by sys-assert package*/
326 int _signal_get_sigchld_fd(void)
332 sigaddset(&mask, SIGCHLD);
334 if (sigprocmask(SIG_BLOCK, &mask, &oldmask) == -1)
335 _E("failed to sigprocmask");
337 sfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
339 _E("failed to create signal for SIGCHLD");
346 int _signal_unblock_sigchld(void)
348 if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) {
349 _E("SIG_SETMASK error");
353 _D("SIGCHLD unblocked");
357 void _signal_fini(void)
359 #ifndef PRELOAD_ACTIVATE
362 for (i = 0; i < _NSIG; i++)