#include "launchpad_common.h"
#include "launchpad_config.h"
#include "launchpad_debug.h"
+#include "launchpad_io_channel.h"
#include "launchpad_signal.h"
#include "launchpad_types.h"
#include "loader_info.h"
int send_fd;
int hydra_fd;
int last_exec_time;
- guint source;
guint timer;
char *loader_path;
char *loader_extra;
guint live_timer;
int state;
bool is_hydra;
- guint pollfd;
- guint hydra_pollfd;
+ io_channel_h client_channel;
+ io_channel_h channel;
+ io_channel_h hydra_channel;
} candidate_process_context_t;
typedef struct {
static int MEMORY_STATUS_LOW;
static int MEMORY_STATUS_NORMAL;
+static io_channel_h __logger_channel;
+static io_channel_h __label_monitor_channel;
+static io_channel_h __sigchild_channel;
+static io_channel_h __launchpad_channel;
+
static candidate_process_context_t *__add_slot(int type, int loader_id,
int caller_pid, const char *loader_path, const char *extra,
int detection_method, int activation_method,
cpc->send_fd = -1;
cpc->prepared = false;
cpc->pid = CANDIDATE_NONE;
- cpc->source = 0;
+ cpc->client_channel = NULL;
cpc->timer = 0;
cpc->live_timer = 0;
}
}
if (cpc->live_timer > 0)
g_source_remove(cpc->live_timer);
- if (cpc->source > 0)
- g_source_remove(cpc->source);
+ if (cpc->client_channel)
+ _io_channel_destroy(cpc->client_channel);
if (cpc->timer > 0)
g_source_remove(cpc->timer);
if (cpc->send_fd > 0)
return fd;
}
-static void __destroy_poll_data(gpointer data)
-{
- free(data);
-}
-
-static gboolean __glib_check(GSource *src)
-{
- GSList *fd_list;
- GPollFD *tmp;
-
- fd_list = src->poll_fds;
- do {
- tmp = (GPollFD *) fd_list->data;
- if ((tmp->revents & (G_IO_IN | G_IO_PRI | G_IO_HUP |
- G_IO_NVAL)))
- return TRUE;
- fd_list = fd_list->next;
- } while (fd_list);
-
- return FALSE;
-}
-
-static gboolean __glib_dispatch(GSource *src, GSourceFunc callback,
- gpointer data)
-{
- return callback(data);
-}
-
-static gboolean __glib_prepare(GSource *src, gint *timeout)
-{
- return FALSE;
-}
-
-static void __glib_finalize(GSource *src)
-{
- GSList *fd_list;
- GPollFD *gpollfd;
-
- fd_list = src->poll_fds;
- do {
- gpollfd = (GPollFD *)fd_list->data;
- close(gpollfd->fd);
- g_free(gpollfd);
-
- fd_list = fd_list->next;
- } while (fd_list);
-}
-
-static GSourceFuncs funcs = {
- .prepare = __glib_prepare,
- .check = __glib_check,
- .dispatch = __glib_dispatch,
- .finalize = __glib_finalize
-};
-
-static guint __poll_fd(int fd, gushort events, GSourceFunc func, int type,
- int loader_id)
+static bool __handle_loader_client_event(int fd, io_condition_e cond,
+ void *data)
{
- int r;
- GPollFD *gpollfd;
- GSource *src;
- loader_context_t *lc;
-
- src = g_source_new(&funcs, sizeof(GSource));
- if (!src) {
- _E("out of memory");
- return 0;
- }
-
- gpollfd = (GPollFD *)g_malloc(sizeof(GPollFD));
- if (!gpollfd) {
- _E("out of memory");
- g_source_destroy(src);
- return 0;
- }
-
- gpollfd->events = events;
- gpollfd->fd = fd;
-
- lc = malloc(sizeof(loader_context_t));
- if (lc == NULL) {
- g_free(gpollfd);
- g_source_destroy(src);
- return 0;
- }
-
- lc->gpollfd = gpollfd;
- lc->type = type;
- lc->loader_id = loader_id;
-
- g_source_add_poll(src, gpollfd);
- g_source_set_callback(src, func,
- (gpointer) lc, __destroy_poll_data);
- g_source_set_priority(src, G_PRIORITY_DEFAULT);
-
- r = g_source_attach(src, NULL);
- if (r == 0) {
- g_free(gpollfd);
- g_source_destroy(src);
- return 0;
- }
-
- return r;
-}
-
-static gboolean __handle_loader_client_event(gpointer data)
-{
- loader_context_t *lc = (loader_context_t *) data;
- int type = lc->type;
- int loader_id = lc->loader_id;
- gushort revents = lc->gpollfd->revents;
- candidate_process_context_t *cpc = __find_slot(type, loader_id);
+ candidate_process_context_t *cpc = data;
if (cpc == NULL)
- return G_SOURCE_REMOVE;
+ return false;
- if (revents & (G_IO_HUP | G_IO_NVAL)) {
- SECURE_LOGE("Type %d candidate process was " \
+ if (cond & (IO_HUP | IO_NVAL)) {
+ SECURE_LOGE("Type %d candidate process was "
"(POLLHUP|POLLNVAL), pid: %d",
cpc->type, cpc->pid);
cpc->pid = CANDIDATE_NONE;
__dispose_candidate_process(cpc);
__prepare_candidate_process(cpc->type, cpc->loader_id);
- return G_SOURCE_REMOVE;
+ return false;
}
- return G_SOURCE_CONTINUE;
+ return true;
+
}
-static gboolean __handle_hydra_client_event(gpointer data)
+static bool __handle_hydra_client_event(int fd, io_condition_e cond,
+ void *data)
{
- loader_context_t *lc = (loader_context_t *)data;
- int type = lc->type;
- int loader_id = lc->loader_id;
- gushort revents = lc->gpollfd->revents;
- candidate_process_context_t *cpc = __find_slot(type, loader_id);
+ candidate_process_context_t *cpc = data;
if (cpc == NULL)
- return G_SOURCE_REMOVE;
+ return false;
- if (revents & (G_IO_HUP | G_IO_NVAL)) {
- SECURE_LOGE("Type %d hydra process was " \
+ if (cond & (IO_HUP | IO_NVAL)) {
+ SECURE_LOGE("Type %d hydra process was "
"(POLLHUP|POLLNVAL), pid: %d",
cpc->type, cpc->hydra_pid);
__dispose_hydra_process(cpc);
__prepare_candidate_process(cpc->type, cpc->loader_id);
- return G_SOURCE_REMOVE;
+ return false;
}
- return G_SOURCE_CONTINUE;
+ return true;
}
-static gboolean __handle_loader_event(gpointer data)
+static bool __handle_loader_event(int fd, io_condition_e cond, void *data)
{
- loader_context_t *lc = (loader_context_t *) data;
- int fd = lc->gpollfd->fd;
- int type = lc->type;
- int loader_id = lc->loader_id;
+ candidate_process_context_t *cpc = data;
int client_fd;
int client_pid;
int ret;
- candidate_process_context_t *cpc = __find_slot(type, loader_id);
-
if (cpc == NULL)
- return G_SOURCE_REMOVE;
+ return false;
if (!cpc->prepared) {
ret = __accept_candidate_process(fd, &client_fd, &client_pid);
cpc->prepared = true;
cpc->send_fd = client_fd;
- SECURE_LOGD("Type %d candidate process was connected," \
- " pid: %d", type, cpc->pid);
- cpc->source = __poll_fd(client_fd, G_IO_IN | G_IO_HUP,
- __handle_loader_client_event, type,
- loader_id);
- if (cpc->source == 0)
+ SECURE_LOGD("Type %d candidate process was connected, "
+ "pid: %d", cpc->type, cpc->pid);
+ cpc->client_channel = _io_channel_create(client_fd,
+ IO_IN | IO_HUP,
+ __handle_loader_client_event,
+ cpc);
+ if (!cpc->client_channel)
close(client_fd);
}
} else {
_E("Refused candidate process connection");
}
- return G_SOURCE_CONTINUE;
+ return true;
}
-static gboolean __handle_hydra_event(gpointer data)
+static bool __handle_hydra_event(int fd, io_condition_e cond, void *data)
{
- loader_context_t *lc = (loader_context_t *) data;
- int fd = lc->gpollfd->fd;
- int type = lc->type;
- int loader_id = lc->loader_id;
+ candidate_process_context_t *cpc = data;
int client_fd;
int client_pid;
int ret;
- candidate_process_context_t *cpc = __find_slot(type, loader_id);
-
if (cpc == NULL)
- return G_SOURCE_REMOVE;
+ return false;
if (!cpc->prepared) {
ret = __accept_candidate_process(fd, &client_fd, &client_pid);
if (ret >= 0) {
cpc->hydra_fd = client_fd;
- SECURE_LOGD("Type %d hydra process was connected," \
- " pid: %d", type, cpc->hydra_pid);
+ SECURE_LOGD("Type %d hydra process was connected,"
+ " pid: %d", cpc->type, cpc->hydra_pid);
- cpc->source = __poll_fd(client_fd, G_IO_IN | G_IO_HUP,
- __handle_hydra_client_event, type,
- loader_id);
- if (cpc->source == 0)
+ cpc->client_channel = _io_channel_create(client_fd,
+ IO_IN | IO_HUP,
+ __handle_hydra_client_event,
+ cpc);
+ if (!cpc->client_channel)
close(client_fd);
}
} else {
_E("Refused hydra process connection");
}
- return G_SOURCE_CONTINUE;
+ return true;
}
-static gboolean __handle_sigchild(gpointer data)
+static bool __handle_sigchild(int fd, io_condition_e cond, void *data)
{
candidate_process_context_t *cpc;
- loader_context_t *lc = (loader_context_t *) data;
- int fd = lc->gpollfd->fd;
struct signalfd_siginfo siginfo;
ssize_t s;
char *appid;
}
} while (s > 0);
- return G_SOURCE_CONTINUE;
+ return true;
}
-static gboolean __handle_label_monitor(gpointer data)
+static bool __handle_label_monitor(int fd, io_condition_e cond, void *data)
{
candidate_process_context_t *cpc;
GList *iter = candidate_slot_list;
- _D("__handle_label_monitor()");
+ _D("%s()", __FUNCTION__);
security_manager_app_labels_monitor_process(label_monitor);
while (iter) {
iter = g_list_next(iter);
}
- return G_SOURCE_CONTINUE;
+ return true;
}
static float __interpolator(float input, int cpu_max, int cpu_min)
}
}
-static gboolean __handle_launch_event(gpointer data)
+static bool __handle_launch_event(int fd, io_condition_e cond, void *data)
{
- loader_context_t *lc = (loader_context_t *) data;
- int fd = lc->gpollfd->fd;
bundle *kb = NULL;
app_pkt_t *pkt = NULL;
appinfo_t *menu_info = NULL;
traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
- return G_SOURCE_CONTINUE;
+ return true;
}
static void __destroy_slot(candidate_process_context_t *cpc)
if (!cpc)
return;
- if (cpc->hydra_pollfd)
- g_source_remove(cpc->hydra_pollfd);
+ if (cpc->hydra_channel)
+ _io_channel_destroy(cpc->hydra_channel);
- if (cpc->pollfd)
- g_source_remove(cpc->pollfd);
+ if (cpc->channel)
+ _io_channel_destroy(cpc->channel);
if (cpc->loader_extra)
free(cpc->loader_extra);
cpc->send_fd = -1;
cpc->hydra_fd = -1;
cpc->last_exec_time = 0;
- cpc->source = 0;
cpc->timer = 0;
cpc->detection_method = detection_method;
cpc->timeout_val = timeout_val;
{
candidate_process_context_t *cpc;
int fd;
- guint pollfd;
+ io_channel_h channel;
int hydra_fd;
- guint hydra_pollfd;
+ io_channel_h hydra_channel;
if (__find_slot(type, loader_id) != NULL)
return NULL;
return NULL;
}
- pollfd = __poll_fd(fd, G_IO_IN, (GSourceFunc)__handle_loader_event,
- cpc->type, cpc->loader_id);
- if (pollfd == 0) {
+ channel = _io_channel_create(fd, IO_IN, __handle_loader_event, cpc);
+ if (!channel) {
close(fd);
__destroy_slot(cpc);
return NULL;
}
- cpc->pollfd = pollfd;
+ cpc->channel = channel;
if (is_hydra) {
hydra_fd = __listen_hydra_process(cpc->type, cpc->loader_id);
_E("[launchpad] Listening the socket to " \
"the type %d hydra process failed.",
cpc->type);
- close(fd);
__destroy_slot(cpc);
return NULL;
}
- hydra_pollfd = __poll_fd(hydra_fd, G_IO_IN,
- (GSourceFunc)__handle_hydra_event,
- cpc->type, cpc->loader_id);
- if (hydra_pollfd == 0) {
+ hydra_channel = _io_channel_create(hydra_fd, IO_IN,
+ __handle_hydra_event, cpc);
+ if (!hydra_channel) {
close(hydra_fd);
- close(fd);
__destroy_slot(cpc);
return NULL;
}
- cpc->hydra_pollfd = hydra_pollfd;
+ cpc->hydra_channel = hydra_channel;
}
static int __init_launchpad_fd(int argc, char **argv)
{
int fd = -1;
- guint pollfd;
fd = __launchpad_pre_init(argc, argv);
if (fd < 0) {
return -1;
}
- pollfd = __poll_fd(fd, G_IO_IN, (GSourceFunc)__handle_launch_event, 0,
- 0);
- if (pollfd == 0) {
+ __launchpad_channel = _io_channel_create(fd, IO_IN,
+ __handle_launch_event, NULL);
+ if (!__launchpad_channel) {
close(fd);
return -1;
}
static int __init_sigchild_fd(void)
{
int fd = -1;
- guint pollfd;
fd = _signal_get_sigchld_fd();
if (fd < 0) {
return -1;
}
- pollfd = __poll_fd(fd, G_IO_IN, (GSourceFunc)__handle_sigchild, 0, 0);
- if (pollfd == 0) {
+ __sigchild_channel = _io_channel_create(fd, IO_IN,
+ __handle_sigchild, NULL);
+ if (!__sigchild_channel) {
close(fd);
return -1;
}
{
int r;
int fd = -1;
- guint pollfd;
r = security_manager_app_labels_monitor_init(&label_monitor);
if (r != SECURITY_MANAGER_SUCCESS)
goto err;
}
- pollfd = __poll_fd(fd, G_IO_IN,
- (GSourceFunc)__handle_label_monitor, 0, 0);
- if (pollfd == 0)
+ __label_monitor_channel = _io_channel_create(fd, IO_IN,
+ __handle_label_monitor, NULL);
+ if (!__label_monitor_channel)
goto err;
return 0;
return 0;
}
-static gboolean __handle_logger(gpointer data)
+static bool __handle_logger(int fd, io_condition_e cond, void *data)
{
- loader_context_t *lc = (loader_context_t *)data;
- int fd = lc->gpollfd->fd;
- app_pkt_t *pkt = NULL;
+ app_pkt_t *pkt;
struct ucred cr;
int clifd = -1;
pkt = _accept_recv_pkt_raw(fd, &clifd, &cr);
if (!pkt) {
_E("Failed to receive the packet");
- return G_SOURCE_CONTINUE;
+ return true;
}
if (getuid() != cr.uid) {
}
SECURE_LOGE("[%d] %s", cr.pid, (const char *)pkt->data);
-
end:
if (clifd != -1)
close(clifd);
- if (pkt)
- free(pkt);
- return G_SOURCE_CONTINUE;
+ free(pkt);
+
+ return true;
}
static int __init_logger_fd(void)
{
int fd;
- guint pollfd;
fd = _create_server_sock(LAUNCHPAD_LOGGER_SOCK);
if (fd < 0) {
return -1;
}
- pollfd = __poll_fd(fd, G_IO_IN, (GSourceFunc)__handle_logger, 0, 0);
- if (pollfd == 0) {
+ __logger_channel = _io_channel_create(fd, IO_IN, __handle_logger, NULL);
+ if (!__logger_channel) {
close(fd);
return -1;
}
_launcher_info_unload(launcher_info_list);
_config_fini();
+ if (__label_monitor_channel)
+ _io_channel_destroy(__label_monitor_channel);
+
if (label_monitor)
security_manager_app_labels_monitor_finish(label_monitor);
+ if (__logger_channel)
+ _io_channel_destroy(__logger_channel);
+
+ if (__launchpad_channel)
+ _io_channel_destroy(__launchpad_channel);
+
+ if (__sigchild_channel)
+ _io_channel_destroy(__sigchild_channel);
+
__sequencer_fini();
}
--- /dev/null
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <glib.h>
+#include <gio/gio.h>
+
+#include "launchpad_io_channel.h"
+#include "log_private.h"
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+
+struct io_channel_s {
+ GIOChannel *io;
+ guint tag;
+ int fd;
+ io_channel_event_cb callback;
+ void *user_data;
+};
+
+struct io_condition_s {
+ io_condition_e io_cond;
+ GIOCondition g_io_cond;
+};
+
+static struct io_condition_s __cond_map[] = {
+ {
+ .io_cond = IO_IN,
+ .g_io_cond = G_IO_IN
+ },
+ {
+ .io_cond = IO_OUT,
+ .g_io_cond = G_IO_OUT
+ },
+ {
+ .io_cond = IO_PRI,
+ .g_io_cond = G_IO_PRI
+ },
+ {
+ .io_cond = IO_ERR,
+ .g_io_cond = G_IO_ERR
+ },
+ {
+ .io_cond = IO_HUP,
+ .g_io_cond = G_IO_HUP
+ },
+ {
+ .io_cond = IO_NVAL,
+ .g_io_cond = G_IO_NVAL,
+ }
+};
+
+static io_condition_e __convert_g_io_condition(GIOCondition cond)
+{
+ io_condition_e condition = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(__cond_map); i++) {
+ if (__cond_map[i].g_io_cond & cond)
+ condition |= __cond_map[i].io_cond;
+ }
+
+ return condition;
+}
+
+static GIOCondition __convert_io_condition(io_condition_e cond)
+{
+ GIOCondition condition = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(__cond_map); i++) {
+ if (__cond_map[i].io_cond & cond)
+ condition |= __cond_map[i].g_io_cond;
+ }
+
+ return condition;
+}
+
+static gboolean __io_event_cb(GIOChannel *source, GIOCondition condition,
+ gpointer data)
+{
+ io_channel_h channel = (io_channel_h)data;
+ io_condition_e cond = __convert_g_io_condition(condition);
+
+ if (!channel->callback(channel->fd, cond, channel->user_data))
+ return G_SOURCE_REMOVE;
+
+ return G_SOURCE_CONTINUE;
+}
+
+io_channel_h _io_channel_create(int fd, io_condition_e cond,
+ io_channel_event_cb callback, void *user_data)
+{
+ struct io_channel_s *channel;
+
+ if (fd < 3 || !callback) {
+ _E("Invalid parameter");
+ return NULL;
+ }
+
+ channel = calloc(1, sizeof(struct io_channel_s));
+ if (!channel) {
+ _E("Out of memory");
+ return NULL;
+ }
+
+ channel->io = g_io_channel_unix_new(fd);
+ if (!channel->io) {
+ _E("Failed to create GIOChannel");
+ _io_channel_destroy(channel);
+ return NULL;
+ }
+
+ channel->tag = g_io_add_watch(channel->io, __convert_io_condition(cond),
+ __io_event_cb, channel);
+ if (!channel->tag) {
+ _E("Failed to add GIO watch");
+ _io_channel_destroy(channel);
+ return NULL;
+ }
+
+ channel->fd = fd;
+ channel->callback = callback;
+ channel->user_data = user_data;
+
+ return channel;
+}
+
+void _io_channel_destroy(io_channel_h channel)
+{
+ if (!channel)
+ return;
+
+ if (channel->tag)
+ g_source_remove(channel->tag);
+
+ if (channel->io)
+ g_io_channel_unref(channel->io);
+
+ if (channel->fd)
+ close(channel->fd);
+
+ free(channel);
+}