src/launchpad_signal.c
src/launchpad_config.c
src/launchpad_io_channel.c
+ src/launchpad_inotify.c
)
ADD_EXECUTABLE(${LAUNCHPAD_PROCESS_POOL} ${${LAUNCHPAD_PROCESS_POOL}_SOURCE_FILES})
#define PAD_CMD_DEMAND 14
#define PAD_CMD_PING 15
#define PAD_CMD_UPDATE_APP_TYPE 16
+#define PAD_CMD_PREPARE_APP_DEFINED_LOADER 17
#define LAUNCHPAD_LAUNCH_SIGNAL 83
#define LAUNCHPAD_DEAD_SIGNAL 61
--- /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.
+ */
+
+#pragma once
+
+#include <stdbool.h>
+#include <sys/inotify.h>
+
+typedef struct inotify_watch_info_s *inotify_watch_info_h;
+
+typedef bool (*inotify_watch_cb)(const char *event_name, uint32_t mask,
+ void *data);
+
+int _inotify_add_watch(const char *path, uint32_t mask,
+ inotify_watch_cb callback, void *data);
+
+void _inotify_rm_watch(inotify_watch_info_h handle);
+
+int _inotify_init(void);
+
+void _inotify_fini(void);
typedef void (*loader_info_foreach_cb)(loader_info_t *info, void *data);
-GList *_loader_info_load(const char *path);
+GList *_loader_info_load_dir(const char *path);
+GList *_loader_info_load_file(GList *list, const char *path);
+GList *_loader_info_unload(GList *list, const char *loader_name);
void _loader_info_dispose(GList *info);
int _loader_info_find_type(GList *info, const char *app_type, bool hwacc);
int _loader_info_find_type_by_loader_name(GList *info, const char *loader_name);
+const char* _loader_info_find_loader_path_by_loader_name(GList *info, const char *loader_name);
+const loader_info_t* _loader_info_find_loader_by_loader_name(GList *info, const char *loader_name);
int *_loader_get_alternative_types(GList *info, int type, int *len);
int _loader_info_foreach(GList *info, loader_info_foreach_cb callback,
void *data);
#include "launchpad_types.h"
#include "loader_info.h"
#include "perf.h"
+#include "launchpad_inotify.h"
#define AUL_PR_NAME 16
#define EXEC_CANDIDATE_EXPIRED 5
#define LAUNCHPAD_LOGGER_SOCK ".launchpad-logger-sock"
#define LOADER_PATH_DEFAULT "/usr/bin/launchpad-loader"
#define LOADER_INFO_PATH "/usr/share/aul"
+#define OPT_SHARE_PATH "/opt/share"
+#define LOADERS_PATH "loaders"
+#define APP_DEFINED_LOADER_INFO_PATH OPT_SHARE_PATH "/" LOADERS_PATH
+#define COMMON_LOADER_NAME "common-loader1"
+
#define LAUNCHER_INFO_PATH LOADER_INFO_PATH
#define REGULAR_UID_MIN 5000
#define PAD_ERR_FAILED -1
static int __sys_hwacc;
static GList *loader_info_list;
+static GList *app_defined_loader_info_list;
static int user_slot_offset;
static GList *candidate_slot_list;
static app_labels_monitor *label_monitor;
static void __dispose_candidate_process(candidate_process_context_t *cpc);
static bool __is_low_memory(void);
static void __update_slot_state(candidate_process_context_t *cpc, int method);
+static void __init_app_defined_loader_monitor(void);
static gboolean __handle_queuing_slots(gpointer data)
{
return -1;
}
+static int __dispatch_cmd_add_app_defined_loader(bundle *kb)
+{
+ const char *loader_name;
+ const char *loader_path;
+ int lid, len;
+ candidate_process_context_t *cpc;
+ const loader_info_t *info;
+ bundle_raw *extra;
+
+ _W("cmd add defined loader");
+ loader_name = bundle_get_val(kb, AUL_K_LOADER_NAME);
+
+ if (loader_name == NULL) {
+ _E("loader_name is NULL");
+ return -1;
+ }
+
+ loader_path = _loader_info_find_loader_path_by_loader_name(
+ loader_info_list, COMMON_LOADER_NAME);
+ info = _loader_info_find_loader_by_loader_name(
+ app_defined_loader_info_list, loader_name);
+
+ if (loader_path == NULL || info == NULL || info->extra == NULL) {
+ _E("loader_name %s, loader_path %d, info %d",
+ loader_name, loader_path != NULL, info != NULL);
+ return -1;
+ }
+
+ bundle_encode(info->extra, &extra, &len);
+
+ lid = __make_loader_id();
+ cpc = __add_slot(LAUNCHPAD_TYPE_DYNAMIC, lid, 0,
+ loader_path, (const char *)extra,
+ METHOD_TIMEOUT | METHOD_VISIBILITY,
+ METHOD_REQUEST | METHOD_AVAILABLE_MEMORY,
+ METHOD_TTL | METHOD_OUT_OF_MEMORY,
+ info->ttl,
+ 2000,
+ DEFAULT_CPU_THRESHOLD_MAX,
+ DEFAULT_CPU_THRESHOLD_MIN,
+ false,
+ true, 0);
+
+ if (cpc == NULL) {
+ _E("cpc is NULL");
+ bundle_free_encoded_rawdata(&extra);
+ return -1;
+ }
+
+ __prepare_candidate_process(LAUNCHPAD_TYPE_DYNAMIC, lid);
+
+ return lid;
+}
+
static int __dispatch_cmd_remove_loader(bundle *kb)
{
const char *id = bundle_get_val(kb, AUL_K_LOADER_ID);
__real_send(clifd, ret);
clifd = -1;
goto end;
+ case PAD_CMD_PREPARE_APP_DEFINED_LOADER:
+ ret = __dispatch_cmd_add_app_defined_loader(kb);
+ __real_send(clifd, ret);
+ clifd = -1;
+ goto end;
case PAD_CMD_DEMAND:
ret = __dispatch_cmd_hint(kb, METHOD_DEMAND);
__real_send(clifd, ret);
return 0;
}
+static bool __on_directory_create(const char *event_name, uint32_t mask,
+ void *user_data)
+{
+ if (!event_name) {
+ _E("Invalid parameter");
+ return true;
+ }
+
+ if (!strcmp(event_name, LOADERS_PATH)) {
+ __init_app_defined_loader_monitor();
+ return false;
+ }
+
+ return true;
+}
+
+static bool __on_file_change(const char *event_name, uint32_t mask,
+ void *user_data)
+{
+ char buf[PATH_MAX];
+ char *ext;
+ if (!event_name) {
+ _E("Invalid parameter");
+ return true;
+ }
+
+ ext = strrchr(event_name, '.');
+ if (ext == NULL || strcmp(ext, ".loader") != 0)
+ return true;
+
+ if (mask & IN_CREATE) {
+ snprintf(buf, sizeof(buf), "%s/%s",
+ APP_DEFINED_LOADER_INFO_PATH, event_name);
+ app_defined_loader_info_list = _loader_info_load_file(
+ app_defined_loader_info_list, buf);
+ } else if (mask & IN_DELETE) {
+ snprintf(buf, ext - event_name, "%s", event_name);
+ app_defined_loader_info_list = _loader_info_unload(
+ app_defined_loader_info_list, buf);
+ }
+
+ return true;
+}
+
+static void __init_app_defined_loader_monitor(void)
+{
+ int ret;
+
+ ret = access(APP_DEFINED_LOADER_INFO_PATH, F_OK);
+ if (ret < 0) {
+ _W("Failed to access %s", APP_DEFINED_LOADER_INFO_PATH);
+ ret = _inotify_add_watch(OPT_SHARE_PATH,
+ IN_CREATE, __on_directory_create, NULL);
+ if (ret != 0)
+ _E("Failed to add inotify watch %s", OPT_SHARE_PATH);
+
+ return;
+ }
+
+ ret = _inotify_add_watch(APP_DEFINED_LOADER_INFO_PATH,
+ IN_CREATE | IN_DELETE, __on_file_change, NULL);
+
+ if (ret < 0) {
+ _E("Failed to add inotify watch %s",
+ APP_DEFINED_LOADER_INFO_PATH);
+ }
+
+ return;
+
+}
+
static int __init_label_monitor_fd(void)
{
int r;
if (loader_info_list)
_loader_info_dispose(loader_info_list);
- loader_info_list = _loader_info_load(LOADER_INFO_PATH);
+ loader_info_list = _loader_info_load_dir(LOADER_INFO_PATH);
if (loader_info_list == NULL)
return -1;
return 0;
}
+static void __add_app_defined_loaders(void)
+{
+ app_defined_loader_info_list = _loader_info_load_dir(APP_DEFINED_LOADER_INFO_PATH);
+}
+
static bool __is_low_memory(void)
{
if (__memory_status_low >= MEMORY_STATUS_LOW)
if (ret != 0)
_W("Failed to initialize config");
+ _inotify_init();
+
__add_default_slots();
launcher_info_list = _launcher_info_load(LAUNCHER_INFO_PATH);
+ __add_app_defined_loaders();
+
ret = _send_cmd_to_amd(LAUNCHPAD_LAUNCH_SIGNAL);
if (ret < 0)
_W("Failed to send cmd(%d) to amd", LAUNCHPAD_LAUNCH_SIGNAL);
}
__register_vconf_events();
+ __init_app_defined_loader_monitor();
return 0;
}
_debug_fini();
_launcher_info_unload(launcher_info_list);
_config_fini();
+ _inotify_fini();
+ _loader_info_dispose(app_defined_loader_info_list);
if (__label_monitor_channel)
_io_channel_destroy(__label_monitor_channel);
--- /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 <string.h>
+#include <stdlib.h>
+#include <sys/inotify.h>
+#include <glib.h>
+#include <gio/gio.h>
+
+#include "launchpad_inotify.h"
+#include "log_private.h"
+
+struct inotify_watch_info_s {
+ int fd;
+ int wd;
+ GIOChannel *io;
+ guint tag;
+ uint32_t mask;
+ inotify_watch_cb cb;
+ void *data;
+};
+
+static GList *__watch_list;
+
+static gboolean __inotify_cb(GIOChannel *source, GIOCondition condition,
+ gpointer data)
+{
+#define ALIGN_INOTIFY_EVENT \
+ __attribute__ ((aligned(__alignof__(struct inotify_event))))
+#define SIZE_INOTIFY_EVENT (sizeof(struct inotify_event))
+ int fd = g_io_channel_unix_get_fd(source);
+ char buf[4096] ALIGN_INOTIFY_EVENT;
+ const struct inotify_event *event;
+ struct inotify_watch_info_s *info = data;
+ ssize_t len;
+ char *ptr;
+ char *nptr;
+
+ while ((len = read(fd, buf, sizeof(buf))) > 0) {
+ for (ptr = buf; ptr < buf + len;
+ ptr += sizeof(struct inotify_event) + event->len) {
+ if ((ptr + SIZE_INOTIFY_EVENT) > (buf + len))
+ break;
+
+ event = (const struct inotify_event *)ptr;
+ nptr = ptr + sizeof(struct inotify_event) + event->len;
+ if (nptr > buf + len)
+ break;
+
+ if (event->mask & info->mask) {
+ if (!info->cb(event->name, event->mask,
+ info->data)) {
+ _inotify_rm_watch(info);
+ return G_SOURCE_CONTINUE;
+ }
+ }
+ }
+ }
+
+ return G_SOURCE_CONTINUE;
+}
+
+static void __destroy_inotify_watch_info(gpointer data)
+{
+ struct inotify_watch_info_s *info = (struct inotify_watch_info_s *)data;
+
+ if (info == NULL)
+ return;
+
+ if (info->tag > 0)
+ g_source_remove(info->tag);
+
+ if (info->io)
+ g_io_channel_unref(info->io);
+
+ if (info->wd > 0)
+ inotify_rm_watch(info->fd, info->wd);
+
+ if (info->fd > 0)
+ close(info->fd);
+
+ free(info);
+}
+
+static struct inotify_watch_info_s *__create_inotify_watch_info(
+ const char *path, uint32_t mask, inotify_watch_cb cb,
+ void *data)
+{
+ GIOCondition cond = G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP;
+ struct inotify_watch_info_s *info;
+
+ info = calloc(1, sizeof(struct inotify_watch_info_s));
+ if (info == NULL) {
+ _E("Out of memory");
+ return NULL;
+ }
+
+ info->fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
+ if (info->fd < 0) {
+ _E("inotify_init1() is failed. errno(%d)", errno);
+ __destroy_inotify_watch_info(info);
+ return NULL;
+ }
+
+ info->wd = inotify_add_watch(info->fd, path, mask);
+ if (info->wd < 0) {
+ _E("inotify_add_watch() is failed. path(%s), errno(%d)",
+ path, errno);
+ __destroy_inotify_watch_info(info);
+ return NULL;
+ }
+
+ info->io = g_io_channel_unix_new(info->fd);
+ if (!info->io) {
+ _E("g_io_channel_unix_new() is failed");
+ __destroy_inotify_watch_info(info);
+ return NULL;
+ }
+
+ info->tag = g_io_add_watch(info->io, cond,
+ __inotify_cb, info);
+ if (!info->tag) {
+ _E("g_io_add_watch() is failed");
+ __destroy_inotify_watch_info(info);
+ return NULL;
+ }
+
+ info->mask = mask;
+ info->cb = cb;
+ info->data = data;
+
+ return info;
+}
+
+int _inotify_add_watch(const char *path, uint32_t mask,
+ inotify_watch_cb callback, void *data)
+{
+ struct inotify_watch_info_s *info;
+
+ if (path == NULL || callback == NULL) {
+ _E("Invalid parameter");
+ return -1;
+ }
+
+ info = __create_inotify_watch_info(path, mask, callback, data);
+ if (info == NULL)
+ return -1;
+
+ __watch_list = g_list_append(__watch_list, info);
+
+ return 0;
+}
+
+void _inotify_rm_watch(inotify_watch_info_h handle)
+{
+ if (handle == NULL)
+ return;
+
+ __watch_list = g_list_remove(__watch_list, handle);
+ __destroy_inotify_watch_info(handle);
+}
+
+int _inotify_init(void)
+{
+ _D("inotify init");
+
+ return 0;
+}
+
+void _inotify_fini(void)
+{
+ _D("inotify fini");
+
+ if (__watch_list)
+ g_list_free_full(__watch_list, __destroy_inotify_watch_info);
+}
#define VAL_METHOD_TTL "TTL"
#define VAL_METHOD_OUT_OF_MEMORY "OUT_OF_MEMORY"
+static int __comp_name(gconstpointer a, gconstpointer b);
+static void __free_info(gpointer data);
+
static loader_info_t *__create_loader_info()
{
loader_info_t *info;
return list;
}
-GList *_loader_info_load(const char *path)
+GList *_loader_info_load_dir(const char *path)
{
DIR *dir_info;
struct dirent *entry = NULL;
return list;
}
+GList *_loader_info_load_file(GList *list, const char *path)
+{
+ return __parse_file(list, path);
+}
+
+GList *_loader_info_unload(GList *list, const char *loader_name)
+{
+ GList *cur;
+ loader_info_t *info;
+
+ cur = g_list_find_custom(list, loader_name, __comp_name);
+ if (cur == NULL)
+ return list;
+
+ info = cur->data;
+
+ list = g_list_remove(list, info);
+ __free_info(info);
+
+ return list;
+}
+
+const char* _loader_info_find_loader_path_by_loader_name(GList *list, const char *loader_name)
+{
+ GList *cur;
+ loader_info_t *info;
+
+ cur = g_list_find_custom(list, loader_name, __comp_name);
+ if (cur == NULL)
+ return NULL;
+
+ info = cur->data;
+
+ return info->exe;
+}
+
+const loader_info_t* _loader_info_find_loader_by_loader_name(GList *list, const char *loader_name)
+{
+ GList *cur;
+ loader_info_t *info;
+
+ cur = g_list_find_custom(list, loader_name, __comp_name);
+ if (cur == NULL)
+ return NULL;
+
+ info = cur->data;
+
+ return info;
+}
+
static void __free_info(gpointer data)
{
loader_info_t *info;