Add app-defined loader 61/224161/5
authorJusung Son <jusung07.son@samsung.com>
Fri, 7 Feb 2020 00:10:57 +0000 (09:10 +0900)
committerHwankyu Jhun <h.jhun@samsung.com>
Mon, 17 Feb 2020 09:21:45 +0000 (18:21 +0900)
Requires:
 - https://review.tizen.org/gerrit/#/c/platform/core/appfw/aul-1/+/224466/
 - https://review.tizen.org/gerrit/#/c/platform/core/appfw/amd/+/224634/
 - https://review.tizen.org/gerrit/#/c/platform/core/api/app-control/+/224798/
 - https://review.tizen.org/gerrit/#/c/platform/core/appfw/launchpad/+/224161/

Change-Id: I66ea0abec98fd387e91cf67a7f5db94e5d0234d0
Signed-off-by: Jusung Son <jusung07.son@samsung.com>
CMakeLists.txt [changed mode: 0755->0644]
inc/launchpad_common.h
inc/launchpad_inotify.h [new file with mode: 0644]
inc/loader_info.h
inc/preexec.h [changed mode: 0755->0644]
src/launchpad.c [changed mode: 0755->0644]
src/launchpad_inotify.c [new file with mode: 0644]
src/loader_info.c

old mode 100755 (executable)
new mode 100644 (file)
index 20d8f0f..6197582
@@ -147,6 +147,7 @@ SET(${LAUNCHPAD_PROCESS_POOL}_SOURCE_FILES
        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})
 
index c5859e2..dc60559 100644 (file)
@@ -46,6 +46,7 @@
 #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
diff --git a/inc/launchpad_inotify.h b/inc/launchpad_inotify.h
new file mode 100644 (file)
index 0000000..4db903e
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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);
index 8714198..2e703b5 100644 (file)
@@ -57,10 +57,14 @@ typedef struct _loader_info {
 
 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);
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
index ecd3f61..af409f5
@@ -49,6 +49,7 @@
 #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
@@ -142,6 +148,7 @@ struct app_info {
 
 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;
@@ -171,6 +178,7 @@ static int __add_idle_checker(int detection_method, GList *cur);
 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)
 {
@@ -1588,6 +1596,60 @@ static int __dispatch_cmd_add_loader(bundle *kb)
        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);
@@ -1841,6 +1903,11 @@ static bool __handle_launch_event(int fd, io_condition_e cond, void *data)
                __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);
@@ -2191,6 +2258,77 @@ static int __init_sigchild_fd(void)
        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;
@@ -2331,7 +2469,7 @@ static int __add_default_slots(void)
        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;
 
@@ -2342,6 +2480,11 @@ static int __add_default_slots(void)
        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)
@@ -2562,9 +2705,13 @@ static int __before_loop(int argc, char **argv)
        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);
@@ -2577,6 +2724,7 @@ static int __before_loop(int argc, char **argv)
        }
 
        __register_vconf_events();
+       __init_app_defined_loader_monitor();
 
        return 0;
 }
@@ -2593,6 +2741,8 @@ static void __after_loop(void)
        _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);
diff --git a/src/launchpad_inotify.c b/src/launchpad_inotify.c
new file mode 100644 (file)
index 0000000..9130fa2
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * 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);
+}
index 39e9f21..375c1fd 100644 (file)
@@ -53,6 +53,9 @@
 #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;
@@ -320,7 +323,7 @@ static GList *__parse_file(GList *list, const char *path)
        return list;
 }
 
-GList *_loader_info_load(const char *path)
+GList *_loader_info_load_dir(const char *path)
 {
        DIR *dir_info;
        struct dirent *entry = NULL;
@@ -346,6 +349,56 @@ GList *_loader_info_load(const char *path)
        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;