We will refactor launchpad to c++ step by step.
Changes:
- debugger_info
- launcher_info
- loader_info
Change-Id: I973d98b0669c4b752ba6cf7203f83e8c83085dc0
Signed-off-by: Changgyu Choi <changyu.choi@samsung.com>
SET(CMAKE_C_FLAGS_DEBUG "-O0 -g")
SET(CMAKE_C_FLAGS_RELEASE "-O2")
-SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_C_FLAGS} -std=c++14")
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_C_FLAGS} -std=c++17")
SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
SET(CMAKE_CXX_FLAGS_RELEASE "-O2")
LAUNCHPAD_PROCESS_POOL_SRCS)
AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/../lib/common/src
LIB_COMMON_SRCS)
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/inc)
ADD_EXECUTABLE(${TARGET_LAUNCHPAD_PROCESS_POOL}
${LAUNCHPAD_PROCESS_POOL_SRCS}
+++ /dev/null
-/*
- * Copyright (c) 2016 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.
- */
-
-#ifndef __DEBUGGER_INFO_H__
-#define __DEBUGGER_INFO_H__
-
-#include <glib.h>
-
-typedef struct debugger_info_s *debugger_info_h;
-
-GList *_debugger_info_load(const char *path);
-void _debugger_info_unload(GList *info);
-debugger_info_h _debugger_info_find(GList *info_list, const char *name);
-const char *_debugger_info_get_exe(debugger_info_h info);
-GList *_debugger_info_get_extra_key_list(debugger_info_h info);
-GList *_debugger_info_get_extra_env_list(debugger_info_h info);
-GList *_debugger_info_get_unlink_list(debugger_info_h info);
-const char *_debugger_info_get_attach(debugger_info_h info);
-GList *_debugger_info_get_last_extra_key_list(debugger_info_h info);
-GList *_debugger_info_get_default_opt_list(debugger_info_h info);
-
-#endif /* __DEBUGGER_INFO_H__ */
--- /dev/null
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef DEBUGGER_INFO_HH_
+#define DEBUGGER_INFO_HH_
+
+#include <filesystem>
+#include <memory>
+#include <string>
+#include <string_view>
+#include <vector>
+
+namespace launchpad {
+
+class DebuggerInfo {
+ public:
+ const std::string& GetName() const;
+ const std::string& GetExe() const;
+ const std::vector<std::string>& GetAppTypes() const;
+ const std::vector<std::string>& GetExtraKeyList() const;
+ const std::vector<std::string>& GetExtraEnvList() const;
+ const std::vector<std::string>& GetUnlinkList() const;
+ const std::string& GetAttachInfo() const;
+ const std::vector<std::string>& GetLastExtraKeyList() const;
+ const std::vector<std::string>& GetDefaultOptList() const;
+
+ private:
+ std::string name_;
+ std::string exe_;
+ std::vector<std::string> app_types_;
+ std::vector<std::string> extra_key_list_;
+ std::vector<std::string> extra_env_list_;
+ std::vector<std::string> unlink_list_;
+ std::string attach_;
+ std::vector<std::string> last_extra_key_list_;
+ std::vector<std::string> default_opt_list_;
+
+ friend class DebuggerInfoInflator;
+};
+
+using DebuggerInfoPtr = std::shared_ptr<DebuggerInfo>;
+
+class DebuggerInfoInflator {
+ public:
+ std::vector<DebuggerInfoPtr> Inflate(const std::string_view path);
+ private:
+ void Parse(std::vector<DebuggerInfoPtr>& debugger_info_list,
+ const std::filesystem::path& path);
+};
+
+} // namespace launchpad
+
+#endif // DEBUGGER_INFO_HH_
--- /dev/null
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef LAUNCHER_INFO_HH_
+#define LAUNCHER_INFO_HH_
+
+#include <filesystem>
+#include <memory>
+#include <string>
+#include <string_view>
+#include <vector>
+
+namespace launchpad {
+
+class LauncherInfo {
+ public:
+ const std::string& GetName() const;
+ const std::string& GetExe() const;
+ const std::vector<std::string>& GetAppTypes() const;
+ const std::vector<std::string>& GetExtraArgs() const;
+
+ private:
+ std::string name_;
+ std::string exe_;
+ std::vector<std::string> app_types_;
+ std::vector<std::string> extra_args_;
+ friend class LauncherInfoInflator;
+};
+
+using LauncherInfoPtr = std::shared_ptr<LauncherInfo>;
+
+class LauncherInfoInflator {
+ public:
+ std::vector<LauncherInfoPtr> Inflate(const std::string_view path);
+
+ private:
+ void Parse(std::vector<LauncherInfoPtr>& launcher_info_list,
+ const std::filesystem::path& path);
+};
+
+} // namespace launchpad
+
+#endif /* LAUNCHER_INFO_HH_ */
#ifndef __LAUNCHPAD_CONFIG_H__
#define __LAUNCHPAD_CONFIG_H__
+#ifdef __cplusplus
+extern "C" {
+#endif
+
typedef enum {
CONFIG_TYPE_MEMORY_STATUS_LOW_KEY,
CONFIG_TYPE_MEMORY_STATUS_LOW_VALUE,
void _config_fini(void);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* __LAUNCHPAD_CONFIG_H__ */
#include <stdbool.h>
#include <bundle.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
int _debug_change_mount_namespace(void);
int _debug_create_extra_argv(int *arg, char ***argv);
int _debug_create_argv(int *argc, char ***argv, bool *attach);
int _debug_init(void);
void _debug_fini(void);
-#endif /* __LAUNCHPAD_DEBUG_H__ */
+#ifdef __cplusplus
+}
+#endif
+#endif /* __LAUNCHPAD_DEBUG_H__ */
#include <stdbool.h>
#include <sys/inotify.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
typedef struct inotify_watch_info_s *inotify_watch_info_h;
typedef bool (*inotify_watch_cb)(const char *event_name, uint32_t mask,
int _inotify_init(void);
void _inotify_fini(void);
+
+#ifdef __cplusplus
+}
+#endif
IO_NVAL = 0x20,
} io_condition_e;
+#ifdef __cplusplus
+extern "C" {
+#endif
+
typedef bool (*io_channel_event_cb)(int fd, io_condition_e condition,
void *user_data);
void _io_channel_destroy(io_channel_h channel);
int _io_channel_set_close_on_destroy(io_channel_h channel, bool do_close);
+
+#ifdef __cplusplus
+}
+#endif
+++ /dev/null
-/*
- * Copyright (c) 2016 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 <glib.h>
-#include <bundle.h>
-
-#define DEFAULT_CPU_THRESHOLD_MAX 90
-#define DEFAULT_CPU_THRESHOLD_MIN 40
-
-enum loader_method_e {
- METHOD_TIMEOUT = 0x0001,
- METHOD_VISIBILITY = 0x0002,
- METHOD_DEMAND = 0x0004,
- METHOD_REQUEST = 0x0010,
- METHOD_AVAILABLE_MEMORY = 0x0020,
- METHOD_TTL = 0x0040,
- METHOD_OUT_OF_MEMORY = 0x0100,
- METHOD_INSTALL = 0x0200,
-};
-
-typedef struct _loader_info {
- int type;
- char *name;
- char *exe;
- GList *app_types;
- int detection_method;
- int timeout_val;
- char *hw_acc;
- GList *alternative_loaders;
- bundle *extra;
- int cpu_threshold_max;
- int cpu_threshold_min;
- bool on_boot;
- bool global;
- bool app_exists;
- int activation_method;
- int deactivation_method;
- unsigned int ttl;
- bool is_hydra;
- bool app_check;
- int on_boot_timeout;
- int sched_priority;
-} loader_info_t;
-
-typedef void (*loader_info_foreach_cb)(loader_info_t *info, void *data);
-
-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);
-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);
-bool _loader_info_exist_app_type(loader_info_t *info, const char *app_type);
--- /dev/null
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef LOADER_INFO_HH_
+#define LOADER_INFO_HH_
+
+#include <bundle_cpp.h>
+
+#include <filesystem>
+#include <memory>
+#include <string>
+#include <string_view>
+#include <vector>
+
+#include "util.hh"
+
+namespace launchpad {
+
+constexpr int DefaultCpuThresholdMax = 90;
+constexpr int DefaultCpuThresholdMin = 40;
+
+enum class LoaderType : int {
+ Unsupported = -1,
+ User = 1,
+ Dynamic = 100,
+ Max
+};
+
+enum class LoaderMethod : int {
+ Empty = 0x0000,
+ Timeout = 0x0001,
+ Visibility = 0x0002,
+ Demand = 0x0004,
+ Request = 0x0010,
+ AvailableMemory = 0x0020,
+ Ttl = 0x0040,
+ OutOfMemory = 0x0100,
+ Install = 0x0200,
+};
+
+class LoaderInfo {
+ public:
+ LoaderType GetType() const;
+ const std::string& GetName() const;
+ const std::string& GetExe() const;
+ int GetCpuThresholdMax() const;
+ int GetCpuThresholdMin() const;
+ unsigned int GetTtl() const;
+ const std::vector<std::string>& GetAppTypes() const;
+ LoaderMethod GetDetectionMethod() const;
+ LoaderMethod GetActivationMethod() const;
+ LoaderMethod GetDeactivationMethod() const;
+ const std::string& GetHwAcc() const;
+ int GetOnbootTimeout() const;
+ int GetTimeoutVal() const;
+ int GetSchedPriority() const;
+ bool IsAppExists() const;
+ bool IsOnBoot() const;
+ bool IsHydraEnabled() const;
+ bool IsNeededAppCheck() const;
+ tizen_base::Bundle& GetExtra();
+ void SetType(LoaderType type);
+ void SetAppExists(bool exsits);
+
+ private:
+ LoaderType type_ = LoaderType::Unsupported;
+ std::string name_;
+ std::string exe_;
+ std::vector<std::string> app_types_;
+ LoaderMethod detection_method_ =
+ LoaderMethod::Timeout | LoaderMethod::Visibility | LoaderMethod::Install;
+ LoaderMethod activation_method_ = LoaderMethod::Empty;
+ LoaderMethod deactivation_method_ = LoaderMethod::Empty;
+ int timeout_val_ = 5000;
+ std::string hw_acc_;
+ std::vector<std::string> alternative_loaders_;
+ tizen_base::Bundle extra_;
+ int cpu_threshold_max_ = DefaultCpuThresholdMax;
+ int cpu_threshold_min_ = DefaultCpuThresholdMin;
+ bool on_boot_ = true;
+ bool global_ = false;
+ bool app_exists_ = false;
+ unsigned int ttl_ = 600U; /* 10 minute */
+ bool is_hydra_ = false;
+ bool app_check_ = true;
+ int on_boot_timeout_ = 0;
+ int sched_priority_ = 0;
+
+ friend class LoaderInfoManager;
+ friend class LoaderInfoInflator;
+};
+
+using LoaderInfoPtr = std::shared_ptr<LoaderInfo>;
+
+class LoaderInfoInflator {
+ public:
+ std::vector<LoaderInfoPtr> Inflate(const std::string_view path);
+ void Parse(std::vector<LoaderInfoPtr>& launcher_info_list,
+ const std::filesystem::path& path);
+
+ private:
+ void ParseDetectionMethod(const LoaderInfoPtr& info,
+ std::string& tok_start,
+ std::istringstream& ss);
+ void ParseActivationMethod(const LoaderInfoPtr& info,
+ std::string& tok_start,
+ std::istringstream& ss);
+ void ParseDeactivationMethod(const LoaderInfoPtr& info,
+ std::string& tok_start,
+ std::istringstream& ss);
+ void ParseAppTypes(const LoaderInfoPtr& info,
+ std::string& tok_start,
+ std::istringstream& ss);
+};
+
+class LoaderInfoManager {
+ public:
+ explicit LoaderInfoManager(std::string path);
+ LoaderInfoManager(const LoaderInfoManager&) = delete;
+ LoaderInfoManager& operator=(const LoaderInfoManager&) = delete;
+
+ void Load();
+ void LoadFile(const std::string_view file);
+ void Unload(const std::string_view loader_name);
+ void Dispose();
+ LoaderType FindHwType(const std::string_view app_type);
+ LoaderType FindSwType(const std::string_view app_type);
+ std::string FindLoaderPath(const std::string_view loader_name);
+ LoaderInfoPtr FindLoaderInfo(const std::string_view loader_name);
+ std::vector<LoaderType> GetAlternativeTypes(LoaderType type);
+ const std::vector<LoaderInfoPtr>& GetLoaderInfoList() const;
+
+ private:
+ std::string path_;
+ std::vector<LoaderInfoPtr> loader_list_;
+};
+
+} // namespace launchpad
+
+#endif // LOADER_INFO_HH_
--- /dev/null
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef UTIL_HH_
+#define UTIL_HH_
+
+#include <string>
+#include <vector>
+
+namespace launchpad {
+
+template <typename E>
+E operator|(E a, E b) {
+ return static_cast<E>(static_cast<int>(a) | static_cast<int>(b));
+}
+
+template <typename E>
+bool operator==(E a, int x) {
+ return static_cast<int>(a) == x;
+}
+
+std::vector<std::string> Split(const std::string& str,
+ const std::string& delim);
+
+} // namespace launchpad
+
+#endif // UTIL_HH_
+++ /dev/null
-/*
- * Copyright (c) 2016 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 <malloc.h>
-#include <stdlib.h>
-#include <dirent.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "launchpad_common.h"
-#include "debugger_info.h"
-
-#define TAG_DEBUGGER "[DEBUGGER]"
-#define TAG_NAME "NAME"
-#define TAG_EXE "EXE"
-#define TAG_APP_TYPE "APP_TYPE"
-#define TAG_EXTRA_KEY "EXTRA_KEY"
-#define TAG_EXTRA_ENV "EXTRA_ENV"
-#define TAG_UNLINK "UNLINK"
-#define TAG_ATTACH "ATTACH"
-#define TAG_LAST_EXTRA_KEY "LAST_EXTRA_KEY"
-#define TAG_DEFAULT_OPT "DEFAULT_OPT"
-
-struct debugger_info_s {
- char *name;
- char *exe;
- GList *app_types;
- GList *extra_key_list;
- GList *extra_env_list;
- GList *unlink_list;
- char *attach;
- GList *last_extra_key_list;
- GList *default_opt_list;
-};
-
-static struct debugger_info_s *__create_debugger_info(void)
-{
- struct debugger_info_s *info;
-
- info = calloc(1, sizeof(struct debugger_info_s));
- if (info == NULL) {
- _E("out of memory");
- return NULL;
- }
-
- return info;
-}
-
-static void __destroy_debugger_info(gpointer data)
-{
- struct debugger_info_s *info = (struct debugger_info_s *)data;
-
- if (info == NULL)
- return;
-
- if (info->default_opt_list)
- g_list_free_full(info->default_opt_list, free);
- if (info->last_extra_key_list)
- g_list_free_full(info->last_extra_key_list, free);
- if (info->attach)
- free(info->attach);
- if (info->unlink_list)
- g_list_free_full(info->unlink_list, free);
- if (info->extra_env_list)
- g_list_free_full(info->extra_env_list, free);
- if (info->extra_key_list)
- g_list_free_full(info->extra_key_list, free);
- if (info->app_types)
- g_list_free_full(info->app_types, free);
- if (info->exe)
- free(info->exe);
- if (info->name)
- free(info->name);
- free(info);
-}
-
-static void __parse_app_types(struct debugger_info_s *info, char *line)
-{
- char *token;
- char *saveptr = NULL;
-
- token = strtok_r(line, " |\t\r\n", &saveptr);
- while (token) {
- info->app_types = g_list_append(info->app_types, strdup(token));
- token = strtok_r(NULL, " |\t\r\n", &saveptr);
- }
-}
-
-static GList *__parse_file(GList *list, const char *path)
-{
- FILE *fp;
- char buf[LINE_MAX];
- char *tok1 = NULL;
- char *tok2 = NULL;
- struct debugger_info_s *info = NULL;
-
- fp = fopen(path, "rt");
- if (fp == NULL)
- return list;
-
- while (fgets(buf, sizeof(buf), fp) != NULL) {
- FREE_AND_NULL(tok1);
- FREE_AND_NULL(tok2);
- sscanf(buf, "%ms %ms", &tok1, &tok2);
- if (tok1 && strcasecmp(TAG_DEBUGGER, tok1) == 0) {
- if (info) {
- _D("name: %s, exe: %s", info->name, info->exe);
- list = g_list_append(list, info);
- }
-
- info = __create_debugger_info();
- if (info == NULL)
- break;
-
- continue;
- }
-
- if (!tok1 || !tok2)
- continue;
- if (tok1[0] == '\0' || tok2[0] == '\0' || tok1[0] == '#')
- continue;
- if (info == NULL)
- continue;
-
- if (strcasecmp(TAG_NAME, tok1) == 0) {
- info->name = strdup(tok2);
- if (info->name == NULL) {
- _E("out of memory");
- __destroy_debugger_info(info);
- info = NULL;
- break;
- }
- } else if (strcasecmp(TAG_EXE, tok1) == 0) {
- info->exe = strdup(tok2);
- if (info->exe == NULL) {
- _E("out of memory");
- __destroy_debugger_info(info);
- info = NULL;
- break;
- }
- } else if (strcasecmp(TAG_APP_TYPE, tok1) == 0) {
- __parse_app_types(info, &buf[strlen(tok1)]);
- if (info->app_types == NULL) {
- _E("app_types is NULL");
- __destroy_debugger_info(info);
- info = NULL;
- break;
- }
- } else if (strcasecmp(TAG_EXTRA_KEY, tok1) == 0) {
- info->extra_key_list = g_list_append(
- info->extra_key_list, strdup(tok2));
- } else if (strcasecmp(TAG_EXTRA_ENV, tok1) == 0) {
- info->extra_env_list = g_list_append(
- info->extra_env_list, strdup(tok2));
- } else if (strcasecmp(TAG_UNLINK, tok1) == 0) {
- info->unlink_list = g_list_append(info->unlink_list,
- strdup(tok2));
- } else if (strcasecmp(TAG_ATTACH, tok1) == 0) {
- info->attach = strdup(tok2);
- if (info->attach == NULL) {
- _E("attach is NULL");
- __destroy_debugger_info(info);
- info = NULL;
- break;
- }
- } else if (strcasecmp(TAG_LAST_EXTRA_KEY, tok1) == 0) {
- info->last_extra_key_list = g_list_append(
- info->last_extra_key_list,
- strdup(tok2));
- } else if (strcasecmp(TAG_DEFAULT_OPT, tok1) == 0) {
- info->default_opt_list = g_list_append(
- info->default_opt_list,
- strdup(tok2));
- }
- }
- fclose(fp);
-
- if (info) {
- _D("name: %s, exe: %s", info->name, info->exe);
- list = g_list_append(list, info);
- }
-
- if (tok1)
- free(tok1);
- if (tok2)
- free(tok2);
-
- return list;
-}
-
-GList *_debugger_info_load(const char *path)
-{
- DIR *dp;
- struct dirent *dentry = NULL;
- GList *list = NULL;
- char buf[PATH_MAX];
- char *ext;
-
- if (path == NULL)
- return NULL;
-
- dp = opendir(path);
- if (dp == NULL)
- return NULL;
-
- while ((dentry = readdir(dp)) != NULL) {
- if (dentry->d_name[0] == '.')
- continue;
-
- ext = strrchr(dentry->d_name, '.');
- if (ext && strcmp(ext, ".debugger") == 0) {
- snprintf(buf, sizeof(buf), "%s/%s",
- path, dentry->d_name);
- list = __parse_file(list, buf);
- }
- }
- closedir(dp);
-
- return list;
-}
-
-void _debugger_info_unload(GList *info)
-{
- if (info == NULL)
- return;
-
- g_list_free_full(info, __destroy_debugger_info);
-}
-
-static int __comp_name(gconstpointer a, gconstpointer b)
-{
- struct debugger_info_s *info = (struct debugger_info_s *)a;
-
- if (info == NULL || info->name == NULL || b == NULL)
- return -1;
-
- if (strcasecmp(info->name, b) == 0)
- return 0;
-
- return -1;
-}
-
-debugger_info_h _debugger_info_find(GList *info_list, const char *name)
-{
- GList *list;
-
- if (info_list == NULL || name == NULL)
- return NULL;
-
- list = g_list_find_custom(info_list, name, __comp_name);
- if (list == NULL)
- return NULL;
-
- return (debugger_info_h)list->data;
-}
-
-const char *_debugger_info_get_exe(debugger_info_h info)
-{
- if (info == NULL)
- return NULL;
-
- return info->exe;
-}
-
-GList *_debugger_info_get_extra_key_list(debugger_info_h info)
-{
- if (info == NULL)
- return NULL;
-
- return info->extra_key_list;
-}
-
-GList *_debugger_info_get_extra_env_list(debugger_info_h info)
-{
- if (info == NULL)
- return NULL;
-
- return info->extra_env_list;
-}
-
-GList *_debugger_info_get_unlink_list(debugger_info_h info)
-{
- if (info == NULL)
- return NULL;
-
- return info->unlink_list;
-}
-
-const char *_debugger_info_get_attach(debugger_info_h info)
-{
- if (info == NULL)
- return NULL;
-
- return info->attach;
-}
-
-GList *_debugger_info_get_last_extra_key_list(debugger_info_h info)
-{
- if (info == NULL)
- return NULL;
-
- return info->last_extra_key_list;
-}
-
-GList *_debugger_info_get_default_opt_list(debugger_info_h info)
-{
- if (info == NULL)
- return NULL;
-
- return info->default_opt_list;
-}
--- /dev/null
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#include <dirent.h>
+#include <limits.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <fstream>
+#include <sstream>
+#include <utility>
+
+#include "debugger_info.hh"
+#include "launchpad_common.h"
+#include "util.hh"
+
+namespace launchpad {
+namespace {
+
+constexpr const char kTagDebugger[] = "[DEBUGGER]";
+constexpr const char kTagName[] = "NAME";
+constexpr const char kTagExe[] = "EXE";
+constexpr const char kTagAppType[] = "APP_TYPE";
+constexpr const char kTagExtraKey[] = "EXTRA_KEY";
+constexpr const char kTagExtraEnv[] = "EXTRA_ENV";
+constexpr const char kTagUnlink[] = "UNLINK";
+constexpr const char kTagAttach[] = "ATTACH";
+constexpr const char kTagLastExtraKey[] = "LAST_EXTRA_KEY";
+constexpr const char kTagDefaultOpt[] = "DEFAULT_OPT";
+
+} // namespace
+
+namespace fs = std::filesystem;
+
+void DebuggerInfoInflator::Parse(
+ std::vector<DebuggerInfoPtr>& debugger_info_list,
+ const fs::path& path) {
+ std::ifstream fp;
+ fp.open(path);
+ if (fp.fail())
+ return;
+
+ DebuggerInfoPtr info;
+ std::string input;
+ while (std::getline(fp, input)) {
+ std::istringstream ss(input);
+ std::string tok1, tok2;
+ if (!(ss >> tok1))
+ continue;
+
+ if (strcasecmp(kTagDebugger, tok1.c_str()) == 0) {
+ if (info != nullptr) {
+ _D("name: %s, exe: %s", info->name_.c_str(), info->exe_.c_str());
+ debugger_info_list.push_back(std::move(info));
+ }
+
+ info = std::make_unique<DebuggerInfo>();
+ continue;
+ }
+
+ if (!(ss >> tok2))
+ continue;
+ if (tok1.front() == '#' || info == nullptr)
+ continue;
+
+ std::string key;
+ std::transform(tok1.begin(), tok1.end(), std::back_inserter(key),
+ [](char ch) { return toupper(ch); });
+ if (kTagName == key) {
+ info->name_ = std::move(tok2);
+ } else if (kTagExe == key) {
+ fs::path file(tok2);
+ if (fs::exists(file) == false) {
+ _E("Failed to access %s", tok2.c_str());
+ info.reset();
+ continue;
+ }
+
+ info->exe_ = std::move(tok2);
+ } else if (kTagAppType == key) {
+ std::string line = std::move(tok2);
+ do {
+ auto tokens = Split(line, " |\t\r\n");
+ for (auto& token : tokens) {
+ _E("types: %s", token.c_str());
+ info->app_types_.push_back(std::move(token));
+ }
+ } while (std::getline(ss, line));
+ } else if (kTagExtraKey == key) {
+ info->extra_key_list_.push_back(std::move(tok2));
+ } else if (kTagExtraEnv == key) {
+ info->extra_env_list_.push_back(std::move(tok2));
+ } else if (kTagUnlink == key) {
+ info->unlink_list_.push_back(std::move(tok2));
+ } else if (kTagAttach == key) {
+ info->attach_ = std::move(tok2);
+ } else if (kTagLastExtraKey == key) {
+ info->last_extra_key_list_.push_back(std::move(tok2));
+ } else if (kTagDefaultOpt == key) {
+ info->default_opt_list_.push_back(std::move(tok2));
+ }
+ }
+
+ fp.close();
+ if (info) {
+ _D("name: %s, exe: %s", info->name_.c_str(), info->exe_.c_str());
+ debugger_info_list.push_back(std::move(info));
+ }
+}
+
+const std::string& DebuggerInfo::GetName() const {
+ return name_;
+}
+
+const std::string& DebuggerInfo::GetExe() const {
+ return exe_;
+}
+
+const std::vector<std::string>& DebuggerInfo::GetAppTypes() const {
+ return app_types_;
+}
+
+const std::vector<std::string>& DebuggerInfo::GetExtraKeyList() const {
+ return extra_key_list_;
+}
+
+const std::vector<std::string>& DebuggerInfo::GetExtraEnvList() const {
+ return extra_env_list_;
+}
+
+const std::vector<std::string>& DebuggerInfo::GetUnlinkList() const {
+ return unlink_list_;
+}
+
+const std::string& DebuggerInfo::GetAttachInfo() const {
+ return attach_;
+}
+
+const std::vector<std::string>& DebuggerInfo::GetLastExtraKeyList() const {
+ return last_extra_key_list_;
+}
+
+const std::vector<std::string>& DebuggerInfo::GetDefaultOptList() const {
+ return default_opt_list_;
+}
+
+std::vector<DebuggerInfoPtr> DebuggerInfoInflator::Inflate(
+ const std::string_view path) {
+ fs::path p(path);
+ if (fs::is_directory(p) == false)
+ return {};
+
+ std::vector<DebuggerInfoPtr> result;
+ for (auto& entry : fs::directory_iterator(p)) {
+ fs::path file(entry.path());
+ if (file.extension() == ".debugger")
+ Parse(result, file);
+ }
+
+ return result;
+}
+
+} // namespace launchpad
+++ /dev/null
-/*
- * Copyright (c) 2016 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 <malloc.h>
-#include <stdlib.h>
-#include <dirent.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "launcher_info.h"
-#include "launchpad_common.h"
-
-#define TAG_LAUNCHER "[LAUNCHER]"
-#define TAG_NAME "NAME"
-#define TAG_EXE "EXE"
-#define TAG_APP_TYPE "APP_TYPE"
-#define TAG_EXTRA_ARG "EXTRA_ARG"
-
-struct launcher_info_s {
- char *name;
- char *exe;
- GList *app_types;
- GList *extra_args;
-};
-
-static struct launcher_info_s *__create_launcher_info(void)
-{
- struct launcher_info_s *info;
-
- info = calloc(1, sizeof(struct launcher_info_s));
- if (info == NULL) {
- _E("out of memory");
- return NULL;
- }
-
- return info;
-}
-
-static void __destroy_launcher_info(gpointer data)
-{
- struct launcher_info_s *info = (struct launcher_info_s *)data;
-
- if (info == NULL)
- return;
-
- if (info->extra_args)
- g_list_free_full(info->extra_args, free);
- if (info->app_types)
- g_list_free_full(info->app_types, free);
- if (info->exe)
- free(info->exe);
- if (info->name)
- free(info->name);
- free(info);
-}
-
-static void __parse_app_types(struct launcher_info_s *info, char *line)
-{
- char *token;
- char *saveptr = NULL;
-
- token = strtok_r(line, " |\t\r\n", &saveptr);
- while (token) {
- info->app_types = g_list_append(info->app_types, strdup(token));
- token = strtok_r(NULL, " |\t\r\n", &saveptr);
- }
-}
-
-static GList *__parse_file(GList *list, const char *path)
-{
- FILE *fp;
- char buf[LINE_MAX];
- char *tok1 = NULL;
- char *tok2 = NULL;
- struct launcher_info_s *info = NULL;
-
- fp = fopen(path, "rt");
- if (fp == NULL)
- return list;
-
- while (fgets(buf, sizeof(buf), fp) != NULL) {
- FREE_AND_NULL(tok1);
- FREE_AND_NULL(tok2);
- sscanf(buf, "%ms %ms", &tok1, &tok2);
- if (tok1 && strcasecmp(TAG_LAUNCHER, tok1) == 0) {
- if (info) {
- _D("name: %s, exe: %s", info->name, info->exe);
- list = g_list_append(list, info);
- }
-
- info = __create_launcher_info();
- if (info == NULL)
- break;
-
- continue;
- }
-
- if (!tok1 || !tok2)
- continue;
- if (tok1[0] == '\0' || tok2[0] == '\0' || tok1[0] == '#')
- continue;
- if (info == NULL)
- continue;
-
- if (strcasecmp(TAG_NAME, tok1) == 0) {
- info->name = strdup(tok2);
- if (info->name == NULL) {
- _E("out of memory");
- __destroy_launcher_info(info);
- info = NULL;
- break;
- }
- } else if (strcasecmp(TAG_EXE, tok1) == 0) {
- info->exe = strdup(tok2);
- if (info->exe == NULL) {
- _E("out of memory");
- __destroy_launcher_info(info);
- info = NULL;
- break;
- }
- if (access(info->exe, F_OK | X_OK) != 0) {
- _E("Failed to access %s", info->exe);
- __destroy_launcher_info(info);
- info = NULL;
- }
- } else if (strcasecmp(TAG_APP_TYPE, tok1) == 0) {
- __parse_app_types(info, &buf[strlen(tok1)]);
- if (info->app_types == NULL) {
- _E("app_types is NULL");
- __destroy_launcher_info(info);
- info = NULL;
- break;
- }
- } else if (strcasecmp(TAG_EXTRA_ARG, tok1) == 0) {
- info->extra_args = g_list_append(info->extra_args,
- strdup(tok2));
- }
- }
- fclose(fp);
-
- if (info) {
- _D("name: %s, exe: %s", info->name, info->exe);
- list = g_list_append(list, info);
- }
-
- if (tok1)
- free(tok1);
- if (tok2)
- free(tok2);
-
- return list;
-}
-
-GList *_launcher_info_load(const char *path)
-{
- DIR *dp;
- struct dirent *dentry = NULL;
- GList *list = NULL;
- char buf[PATH_MAX];
- char *ext;
-
- if (path == NULL)
- return NULL;
-
- dp = opendir(path);
- if (dp == NULL)
- return NULL;
-
- while ((dentry = readdir(dp)) != NULL) {
- if (dentry->d_name[0] == '.')
- continue;
-
- ext = strrchr(dentry->d_name, '.');
- if (ext && strcmp(ext, ".launcher") == 0) {
- snprintf(buf, sizeof(buf), "%s/%s",
- path, dentry->d_name);
- list = __parse_file(list, buf);
- }
- }
- closedir(dp);
-
- return list;
-}
-
-void _launcher_info_unload(GList *info)
-{
- if (info == NULL)
- return;
-
- g_list_free_full(info, __destroy_launcher_info);
-}
-
-static int __comp_str(gconstpointer a, gconstpointer b)
-{
- if (a == NULL || b == NULL)
- return -1;
-
- return strcmp(a, b);
-}
-
-static int __comp_app_type(gconstpointer a, gconstpointer b)
-{
- struct launcher_info_s *info = (struct launcher_info_s *)a;
-
- if (info == NULL || info->app_types == NULL || b == NULL)
- return -1;
-
- if (g_list_find_custom(info->app_types, b, __comp_str))
- return 0;
-
- return -1;
-}
-
-launcher_info_h _launcher_info_find(GList *info_list, const char *app_type)
-{
- GList *list;
-
- if (info_list == NULL || app_type == NULL)
- return NULL;
-
- list = g_list_find_custom(info_list, app_type, __comp_app_type);
- if (list == NULL)
- return NULL;
-
- return (launcher_info_h)list->data;
-}
-
-const char *_launcher_info_get_exe(launcher_info_h info)
-{
- if (info == NULL)
- return NULL;
-
- return info->exe;
-}
-
-GList *_launcher_info_get_extra_args(launcher_info_h info)
-{
- if (info == NULL)
- return NULL;
-
- return info->extra_args;
-}
--- /dev/null
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#include <dirent.h>
+#include <limits.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <fstream>
+#include <sstream>
+#include <utility>
+
+#include "launcher_info.hh"
+#include "launchpad_common.h"
+#include "util.hh"
+
+namespace launchpad {
+namespace {
+
+constexpr const char kTagLauncher[] = "[LAUNCHER]";
+constexpr const char kTagName[] = "NAME";
+constexpr const char kTagExe[] = "EXE";
+constexpr const char kTagAppType[] = "APP_TYPE";
+constexpr const char kTagExtraArg[] = "EXTRA_ARG";
+
+} // namespace
+
+namespace fs = std::filesystem;
+
+const std::string& LauncherInfo::GetName() const {
+ return name_;
+}
+
+const std::string& LauncherInfo::GetExe() const {
+ return exe_;
+}
+
+const std::vector<std::string>& LauncherInfo::GetAppTypes() const {
+ return app_types_;
+}
+
+const std::vector<std::string>& LauncherInfo::GetExtraArgs() const {
+ return extra_args_;
+}
+
+void LauncherInfoInflator::Parse(
+ std::vector<LauncherInfoPtr>& launcher_info_list,
+ const fs::path& path) {
+ std::ifstream fp;
+ fp.open(path);
+ if (fp.fail())
+ return;
+
+ LauncherInfoPtr info;
+ std::string input;
+ while (std::getline(fp, input)) {
+ std::istringstream ss(input);
+ std::string tok1, tok2;
+ if (!(ss >> tok1))
+ continue;
+
+ if (strcasecmp(kTagLauncher, tok1.c_str()) == 0) {
+ if (info != nullptr) {
+ _D("name: %s, exe: %s", info->name_.c_str(), info->exe_.c_str());
+ launcher_info_list.push_back(std::move(info));
+ }
+
+ info = std::make_shared<LauncherInfo>();
+ continue;
+ }
+
+ if (!(ss >> tok2))
+ continue;
+ if (tok1.front() == '#' || info == nullptr)
+ continue;
+
+ std::string key;
+ std::transform(tok1.begin(), tok1.end(), std::back_inserter(key),
+ [](char ch) { return toupper(ch); });
+ if (kTagName == key) {
+ info->name_ = std::move(tok2);
+ } else if (kTagExe == key) {
+ fs::path file(tok2);
+ if (fs::exists(file) == false) {
+ _E("Failed to access %s", tok2.c_str());
+ info.reset();
+ continue;
+ }
+
+ info->exe_ = std::move(tok2);
+ } else if (kTagAppType == key) {
+ std::string line = std::move(tok2);
+ do {
+ auto tokens = Split(line, " |\t\r\n");
+ for (auto& token : tokens) {
+ info->app_types_.push_back(std::move(token));
+ }
+ } while (std::getline(ss, line));
+ } else if (kTagExtraArg == key) {
+ info->extra_args_.push_back(std::move(tok2));
+ }
+ }
+
+ fp.close();
+ if (info) {
+ _D("name: %s, exe: %s", info->name_.c_str(), info->exe_.c_str());
+ launcher_info_list.push_back(std::move(info));
+ }
+}
+
+std::vector<LauncherInfoPtr> LauncherInfoInflator::Inflate(
+ const std::string_view path) {
+ fs::path p(path);
+ if (fs::is_directory(p) == false)
+ return {};
+
+ std::vector<LauncherInfoPtr> result;
+ for (auto& entry : fs::directory_iterator(p)) {
+ fs::path file(entry.path());
+ if (file.extension() == ".launcher") {
+ Parse(result, file);
+ }
+ }
+
+ return result;
+}
+
+} // namespace launchpad
+++ /dev/null
-/*
- * Copyright (c) 2015 - 2016 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 <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <systemd/sd-daemon.h>
-#include <sys/prctl.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sys/stat.h>
-#include <sys/capability.h>
-#include <sched.h>
-#include <stdbool.h>
-#include <malloc.h>
-#include <bundle_internal.h>
-#include <security-manager.h>
-#include <time.h>
-#include <systemd/sd-daemon.h>
-#include <glib.h>
-#include <linux/limits.h>
-#include <ttrace.h>
-#include <vconf.h>
-#include <math.h>
-#include <trust-anchor.h>
-
-#include "key.h"
-#include "launcher_info.h"
-#include "launchpad_common.h"
-#include "launchpad_config.h"
-#include "launchpad_dbus.h"
-#include "launchpad_debug.h"
-#include "launchpad_inotify.h"
-#include "launchpad_io_channel.h"
-#include "launchpad_log.h"
-#include "launchpad_memory_monitor.h"
-#include "launchpad_plugin.h"
-#include "launchpad_proc.h"
-#include "launchpad_signal.h"
-#include "launchpad_types.h"
-#include "launchpad_worker.h"
-#include "loader_info.h"
-#include "perf.h"
-#include "slot_info.h"
-
-#define AUL_PR_NAME 16
-#define EXEC_CANDIDATE_EXPIRED 5
-#define EXEC_CANDIDATE_WAIT 1
-#define DIFF(a, b) (((a) > (b)) ? (a) - (b) : (b) - (a))
-#define CANDIDATE_NONE 0
-#define HYDRA_NONE 0
-#define PROCESS_POOL_LAUNCHPAD_SOCK ".launchpad-process-pool-sock"
-#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
-#define PAD_ERR_REJECTED -2
-#define PAD_ERR_INVALID_ARGUMENT -3
-#define PAD_ERR_INVALID_PATH -4
-#define CPU_CHECKER_TIMEOUT 1000
-#define PI 3.14159265
-#define WIN_SCORE 100
-#define LOSE_SCORE_RATE 0.7f
-
-enum candidate_process_state_e {
- CANDIDATE_PROCESS_STATE_RUNNING,
- CANDIDATE_PROCESS_STATE_PAUSED,
-};
-
-typedef struct {
- int type;
- bool prepared;
- int pid; /* for hydra this pid is not the pid of hydra itself */
- /* but pid of non-hydra candidate, which was forked from hydra */
- int hydra_pid;
- int loader_id;
- int caller_pid;
- int send_fd;
- int hydra_fd;
- int last_exec_time;
- guint timer;
- char *loader_name;
- char *loader_path;
- char *loader_extra;
- int detection_method;
- int timeout_val;
- unsigned long long cpu_total_time;
- unsigned long long cpu_idle_time;
- int threshold;
- int threshold_max;
- int threshold_min;
- int cur_event;
- bool on_boot;
- bool app_exists;
- bool touched;
- int activation_method;
- int deactivation_method;
- unsigned int ttl;
- guint live_timer;
- int state;
- bool is_hydra;
- bool app_check;
- io_channel_h client_channel;
- io_channel_h channel;
- io_channel_h hydra_channel;
- unsigned int score;
- unsigned int pss;
- int cpu_check_count;
- int on_boot_timeout;
- guint on_boot_timer;
- int sched_priority;
-} candidate_process_context_t;
-
-typedef struct {
- GPollFD *gpollfd;
- int type;
- int loader_id;
-} loader_context_t;
-
-typedef struct {
- GQueue *queue;
- guint timer;
- guint idle_checker;
- candidate_process_context_t *running_cpc;
-} sequencer;
-
-struct app_launch_arg {
- const char *appid;
- const char *app_path;
- appinfo_t *menu_info;
- bundle *kb;
-};
-
-struct app_arg {
- int argc;
- char **argv;
-};
-
-struct app_info {
- const char *type;
- bool exists;
-};
-
-struct cleanup_info_s {
- char *appid;
- int pid;
-};
-
-typedef struct candidate_info_s {
- char **argv;
- int argc;
- int loader_id;
- int type;
- pid_t pid;
-} candidate_info_t;
-
-typedef struct request_s {
- app_pkt_t *pkt;
- appinfo_t *menu_info;
- bundle *kb;
- candidate_process_context_t *cpc;
- candidate_process_context_t *org_cpc;
- const char *app_path;
- int clifd;
- int cmd;
- int loader_id;
- pid_t caller_pid;
- uid_t caller_uid;
- pid_t pid; /* result */
-} request_t;
-
-typedef request_t *request_h;
-
-typedef int (*request_handler)(request_h request);
-
-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 GList *launcher_info_list;
-static GHashTable *__pid_table;
-static int __memory_status_low;
-static int __memory_status_normal;
-static sequencer __sequencer;
-static int MEMORY_STATUS_LOW;
-static int MEMORY_STATUS_NORMAL;
-static int MAX_CPU_CHECK_COUNT;
-
-static io_channel_h __logger_channel;
-static io_channel_h __label_monitor_channel;
-static io_channel_h __launchpad_channel;
-static int __client_fd = -1;
-static worker_h __cleaner;
-
-static candidate_process_context_t *__add_slot(slot_info_t *info);
-static int __remove_slot(int type, int loader_id);
-static int __add_default_slots(void);
-static gboolean __handle_idle_checker(gpointer data);
-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,
- bool force);
-static void __init_app_defined_loader_monitor(void);
-static gboolean __launchpad_recovery_cb(gpointer data);
-static gboolean __logger_recovery_cb(gpointer data);
-
-static gboolean __handle_queuing_slots(gpointer data)
-{
- candidate_process_context_t *cpc;
- unsigned long long total = 0;
- unsigned long long idle = 0;
-
- if (__sequencer.idle_checker > 0)
- return G_SOURCE_CONTINUE;
-
- if (g_queue_is_empty(__sequencer.queue)) {
- __sequencer.timer = 0;
- return G_SOURCE_REMOVE;
- }
-
- cpc = (candidate_process_context_t *)g_queue_pop_head(
- __sequencer.queue);
- if (!cpc) {
- _E("Critical error!");
- __sequencer.timer = 0;
- return G_SOURCE_REMOVE;;
- }
-
- if (cpc->app_check && !cpc->app_exists) {
- _W("The application is not installed. Type(%d)", cpc->type);
- return G_SOURCE_CONTINUE;
- }
-
- if (cpc->timer) {
- g_source_remove(cpc->timer);
- cpc->timer = 0;
- }
-
- if (cpc->pid != CANDIDATE_NONE) {
- _W("The slot(%d) is already running. pid(%d)",
- cpc->type, cpc->pid);
- return G_SOURCE_CONTINUE;
- }
-
- _get_cpu_idle(&total, &idle);
- cpc->cpu_idle_time = idle;
- cpc->cpu_total_time = total;
- cpc->cpu_check_count = 0;
-
- __sequencer.idle_checker = g_timeout_add(CPU_CHECKER_TIMEOUT,
- __handle_idle_checker, cpc);
- __sequencer.running_cpc = cpc;
-
- _W("[__SEQUENCER__] Add idle checker. Type(%d)", cpc->type);
-
- return G_SOURCE_CONTINUE;
-}
-
-static bool __sequencer_slot_is_running(candidate_process_context_t *cpc)
-{
- if (__sequencer.running_cpc == cpc)
- return true;
-
- return false;
-}
-
-static bool __sequencer_slot_exist(candidate_process_context_t *cpc)
-{
- GList *found;
-
- found = g_queue_find(__sequencer.queue, cpc);
- if (found)
- return true;
-
- return false;
-}
-
-static int __sequencer_add_slot(candidate_process_context_t *cpc)
-{
- if (__sequencer_slot_exist(cpc)) {
- _W("Already exists");
- return -1;
- }
-
- if (__sequencer_slot_is_running(cpc)) {
- _W("slot(%d) is running", cpc->type);
- return -1;
- }
-
- g_queue_push_tail(__sequencer.queue, cpc);
-
- return 0;
-}
-
-static void __sequencer_remove_slot(candidate_process_context_t *cpc)
-{
- g_queue_remove(__sequencer.queue, cpc);
-}
-
-static void __sequencer_run(void)
-{
- if (__sequencer.timer)
- return;
-
- __sequencer.timer = g_timeout_add(500, __handle_queuing_slots, NULL);
- if (!__sequencer.timer)
- _E("Failed to add sequencer timer");
-}
-
-static void __sequencer_stop(void)
-{
- if (!__sequencer.timer)
- return;
-
- g_source_remove(__sequencer.timer);
- __sequencer.timer = 0;
-}
-
-static bool __sequencer_queue_is_empty(void)
-{
- if (g_queue_is_empty(__sequencer.queue))
- return true;
-
- return false;
-}
-
-static int __sequencer_init(void)
-{
- _D("[__SEQUENCER__] Init");
-
- __sequencer.queue = g_queue_new();
- if (!__sequencer.queue) {
- _E("Out of memory");
- return -1;
- }
-
- return 0;
-}
-
-static void __sequencer_fini(void)
-{
- _D("[__SEQUENCER__] Finish");
-
- if (__sequencer.idle_checker > 0)
- g_source_remove(__sequencer.idle_checker);
-
- if (__sequencer.timer > 0)
- g_source_remove(__sequencer.timer);
-
- g_queue_free(__sequencer.queue);
-}
-
-static int __make_loader_id(void)
-{
- static int id = PAD_LOADER_ID_DYNAMIC_BASE;
-
- return ++id;
-}
-
-static candidate_process_context_t *__find_slot_from_static_type(int type)
-{
- candidate_process_context_t *cpc;
- GList *iter = candidate_slot_list;
-
- if (type == LAUNCHPAD_LOADER_TYPE_DYNAMIC ||
- type == LAUNCHPAD_LOADER_TYPE_UNSUPPORTED)
- return NULL;
-
- while (iter) {
- cpc = (candidate_process_context_t *)iter->data;
- if (type == cpc->type)
- return cpc;
-
- iter = g_list_next(iter);
- }
-
- return NULL;
-}
-
-static candidate_process_context_t *__find_slot_from_pid(int pid)
-{
- candidate_process_context_t *cpc;
- GList *iter = candidate_slot_list;
-
- while (iter) {
- cpc = (candidate_process_context_t *)iter->data;
- if (pid == cpc->pid)
- return cpc;
-
- iter = g_list_next(iter);
- }
-
- return NULL;
-}
-
-static candidate_process_context_t *__find_hydra_slot_from_pid(int pid)
-{
- candidate_process_context_t *cpc;
- GList *iter = candidate_slot_list;
-
- while (iter) {
- cpc = (candidate_process_context_t *)iter->data;
- if (cpc->is_hydra && pid == cpc->hydra_pid)
- return cpc;
-
- iter = g_list_next(iter);
- }
-
- return NULL;
-}
-
-static candidate_process_context_t *__find_slot_from_caller_pid(int caller_pid)
-{
- candidate_process_context_t *cpc;
- GList *iter = candidate_slot_list;
-
- while (iter) {
- cpc = (candidate_process_context_t *)iter->data;
- if (caller_pid == cpc->caller_pid)
- return cpc;
-
- iter = g_list_next(iter);
- }
-
- return NULL;
-}
-
-static candidate_process_context_t *__find_slot_from_loader_id(int id)
-{
- candidate_process_context_t *cpc;
- GList *iter = candidate_slot_list;
-
- while (iter) {
- cpc = (candidate_process_context_t *)iter->data;
- if (id == cpc->loader_id)
- return cpc;
-
- iter = g_list_next(iter);
- }
-
- return NULL;
-}
-
-static candidate_process_context_t *__find_slot_from_loader_name(const char *loader_name)
-{
- candidate_process_context_t *cpc;
- GList *iter = candidate_slot_list;
-
- while (iter) {
- cpc = (candidate_process_context_t *)iter->data;
- if (strcmp(cpc->loader_name, loader_name) == 0)
- return cpc;
-
- iter = g_list_next(iter);
- }
-
- return NULL;
-}
-
-static candidate_process_context_t *__find_slot(int type, int loader_id)
-{
- if (type == LAUNCHPAD_LOADER_TYPE_DYNAMIC)
- return __find_slot_from_loader_id(loader_id);
-
- return __find_slot_from_static_type(type);
-}
-
-static void __update_slot_score(candidate_process_context_t *slot)
-{
- if (!slot)
- return;
-
- slot->score *= LOSE_SCORE_RATE;
- slot->score += WIN_SCORE;
-}
-
-static void __update_slots_pss(void)
-{
- candidate_process_context_t *cpc;
- GList *iter;
-
- iter = candidate_slot_list;
- while (iter) {
- cpc = (candidate_process_context_t *)iter->data;
- iter = g_list_next(iter);
-
- if (cpc->pid == CANDIDATE_NONE)
- continue;
-
- _proc_get_mem_pss(cpc->pid, &cpc->pss);
- }
-}
-
-static gint __compare_slot(gconstpointer a, gconstpointer b)
-{
- candidate_process_context_t *slot_a = (candidate_process_context_t *)a;
- candidate_process_context_t *slot_b = (candidate_process_context_t *)b;
-
- if (slot_a->is_hydra && !slot_b->is_hydra)
- return -1;
- if (!slot_a->is_hydra && slot_b->is_hydra)
- return 1;
-
- if (slot_a->score < slot_b->score)
- return 1;
- if (slot_a->score > slot_b->score)
- return -1;
-
- if (slot_a->pss < slot_b->pss)
- return -1;
- if (slot_a->pss > slot_b->pss)
- return 1;
-
- return 0;
-}
-
-static candidate_process_context_t *__get_running_slot(bool is_hydra)
-{
- candidate_process_context_t *cpc;
- GList *iter;
-
- iter = candidate_slot_list;
- while (iter) {
- cpc = (candidate_process_context_t *)iter->data;
- if (cpc->is_hydra == is_hydra && cpc->pid != CANDIDATE_NONE)
- return cpc;
-
- iter = g_list_next(iter);
- }
-
- return NULL;
-}
-
-static void __pause_all_running_slots(bool is_hydra)
-{
- candidate_process_context_t *cpc = NULL;
- GList *iter;
-
- iter = g_list_last(candidate_slot_list);
- while (iter) {
- cpc = (candidate_process_context_t *)iter->data;
- if (cpc->is_hydra == is_hydra && cpc->pid != CANDIDATE_NONE) {
- __update_slot_state(cpc, METHOD_OUT_OF_MEMORY, true);
- if (!_memory_monitor_is_low_memory())
- return;
- }
-
- iter = g_list_previous(iter);
- }
-}
-
-static void __resume_all_slots(void)
-{
- candidate_process_context_t *cpc;
- GList *iter;
-
- iter = candidate_slot_list;
- while (iter) {
- cpc = (candidate_process_context_t *)iter->data;
- __update_slot_state(cpc, METHOD_AVAILABLE_MEMORY, true);
-
- iter = g_list_next(iter);
- }
-}
-
-static void __kill_process(int pid)
-{
- char err_str[MAX_LOCAL_BUFSZ] = { 0, };
-
- if (kill(pid, SIGKILL) == -1) {
- _E("send SIGKILL: %s",
- strerror_r(errno, err_str, sizeof(err_str)));
- }
-}
-
-static void __refuse_candidate_process(int server_fd)
-{
- int client_fd = -1;
-
- if (server_fd == -1) {
- _E("arguments error!");
- goto error;
- }
-
- client_fd = accept(server_fd, NULL, NULL);
- if (client_fd == -1) {
- _E("accept error!");
- goto error;
- }
-
- close(client_fd);
- _D("refuse connection!");
-
-error:
- return;
-}
-
-static int __accept_candidate_process(int server_fd, int *out_client_fd,
- int *out_client_pid, int cpc_pid)
-{
- int client_fd = -1;
- int recv_pid = 0;
- int ret;
- socklen_t len;
- struct ucred cred = {};
-
- if (server_fd == -1 || out_client_fd == NULL ||
- out_client_pid == NULL) {
- _E("arguments error!");
- goto error;
- }
-
- client_fd = accept(server_fd, NULL, NULL);
- if (client_fd == -1) {
- _E("accept error!");
- goto error;
- }
-
- if (_set_sock_option(client_fd, 1) < 0) {
- _E("Failed to set sock option");
- goto error;
- }
-
- ret = recv(client_fd, &recv_pid, sizeof(recv_pid), MSG_WAITALL);
- if (ret == -1) {
- _E("recv error!");
- goto error;
- }
-
- len = (socklen_t)sizeof(cred);
- ret = getsockopt(client_fd, SOL_SOCKET, SO_PEERCRED, &cred, &len);
- if (ret < 0) {
- _E("getsockopt error");
- goto error;
- }
-
- if (cpc_pid != -1 && cred.pid != cpc_pid) {
- _E("Invalid accept. pid(%d)", cred.pid);
- goto error;
- }
-
- if (cred.pid != recv_pid)
- _W("Not equal recv and real pid");
-
- *out_client_fd = client_fd;
- *out_client_pid = cred.pid;
-
- return *out_client_fd;
-
-error:
- if (client_fd != -1)
- close(client_fd);
-
- return -1;
-}
-
-static int __listen_addr(struct sockaddr_un *addr)
-{
- int fd = -1;
- fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
- if (fd < 0) {
- _E("Socket error");
- goto error;
- }
-
- unlink(addr->sun_path);
-
- _D("bind to %s", addr->sun_path);
- if (bind(fd, (struct sockaddr *)addr, sizeof(struct sockaddr_un)) < 0) {
- _E("bind error");
- goto error;
- }
-
- _D("listen to %s", addr->sun_path);
- if (listen(fd, MAX_PENDING_CONNECTIONS) == -1) {
- _E("listen error");
- goto error;
- }
-
- SECURE_LOGD("[launchpad] done, listen fd: %d", fd);
- return fd;
-
-error:
- if (fd != -1)
- close(fd);
-
- return -1;
-}
-
-static int __listen_candidate_process(int type, int loader_id)
-{
- struct sockaddr_un addr;
-
- _D("[launchpad] enter, type: %d", type);
-
- memset(&addr, 0x00, sizeof(struct sockaddr_un));
- addr.sun_family = AF_UNIX;
- snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/daemons/%u/%s%d-%d",
- SOCKET_PATH, getuid(), LAUNCHPAD_LOADER_SOCKET_NAME,
- type, loader_id);
-
- return __listen_addr(&addr);
-}
-
-static int __listen_hydra_process(int type, int loader_id)
-{
- struct sockaddr_un addr;
-
- _D("[launchpad] enter, type: %d", type);
-
- memset(&addr, 0x00, sizeof(struct sockaddr_un));
- addr.sun_family = AF_UNIX;
- snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/daemons/%d/%s%d-%d",
- SOCKET_PATH, getuid(), HYDRA_LOADER_SOCKET_NAME,
- type, loader_id);
-
- return __listen_addr(&addr);
-}
-
-static int __get_loader_id(bundle *kb)
-{
- const char *val;
-
- val = bundle_get_val(kb, AUL_K_LOADER_ID);
- if (val == NULL)
- return -1;
- _W("Requested loader id: %s", val);
-
- return atoi(val);
-}
-
-static int __candidate_process_real_launch(int candidate_fd, app_pkt_t *pkt)
-{
- return _send_pkt_raw(candidate_fd, pkt);
-}
-
-static int __real_send(int clifd, int ret)
-{
- if (clifd < 3) {
- _E("Invalid parameter. clifd(%d)", clifd);
- return -1;
- }
-
- if (send(clifd, &ret, sizeof(int), MSG_NOSIGNAL) < 0) {
- if (errno == EPIPE) {
- _E("send failed due to EPIPE.");
- close(clifd);
- return -1;
- }
- _E("send fail to client");
- }
-
- close(clifd);
- return 0;
-}
-
-static int __fork_app_process(int (*child_fn)(void *), void *arg,
- int sched_priority)
-{
- int pid;
- int ret;
-
- pid = fork();
- if (pid == -1) {
- _E("failed to fork child process");
- return -1;
- }
-
- if (pid == 0) {
- if (sched_priority != 0)
- _set_priority(sched_priority);
-
- _W("security_manager_prepare_app_candidate ++");
- ret = security_manager_prepare_app_candidate();
- _W("security_manager_prepare_app_candidate --");
- if (ret != SECURITY_MANAGER_SUCCESS) {
- _E("failed to prepare app candidate process (%d)", ret);
- exit(1);
- }
-
- ret = child_fn(arg);
- _E("failed to exec app process (%d)", errno);
- exit(ret);
- }
-
- return pid;
-}
-
-static int __exec_loader_process(void *arg)
-{
- char **argv = arg;
- char err_buf[1024];
-
- _signal_unblock_sigchld();
- _close_all_fds();
- _setup_stdio(basename(argv[LOADER_ARG_PATH]));
-
- if (execv(argv[LOADER_ARG_PATH], argv) < 0) {
- _send_message_to_logger(argv[LOADER_ARG_PATH],
- "Failed to prepare candidate process. error(%d:%s)",
- errno, strerror_r(errno, err_buf, sizeof(err_buf)));
- } else {
- _D("Succeeded to prepare candidate_process");
- }
-
- return -1;
-}
-
-static gboolean __handle_deactivate_event(gpointer user_data)
-{
- candidate_process_context_t *cpc;
-
- cpc = (candidate_process_context_t *)user_data;
- __update_slot_state(cpc, METHOD_TTL, false);
- _D("Deactivate event: type(%d)", cpc->type);
-
- return G_SOURCE_REMOVE;
-}
-
-static void __set_live_timer(candidate_process_context_t *cpc)
-{
- if (!cpc)
- return;
-
- if (cpc->deactivation_method & METHOD_TTL) {
- if (cpc->live_timer == 0) {
- cpc->live_timer = g_timeout_add_seconds(cpc->ttl,
- __handle_deactivate_event, cpc);
- }
- }
-}
-
-static int __hydra_send_request(int fd, enum hydra_cmd cmd)
-{
- int sent = 0;
- int size = (int)sizeof(cmd);
- int send_ret = 0;
-
- while (sent != size) {
- send_ret = send(fd, (char *)&cmd + sent,
- size - sent, MSG_NOSIGNAL);
- if (send_ret == -1) {
- _E("send error! (%d)", errno);
- return -1;
- }
-
- sent += send_ret;
- _D("send(%d: ret: %d) : %d / %d",
- fd, send_ret, sent, size);
- }
-
- return 0;
-}
-
-static int __hydra_send_launch_candidate_request(int fd)
-{
- SECURE_LOGD("Send launch cmd to hydra, fd: %d", fd);
- return __hydra_send_request(fd, LAUNCH_CANDIDATE);
-}
-
-static void __candidate_info_free(candidate_info_t *info)
-{
- int i;
-
- if (info == NULL)
- return;
-
- if (info->argv) {
- for (i = 0; i < info->argc; i++)
- free(info->argv[i]);
-
- free(info->argv);
- }
-
- free(info);
-}
-
-static int __candidate_info_create(candidate_process_context_t *cpt,
- candidate_info_t **candidate_info)
-{
- char type_str[12] = {0, };
- char loader_id_str[12] = {0, };
- char argbuf[LOADER_ARG_LEN];
- candidate_info_t *info;
-
- if (cpt == NULL)
- return -EINVAL;
-
- info = calloc(1, sizeof(candidate_info_t));
- if (info == NULL) {
- _E("calloc() is failed");
- return -ENOMEM;
- }
-
- info->argv = calloc(LOADER_ARG_DUMMY + 1, sizeof(char *));
- if (info->argv == NULL) {
- _E("calloc() is failed");
- __candidate_info_free(info);
- return -ENOMEM;
- }
-
- memset(argbuf, ' ', LOADER_ARG_LEN);
- argbuf[LOADER_ARG_LEN - 1] = '\0';
- info->argv[LOADER_ARG_DUMMY] = strdup(argbuf);
-
- snprintf(loader_id_str, sizeof(loader_id_str), "%d", cpt->loader_id);
- snprintf(type_str, sizeof(type_str), "%d", cpt->type);
- info->argv[LOADER_ARG_PATH] = strdup(cpt->loader_path);
- info->argv[LOADER_ARG_TYPE] = strdup(type_str);
- info->argv[LOADER_ARG_ID] = strdup(loader_id_str);
- info->argv[LOADER_ARG_HYDRA] = strdup(cpt->is_hydra ? "1" : "0");
- info->argv[LOADER_ARG_EXTRA] = strdup(cpt->loader_extra);
-
- info->argc = LOADER_ARG_DUMMY + 1;
- info->type = cpt->type;
- info->loader_id = cpt->loader_id;
-
- *candidate_info = info;
- return 0;
-}
-
-static int __prepare_candidate_process(int type, int loader_id)
-{
- candidate_process_context_t *cpt = __find_slot(type, loader_id);
- candidate_info_t *info;
- int ret;
-
- if (cpt == NULL)
- return -1;
-
- if (cpt->is_hydra && cpt->hydra_pid != HYDRA_NONE)
- return __hydra_send_launch_candidate_request(cpt->hydra_fd);
-
- _D("prepare candidate process / type:%d", type);
- ret = __candidate_info_create(cpt, &info);
- if (ret < 0)
- return ret;
-
- info->pid = __fork_app_process(__exec_loader_process, info->argv,
- cpt->sched_priority);
- if (info->pid == -1) {
- _E("Failed to create a child process. type: %d", type);
- __candidate_info_free(info);
- return -1;
- }
-
- _W("Candidate process. type: %d, loader_id: %d, pid: %d",
- info->type, info->loader_id, info->pid);
- cpt = __find_slot(info->type, info->loader_id);
- if (cpt == NULL) {
- _E("Not found slot.");
- __candidate_info_free(info);
- return -1;
- }
-
- cpt->last_exec_time = time(NULL);
- if (cpt->is_hydra) {
- cpt->hydra_pid = info->pid;
- } else {
- cpt->pid = info->pid;
- __set_live_timer(cpt);
- }
-
- _log_print("[CANDIDATE]", "pid(%7d) | type(%d) | loader(%s)",
- info->pid, cpt->loader_id, cpt->loader_name);
- _memory_monitor_reset_timer();
- __candidate_info_free(info);
- return 0;
-}
-
-static gboolean __handle_timeout_event(gpointer user_data)
-{
- candidate_process_context_t *cpc;
-
- cpc = (candidate_process_context_t *)user_data;
- cpc->timer = 0;
-
- if (cpc->pid != CANDIDATE_NONE) {
- _W("Candidate(%d) process(%d) is running", cpc->type, cpc->pid);
- return G_SOURCE_REMOVE;
- }
-
- __sequencer_add_slot(cpc);
- __sequencer_run();
- return G_SOURCE_REMOVE;
-}
-
-static void __set_timer(candidate_process_context_t *cpc)
-{
- if (cpc == NULL || cpc->timer > 0)
- return;
-
- if ((cpc->detection_method & METHOD_TIMEOUT) &&
- cpc->state == CANDIDATE_PROCESS_STATE_RUNNING) {
- cpc->timer = g_timeout_add(cpc->timeout_val,
- __handle_timeout_event, cpc);
- }
-}
-
-static void __reset_slot(candidate_process_context_t *cpc)
-{
- if (cpc == NULL)
- return;
-
- cpc->send_fd = -1;
- cpc->prepared = false;
- cpc->pid = CANDIDATE_NONE;
- cpc->client_channel = NULL;
- cpc->timer = 0;
- cpc->live_timer = 0;
- cpc->on_boot_timer = 0;
-}
-
-static void __dispose_candidate_process(candidate_process_context_t *cpc)
-{
- if (!cpc)
- return;
-
- _D("Dispose candidate process %d", cpc->type);
- if (cpc->pid > 0) {
- _D("kill process %d", cpc->pid);
- __kill_process(cpc->pid);
- }
- if (cpc->live_timer > 0)
- g_source_remove(cpc->live_timer);
- if (cpc->client_channel)
- _io_channel_destroy(cpc->client_channel);
- if (cpc->timer > 0)
- g_source_remove(cpc->timer);
- if (cpc->send_fd > 0)
- close(cpc->send_fd);
- if (cpc->on_boot_timer > 0)
- g_source_remove(cpc->on_boot_timer);
- __reset_slot(cpc);
-}
-
-static void __dispose_hydra_process(candidate_process_context_t *cpc)
-{
- if (!cpc)
- return;
-
- __dispose_candidate_process(cpc);
-
- _D("Dispose hydra process %d", cpc->type);
- if (cpc->hydra_pid > 0) {
- _D("kill process %d", cpc->hydra_pid);
- __kill_process(cpc->hydra_pid);
- cpc->hydra_pid = HYDRA_NONE;
- }
-
- if (cpc->hydra_fd > 0) {
- close(cpc->hydra_fd);
- cpc->hydra_fd = -1;
- }
-}
-
-static int __send_launchpad_loader(candidate_process_context_t *cpc,
- app_pkt_t *pkt, const char *app_path, int clifd)
-{
- int pid = -1;
- int ret;
-
- ret = _delete_sock_path(cpc->pid, getuid());
- if (ret != 0)
- return -1;
-
- __candidate_process_real_launch(cpc->send_fd, pkt);
- SECURE_LOGD("Request to candidate process, pid: %d, bin path: %s",
- cpc->pid, app_path);
-
- pid = cpc->pid;
- cpc->pid = CANDIDATE_NONE;
- __dispose_candidate_process(cpc);
- __set_timer(cpc);
- __update_slot_score(cpc);
-
- return pid;
-}
-
-static int __normal_fork_exec(int argc, char **argv, const char *app_path)
-{
- char *libdir;
- char err_buf[1024];
-
- _D("start real fork and exec");
-
- libdir = _get_libdir(app_path);
- if (libdir) {
- setenv("LD_LIBRARY_PATH", libdir, 1);
- free(libdir);
- }
-
- _close_all_fds();
-
- if (execv(argv[LOADER_ARG_PATH], argv) < 0) { /* Flawfinder: ignore */
- _send_message_to_logger(argv[LOADER_ARG_PATH],
- "Failed to execute a file. error(%d:%s)",
- errno, strerror_r(errno, err_buf, sizeof(err_buf)));
- return -1;
- }
- /* never reach*/
- return 0;
-}
-
-static int __create_launcher_argv(int *argc, char ***argv, const char *app_type)
-{
- int launcher_argc;
- char **launcher_argv;
- launcher_info_h launcher_info;
- const char *exe;
- const char *extra_arg;
- GList *extra_args;
- GList *iter;
- int i;
-
- launcher_info = _launcher_info_find(launcher_info_list, app_type);
- if (launcher_info == NULL)
- return 0;
-
- exe = _launcher_info_get_exe(launcher_info);
- if (exe == NULL) {
- _E("Failed to get launcher exe");
- return -1;
- }
-
- extra_args = _launcher_info_get_extra_args(launcher_info);
- launcher_argc = g_list_length(extra_args) + 1;
- launcher_argv = (char **)calloc(launcher_argc, sizeof(char *));
- if (launcher_argv == NULL) {
- _E("out of memory");
- return -1;
- }
-
- i = LOADER_ARG_PATH;
- launcher_argv[i++] = strdup(exe);
-
- iter = g_list_first(extra_args);
- while (iter) {
- extra_arg = (const char *)iter->data;
- if (extra_arg)
- launcher_argv[i++] = strdup(extra_arg);
-
- iter = g_list_next(iter);
- }
-
- *argc = launcher_argc;
- *argv = launcher_argv;
-
-
- return 0;
-}
-
-static void __destroy_launcher_argv(int argc, char **argv)
-{
- int i;
-
- if (argv == NULL)
- return;
-
- for (i = 0; i < argc; i++)
- free(argv[i]);
- free(argv);
-}
-
-static int __create_app_argv(int *argc, char ***argv, const char *app_path,
- bundle *kb, const char *app_type)
-{
- int new_argc;
- char **new_argv;
- bool attach = false;
- struct app_arg debug_arg = {0,};
- struct app_arg launcher_arg = {0,};
- struct app_arg arg = {0,};
- struct app_arg debug_extra_arg = {0,};
- int ret;
- int i;
- int c;
-
- ret = _debug_create_argv(&debug_arg.argc, &debug_arg.argv, &attach);
- if (ret < 0) {
- _E("Failed to create debugger argv");
- return -1;
- }
-
- if (attach) {
- *argc = debug_arg.argc;
- *argv = debug_arg.argv;
- return 0;
- }
-
- ret = _debug_create_extra_argv(&debug_extra_arg.argc,
- &debug_extra_arg.argv);
- if (ret < 0) {
- _E("Failed to create debugger extra argv");
- _debug_destroy_argv(debug_arg.argc, debug_arg.argv);
- return -1;
- }
-
- ret = __create_launcher_argv(&launcher_arg.argc, &launcher_arg.argv,
- app_type);
- if (ret < 0) {
- _E("Failed to create launcher argv");
- _debug_destroy_argv(debug_extra_arg.argc, debug_extra_arg.argv);
- _debug_destroy_argv(debug_arg.argc, debug_arg.argv);
- return -1;
- }
-
- arg.argc = bundle_export_to_argv(kb, &arg.argv);
- if (arg.argc <= 0) {
- _E("Failed to export bundle");
- __destroy_launcher_argv(launcher_arg.argc, launcher_arg.argv);
- _debug_destroy_argv(debug_extra_arg.argc, debug_extra_arg.argv);
- _debug_destroy_argv(debug_arg.argc, debug_arg.argv);
- return -1;
- }
- arg.argv[LOADER_ARG_PATH] = strdup(app_path);
-
- new_argc = debug_arg.argc + launcher_arg.argc + arg.argc +
- debug_extra_arg.argc;
- if (new_argc == arg.argc) {
- *argc = arg.argc;
- *argv = arg.argv;
- return 0;
- }
-
- new_argv = (char **)calloc(new_argc + 1, sizeof(char *));
- if (new_argv == NULL) {
- _E("out of memory");
- free(arg.argv[LOADER_ARG_PATH]);
- bundle_free_exported_argv(arg.argc, &arg.argv);
- __destroy_launcher_argv(launcher_arg.argc, launcher_arg.argv);
- _debug_destroy_argv(debug_extra_arg.argc, debug_extra_arg.argv);
- _debug_destroy_argv(debug_arg.argc, debug_arg.argv);
- return -1;
- }
-
- c = LOADER_ARG_PATH;
- for (i = 0; i < debug_arg.argc; i++)
- new_argv[c++] = debug_arg.argv[i];
- for (i = 0; i < launcher_arg.argc; i++)
- new_argv[c++] = launcher_arg.argv[i];
- for (i = 0; i < arg.argc; i++)
- new_argv[c++] = arg.argv[i];
- for (i = 0; i < debug_extra_arg.argc; i++)
- new_argv[c++] = debug_extra_arg.argv[i];
-
- *argc = new_argc;
- *argv = new_argv;
-
- return 0;
-}
-
-static void __real_launch(const char *app_path, bundle *kb,
- appinfo_t *menu_info)
-{
- int app_argc = 0;
- char **app_argv;
- int i;
- int ret;
-
- if (bundle_get_val(kb, AUL_K_DEBUG) != NULL)
- putenv("TIZEN_DEBUGGING_PORT=1");
-
- ret = __create_app_argv(&app_argc, &app_argv, app_path,
- kb, menu_info->app_type);
- if (ret < 0) {
- _E("Failed to create app argv");
- exit(-1);
- }
-
- for (i = 0; i < app_argc; i++)
- SECURE_LOGD("input argument %d : %s##", i, app_argv[i]);
-
- PERF("setup argument done");
- __normal_fork_exec(app_argc, app_argv, app_path);
-}
-
-static int __prepare_exec(const char *appid, const char *app_path,
- appinfo_t *menu_info, bundle *kb)
-{
- char *file_name;
- const char *enabled_light_user;
- char process_name[AUL_PR_NAME];
- int ret;
-
- /* Set new session ID & new process group ID*/
- /* In linux, child can set new session ID without check permission */
- /* TODO : should be add to check permission in the kernel*/
- setsid();
-
- ret = _launchpad_plugin_prepare_app(appid, kb);
- if (ret < 0) {
- _E("_launchpad_plugin_prepare_app() is failed. error(%d)", ret);
- return PAD_ERR_FAILED;
- }
-
- ret = _enable_external_pkg(kb, menu_info->pkgid,
- menu_info->global ? GLOBAL_USER : getuid());
- if (ret < 0)
- return PAD_ERR_FAILED;
-
- if (menu_info->global)
- ret = trust_anchor_launch(menu_info->pkgid, GLOBAL_USER);
- else
- ret = trust_anchor_launch(menu_info->pkgid, getuid());
- if (ret != TRUST_ANCHOR_ERROR_NONE &&
- ret != TRUST_ANCHOR_ERROR_NOT_INSTALLED) {
- _E("trust_anchor_launch() returns %d", ret);
- return PAD_ERR_REJECTED;
- }
-
- ret = _mount_res_dir(menu_info->root_path, kb);
- if (ret < 0)
- return PAD_ERR_FAILED;
-
- if (bundle_get_type(kb, AUL_K_SDK) != BUNDLE_TYPE_NONE)
- _debug_change_mount_namespace();
-
- /* SET PRIVILEGES*/
- enabled_light_user = bundle_get_val(kb, AUL_K_ENABLED_LIGHT_USER);
- _W("security_manager_prepare_app2 ++ %s", appid);
- ret = security_manager_prepare_app2(appid, enabled_light_user);
- _W("security_manager_prepare_app2 -- %s", appid);
- if (ret != SECURITY_MANAGER_SUCCESS)
- return PAD_ERR_REJECTED;
-
- if (bundle_get_type(kb, AUL_K_SDK) == BUNDLE_TYPE_NONE)
- _setup_stdio(basename(app_path));
-
- /* SET DUMPABLE - for coredump*/
- prctl(PR_SET_DUMPABLE, 1);
-
- /* SET PROCESS NAME*/
- if (app_path == NULL)
- return PAD_ERR_INVALID_ARGUMENT;
-
- file_name = strrchr(app_path, '/');
- if (file_name == NULL)
- return PAD_ERR_INVALID_PATH;
-
- file_name++;
- if (*file_name == '\0')
- return PAD_ERR_INVALID_PATH;
-
- memset(process_name, '\0', AUL_PR_NAME);
- snprintf(process_name, AUL_PR_NAME, "%s", file_name);
- prctl(PR_SET_NAME, process_name);
-
- /* SET ENVIROMENT*/
- _set_env(menu_info, kb);
-
- ret = _wait_tep_mount(kb);
- if (ret < 0)
- return PAD_ERR_FAILED;
-
- if (bundle_get_type(kb, AUL_K_SDK) == BUNDLE_TYPE_NONE) {
- ret = _prepare_app_socket();
- if (ret < 0)
- return PAD_ERR_FAILED;
-
- ret = _prepare_id_file();
- if (ret < 0)
- return PAD_ERR_FAILED;
- }
-
- _send_cmd_to_amd(APP_STARTUP_SIGNAL);
- return 0;
-}
-
-static int __exec_app_process(void *arg)
-{
- struct app_launch_arg *launch_arg = arg;
- int ret;
-
- _print_hwc_log("%d|after calling fork(). %s",
- getpid(), launch_arg->appid);
- PERF("fork done");
- _D("lock up test log(no error) : fork done");
-
- if (bundle_get_type(launch_arg->kb, AUL_K_SDK) != BUNDLE_TYPE_NONE)
- _debug_prepare_debugger(launch_arg->kb);
-
- _signal_unblock_sigchld();
-
- _delete_sock_path(getpid(), getuid());
-
- PERF("prepare exec - first done");
- ret = __prepare_exec(launch_arg->appid, launch_arg->app_path,
- launch_arg->menu_info, launch_arg->kb);
- if (ret < 0)
- return ret;
-
- PERF("prepare exec - second done");
- __real_launch(launch_arg->app_path, launch_arg->kb,
- launch_arg->menu_info);
-
- return PAD_ERR_FAILED;
-}
-
-static int __launch_directly(const char *appid, const char *app_path, int clifd,
- bundle *kb, appinfo_t *menu_info,
- candidate_process_context_t *cpc)
-{
- struct app_launch_arg arg;
- int pid;
-
- arg.appid = appid;
- arg.app_path = app_path;
- arg.menu_info = menu_info;
- arg.kb = kb;
-
- _print_hwc_log("before calling fork(). %s", appid);
- pid = __fork_app_process(__exec_app_process, &arg, 0);
- if (pid <= 0)
- _E("failed to fork app process");
-
- SECURE_LOGD("==> real launch pid : %d %s", pid, app_path);
-
- return pid;
-}
-
-static int __create_sock_activation(void)
-{
- int fds;
- char launchpad_process_pool_sock_path[108];
- int i;
-
- fds = sd_listen_fds(0);
- snprintf(launchpad_process_pool_sock_path,
- sizeof(launchpad_process_pool_sock_path), "%s/daemons/%u/%s",
- SOCKET_PATH, getuid(), PROCESS_POOL_LAUNCHPAD_SOCK);
-
- for (i = SD_LISTEN_FDS_START; i < SD_LISTEN_FDS_START + fds; ++i) {
- if (sd_is_socket_unix(i, SOCK_STREAM, 1,
- launchpad_process_pool_sock_path, 0) > 0)
- return i;
- }
-
- _W("There is no socket stream");
- return -1;
-}
-
-static int __get_launchpad_listen_fd(void)
-{
- const char *val;
-
- val = getenv("LAUNCHPAD_LISTEN_FD");
- if (!val) {
- _E("Failed to get LAUNCHPAD_LISTEN_FD");
- return -1;
- }
-
- _W("Listen Fd: %s", val);
- return atoi(val);
-}
-
-static int __launchpad_pre_init(int argc, char **argv)
-{
- int fd;
-
- /* create launchpad sock */
- fd = __create_sock_activation();
- if (fd >= 0)
- return fd;
-
- fd = __get_launchpad_listen_fd();
- if (fd >= 0)
- return fd;
-
- fd = _create_server_sock(PROCESS_POOL_LAUNCHPAD_SOCK);
- if (fd < 0) {
- _E("server sock error %d", fd);
- return -1;
- }
-
- return fd;
-}
-
-static bool __handle_loader_client_event(int fd, io_condition_e cond,
- void *data)
-{
- candidate_process_context_t *cpc = data;
-
- if (cpc == NULL)
- return false;
-
- 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 false;
- }
-
- return true;
-
-}
-
-static bool __handle_hydra_client_event(int fd, io_condition_e cond,
- void *data)
-{
- candidate_process_context_t *cpc = data;
- int recv_pid = -1;
- int ret;
-
- if (cpc == NULL)
- return false;
-
- 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 false;
- }
-
- if (cond & IO_IN) {
- ret = recv(cpc->hydra_fd, &recv_pid, sizeof(recv_pid),
- MSG_WAITALL);
- if (ret == -1) {
- _E("recv() is failed. errno(%d)", errno);
- } else {
- _W("candidate process: %d", recv_pid);
- if (recv_pid > 1)
- cpc->pid = recv_pid;
- }
- }
-
- return true;
-}
-
-static bool __handle_loader_event(int fd, io_condition_e cond, void *data)
-{
- candidate_process_context_t *cpc = data;
- int client_fd;
- int client_pid;
- int ret;
-
- if (cpc == NULL)
- return false;
-
- if (!cpc->prepared) {
- ret = __accept_candidate_process(fd, &client_fd, &client_pid,
- cpc->is_hydra ? -1 : cpc->pid);
- if (ret >= 0) {
- /* for hydra need to set pid to pid of non-hydra candidate, */
- /* which is connecting now */
- if (cpc->is_hydra)
- cpc->pid = client_pid;
-
- cpc->prepared = true;
- cpc->send_fd = client_fd;
-
- SECURE_LOGI("Type %d candidate process was connected, "
- "pid: %d", cpc->type, cpc->pid);
-
- _print_hwc_log("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 {
- __refuse_candidate_process(fd);
- _E("Refused candidate process connection");
- }
-
- return true;
-}
-
-static bool __handle_hydra_event(int fd, io_condition_e cond, void *data)
-{
- candidate_process_context_t *cpc = data;
- int client_fd;
- int client_pid;
- int ret;
-
- if (cpc == NULL)
- return false;
-
- if (!cpc->prepared) {
- ret = __accept_candidate_process(fd, &client_fd, &client_pid,
- cpc->hydra_pid);
- if (ret >= 0) {
- cpc->hydra_fd = client_fd;
-
- SECURE_LOGD("Type %d hydra process was connected,"
- " pid: %d", cpc->type, cpc->hydra_pid);
-
- 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 {
- __refuse_candidate_process(fd);
- _E("Refused hydra process connection");
- }
-
- return true;
-}
-
-static void __destroy_cleanup_info(struct cleanup_info_s *info)
-{
- if (!info)
- return;
-
- free(info->appid);
- free(info);
-}
-
-static struct cleanup_info_s *__create_cleanup_info(const char *appid, int pid)
-{
- struct cleanup_info_s *info;
-
- info = malloc(sizeof(struct cleanup_info_s));
- if (!info) {
- _E("Out of memory");
- return NULL;
- }
-
- info->appid = strdup(appid);
- if (!info->appid) {
- _E("strdup(%s) is failed", appid);
- __destroy_cleanup_info(info);
- return NULL;
- }
-
- info->pid = pid;
-
- return info;
-}
-
-static bool __cleanup_app_cb(void *user_data)
-{
- struct cleanup_info_s *info = (struct cleanup_info_s *)user_data;
-
- _W("security_manager_cleanup_app() ++");
- security_manager_cleanup_app(info->appid, getuid(), info->pid);
- _W("security_manager_cleanup_app() --");
- __destroy_cleanup_info(info);
- return false;
-}
-
-static void __handle_sigchild(int pid, void *user_data)
-{
- candidate_process_context_t *cpc;
- struct cleanup_info_s *info;
- char *appid;
- int ret = -1;
-
- appid = g_hash_table_lookup(__pid_table, GINT_TO_POINTER(pid));
- if (appid) {
- info = __create_cleanup_info(appid, pid);
- if (info)
- ret = _worker_add_job(__cleaner, __cleanup_app_cb, info);
-
- if (ret != 0) {
- __destroy_cleanup_info(info);
- _W("security_manager_cleanup_app() ++");
- security_manager_cleanup_app(appid, getuid(), pid);
- _W("security_manager_cleanup_app() --");
- }
-
- g_hash_table_remove(__pid_table, GINT_TO_POINTER(pid));
- }
-
- _log_print("[SIGCHLD]", "pid(%7d)", pid);
- cpc = __find_slot_from_pid(pid);
- if (cpc != NULL) {
- cpc->pid = CANDIDATE_NONE;
- __dispose_candidate_process(cpc);
- __prepare_candidate_process(cpc->type, cpc->loader_id);
- } else {
- cpc = __find_hydra_slot_from_pid(pid);
- if (cpc != NULL) {
- cpc->hydra_pid = HYDRA_NONE;
- __dispose_hydra_process(cpc);
- __prepare_candidate_process(cpc->type, cpc->loader_id);
- }
- }
-
- cpc = __find_slot_from_caller_pid(pid);
- while (cpc) {
- __remove_slot(LAUNCHPAD_LOADER_TYPE_DYNAMIC, cpc->loader_id);
- cpc = __find_slot_from_caller_pid(pid);
- }
-}
-
-static bool __handle_label_monitor(int fd, io_condition_e cond, void *data)
-{
- candidate_process_context_t *cpc;
- GList *iter = candidate_slot_list;
-
- if (cond & (IO_ERR | IO_HUP | IO_NVAL)) {
- _E("fd(%d), io_condition(%d)", fd, cond);
- abort();
- return false;
- }
-
- _D("fd(%d) condition(%d)", fd, cond);
- _log_print("[LABEL]", "fd(%d), condition(%d)", fd, cond);
- security_manager_app_labels_monitor_process(label_monitor);
-
- while (iter) {
- cpc = (candidate_process_context_t *)iter->data;
- if (cpc->is_hydra) {
- if (cpc->hydra_pid > 0) {
- __dispose_hydra_process(cpc);
- __prepare_candidate_process(cpc->type,
- cpc->loader_id);
- }
- } else if (cpc->pid > 0) {
- __dispose_candidate_process(cpc);
- __prepare_candidate_process(cpc->type, cpc->loader_id);
- }
-
- iter = g_list_next(iter);
- }
-
- return true;
-}
-
-static float __interpolator(float input, int cpu_max, int cpu_min)
-{
- float ret;
- float min = cpu_min / 100.0f;
- float max = cpu_max / 100.0f;
-
- if (input > 1.0f)
- input = 1.0f;
- if (input < 0.0f)
- input = 0.0f;
-
- ret = cos(input * PI) / 2.0f + 0.5f;
- ret *= max - min;
- ret += min;
-
- return ret;
-}
-
-static void __update_threshold(candidate_process_context_t *cpc, float delta)
-{
- static float pos = 0.0f;
-
- pos += delta;
- if (pos < 0.0f)
- pos = 0.0f;
-
- if (pos > 1.0f)
- pos = 1.0f;
-
- cpc->threshold = (int)(__interpolator(pos,
- cpc->threshold_max, cpc->threshold_min) * 100);
- _D("[CPU] type:%d / delta:%f / input cursor : %f / threshold : %d",
- cpc->type, delta, pos, cpc->threshold);
-}
-
-static gboolean __handle_idle_checker(gpointer data)
-{
- unsigned long long total = 0;
- unsigned long long idle = 0;
- int per;
- candidate_process_context_t *cpc;
-
- if (!data) {
- _E("Critical error!");
- __sequencer.idle_checker = 0;
- __sequencer.running_cpc = NULL;
- return G_SOURCE_REMOVE;
- }
-
- cpc = (candidate_process_context_t *)data;
- if (cpc->app_check && !cpc->app_exists) {
- _W("The application is not installed. loader(%s:%d)",
- cpc->loader_name, cpc->type);
- __sequencer.idle_checker = 0;
- __sequencer.running_cpc = NULL;
- return G_SOURCE_REMOVE;
- }
-
- if (cpc->state != CANDIDATE_PROCESS_STATE_RUNNING) {
- _W("Slot state is not running. loader(%s:%d)",
- cpc->loader_name, cpc->type);
- __sequencer.idle_checker = 0;
- __sequencer.running_cpc = NULL;
- return G_SOURCE_REMOVE;
- }
-
- if (cpc->pid != CANDIDATE_NONE) {
- _W("Slot is already running. %d:%s:%d",
- cpc->type, cpc->loader_name, cpc->pid);
- __sequencer.idle_checker = 0;
- __sequencer.running_cpc = NULL;
- return G_SOURCE_REMOVE;
- }
-
- _get_cpu_idle(&total, &idle);
- if (total == cpc->cpu_total_time)
- total++;
-
- per = (idle - cpc->cpu_idle_time) * 100 / (total - cpc->cpu_total_time);
- _D("[CPU] Idle : %d / loader(%s:%d)", per, cpc->loader_name, cpc->type);
-
- if (per >= cpc->threshold) {
- __update_threshold(cpc, -0.02f * (per - cpc->threshold));
- __prepare_candidate_process(cpc->type, cpc->loader_id);
- cpc->touched = true;
- __sequencer.idle_checker = 0;
- __sequencer.running_cpc = NULL;
- return G_SOURCE_REMOVE;
- }
-
- cpc->cpu_idle_time = idle;
- cpc->cpu_total_time = total;
- __update_threshold(cpc, 0.05f);
-
- cpc->cpu_check_count++;
- if (cpc->cpu_check_count == MAX_CPU_CHECK_COUNT) {
- _W("CPU check count has exceeded %d times. loader(%s:%d)",
- cpc->cpu_check_count,
- cpc->loader_name,
- cpc->type);
- __sequencer.idle_checker = 0;
- __sequencer.running_cpc = NULL;
- __sequencer_add_slot(cpc);
- return G_SOURCE_REMOVE;
- }
-
- return G_SOURCE_CONTINUE;
-}
-
-static gboolean __on_boot_timeout_cb(gpointer user_data)
-{
- candidate_process_context_t *context = user_data;
-
- _W("type(%d), loader_name(%s)", context->type, context->loader_name);
- context->on_boot_timer = 0;
- if (context->pid != CANDIDATE_NONE) {
- _E("Candidate process is already running. %d:%s:%d",
- context->type, context->loader_name,
- context->pid);
- } else {
- __prepare_candidate_process(context->type, context->loader_id);
- context->touched = true;
- }
-
- return G_SOURCE_REMOVE;
-}
-
-static void __add_on_boot_timer(candidate_process_context_t *context)
-{
- if (context->on_boot_timer != 0)
- return;
-
- context->on_boot_timer = g_timeout_add(context->on_boot_timeout,
- __on_boot_timeout_cb, context);
-}
-
-static int __add_idle_checker(int detection_method, GList *cur)
-{
- candidate_process_context_t *cpc;
- GList *iter = cur;
-
- while (iter) {
- cpc = (candidate_process_context_t *)iter->data;
- if (!cpc->touched && cpc->on_boot && cpc->on_boot_timeout > 0)
- __add_on_boot_timer(cpc);
-
- if (cpc->state != CANDIDATE_PROCESS_STATE_RUNNING) {
- iter = g_list_next(iter);
- continue;
- }
-
- if (strcmp("null", cpc->loader_path) == 0) {
- iter = g_list_next(iter);
- continue;
- }
-
- if (!cpc->touched && !cpc->on_boot) {
- iter = g_list_next(iter);
- continue;
- }
-
- if (cpc->app_check && !cpc->app_exists) {
- iter = g_list_next(iter);
- continue;
- }
-
- if (cpc->pid == CANDIDATE_NONE &&
- (!cpc->touched ||
- (cpc->detection_method & detection_method))) {
- if (cpc->timer > 0) {
- g_source_remove(cpc->timer);
- cpc->timer = 0;
- }
-
- cpc->cur_event = detection_method;
- __sequencer_add_slot(cpc);
- __sequencer_run();
- }
-
- iter = g_list_next(iter);
- }
-
- return -1;
-}
-
-static int __dispatch_cmd_hint(bundle *kb, int detection_method)
-{
- _W("cmd hint %d", detection_method);
- __add_idle_checker(detection_method, candidate_slot_list);
-
- return 0;
-}
-
-static int __dispatch_cmd_add_loader(bundle *kb)
-{
- const char *add_slot_str = NULL;
- const char *caller_pid = NULL;
- const char *extra;
- int lid, size;
- char *loader_name;
- candidate_process_context_t *cpc;
- slot_info_t slot_info;
-
- _W("cmd add loader");
- add_slot_str = bundle_get_val(kb, AUL_K_LOADER_PATH);
- caller_pid = bundle_get_val(kb, AUL_K_CALLER_PID);
- extra = bundle_get_val(kb, AUL_K_LOADER_EXTRA);
-
- if (add_slot_str == NULL || caller_pid == NULL)
- return -1;
-
- lid = __make_loader_id();
- size = snprintf(0, 0, "%s%s%d", add_slot_str, caller_pid, lid);
- loader_name = (char *)malloc(size + 1);
- if (loader_name == NULL) {
- _E("Out of memory");
- return -1;
- }
-
- snprintf(loader_name, size, "%s%s%d", add_slot_str, caller_pid, lid);
-
- slot_info.type = LAUNCHPAD_LOADER_TYPE_DYNAMIC;
- slot_info.loader_id = lid;
- slot_info.caller_pid = atoi(caller_pid);
- slot_info.loader_name = loader_name;
- slot_info.loader_path = add_slot_str;
- slot_info.loader_extra = extra;
- slot_info.detection_method = METHOD_TIMEOUT | METHOD_VISIBILITY;
- slot_info.activation_method = METHOD_REQUEST | METHOD_AVAILABLE_MEMORY;
- slot_info.deactivation_method = METHOD_TTL | METHOD_OUT_OF_MEMORY;
- slot_info.ttl = 600;
- slot_info.timeout_val = 2000;
- slot_info.threshold_max = DEFAULT_CPU_THRESHOLD_MAX;
- slot_info.threshold_min = DEFAULT_CPU_THRESHOLD_MIN;
- slot_info.on_boot = false;
- slot_info.app_exists = true;
- slot_info.is_hydra = false;
- slot_info.app_check = true;
- slot_info.on_boot_timeout = 0;
- slot_info.sched_priority = 0;
-
- cpc = __add_slot(&slot_info);
- free(loader_name);
- if (cpc == NULL)
- return -1;
-
- __set_timer(cpc);
- return lid;
-}
-
-static int __dispatch_cmd_add_app_defined_loader(bundle *kb)
-{
- const char *loader_name;
- int lid, len;
- candidate_process_context_t *cpc;
- loader_info_t *info;
- bundle_raw *extra;
- slot_info_t slot_info;
-
- _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 -EINVAL;
- }
-
- info = _loader_info_find_loader_by_loader_name(
- app_defined_loader_info_list, loader_name);
- if (info == NULL || info->extra == NULL) {
- _E("loader_name %s, info %d", loader_name, info != NULL);
- return -EINVAL;
- }
-
-
- cpc = __find_slot_from_loader_name(loader_name);
- if (cpc == NULL) {
- lid = __make_loader_id();
- bundle_encode(info->extra, &extra, &len);
- slot_info.type = LAUNCHPAD_LOADER_TYPE_DYNAMIC;
- slot_info.loader_id = lid;
- slot_info.caller_pid = 0;
- slot_info.loader_name = loader_name;
- slot_info.loader_path = "/usr/bin/app-defined-loader";
- slot_info.loader_extra = (const char *)extra;
- slot_info.detection_method = METHOD_TIMEOUT | METHOD_VISIBILITY;
- slot_info.activation_method =
- METHOD_REQUEST | METHOD_AVAILABLE_MEMORY;
- slot_info.deactivation_method =
- METHOD_TTL | METHOD_OUT_OF_MEMORY;
- slot_info.ttl = info->ttl;
- slot_info.timeout_val = 2000;
- slot_info.threshold_max = DEFAULT_CPU_THRESHOLD_MAX;
- slot_info.threshold_min = DEFAULT_CPU_THRESHOLD_MIN;
- slot_info.on_boot = false;
- slot_info.app_exists = true;
- slot_info.is_hydra = false;
- slot_info.app_check = true;
- slot_info.on_boot_timeout = 0;
- slot_info.sched_priority = 0;
-
- cpc = __add_slot(&slot_info);
- bundle_free_encoded_rawdata(&extra);
- if (cpc == NULL) {
- _E("cpc is NULL");
- return -ENOMEM;
- }
- } else {
- lid = cpc->loader_id;
- }
-
- if (cpc->pid == CANDIDATE_NONE)
- __prepare_candidate_process(LAUNCHPAD_LOADER_TYPE_DYNAMIC, lid);
-
- return lid;
-}
-
-static int __dispatch_cmd_remove_loader(bundle *kb)
-{
- const char *id = bundle_get_val(kb, AUL_K_LOADER_ID);
- int lid;
-
- _W("cmd remove loader");
- if (id) {
- lid = atoi(id);
- if (__remove_slot(LAUNCHPAD_LOADER_TYPE_DYNAMIC, lid) == 0)
- return 0;
- }
-
- return -1;
-}
-
-static int __check_caller_by_pid(int pid)
-{
- int ret;
- char buf[PATH_MAX] = { 0, };
-
- ret = _proc_get_attr(pid, buf, sizeof(buf));
- if (ret < 0)
- return -1;
-
- if (strcmp(buf, "User") == 0 ||
- strcmp(buf, "System") == 0 ||
- strcmp(buf, "System::Privileged") == 0)
- return 0;
-
- return -1;
-}
-
-static bool __is_hw_acc(const char *hwacc)
-{
- if (strcmp(hwacc, "USE") == 0 ||
- (strcmp(hwacc, "SYS") == 0 &&
- __sys_hwacc == SETTING_HW_ACCELERATION_ON))
- return true;
-
- return false;
-}
-
-static candidate_process_context_t *__find_available_slot(const char *hwacc,
- const char *app_type, const char *loader_name,
- candidate_process_context_t **org_cpc)
-{
- int type;
- candidate_process_context_t *cpc;
- int *a_types;
- int len = 0;
- int i;
-
- if (loader_name) {
- type = _loader_info_find_type_by_loader_name(loader_info_list,
- loader_name);
- } else {
- type = _loader_info_find_type(loader_info_list,
- app_type, __is_hw_acc(hwacc));
- }
- cpc = __find_slot(type, PAD_LOADER_ID_STATIC);
- if (!cpc)
- return NULL;
-
- *org_cpc = cpc;
-
- if (cpc->prepared)
- return cpc;
-
- a_types = _loader_get_alternative_types(loader_info_list, type, &len);
- if (!a_types)
- return NULL;
-
- for (i = 0; i < len; i++) {
- cpc = __find_slot(a_types[i], PAD_LOADER_ID_STATIC);
- if (!cpc)
- continue;
- if (cpc->prepared) {
- free(a_types);
- return cpc;
- }
- }
-
- free(a_types);
- return NULL;
-}
-
-static void __update_slot(int type, bool app_exists)
-{
- candidate_process_context_t *cpc;
-
- cpc = __find_slot(type, PAD_LOADER_ID_STATIC);
- if (!cpc)
- return;
-
- cpc->app_exists = app_exists;
- if (cpc->app_check && !cpc->app_exists) {
- if (cpc->pid > 0)
- __dispose_candidate_process(cpc);
- __sequencer_remove_slot(cpc);
- if (__sequencer_queue_is_empty())
- __sequencer_stop();
- } else {
- if (cpc->state != CANDIDATE_PROCESS_STATE_RUNNING)
- return;
-
- if (!cpc->touched && !cpc->on_boot)
- return;
-
- if (cpc->timer > 0) {
- g_source_remove(cpc->timer);
- cpc->timer = 0;
- }
-
- if (cpc->pid == CANDIDATE_NONE) {
- __sequencer_add_slot(cpc);
- __sequencer_run();
- }
- }
-}
-
-static void __foreach_loader_info(loader_info_t *info, void *data)
-{
- struct app_info *ai = (struct app_info *)data;
- bool exist;
-
- exist = _loader_info_exist_app_type(info, ai->type);
- if (!exist)
- return;
-
- info->app_exists = ai->exists;
- __update_slot(info->type, info->app_exists);
-}
-
-static int __dispatch_cmd_update_app_type(bundle *b)
-{
- int r;
- struct app_info info;
- const char *is_installed;
-
- info.type = bundle_get_val(b, AUL_K_APP_TYPE);
- if (!info.type)
- return -1;
-
- is_installed = bundle_get_val(b, AUL_K_IS_INSTALLED);
- if (is_installed && !strcmp(is_installed, "true"))
- info.exists = true;
- else
- info.exists = false;
-
- _I("[LAUNCHPAD] type(%s), exists(%d)", info.type, info.exists);
-
- r = _loader_info_foreach(loader_info_list, __foreach_loader_info,
- &info);
- if (r != 0) {
- _E("Failed to retrieve loader info");
- return -1;
- }
-
- return 0;
-}
-
-static void __deactivate_slot(candidate_process_context_t *cpc)
-{
- if (cpc->state == CANDIDATE_PROCESS_STATE_PAUSED)
- return;
-
- cpc->state = CANDIDATE_PROCESS_STATE_PAUSED;
- if (cpc->is_hydra)
- __dispose_hydra_process(cpc);
- else
- __dispose_candidate_process(cpc);
-}
-
-static void __activate_slot(candidate_process_context_t *cpc)
-{
- if (cpc->state == CANDIDATE_PROCESS_STATE_RUNNING)
- return;
-
- cpc->state = CANDIDATE_PROCESS_STATE_RUNNING;
- if (!cpc->touched && !cpc->on_boot)
- return;
-
- if ((cpc->app_check && !cpc->app_exists) || cpc->pid > CANDIDATE_NONE)
- return;
-
- if (cpc->detection_method & METHOD_TIMEOUT)
- __set_timer(cpc);
-}
-
-static void __update_slot_state(candidate_process_context_t *cpc, int method,
- bool force)
-{
- switch (method) {
- case METHOD_OUT_OF_MEMORY:
- if ((force || cpc->deactivation_method & method) &&
- __is_low_memory()) {
- _W("Low memory, deactivate slot %d", cpc->type);
- __deactivate_slot(cpc);
- } else {
- __activate_slot(cpc);
- }
- break;
- case METHOD_TTL:
- if (force || cpc->deactivation_method & method)
- __deactivate_slot(cpc);
- break;
- case METHOD_AVAILABLE_MEMORY:
- if (force || cpc->activation_method & method)
- __activate_slot(cpc);
- break;
- case METHOD_REQUEST:
- if (force || cpc->activation_method & method)
- __update_slot_state(cpc, METHOD_OUT_OF_MEMORY, force);
- break;
- default:
- __activate_slot(cpc);
- break;
- }
-}
-
-static void __request_destroy(request_t *request)
-{
- if (request == NULL)
- return;
-
- if (request->clifd > -1)
- close(request->clifd);
- if (request->menu_info)
- _appinfo_free(request->menu_info);
- if (request->kb)
- bundle_free(request->kb);
- if (request->pkt)
- free(request->pkt);
- free(request);
-}
-
-static int __request_create(int fd, request_t **request)
-{
- struct ucred cr;
- request_t *req;
-
- if (request == NULL) {
- _E("Invalid parameter");
- return -EINVAL;
- }
-
- req = calloc(1, sizeof(request_t));
- if (req == NULL) {
- _E("calloc() is failed");
- return -ENOMEM;
- }
-
- req->clifd = -1;
- req->pkt = _accept_recv_pkt_raw(fd, &req->clifd, &cr);
- if (req->pkt == NULL) {
- _E("_accept_recv_pkt_raw() is failed");
- __request_destroy(req);
- return -ECOMM;
- }
-
- req->kb = bundle_decode(req->pkt->data, req->pkt->len);
- if (req->kb == NULL) {
- _E("bundle_decode() is failed");
- __real_send(req->clifd, -EINVAL);
- req->clifd = -1;
- __request_destroy(req);
- return -EINVAL;
- }
-
- req->cmd = req->pkt->cmd;
- req->caller_pid = cr.pid;
- req->caller_uid = cr.uid;
- *request = req;
- return 0;
-}
-
-static void __request_send_result(request_h request, int result)
-{
- if (request->clifd < 0)
- return;
-
- __real_send(request->clifd, result);
- request->clifd = -1;
-}
-
-static int __visibility_request_handler(request_h request)
-{
- int ret = __dispatch_cmd_hint(request->kb, METHOD_VISIBILITY);
-
- __request_send_result(request, ret);
- _D("[PAD_CMD_VISIBILITY] result: %d", ret);
- return ret;
-}
-
-static int __add_loader_request_handler(request_h request)
-{
- int ret = __dispatch_cmd_add_loader(request->kb);
-
- __request_send_result(request, ret);
- _D("[PAD_CMD_ADD_LOADER] result: %d", ret);
- return ret;
-}
-
-static int __remove_loader_request_handler(request_h request)
-{
- int ret = __dispatch_cmd_remove_loader(request->kb);
-
- __request_send_result(request, ret);
- _D("[PAD_CMD_REMOVE_LOADER] result: %d", ret);
- return ret;
-}
-
-static int __make_default_slots_request_handler(request_h request)
-{
- int ret = __add_default_slots();
-
- __request_send_result(request, ret);
- _D("[PAD_CMD_MAKE_DEFAULT_SLOTS] result: %d", ret);
- return ret;
-}
-
-static int __prepare_app_defined_loader_request_handler(request_h request)
-{
- int ret = __dispatch_cmd_add_app_defined_loader(request->kb);
-
- __request_send_result(request, ret);
- _D("[PAD_CMD_PREPARE_APP_DEFINED_LOADER] result: %d", ret);
- return ret;
-}
-
-static int __demand_request_handler(request_h request)
-{
- int ret = __dispatch_cmd_hint(request->kb, METHOD_DEMAND);
-
- __request_send_result(request, ret);
- _D("[PAD_CMD_DEMAND] result: %d", ret);
- return ret;
-}
-
-static int __ping_request_handler(request_h request)
-{
- __request_send_result(request, getpid());
- _D("[PAD_CMD_PING] result: %d", getpid());
- return 0;
-}
-
-static int __update_app_type_request_handler(request_h request)
-{
- int ret = __dispatch_cmd_update_app_type(request->kb);
-
- _D("[PAD_CMD_UPDATE_APP_TYPE] result: %d", ret);
- return ret;
-}
-
-static int __connect_request_handler(request_h request)
-{
- if (__client_fd != -1)
- close(__client_fd);
-
- __client_fd = request->clifd;
- request->clifd = -1;
- _D("[PAD_CMD_CONNECT] client fd: %d", __client_fd);
- return 0;
-}
-
-static int __launch_request_prepare(request_h request)
-{
- const appinfo_t *menu_info;
- int type = -1;
-
- request->menu_info = _appinfo_create(request->kb);
- if (request->menu_info == NULL) {
- _E("_appinfo_create() is failed");
- return -1;
- }
-
- request->app_path = _appinfo_get_app_path(request->menu_info);
- if (request->app_path == NULL) {
- _E("_appinfo_get_app_path() is failed");
- return -1;
- }
-
- if (request->app_path[0] != '/') {
- _E("app path is not absolute path");
- return -1;
- }
-
- menu_info = request->menu_info;
- if (menu_info->hwacc == NULL) {
- _E("Failed to find HW acceeleration type");
- return -1;
- }
-
- SECURE_LOGD("appid: %s", menu_info->appid);
- SECURE_LOGD("exec: %s", menu_info->app_path);
- SECURE_LOGD("comp_type: %s", menu_info->comp_type);
- SECURE_LOGD("internal pool: %s", menu_info->internal_pool);
- SECURE_LOGD("hwacc: %s", menu_info->hwacc);
- SECURE_LOGD("app_type: %s", menu_info->app_type);
- SECURE_LOGD("pkg_type: %s", menu_info->pkg_type);
-
- if (menu_info->comp_type && !strcmp(menu_info->comp_type, "svcapp")) {
- request->loader_id = __get_loader_id(request->kb);
- if (request->loader_id > PAD_LOADER_ID_DYNAMIC_BASE) {
- type = LAUNCHPAD_LOADER_TYPE_DYNAMIC;
- request->cpc = __find_slot(type, request->loader_id);
- if (request->cpc && !request->cpc->prepared)
- request->cpc = NULL;
- } else {
- request->loader_id = PAD_LOADER_ID_DIRECT;
- }
- } else if (menu_info->comp_type && menu_info->app_type &&
- !strcmp(menu_info->comp_type, "widgetapp") &&
- !strcmp(menu_info->app_type, "webapp")) {
- request->loader_id = PAD_LOADER_ID_DIRECT;
- } else {
- request->loader_id = __get_loader_id(request->kb);
- if (request->loader_id <= PAD_LOADER_ID_STATIC) {
- request->cpc = __find_available_slot(menu_info->hwacc,
- menu_info->app_type,
- menu_info->loader_name,
- &request->org_cpc);
- } else {
- type = LAUNCHPAD_LOADER_TYPE_DYNAMIC;
- request->cpc = __find_slot(type, request->loader_id);
- if (request->cpc && !request->cpc->prepared)
- request->cpc = NULL;
- }
- }
-
- _modify_bundle(request->kb, request->caller_pid, request->menu_info,
- request->cmd);
- if (menu_info->appid == NULL) {
- _E("Unable to get appid from app info");
- return -1;
- }
-
- PERF("Getting package information & modifying bundle done");
- return 0;
-}
-
-static void __launch_request_complete(request_h request)
-{
- _memory_monitor_reset_timer();
- __request_send_result(request, request->pid);
-
- if (request->pid > 0) {
- _dbus_send_app_launch_signal(request->pid,
- request->menu_info->appid);
- g_hash_table_insert(__pid_table, GINT_TO_POINTER(request->pid),
- strdup(request->menu_info->appid));
- _log_print("[LAUNCH]", "pid(%7d) | appid(%s)",
- request->pid, request->menu_info->appid);
- }
-}
-
-static void __handle_direct_launch(request_h request)
-{
- if (request->org_cpc && (!request->org_cpc->app_check ||
- request->org_cpc->app_exists) &&
- request->org_cpc->pid == CANDIDATE_NONE &&
- !__sequencer_slot_exist(request->org_cpc)) {
- if (request->org_cpc->timer > 0) {
- g_source_remove(request->org_cpc->timer);
- request->org_cpc->timer = 0;
- }
-
- __update_slot_state(request->org_cpc, METHOD_REQUEST, true);
- __set_timer(request->org_cpc);
- }
-}
-
-static void __fork_processing(request_h request)
-{
- if (bundle_get_type(request->kb, AUL_K_SDK) != BUNDLE_TYPE_NONE)
- _debug_init();
-
- _W("appid: %s", request->menu_info->appid);
- request->pid = __launch_directly(request->menu_info->appid,
- request->app_path, request->clifd, request->kb,
- request->menu_info, NULL);
- if (request->pid == -1) {
- _E("Failed to create a child process. appid(%s)",
- request->menu_info->appid);
- }
-
- __request_send_result(request, request->pid);
- _W("appid: %s, pid: %d", request->menu_info->appid, request->pid);
- __handle_direct_launch(request);
-}
-
-static int __launch_request_do(request_h request)
-{
- if (request->loader_id == PAD_LOADER_ID_DIRECT ||
- request->cpc == NULL) {
- __fork_processing(request);
- return 0;
- }
-
- _W("Launch %d type process. appid(%s)",
- request->cpc->type, request->menu_info->appid);
- request->pid = __send_launchpad_loader(request->cpc, request->pkt,
- request->app_path, request->clifd);
- return 0;
-}
-
-static int __launch_request_handler(request_h request)
-{
- int ret;
-
- traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "LAUNCHPAD:LAUNCH");
- INIT_PERF(kb);
- PERF("Packet processing start");
-
- ret = __launch_request_prepare(request);
- if (ret < 0) {
- traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
- __request_send_result(request, ret);
- return ret;
- }
-
- ret = __launch_request_do(request);
- if (ret < 0)
- request->pid = ret;
-
- __launch_request_complete(request);
- traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
- _D("[PAD_CMD_LAUNCH] appid: %s, result: %d",
- request->menu_info->appid, request->pid);
- return 0;
-}
-
-static request_handler __request_handlers[] = {
- [PAD_CMD_VISIBILITY] = __visibility_request_handler,
- [PAD_CMD_ADD_LOADER] = __add_loader_request_handler,
- [PAD_CMD_REMOVE_LOADER] = __remove_loader_request_handler,
- [PAD_CMD_MAKE_DEFAULT_SLOTS] = __make_default_slots_request_handler,
- [PAD_CMD_PREPARE_APP_DEFINED_LOADER] =
- __prepare_app_defined_loader_request_handler,
- [PAD_CMD_DEMAND] = __demand_request_handler,
- [PAD_CMD_PING] = __ping_request_handler,
- [PAD_CMD_UPDATE_APP_TYPE] = __update_app_type_request_handler,
- [PAD_CMD_CONNECT] = __connect_request_handler,
- [PAD_CMD_LAUNCH] = __launch_request_handler,
-};
-
-static bool __handle_launch_event(int fd, io_condition_e cond, void *data)
-{
- request_t *request = NULL;
- int ret;
-
- if (cond & (IO_ERR | IO_HUP | IO_NVAL)) {
- _E("fd(%d), condition(%d)", fd, cond);
- g_idle_add(__launchpad_recovery_cb, __launchpad_channel);
- __launchpad_channel = NULL;
- return false;
- }
-
- ret = __request_create(fd, &request);
- if (ret != 0)
- return true;
-
- _W("cmd(%d), caller(%d)", request->cmd, request->caller_pid);
- if (request->caller_uid >= REGULAR_UID_MIN) {
- if (__check_caller_by_pid(request->caller_pid) < 0) {
- _E("Permission denied. pid(%d)", request->caller_pid);
- __request_send_result(request, -EPERM);
- __request_destroy(request);
- return true;
- }
- }
-
- if (request->cmd < 0 || request->cmd >= ARRAY_SIZE(__request_handlers)
- || __request_handlers[request->cmd] == NULL) {
- _E("Unknown command: %d", request->cmd);
- __request_send_result(request, -EINVAL);
- __request_destroy(request);
- return true;
- }
-
- __request_handlers[request->cmd](request);
- __request_destroy(request);
- return true;
-}
-
-static void __destroy_slot(candidate_process_context_t *cpc)
-{
- if (!cpc)
- return;
-
- if (cpc->hydra_channel)
- _io_channel_destroy(cpc->hydra_channel);
-
- if (cpc->channel)
- _io_channel_destroy(cpc->channel);
-
- if (cpc->loader_extra)
- free(cpc->loader_extra);
-
- if (cpc->loader_path)
- free(cpc->loader_path);
-
- if (cpc->loader_name)
- free(cpc->loader_name);
-
- free(cpc);
-}
-
-static candidate_process_context_t *__create_slot(slot_info_t *info)
-{
- candidate_process_context_t *cpc;
-
- cpc = calloc(1, sizeof(candidate_process_context_t));
- if (cpc == NULL) {
- _E("Out of memory");
- return NULL;
- }
-
- cpc->loader_name = strdup(info->loader_name);
- if (cpc->loader_name == NULL) {
- _E("Failed to duplicate loader name(%s)", info->loader_name);
- __destroy_slot(cpc);
- return NULL;
- }
-
- cpc->loader_path = strdup(info->loader_path);
- if (cpc->loader_path == NULL) {
- _E("Failed to duplicate loader path(%s)", info->loader_path);
- __destroy_slot(cpc);
- return NULL;
- }
-
- cpc->loader_extra =
- info->loader_extra ? strdup(info->loader_extra) : strdup("");
- if (cpc->loader_extra == NULL) {
- _E("Failed to duplicate loader extra(%s)", info->loader_extra);
- __destroy_slot(cpc);
- return NULL;
- }
-
- cpc->type = info->type;
- cpc->prepared = false;
- cpc->pid = CANDIDATE_NONE;
- cpc->hydra_pid = HYDRA_NONE;
- cpc->caller_pid = info->caller_pid;
- cpc->loader_id = info->loader_id;
- cpc->send_fd = -1;
- cpc->hydra_fd = -1;
- cpc->last_exec_time = 0;
- cpc->timer = 0;
- cpc->detection_method = info->detection_method;
- cpc->timeout_val = info->timeout_val;
- cpc->cpu_total_time = 0;
- cpc->cpu_idle_time = 0;
- cpc->threshold = info->threshold_max;
- cpc->threshold_max = info->threshold_max;
- cpc->threshold_min = info->threshold_min;
- cpc->on_boot = info->on_boot;
- cpc->app_exists = info->app_exists;
- cpc->touched = false;
- cpc->cur_event = 0;
- cpc->activation_method = info->activation_method;
- cpc->deactivation_method = info->deactivation_method;
- cpc->ttl = info->ttl;
- cpc->live_timer = 0;
- cpc->is_hydra = info->is_hydra;
- cpc->app_check = info->app_check;
- cpc->score = WIN_SCORE;
- cpc->pss = 0;
- cpc->cpu_check_count = 0;
- cpc->on_boot_timeout = info->on_boot_timeout;
- cpc->sched_priority = info->sched_priority;
-
- if ((cpc->deactivation_method & METHOD_OUT_OF_MEMORY) &&
- __is_low_memory())
- cpc->state = CANDIDATE_PROCESS_STATE_PAUSED;
- else
- cpc->state = CANDIDATE_PROCESS_STATE_RUNNING;
-
- _W("loader(%s), type(%d), state(%d)",
- cpc->loader_name, cpc->type, cpc->state);
- return cpc;
-}
-
-static candidate_process_context_t *__add_slot(slot_info_t *info)
-{
- candidate_process_context_t *cpc;
- int fd;
- io_channel_h channel;
- int hydra_fd;
- io_channel_h hydra_channel;
-
- if (info == NULL)
- return NULL;
-
- if (__find_slot(info->type, info->loader_id) != NULL)
- return NULL;
-
- cpc = __create_slot(info);
- if (cpc == NULL)
- return NULL;
-
- fd = __listen_candidate_process(cpc->type, cpc->loader_id);
- if (fd == -1) {
- _E("[launchpad] Listening the socket to " \
- "the type %d candidate process failed.",
- cpc->type);
- __destroy_slot(cpc);
- return NULL;
- }
-
- channel = _io_channel_create(fd, IO_IN, __handle_loader_event, cpc);
- if (!channel) {
- close(fd);
- __destroy_slot(cpc);
- return NULL;
- }
-
- cpc->channel = channel;
-
- if (info->is_hydra) {
- hydra_fd = __listen_hydra_process(cpc->type, cpc->loader_id);
- if (hydra_fd == -1) {
- _E("[launchpad] Listening the socket to " \
- "the type %d hydra process failed.",
- cpc->type);
- __destroy_slot(cpc);
- return NULL;
- }
-
- hydra_channel = _io_channel_create(hydra_fd, IO_IN,
- __handle_hydra_event, cpc);
- if (!hydra_channel) {
- close(hydra_fd);
- __destroy_slot(cpc);
- return NULL;
- }
-
- cpc->hydra_channel = hydra_channel;
- }
-
- candidate_slot_list = g_list_append(candidate_slot_list, cpc);
-
- return cpc;
-}
-
-static int __remove_slot(int type, int loader_id)
-{
- candidate_process_context_t *cpc;
- GList *iter;
-
- iter = candidate_slot_list;
- while (iter) {
- cpc = (candidate_process_context_t *)iter->data;
- if (type == cpc->type && loader_id == cpc->loader_id) {
- __dispose_candidate_process(cpc);
- candidate_slot_list = g_list_delete_link(
- candidate_slot_list, iter);
- __destroy_slot(cpc);
- return 0;
- }
-
- iter = g_list_next(iter);
- }
-
- return -1;
-}
-
-static int __init_launchpad_fd(int argc, char **argv)
-{
- io_condition_e cond;
- int fd;
-
- fd = __launchpad_pre_init(argc, argv);
- if (fd < 0) {
- _E("launchpad pre init failed");
- return -1;
- }
-
- cond = IO_IN | IO_PRI | IO_HUP | IO_ERR | IO_NVAL;
- __launchpad_channel = _io_channel_create(fd, cond,
- __handle_launch_event, NULL);
- if (!__launchpad_channel) {
- close(fd);
- return -1;
- }
-
- 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)) {
- _W("%s is created", 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;
- loader_info_t* info;
- candidate_process_context_t *cpc;
-
- if (!event_name) {
- _E("Invalid parameter");
- return true;
- }
-
- ext = strrchr(event_name, '.');
- if (ext == NULL || strcmp(ext, ".loader") != 0)
- return true;
-
- _W("event_name(%s), mask(%u)", event_name, mask);
- 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 + 1, "%s", event_name);
-
- info = _loader_info_find_loader_by_loader_name(
- app_defined_loader_info_list, buf);
- cpc = __find_slot_from_loader_name(info->name);
- __remove_slot(cpc->type, cpc->loader_id);
- 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)
-{
- io_condition_e cond;
- int r;
- int fd = -1;
-
- r = security_manager_app_labels_monitor_init(&label_monitor);
- if (r != SECURITY_MANAGER_SUCCESS)
- return -1;
-
- r = security_manager_app_labels_monitor_process(label_monitor);
- if (r != SECURITY_MANAGER_SUCCESS)
- goto err;
-
- security_manager_app_labels_monitor_get_fd(label_monitor, &fd);
- if (fd < 0) {
- _E("failed to get fd");
- goto err;
- }
-
- cond = IO_IN | IO_PRI | IO_HUP | IO_ERR | IO_NVAL;
- __label_monitor_channel = _io_channel_create(fd, cond,
- __handle_label_monitor, NULL);
- if (!__label_monitor_channel)
- goto err;
-
- return 0;
-
-err:
- if (fd > 0)
- close(fd);
-
- if (label_monitor) {
- security_manager_app_labels_monitor_finish(label_monitor);
- label_monitor = NULL;
- }
-
- return -1;
-}
-
-static int __verify_loader_caps(const char *loader)
-{
- cap_t cap_d;
- cap_flag_value_t eff_state;
- cap_flag_value_t inh_state;
- cap_value_t values[] = {CAP_SETGID, CAP_MAC_ADMIN};
- int r;
- int i;
- int size = ARRAY_SIZE(values);
-
- /* If Dytransition feature is enabled, CAP_MAC_ADMIN is unnecessary */
- if (label_monitor)
- size--;
-
- cap_d = cap_get_file(loader);
- if (!cap_d) {
- _E("Failed to get cap from file(%s)", loader);
- return -1;
- }
-
- for (i = 0; i < size; i++) {
- r = cap_get_flag(cap_d, values[i], CAP_INHERITABLE, &inh_state);
- if (r != 0) {
- _E("Failed to get cap inh - errno(%d)", errno);
- cap_free(cap_d);
- return -1;
- }
-
- r = cap_get_flag(cap_d, values[i], CAP_EFFECTIVE, &eff_state);
- if (r != 0) {
- _E("Failed to get cap eff - errno(%d)", errno);
- cap_free(cap_d);
- return -1;
- }
-
- if ((inh_state != CAP_SET) || (eff_state != CAP_SET)) {
- _E("The %s doesn't have %d cap", loader, values[i]);
- cap_free(cap_d);
- return -1;
- }
- }
- cap_free(cap_d);
-
- return 0;
-}
-
-static void __get_app_type_string(loader_info_t *info, char buf[], int size)
-{
- GList *iter = info->app_types;
- char *app_type;
- char *ptr = buf;
- int len;
-
- while (iter) {
- app_type = (char *)iter->data;
- iter = g_list_next(iter);
- len = strlen(app_type);
- if (size < len + 1)
- return;
-
- strncpy(ptr, app_type, size);
- ptr += len;
- size -= len;
- if (iter) {
- (*ptr++) = ' ';
- size--;
- }
- }
-}
-
-static void __add_slot_from_info(gpointer data, gpointer user_data)
-{
- loader_info_t *info = (loader_info_t *)data;
- candidate_process_context_t *cpc;
- bundle_raw *extra = NULL;
- int len;
- char buf[2048] = {0, };
- slot_info_t slot_info = {
- .type = LAUNCHPAD_LOADER_TYPE_USER + user_slot_offset,
- .loader_name = info->name,
- .loader_path = info->exe,
- .threshold_max = info->cpu_threshold_max,
- .threshold_min = info->cpu_threshold_min,
- .app_exists = info->app_exists,
- .is_hydra = info->is_hydra,
- .app_check = info->app_check,
- .on_boot_timeout = info->on_boot_timeout,
- .sched_priority = info->sched_priority,
- };
-
- if (!strcmp(info->exe, "null")) {
- slot_info.loader_id = PAD_LOADER_ID_DIRECT;
-
- cpc = __add_slot(&slot_info);
- if (cpc == NULL)
- return;
-
- info->type = LAUNCHPAD_LOADER_TYPE_USER + user_slot_offset;
- user_slot_offset++;
- return;
- }
-
- if (access(info->exe, F_OK | X_OK) == 0) {
- if (__verify_loader_caps(info->exe) < 0)
- return;
-
- if (info->extra)
- bundle_encode(info->extra, &extra, &len);
-
- slot_info.loader_id = PAD_LOADER_ID_STATIC;
- slot_info.loader_extra = (const char *)extra;
- slot_info.detection_method = info->detection_method;
- slot_info.activation_method = info->activation_method;
- slot_info.deactivation_method = info->deactivation_method;
- slot_info.ttl = info->ttl;
- slot_info.timeout_val = info->timeout_val;
- slot_info.on_boot = info->on_boot;
-
- cpc = __add_slot(&slot_info);
- bundle_free_encoded_rawdata(&extra);
- if (cpc == NULL)
- return;
-
- info->type = LAUNCHPAD_LOADER_TYPE_USER + user_slot_offset;
- user_slot_offset++;
- __get_app_type_string(info, buf, sizeof(buf));
- _I("candidate slot. app-type(%s) loader-type(%d)",
- buf, info->type);
- _print_hwc_log("candidate slot. app-type(%s) loader-type(%d)",
- buf, info->type);
- }
-}
-
-static int __add_default_slots(void)
-{
- if (loader_info_list)
- _loader_info_dispose(loader_info_list);
-
- loader_info_list = _loader_info_load_dir(LOADER_INFO_PATH);
- if (loader_info_list == NULL)
- return -1;
-
- user_slot_offset = 0;
- g_list_foreach(loader_info_list, __add_slot_from_info, NULL);
- __add_idle_checker(0, candidate_slot_list);
-
- 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_monitor_is_low_memory())
- return true;
-
- if (__memory_status_low >= MEMORY_STATUS_LOW)
- return true;
-
- return false;
-}
-
-static void __hw_acceleration_changed_cb(keynode_t *key, void *data)
-{
- __sys_hwacc = vconf_keynode_get_int(key);
- _D("sys hwacc: %d", __sys_hwacc);
-}
-
-static void __update_lang(keynode_t *node, void *user_data)
-{
- char *lang;
-
- lang = vconf_keynode_get_str(node);
- if (!lang) {
- _E("Failed to get language");
- return;
- }
-
- setenv("LANG", lang, 1);
-}
-
-static void __region_format_changed_cb(keynode_t *node, void *data)
-{
- char *region;
-
- region = vconf_keynode_get_str(node);
- if (!region) {
- _E("Failed to get value");
- return;
- }
-
- setenv("LC_CTYPE", region, 1);
-}
-
-static void __memory_status_low_changed_cb(keynode_t *node, void *data)
-{
- candidate_process_context_t *cpc;
- GList *iter;
-
- __memory_status_low = vconf_keynode_get_int(node);
- if (__memory_status_low >= MEMORY_STATUS_LOW) {
- _W("Low memory");
- iter = candidate_slot_list;
- while (iter) {
- cpc = (candidate_process_context_t *)iter->data;
- __update_slot_state(cpc, METHOD_OUT_OF_MEMORY, false);
- iter = g_list_next(iter);
- }
- }
-}
-
-static void __memory_status_normal_changed_cb(keynode_t *node, void *data)
-{
- candidate_process_context_t *cpc;
- GList *iter;
-
- __memory_status_normal = vconf_keynode_get_int(node);
- if (__memory_status_normal == MEMORY_STATUS_NORMAL) {
- _W("Normal");
- iter = candidate_slot_list;
- while (iter) {
- cpc = (candidate_process_context_t *)iter->data;
- __update_slot_state(cpc, METHOD_AVAILABLE_MEMORY, true);
- iter = g_list_next(iter);
- }
- }
-}
-
-static void __unregister_vconf_events(void)
-{
- const char *key;
- config_type_e type;
-
- type = CONFIG_TYPE_MEMORY_STATUS_NORMAL_KEY;
- key = _config_get_string_value(type);
- vconf_ignore_key_changed(key, __memory_status_normal_changed_cb);
-
- type = CONFIG_TYPE_MEMORY_STATUS_LOW_KEY;
- key = _config_get_string_value(type);
- vconf_ignore_key_changed(key, __memory_status_low_changed_cb);
-
- vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT,
- __region_format_changed_cb);
- vconf_ignore_key_changed(VCONFKEY_LANGSET,
- __update_lang);
- vconf_ignore_key_changed(VCONFKEY_SETAPPL_APP_HW_ACCELERATION,
- __hw_acceleration_changed_cb);
-}
-
-static int __register_vconf_events(void)
-{
- int r;
- char *lang;
- char *region;
- const char *key;
- config_type_e type;
-
- r = vconf_get_int(VCONFKEY_SETAPPL_APP_HW_ACCELERATION, &__sys_hwacc);
- if (r != VCONF_OK)
- _E("Failed to get vconf hw acceleration. err = %d", r);
-
- r = vconf_notify_key_changed(VCONFKEY_SETAPPL_APP_HW_ACCELERATION,
- __hw_acceleration_changed_cb, NULL);
- if (r != VCONF_OK) {
- _E("Failed to register callback for hw acceleration. err = %d",
- r);
- }
-
- lang = vconf_get_str(VCONFKEY_LANGSET);
- if (lang) {
- setenv("LANG", lang, 1);
- free(lang);
- }
-
- r = vconf_notify_key_changed(VCONFKEY_LANGSET, __update_lang, NULL);
- if (r != VCONF_OK)
- _E("Failed to register callback for langset. err = %d", r);
-
- region = vconf_get_str(VCONFKEY_REGIONFORMAT);
- if (region) {
- setenv("LC_CTYPE", region, 1);
- free(region);
- }
-
- r = vconf_notify_key_changed(VCONFKEY_REGIONFORMAT,
- __region_format_changed_cb, NULL);
- if (r != VCONF_OK)
- _E("Failed to register callback for regionformat. err = %d", r);
-
- type = CONFIG_TYPE_MEMORY_STATUS_LOW_KEY;
- key = _config_get_string_value(type);
- type = CONFIG_TYPE_MEMORY_STATUS_LOW_VALUE;
- MEMORY_STATUS_LOW = _config_get_int_value(type);
-
- r = vconf_get_int(key, &__memory_status_low);
- if (r != VCONF_OK)
- _E("Failed to get vconf low memory. err = %d", r);
-
- r = vconf_notify_key_changed(key,
- __memory_status_low_changed_cb, NULL);
- if (r != 0)
- _E("Failed to register callback for low memory. err = %d", r);
-
- type = CONFIG_TYPE_MEMORY_STATUS_NORMAL_KEY;
- key = _config_get_string_value(type);
- type = CONFIG_TYPE_MEMORY_STATUS_NORMAL_VALUE;
- MEMORY_STATUS_NORMAL = _config_get_int_value(type);
-
- r = vconf_get_int(key, &__memory_status_normal);
- if (r != VCONF_OK)
- _E("Failed to get vconf normal memory. err = %d", r);
-
- r = vconf_notify_key_changed(key,
- __memory_status_normal_changed_cb, NULL);
- if (r != 0)
- _E("Failed to register callback for normal memory. err = %d", r);
-
- return 0;
-}
-
-static bool __handle_logger(int fd, io_condition_e cond, void *data)
-{
- app_pkt_t *pkt;
- struct ucred cr;
- int clifd = -1;
-
- if (cond & (IO_ERR | IO_HUP | IO_NVAL)) {
- _E("fd(%d), io_condition(%d)", fd, cond);
- g_idle_add(__logger_recovery_cb, __logger_channel);
- __logger_channel = NULL;
- return false;
- }
-
- pkt = _accept_recv_pkt_raw(fd, &clifd, &cr);
- if (!pkt) {
- _E("Failed to receive the packet");
- return true;
- }
-
- if (getuid() != cr.uid) {
- _E("Invalid caller");
- goto end;
- }
-
- if (pkt->len <= 0) {
- _E("Invalid message");
- goto end;
- }
-
- _E("[%d] %s", cr.pid, (const char *)pkt->data);
- _log_print("[ERROR]", "pid(%7d) | message(%s)",
- cr.pid, (const char *)pkt->data);
-end:
- if (clifd != -1)
- close(clifd);
-
- free(pkt);
-
- return true;
-}
-
-static int __init_logger_fd(void)
-{
- io_condition_e cond;
- int fd;
-
- fd = _create_server_sock(LAUNCHPAD_LOGGER_SOCK);
- if (fd < 0) {
- _E("Failed to create logger socker");
- return -1;
- }
-
- cond = IO_IN | IO_PRI | IO_ERR | IO_HUP | IO_NVAL;
- __logger_channel = _io_channel_create(fd, cond, __handle_logger, NULL);
- if (!__logger_channel) {
- close(fd);
- return -1;
- }
-
- return 0;
-}
-
-static int __memory_monitor_cb(bool low_memory, void *user_data)
-{
- candidate_process_context_t *cpc;
-
- cpc = __get_running_slot(false);
- if (!cpc && low_memory)
- return -1;
-
- if (low_memory) {
- _W("Low memory");
- __update_slots_pss();
-
- candidate_slot_list = g_list_sort(candidate_slot_list,
- __compare_slot);
- __pause_all_running_slots(false);
- } else {
- __resume_all_slots();
- }
-
- return 0;
-}
-
-static gboolean __logger_recovery_cb(gpointer data)
-{
- io_channel_h channel = data;
- int ret;
-
- _io_channel_destroy(channel);
-
- ret = __init_logger_fd();
- if (ret < 0) {
- _E("Failed to recover logger socket");
- return G_SOURCE_REMOVE;
- }
-
- _E("[__RECOVERY__] Logger socket");
-
- return G_SOURCE_REMOVE;
-}
-
-static gboolean __launchpad_recovery_cb(gpointer data)
-{
- io_channel_h channel = data;
- int ret;
-
- _io_channel_destroy(channel);
-
- ret = __init_launchpad_fd(0, NULL);
- if (ret < 0) {
- _E("Failed to recover launchpad socket");
- abort();
- return G_SOURCE_REMOVE;
- }
-
- _E("[__RECOVERY__] Launchpad socket");
-
- return G_SOURCE_REMOVE;
-}
-
-static int __before_loop(int argc, char **argv)
-{
- int ret;
-
- _print_hwc_log("%s(%d): START", __FUNCTION__, __LINE__);
- ret = __sequencer_init();
- if (ret < 0) {
- _E("Failed to initialize sequencer");
- return -1;
- }
-
- ret = _signal_init();
- if (ret < 0) {
- _E("Failed to initialize signal");
- return -1;
- }
-
- _signal_set_sigchld_cb(__handle_sigchild, NULL);
-
- ret = __init_launchpad_fd(argc, argv);
- if (ret != 0) {
- _E("__init_launchpad_fd() failed");
- return -1;
- }
-
- ret = __init_logger_fd();
- if (ret != 0) {
- _E("__init_logger_fd() failed");
- return -1;
- }
-
- ret = __init_label_monitor_fd();
- if (ret != 0)
- _W("Failed to initialize label monitor");
-
- ret = _config_init();
- if (ret != 0)
- _W("Failed to initialize config");
-
- ret = _dbus_init();
- if (ret != 0)
- _W("Failed to initialize dbus");
-
- _inotify_init();
-
- MAX_CPU_CHECK_COUNT = _config_get_int_value(
- CONFIG_TYPE_CPU_CHECKER_MAX_COUNT);
- __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);
-
- __pid_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
- NULL, free);
- if (!__pid_table) {
- _E("Failed to create pid table");
- return -1;
- }
-
- ret = _worker_create("cleaner+", &__cleaner);
- if (ret < 0)
- return ret;
-
- __register_vconf_events();
- __init_app_defined_loader_monitor();
- _memory_monitor_init();
- _memory_monitor_set_event_cb(__memory_monitor_cb, NULL);
- _log_init();
- _print_hwc_log("%s(%d): END", __FUNCTION__, __LINE__);
-
- return 0;
-}
-
-static void __after_loop(void)
-{
- _log_fini();
- _memory_monitor_fini();
- __unregister_vconf_events();
- _worker_destroy(__cleaner);
- if (__pid_table)
- g_hash_table_destroy(__pid_table);
-
- if (_send_cmd_to_amd(LAUNCHPAD_DEAD_SIGNAL) < 0)
- _W("Failed to send cmd(%d) to amd", LAUNCHPAD_DEAD_SIGNAL);
-
- _debug_fini();
- _launcher_info_unload(launcher_info_list);
- _dbus_fini();
- _config_fini();
- _inotify_fini();
- _loader_info_dispose(app_defined_loader_info_list);
-
- 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);
-
- _signal_fini();
-
- __sequencer_fini();
-}
-
-int main(int argc, char **argv)
-{
- GMainLoop *mainloop = NULL;
-
- _print_hwc_log("%s(%d): START", __FUNCTION__, __LINE__);
- prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0);
-
- mainloop = g_main_loop_new(NULL, FALSE);
- if (!mainloop) {
- _E("Failed to create glib main loop");
- return -1;
- }
-
- _print_hwc_log("%s(%d): __before_loop()", __FUNCTION__, __LINE__);
- if (__before_loop(argc, argv) != 0) {
- _E("process-pool Initialization failed!");
- return -1;
- }
-
-#ifdef TIZEN_FEATURE_PRIORITY_CHANGE
- _set_priority(-12);
-#endif
- _print_hwc_log("%s(%d): g_main_loop_run()", __FUNCTION__, __LINE__);
- g_main_loop_run(mainloop);
-
- __after_loop();
-
- return -1;
-}
--- /dev/null
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#include <bundle_internal.h>
+#include <errno.h>
+#include <glib.h>
+#include <linux/limits.h>
+#include <malloc.h>
+#include <math.h>
+#include <sched.h>
+#include <security-manager.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/capability.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+#include <systemd/sd-daemon.h>
+#include <time.h>
+#include <trust-anchor.h>
+#include <ttrace.h>
+#include <vconf.h>
+
+#include <algorithm>
+
+#include "key.h"
+#include "launcher_info.hh"
+#include "launchpad_common.h"
+#include "launchpad_config.h"
+#include "launchpad_dbus.h"
+#include "launchpad_debug.h"
+#include "launchpad_inotify.h"
+#include "launchpad_io_channel.h"
+#include "launchpad_log.h"
+#include "launchpad_memory_monitor.h"
+#include "launchpad_plugin.h"
+#include "launchpad_proc.h"
+#include "launchpad_signal.h"
+#include "launchpad_types.h"
+#include "launchpad_worker.h"
+#include "loader_info.hh"
+#include "perf.h"
+#include "slot_info.h"
+
+#define AUL_PR_NAME 16
+#define EXEC_CANDIDATE_EXPIRED 5
+#define EXEC_CANDIDATE_WAIT 1
+#define DIFF(a, b) (((a) > (b)) ? (a) - (b) : (b) - (a))
+#define CANDIDATE_NONE 0
+#define HYDRA_NONE 0
+#define PROCESS_POOL_LAUNCHPAD_SOCK ".launchpad-process-pool-sock"
+#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
+#define PAD_ERR_REJECTED -2
+#define PAD_ERR_INVALID_ARGUMENT -3
+#define PAD_ERR_INVALID_PATH -4
+#define CPU_CHECKER_TIMEOUT 1000
+#define PI 3.14159265
+#define WIN_SCORE 100
+#define LOSE_SCORE_RATE 0.7f
+
+enum candidate_process_state_e {
+ CANDIDATE_PROCESS_STATE_RUNNING,
+ CANDIDATE_PROCESS_STATE_PAUSED,
+};
+
+typedef struct {
+ int type;
+ bool prepared;
+ int pid; /* for hydra this pid is not the pid of hydra itself */
+ /* but pid of non-hydra candidate, which was forked from hydra */
+ int hydra_pid;
+ int loader_id;
+ int caller_pid;
+ int send_fd;
+ int hydra_fd;
+ int last_exec_time;
+ guint timer;
+ char* loader_name;
+ char* loader_path;
+ char* loader_extra;
+ int detection_method;
+ int timeout_val;
+ unsigned long long cpu_total_time;
+ unsigned long long cpu_idle_time;
+ int threshold;
+ int threshold_max;
+ int threshold_min;
+ int cur_event;
+ bool on_boot;
+ bool app_exists;
+ bool touched;
+ int activation_method;
+ int deactivation_method;
+ unsigned int ttl;
+ guint live_timer;
+ int state;
+ bool is_hydra;
+ bool app_check;
+ io_channel_h client_channel;
+ io_channel_h channel;
+ io_channel_h hydra_channel;
+ unsigned int score;
+ unsigned int pss;
+ int cpu_check_count;
+ int on_boot_timeout;
+ guint on_boot_timer;
+ int sched_priority;
+} candidate_process_context_t;
+
+typedef struct {
+ GPollFD* gpollfd;
+ int type;
+ int loader_id;
+} loader_context_t;
+
+typedef struct {
+ GQueue* queue;
+ guint timer;
+ guint idle_checker;
+ candidate_process_context_t* running_cpc;
+} sequencer;
+
+struct app_launch_arg {
+ const char* appid;
+ const char* app_path;
+ appinfo_t* menu_info;
+ bundle* kb;
+};
+
+struct app_arg {
+ int argc;
+ char** argv;
+};
+
+struct app_info {
+ const char* type;
+ bool exists;
+};
+
+struct cleanup_info_s {
+ char* appid;
+ int pid;
+};
+
+typedef struct candidate_info_s {
+ char** argv;
+ int argc;
+ int loader_id;
+ int type;
+ pid_t pid;
+} candidate_info_t;
+
+typedef struct request_s {
+ app_pkt_t* pkt;
+ appinfo_t* menu_info;
+ bundle* kb;
+ candidate_process_context_t* cpc;
+ candidate_process_context_t* org_cpc;
+ const char* app_path;
+ int clifd;
+ int cmd;
+ int loader_id;
+ pid_t caller_pid;
+ uid_t caller_uid;
+ pid_t pid; /* result */
+} request_t;
+
+typedef request_t* request_h;
+
+typedef int (*request_handler)(request_h request);
+
+namespace {
+
+int __sys_hwacc;
+std::unique_ptr<launchpad::LoaderInfoManager> loader_info_manager;
+std::unique_ptr<launchpad::LoaderInfoManager> app_defined_loader_info_manager;
+int user_slot_offset;
+GList* candidate_slot_list;
+app_labels_monitor* label_monitor;
+std::vector<launchpad::LauncherInfoPtr> launcher_info_list;
+GHashTable* __pid_table;
+int __memory_status_low;
+int __memory_status_normal;
+sequencer __sequencer;
+int MEMORY_STATUS_LOW;
+int MEMORY_STATUS_NORMAL;
+int MAX_CPU_CHECK_COUNT;
+
+io_channel_h __logger_channel;
+io_channel_h __label_monitor_channel;
+io_channel_h __launchpad_channel;
+int __client_fd = -1;
+worker_h __cleaner;
+
+} // namespace
+
+static candidate_process_context_t* __add_slot(slot_info_t* info);
+static int __remove_slot(int type, int loader_id);
+static int __add_default_slots(void);
+static gboolean __handle_idle_checker(gpointer data);
+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,
+ launchpad::LoaderMethod method,
+ bool force);
+static void __init_app_defined_loader_monitor(void);
+static gboolean __launchpad_recovery_cb(gpointer data);
+static gboolean __logger_recovery_cb(gpointer data);
+
+static gboolean __handle_queuing_slots(gpointer data) {
+ candidate_process_context_t* cpc;
+ unsigned long long total = 0;
+ unsigned long long idle = 0;
+
+ if (__sequencer.idle_checker > 0)
+ return G_SOURCE_CONTINUE;
+
+ if (g_queue_is_empty(__sequencer.queue)) {
+ __sequencer.timer = 0;
+ return G_SOURCE_REMOVE;
+ }
+
+ cpc = (candidate_process_context_t*)g_queue_pop_head(__sequencer.queue);
+ if (!cpc) {
+ _E("Critical error!");
+ __sequencer.timer = 0;
+ return G_SOURCE_REMOVE;
+ ;
+ }
+
+ if (cpc->app_check && !cpc->app_exists) {
+ _W("The application is not installed. Type(%d)", cpc->type);
+ return G_SOURCE_CONTINUE;
+ }
+
+ if (cpc->timer) {
+ g_source_remove(cpc->timer);
+ cpc->timer = 0;
+ }
+
+ if (cpc->pid != CANDIDATE_NONE) {
+ _W("The slot(%d) is already running. pid(%d)", cpc->type, cpc->pid);
+ return G_SOURCE_CONTINUE;
+ }
+
+ _get_cpu_idle(&total, &idle);
+ cpc->cpu_idle_time = idle;
+ cpc->cpu_total_time = total;
+ cpc->cpu_check_count = 0;
+
+ __sequencer.idle_checker =
+ g_timeout_add(CPU_CHECKER_TIMEOUT, __handle_idle_checker, cpc);
+ __sequencer.running_cpc = cpc;
+
+ _W("[__SEQUENCER__] Add idle checker. Type(%d)", cpc->type);
+
+ return G_SOURCE_CONTINUE;
+}
+
+static bool __sequencer_slot_is_running(candidate_process_context_t* cpc) {
+ if (__sequencer.running_cpc == cpc)
+ return true;
+
+ return false;
+}
+
+static bool __sequencer_slot_exist(candidate_process_context_t* cpc) {
+ GList* found;
+
+ found = g_queue_find(__sequencer.queue, cpc);
+ if (found)
+ return true;
+
+ return false;
+}
+
+static int __sequencer_add_slot(candidate_process_context_t* cpc) {
+ if (__sequencer_slot_exist(cpc)) {
+ _W("Already exists");
+ return -1;
+ }
+
+ if (__sequencer_slot_is_running(cpc)) {
+ _W("slot(%d) is running", cpc->type);
+ return -1;
+ }
+
+ g_queue_push_tail(__sequencer.queue, cpc);
+
+ return 0;
+}
+
+static void __sequencer_remove_slot(candidate_process_context_t* cpc) {
+ g_queue_remove(__sequencer.queue, cpc);
+}
+
+static void __sequencer_run(void) {
+ if (__sequencer.timer)
+ return;
+
+ __sequencer.timer = g_timeout_add(500, __handle_queuing_slots, nullptr);
+ if (!__sequencer.timer)
+ _E("Failed to add sequencer timer");
+}
+
+static void __sequencer_stop(void) {
+ if (!__sequencer.timer)
+ return;
+
+ g_source_remove(__sequencer.timer);
+ __sequencer.timer = 0;
+}
+
+static bool __sequencer_queue_is_empty(void) {
+ if (g_queue_is_empty(__sequencer.queue))
+ return true;
+
+ return false;
+}
+
+static int __sequencer_init(void) {
+ _D("[__SEQUENCER__] Init");
+
+ __sequencer.queue = g_queue_new();
+ if (!__sequencer.queue) {
+ _E("Out of memory");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void __sequencer_fini(void) {
+ _D("[__SEQUENCER__] Finish");
+
+ if (__sequencer.idle_checker > 0)
+ g_source_remove(__sequencer.idle_checker);
+
+ if (__sequencer.timer > 0)
+ g_source_remove(__sequencer.timer);
+
+ g_queue_free(__sequencer.queue);
+}
+
+static int __make_loader_id(void) {
+ static int id = PAD_LOADER_ID_DYNAMIC_BASE;
+
+ return ++id;
+}
+
+static candidate_process_context_t* __find_slot_from_static_type(int type) {
+ candidate_process_context_t* cpc;
+ GList* iter = candidate_slot_list;
+
+ if (type == static_cast<int>(launchpad::LoaderType::Dynamic) ||
+ type == static_cast<int>(launchpad::LoaderType::Unsupported))
+ return nullptr;
+
+ while (iter) {
+ cpc = (candidate_process_context_t*)iter->data;
+ if (type == cpc->type)
+ return cpc;
+
+ iter = g_list_next(iter);
+ }
+
+ return nullptr;
+}
+
+static candidate_process_context_t* __find_slot_from_pid(int pid) {
+ candidate_process_context_t* cpc;
+ GList* iter = candidate_slot_list;
+
+ while (iter) {
+ cpc = (candidate_process_context_t*)iter->data;
+ if (pid == cpc->pid)
+ return cpc;
+
+ iter = g_list_next(iter);
+ }
+
+ return nullptr;
+}
+
+static candidate_process_context_t* __find_hydra_slot_from_pid(int pid) {
+ candidate_process_context_t* cpc;
+ GList* iter = candidate_slot_list;
+
+ while (iter) {
+ cpc = (candidate_process_context_t*)iter->data;
+ if (cpc->is_hydra && pid == cpc->hydra_pid)
+ return cpc;
+
+ iter = g_list_next(iter);
+ }
+
+ return nullptr;
+}
+
+static candidate_process_context_t* __find_slot_from_caller_pid(
+ int caller_pid) {
+ candidate_process_context_t* cpc;
+ GList* iter = candidate_slot_list;
+
+ while (iter) {
+ cpc = (candidate_process_context_t*)iter->data;
+ if (caller_pid == cpc->caller_pid)
+ return cpc;
+
+ iter = g_list_next(iter);
+ }
+
+ return nullptr;
+}
+
+static candidate_process_context_t* __find_slot_from_loader_id(int id) {
+ candidate_process_context_t* cpc;
+ GList* iter = candidate_slot_list;
+
+ while (iter) {
+ cpc = (candidate_process_context_t*)iter->data;
+ if (id == cpc->loader_id)
+ return cpc;
+
+ iter = g_list_next(iter);
+ }
+
+ return nullptr;
+}
+
+static candidate_process_context_t* __find_slot_from_loader_name(
+ const char* loader_name) {
+ candidate_process_context_t* cpc;
+ GList* iter = candidate_slot_list;
+
+ while (iter) {
+ cpc = (candidate_process_context_t*)iter->data;
+ if (strcmp(cpc->loader_name, loader_name) == 0)
+ return cpc;
+
+ iter = g_list_next(iter);
+ }
+
+ return nullptr;
+}
+
+static candidate_process_context_t* __find_slot(int type, int loader_id) {
+ if (type == static_cast<int>(launchpad::LoaderType::Dynamic))
+ return __find_slot_from_loader_id(loader_id);
+
+ return __find_slot_from_static_type(type);
+}
+
+static void __update_slot_score(candidate_process_context_t* slot) {
+ if (!slot)
+ return;
+
+ slot->score *= LOSE_SCORE_RATE;
+ slot->score += WIN_SCORE;
+}
+
+static void __update_slots_pss(void) {
+ candidate_process_context_t* cpc;
+ GList* iter;
+
+ iter = candidate_slot_list;
+ while (iter) {
+ cpc = (candidate_process_context_t*)iter->data;
+ iter = g_list_next(iter);
+
+ if (cpc->pid == CANDIDATE_NONE)
+ continue;
+
+ _proc_get_mem_pss(cpc->pid, &cpc->pss);
+ }
+}
+
+static gint __compare_slot(gconstpointer a, gconstpointer b) {
+ candidate_process_context_t* slot_a = (candidate_process_context_t*)a;
+ candidate_process_context_t* slot_b = (candidate_process_context_t*)b;
+
+ if (slot_a->is_hydra && !slot_b->is_hydra)
+ return -1;
+ if (!slot_a->is_hydra && slot_b->is_hydra)
+ return 1;
+
+ if (slot_a->score < slot_b->score)
+ return 1;
+ if (slot_a->score > slot_b->score)
+ return -1;
+
+ if (slot_a->pss < slot_b->pss)
+ return -1;
+ if (slot_a->pss > slot_b->pss)
+ return 1;
+
+ return 0;
+}
+
+static candidate_process_context_t* __get_running_slot(bool is_hydra) {
+ candidate_process_context_t* cpc;
+ GList* iter;
+
+ iter = candidate_slot_list;
+ while (iter) {
+ cpc = (candidate_process_context_t*)iter->data;
+ if (cpc->is_hydra == is_hydra && cpc->pid != CANDIDATE_NONE)
+ return cpc;
+
+ iter = g_list_next(iter);
+ }
+
+ return nullptr;
+}
+
+static void __pause_all_running_slots(bool is_hydra) {
+ candidate_process_context_t* cpc = nullptr;
+ GList* iter;
+
+ iter = g_list_last(candidate_slot_list);
+ while (iter) {
+ cpc = (candidate_process_context_t*)iter->data;
+ if (cpc->is_hydra == is_hydra && cpc->pid != CANDIDATE_NONE) {
+ __update_slot_state(cpc, launchpad::LoaderMethod::OutOfMemory, true);
+ if (!_memory_monitor_is_low_memory())
+ return;
+ }
+
+ iter = g_list_previous(iter);
+ }
+}
+
+static void __resume_all_slots(void) {
+ candidate_process_context_t* cpc;
+ GList* iter;
+
+ iter = candidate_slot_list;
+ while (iter) {
+ cpc = (candidate_process_context_t*)iter->data;
+ __update_slot_state(cpc, launchpad::LoaderMethod::AvailableMemory, true);
+
+ iter = g_list_next(iter);
+ }
+}
+
+static void __kill_process(int pid) {
+ char err_str[MAX_LOCAL_BUFSZ] = {
+ 0,
+ };
+
+ if (kill(pid, SIGKILL) == -1) {
+ _E("send SIGKILL: %s", strerror_r(errno, err_str, sizeof(err_str)));
+ }
+}
+
+static void __refuse_candidate_process(int server_fd) {
+ int client_fd = -1;
+
+ if (server_fd == -1) {
+ _E("arguments error!");
+ goto error;
+ }
+
+ client_fd = accept(server_fd, nullptr, nullptr);
+ if (client_fd == -1) {
+ _E("accept error!");
+ goto error;
+ }
+
+ close(client_fd);
+ _D("refuse connection!");
+
+error:
+ return;
+}
+
+static int __accept_candidate_process(int server_fd,
+ int* out_client_fd,
+ int* out_client_pid,
+ int cpc_pid) {
+ int client_fd = -1;
+ int recv_pid = 0;
+ int ret;
+ socklen_t len;
+ struct ucred cred = {};
+
+ if (server_fd == -1 || out_client_fd == nullptr ||
+ out_client_pid == nullptr) {
+ _E("arguments error!");
+ goto error;
+ }
+
+ client_fd = accept(server_fd, nullptr, nullptr);
+ if (client_fd == -1) {
+ _E("accept error!");
+ goto error;
+ }
+
+ if (_set_sock_option(client_fd, 1) < 0) {
+ _E("Failed to set sock option");
+ goto error;
+ }
+
+ ret = recv(client_fd, &recv_pid, sizeof(recv_pid), MSG_WAITALL);
+ if (ret == -1) {
+ _E("recv error!");
+ goto error;
+ }
+
+ len = (socklen_t)sizeof(cred);
+ ret = getsockopt(client_fd, SOL_SOCKET, SO_PEERCRED, &cred, &len);
+ if (ret < 0) {
+ _E("getsockopt error");
+ goto error;
+ }
+
+ if (cpc_pid != -1 && cred.pid != cpc_pid) {
+ _E("Invalid accept. pid(%d)", cred.pid);
+ goto error;
+ }
+
+ if (cred.pid != recv_pid)
+ _W("Not equal recv and real pid");
+
+ *out_client_fd = client_fd;
+ *out_client_pid = cred.pid;
+
+ return *out_client_fd;
+
+error:
+ if (client_fd != -1)
+ close(client_fd);
+
+ return -1;
+}
+
+static int __listen_addr(struct sockaddr_un* addr) {
+ int fd = -1;
+ fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ if (fd < 0) {
+ _E("Socket error");
+ goto error;
+ }
+
+ unlink(addr->sun_path);
+
+ _D("bind to %s", addr->sun_path);
+ if (bind(fd, (struct sockaddr*)addr, sizeof(struct sockaddr_un)) < 0) {
+ _E("bind error");
+ goto error;
+ }
+
+ _D("listen to %s", addr->sun_path);
+ if (listen(fd, MAX_PENDING_CONNECTIONS) == -1) {
+ _E("listen error");
+ goto error;
+ }
+
+ SECURE_LOGD("[launchpad] done, listen fd: %d", fd);
+ return fd;
+
+error:
+ if (fd != -1)
+ close(fd);
+
+ return -1;
+}
+
+static int __listen_candidate_process(int type, int loader_id) {
+ struct sockaddr_un addr;
+
+ _D("[launchpad] enter, type: %d", type);
+
+ memset(&addr, 0x00, sizeof(struct sockaddr_un));
+ addr.sun_family = AF_UNIX;
+ snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/daemons/%u/%s%d-%d",
+ SOCKET_PATH, getuid(), LAUNCHPAD_LOADER_SOCKET_NAME, type,
+ loader_id);
+
+ return __listen_addr(&addr);
+}
+
+static int __listen_hydra_process(int type, int loader_id) {
+ struct sockaddr_un addr;
+
+ _D("[launchpad] enter, type: %d", type);
+
+ memset(&addr, 0x00, sizeof(struct sockaddr_un));
+ addr.sun_family = AF_UNIX;
+ snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/daemons/%d/%s%d-%d",
+ SOCKET_PATH, getuid(), HYDRA_LOADER_SOCKET_NAME, type, loader_id);
+
+ return __listen_addr(&addr);
+}
+
+static int __get_loader_id(bundle* kb) {
+ const char* val;
+
+ val = bundle_get_val(kb, AUL_K_LOADER_ID);
+ if (val == nullptr)
+ return -1;
+ _W("Requested loader id: %s", val);
+
+ return atoi(val);
+}
+
+static int __candidate_process_real_launch(int candidate_fd, app_pkt_t* pkt) {
+ return _send_pkt_raw(candidate_fd, pkt);
+}
+
+static int __real_send(int clifd, int ret) {
+ if (clifd < 3) {
+ _E("Invalid parameter. clifd(%d)", clifd);
+ return -1;
+ }
+
+ if (send(clifd, &ret, sizeof(int), MSG_NOSIGNAL) < 0) {
+ if (errno == EPIPE) {
+ _E("send failed due to EPIPE.");
+ close(clifd);
+ return -1;
+ }
+ _E("send fail to client");
+ }
+
+ close(clifd);
+ return 0;
+}
+
+static int __fork_app_process(int (*child_fn)(void*), void* arg,
+ int sched_priority) {
+ int pid;
+ int ret;
+
+ pid = fork();
+ if (pid == -1) {
+ _E("failed to fork child process");
+ return -1;
+ }
+
+ if (pid == 0) {
+ if (sched_priority != 0)
+ _set_priority(sched_priority);
+
+ _W("security_manager_prepare_app_candidate ++");
+ ret = security_manager_prepare_app_candidate();
+ _W("security_manager_prepare_app_candidate --");
+ if (ret != SECURITY_MANAGER_SUCCESS) {
+ _E("failed to prepare app candidate process (%d)", ret);
+ exit(1);
+ }
+
+ ret = child_fn(arg);
+ _E("failed to exec app process (%d)", errno);
+ exit(ret);
+ }
+
+ return pid;
+}
+
+static int __exec_loader_process(void* arg) {
+ char** argv = static_cast<char**>(arg);
+ char err_buf[1024];
+
+ _signal_unblock_sigchld();
+ _close_all_fds();
+ _setup_stdio(basename(argv[LOADER_ARG_PATH]));
+
+ if (execv(argv[LOADER_ARG_PATH], argv) < 0) {
+ _send_message_to_logger(argv[LOADER_ARG_PATH],
+ "Failed to prepare candidate process. error(%d:%s)",
+ errno, strerror_r(errno, err_buf, sizeof(err_buf)));
+ } else {
+ _D("Succeeded to prepare candidate_process");
+ }
+
+ return -1;
+}
+
+static gboolean __handle_deactivate_event(gpointer user_data) {
+ candidate_process_context_t* cpc;
+
+ cpc = (candidate_process_context_t*)user_data;
+ __update_slot_state(cpc, launchpad::LoaderMethod::Ttl, false);
+ _D("Deactivate event: type(%d)", cpc->type);
+
+ return G_SOURCE_REMOVE;
+}
+
+static void __set_live_timer(candidate_process_context_t* cpc) {
+ if (!cpc)
+ return;
+
+ if (cpc->deactivation_method & static_cast<int>(launchpad::LoaderMethod::Ttl)) {
+ if (cpc->live_timer == 0) {
+ cpc->live_timer =
+ g_timeout_add_seconds(cpc->ttl, __handle_deactivate_event, cpc);
+ }
+ }
+}
+
+static int __hydra_send_request(int fd, enum hydra_cmd cmd) {
+ int sent = 0;
+ int size = (int)sizeof(cmd);
+ int send_ret = 0;
+
+ while (sent != size) {
+ send_ret = send(fd, (char*)&cmd + sent, size - sent, MSG_NOSIGNAL);
+ if (send_ret == -1) {
+ _E("send error! (%d)", errno);
+ return -1;
+ }
+
+ sent += send_ret;
+ _D("send(%d: ret: %d) : %d / %d", fd, send_ret, sent, size);
+ }
+
+ return 0;
+}
+
+static int __hydra_send_launch_candidate_request(int fd) {
+ SECURE_LOGD("Send launch cmd to hydra, fd: %d", fd);
+ return __hydra_send_request(fd, LAUNCH_CANDIDATE);
+}
+
+static void __candidate_info_free(candidate_info_t* info) {
+ int i;
+
+ if (info == nullptr)
+ return;
+
+ if (info->argv) {
+ for (i = 0; i < info->argc; i++)
+ free(info->argv[i]);
+
+ free(info->argv);
+ }
+
+ free(info);
+}
+
+static int __candidate_info_create(candidate_process_context_t* cpt,
+ candidate_info_t** candidate_info) {
+ char type_str[12] = {
+ 0,
+ };
+ char loader_id_str[12] = {
+ 0,
+ };
+ char argbuf[LOADER_ARG_LEN];
+ candidate_info_t* info;
+
+ if (cpt == nullptr)
+ return -EINVAL;
+
+ info = static_cast<candidate_info_t*>(calloc(1, sizeof(candidate_info_t)));
+ if (info == nullptr) {
+ _E("calloc() is failed");
+ return -ENOMEM;
+ }
+
+ info->argv = static_cast<char**>(calloc(LOADER_ARG_DUMMY + 1, sizeof(char*)));
+ if (info->argv == nullptr) {
+ _E("calloc() is failed");
+ __candidate_info_free(info);
+ return -ENOMEM;
+ }
+
+ memset(argbuf, ' ', LOADER_ARG_LEN);
+ argbuf[LOADER_ARG_LEN - 1] = '\0';
+ info->argv[LOADER_ARG_DUMMY] = strdup(argbuf);
+
+ snprintf(loader_id_str, sizeof(loader_id_str), "%d", cpt->loader_id);
+ snprintf(type_str, sizeof(type_str), "%d", cpt->type);
+ info->argv[LOADER_ARG_PATH] = strdup(cpt->loader_path);
+ info->argv[LOADER_ARG_TYPE] = strdup(type_str);
+ info->argv[LOADER_ARG_ID] = strdup(loader_id_str);
+ info->argv[LOADER_ARG_HYDRA] = strdup(cpt->is_hydra ? "1" : "0");
+ info->argv[LOADER_ARG_EXTRA] = strdup(cpt->loader_extra);
+
+ info->argc = LOADER_ARG_DUMMY + 1;
+ info->type = cpt->type;
+ info->loader_id = cpt->loader_id;
+
+ *candidate_info = info;
+ return 0;
+}
+
+static int __prepare_candidate_process(int type, int loader_id) {
+ candidate_process_context_t* cpt = __find_slot(type, loader_id);
+ candidate_info_t* info;
+ int ret;
+
+ if (cpt == nullptr)
+ return -1;
+
+ if (cpt->is_hydra && cpt->hydra_pid != HYDRA_NONE)
+ return __hydra_send_launch_candidate_request(cpt->hydra_fd);
+
+ _D("prepare candidate process / type:%d", type);
+ ret = __candidate_info_create(cpt, &info);
+ if (ret < 0)
+ return ret;
+
+ info->pid = __fork_app_process(__exec_loader_process, info->argv,
+ cpt->sched_priority);
+ if (info->pid == -1) {
+ _E("Failed to create a child process. type: %d", type);
+ __candidate_info_free(info);
+ return -1;
+ }
+
+ _W("Candidate process. type: %d, loader_id: %d, pid: %d", info->type,
+ info->loader_id, info->pid);
+ cpt = __find_slot(info->type, info->loader_id);
+ if (cpt == nullptr) {
+ _E("Not found slot.");
+ __candidate_info_free(info);
+ return -1;
+ }
+
+ cpt->last_exec_time = time(nullptr);
+ if (cpt->is_hydra) {
+ cpt->hydra_pid = info->pid;
+ } else {
+ cpt->pid = info->pid;
+ __set_live_timer(cpt);
+ }
+
+ _log_print("[CANDIDATE]", "pid(%7d) | type(%d) | loader(%s)", info->pid,
+ cpt->loader_id, cpt->loader_name);
+ _memory_monitor_reset_timer();
+ __candidate_info_free(info);
+ return 0;
+}
+
+static gboolean __handle_timeout_event(gpointer user_data) {
+ candidate_process_context_t* cpc;
+
+ cpc = (candidate_process_context_t*)user_data;
+ cpc->timer = 0;
+
+ if (cpc->pid != CANDIDATE_NONE) {
+ _W("Candidate(%d) process(%d) is running", cpc->type, cpc->pid);
+ return G_SOURCE_REMOVE;
+ }
+
+ __sequencer_add_slot(cpc);
+ __sequencer_run();
+ return G_SOURCE_REMOVE;
+}
+
+static void __set_timer(candidate_process_context_t* cpc) {
+ if (cpc == nullptr || cpc->timer > 0)
+ return;
+
+ if ((cpc->detection_method & static_cast<int>(launchpad::LoaderMethod::Timeout)) &&
+ cpc->state == CANDIDATE_PROCESS_STATE_RUNNING) {
+ cpc->timer = g_timeout_add(cpc->timeout_val, __handle_timeout_event, cpc);
+ }
+}
+
+static void __reset_slot(candidate_process_context_t* cpc) {
+ if (cpc == nullptr)
+ return;
+
+ cpc->send_fd = -1;
+ cpc->prepared = false;
+ cpc->pid = CANDIDATE_NONE;
+ cpc->client_channel = nullptr;
+ cpc->timer = 0;
+ cpc->live_timer = 0;
+ cpc->on_boot_timer = 0;
+}
+
+static void __dispose_candidate_process(candidate_process_context_t* cpc) {
+ if (!cpc)
+ return;
+
+ _D("Dispose candidate process %d", cpc->type);
+ if (cpc->pid > 0) {
+ _D("kill process %d", cpc->pid);
+ __kill_process(cpc->pid);
+ }
+ if (cpc->live_timer > 0)
+ g_source_remove(cpc->live_timer);
+ if (cpc->client_channel)
+ _io_channel_destroy(cpc->client_channel);
+ if (cpc->timer > 0)
+ g_source_remove(cpc->timer);
+ if (cpc->send_fd > 0)
+ close(cpc->send_fd);
+ if (cpc->on_boot_timer > 0)
+ g_source_remove(cpc->on_boot_timer);
+ __reset_slot(cpc);
+}
+
+static void __dispose_hydra_process(candidate_process_context_t* cpc) {
+ if (!cpc)
+ return;
+
+ __dispose_candidate_process(cpc);
+
+ _D("Dispose hydra process %d", cpc->type);
+ if (cpc->hydra_pid > 0) {
+ _D("kill process %d", cpc->hydra_pid);
+ __kill_process(cpc->hydra_pid);
+ cpc->hydra_pid = HYDRA_NONE;
+ }
+
+ if (cpc->hydra_fd > 0) {
+ close(cpc->hydra_fd);
+ cpc->hydra_fd = -1;
+ }
+}
+
+static int __send_launchpad_loader(candidate_process_context_t* cpc,
+ app_pkt_t* pkt,
+ const char* app_path,
+ int clifd) {
+ int pid = -1;
+ int ret;
+
+ ret = _delete_sock_path(cpc->pid, getuid());
+ if (ret != 0)
+ return -1;
+
+ __candidate_process_real_launch(cpc->send_fd, pkt);
+ SECURE_LOGD("Request to candidate process, pid: %d, bin path: %s", cpc->pid,
+ app_path);
+
+ pid = cpc->pid;
+ cpc->pid = CANDIDATE_NONE;
+ __dispose_candidate_process(cpc);
+ __set_timer(cpc);
+ __update_slot_score(cpc);
+
+ return pid;
+}
+
+static int __normal_fork_exec(int argc, char** argv, const char* app_path) {
+ char* libdir;
+ char err_buf[1024];
+
+ _D("start real fork and exec");
+
+ libdir = _get_libdir(app_path);
+ if (libdir) {
+ setenv("LD_LIBRARY_PATH", libdir, 1);
+ free(libdir);
+ }
+
+ _close_all_fds();
+
+ if (execv(argv[LOADER_ARG_PATH], argv) < 0) { /* Flawfinder: ignore */
+ _send_message_to_logger(argv[LOADER_ARG_PATH],
+ "Failed to execute a file. error(%d:%s)", errno,
+ strerror_r(errno, err_buf, sizeof(err_buf)));
+ return -1;
+ }
+ /* never reach*/
+ return 0;
+}
+
+static int __create_launcher_argv(int* argc,
+ char*** argv,
+ const char* app_type) {
+ int launcher_argc;
+ char** launcher_argv;
+ launchpad::LauncherInfoPtr launcher_info;
+ const char* exe;
+ int i;
+
+ auto it = std::find_if(
+ launcher_info_list.begin(), launcher_info_list.end(),
+ [app_type](const launchpad::LauncherInfoPtr& info) -> bool {
+ return std::find_if(info->GetAppTypes().begin(),
+ info->GetAppTypes().end(),
+ [app_type](const std::string& type) -> bool {
+ return strcmp(type.c_str(), app_type) == 0;
+ }) != info->GetAppTypes().end();
+ });
+
+ if (it == launcher_info_list.end())
+ return 0;
+
+ launcher_info = *it;
+ exe = launcher_info->GetExe().c_str();
+
+ auto& extra_args = launcher_info->GetExtraArgs();
+ launcher_argc = extra_args.size() + 1;
+ launcher_argv = static_cast<char**>(calloc(launcher_argc, sizeof(char*)));
+ if (launcher_argv == nullptr) {
+ _E("out of memory");
+ return -1;
+ }
+
+ i = LOADER_ARG_PATH;
+ launcher_argv[i++] = strdup(exe);
+
+ for (auto& extra_arg : extra_args) {
+ launcher_argv[i++] = strdup(extra_arg.c_str());
+ }
+
+ *argc = launcher_argc;
+ *argv = launcher_argv;
+
+ return 0;
+}
+
+static void __destroy_launcher_argv(int argc, char** argv) {
+ int i;
+
+ if (argv == nullptr)
+ return;
+
+ for (i = 0; i < argc; i++)
+ free(argv[i]);
+ free(argv);
+}
+
+static int __create_app_argv(int* argc,
+ char*** argv,
+ const char* app_path,
+ bundle* kb,
+ const char* app_type) {
+ int new_argc;
+ char** new_argv;
+ bool attach = false;
+ struct app_arg debug_arg = {
+ 0,
+ };
+ struct app_arg launcher_arg = {
+ 0,
+ };
+ struct app_arg arg = {
+ 0,
+ };
+ struct app_arg debug_extra_arg = {
+ 0,
+ };
+ int ret;
+ int i;
+ int c;
+
+ ret = _debug_create_argv(&debug_arg.argc, &debug_arg.argv, &attach);
+ if (ret < 0) {
+ _E("Failed to create debugger argv");
+ return -1;
+ }
+
+ if (attach) {
+ *argc = debug_arg.argc;
+ *argv = debug_arg.argv;
+ return 0;
+ }
+
+ ret = _debug_create_extra_argv(&debug_extra_arg.argc, &debug_extra_arg.argv);
+ if (ret < 0) {
+ _E("Failed to create debugger extra argv");
+ _debug_destroy_argv(debug_arg.argc, debug_arg.argv);
+ return -1;
+ }
+
+ ret =
+ __create_launcher_argv(&launcher_arg.argc, &launcher_arg.argv, app_type);
+ if (ret < 0) {
+ _E("Failed to create launcher argv");
+ _debug_destroy_argv(debug_extra_arg.argc, debug_extra_arg.argv);
+ _debug_destroy_argv(debug_arg.argc, debug_arg.argv);
+ return -1;
+ }
+
+ arg.argc = bundle_export_to_argv(kb, &arg.argv);
+ if (arg.argc <= 0) {
+ _E("Failed to export bundle");
+ __destroy_launcher_argv(launcher_arg.argc, launcher_arg.argv);
+ _debug_destroy_argv(debug_extra_arg.argc, debug_extra_arg.argv);
+ _debug_destroy_argv(debug_arg.argc, debug_arg.argv);
+ return -1;
+ }
+ arg.argv[LOADER_ARG_PATH] = strdup(app_path);
+
+ new_argc =
+ debug_arg.argc + launcher_arg.argc + arg.argc + debug_extra_arg.argc;
+ if (new_argc == arg.argc) {
+ *argc = arg.argc;
+ *argv = arg.argv;
+ return 0;
+ }
+
+ new_argv = (char**)calloc(new_argc + 1, sizeof(char*));
+ if (new_argv == nullptr) {
+ _E("out of memory");
+ free(arg.argv[LOADER_ARG_PATH]);
+ bundle_free_exported_argv(arg.argc, &arg.argv);
+ __destroy_launcher_argv(launcher_arg.argc, launcher_arg.argv);
+ _debug_destroy_argv(debug_extra_arg.argc, debug_extra_arg.argv);
+ _debug_destroy_argv(debug_arg.argc, debug_arg.argv);
+ return -1;
+ }
+
+ c = LOADER_ARG_PATH;
+ for (i = 0; i < debug_arg.argc; i++)
+ new_argv[c++] = debug_arg.argv[i];
+ for (i = 0; i < launcher_arg.argc; i++)
+ new_argv[c++] = launcher_arg.argv[i];
+ for (i = 0; i < arg.argc; i++)
+ new_argv[c++] = arg.argv[i];
+ for (i = 0; i < debug_extra_arg.argc; i++)
+ new_argv[c++] = debug_extra_arg.argv[i];
+
+ *argc = new_argc;
+ *argv = new_argv;
+
+ return 0;
+}
+
+static void __real_launch(const char* app_path,
+ bundle* kb,
+ appinfo_t* menu_info) {
+ int app_argc = 0;
+ char** app_argv;
+ int i;
+ int ret;
+
+ if (bundle_get_val(kb, AUL_K_DEBUG) != nullptr)
+ putenv("TIZEN_DEBUGGING_PORT=1");
+
+ ret = __create_app_argv(&app_argc, &app_argv, app_path, kb,
+ menu_info->app_type);
+ if (ret < 0) {
+ _E("Failed to create app argv");
+ exit(-1);
+ }
+
+ for (i = 0; i < app_argc; i++)
+ SECURE_LOGD("input argument %d : %s##", i, app_argv[i]);
+
+ PERF("setup argument done");
+ __normal_fork_exec(app_argc, app_argv, app_path);
+}
+
+static int __prepare_exec(const char* appid,
+ const char* app_path,
+ appinfo_t* menu_info,
+ bundle* kb) {
+ char* file_name;
+ const char* enabled_light_user;
+ char process_name[AUL_PR_NAME];
+ int ret;
+
+ /* Set new session ID & new process group ID*/
+ /* In linux, child can set new session ID without check permission */
+ /* TODO : should be add to check permission in the kernel*/
+ setsid();
+
+ ret = _launchpad_plugin_prepare_app(appid, kb);
+ if (ret < 0) {
+ _E("_launchpad_plugin_prepare_app() is failed. error(%d)", ret);
+ return PAD_ERR_FAILED;
+ }
+
+ ret = _enable_external_pkg(kb, menu_info->pkgid,
+ menu_info->global ? GLOBAL_USER : getuid());
+ if (ret < 0)
+ return PAD_ERR_FAILED;
+
+ if (menu_info->global)
+ ret = trust_anchor_launch(menu_info->pkgid, GLOBAL_USER);
+ else
+ ret = trust_anchor_launch(menu_info->pkgid, getuid());
+ if (ret != TRUST_ANCHOR_ERROR_NONE &&
+ ret != TRUST_ANCHOR_ERROR_NOT_INSTALLED) {
+ _E("trust_anchor_launch() returns %d", ret);
+ return PAD_ERR_REJECTED;
+ }
+
+ ret = _mount_res_dir(menu_info->root_path, kb);
+ if (ret < 0)
+ return PAD_ERR_FAILED;
+
+ if (bundle_get_type(kb, AUL_K_SDK) != BUNDLE_TYPE_NONE)
+ _debug_change_mount_namespace();
+
+ /* SET PRIVILEGES*/
+ enabled_light_user = bundle_get_val(kb, AUL_K_ENABLED_LIGHT_USER);
+ _W("security_manager_prepare_app2 ++ %s", appid);
+ ret = security_manager_prepare_app2(appid, enabled_light_user);
+ _W("security_manager_prepare_app2 -- %s", appid);
+ if (ret != SECURITY_MANAGER_SUCCESS)
+ return PAD_ERR_REJECTED;
+
+ if (bundle_get_type(kb, AUL_K_SDK) == BUNDLE_TYPE_NONE)
+ _setup_stdio(basename(app_path));
+
+ /* SET DUMPABLE - for coredump*/
+ prctl(PR_SET_DUMPABLE, 1);
+
+ /* SET PROCESS NAME*/
+ if (app_path == nullptr)
+ return PAD_ERR_INVALID_ARGUMENT;
+
+ file_name = const_cast<char*>(strrchr(app_path, '/'));
+ if (file_name == nullptr)
+ return PAD_ERR_INVALID_PATH;
+
+ file_name++;
+ if (*file_name == '\0')
+ return PAD_ERR_INVALID_PATH;
+
+ memset(process_name, '\0', AUL_PR_NAME);
+ snprintf(process_name, AUL_PR_NAME, "%s", file_name);
+ prctl(PR_SET_NAME, process_name);
+
+ /* SET ENVIROMENT*/
+ _set_env(menu_info, kb);
+
+ ret = _wait_tep_mount(kb);
+ if (ret < 0)
+ return PAD_ERR_FAILED;
+
+ if (bundle_get_type(kb, AUL_K_SDK) == BUNDLE_TYPE_NONE) {
+ ret = _prepare_app_socket();
+ if (ret < 0)
+ return PAD_ERR_FAILED;
+
+ ret = _prepare_id_file();
+ if (ret < 0)
+ return PAD_ERR_FAILED;
+ }
+
+ _send_cmd_to_amd(APP_STARTUP_SIGNAL);
+ return 0;
+}
+
+static int __exec_app_process(void* arg) {
+ auto* launch_arg = static_cast<app_launch_arg*>(arg);
+ int ret;
+
+ _print_hwc_log("%d|after calling fork(). %s", getpid(), launch_arg->appid);
+ PERF("fork done");
+ _D("lock up test log(no error) : fork done");
+
+ if (bundle_get_type(launch_arg->kb, AUL_K_SDK) != BUNDLE_TYPE_NONE)
+ _debug_prepare_debugger(launch_arg->kb);
+
+ _signal_unblock_sigchld();
+
+ _delete_sock_path(getpid(), getuid());
+
+ PERF("prepare exec - first done");
+ ret = __prepare_exec(launch_arg->appid, launch_arg->app_path,
+ launch_arg->menu_info, launch_arg->kb);
+ if (ret < 0)
+ return ret;
+
+ PERF("prepare exec - second done");
+ __real_launch(launch_arg->app_path, launch_arg->kb, launch_arg->menu_info);
+
+ return PAD_ERR_FAILED;
+}
+
+static int __launch_directly(const char* appid,
+ const char* app_path,
+ int clifd,
+ bundle* kb,
+ appinfo_t* menu_info,
+ candidate_process_context_t* cpc) {
+ struct app_launch_arg arg;
+ int pid;
+
+ arg.appid = appid;
+ arg.app_path = app_path;
+ arg.menu_info = menu_info;
+ arg.kb = kb;
+
+ _print_hwc_log("before calling fork(). %s", appid);
+ pid = __fork_app_process(__exec_app_process, &arg, 0);
+ if (pid <= 0)
+ _E("failed to fork app process");
+
+ SECURE_LOGD("==> real launch pid : %d %s", pid, app_path);
+
+ return pid;
+}
+
+static int __create_sock_activation(void) {
+ int fds;
+ char launchpad_process_pool_sock_path[108];
+ int i;
+
+ fds = sd_listen_fds(0);
+ snprintf(launchpad_process_pool_sock_path,
+ sizeof(launchpad_process_pool_sock_path), "%s/daemons/%u/%s",
+ SOCKET_PATH, getuid(), PROCESS_POOL_LAUNCHPAD_SOCK);
+
+ for (i = SD_LISTEN_FDS_START; i < SD_LISTEN_FDS_START + fds; ++i) {
+ if (sd_is_socket_unix(i, SOCK_STREAM, 1, launchpad_process_pool_sock_path,
+ 0) > 0)
+ return i;
+ }
+
+ _W("There is no socket stream");
+ return -1;
+}
+
+static int __get_launchpad_listen_fd(void) {
+ const char* val;
+
+ val = getenv("LAUNCHPAD_LISTEN_FD");
+ if (!val) {
+ _E("Failed to get LAUNCHPAD_LISTEN_FD");
+ return -1;
+ }
+
+ _W("Listen Fd: %s", val);
+ return atoi(val);
+}
+
+static int __launchpad_pre_init(int argc, char** argv) {
+ int fd;
+
+ /* create launchpad sock */
+ fd = __create_sock_activation();
+ if (fd >= 0)
+ return fd;
+
+ fd = __get_launchpad_listen_fd();
+ if (fd >= 0)
+ return fd;
+
+ fd = _create_server_sock(PROCESS_POOL_LAUNCHPAD_SOCK);
+ if (fd < 0) {
+ _E("server sock error %d", fd);
+ return -1;
+ }
+
+ return fd;
+}
+
+static bool __handle_loader_client_event(int fd,
+ io_condition_e cond,
+ void* data) {
+ auto* cpc = static_cast<candidate_process_context_t*>(data);
+
+ if (cpc == nullptr)
+ return false;
+
+ 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 false;
+ }
+
+ return true;
+}
+
+static bool __handle_hydra_client_event(int fd,
+ io_condition_e cond,
+ void* data) {
+ auto* cpc = static_cast<candidate_process_context_t*>(data);
+ int recv_pid = -1;
+ int ret;
+
+ if (cpc == nullptr)
+ return false;
+
+ 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 false;
+ }
+
+ if (cond & IO_IN) {
+ ret = recv(cpc->hydra_fd, &recv_pid, sizeof(recv_pid), MSG_WAITALL);
+ if (ret == -1) {
+ _E("recv() is failed. errno(%d)", errno);
+ } else {
+ _W("candidate process: %d", recv_pid);
+ if (recv_pid > 1)
+ cpc->pid = recv_pid;
+ }
+ }
+
+ return true;
+}
+
+static bool __handle_loader_event(int fd, io_condition_e cond, void* data) {
+ auto* cpc = static_cast<candidate_process_context_t*>(data);
+ int client_fd;
+ int client_pid;
+ int ret;
+
+ if (cpc == nullptr)
+ return false;
+
+ if (!cpc->prepared) {
+ ret = __accept_candidate_process(fd, &client_fd, &client_pid,
+ cpc->is_hydra ? -1 : cpc->pid);
+ if (ret >= 0) {
+ /* for hydra need to set pid to pid of non-hydra candidate, */
+ /* which is connecting now */
+ if (cpc->is_hydra)
+ cpc->pid = client_pid;
+
+ cpc->prepared = true;
+ cpc->send_fd = client_fd;
+
+ SECURE_LOGI(
+ "Type %d candidate process was connected, "
+ "pid: %d",
+ cpc->type, cpc->pid);
+
+ _print_hwc_log(
+ "Type %d candidate process was connected, "
+ "pid: %d",
+ cpc->type, cpc->pid);
+ cpc->client_channel = _io_channel_create(
+ client_fd, static_cast<io_condition_e>(IO_IN | IO_HUP),
+ __handle_loader_client_event, cpc);
+ if (!cpc->client_channel)
+ close(client_fd);
+ }
+ } else {
+ __refuse_candidate_process(fd);
+ _E("Refused candidate process connection");
+ }
+
+ return true;
+}
+
+static bool __handle_hydra_event(int fd, io_condition_e cond, void* data) {
+ auto* cpc = static_cast<candidate_process_context_t*>(data);
+ int client_fd;
+ int client_pid;
+ int ret;
+
+ if (cpc == nullptr)
+ return false;
+
+ if (!cpc->prepared) {
+ ret =
+ __accept_candidate_process(fd, &client_fd, &client_pid, cpc->hydra_pid);
+ if (ret >= 0) {
+ cpc->hydra_fd = client_fd;
+
+ SECURE_LOGD(
+ "Type %d hydra process was connected,"
+ " pid: %d",
+ cpc->type, cpc->hydra_pid);
+
+ cpc->client_channel = _io_channel_create(
+ client_fd, static_cast<io_condition_e>(IO_IN | IO_HUP),
+ __handle_hydra_client_event, cpc);
+ if (!cpc->client_channel)
+ close(client_fd);
+ }
+ } else {
+ __refuse_candidate_process(fd);
+ _E("Refused hydra process connection");
+ }
+
+ return true;
+}
+
+static void __destroy_cleanup_info(struct cleanup_info_s* info) {
+ if (!info)
+ return;
+
+ free(info->appid);
+ free(info);
+}
+
+static struct cleanup_info_s* __create_cleanup_info(const char* appid,
+ int pid) {
+ struct cleanup_info_s* info;
+
+ info = static_cast<cleanup_info_s*>(malloc(sizeof(struct cleanup_info_s)));
+ if (!info) {
+ _E("Out of memory");
+ return nullptr;
+ }
+
+ info->appid = strdup(appid);
+ if (!info->appid) {
+ _E("strdup(%s) is failed", appid);
+ __destroy_cleanup_info(info);
+ return nullptr;
+ }
+
+ info->pid = pid;
+
+ return info;
+}
+
+static bool __cleanup_app_cb(void* user_data) {
+ struct cleanup_info_s* info = (struct cleanup_info_s*)user_data;
+
+ _W("security_manager_cleanup_app() ++");
+ security_manager_cleanup_app(info->appid, getuid(), info->pid);
+ _W("security_manager_cleanup_app() --");
+ __destroy_cleanup_info(info);
+ return false;
+}
+
+static void __handle_sigchild(int pid, void* user_data) {
+ candidate_process_context_t* cpc;
+ struct cleanup_info_s* info;
+ char* appid;
+ int ret = -1;
+
+ appid = static_cast<char*>(
+ g_hash_table_lookup(__pid_table, GINT_TO_POINTER(pid)));
+ if (appid) {
+ info = __create_cleanup_info(appid, pid);
+ if (info)
+ ret = _worker_add_job(__cleaner, __cleanup_app_cb, info);
+
+ if (ret != 0) {
+ __destroy_cleanup_info(info);
+ _W("security_manager_cleanup_app() ++");
+ security_manager_cleanup_app(appid, getuid(), pid);
+ _W("security_manager_cleanup_app() --");
+ }
+
+ g_hash_table_remove(__pid_table, GINT_TO_POINTER(pid));
+ }
+
+ _log_print("[SIGCHLD]", "pid(%7d)", pid);
+ cpc = __find_slot_from_pid(pid);
+ if (cpc != nullptr) {
+ cpc->pid = CANDIDATE_NONE;
+ __dispose_candidate_process(cpc);
+ __prepare_candidate_process(cpc->type, cpc->loader_id);
+ } else {
+ cpc = __find_hydra_slot_from_pid(pid);
+ if (cpc != nullptr) {
+ cpc->hydra_pid = HYDRA_NONE;
+ __dispose_hydra_process(cpc);
+ __prepare_candidate_process(cpc->type, cpc->loader_id);
+ }
+ }
+
+ cpc = __find_slot_from_caller_pid(pid);
+ while (cpc) {
+ __remove_slot(static_cast<int>(launchpad::LoaderType::Dynamic), cpc->loader_id);
+ cpc = __find_slot_from_caller_pid(pid);
+ }
+}
+
+static bool __handle_label_monitor(int fd, io_condition_e cond, void* data) {
+ candidate_process_context_t* cpc;
+ GList* iter = candidate_slot_list;
+
+ if (cond & (IO_ERR | IO_HUP | IO_NVAL)) {
+ _E("fd(%d), io_condition(%d)", fd, cond);
+ abort();
+ return false;
+ }
+
+ _D("fd(%d) condition(%d)", fd, cond);
+ _log_print("[LABEL]", "fd(%d), condition(%d)", fd, cond);
+ security_manager_app_labels_monitor_process(label_monitor);
+
+ while (iter) {
+ cpc = (candidate_process_context_t*)iter->data;
+ if (cpc->is_hydra) {
+ if (cpc->hydra_pid > 0) {
+ __dispose_hydra_process(cpc);
+ __prepare_candidate_process(cpc->type, cpc->loader_id);
+ }
+ } else if (cpc->pid > 0) {
+ __dispose_candidate_process(cpc);
+ __prepare_candidate_process(cpc->type, cpc->loader_id);
+ }
+
+ iter = g_list_next(iter);
+ }
+
+ return true;
+}
+
+static float __interpolator(float input, int cpu_max, int cpu_min) {
+ float ret;
+ float min = cpu_min / 100.0f;
+ float max = cpu_max / 100.0f;
+
+ if (input > 1.0f)
+ input = 1.0f;
+ if (input < 0.0f)
+ input = 0.0f;
+
+ ret = cos(input * PI) / 2.0f + 0.5f;
+ ret *= max - min;
+ ret += min;
+
+ return ret;
+}
+
+static void __update_threshold(candidate_process_context_t* cpc, float delta) {
+ static float pos = 0.0f;
+
+ pos += delta;
+ if (pos < 0.0f)
+ pos = 0.0f;
+
+ if (pos > 1.0f)
+ pos = 1.0f;
+
+ cpc->threshold =
+ (int)(__interpolator(pos, cpc->threshold_max, cpc->threshold_min) * 100);
+ _D("[CPU] type:%d / delta:%f / input cursor : %f / threshold : %d", cpc->type,
+ delta, pos, cpc->threshold);
+}
+
+static gboolean __handle_idle_checker(gpointer data) {
+ unsigned long long total = 0;
+ unsigned long long idle = 0;
+ int per;
+ candidate_process_context_t* cpc;
+
+ if (!data) {
+ _E("Critical error!");
+ __sequencer.idle_checker = 0;
+ __sequencer.running_cpc = nullptr;
+ return G_SOURCE_REMOVE;
+ }
+
+ cpc = (candidate_process_context_t*)data;
+ if (cpc->app_check && !cpc->app_exists) {
+ _W("The application is not installed. loader(%s:%d)", cpc->loader_name,
+ cpc->type);
+ __sequencer.idle_checker = 0;
+ __sequencer.running_cpc = nullptr;
+ return G_SOURCE_REMOVE;
+ }
+
+ if (cpc->state != CANDIDATE_PROCESS_STATE_RUNNING) {
+ _W("Slot state is not running. loader(%s:%d)", cpc->loader_name, cpc->type);
+ __sequencer.idle_checker = 0;
+ __sequencer.running_cpc = nullptr;
+ return G_SOURCE_REMOVE;
+ }
+
+ if (cpc->pid != CANDIDATE_NONE) {
+ _W("Slot is already running. %d:%s:%d", cpc->type, cpc->loader_name,
+ cpc->pid);
+ __sequencer.idle_checker = 0;
+ __sequencer.running_cpc = nullptr;
+ return G_SOURCE_REMOVE;
+ }
+
+ _get_cpu_idle(&total, &idle);
+ if (total == cpc->cpu_total_time)
+ total++;
+
+ per = (idle - cpc->cpu_idle_time) * 100 / (total - cpc->cpu_total_time);
+ _D("[CPU] Idle : %d / loader(%s:%d)", per, cpc->loader_name, cpc->type);
+
+ if (per >= cpc->threshold) {
+ __update_threshold(cpc, -0.02f * (per - cpc->threshold));
+ __prepare_candidate_process(cpc->type, cpc->loader_id);
+ cpc->touched = true;
+ __sequencer.idle_checker = 0;
+ __sequencer.running_cpc = nullptr;
+ return G_SOURCE_REMOVE;
+ }
+
+ cpc->cpu_idle_time = idle;
+ cpc->cpu_total_time = total;
+ __update_threshold(cpc, 0.05f);
+
+ cpc->cpu_check_count++;
+ if (cpc->cpu_check_count == MAX_CPU_CHECK_COUNT) {
+ _W("CPU check count has exceeded %d times. loader(%s:%d)",
+ cpc->cpu_check_count, cpc->loader_name, cpc->type);
+ __sequencer.idle_checker = 0;
+ __sequencer.running_cpc = nullptr;
+ __sequencer_add_slot(cpc);
+ return G_SOURCE_REMOVE;
+ }
+
+ return G_SOURCE_CONTINUE;
+}
+
+static gboolean __on_boot_timeout_cb(gpointer user_data) {
+ auto* context = static_cast<candidate_process_context_t*>(user_data);
+
+ _W("type(%d), loader_name(%s)", context->type, context->loader_name);
+ context->on_boot_timer = 0;
+ if (context->pid != CANDIDATE_NONE) {
+ _E("Candidate process is already running. %d:%s:%d", context->type,
+ context->loader_name, context->pid);
+ } else {
+ __prepare_candidate_process(context->type, context->loader_id);
+ context->touched = true;
+ }
+
+ return G_SOURCE_REMOVE;
+}
+
+static void __add_on_boot_timer(candidate_process_context_t* context) {
+ if (context->on_boot_timer != 0)
+ return;
+
+ context->on_boot_timer =
+ g_timeout_add(context->on_boot_timeout, __on_boot_timeout_cb, context);
+}
+
+static int __add_idle_checker(int detection_method, GList* cur) {
+ candidate_process_context_t* cpc;
+ GList* iter = cur;
+
+ while (iter) {
+ cpc = (candidate_process_context_t*)iter->data;
+ if (!cpc->touched && cpc->on_boot && cpc->on_boot_timeout > 0)
+ __add_on_boot_timer(cpc);
+
+ if (cpc->state != CANDIDATE_PROCESS_STATE_RUNNING) {
+ iter = g_list_next(iter);
+ continue;
+ }
+
+ if (strcmp("null", cpc->loader_path) == 0) {
+ iter = g_list_next(iter);
+ continue;
+ }
+
+ if (!cpc->touched && !cpc->on_boot) {
+ iter = g_list_next(iter);
+ continue;
+ }
+
+ if (cpc->app_check && !cpc->app_exists) {
+ iter = g_list_next(iter);
+ continue;
+ }
+
+ if (cpc->pid == CANDIDATE_NONE &&
+ (!cpc->touched || (cpc->detection_method & detection_method))) {
+ if (cpc->timer > 0) {
+ g_source_remove(cpc->timer);
+ cpc->timer = 0;
+ }
+
+ cpc->cur_event = detection_method;
+ __sequencer_add_slot(cpc);
+ __sequencer_run();
+ }
+
+ iter = g_list_next(iter);
+ }
+
+ return -1;
+}
+
+static int __dispatch_cmd_hint(bundle* kb, int detection_method) {
+ _W("cmd hint %d", detection_method);
+ __add_idle_checker(detection_method, candidate_slot_list);
+
+ return 0;
+}
+
+static int __dispatch_cmd_add_loader(bundle* kb) {
+ const char* add_slot_str = nullptr;
+ const char* caller_pid = nullptr;
+ const char* extra;
+ int lid, size;
+ char* loader_name;
+ candidate_process_context_t* cpc;
+ slot_info_t slot_info;
+
+ _W("cmd add loader");
+ add_slot_str = bundle_get_val(kb, AUL_K_LOADER_PATH);
+ caller_pid = bundle_get_val(kb, AUL_K_CALLER_PID);
+ extra = bundle_get_val(kb, AUL_K_LOADER_EXTRA);
+
+ if (add_slot_str == nullptr || caller_pid == nullptr)
+ return -1;
+
+ lid = __make_loader_id();
+ size = snprintf(0, 0, "%s%s%d", add_slot_str, caller_pid, lid);
+ loader_name = (char*)malloc(size + 1);
+ if (loader_name == nullptr) {
+ _E("Out of memory");
+ return -1;
+ }
+
+ snprintf(loader_name, size, "%s%s%d", add_slot_str, caller_pid, lid);
+
+ slot_info.type = static_cast<int>(launchpad::LoaderType::Dynamic);
+ slot_info.loader_id = lid;
+ slot_info.caller_pid = atoi(caller_pid);
+ slot_info.loader_name = loader_name;
+ slot_info.loader_path = add_slot_str;
+ slot_info.loader_extra = extra;
+ slot_info.detection_method = static_cast<int>(
+ launchpad::LoaderMethod::Timeout | launchpad::LoaderMethod::Visibility);
+ slot_info.activation_method =
+ static_cast<int>(launchpad::LoaderMethod::Request |
+ launchpad::LoaderMethod::AvailableMemory);
+ slot_info.deactivation_method = static_cast<int>(
+ launchpad::LoaderMethod::Ttl | launchpad::LoaderMethod::OutOfMemory);
+ slot_info.ttl = 600;
+ slot_info.timeout_val = 2000;
+ slot_info.threshold_max = launchpad::DefaultCpuThresholdMax;
+ slot_info.threshold_min = launchpad::DefaultCpuThresholdMin;
+ slot_info.on_boot = false;
+ slot_info.app_exists = true;
+ slot_info.is_hydra = false;
+ slot_info.app_check = true;
+ slot_info.on_boot_timeout = 0;
+ slot_info.sched_priority = 0;
+
+ cpc = __add_slot(&slot_info);
+ free(loader_name);
+ if (cpc == nullptr)
+ return -1;
+
+ __set_timer(cpc);
+ return lid;
+}
+
+static int __dispatch_cmd_add_app_defined_loader(bundle* kb) {
+ const char* loader_name;
+ int lid, len;
+ candidate_process_context_t* cpc;
+ launchpad::LoaderInfoPtr info;
+ bundle_raw* extra;
+ slot_info_t slot_info;
+
+ _W("cmd add defined loader");
+ loader_name = bundle_get_val(kb, AUL_K_LOADER_NAME);
+
+ if (loader_name == nullptr) {
+ _E("loader_name is nullptr");
+ return -EINVAL;
+ }
+
+ info = app_defined_loader_info_manager->FindLoaderInfo(loader_name);
+ if (info == nullptr) {
+ _E("loader_name %s, info %d", loader_name, info != nullptr);
+ return -EINVAL;
+ }
+
+ cpc = __find_slot_from_loader_name(loader_name);
+ if (cpc == nullptr) {
+ lid = __make_loader_id();
+ bundle_encode(info->GetExtra().GetHandle(), &extra, &len);
+ slot_info.type = static_cast<int>(launchpad::LoaderType::Dynamic);
+ slot_info.loader_id = lid;
+ slot_info.caller_pid = 0;
+ slot_info.loader_name = loader_name;
+ slot_info.loader_path = "/usr/bin/app-defined-loader";
+ slot_info.loader_extra = (const char*)extra;
+ slot_info.detection_method = static_cast<int>(launchpad::LoaderMethod::Timeout) | static_cast<int>(launchpad::LoaderMethod::Visibility);
+ slot_info.activation_method = static_cast<int>(launchpad::LoaderMethod::Request) | static_cast<int>(launchpad::LoaderMethod::AvailableMemory);
+ slot_info.deactivation_method = static_cast<int>(launchpad::LoaderMethod::Ttl) | static_cast<int>(launchpad::LoaderMethod::OutOfMemory);
+ slot_info.ttl = info->GetTtl();
+ slot_info.timeout_val = 2000;
+ slot_info.threshold_max = launchpad::DefaultCpuThresholdMax;
+ slot_info.threshold_min = launchpad::DefaultCpuThresholdMin;
+ slot_info.on_boot = false;
+ slot_info.app_exists = true;
+ slot_info.is_hydra = false;
+ slot_info.app_check = true;
+ slot_info.on_boot_timeout = 0;
+ slot_info.sched_priority = 0;
+
+ cpc = __add_slot(&slot_info);
+ bundle_free_encoded_rawdata(&extra);
+ if (cpc == nullptr) {
+ _E("cpc is nullptr");
+ return -ENOMEM;
+ }
+ } else {
+ lid = cpc->loader_id;
+ }
+
+ if (cpc->pid == CANDIDATE_NONE)
+ __prepare_candidate_process(static_cast<int>(launchpad::LoaderType::Dynamic), lid);
+
+ return lid;
+}
+
+static int __dispatch_cmd_remove_loader(bundle* kb) {
+ const char* id = bundle_get_val(kb, AUL_K_LOADER_ID);
+ int lid;
+
+ _W("cmd remove loader");
+ if (id) {
+ lid = atoi(id);
+ if (__remove_slot(static_cast<int>(launchpad::LoaderType::Dynamic), lid) == 0)
+ return 0;
+ }
+
+ return -1;
+}
+
+static int __check_caller_by_pid(int pid) {
+ int ret;
+ char buf[PATH_MAX] = {
+ 0,
+ };
+
+ ret = _proc_get_attr(pid, buf, sizeof(buf));
+ if (ret < 0)
+ return -1;
+
+ if (strcmp(buf, "User") == 0 || strcmp(buf, "System") == 0 ||
+ strcmp(buf, "System::Privileged") == 0)
+ return 0;
+
+ return -1;
+}
+
+static bool __is_hw_acc(const char* hwacc) {
+ if (strcmp(hwacc, "USE") == 0 ||
+ (strcmp(hwacc, "SYS") == 0 && __sys_hwacc == SETTING_HW_ACCELERATION_ON))
+ return true;
+
+ return false;
+}
+
+static candidate_process_context_t* __find_available_slot(
+ const char* hwacc,
+ const char* app_type,
+ const char* loader_name,
+ candidate_process_context_t** org_cpc) {
+ launchpad::LoaderType type = launchpad::LoaderType::Unsupported;
+ candidate_process_context_t* cpc;
+
+ if (loader_name) {
+ for (auto& info : loader_info_manager->GetLoaderInfoList()) {
+ if (info->GetName() == loader_name) {
+ type = info->GetType();
+ break;
+ }
+ }
+ } else {
+ if (__is_hw_acc(hwacc))
+ type = loader_info_manager->FindHwType(app_type);
+ else
+ type = loader_info_manager->FindSwType(app_type);
+ }
+
+ cpc = __find_slot(static_cast<int>(type), PAD_LOADER_ID_STATIC);
+ if (!cpc)
+ return nullptr;
+
+ *org_cpc = cpc;
+
+ if (cpc->prepared)
+ return cpc;
+
+ auto a_types = loader_info_manager->GetAlternativeTypes(type);
+ if (a_types.empty())
+ return nullptr;
+
+ for (auto& a_type : a_types) {
+ cpc = __find_slot(static_cast<int>(a_type), PAD_LOADER_ID_STATIC);
+ if (!cpc)
+ continue;
+ if (cpc->prepared) {
+ return cpc;
+ }
+ }
+
+ return nullptr;
+}
+
+static void __update_slot(int type, bool app_exists) {
+ candidate_process_context_t* cpc;
+
+ cpc = __find_slot(type, PAD_LOADER_ID_STATIC);
+ if (!cpc)
+ return;
+
+ cpc->app_exists = app_exists;
+ if (cpc->app_check && !cpc->app_exists) {
+ if (cpc->pid > 0)
+ __dispose_candidate_process(cpc);
+ __sequencer_remove_slot(cpc);
+ if (__sequencer_queue_is_empty())
+ __sequencer_stop();
+ } else {
+ if (cpc->state != CANDIDATE_PROCESS_STATE_RUNNING)
+ return;
+
+ if (!cpc->touched && !cpc->on_boot)
+ return;
+
+ if (cpc->timer > 0) {
+ g_source_remove(cpc->timer);
+ cpc->timer = 0;
+ }
+
+ if (cpc->pid == CANDIDATE_NONE) {
+ __sequencer_add_slot(cpc);
+ __sequencer_run();
+ }
+ }
+}
+
+static void __foreach_loader_info(const launchpad::LoaderInfoPtr& info,
+ void* data) {
+ struct app_info* ai = (struct app_info*)data;
+ auto it = std::find_if(
+ info->GetAppTypes().begin(), info->GetAppTypes().end(),
+ [&](const std::string& type) -> bool { return type == ai->type; });
+
+ if (it == info->GetAppTypes().end())
+ return;
+
+ info->SetAppExists(ai->exists);
+ __update_slot(static_cast<int>(info->GetType()), info->IsAppExists());
+}
+
+static int __dispatch_cmd_update_app_type(bundle* b) {
+ int r;
+ struct app_info info;
+ const char* is_installed;
+
+ info.type = bundle_get_val(b, AUL_K_APP_TYPE);
+ if (!info.type)
+ return -1;
+
+ is_installed = bundle_get_val(b, AUL_K_IS_INSTALLED);
+ if (is_installed && !strcmp(is_installed, "true"))
+ info.exists = true;
+ else
+ info.exists = false;
+
+ _I("[LAUNCHPAD] type(%s), exists(%d)", info.type, info.exists);
+
+ for (auto& linfo : loader_info_manager->GetLoaderInfoList()) {
+ __foreach_loader_info(linfo, &info);
+ }
+
+ return 0;
+}
+
+static void __deactivate_slot(candidate_process_context_t* cpc) {
+ if (cpc->state == CANDIDATE_PROCESS_STATE_PAUSED)
+ return;
+
+ cpc->state = CANDIDATE_PROCESS_STATE_PAUSED;
+ if (cpc->is_hydra)
+ __dispose_hydra_process(cpc);
+ else
+ __dispose_candidate_process(cpc);
+}
+
+static void __activate_slot(candidate_process_context_t* cpc) {
+ if (cpc->state == CANDIDATE_PROCESS_STATE_RUNNING)
+ return;
+
+ cpc->state = CANDIDATE_PROCESS_STATE_RUNNING;
+ if (!cpc->touched && !cpc->on_boot)
+ return;
+
+ if ((cpc->app_check && !cpc->app_exists) || cpc->pid > CANDIDATE_NONE)
+ return;
+
+ if (cpc->detection_method & static_cast<int>(launchpad::LoaderMethod::Timeout))
+ __set_timer(cpc);
+}
+
+static void __update_slot_state(candidate_process_context_t* cpc,
+ launchpad::LoaderMethod method,
+ bool force) {
+ switch (method) {
+ case launchpad::LoaderMethod::OutOfMemory:
+ if ((force || cpc->deactivation_method & static_cast<int>(method)) && __is_low_memory()) {
+ _W("Low memory, deactivate slot %d", cpc->type);
+ __deactivate_slot(cpc);
+ } else {
+ __activate_slot(cpc);
+ }
+ break;
+ case launchpad::LoaderMethod::Ttl:
+ if (force || cpc->deactivation_method & static_cast<int>(method))
+ __deactivate_slot(cpc);
+ break;
+ case launchpad::LoaderMethod::AvailableMemory:
+ if (force || cpc->activation_method & static_cast<int>(method))
+ __activate_slot(cpc);
+ break;
+ case launchpad::LoaderMethod::Request:
+ if (force || cpc->activation_method & static_cast<int>(method))
+ __update_slot_state(cpc, launchpad::LoaderMethod::OutOfMemory, force);
+ break;
+ default:
+ __activate_slot(cpc);
+ break;
+ }
+}
+
+static void __request_destroy(request_t* request) {
+ if (request == nullptr)
+ return;
+
+ if (request->clifd > -1)
+ close(request->clifd);
+ if (request->menu_info)
+ _appinfo_free(request->menu_info);
+ if (request->kb)
+ bundle_free(request->kb);
+ if (request->pkt)
+ free(request->pkt);
+ free(request);
+}
+
+static int __request_create(int fd, request_t** request) {
+ struct ucred cr;
+ request_t* req;
+
+ if (request == nullptr) {
+ _E("Invalid parameter");
+ return -EINVAL;
+ }
+
+ req = static_cast<request_t*>(calloc(1, sizeof(request_t)));
+ if (req == nullptr) {
+ _E("calloc() is failed");
+ return -ENOMEM;
+ }
+
+ req->clifd = -1;
+ req->pkt = _accept_recv_pkt_raw(fd, &req->clifd, &cr);
+ if (req->pkt == nullptr) {
+ _E("_accept_recv_pkt_raw() is failed");
+ __request_destroy(req);
+ return -ECOMM;
+ }
+
+ req->kb = bundle_decode(req->pkt->data, req->pkt->len);
+ if (req->kb == nullptr) {
+ _E("bundle_decode() is failed");
+ __real_send(req->clifd, -EINVAL);
+ req->clifd = -1;
+ __request_destroy(req);
+ return -EINVAL;
+ }
+
+ req->cmd = req->pkt->cmd;
+ req->caller_pid = cr.pid;
+ req->caller_uid = cr.uid;
+ *request = req;
+ return 0;
+}
+
+static void __request_send_result(request_h request, int result) {
+ if (request->clifd < 0)
+ return;
+
+ __real_send(request->clifd, result);
+ request->clifd = -1;
+}
+
+static int __visibility_request_handler(request_h request) {
+ int ret = __dispatch_cmd_hint(request->kb,
+ static_cast<int>(launchpad::LoaderMethod::Visibility));
+
+ __request_send_result(request, ret);
+ _D("[PAD_CMD_VISIBILITY] result: %d", ret);
+ return ret;
+}
+
+static int __add_loader_request_handler(request_h request) {
+ int ret = __dispatch_cmd_add_loader(request->kb);
+
+ __request_send_result(request, ret);
+ _D("[PAD_CMD_ADD_LOADER] result: %d", ret);
+ return ret;
+}
+
+static int __remove_loader_request_handler(request_h request) {
+ int ret = __dispatch_cmd_remove_loader(request->kb);
+
+ __request_send_result(request, ret);
+ _D("[PAD_CMD_REMOVE_LOADER] result: %d", ret);
+ return ret;
+}
+
+static int __make_default_slots_request_handler(request_h request) {
+ int ret = __add_default_slots();
+
+ __request_send_result(request, ret);
+ _D("[PAD_CMD_MAKE_DEFAULT_SLOTS] result: %d", ret);
+ return ret;
+}
+
+static int __prepare_app_defined_loader_request_handler(request_h request) {
+ int ret = __dispatch_cmd_add_app_defined_loader(request->kb);
+
+ __request_send_result(request, ret);
+ _D("[PAD_CMD_PREPARE_APP_DEFINED_LOADER] result: %d", ret);
+ return ret;
+}
+
+static int __demand_request_handler(request_h request) {
+ int ret = __dispatch_cmd_hint(request->kb,
+ static_cast<int>(launchpad::LoaderMethod::Demand));
+
+ __request_send_result(request, ret);
+ _D("[PAD_CMD_DEMAND] result: %d", ret);
+ return ret;
+}
+
+static int __ping_request_handler(request_h request) {
+ __request_send_result(request, getpid());
+ _D("[PAD_CMD_PING] result: %d", getpid());
+ return 0;
+}
+
+static int __update_app_type_request_handler(request_h request) {
+ int ret = __dispatch_cmd_update_app_type(request->kb);
+
+ _D("[PAD_CMD_UPDATE_APP_TYPE] result: %d", ret);
+ return ret;
+}
+
+static int __connect_request_handler(request_h request) {
+ if (__client_fd != -1)
+ close(__client_fd);
+
+ __client_fd = request->clifd;
+ request->clifd = -1;
+ _D("[PAD_CMD_CONNECT] client fd: %d", __client_fd);
+ return 0;
+}
+
+static int __launch_request_prepare(request_h request) {
+ const appinfo_t* menu_info;
+ int type = -1;
+
+ request->menu_info = _appinfo_create(request->kb);
+ if (request->menu_info == nullptr) {
+ _E("_appinfo_create() is failed");
+ return -1;
+ }
+
+ request->app_path = _appinfo_get_app_path(request->menu_info);
+ if (request->app_path == nullptr) {
+ _E("_appinfo_get_app_path() is failed");
+ return -1;
+ }
+
+ if (request->app_path[0] != '/') {
+ _E("app path is not absolute path");
+ return -1;
+ }
+
+ menu_info = request->menu_info;
+ if (menu_info->hwacc == nullptr) {
+ _E("Failed to find HW acceeleration type");
+ return -1;
+ }
+
+ SECURE_LOGD("appid: %s", menu_info->appid);
+ SECURE_LOGD("exec: %s", menu_info->app_path);
+ SECURE_LOGD("comp_type: %s", menu_info->comp_type);
+ SECURE_LOGD("internal pool: %s", menu_info->internal_pool);
+ SECURE_LOGD("hwacc: %s", menu_info->hwacc);
+ SECURE_LOGD("app_type: %s", menu_info->app_type);
+ SECURE_LOGD("pkg_type: %s", menu_info->pkg_type);
+
+ if (menu_info->comp_type && !strcmp(menu_info->comp_type, "svcapp")) {
+ request->loader_id = __get_loader_id(request->kb);
+ if (request->loader_id > PAD_LOADER_ID_DYNAMIC_BASE) {
+ type = static_cast<int>(launchpad::LoaderType::Dynamic);
+ request->cpc = __find_slot(type, request->loader_id);
+ if (request->cpc && !request->cpc->prepared)
+ request->cpc = nullptr;
+ } else {
+ request->loader_id = PAD_LOADER_ID_DIRECT;
+ }
+ } else if (menu_info->comp_type && menu_info->app_type &&
+ !strcmp(menu_info->comp_type, "widgetapp") &&
+ !strcmp(menu_info->app_type, "webapp")) {
+ request->loader_id = PAD_LOADER_ID_DIRECT;
+ } else {
+ request->loader_id = __get_loader_id(request->kb);
+ if (request->loader_id <= PAD_LOADER_ID_STATIC) {
+ request->cpc =
+ __find_available_slot(menu_info->hwacc, menu_info->app_type,
+ menu_info->loader_name, &request->org_cpc);
+ } else {
+ type = static_cast<int>(launchpad::LoaderType::Dynamic);
+ request->cpc = __find_slot(type, request->loader_id);
+ if (request->cpc && !request->cpc->prepared)
+ request->cpc = nullptr;
+ }
+ }
+
+ _modify_bundle(request->kb, request->caller_pid, request->menu_info,
+ request->cmd);
+ if (menu_info->appid == nullptr) {
+ _E("Unable to get appid from app info");
+ return -1;
+ }
+
+ PERF("Getting package information & modifying bundle done");
+ return 0;
+}
+
+static void __launch_request_complete(request_h request) {
+ _memory_monitor_reset_timer();
+ __request_send_result(request, request->pid);
+
+ if (request->pid > 0) {
+ _dbus_send_app_launch_signal(request->pid, request->menu_info->appid);
+ g_hash_table_insert(__pid_table, GINT_TO_POINTER(request->pid),
+ strdup(request->menu_info->appid));
+ _log_print("[LAUNCH]", "pid(%7d) | appid(%s)", request->pid,
+ request->menu_info->appid);
+ }
+}
+
+static void __handle_direct_launch(request_h request) {
+ if (request->org_cpc &&
+ (!request->org_cpc->app_check || request->org_cpc->app_exists) &&
+ request->org_cpc->pid == CANDIDATE_NONE &&
+ !__sequencer_slot_exist(request->org_cpc)) {
+ if (request->org_cpc->timer > 0) {
+ g_source_remove(request->org_cpc->timer);
+ request->org_cpc->timer = 0;
+ }
+
+ __update_slot_state(request->org_cpc, launchpad::LoaderMethod::Request, true);
+ __set_timer(request->org_cpc);
+ }
+}
+
+static void __fork_processing(request_h request) {
+ if (bundle_get_type(request->kb, AUL_K_SDK) != BUNDLE_TYPE_NONE)
+ _debug_init();
+
+ _W("appid: %s", request->menu_info->appid);
+ request->pid = __launch_directly(request->menu_info->appid, request->app_path,
+ request->clifd, request->kb,
+ request->menu_info, nullptr);
+ if (request->pid == -1) {
+ _E("Failed to create a child process. appid(%s)",
+ request->menu_info->appid);
+ }
+
+ __request_send_result(request, request->pid);
+ _W("appid: %s, pid: %d", request->menu_info->appid, request->pid);
+ __handle_direct_launch(request);
+}
+
+static int __launch_request_do(request_h request) {
+ if (request->loader_id == PAD_LOADER_ID_DIRECT || request->cpc == nullptr) {
+ __fork_processing(request);
+ return 0;
+ }
+
+ _W("Launch %d type process. appid(%s)", request->cpc->type,
+ request->menu_info->appid);
+ request->pid = __send_launchpad_loader(request->cpc, request->pkt,
+ request->app_path, request->clifd);
+ return 0;
+}
+
+static int __launch_request_handler(request_h request) {
+ int ret;
+
+ traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "LAUNCHPAD:LAUNCH");
+ INIT_PERF(kb);
+ PERF("Packet processing start");
+
+ ret = __launch_request_prepare(request);
+ if (ret < 0) {
+ traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
+ __request_send_result(request, ret);
+ return ret;
+ }
+
+ ret = __launch_request_do(request);
+ if (ret < 0)
+ request->pid = ret;
+
+ __launch_request_complete(request);
+ traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
+ _D("[PAD_CMD_LAUNCH] appid: %s, result: %d", request->menu_info->appid,
+ request->pid);
+ return 0;
+}
+
+static request_handler __request_handlers[PAD_CMD_CONNECT + 1] = {};
+
+static bool __handle_launch_event(int fd, io_condition_e cond, void* data) {
+ request_t* request = nullptr;
+ int ret;
+
+ if (cond & (IO_ERR | IO_HUP | IO_NVAL)) {
+ _E("fd(%d), condition(%d)", fd, cond);
+ g_idle_add(__launchpad_recovery_cb, __launchpad_channel);
+ __launchpad_channel = nullptr;
+ return false;
+ }
+
+ ret = __request_create(fd, &request);
+ if (ret != 0)
+ return true;
+
+ _W("cmd(%d), caller(%d)", request->cmd, request->caller_pid);
+ if (request->caller_uid >= REGULAR_UID_MIN) {
+ if (__check_caller_by_pid(request->caller_pid) < 0) {
+ _E("Permission denied. pid(%d)", request->caller_pid);
+ __request_send_result(request, -EPERM);
+ __request_destroy(request);
+ return true;
+ }
+ }
+
+ if (request->cmd < 0 || request->cmd >= ARRAY_SIZE(__request_handlers) ||
+ __request_handlers[request->cmd] == nullptr) {
+ _E("Unknown command: %d", request->cmd);
+ __request_send_result(request, -EINVAL);
+ __request_destroy(request);
+ return true;
+ }
+
+ __request_handlers[request->cmd](request);
+ __request_destroy(request);
+ return true;
+}
+
+static void __destroy_slot(candidate_process_context_t* cpc) {
+ if (!cpc)
+ return;
+
+ if (cpc->hydra_channel)
+ _io_channel_destroy(cpc->hydra_channel);
+
+ if (cpc->channel)
+ _io_channel_destroy(cpc->channel);
+
+ if (cpc->loader_extra)
+ free(cpc->loader_extra);
+
+ if (cpc->loader_path)
+ free(cpc->loader_path);
+
+ if (cpc->loader_name)
+ free(cpc->loader_name);
+
+ free(cpc);
+}
+
+static candidate_process_context_t* __create_slot(slot_info_t* info) {
+ candidate_process_context_t* cpc;
+
+ cpc = static_cast<candidate_process_context_t*>(
+ calloc(1, sizeof(candidate_process_context_t)));
+ if (cpc == nullptr) {
+ _E("Out of memory");
+ return nullptr;
+ }
+
+ cpc->loader_name = strdup(info->loader_name);
+ if (cpc->loader_name == nullptr) {
+ _E("Failed to duplicate loader name(%s)", info->loader_name);
+ __destroy_slot(cpc);
+ return nullptr;
+ }
+
+ cpc->loader_path = strdup(info->loader_path);
+ if (cpc->loader_path == nullptr) {
+ _E("Failed to duplicate loader path(%s)", info->loader_path);
+ __destroy_slot(cpc);
+ return nullptr;
+ }
+
+ cpc->loader_extra =
+ info->loader_extra ? strdup(info->loader_extra) : strdup("");
+ if (cpc->loader_extra == nullptr) {
+ _E("Failed to duplicate loader extra(%s)", info->loader_extra);
+ __destroy_slot(cpc);
+ return nullptr;
+ }
+
+ cpc->type = info->type;
+ cpc->prepared = false;
+ cpc->pid = CANDIDATE_NONE;
+ cpc->hydra_pid = HYDRA_NONE;
+ cpc->caller_pid = info->caller_pid;
+ cpc->loader_id = info->loader_id;
+ cpc->send_fd = -1;
+ cpc->hydra_fd = -1;
+ cpc->last_exec_time = 0;
+ cpc->timer = 0;
+ cpc->detection_method = info->detection_method;
+ cpc->timeout_val = info->timeout_val;
+ cpc->cpu_total_time = 0;
+ cpc->cpu_idle_time = 0;
+ cpc->threshold = info->threshold_max;
+ cpc->threshold_max = info->threshold_max;
+ cpc->threshold_min = info->threshold_min;
+ cpc->on_boot = info->on_boot;
+ cpc->app_exists = info->app_exists;
+ cpc->touched = false;
+ cpc->cur_event = 0;
+ cpc->activation_method = info->activation_method;
+ cpc->deactivation_method = info->deactivation_method;
+ cpc->ttl = info->ttl;
+ cpc->live_timer = 0;
+ cpc->is_hydra = info->is_hydra;
+ cpc->app_check = info->app_check;
+ cpc->score = WIN_SCORE;
+ cpc->pss = 0;
+ cpc->cpu_check_count = 0;
+ cpc->on_boot_timeout = info->on_boot_timeout;
+ cpc->sched_priority = info->sched_priority;
+
+ if ((cpc->deactivation_method & static_cast<int>(launchpad::LoaderMethod::OutOfMemory)) && __is_low_memory())
+ cpc->state = CANDIDATE_PROCESS_STATE_PAUSED;
+ else
+ cpc->state = CANDIDATE_PROCESS_STATE_RUNNING;
+
+ _W("loader(%s), type(%d), state(%d)", cpc->loader_name, cpc->type,
+ cpc->state);
+ return cpc;
+}
+
+static candidate_process_context_t* __add_slot(slot_info_t* info) {
+ candidate_process_context_t* cpc;
+ int fd;
+ io_channel_h channel;
+ int hydra_fd;
+ io_channel_h hydra_channel;
+
+ if (info == nullptr)
+ return nullptr;
+
+ if (__find_slot(info->type, info->loader_id) != nullptr)
+ return nullptr;
+
+ cpc = __create_slot(info);
+ if (cpc == nullptr)
+ return nullptr;
+
+ fd = __listen_candidate_process(cpc->type, cpc->loader_id);
+ if (fd == -1) {
+ _E("[launchpad] Listening the socket to "
+ "the type %d candidate process failed.",
+ cpc->type);
+ __destroy_slot(cpc);
+ return nullptr;
+ }
+
+ channel = _io_channel_create(fd, IO_IN, __handle_loader_event, cpc);
+ if (!channel) {
+ close(fd);
+ __destroy_slot(cpc);
+ return nullptr;
+ }
+
+ cpc->channel = channel;
+
+ if (info->is_hydra) {
+ hydra_fd = __listen_hydra_process(cpc->type, cpc->loader_id);
+ if (hydra_fd == -1) {
+ _E("[launchpad] Listening the socket to "
+ "the type %d hydra process failed.",
+ cpc->type);
+ __destroy_slot(cpc);
+ return nullptr;
+ }
+
+ hydra_channel =
+ _io_channel_create(hydra_fd, IO_IN, __handle_hydra_event, cpc);
+ if (!hydra_channel) {
+ close(hydra_fd);
+ __destroy_slot(cpc);
+ return nullptr;
+ }
+
+ cpc->hydra_channel = hydra_channel;
+ }
+
+ candidate_slot_list = g_list_append(candidate_slot_list, cpc);
+
+ return cpc;
+}
+
+static int __remove_slot(int type, int loader_id) {
+ candidate_process_context_t* cpc;
+ GList* iter;
+
+ iter = candidate_slot_list;
+ while (iter) {
+ cpc = (candidate_process_context_t*)iter->data;
+ if (type == cpc->type && loader_id == cpc->loader_id) {
+ __dispose_candidate_process(cpc);
+ candidate_slot_list = g_list_delete_link(candidate_slot_list, iter);
+ __destroy_slot(cpc);
+ return 0;
+ }
+
+ iter = g_list_next(iter);
+ }
+
+ return -1;
+}
+
+static int __init_launchpad_fd(int argc, char** argv) {
+ int fd;
+
+ fd = __launchpad_pre_init(argc, argv);
+ if (fd < 0) {
+ _E("launchpad pre init failed");
+ return -1;
+ }
+
+ auto cond = IO_IN | IO_PRI | IO_HUP | IO_ERR | IO_NVAL;
+ __launchpad_channel = _io_channel_create(
+ fd, static_cast<io_condition_e>(cond), __handle_launch_event, nullptr);
+ if (!__launchpad_channel) {
+ close(fd);
+ return -1;
+ }
+
+ 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)) {
+ _W("%s is created", 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;
+ launchpad::LoaderInfoPtr info;
+ candidate_process_context_t* cpc;
+
+ if (!event_name) {
+ _E("Invalid parameter");
+ return true;
+ }
+
+ ext = const_cast<char*>(strrchr(event_name, '.'));
+ if (ext == nullptr || strcmp(ext, ".loader") != 0)
+ return true;
+
+ _W("event_name(%s), mask(%u)", event_name, mask);
+ if (mask & IN_CREATE) {
+ app_defined_loader_info_manager->LoadFile(event_name);
+ } else if (mask & IN_DELETE) {
+ snprintf(buf, ext - event_name + 1, "%s", event_name);
+
+ info = app_defined_loader_info_manager->FindLoaderInfo(buf);
+ cpc = __find_slot_from_loader_name(info->GetName().c_str());
+ __remove_slot(cpc->type, cpc->loader_id);
+ app_defined_loader_info_manager->Unload(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,
+ nullptr);
+ 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, nullptr);
+
+ 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;
+ int fd = -1;
+
+ auto err_handler = [&]() -> int {
+ if (fd > 0)
+ close(fd);
+
+ if (label_monitor) {
+ security_manager_app_labels_monitor_finish(label_monitor);
+ label_monitor = nullptr;
+ }
+ return -1;
+ };
+
+ r = security_manager_app_labels_monitor_init(&label_monitor);
+ if (r != SECURITY_MANAGER_SUCCESS)
+ return -1;
+
+ r = security_manager_app_labels_monitor_process(label_monitor);
+ if (r != SECURITY_MANAGER_SUCCESS)
+ return err_handler();
+
+ security_manager_app_labels_monitor_get_fd(label_monitor, &fd);
+ if (fd < 0) {
+ _E("failed to get fd");
+ return err_handler();
+ }
+
+ auto cond = IO_IN | IO_PRI | IO_HUP | IO_ERR | IO_NVAL;
+ __label_monitor_channel = _io_channel_create(
+ fd, static_cast<io_condition_e>(cond), __handle_label_monitor, nullptr);
+ if (!__label_monitor_channel)
+ return err_handler();
+
+ return 0;
+
+
+}
+
+static int __verify_loader_caps(const char* loader) {
+ cap_t cap_d;
+ cap_flag_value_t eff_state;
+ cap_flag_value_t inh_state;
+ cap_value_t values[] = {CAP_SETGID, CAP_MAC_ADMIN};
+ int r;
+ int i;
+ int size = ARRAY_SIZE(values);
+
+ /* If Dytransition feature is enabled, CAP_MAC_ADMIN is unnecessary */
+ if (label_monitor)
+ size--;
+
+ cap_d = cap_get_file(loader);
+ if (!cap_d) {
+ _E("Failed to get cap from file(%s)", loader);
+ return -1;
+ }
+
+ for (i = 0; i < size; i++) {
+ r = cap_get_flag(cap_d, values[i], CAP_INHERITABLE, &inh_state);
+ if (r != 0) {
+ _E("Failed to get cap inh - errno(%d)", errno);
+ cap_free(cap_d);
+ return -1;
+ }
+
+ r = cap_get_flag(cap_d, values[i], CAP_EFFECTIVE, &eff_state);
+ if (r != 0) {
+ _E("Failed to get cap eff - errno(%d)", errno);
+ cap_free(cap_d);
+ return -1;
+ }
+
+ if ((inh_state != CAP_SET) || (eff_state != CAP_SET)) {
+ _E("The %s doesn't have %d cap", loader, values[i]);
+ cap_free(cap_d);
+ return -1;
+ }
+ }
+ cap_free(cap_d);
+
+ return 0;
+}
+
+static void __get_app_type_string(const launchpad::LoaderInfoPtr& info,
+ char buf[], int size) {
+ char* ptr = buf;
+
+ for (auto& app_type : info->GetAppTypes()) {
+ if (size < app_type.size() + 1)
+ return;
+
+ strncpy(ptr, app_type.c_str(), size);
+ ptr += app_type.size();
+ size -= app_type.size();
+ (*ptr++) = ' ';
+ size--;
+ }
+}
+
+static void __add_slot_from_info(const launchpad::LoaderInfoPtr& info) {
+ candidate_process_context_t* cpc;
+ bundle_raw* extra = nullptr;
+ int len;
+ char buf[2048] = {
+ 0,
+ };
+
+ // TODO(changyu.choi): slot_info will be implemented to refer to loader_info
+ slot_info_t slot_info = {
+ .type = LAUNCHPAD_LOADER_TYPE_USER + user_slot_offset,
+ .loader_name = info->GetName().c_str(),
+ .loader_path = info->GetExe().c_str(),
+ .threshold_max = info->GetCpuThresholdMax(),
+ .threshold_min = info->GetCpuThresholdMin(),
+ .app_exists = info->IsAppExists(),
+ .is_hydra = info->IsHydraEnabled(),
+ .app_check = info->IsNeededAppCheck(),
+ .on_boot_timeout = info->GetOnbootTimeout(),
+ .sched_priority = info->GetSchedPriority()
+ };
+
+ if (info->GetExe() == "null") {
+ slot_info.loader_id = PAD_LOADER_ID_DIRECT;
+
+ cpc = __add_slot(&slot_info);
+ if (cpc == nullptr)
+ return;
+
+ info->SetType(static_cast<launchpad::LoaderType>(
+ static_cast<int>(launchpad::LoaderType::User) + user_slot_offset));
+ user_slot_offset++;
+ return;
+ } else if (access(info->GetExe().c_str(), F_OK | X_OK) == 0) {
+ if (__verify_loader_caps(info->GetExe().c_str()) < 0)
+ return;
+
+ bundle_encode(info->GetExtra().GetHandle(), &extra, &len);
+
+ slot_info.loader_id = PAD_LOADER_ID_STATIC;
+ slot_info.loader_extra = (const char*)extra;
+ slot_info.detection_method = static_cast<int>(info->GetDetectionMethod());
+ slot_info.activation_method = static_cast<int>(info->GetActivationMethod());
+ slot_info.deactivation_method = static_cast<int>(info->GetDeactivationMethod());
+ slot_info.ttl = info->GetTtl();
+ slot_info.timeout_val = info->GetTimeoutVal();
+ slot_info.on_boot = info->IsOnBoot();
+
+ cpc = __add_slot(&slot_info);
+ bundle_free_encoded_rawdata(&extra);
+ if (cpc == nullptr)
+ return;
+
+ info->SetType(static_cast<launchpad::LoaderType>(
+ static_cast<int>(launchpad::LoaderType::User) + user_slot_offset));
+ user_slot_offset++;
+ __get_app_type_string(info, buf, sizeof(buf));
+ _I("candidate slot. app-type(%s) loader-type(%d)", buf,
+ static_cast<int>(info->GetType()));
+ _print_hwc_log("candidate slot. app-type(%s) loader-type(%d)", buf,
+ static_cast<int>(info->GetType()));
+ }
+}
+
+static int __add_default_slots(void) {
+ loader_info_manager =
+ std::make_unique<launchpad::LoaderInfoManager>(LOADER_INFO_PATH);
+
+ loader_info_manager->Load();
+ user_slot_offset = 0;
+ for (auto& info : loader_info_manager->GetLoaderInfoList()) {
+ __add_slot_from_info(info);
+ }
+ __add_idle_checker(0, candidate_slot_list);
+
+ return 0;
+}
+
+static void __add_app_defined_loaders(void) {
+ app_defined_loader_info_manager =
+ std::make_unique<launchpad::LoaderInfoManager>(
+ APP_DEFINED_LOADER_INFO_PATH);
+
+ app_defined_loader_info_manager->Load();
+}
+
+static bool __is_low_memory(void) {
+ if (_memory_monitor_is_low_memory())
+ return true;
+
+ if (__memory_status_low >= MEMORY_STATUS_LOW)
+ return true;
+
+ return false;
+}
+
+static void __hw_acceleration_changed_cb(keynode_t* key, void* data) {
+ __sys_hwacc = vconf_keynode_get_int(key);
+ _D("sys hwacc: %d", __sys_hwacc);
+}
+
+static void __update_lang(keynode_t* node, void* user_data) {
+ char* lang;
+
+ lang = vconf_keynode_get_str(node);
+ if (!lang) {
+ _E("Failed to get language");
+ return;
+ }
+
+ setenv("LANG", lang, 1);
+}
+
+static void __region_format_changed_cb(keynode_t* node, void* data) {
+ char* region;
+
+ region = vconf_keynode_get_str(node);
+ if (!region) {
+ _E("Failed to get value");
+ return;
+ }
+
+ setenv("LC_CTYPE", region, 1);
+}
+
+static void __memory_status_low_changed_cb(keynode_t* node, void* data) {
+ candidate_process_context_t* cpc;
+ GList* iter;
+
+ __memory_status_low = vconf_keynode_get_int(node);
+ if (__memory_status_low >= MEMORY_STATUS_LOW) {
+ _W("Low memory");
+ iter = candidate_slot_list;
+ while (iter) {
+ cpc = (candidate_process_context_t*)iter->data;
+ __update_slot_state(cpc, launchpad::LoaderMethod::OutOfMemory, false);
+ iter = g_list_next(iter);
+ }
+ }
+}
+
+static void __memory_status_normal_changed_cb(keynode_t* node, void* data) {
+ candidate_process_context_t* cpc;
+ GList* iter;
+
+ __memory_status_normal = vconf_keynode_get_int(node);
+ if (__memory_status_normal == MEMORY_STATUS_NORMAL) {
+ _W("Normal");
+ iter = candidate_slot_list;
+ while (iter) {
+ cpc = (candidate_process_context_t*)iter->data;
+ __update_slot_state(cpc, launchpad::LoaderMethod::AvailableMemory, true);
+ iter = g_list_next(iter);
+ }
+ }
+}
+
+static void __unregister_vconf_events(void) {
+ const char* key;
+ config_type_e type;
+
+ type = CONFIG_TYPE_MEMORY_STATUS_NORMAL_KEY;
+ key = _config_get_string_value(type);
+ vconf_ignore_key_changed(key, __memory_status_normal_changed_cb);
+
+ type = CONFIG_TYPE_MEMORY_STATUS_LOW_KEY;
+ key = _config_get_string_value(type);
+ vconf_ignore_key_changed(key, __memory_status_low_changed_cb);
+
+ vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT, __region_format_changed_cb);
+ vconf_ignore_key_changed(VCONFKEY_LANGSET, __update_lang);
+ vconf_ignore_key_changed(VCONFKEY_SETAPPL_APP_HW_ACCELERATION,
+ __hw_acceleration_changed_cb);
+}
+
+static int __register_vconf_events(void) {
+ int r;
+ char* lang;
+ char* region;
+ const char* key;
+ config_type_e type;
+
+ r = vconf_get_int(VCONFKEY_SETAPPL_APP_HW_ACCELERATION, &__sys_hwacc);
+ if (r != VCONF_OK)
+ _E("Failed to get vconf hw acceleration. err = %d", r);
+
+ r = vconf_notify_key_changed(VCONFKEY_SETAPPL_APP_HW_ACCELERATION,
+ __hw_acceleration_changed_cb, nullptr);
+ if (r != VCONF_OK) {
+ _E("Failed to register callback for hw acceleration. err = %d", r);
+ }
+
+ lang = vconf_get_str(VCONFKEY_LANGSET);
+ if (lang) {
+ setenv("LANG", lang, 1);
+ free(lang);
+ }
+
+ r = vconf_notify_key_changed(VCONFKEY_LANGSET, __update_lang, nullptr);
+ if (r != VCONF_OK)
+ _E("Failed to register callback for langset. err = %d", r);
+
+ region = vconf_get_str(VCONFKEY_REGIONFORMAT);
+ if (region) {
+ setenv("LC_CTYPE", region, 1);
+ free(region);
+ }
+
+ r = vconf_notify_key_changed(VCONFKEY_REGIONFORMAT,
+ __region_format_changed_cb, nullptr);
+ if (r != VCONF_OK)
+ _E("Failed to register callback for regionformat. err = %d", r);
+
+ type = CONFIG_TYPE_MEMORY_STATUS_LOW_KEY;
+ key = _config_get_string_value(type);
+ type = CONFIG_TYPE_MEMORY_STATUS_LOW_VALUE;
+ MEMORY_STATUS_LOW = _config_get_int_value(type);
+
+ r = vconf_get_int(key, &__memory_status_low);
+ if (r != VCONF_OK)
+ _E("Failed to get vconf low memory. err = %d", r);
+
+ r = vconf_notify_key_changed(key, __memory_status_low_changed_cb, nullptr);
+ if (r != 0)
+ _E("Failed to register callback for low memory. err = %d", r);
+
+ type = CONFIG_TYPE_MEMORY_STATUS_NORMAL_KEY;
+ key = _config_get_string_value(type);
+ type = CONFIG_TYPE_MEMORY_STATUS_NORMAL_VALUE;
+ MEMORY_STATUS_NORMAL = _config_get_int_value(type);
+
+ r = vconf_get_int(key, &__memory_status_normal);
+ if (r != VCONF_OK)
+ _E("Failed to get vconf normal memory. err = %d", r);
+
+ r = vconf_notify_key_changed(key, __memory_status_normal_changed_cb, nullptr);
+ if (r != 0)
+ _E("Failed to register callback for normal memory. err = %d", r);
+
+ return 0;
+}
+
+static bool __handle_logger(int fd, io_condition_e cond, void* data) {
+ app_pkt_t* pkt;
+ struct ucred cr;
+ int clifd = -1;
+
+ if (cond & (IO_ERR | IO_HUP | IO_NVAL)) {
+ _E("fd(%d), io_condition(%d)", fd, cond);
+ g_idle_add(__logger_recovery_cb, __logger_channel);
+ __logger_channel = nullptr;
+ return false;
+ }
+
+ pkt = _accept_recv_pkt_raw(fd, &clifd, &cr);
+ if (!pkt) {
+ _E("Failed to receive the packet");
+ return true;
+ }
+
+ if (getuid() != cr.uid) {
+ _E("Invalid caller");
+ goto end;
+ }
+
+ if (pkt->len <= 0) {
+ _E("Invalid message");
+ goto end;
+ }
+
+ _E("[%d] %s", cr.pid, (const char*)pkt->data);
+ _log_print("[ERROR]", "pid(%7d) | message(%s)", cr.pid,
+ (const char*)pkt->data);
+end:
+ if (clifd != -1)
+ close(clifd);
+
+ free(pkt);
+
+ return true;
+}
+
+static int __init_logger_fd(void) {
+ int fd;
+
+ fd = _create_server_sock(LAUNCHPAD_LOGGER_SOCK);
+ if (fd < 0) {
+ _E("Failed to create logger socker");
+ return -1;
+ }
+
+ auto cond = IO_IN | IO_PRI | IO_ERR | IO_HUP | IO_NVAL;
+ __logger_channel = _io_channel_create(fd, static_cast<io_condition_e>(cond),
+ __handle_logger, nullptr);
+ if (!__logger_channel) {
+ close(fd);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int __memory_monitor_cb(bool low_memory, void* user_data) {
+ candidate_process_context_t* cpc;
+
+ cpc = __get_running_slot(false);
+ if (!cpc && low_memory)
+ return -1;
+
+ if (low_memory) {
+ _W("Low memory");
+ __update_slots_pss();
+
+ candidate_slot_list = g_list_sort(candidate_slot_list, __compare_slot);
+ __pause_all_running_slots(false);
+ } else {
+ __resume_all_slots();
+ }
+
+ return 0;
+}
+
+static gboolean __logger_recovery_cb(gpointer data) {
+ auto channel = static_cast<io_channel_h>(data);
+ int ret;
+
+ _io_channel_destroy(channel);
+
+ ret = __init_logger_fd();
+ if (ret < 0) {
+ _E("Failed to recover logger socket");
+ return G_SOURCE_REMOVE;
+ }
+
+ _E("[__RECOVERY__] Logger socket");
+
+ return G_SOURCE_REMOVE;
+}
+
+static gboolean __launchpad_recovery_cb(gpointer data) {
+ auto channel = static_cast<io_channel_h>(data);
+ int ret;
+
+ _io_channel_destroy(channel);
+
+ ret = __init_launchpad_fd(0, nullptr);
+ if (ret < 0) {
+ _E("Failed to recover launchpad socket");
+ abort();
+ return G_SOURCE_REMOVE;
+ }
+
+ _E("[__RECOVERY__] Launchpad socket");
+
+ return G_SOURCE_REMOVE;
+}
+
+static int __before_loop(int argc, char** argv) {
+ __request_handlers[PAD_CMD_VISIBILITY] = __visibility_request_handler;
+ __request_handlers[PAD_CMD_ADD_LOADER] = __add_loader_request_handler;
+ __request_handlers[PAD_CMD_REMOVE_LOADER] = __remove_loader_request_handler;
+ __request_handlers[PAD_CMD_MAKE_DEFAULT_SLOTS] =
+ __make_default_slots_request_handler;
+ __request_handlers[PAD_CMD_PREPARE_APP_DEFINED_LOADER] =
+ __prepare_app_defined_loader_request_handler;
+ __request_handlers[PAD_CMD_DEMAND] = __demand_request_handler;
+ __request_handlers[PAD_CMD_PING] = __ping_request_handler;
+ __request_handlers[PAD_CMD_UPDATE_APP_TYPE] =
+ __update_app_type_request_handler;
+ __request_handlers[PAD_CMD_CONNECT] = __connect_request_handler;
+ __request_handlers[PAD_CMD_LAUNCH] = __launch_request_handler;
+
+ _print_hwc_log("%s(%d): START", __FUNCTION__, __LINE__);
+ int ret = __sequencer_init();
+ if (ret < 0) {
+ _E("Failed to initialize sequencer");
+ return -1;
+ }
+
+ ret = _signal_init();
+ if (ret < 0) {
+ _E("Failed to initialize signal");
+ return -1;
+ }
+
+ _signal_set_sigchld_cb(__handle_sigchild, nullptr);
+
+ ret = __init_launchpad_fd(argc, argv);
+ if (ret != 0) {
+ _E("__init_launchpad_fd() failed");
+ return -1;
+ }
+
+ ret = __init_logger_fd();
+ if (ret != 0) {
+ _E("__init_logger_fd() failed");
+ return -1;
+ }
+
+ ret = __init_label_monitor_fd();
+ if (ret != 0)
+ _W("Failed to initialize label monitor");
+
+ ret = _config_init();
+ if (ret != 0)
+ _W("Failed to initialize config");
+
+ ret = _dbus_init();
+ if (ret != 0)
+ _W("Failed to initialize dbus");
+
+ _inotify_init();
+
+ MAX_CPU_CHECK_COUNT =
+ _config_get_int_value(CONFIG_TYPE_CPU_CHECKER_MAX_COUNT);
+ __add_default_slots();
+
+ launchpad::LauncherInfoInflator inflator;
+ launcher_info_list = inflator.Inflate(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);
+
+ __pid_table =
+ g_hash_table_new_full(g_direct_hash, g_direct_equal, nullptr, free);
+ if (!__pid_table) {
+ _E("Failed to create pid table");
+ return -1;
+ }
+
+ ret = _worker_create("cleaner+", &__cleaner);
+ if (ret < 0)
+ return ret;
+
+ __register_vconf_events();
+ __init_app_defined_loader_monitor();
+ _memory_monitor_init();
+ _memory_monitor_set_event_cb(__memory_monitor_cb, nullptr);
+ _log_init();
+ _print_hwc_log("%s(%d): END", __FUNCTION__, __LINE__);
+
+ return 0;
+}
+
+static void __after_loop(void) {
+ _log_fini();
+ _memory_monitor_fini();
+ __unregister_vconf_events();
+ _worker_destroy(__cleaner);
+ if (__pid_table)
+ g_hash_table_destroy(__pid_table);
+
+ if (_send_cmd_to_amd(LAUNCHPAD_DEAD_SIGNAL) < 0)
+ _W("Failed to send cmd(%d) to amd", LAUNCHPAD_DEAD_SIGNAL);
+
+ _debug_fini();
+ launcher_info_list.clear();
+ _dbus_fini();
+ _config_fini();
+ _inotify_fini();
+ app_defined_loader_info_manager->Dispose();
+
+ 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);
+
+ _signal_fini();
+
+ __sequencer_fini();
+}
+
+int main(int argc, char** argv) {
+ GMainLoop* mainloop = nullptr;
+
+ _print_hwc_log("%s(%d): START", __FUNCTION__, __LINE__);
+ prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0);
+
+ mainloop = g_main_loop_new(nullptr, FALSE);
+ if (!mainloop) {
+ _E("Failed to create glib main loop");
+ return -1;
+ }
+
+ _print_hwc_log("%s(%d): __before_loop()", __FUNCTION__, __LINE__);
+ if (__before_loop(argc, argv) != 0) {
+ _E("process-pool Initialization failed!");
+ return -1;
+ }
+
+#ifdef TIZEN_FEATURE_PRIORITY_CHANGE
+ _set_priority(-12);
+#endif
+ _print_hwc_log("%s(%d): g_main_loop_run()", __FUNCTION__, __LINE__);
+ g_main_loop_run(mainloop);
+
+ __after_loop();
+
+ return -1;
+}
* limitations under the License.
*/
-#define _GNU_SOURCE
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
+++ /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 <gio/gio.h>
-#include <glib.h>
-
-#include "launchpad_dbus.h"
-#include "log_private.h"
-
-#define AUL_DBUS_PATH "/aul/dbus_handler"
-#define AUL_DBUS_SIGNAL_INTERFACE "org.tizen.aul.signal"
-#define AUL_DBUS_APPDEAD_SIGNAL "app_dead"
-#define AUL_DBUS_APPLAUNCH_SIGNAL "app_launch"
-
-#define PENDING_ITEM_INTERVAL 1000
-
-#define GET_CONNECTION_ERROR_THRESHOLD 10
-#define GET_CONNECTION_ERROR_MODULO 1000
-typedef enum {
- APP_SIGNAL_DEAD,
- APP_SIGNAL_LAUNCH,
-} app_signal_e;
-
-typedef struct pending_item_s {
- char *app_id;
- int pid;
- app_signal_e app_signal;
-} pending_item_t;
-
-static GList *__pending_items;
-static guint __timer;
-static GDBusConnection *__conn;
-
-static void __set_pending_item_timer(void);
-
-static void __destroy_pending_item(gpointer data)
-{
- pending_item_t *item = data;
-
- free(item->app_id);
- free(item);
-}
-
-static pending_item_t *__create_pending_item(const char *app_id,
- int pid, app_signal_e app_signal)
-{
- pending_item_t *item;
-
- item = calloc(1, sizeof(pending_item_t));
- if (!item) {
- _E("Out of memory");
- return NULL;
- }
-
- if (app_id) {
- item->app_id = strdup(app_id);
- if (!item->app_id) {
- _E("Failed to duplicate app ID(%s)", app_id);
- __destroy_pending_item(item);
- return NULL;
- }
- }
-
- item->pid = pid;
- item->app_signal = app_signal;
-
- return item;
-}
-
-static GDBusConnection *__get_connection(void)
-{
- GError *error = NULL;
- static unsigned int error_count = 0;
-
- if (__conn)
- return __conn;
-
- __conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
- if (!__conn) {
- error_count++;
- if (error_count < GET_CONNECTION_ERROR_THRESHOLD ||
- error_count % GET_CONNECTION_ERROR_MODULO == 0) {
- _E("g_bus_get_sync() is failed. error(%s)",
- error ? error->message : "Unknown");
- }
-
- g_clear_error(&error);
- return NULL;
- }
-
- return __conn;
-}
-
-static int __emit_signal(const char *path,
- const char *interface,
- const char *signal,
- GVariant *param)
-{
- GDBusConnection *conn;
- GError *error = NULL;
- gboolean ret;
-
- conn = __get_connection();
- if (!conn)
- return -1;
-
- ret = g_dbus_connection_emit_signal(conn,
- NULL,
- path,
- interface,
- signal,
- param,
- &error);
- if (ret != TRUE) {
- _E("g_dbus_connection_emit_signal() is failed. error(%s)",
- error ? error->message : "Unknown");
- g_clear_error(&error);
- return -1;
- }
-
- ret = g_dbus_connection_flush_sync(conn, NULL, &error);
- if (ret != TRUE) {
- _E("g_dbus_connection_flush_sync() is failed. error(%s)",
- error ? error->message : "Unknown");
- g_clear_error(&error);
- return -1;
- }
-
- return 0;
-}
-
-static int __emit_app_launch_signal(int pid, const char *app_id)
-{
- int ret;
-
- ret = __emit_signal(AUL_DBUS_PATH,
- AUL_DBUS_SIGNAL_INTERFACE,
- AUL_DBUS_APPLAUNCH_SIGNAL,
- g_variant_new("(us)", pid, app_id));
- if (ret < 0)
- return ret;
-
- _D("App launch. pid(%d), app_id(%s)", pid, app_id);
-
- return 0;
-}
-
-static int __emit_app_dead_signal(int pid)
-{
- int ret;
-
- ret = __emit_signal(AUL_DBUS_PATH,
- AUL_DBUS_SIGNAL_INTERFACE,
- AUL_DBUS_APPDEAD_SIGNAL,
- g_variant_new("(u)", pid));
- if (ret < 0)
- return ret;
-
- _D("App dead. pid(%d)", pid);
-
- return 0;
-}
-
-static gboolean __flush_pending_item(gpointer data)
-{
- pending_item_t *item;
- GList *iter;
- int ret;
-
- if (!__pending_items) {
- __timer = 0;
- return G_SOURCE_REMOVE;
- }
-
- iter = __pending_items;
- while (iter) {
- item = (pending_item_t *)iter->data;
- if (item->app_signal == APP_SIGNAL_DEAD)
- ret = __emit_app_dead_signal(item->pid);
- else
- ret = __emit_app_launch_signal(item->pid, item->app_id);
-
- if (ret < 0)
- return G_SOURCE_CONTINUE;
-
- iter = g_list_next(iter);
- __pending_items = g_list_remove(__pending_items, item);
- __destroy_pending_item(item);
- }
-
- __timer = 0;
- return G_SOURCE_REMOVE;
-}
-
-static void __set_pending_item_timer(void)
-{
- if (__timer)
- return;
-
- __timer = g_timeout_add(PENDING_ITEM_INTERVAL,
- __flush_pending_item, NULL);
-}
-
-static void __unset_pending_item_timer(void)
-{
- if (!__timer)
- return;
-
- g_source_remove(__timer);
- __timer = 0;
-}
-
-int _dbus_send_app_launch_signal(int pid, const char *app_id)
-{
- pending_item_t *item;
- int ret;
-
- if (pid <= 1 || !app_id) {
- _E("Invalid parameter");
- return -EINVAL;
- }
-
- ret = __emit_app_launch_signal(pid, app_id);
- if (ret < 0) {
- item = __create_pending_item(app_id, pid, APP_SIGNAL_LAUNCH);
- if (!item)
- return -ENOMEM;
-
- _W("Pend app launch signal. pid(%d), app_id(%s)", pid, app_id);
- __pending_items = g_list_append(__pending_items, item);
- __set_pending_item_timer();
- }
-
- return 0;
-}
-
-int _dbus_send_app_dead_signal(int pid)
-{
- pending_item_t *item;
- int ret;
-
- if (pid <= 1) {
- _E("Invalid parameter");
- return -EINVAL;
- }
-
- ret = __emit_app_dead_signal(pid);
- if (ret < 0) {
- item = __create_pending_item(NULL, pid, APP_SIGNAL_DEAD);
- if (!item)
- return -ENOMEM;
-
- _W("Pend app dead signal. pid(%d)", pid);
- __pending_items = g_list_append(__pending_items, item);
- __set_pending_item_timer();
- }
-
- return 0;
-}
-
-int _dbus_init(void)
-{
- GDBusConnection *conn;
-
- _D("DBUS_INIT");
- conn = __get_connection();
- if (!conn)
- return -1;
-
- return 0;
-}
-
-void _dbus_fini(void)
-{
- _D("DBUS_FINI");
- if (__pending_items)
- g_list_free_full(__pending_items, __destroy_pending_item);
-
- __unset_pending_item_timer();
-
- if (__conn)
- g_object_unref(__conn);
-}
--- /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.
+ */
+
+#include <gio/gio.h>
+#include <glib.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "launchpad_dbus.h"
+#include "log_private.h"
+
+#define AUL_DBUS_PATH "/aul/dbus_handler"
+#define AUL_DBUS_SIGNAL_INTERFACE "org.tizen.aul.signal"
+#define AUL_DBUS_APPDEAD_SIGNAL "app_dead"
+#define AUL_DBUS_APPLAUNCH_SIGNAL "app_launch"
+
+#define PENDING_ITEM_INTERVAL 1000
+
+#define GET_CONNECTION_ERROR_THRESHOLD 10
+#define GET_CONNECTION_ERROR_MODULO 1000
+typedef enum {
+ APP_SIGNAL_DEAD,
+ APP_SIGNAL_LAUNCH,
+} app_signal_e;
+
+typedef struct pending_item_s {
+ char* app_id;
+ int pid;
+ app_signal_e app_signal;
+} pending_item_t;
+
+static GList* __pending_items;
+static guint __timer;
+static GDBusConnection* __conn;
+
+static void __set_pending_item_timer(void);
+
+static void __destroy_pending_item(gpointer data) {
+ auto* item = static_cast<pending_item_t*>(data);
+
+ free(item->app_id);
+ free(item);
+}
+
+static pending_item_t* __create_pending_item(const char* app_id,
+ int pid,
+ app_signal_e app_signal) {
+ pending_item_t* item;
+
+ item = static_cast<pending_item_t*>(calloc(1, sizeof(pending_item_t)));
+ if (!item) {
+ _E("Out of memory");
+ return nullptr;
+ }
+
+ if (app_id) {
+ item->app_id = strdup(app_id);
+ if (!item->app_id) {
+ _E("Failed to duplicate app ID(%s)", app_id);
+ __destroy_pending_item(item);
+ return nullptr;
+ }
+ }
+
+ item->pid = pid;
+ item->app_signal = app_signal;
+
+ return item;
+}
+
+static GDBusConnection* __get_connection(void) {
+ GError* error = nullptr;
+ static unsigned int error_count = 0;
+
+ if (__conn)
+ return __conn;
+
+ __conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, &error);
+ if (!__conn) {
+ error_count++;
+ if (error_count < GET_CONNECTION_ERROR_THRESHOLD ||
+ error_count % GET_CONNECTION_ERROR_MODULO == 0) {
+ _E("g_bus_get_sync() is failed. error(%s)",
+ error ? error->message : "Unknown");
+ }
+
+ g_clear_error(&error);
+ return nullptr;
+ }
+
+ return __conn;
+}
+
+static int __emit_signal(const char* path,
+ const char* interface,
+ const char* signal,
+ GVariant* param) {
+ GDBusConnection* conn;
+ GError* error = nullptr;
+ gboolean ret;
+
+ conn = __get_connection();
+ if (!conn)
+ return -1;
+
+ ret = g_dbus_connection_emit_signal(conn, nullptr, path, interface, signal,
+ param, &error);
+ if (ret != TRUE) {
+ _E("g_dbus_connection_emit_signal() is failed. error(%s)",
+ error ? error->message : "Unknown");
+ g_clear_error(&error);
+ return -1;
+ }
+
+ ret = g_dbus_connection_flush_sync(conn, nullptr, &error);
+ if (ret != TRUE) {
+ _E("g_dbus_connection_flush_sync() is failed. error(%s)",
+ error ? error->message : "Unknown");
+ g_clear_error(&error);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int __emit_app_launch_signal(int pid, const char* app_id) {
+ int ret;
+
+ ret = __emit_signal(AUL_DBUS_PATH, AUL_DBUS_SIGNAL_INTERFACE,
+ AUL_DBUS_APPLAUNCH_SIGNAL,
+ g_variant_new("(us)", pid, app_id));
+ if (ret < 0)
+ return ret;
+
+ _D("App launch. pid(%d), app_id(%s)", pid, app_id);
+
+ return 0;
+}
+
+static int __emit_app_dead_signal(int pid) {
+ int ret;
+
+ ret = __emit_signal(AUL_DBUS_PATH, AUL_DBUS_SIGNAL_INTERFACE,
+ AUL_DBUS_APPDEAD_SIGNAL, g_variant_new("(u)", pid));
+ if (ret < 0)
+ return ret;
+
+ _D("App dead. pid(%d)", pid);
+
+ return 0;
+}
+
+static gboolean __flush_pending_item(gpointer data) {
+ pending_item_t* item;
+ GList* iter;
+ int ret;
+
+ if (!__pending_items) {
+ __timer = 0;
+ return G_SOURCE_REMOVE;
+ }
+
+ iter = __pending_items;
+ while (iter) {
+ item = (pending_item_t*)iter->data;
+ if (item->app_signal == APP_SIGNAL_DEAD)
+ ret = __emit_app_dead_signal(item->pid);
+ else
+ ret = __emit_app_launch_signal(item->pid, item->app_id);
+
+ if (ret < 0)
+ return G_SOURCE_CONTINUE;
+
+ iter = g_list_next(iter);
+ __pending_items = g_list_remove(__pending_items, item);
+ __destroy_pending_item(item);
+ }
+
+ __timer = 0;
+ return G_SOURCE_REMOVE;
+}
+
+static void __set_pending_item_timer(void) {
+ if (__timer)
+ return;
+
+ __timer = g_timeout_add(PENDING_ITEM_INTERVAL, __flush_pending_item, nullptr);
+}
+
+static void __unset_pending_item_timer(void) {
+ if (!__timer)
+ return;
+
+ g_source_remove(__timer);
+ __timer = 0;
+}
+
+int _dbus_send_app_launch_signal(int pid, const char* app_id) {
+ pending_item_t* item;
+ int ret;
+
+ if (pid <= 1 || !app_id) {
+ _E("Invalid parameter");
+ return -EINVAL;
+ }
+
+ ret = __emit_app_launch_signal(pid, app_id);
+ if (ret < 0) {
+ item = __create_pending_item(app_id, pid, APP_SIGNAL_LAUNCH);
+ if (!item)
+ return -ENOMEM;
+
+ _W("Pend app launch signal. pid(%d), app_id(%s)", pid, app_id);
+ __pending_items = g_list_append(__pending_items, item);
+ __set_pending_item_timer();
+ }
+
+ return 0;
+}
+
+int _dbus_send_app_dead_signal(int pid) {
+ pending_item_t* item;
+ int ret;
+
+ if (pid <= 1) {
+ _E("Invalid parameter");
+ return -EINVAL;
+ }
+
+ ret = __emit_app_dead_signal(pid);
+ if (ret < 0) {
+ item = __create_pending_item(nullptr, pid, APP_SIGNAL_DEAD);
+ if (!item)
+ return -ENOMEM;
+
+ _W("Pend app dead signal. pid(%d)", pid);
+ __pending_items = g_list_append(__pending_items, item);
+ __set_pending_item_timer();
+ }
+
+ return 0;
+}
+
+int _dbus_init(void) {
+ GDBusConnection* conn;
+
+ _D("DBUS_INIT");
+ conn = __get_connection();
+ if (!conn)
+ return -1;
+
+ return 0;
+}
+
+void _dbus_fini(void) {
+ _D("DBUS_FINI");
+ if (__pending_items)
+ g_list_free_full(__pending_items, __destroy_pending_item);
+
+ __unset_pending_item_timer();
+
+ if (__conn)
+ g_object_unref(__conn);
+}
+++ /dev/null
-/*
- * Copyright (c) 2016 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 <linux/limits.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <bundle_internal.h>
-#include <ctype.h>
-
-#include "debugger_info.h"
-#include "key.h"
-#include "launchpad_common.h"
-#include "launchpad_debug.h"
-#include "launchpad_types.h"
-
-#define DEBUGGER_INFO_PATH "/usr/share/aul"
-
-static int __debug_initialized;
-static GList *__debugger_info_list;
-static debugger_info_h __debugger_info;
-static GList *__debug_argv_list;
-static GList *__extra_argv_list;
-
-int _debug_change_mount_namespace(void)
-{
- const char *pid_str;
- char buf[PATH_MAX];
- int ret;
- int fd;
-
- pid_str = getenv("TARGET_PID");
- if (pid_str == NULL)
- return 0;
-
- snprintf(buf, sizeof(buf), "/proc/%s/ns/mnt", pid_str);
- fd = open(buf, O_RDONLY);
- if (fd < 0) {
- _E("open() is failed. path(%s), errno(%d)", buf, errno);
- return -1;
- }
-
- ret = setns(fd, CLONE_NEWNS);
- close(fd);
- if (ret != 0)
- _E("setns() is failed. errno(%d)", errno);
-
- return ret;
-}
-
-int _debug_create_extra_argv(int *argc, char ***argv)
-{
- int new_argc;
- char **new_argv;
- const char *extra_argv;
- GList *iter;
- int i;
-
- if (argc == NULL || argv == NULL) {
- _E("[DEBUG] Invalid parameter");
- return -1;
- }
-
- if (__debugger_info == NULL)
- return 0;
-
- new_argc = g_list_length(__extra_argv_list);
- if (new_argc == 0)
- return 0;
-
- new_argv = (char **)calloc(new_argc, sizeof(char *));
- if (new_argv == NULL) {
- _E("out of memory");
- return -1;
- }
-
- i = LOADER_ARG_PATH;
- iter = g_list_first(__extra_argv_list);
- while (iter) {
- extra_argv = (const char *)iter->data;
- if (extra_argv)
- new_argv[i++] = strdup(extra_argv);
-
- iter = g_list_next(iter);
- }
-
- *argc = new_argc;
- *argv = new_argv;
- _D("[DEBUG] argc: %d, i: %d", *argc, i);
-
- return 0;
-}
-
-int _debug_create_argv(int *argc, char ***argv, bool *attach)
-{
- int new_argc = 0;
- char **new_argv;
- const char *exe;
- const char *debug_argv;
- const char *attach_str;
- GList *iter;
- GList *list;
- int i;
-
- if (argc == NULL || argv == NULL || attach == NULL) {
- _E("[DEBUG] Invalid parameter");
- return -1;
- }
-
- if (__debugger_info == NULL)
- return 0;
-
- exe = _debugger_info_get_exe(__debugger_info);
- if (exe == NULL)
- return 0;
-
- attach_str = _debugger_info_get_attach(__debugger_info);
- if (attach_str && strcasecmp(attach_str, "true") == 0) {
- *attach = true;
- new_argc++;
- }
-
- list = _debugger_info_get_default_opt_list(__debugger_info);
- new_argc += g_list_length(__debug_argv_list) + g_list_length(list) + 1;
- new_argv = (char **)calloc(new_argc, sizeof(char *));
- if (new_argv == NULL) {
- _E("out of memory");
- return -1;
- }
-
- i = LOADER_ARG_PATH;
- new_argv[i++] = strdup(exe);
-
- iter = g_list_first(list);
- while (iter) {
- debug_argv = (const char *)iter->data;
- if (debug_argv)
- new_argv[i++] = strdup(debug_argv);
-
- iter = g_list_next(iter);
- }
-
- iter = g_list_first(__debug_argv_list);
- while (iter) {
- debug_argv = (const char *)iter->data;
- if (debug_argv)
- new_argv[i++] = strdup(debug_argv);
-
- iter = g_list_next(iter);
- }
-
- *argc = new_argc;
- *argv = new_argv;
- _D("[DEBUG] argc: %d, argv[0]: %s",
- new_argc, new_argv[LOADER_ARG_PATH]);
-
- return 0;
-}
-
-void _debug_destroy_argv(int argc, char **argv)
-{
- int i;
-
- if (argv == NULL)
- return;
-
- for (i = 0; i < argc; i++)
- free(argv[i]);
- free(argv);
-}
-
-int _debug_get_caller_pid(bundle *kb)
-{
- const char *pid_str;
- int pid;
-
- pid_str = bundle_get_val(kb, AUL_K_ORG_CALLER_PID);
- if (pid_str == NULL)
- pid_str = bundle_get_val(kb, AUL_K_CALLER_PID);
-
- if (pid_str == NULL)
- return -1;
-
- pid = atoi(pid_str);
- if (pid <= 1)
- return -1;
-
- return pid;
-}
-
-static int __redirect_std_fds(bundle *kb)
-{
- char path[PATH_MAX];
- char err_buf[1024];
- int fd;
- int caller_pid;
-
- if (kb == NULL) {
- _E("[DEBUG] Invalid parameter");
- return -1;
- }
-
- caller_pid = _debug_get_caller_pid(kb);
- if (caller_pid < 0) {
- _E("[DEBUG] Failed to get caller pid");
- return -1;
- }
-
- /* stdin */
- snprintf(path, sizeof(path), "/proc/%d/fd/0", caller_pid);
- fd = open(path, O_RDONLY);
- if (fd < 0) {
- _E("[DEBUG] Failed to open %s [%s]", path,
- strerror_r(errno, err_buf, sizeof(err_buf)));
- return -1;
- }
- dup2(fd, 0);
- close(fd);
-
- /* stdout */
- snprintf(path, sizeof(path), "/proc/%d/fd/1", caller_pid);
- fd = open(path, O_WRONLY);
- if (fd < 0) {
- _E("[DEBUG] Failed to open %s [%s]", path,
- strerror_r(errno, err_buf, sizeof(err_buf)));
- return -1;
- }
- dup2(fd, 1);
- close(fd);
-
- /* stderr */
- snprintf(path, sizeof(path), "/proc/%d/fd/2", caller_pid);
- fd = open(path, O_WRONLY);
- if (fd < 0) {
- _E("[DEBUG] Failed to open %s [%s]", path,
- strerror_r(errno, err_buf, sizeof(err_buf)));
- return -1;
- }
- dup2(fd, 2);
- close(fd);
-
- return 0;
-}
-
-static void __add_extra_argv(gpointer data, gpointer user_data)
-{
- const char *key = (const char *)data;
- bundle *kb = (bundle *)user_data;
- const char *str;
- const char **str_arr = NULL;
- int len = 0;
- int i;
-
- if (key == NULL || kb == NULL)
- return;
-
- _D("[DEBUG] key: %s", key);
- if (bundle_get_type(kb, key) & BUNDLE_TYPE_ARRAY) {
- str_arr = bundle_get_str_array(kb, key, &len);
- } else {
- str = bundle_get_val(kb, key);
- if (str) {
- str_arr = &str;
- len = 1;
- }
- }
-
- for (i = 0; i < len; i++) {
- if (str_arr[i] == NULL)
- break;
-
- __extra_argv_list = g_list_append(__extra_argv_list,
- strdup(str_arr[i]));
- }
-
- if (str_arr)
- bundle_del(kb, key);
-}
-
-static void __add_debug_argv(gpointer data, gpointer user_data)
-{
- const char *key = (const char *)data;
- bundle *kb = (bundle *)user_data;
- const char *str;
- const char **str_arr = NULL;
- int len = 0;
- int i;
-
- if (key == NULL || kb == NULL)
- return;
-
- _D("[DEBUG] key: %s", key);
- if (bundle_get_type(kb, key) & BUNDLE_TYPE_ARRAY) {
- str_arr = bundle_get_str_array(kb, key, &len);
- } else {
- str = bundle_get_val(kb, key);
- if (str) {
- str_arr = &str;
- len = 1;
- }
- }
-
- for (i = 0; i < len; i++) {
- if (str_arr[i] == NULL)
- break;
-
- __debug_argv_list = g_list_append(__debug_argv_list,
- strdup(str_arr[i]));
- if (!strcmp(key, "__DLP_ATTACH_ARG__")) {
- if (isdigit(str_arr[i][0])) {
- _D("Target PID: %s", str_arr[i]);
- setenv("TARGET_PID", str_arr[i], 1);
- }
- }
- }
-
- if (str_arr)
- bundle_del(kb, key);
-}
-
-static void __set_debug_env(gpointer data, gpointer user_data)
-{
- const char *key = (const char *)data;
- bundle *kb = (bundle *)user_data;
- const char *str;
- const char **str_arr = NULL;
- int len = 0;
- int i;
- char buf[LINE_MAX] = {0,};
-
- if (key == NULL || kb == NULL)
- return;
-
- _D("[DEBUG] key: %s", key);
- if (bundle_get_type(kb, key) & BUNDLE_TYPE_ARRAY) {
- str_arr = bundle_get_str_array(kb, key, &len);
- } else {
- str = bundle_get_val(kb, key);
- if (str) {
- str_arr = &str;
- len = 1;
- }
- }
-
- if (str_arr == NULL)
- return;
-
- strncat(buf, str_arr[0], sizeof(buf) - strlen(buf) - 1);
- for (i = 1; i < len; i++) {
- if (str_arr[i] == NULL)
- break;
-
- strncat(buf, ",", sizeof(buf) - strlen(buf) - 1);
- strncat(buf, str_arr[i], sizeof(buf) - strlen(buf) - 1);
- }
-
- bundle_del(kb, key);
- _D("[DEBUG] name: %s, value: %s", key, buf);
- setenv(key, buf, 1);
-}
-
-static void __remove_file(gpointer data, gpointer user_data)
-{
- const char *file = (const char *)data;
-
- if (file == NULL)
- return;
-
- _D("[DEBUG] file: %s", file);
- if (access(file, F_OK) == 0) {
- if (remove(file) != 0)
- _W("[DEBUG] Failed to remove %s", file);
- }
-}
-
-void _debug_prepare_debugger(bundle *kb)
-{
- const char *debugger;
- GList *list;
- int ret;
-
- if (kb == NULL)
- return;
-
- debugger = bundle_get_val(kb, AUL_K_SDK);
- if (debugger == NULL)
- return;
-
- if (!strcmp(debugger, "ASAN"))
- setenv("TIZEN_ASAN_ACTIVATION", "1", 1);
-
- ret = __redirect_std_fds(kb);
- if (ret < 0)
- _E("[DEBUG] Failed to redirect standard fds");
-
- _D("[DEBUG] debugger: %s", debugger);
- __debugger_info = _debugger_info_find(__debugger_info_list, debugger);
- if (__debugger_info == NULL)
- return;
-
- list = _debugger_info_get_unlink_list(__debugger_info);
- g_list_foreach(list, __remove_file, NULL);
-
- list = _debugger_info_get_extra_env_list(__debugger_info);
- g_list_foreach(list, __set_debug_env, kb);
-
- list = _debugger_info_get_extra_key_list(__debugger_info);
- g_list_foreach(list, __add_debug_argv, kb);
-
- list = _debugger_info_get_last_extra_key_list(__debugger_info);
- g_list_foreach(list, __add_extra_argv, kb);
-}
-
-int _debug_init(void)
-{
- if (__debug_initialized)
- return 0;
-
- __debugger_info_list = _debugger_info_load(DEBUGGER_INFO_PATH);
- if (__debugger_info_list == NULL)
- return -1;
-
- __debug_initialized = 1;
-
- return 0;
-}
-
-void _debug_fini(void)
-{
- if (!__debug_initialized)
- return;
-
- _debugger_info_unload(__debugger_info_list);
-}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.
+ */
+
+#include <bundle_internal.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <linux/limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <algorithm>
+
+#include "debugger_info.hh"
+#include "key.h"
+#include "launchpad_common.h"
+#include "launchpad_debug.h"
+#include "launchpad_types.h"
+
+#define DEBUGGER_INFO_PATH "/usr/share/aul"
+
+namespace {
+
+int __debug_initialized;
+std::vector<launchpad::DebuggerInfoPtr> __debugger_info_list;
+launchpad::DebuggerInfoPtr __debugger_info;
+std::vector<std::string> __debug_argv_list;
+std::vector<std::string> __extra_argv_list;
+
+} // namespace
+
+int _debug_change_mount_namespace(void) {
+ const char* pid_str;
+ char buf[PATH_MAX];
+ int ret;
+ int fd;
+
+ pid_str = getenv("TARGET_PID");
+ if (pid_str == nullptr)
+ return 0;
+
+ snprintf(buf, sizeof(buf), "/proc/%s/ns/mnt", pid_str);
+ fd = open(buf, O_RDONLY);
+ if (fd < 0) {
+ _E("open() is failed. path(%s), errno(%d)", buf, errno);
+ return -1;
+ }
+
+ ret = setns(fd, CLONE_NEWNS);
+ close(fd);
+ if (ret != 0)
+ _E("setns() is failed. errno(%d)", errno);
+
+ return ret;
+}
+
+int _debug_create_extra_argv(int* argc, char*** argv) {
+ int new_argc;
+ char** new_argv;
+ int i;
+
+ if (argc == nullptr || argv == nullptr) {
+ _E("[DEBUG] Invalid parameter");
+ return -1;
+ }
+
+ if (__debugger_info == nullptr)
+ return 0;
+
+ new_argc = __extra_argv_list.size();
+ if (new_argc == 0)
+ return 0;
+
+ new_argv = static_cast<char**>(calloc(new_argc, sizeof(char*)));
+ if (new_argv == nullptr) {
+ _E("out of memory");
+ return -1;
+ }
+
+ i = LOADER_ARG_PATH;
+ for (auto& argv : __extra_argv_list) {
+ new_argv[i++] = strdup(argv.c_str());
+ }
+
+ *argc = new_argc;
+ *argv = new_argv;
+ _D("[DEBUG] argc: %d, i: %d", *argc, i);
+
+ return 0;
+}
+
+int _debug_create_argv(int* argc, char*** argv, bool* attach) {
+ int new_argc = 0;
+ char** new_argv;
+ const char* exe;
+ const char* attach_str;
+ int i;
+
+ if (argc == nullptr || argv == nullptr || attach == nullptr) {
+ _E("[DEBUG] Invalid parameter");
+ return -1;
+ }
+
+ if (__debugger_info == nullptr)
+ return 0;
+
+ exe = __debugger_info->GetExe().data();
+ if (exe == nullptr)
+ return 0;
+
+ attach_str = __debugger_info->GetAttachInfo().c_str();
+ if (attach_str && strcasecmp(attach_str, "true") == 0) {
+ *attach = true;
+ new_argc++;
+ }
+
+ auto list = __debugger_info->GetDefaultOptList();
+ new_argc += __debug_argv_list.size() + list.size() + 1;
+ new_argv = static_cast<char**>(calloc(new_argc, sizeof(char*)));
+ if (new_argv == nullptr) {
+ _E("out of memory");
+ return -1;
+ }
+
+ i = LOADER_ARG_PATH;
+ new_argv[i++] = strdup(exe);
+
+ for (auto& debug_argv : list) {
+ new_argv[i++] = strdup(debug_argv.c_str());
+ }
+
+ for (auto& debug_argv : __debug_argv_list) {
+ new_argv[i++] = strdup(debug_argv.c_str());
+ }
+
+ *argc = new_argc;
+ *argv = new_argv;
+ _D("[DEBUG] argc: %d, argv[0]: %s", new_argc, new_argv[LOADER_ARG_PATH]);
+
+ return 0;
+}
+
+void _debug_destroy_argv(int argc, char** argv) {
+ int i;
+
+ if (argv == nullptr)
+ return;
+
+ for (i = 0; i < argc; i++)
+ free(argv[i]);
+ free(argv);
+}
+
+int _debug_get_caller_pid(bundle* kb) {
+ const char* pid_str;
+ int pid;
+
+ pid_str = bundle_get_val(kb, AUL_K_ORG_CALLER_PID);
+ if (pid_str == nullptr)
+ pid_str = bundle_get_val(kb, AUL_K_CALLER_PID);
+
+ if (pid_str == nullptr)
+ return -1;
+
+ pid = atoi(pid_str);
+ if (pid <= 1)
+ return -1;
+
+ return pid;
+}
+
+static int __redirect_std_fds(bundle* kb) {
+ char path[PATH_MAX];
+ char err_buf[1024];
+ int fd;
+ int caller_pid;
+
+ if (kb == nullptr) {
+ _E("[DEBUG] Invalid parameter");
+ return -1;
+ }
+
+ caller_pid = _debug_get_caller_pid(kb);
+ if (caller_pid < 0) {
+ _E("[DEBUG] Failed to get caller pid");
+ return -1;
+ }
+
+ /* stdin */
+ snprintf(path, sizeof(path), "/proc/%d/fd/0", caller_pid);
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ _E("[DEBUG] Failed to open %s [%s]", path,
+ strerror_r(errno, err_buf, sizeof(err_buf)));
+ return -1;
+ }
+ dup2(fd, 0);
+ close(fd);
+
+ /* stdout */
+ snprintf(path, sizeof(path), "/proc/%d/fd/1", caller_pid);
+ fd = open(path, O_WRONLY);
+ if (fd < 0) {
+ _E("[DEBUG] Failed to open %s [%s]", path,
+ strerror_r(errno, err_buf, sizeof(err_buf)));
+ return -1;
+ }
+ dup2(fd, 1);
+ close(fd);
+
+ /* stderr */
+ snprintf(path, sizeof(path), "/proc/%d/fd/2", caller_pid);
+ fd = open(path, O_WRONLY);
+ if (fd < 0) {
+ _E("[DEBUG] Failed to open %s [%s]", path,
+ strerror_r(errno, err_buf, sizeof(err_buf)));
+ return -1;
+ }
+ dup2(fd, 2);
+ close(fd);
+
+ return 0;
+}
+
+static void __add_extra_argv(const std::string& key, bundle* kb) {
+ const char* str;
+ const char** str_arr = nullptr;
+ int len = 0;
+ int i;
+
+ _D("[DEBUG] key: %s", key.c_str());
+ if (bundle_get_type(kb, key.c_str()) & BUNDLE_TYPE_ARRAY) {
+ str_arr = bundle_get_str_array(kb, key.c_str(), &len);
+ } else {
+ str = bundle_get_val(kb, key.c_str());
+ if (str) {
+ str_arr = &str;
+ len = 1;
+ }
+ }
+
+ for (i = 0; i < len; i++) {
+ if (str_arr[i] == nullptr)
+ break;
+
+ __extra_argv_list.push_back(str_arr[i]);
+ }
+
+ if (str_arr)
+ bundle_del(kb, key.c_str());
+}
+
+static void __add_debug_argv(const std::string& key, bundle* kb) {
+ const char* str;
+ const char** str_arr = nullptr;
+ int len = 0;
+ int i;
+
+ _D("[DEBUG] key: %s", key.c_str());
+ if (bundle_get_type(kb, key.c_str()) & BUNDLE_TYPE_ARRAY) {
+ str_arr = bundle_get_str_array(kb, key.c_str(), &len);
+ } else {
+ str = bundle_get_val(kb, key.c_str());
+ if (str) {
+ str_arr = &str;
+ len = 1;
+ }
+ }
+
+ for (i = 0; i < len; i++) {
+ if (str_arr[i] == nullptr)
+ break;
+
+ __debug_argv_list.push_back(str_arr[i]);
+ if (!strcmp(key.c_str(), "__DLP_ATTACH_ARG__")) {
+ if (isdigit(str_arr[i][0])) {
+ _D("Target PID: %s", str_arr[i]);
+ setenv("TARGET_PID", str_arr[i], 1);
+ }
+ }
+ }
+
+ if (str_arr)
+ bundle_del(kb, key.c_str());
+}
+
+static void __set_debug_env(const std::string& key, bundle* kb) {
+ const char* str;
+ const char** str_arr = nullptr;
+ int len = 0;
+ int i;
+ char buf[LINE_MAX] = {
+ 0,
+ };
+
+ _D("[DEBUG] key: %s", key.c_str());
+ if (bundle_get_type(kb, key.c_str()) & BUNDLE_TYPE_ARRAY) {
+ str_arr = bundle_get_str_array(kb, key.c_str(), &len);
+ } else {
+ str = bundle_get_val(kb, key.c_str());
+ if (str) {
+ str_arr = &str;
+ len = 1;
+ }
+ }
+
+ if (str_arr == nullptr)
+ return;
+
+ strncat(buf, str_arr[0], sizeof(buf) - strlen(buf) - 1);
+ for (i = 1; i < len; i++) {
+ if (str_arr[i] == nullptr)
+ break;
+
+ strncat(buf, ",", sizeof(buf) - strlen(buf) - 1);
+ strncat(buf, str_arr[i], sizeof(buf) - strlen(buf) - 1);
+ }
+
+ bundle_del(kb, key.c_str());
+ _D("[DEBUG] name: %s, value: %s", key.c_str(), buf);
+ setenv(key.c_str(), buf, 1);
+}
+
+static void __remove_file(const std::string& file) {
+ _D("[DEBUG] file: %s", file.c_str());
+ if (access(file.c_str(), F_OK) == 0) {
+ if (remove(file.c_str()) != 0)
+ _W("[DEBUG] Failed to remove %s", file.c_str());
+ }
+}
+
+void _debug_prepare_debugger(bundle* kb) {
+ const char* debugger;
+ int ret;
+
+ if (kb == nullptr)
+ return;
+
+ debugger = bundle_get_val(kb, AUL_K_SDK);
+ if (debugger == nullptr)
+ return;
+
+ if (!strcmp(debugger, "ASAN"))
+ setenv("TIZEN_ASAN_ACTIVATION", "1", 1);
+
+ ret = __redirect_std_fds(kb);
+ if (ret < 0)
+ _E("[DEBUG] Failed to redirect standard fds");
+
+ _D("[DEBUG] debugger: %s", debugger);
+ auto it =
+ std::find_if(__debugger_info_list.begin(), __debugger_info_list.end(),
+ [&](const launchpad::DebuggerInfoPtr& info) -> bool {
+ return strcasecmp(info->GetExe().c_str(), debugger) == 0;
+ });
+ if (it == __debugger_info_list.end())
+ return;
+
+ __debugger_info = *it;
+ for (auto& unlink_file : __debugger_info->GetUnlinkList()) {
+ __remove_file(unlink_file);
+ }
+
+ for (auto& extra_env : __debugger_info->GetExtraEnvList()) {
+ __set_debug_env(extra_env, kb);
+ }
+
+ for (auto& extra_key : __debugger_info->GetExtraKeyList()) {
+ __add_debug_argv(extra_key, kb);
+ }
+
+ for (auto& last_extra_key : __debugger_info->GetLastExtraKeyList()) {
+ __add_extra_argv(last_extra_key, kb);
+ }
+}
+
+int _debug_init(void) {
+ if (__debug_initialized)
+ return 0;
+
+ launchpad::DebuggerInfoInflator inflator;
+ __debugger_info_list = inflator.Inflate(DEBUGGER_INFO_PATH);
+ if (__debugger_info_list.empty())
+ return -1;
+
+ __debug_initialized = 1;
+
+ return 0;
+}
+
+void _debug_fini(void) {
+ if (!__debug_initialized)
+ return;
+
+ __debugger_info_list.clear();
+}
+++ /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);
-}
--- /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.
+ */
+
+#include <gio/gio.h>
+#include <glib.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/inotify.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;
+ auto* info = static_cast<inotify_watch_info_s*>(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 == nullptr)
+ 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) {
+ auto cond = G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP;
+ struct inotify_watch_info_s* info;
+
+ info = static_cast<inotify_watch_info_s*>(
+ calloc(1, sizeof(inotify_watch_info_s)));
+ if (info == nullptr) {
+ _E("Out of memory");
+ return nullptr;
+ }
+
+ 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 nullptr;
+ }
+
+ 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 nullptr;
+ }
+
+ 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 nullptr;
+ }
+
+ info->tag = g_io_add_watch(info->io, static_cast<GIOCondition>(cond),
+ __inotify_cb, info);
+ if (!info->tag) {
+ _E("g_io_add_watch() is failed");
+ __destroy_inotify_watch_info(info);
+ return nullptr;
+ }
+
+ 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 == nullptr || callback == nullptr) {
+ _E("Invalid parameter");
+ return -1;
+ }
+
+ info = __create_inotify_watch_info(path, mask, callback, data);
+ if (info == nullptr)
+ return -1;
+
+ __watch_list = g_list_append(__watch_list, info);
+
+ return 0;
+}
+
+void _inotify_rm_watch(inotify_watch_info_h handle) {
+ if (handle == nullptr)
+ 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);
+}
+++ /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;
- bool do_close;
- 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);
- int fd = g_io_channel_unix_get_fd(source);
-
- if (!channel->callback(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->do_close = true;
- 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->do_close && channel->fd > 0)
- close(channel->fd);
-
- free(channel);
-}
-
-int _io_channel_set_close_on_destroy(io_channel_h channel, bool do_close)
-{
- if (!channel) {
- _E("Invalid parameter");
- return -EINVAL;
- }
-
- channel->do_close = do_close;
-
- return 0;
-}
--- /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.
+ */
+
+#include <gio/gio.h>
+#include <glib.h>
+#include <stdio.h>
+#include <stdlib.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;
+ bool do_close;
+ 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) {
+ int 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 static_cast<io_condition_e>(condition);
+}
+
+static GIOCondition __convert_io_condition(io_condition_e cond) {
+ int 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 static_cast<GIOCondition>(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);
+ int fd = g_io_channel_unix_get_fd(source);
+
+ if (!channel->callback(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 nullptr;
+ }
+
+ channel = static_cast<io_channel_s*>(calloc(1, sizeof(io_channel_s)));
+ if (!channel) {
+ _E("Out of memory");
+ return nullptr;
+ }
+
+ channel->io = g_io_channel_unix_new(fd);
+ if (!channel->io) {
+ _E("Failed to create GIOChannel");
+ _io_channel_destroy(channel);
+ return nullptr;
+ }
+
+ 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 nullptr;
+ }
+
+ channel->do_close = true;
+ 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->do_close && channel->fd > 0)
+ close(channel->fd);
+
+ free(channel);
+}
+
+int _io_channel_set_close_on_destroy(io_channel_h channel, bool do_close) {
+ if (!channel) {
+ _E("Invalid parameter");
+ return -EINVAL;
+ }
+
+ channel->do_close = do_close;
+
+ return 0;
+}
* limitations under the License.
*/
-#define _GNU_SOURCE
+#include <linux/limits.h>
#include <stdarg.h>
#include <stdio.h>
-#include <linux/limits.h>
#include "launchpad_config.h"
#include "launchpad_log.h"
static logger_h __logger;
-int _log_print(const char *tag, const char *format, ...)
-{
- char formatted_buf[LAUNCHPAD_LOG_MAX_STRING_SIZE];
- va_list ap;
- int ret;
+int _log_print(const char* tag, const char* format, ...) {
+ char formatted_buf[LAUNCHPAD_LOG_MAX_STRING_SIZE];
+ va_list ap;
+ int ret;
- if (!__logger)
- return 0;
+ if (!__logger)
+ return 0;
- va_start(ap, format);
- ret = vsnprintf(formatted_buf, sizeof(formatted_buf), format, ap);
- va_end(ap);
- if (ret < 0 || ret >= sizeof(formatted_buf)) {
- _E("vsnprintf() is failed. result(%d)", ret);
- return -1;
- }
+ va_start(ap, format);
+ ret = vsnprintf(formatted_buf, sizeof(formatted_buf), format, ap);
+ va_end(ap);
+ if (ret < 0 || ret >= sizeof(formatted_buf)) {
+ _E("vsnprintf() is failed. result(%d)", ret);
+ return -1;
+ }
- return _logger_print(__logger, tag, formatted_buf);
+ return _logger_print(__logger, tag, formatted_buf);
}
-int _log_init(void)
-{
- char path[PATH_MAX];
- int ret;
+int _log_init(void) {
+ char path[PATH_MAX];
+ int ret;
- _W("LOG_INIT");
- snprintf(path, sizeof(path), "%s/launchpad/launchpad.log",
- _config_get_string_value(CONFIG_TYPE_LOGGER_PATH));
- ret = _logger_create(path, &__logger);
- if (ret != 0) {
- _E("Failed to create log file. error(%d)", ret);
- return ret;
- }
+ _W("LOG_INIT");
+ snprintf(path, sizeof(path), "%s/launchpad/launchpad.log",
+ _config_get_string_value(CONFIG_TYPE_LOGGER_PATH));
+ ret = _logger_create(path, &__logger);
+ if (ret != 0) {
+ _E("Failed to create log file. error(%d)", ret);
+ return ret;
+ }
- return 0;
+ return 0;
}
-void _log_fini(void)
-{
- _W("LOG_FINI");
+void _log_fini(void) {
+ _W("LOG_FINI");
- if (__logger)
- _logger_destroy(__logger);
+ if (__logger)
+ _logger_destroy(__logger);
}
+++ /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 <errno.h>
-#include <fcntl.h>
-#include <grp.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/smack.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <time.h>
-#include <unistd.h>
-#include <linux/limits.h>
-
-#include "launchpad_config.h"
-#include "launchpad_logger.h"
-#include "log_private.h"
-
-#define LAUNCHPAD_LOG_APPFW_PATH "/var/log/appfw"
-#define LAUNCHPAD_LOG_PATH "/var/log/appfw/launchpad"
-#define LAUNCHPAD_LOG_MAX_SIZE 2500
-#define LAUNCHPAD_LOG_MAX_BUFFER_SIZE 256
-
-struct logger_s {
- int fd;
- int index;
-};
-
-static int __set_smack_label(const char *path, const char *label)
-{
- int ret;
-
- ret = smack_setlabel(path, label, SMACK_LABEL_ACCESS);
- if (ret != 0) {
- ret = -errno;
- _E("smack_setlabel() is failed. path(%s), label(%s), errno(%d)",
- path, label, errno);
- return ret;
- }
-
- return 0;
-}
-
-static int __create_directory(const char *path)
-{
- mode_t mode;
- int ret;
-
- ret = access(path, F_OK);
- if (ret == 0)
- return 0;
-
- mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP;
- ret = mkdir(path, mode);
- if (ret < 0) {
- ret = -errno;
- _E("Failed to create directory(%s). errno(%d)", path, errno);
- return ret;
- }
-
- return 0;
-}
-
-static int __create_launchpad_directories(void)
-{
- const char *logger_path;
- char path[PATH_MAX];
- int ret;
-
- logger_path = _config_get_string_value(CONFIG_TYPE_LOGGER_PATH);
- ret = __create_directory(logger_path);
- if (ret < 0)
- return ret;
-
- ret = __set_smack_label(logger_path, "User::Home");
- if (ret < 0)
- return ret;
-
- snprintf(path, sizeof(path), "%s/launchpad", logger_path);
- ret = __create_directory(path);
- if (ret < 0)
- return ret;
-
- ret = __set_smack_label(path, "User");
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-int _logger_create(const char *path, logger_h *handle)
-{
- struct logger_s *logger;
- off_t offset;
- int ret;
-
- if (!_config_get_int_value(CONFIG_TYPE_LOGGER_ENABLE))
- return 0;
-
- if (!path || !handle) {
- _E("Invalid parameter");
- return -EINVAL;
- }
-
- ret = __create_launchpad_directories();
- if (ret < 0)
- return ret;
-
- logger = calloc(1, sizeof(struct logger_s));
- if (!logger) {
- _E("Out of memory");
- return -ENOMEM;
- }
-
- logger->fd = open(path, O_CREAT | O_WRONLY, 0640);
- if (logger->fd < 0) {
- ret = -errno;
- _E("Failed to open path(%s), errno(%d)", path, errno);
- _logger_destroy(logger);
- return ret;
- }
-
- ret = __set_smack_label(path, "User");
- if (ret < 0) {
- _logger_destroy(logger);
- return ret;
- }
-
- offset = lseek(logger->fd, 0, SEEK_END);
- if (offset != 0) {
- logger->index = (int)(offset / LAUNCHPAD_LOG_MAX_STRING_SIZE);
- if (logger->index >= LAUNCHPAD_LOG_MAX_SIZE) {
- logger->index = 0;
- lseek(logger->fd, 0, SEEK_SET);
- }
- }
-
- *handle = logger;
-
- return 0;
-}
-
-int _logger_destroy(logger_h handle)
-{
- if (!_config_get_int_value(CONFIG_TYPE_LOGGER_ENABLE))
- return 0;
-
- if (!handle) {
- _E("Invalid parameter");
- return -EINVAL;
- }
-
- if (handle->fd > 0)
- close(handle->fd);
-
- free(handle);
-
- return 0;
-}
-
-int _logger_print(logger_h handle, const char *tag, const char *format, ...)
-{
- char buf[LAUNCHPAD_LOG_MAX_BUFFER_SIZE];
- char format_buf[128];
- struct tm tm = { 0, };
- time_t t;
- ssize_t ret;
- va_list ap;
- off_t offset;
- int bytes;
-
- if (!_config_get_int_value(CONFIG_TYPE_LOGGER_ENABLE))
- return 0;
-
- if (!handle || !tag || !format) {
- _E("Invalid parameter");
- return -EINVAL;
- }
-
- t = time(NULL);
- localtime_r(&t, &tm);
-
- if (handle->index != 0)
- offset = lseek(handle->fd, 0, SEEK_CUR);
- else
- offset = lseek(handle->fd, 0, SEEK_SET);
-
- if (offset == -1)
- _E("lseek() is failed. errno(%d)", errno);
-
- va_start(ap, format);
- bytes = vsnprintf(format_buf, sizeof(format_buf), format, ap);
- va_end(ap);
- if (bytes < 0 || bytes >= sizeof(format_buf)) {
- _E("vsnprintf() is failed. result(%d)", bytes);
- return -1;
- }
-
- snprintf(buf, sizeof(buf),
- "[%6d] %04d-%02d-%02d %02d:%02d:%02d %-16s %-100s\n",
- handle->index,
- tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
- tm.tm_hour, tm.tm_min, tm.tm_sec,
- tag, format_buf);
- ret = write(handle->fd, buf, strlen(buf));
- if (ret < 0) {
- ret = -errno;
- _E("Failed to write log message. errno(%d)", errno);
- return ret;
- }
-
- if (++handle->index >= LAUNCHPAD_LOG_MAX_SIZE)
- handle->index = 0;
-
- return ret;
-}
-
-int _logger_get_fd(logger_h handle, int *fd)
-{
- if (!_config_get_int_value(CONFIG_TYPE_LOGGER_ENABLE))
- return 0;
-
- if (!handle || !fd) {
- _E("Invalid parameter");
- return -EINVAL;
- }
-
- *fd = handle->fd;
-
- return 0;
-}
--- /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.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <linux/limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/smack.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "launchpad_config.h"
+#include "launchpad_logger.h"
+#include "log_private.h"
+
+#define LAUNCHPAD_LOG_APPFW_PATH "/var/log/appfw"
+#define LAUNCHPAD_LOG_PATH "/var/log/appfw/launchpad"
+#define LAUNCHPAD_LOG_MAX_SIZE 2500
+#define LAUNCHPAD_LOG_MAX_BUFFER_SIZE 256
+
+struct logger_s {
+ int fd;
+ int index;
+};
+
+static int __set_smack_label(const char* path, const char* label) {
+ int ret;
+
+ ret = smack_setlabel(path, label, SMACK_LABEL_ACCESS);
+ if (ret != 0) {
+ ret = -errno;
+ _E("smack_setlabel() is failed. path(%s), label(%s), errno(%d)", path,
+ label, errno);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int __create_directory(const char* path) {
+ mode_t mode;
+ int ret;
+
+ ret = access(path, F_OK);
+ if (ret == 0)
+ return 0;
+
+ mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP;
+ ret = mkdir(path, mode);
+ if (ret < 0) {
+ ret = -errno;
+ _E("Failed to create directory(%s). errno(%d)", path, errno);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int __create_launchpad_directories(void) {
+ const char* logger_path;
+ char path[PATH_MAX];
+ int ret;
+
+ logger_path = _config_get_string_value(CONFIG_TYPE_LOGGER_PATH);
+ ret = __create_directory(logger_path);
+ if (ret < 0)
+ return ret;
+
+ ret = __set_smack_label(logger_path, "User::Home");
+ if (ret < 0)
+ return ret;
+
+ snprintf(path, sizeof(path), "%s/launchpad", logger_path);
+ ret = __create_directory(path);
+ if (ret < 0)
+ return ret;
+
+ ret = __set_smack_label(path, "User");
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int _logger_create(const char* path, logger_h* handle) {
+ struct logger_s* logger;
+ off_t offset;
+ int ret;
+
+ if (!_config_get_int_value(CONFIG_TYPE_LOGGER_ENABLE))
+ return 0;
+
+ if (!path || !handle) {
+ _E("Invalid parameter");
+ return -EINVAL;
+ }
+
+ ret = __create_launchpad_directories();
+ if (ret < 0)
+ return ret;
+
+ logger = static_cast<logger_s*>(calloc(1, sizeof(struct logger_s)));
+ if (!logger) {
+ _E("Out of memory");
+ return -ENOMEM;
+ }
+
+ logger->fd = open(path, O_CREAT | O_WRONLY, 0640);
+ if (logger->fd < 0) {
+ ret = -errno;
+ _E("Failed to open path(%s), errno(%d)", path, errno);
+ _logger_destroy(logger);
+ return ret;
+ }
+
+ ret = __set_smack_label(path, "User");
+ if (ret < 0) {
+ _logger_destroy(logger);
+ return ret;
+ }
+
+ offset = lseek(logger->fd, 0, SEEK_END);
+ if (offset != 0) {
+ logger->index = (int)(offset / LAUNCHPAD_LOG_MAX_STRING_SIZE);
+ if (logger->index >= LAUNCHPAD_LOG_MAX_SIZE) {
+ logger->index = 0;
+ lseek(logger->fd, 0, SEEK_SET);
+ }
+ }
+
+ *handle = logger;
+
+ return 0;
+}
+
+int _logger_destroy(logger_h handle) {
+ if (!_config_get_int_value(CONFIG_TYPE_LOGGER_ENABLE))
+ return 0;
+
+ if (!handle) {
+ _E("Invalid parameter");
+ return -EINVAL;
+ }
+
+ if (handle->fd > 0)
+ close(handle->fd);
+
+ free(handle);
+
+ return 0;
+}
+
+int _logger_print(logger_h handle, const char* tag, const char* format, ...) {
+ char buf[LAUNCHPAD_LOG_MAX_BUFFER_SIZE];
+ char format_buf[128];
+ struct tm tm = {
+ 0,
+ };
+ time_t t;
+ ssize_t ret;
+ va_list ap;
+ off_t offset;
+ int bytes;
+
+ if (!_config_get_int_value(CONFIG_TYPE_LOGGER_ENABLE))
+ return 0;
+
+ if (!handle || !tag || !format) {
+ _E("Invalid parameter");
+ return -EINVAL;
+ }
+
+ t = time(nullptr);
+ localtime_r(&t, &tm);
+
+ if (handle->index != 0)
+ offset = lseek(handle->fd, 0, SEEK_CUR);
+ else
+ offset = lseek(handle->fd, 0, SEEK_SET);
+
+ if (offset == -1)
+ _E("lseek() is failed. errno(%d)", errno);
+
+ va_start(ap, format);
+ bytes = vsnprintf(format_buf, sizeof(format_buf), format, ap);
+ va_end(ap);
+ if (bytes < 0 || bytes >= sizeof(format_buf)) {
+ _E("vsnprintf() is failed. result(%d)", bytes);
+ return -1;
+ }
+
+ snprintf(buf, sizeof(buf),
+ "[%6d] %04d-%02d-%02d %02d:%02d:%02d %-16s %-100s\n", handle->index,
+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min,
+ tm.tm_sec, tag, format_buf);
+ ret = write(handle->fd, buf, strlen(buf));
+ if (ret < 0) {
+ ret = -errno;
+ _E("Failed to write log message. errno(%d)", errno);
+ return ret;
+ }
+
+ if (++handle->index >= LAUNCHPAD_LOG_MAX_SIZE)
+ handle->index = 0;
+
+ return ret;
+}
+
+int _logger_get_fd(logger_h handle, int* fd) {
+ if (!_config_get_int_value(CONFIG_TYPE_LOGGER_ENABLE))
+ return 0;
+
+ if (!handle || !fd) {
+ _E("Invalid parameter");
+ return -EINVAL;
+ }
+
+ *fd = handle->fd;
+
+ return 0;
+}
+++ /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 <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <glib.h>
-
-#include "launchpad_config.h"
-#include "launchpad_memory_monitor.h"
-#include "launchpad_proc.h"
-#include "log_private.h"
-
-#define INTERVAL_BASE_RATE 0.15f
-
-struct memory_monitor_s {
- unsigned int threshold;
- unsigned int prev_used_ratio;
- unsigned int base_interval;
- unsigned int interval;
- bool low_memory;
- guint tag;
- memory_monitor_cb callback;
- void *user_data;
-};
-
-static struct memory_monitor_s __monitor;
-
-static void __memory_monitor_start(void);
-
-static gboolean __memory_check_cb(gpointer data)
-{
- bool low_memory;
-
- __monitor.tag = 0;
- low_memory = _memory_monitor_is_low_memory();
- if (__monitor.low_memory != low_memory && __monitor.callback)
- __monitor.callback(low_memory, __monitor.user_data);
-
- __monitor.low_memory = low_memory;
- __memory_monitor_start();
-
- return G_SOURCE_REMOVE;
-}
-
-static void __memory_monitor_stop(void)
-{
- if (!__monitor.tag)
- return;
-
- g_source_remove(__monitor.tag);
- __monitor.tag = 0;
-}
-
-static void __memory_monitor_start(void)
-{
- if (__monitor.threshold == 100)
- return;
-
- if (__monitor.tag)
- return;
-
- __monitor.tag = g_timeout_add(__monitor.interval,
- __memory_check_cb, NULL);
-
- __monitor.interval += __monitor.interval * INTERVAL_BASE_RATE;
-}
-
-int _memory_monitor_reset_timer(void)
-{
- _W("Reset");
- __monitor.interval = __monitor.base_interval;
-
- __memory_monitor_stop();
- __memory_monitor_start();
-
- return 0;
-}
-
-bool _memory_monitor_is_low_memory(void)
-{
- unsigned int mem_used_ratio = 0;
-
- if (__monitor.threshold == 100)
- return false;
-
- _proc_get_mem_used_ratio(&mem_used_ratio);
-
- _W("previous used ratio(%u), current used ratio(%u)",
- __monitor.prev_used_ratio, mem_used_ratio);
-
- __monitor.prev_used_ratio = mem_used_ratio;
-
- if (mem_used_ratio > __monitor.threshold)
- return true;
-
- return false;
-}
-
-int _memory_monitor_set_event_cb(memory_monitor_cb callback, void *user_data)
-{
- __monitor.callback = callback;
- __monitor.user_data = user_data;
-
- return 0;
-}
-
-int _memory_monitor_init(void)
-{
- int ret;
-
- _W("MEMORY_MONITOR_INIT");
-
- __monitor.threshold = _config_get_int_value(
- CONFIG_TYPE_MEMORY_MONITOR_THRESHOLD);
- __monitor.base_interval = _config_get_int_value(
- CONFIG_TYPE_MEMORY_MONITOR_INTERVAL);
- __monitor.interval = __monitor.base_interval;
-
- ret = _proc_get_mem_used_ratio(&__monitor.prev_used_ratio);
- if (ret != 0) {
- _E("Failed to get mem used ratio. error(%d)", ret);
- return ret;
- }
-
- __memory_monitor_start();
-
- return 0;
-}
-
-void _memory_monitor_fini(void)
-{
- _W("MEMORY_MONITOR_FINI");
-
- __memory_monitor_stop();
-}
--- /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.
+ */
+
+#include <errno.h>
+#include <glib.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "launchpad_config.h"
+#include "launchpad_memory_monitor.h"
+#include "launchpad_proc.h"
+#include "log_private.h"
+
+#define INTERVAL_BASE_RATE 0.15f
+
+struct memory_monitor_s {
+ unsigned int threshold;
+ unsigned int prev_used_ratio;
+ unsigned int base_interval;
+ unsigned int interval;
+ bool low_memory;
+ guint tag;
+ memory_monitor_cb callback;
+ void* user_data;
+};
+
+static struct memory_monitor_s __monitor;
+
+static void __memory_monitor_start(void);
+
+static gboolean __memory_check_cb(gpointer data) {
+ bool low_memory;
+
+ __monitor.tag = 0;
+ low_memory = _memory_monitor_is_low_memory();
+ if (__monitor.low_memory != low_memory && __monitor.callback)
+ __monitor.callback(low_memory, __monitor.user_data);
+
+ __monitor.low_memory = low_memory;
+ __memory_monitor_start();
+
+ return G_SOURCE_REMOVE;
+}
+
+static void __memory_monitor_stop(void) {
+ if (!__monitor.tag)
+ return;
+
+ g_source_remove(__monitor.tag);
+ __monitor.tag = 0;
+}
+
+static void __memory_monitor_start(void) {
+ if (__monitor.threshold == 100)
+ return;
+
+ if (__monitor.tag)
+ return;
+
+ __monitor.tag = g_timeout_add(__monitor.interval, __memory_check_cb, NULL);
+
+ __monitor.interval += __monitor.interval * INTERVAL_BASE_RATE;
+}
+
+int _memory_monitor_reset_timer(void) {
+ _W("Reset");
+ __monitor.interval = __monitor.base_interval;
+
+ __memory_monitor_stop();
+ __memory_monitor_start();
+
+ return 0;
+}
+
+bool _memory_monitor_is_low_memory(void) {
+ unsigned int mem_used_ratio = 0;
+
+ if (__monitor.threshold == 100)
+ return false;
+
+ _proc_get_mem_used_ratio(&mem_used_ratio);
+
+ _W("previous used ratio(%u), current used ratio(%u)",
+ __monitor.prev_used_ratio, mem_used_ratio);
+
+ __monitor.prev_used_ratio = mem_used_ratio;
+
+ if (mem_used_ratio > __monitor.threshold)
+ return true;
+
+ return false;
+}
+
+int _memory_monitor_set_event_cb(memory_monitor_cb callback, void* user_data) {
+ __monitor.callback = callback;
+ __monitor.user_data = user_data;
+
+ return 0;
+}
+
+int _memory_monitor_init(void) {
+ int ret;
+
+ _W("MEMORY_MONITOR_INIT");
+
+ __monitor.threshold =
+ _config_get_int_value(CONFIG_TYPE_MEMORY_MONITOR_THRESHOLD);
+ __monitor.base_interval =
+ _config_get_int_value(CONFIG_TYPE_MEMORY_MONITOR_INTERVAL);
+ __monitor.interval = __monitor.base_interval;
+
+ ret = _proc_get_mem_used_ratio(&__monitor.prev_used_ratio);
+ if (ret != 0) {
+ _E("Failed to get mem used ratio. error(%d)", ret);
+ return ret;
+ }
+
+ __memory_monitor_start();
+
+ return 0;
+}
+
+void _memory_monitor_fini(void) {
+ _W("MEMORY_MONITOR_FINI");
+
+ __memory_monitor_stop();
+}
+++ /dev/null
-/*
- * Copyright (c) 2015 - 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 <dirent.h>
-#include <gio/gio.h>
-#include <glib.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/signalfd.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include "launchpad_common.h"
-#include "launchpad_dbus.h"
-#include "launchpad_io_channel.h"
-#include "launchpad_proc.h"
-#include "launchpad_signal.h"
-#include "launchpad_socket.h"
-#include "log_private.h"
-
-#define HYDRA_SIGCHLD_SOCK ".hydra-sigchld-sock"
-
-static pid_t __pid;
-static sigset_t __mask;
-static sigset_t __old_mask;
-static socket_h __sigchld_socket;
-static io_channel_h __sigchld_channel;
-static socket_h __hydra_sigchld_socket;
-static io_channel_h __hydra_sigchld_channel;
-static signal_sigchld_cb __callback;
-static void *__user_data;
-
-static gboolean __hydra_sigchld_recovery_cb(gpointer data);
-static gboolean __sigchld_recovery_cb(gpointer data);
-
-static void __socket_garbage_collector(void)
-{
- DIR *dp;
- struct dirent *dentry = NULL;
- char path[PATH_MAX];
-
- snprintf(path, sizeof(path), "/run/aul/apps/%d", getuid());
- dp = opendir(path);
- if (!dp)
- return;
-
- while ((dentry = readdir(dp)) != NULL) {
- if (!isdigit(dentry->d_name[0]))
- continue;
-
- snprintf(path, sizeof(path), "/proc/%s", dentry->d_name);
- if (access(path, F_OK) < 0)
- _delete_sock_path(atoi(dentry->d_name), getuid());
- }
- closedir(dp);
-}
-
-static void __sigchld_action(int pid)
-{
- _dbus_send_app_dead_signal(pid);
- _delete_sock_path(pid, getuid());
- __socket_garbage_collector();
-}
-
-static int __check_permission(int pid)
-{
- char buf[512] = { 0, };
- int ret;
-
- ret = _proc_get_attr(pid, buf, sizeof(buf));
- if (ret < 0)
- return -1;
-
- if (!strcmp(buf, "User") ||
- !strcmp(buf, "System") ||
- !strcmp(buf, "System::Privileged"))
- return 0;
-
- _E("Permission denied. peer(%d:%s)", pid, buf);
- return -1;
-}
-
-static bool __hydra_sigchld_handler(int fd, io_condition_e cond,
- void *user_data)
-{
- socket_h client_socket;
- int caller_pid;
- int pid = -1;
- int ret;
-
- if (cond & (IO_ERR | IO_HUP | IO_NVAL)) {
- _E("fd(%d), io_condition(%d)", fd, cond);
- g_idle_add(__hydra_sigchld_recovery_cb, NULL);
- return false;
- }
-
- ret = _socket_accept(__hydra_sigchld_socket, &client_socket);
- if (ret < 0)
- return true;
-
- _socket_get_pid(client_socket, &caller_pid);
- ret = __check_permission(caller_pid);
- if (ret < 0) {
- _socket_destroy(client_socket);
- return true;
- }
-
- ret = _socket_read(client_socket, &pid, sizeof(pid));
- _socket_destroy(client_socket);
- if (ret < 0) {
- _E("Failed to read process id. ret(%d)", ret);
- return true;
- }
-
- _W("[__SIGCHLD__] pid(%d)", pid);
- __sigchld_action(pid);
-
- if (__callback)
- __callback(pid, user_data);
-
- return true;
-}
-
-static int __hydra_sigchld_init(void)
-{
- char path[LAUNCHPAD_SOCKET_PATH_SIZE];
- io_channel_h channel;
- io_condition_e cond;
- socket_h socket;
- int ret;
- int fd;
-
- snprintf(path, sizeof(path), "/run/aul/daemons/%u/%s",
- getuid(), HYDRA_SIGCHLD_SOCK);
- ret = _socket_create(path, false, &socket);
- if (ret < 0)
- return ret;
-
- _socket_get_fd(socket, &fd);
-
- cond = IO_IN | IO_PRI | IO_ERR | IO_HUP | IO_NVAL;
- channel = _io_channel_create(fd, cond,
- __hydra_sigchld_handler, NULL);
- if (!channel) {
- _socket_destroy(socket);
- return -ENOMEM;
- }
-
- _io_channel_set_close_on_destroy(channel, false);
-
- __hydra_sigchld_socket = socket;
- __hydra_sigchld_channel = channel;
-
- return 0;
-}
-
-static int __hydra_sigchld_fini(void)
-{
- if (__hydra_sigchld_channel)
- _io_channel_destroy(__hydra_sigchld_channel);
-
- if (__hydra_sigchld_socket) {
- if (__pid != getpid())
- _socket_set_fd(__hydra_sigchld_socket, -1);
-
- _socket_destroy(__hydra_sigchld_socket);
- }
-
- return 0;
-}
-
-static bool __sigchld_handler(int fd, io_condition_e cond, void *user_data)
-{
- struct signalfd_siginfo info;
- pid_t child_pid;
- pid_t child_pgid;
- int status;
- int ret;
-
- if (cond & (IO_ERR | IO_HUP | IO_NVAL)) {
- _E("fd(%d), io_condition(%d)", fd, cond);
- g_idle_add(__sigchld_recovery_cb, NULL);
- return false;
- }
-
- do {
- ret = _socket_read(__sigchld_socket, &info, sizeof(info));
- if (ret < 0)
- break;
-
- child_pgid = getpgid(info.ssi_pid);
- _W("[__SIGCHLD__] pid(%d), pgid(%d), status(%d)",
- info.ssi_pid, child_pgid, info.ssi_status);
-
- while ((child_pid = waitpid(-1, &status, WNOHANG)) > 0) {
- if (child_pid == child_pgid)
- killpg(child_pgid, SIGKILL);
-
- __sigchld_action(child_pid);
- }
-
- if (__callback)
- __callback(info.ssi_pid, __user_data);
- } while (ret == 0);
-
- return true;
-}
-
-static int __signal_block_sigchld(void)
-{
- int ret;
-
- sigemptyset(&__mask);
- sigaddset(&__mask, SIGCHLD);
-
- ret = sigprocmask(SIG_BLOCK, &__mask, &__old_mask);
- if (ret < 0) {
- ret = -errno;
- _E("sigprocmask(SIG_BLOCK) is failed. errno(%d)", errno);
- return ret;
- }
-
- return 0;
-}
-
-static int __signal_get_sigchld_fd(void)
-{
- int sfd;
-
- sfd = signalfd(-1, &__mask, SFD_NONBLOCK | SFD_CLOEXEC);
- if (sfd < 0) {
- sfd = -errno;
- _E("signalfd() is failed. errno(%d)", errno);
- return sfd;
- }
-
- return sfd;
-}
-
-int _signal_unblock_sigchld(void)
-{
- int ret;
-
- ret = sigprocmask(SIG_SETMASK, &__old_mask, NULL);
- if (ret < 0) {
- ret = -errno;
- _E("sigprocmask(SIG_SETMASK) is failed. errno(%d)", errno);
- return ret;
- }
-
- return 0;
-}
-
-static int __sigchld_init(void)
-{
- io_channel_h channel;
- io_condition_e cond;
- socket_h socket;
- int sfd;
- int ret;
-
- sfd = __signal_get_sigchld_fd();
- if (sfd < 0)
- return sfd;
-
- ret = _socket_create_with_fd(sfd, &socket);
- if (ret < 0) {
- close(sfd);
- return ret;
- }
-
- cond = IO_IN | IO_PRI | IO_ERR | IO_HUP | IO_NVAL;
- channel = _io_channel_create(sfd, cond,
- __sigchld_handler, NULL);
- if (!channel) {
- _socket_destroy(socket);
- return -ENOMEM;
- }
- _io_channel_set_close_on_destroy(channel, false);
-
- __sigchld_socket = socket;
- __sigchld_channel = channel;
-
- return 0;
-}
-
-static int __sigchld_fini(void)
-{
- if (__sigchld_channel)
- _io_channel_destroy(__sigchld_channel);
-
- if (__sigchld_socket) {
- if (__pid != getpid())
- _socket_set_fd(__sigchld_socket, -1);
-
- _socket_destroy(__sigchld_socket);
- }
-
- return 0;
-}
-
-int _signal_set_sigchld_cb(signal_sigchld_cb callback, void *user_data)
-{
- __callback = callback;
- __user_data = user_data;
-
- return 0;
-}
-
-static gboolean __hydra_sigchld_recovery_cb(gpointer data)
-{
- int ret;
-
- __hydra_sigchld_fini();
-
- ret = __hydra_sigchld_init();
- if (ret < 0) {
- _E("Failed to recover hydra sigchld socket");
- abort();
- } else {
- _W("[__RECOVERY__] Hydra SIGCHLD Socket");
- }
-
- return G_SOURCE_REMOVE;
-}
-
-static gboolean __sigchld_recovery_cb(gpointer data)
-{
- int ret;
-
- __sigchld_fini();
-
- ret = __sigchld_init();
- if (ret < 0) {
- _E("Failed to recover sigchld fd");
- abort();
- } else {
- _W("[__RECOVERY__] SIGCHLD fd");
- }
-
- return G_SOURCE_REMOVE;
-}
-
-int _signal_init(void)
-{
- int ret;
- int i;
-
- _D("SIGNAL_INIT");
- __pid = getpid();
-
- ret = __signal_block_sigchld();
- if (ret < 0)
- return ret;
-
- ret = __sigchld_init();
- if (ret < 0)
- return ret;
-
- ret = __hydra_sigchld_init();
- if (ret < 0)
- return ret;
-
- for (i = 0; i < _NSIG; ++i) {
- switch (i) {
- /* controlled by sys-assert package*/
- case SIGQUIT:
- case SIGILL:
- case SIGABRT:
- case SIGBUS:
- case SIGFPE:
- case SIGSEGV:
- case SIGPIPE:
- break;
- default:
- signal(i, SIG_DFL);
- break;
- }
- }
-
- return 0;
-}
-
-void _signal_fini(void)
-{
-#ifndef PRELOAD_ACTIVATE
- int i;
-
- for (i = 0; i < _NSIG; ++i)
- signal(i, SIG_DFL);
-#endif
-
- _D("SIGNAL_FINI");
- _signal_set_sigchld_cb(NULL, NULL);
- __hydra_sigchld_fini();
- __sigchld_fini();
- _signal_unblock_sigchld();
-}
--- /dev/null
+/*
+ * Copyright (c) 2015 - 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.
+ */
+
+#include <dirent.h>
+#include <gio/gio.h>
+#include <glib.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/signalfd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "launchpad_common.h"
+#include "launchpad_dbus.h"
+#include "launchpad_io_channel.h"
+#include "launchpad_proc.h"
+#include "launchpad_signal.h"
+#include "launchpad_socket.h"
+#include "log_private.h"
+
+#define HYDRA_SIGCHLD_SOCK ".hydra-sigchld-sock"
+
+static pid_t __pid;
+static sigset_t __mask;
+static sigset_t __old_mask;
+static socket_h __sigchld_socket;
+static io_channel_h __sigchld_channel;
+static socket_h __hydra_sigchld_socket;
+static io_channel_h __hydra_sigchld_channel;
+static signal_sigchld_cb __callback;
+static void* __user_data;
+
+static gboolean __hydra_sigchld_recovery_cb(gpointer data);
+static gboolean __sigchld_recovery_cb(gpointer data);
+
+static void __socket_garbage_collector(void) {
+ DIR* dp;
+ struct dirent* dentry = nullptr;
+ char path[PATH_MAX];
+
+ snprintf(path, sizeof(path), "/run/aul/apps/%d", getuid());
+ dp = opendir(path);
+ if (!dp)
+ return;
+
+ while ((dentry = readdir(dp)) != nullptr) {
+ if (!isdigit(dentry->d_name[0]))
+ continue;
+
+ snprintf(path, sizeof(path), "/proc/%s", dentry->d_name);
+ if (access(path, F_OK) < 0)
+ _delete_sock_path(atoi(dentry->d_name), getuid());
+ }
+ closedir(dp);
+}
+
+static void __sigchld_action(int pid) {
+ _dbus_send_app_dead_signal(pid);
+ _delete_sock_path(pid, getuid());
+ __socket_garbage_collector();
+}
+
+static int __check_permission(int pid) {
+ char buf[512] = {
+ 0,
+ };
+ int ret;
+
+ ret = _proc_get_attr(pid, buf, sizeof(buf));
+ if (ret < 0)
+ return -1;
+
+ if (!strcmp(buf, "User") || !strcmp(buf, "System") ||
+ !strcmp(buf, "System::Privileged"))
+ return 0;
+
+ _E("Permission denied. peer(%d:%s)", pid, buf);
+ return -1;
+}
+
+static bool __hydra_sigchld_handler(int fd,
+ io_condition_e cond,
+ void* user_data) {
+ socket_h client_socket;
+ int caller_pid;
+ int pid = -1;
+ int ret;
+
+ if (cond & (IO_ERR | IO_HUP | IO_NVAL)) {
+ _E("fd(%d), io_condition(%d)", fd, cond);
+ g_idle_add(__hydra_sigchld_recovery_cb, nullptr);
+ return false;
+ }
+
+ ret = _socket_accept(__hydra_sigchld_socket, &client_socket);
+ if (ret < 0)
+ return true;
+
+ _socket_get_pid(client_socket, &caller_pid);
+ ret = __check_permission(caller_pid);
+ if (ret < 0) {
+ _socket_destroy(client_socket);
+ return true;
+ }
+
+ ret = _socket_read(client_socket, &pid, sizeof(pid));
+ _socket_destroy(client_socket);
+ if (ret < 0) {
+ _E("Failed to read process id. ret(%d)", ret);
+ return true;
+ }
+
+ _W("[__SIGCHLD__] pid(%d)", pid);
+ __sigchld_action(pid);
+
+ if (__callback)
+ __callback(pid, user_data);
+
+ return true;
+}
+
+static int __hydra_sigchld_init(void) {
+ char path[LAUNCHPAD_SOCKET_PATH_SIZE];
+ io_channel_h channel;
+ socket_h socket;
+ int ret;
+ int fd;
+
+ snprintf(path, sizeof(path), "/run/aul/daemons/%u/%s", getuid(),
+ HYDRA_SIGCHLD_SOCK);
+ ret = _socket_create(path, false, &socket);
+ if (ret < 0)
+ return ret;
+
+ _socket_get_fd(socket, &fd);
+
+ auto cond = IO_IN | IO_PRI | IO_ERR | IO_HUP | IO_NVAL;
+ channel = _io_channel_create(fd, static_cast<io_condition_e>(cond),
+ __hydra_sigchld_handler, nullptr);
+ if (!channel) {
+ _socket_destroy(socket);
+ return -ENOMEM;
+ }
+
+ _io_channel_set_close_on_destroy(channel, false);
+
+ __hydra_sigchld_socket = socket;
+ __hydra_sigchld_channel = channel;
+
+ return 0;
+}
+
+static int __hydra_sigchld_fini(void) {
+ if (__hydra_sigchld_channel)
+ _io_channel_destroy(__hydra_sigchld_channel);
+
+ if (__hydra_sigchld_socket) {
+ if (__pid != getpid())
+ _socket_set_fd(__hydra_sigchld_socket, -1);
+
+ _socket_destroy(__hydra_sigchld_socket);
+ }
+
+ return 0;
+}
+
+static bool __sigchld_handler(int fd, io_condition_e cond, void* user_data) {
+ struct signalfd_siginfo info;
+ pid_t child_pid;
+ pid_t child_pgid;
+ int status;
+ int ret;
+
+ if (cond & (IO_ERR | IO_HUP | IO_NVAL)) {
+ _E("fd(%d), io_condition(%d)", fd, cond);
+ g_idle_add(__sigchld_recovery_cb, nullptr);
+ return false;
+ }
+
+ do {
+ ret = _socket_read(__sigchld_socket, &info, sizeof(info));
+ if (ret < 0)
+ break;
+
+ child_pgid = getpgid(info.ssi_pid);
+ _W("[__SIGCHLD__] pid(%d), pgid(%d), status(%d)", info.ssi_pid, child_pgid,
+ info.ssi_status);
+
+ while ((child_pid = waitpid(-1, &status, WNOHANG)) > 0) {
+ if (child_pid == child_pgid)
+ killpg(child_pgid, SIGKILL);
+
+ __sigchld_action(child_pid);
+ }
+
+ if (__callback)
+ __callback(info.ssi_pid, __user_data);
+ } while (ret == 0);
+
+ return true;
+}
+
+static int __signal_block_sigchld(void) {
+ int ret;
+
+ sigemptyset(&__mask);
+ sigaddset(&__mask, SIGCHLD);
+
+ ret = sigprocmask(SIG_BLOCK, &__mask, &__old_mask);
+ if (ret < 0) {
+ ret = -errno;
+ _E("sigprocmask(SIG_BLOCK) is failed. errno(%d)", errno);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int __signal_get_sigchld_fd(void) {
+ int sfd;
+
+ sfd = signalfd(-1, &__mask, SFD_NONBLOCK | SFD_CLOEXEC);
+ if (sfd < 0) {
+ sfd = -errno;
+ _E("signalfd() is failed. errno(%d)", errno);
+ return sfd;
+ }
+
+ return sfd;
+}
+
+int _signal_unblock_sigchld(void) {
+ int ret;
+
+ ret = sigprocmask(SIG_SETMASK, &__old_mask, nullptr);
+ if (ret < 0) {
+ ret = -errno;
+ _E("sigprocmask(SIG_SETMASK) is failed. errno(%d)", errno);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int __sigchld_init(void) {
+ io_channel_h channel;
+ socket_h socket;
+ int sfd;
+ int ret;
+
+ sfd = __signal_get_sigchld_fd();
+ if (sfd < 0)
+ return sfd;
+
+ ret = _socket_create_with_fd(sfd, &socket);
+ if (ret < 0) {
+ close(sfd);
+ return ret;
+ }
+
+ auto cond = IO_IN | IO_PRI | IO_ERR | IO_HUP | IO_NVAL;
+ channel = _io_channel_create(sfd, static_cast<io_condition_e>(cond),
+ __sigchld_handler, nullptr);
+ if (!channel) {
+ _socket_destroy(socket);
+ return -ENOMEM;
+ }
+ _io_channel_set_close_on_destroy(channel, false);
+
+ __sigchld_socket = socket;
+ __sigchld_channel = channel;
+
+ return 0;
+}
+
+static int __sigchld_fini(void) {
+ if (__sigchld_channel)
+ _io_channel_destroy(__sigchld_channel);
+
+ if (__sigchld_socket) {
+ if (__pid != getpid())
+ _socket_set_fd(__sigchld_socket, -1);
+
+ _socket_destroy(__sigchld_socket);
+ }
+
+ return 0;
+}
+
+int _signal_set_sigchld_cb(signal_sigchld_cb callback, void* user_data) {
+ __callback = callback;
+ __user_data = user_data;
+
+ return 0;
+}
+
+static gboolean __hydra_sigchld_recovery_cb(gpointer data) {
+ int ret;
+
+ __hydra_sigchld_fini();
+
+ ret = __hydra_sigchld_init();
+ if (ret < 0) {
+ _E("Failed to recover hydra sigchld socket");
+ abort();
+ } else {
+ _W("[__RECOVERY__] Hydra SIGCHLD Socket");
+ }
+
+ return G_SOURCE_REMOVE;
+}
+
+static gboolean __sigchld_recovery_cb(gpointer data) {
+ int ret;
+
+ __sigchld_fini();
+
+ ret = __sigchld_init();
+ if (ret < 0) {
+ _E("Failed to recover sigchld fd");
+ abort();
+ } else {
+ _W("[__RECOVERY__] SIGCHLD fd");
+ }
+
+ return G_SOURCE_REMOVE;
+}
+
+int _signal_init(void) {
+ int ret;
+ int i;
+
+ _D("SIGNAL_INIT");
+ __pid = getpid();
+
+ ret = __signal_block_sigchld();
+ if (ret < 0)
+ return ret;
+
+ ret = __sigchld_init();
+ if (ret < 0)
+ return ret;
+
+ ret = __hydra_sigchld_init();
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < _NSIG; ++i) {
+ switch (i) {
+ /* controlled by sys-assert package*/
+ case SIGQUIT:
+ case SIGILL:
+ case SIGABRT:
+ case SIGBUS:
+ case SIGFPE:
+ case SIGSEGV:
+ case SIGPIPE:
+ break;
+ default:
+ signal(i, SIG_DFL);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+void _signal_fini(void) {
+#ifndef PRELOAD_ACTIVATE
+ int i;
+
+ for (i = 0; i < _NSIG; ++i)
+ signal(i, SIG_DFL);
+#endif
+
+ _D("SIGNAL_FINI");
+ _signal_set_sigchld_cb(nullptr, nullptr);
+ __hydra_sigchld_fini();
+ __sigchld_fini();
+ _signal_unblock_sigchld();
+}
+++ /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 <errno.h>
-#include <glib.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/syscall.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-#include "launchpad_worker.h"
-#include "log_private.h"
-
-struct job_s {
- worker_job_cb callback;
- void *user_data;
-};
-
-struct worker_s {
- char *name;
- GThread *thread;
- GMutex mutex;
- GCond cond;
- GQueue *queue;
-};
-
-int _worker_add_job(worker_h worker, worker_job_cb callback, void *user_data)
-{
- struct job_s *job;
-
- if (!worker || !callback) {
- _E("Invalid parameter");
- return -EINVAL;
- }
-
- job = malloc(sizeof(struct job_s));
- if (!job) {
- _E("Out of memory");
- return -ENOMEM;
- }
-
- job->callback = callback;
- job->user_data = user_data;
-
- g_mutex_lock(&worker->mutex);
- g_queue_push_tail(worker->queue, job);
- g_cond_signal(&worker->cond);
- g_mutex_unlock(&worker->mutex);
-
- return 0;
-}
-
-static int __set_comm(const char *name)
-{
- int fd;
- ssize_t bytes_written;
- char path[PATH_MAX];
- pid_t tid = syscall(__NR_gettid);
-
- _I("[%s] TID(%d)", name, tid);
- snprintf(path, sizeof(path), "/proc/%d/comm", tid);
- fd = open(path, O_WRONLY);
- if (fd < 0) {
- _E("Failed to open %s. error(%d)", path, errno);
- return -1;
- }
-
- bytes_written = write(fd, name, strlen(name) + 1);
- if (bytes_written < 0) {
- _E("Failed to write name(%s)", name);
- close(fd);
- return -1;
- }
-
- close(fd);
- return 0;
-}
-
-static gpointer __worker_thread_cb(gpointer data)
-{
- struct worker_s *worker = (struct worker_s *)data;
- struct job_s *job;
- bool done = false;
-
- __set_comm(worker->name);
- do {
- g_mutex_lock(&worker->mutex);
- if (g_queue_is_empty(worker->queue))
- g_cond_wait(&worker->cond, &worker->mutex);
-
- job = (struct job_s *)g_queue_pop_head(worker->queue);
- g_mutex_unlock(&worker->mutex);
- done = job->callback(job->user_data);
- free(job);
- } while (!done);
-
- return NULL;
-}
-
-int _worker_create(const char *name, worker_h *worker)
-{
- struct worker_s *handle;
-
- if (name == NULL || worker == NULL) {
- _E("Invalid parameter");
- return -EINVAL;
- }
-
- handle = calloc(1, sizeof(struct worker_s));
- if (handle == NULL) {
- _E("calloc() is failed");
- return -ENOMEM;
- }
-
- g_mutex_init(&handle->mutex);
- g_cond_init(&handle->cond);
-
- handle->name = strdup(name);
- if (!handle->name) {
- _E("strdup() is failed");
- _worker_destroy(handle);
- return -ENOMEM;
- }
-
- handle->queue = g_queue_new();
- if (!handle->queue) {
- _E("g_queue_new() is failed");
- _worker_destroy(handle);
- return -ENOMEM;
- }
-
- handle->thread = g_thread_new(name, __worker_thread_cb, handle);
- if (!handle->thread) {
- _E("g_thread_new() is failed");
- _worker_destroy(handle);
- return -ENOMEM;
- }
-
- *worker = handle;
- return 0;
-}
-
-static bool __worker_done_cb(void *user_data)
-{
- _W("Done");
- return true;
-}
-
-void _worker_destroy(worker_h worker)
-{
- if (worker == NULL)
- return;
-
- if (worker->thread) {
- _worker_add_job(worker, __worker_done_cb, NULL);
- g_thread_join(worker->thread);
- }
-
- if (worker->queue)
- g_queue_free_full(worker->queue, (GDestroyNotify)free);
-
- if (worker->name)
- free(worker->name);
-
- g_cond_clear(&worker->cond);
- g_mutex_clear(&worker->mutex);
- free(worker);
-}
--- /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.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <glib.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "launchpad_worker.h"
+#include "log_private.h"
+
+struct job_s {
+ worker_job_cb callback;
+ void* user_data;
+};
+
+struct worker_s {
+ char* name;
+ GThread* thread;
+ GMutex mutex;
+ GCond cond;
+ GQueue* queue;
+};
+
+int _worker_add_job(worker_h worker, worker_job_cb callback, void* user_data) {
+ struct job_s* job;
+
+ if (!worker || !callback) {
+ _E("Invalid parameter");
+ return -EINVAL;
+ }
+
+ job = static_cast<job_s*>(malloc(sizeof(job_s)));
+ if (!job) {
+ _E("Out of memory");
+ return -ENOMEM;
+ }
+
+ job->callback = callback;
+ job->user_data = user_data;
+
+ g_mutex_lock(&worker->mutex);
+ g_queue_push_tail(worker->queue, job);
+ g_cond_signal(&worker->cond);
+ g_mutex_unlock(&worker->mutex);
+
+ return 0;
+}
+
+static int __set_comm(const char* name) {
+ int fd;
+ ssize_t bytes_written;
+ char path[PATH_MAX];
+ pid_t tid = syscall(__NR_gettid);
+
+ _I("[%s] TID(%d)", name, tid);
+ snprintf(path, sizeof(path), "/proc/%d/comm", tid);
+ fd = open(path, O_WRONLY);
+ if (fd < 0) {
+ _E("Failed to open %s. error(%d)", path, errno);
+ return -1;
+ }
+
+ bytes_written = write(fd, name, strlen(name) + 1);
+ if (bytes_written < 0) {
+ _E("Failed to write name(%s)", name);
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ return 0;
+}
+
+static gpointer __worker_thread_cb(gpointer data) {
+ struct worker_s* worker = (struct worker_s*)data;
+ struct job_s* job;
+ bool done = false;
+
+ __set_comm(worker->name);
+ do {
+ g_mutex_lock(&worker->mutex);
+ if (g_queue_is_empty(worker->queue))
+ g_cond_wait(&worker->cond, &worker->mutex);
+
+ job = (struct job_s*)g_queue_pop_head(worker->queue);
+ g_mutex_unlock(&worker->mutex);
+ done = job->callback(job->user_data);
+ free(job);
+ } while (!done);
+
+ return NULL;
+}
+
+int _worker_create(const char* name, worker_h* worker) {
+ struct worker_s* handle;
+
+ if (name == NULL || worker == NULL) {
+ _E("Invalid parameter");
+ return -EINVAL;
+ }
+
+ handle = static_cast<worker_s*>(calloc(1, sizeof(worker_s)));
+ if (handle == NULL) {
+ _E("calloc() is failed");
+ return -ENOMEM;
+ }
+
+ g_mutex_init(&handle->mutex);
+ g_cond_init(&handle->cond);
+
+ handle->name = strdup(name);
+ if (!handle->name) {
+ _E("strdup() is failed");
+ _worker_destroy(handle);
+ return -ENOMEM;
+ }
+
+ handle->queue = g_queue_new();
+ if (!handle->queue) {
+ _E("g_queue_new() is failed");
+ _worker_destroy(handle);
+ return -ENOMEM;
+ }
+
+ handle->thread = g_thread_new(name, __worker_thread_cb, handle);
+ if (!handle->thread) {
+ _E("g_thread_new() is failed");
+ _worker_destroy(handle);
+ return -ENOMEM;
+ }
+
+ *worker = handle;
+ return 0;
+}
+
+static bool __worker_done_cb(void* user_data) {
+ _W("Done");
+ return true;
+}
+
+void _worker_destroy(worker_h worker) {
+ if (worker == NULL)
+ return;
+
+ if (worker->thread) {
+ _worker_add_job(worker, __worker_done_cb, NULL);
+ g_thread_join(worker->thread);
+ }
+
+ if (worker->queue)
+ g_queue_free_full(worker->queue, (GDestroyNotify)free);
+
+ if (worker->name)
+ free(worker->name);
+
+ g_cond_clear(&worker->cond);
+ g_mutex_clear(&worker->mutex);
+ free(worker);
+}
+++ /dev/null
-/*
- * Copyright (c) 2016 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 <malloc.h>
-#include <stdlib.h>
-#include <dirent.h>
-#include <string.h>
-
-#include "loader_info.h"
-#include "launchpad_common.h"
-
-#define TAG_LOADER "[LOADER]"
-#define TAG_NAME "NAME"
-#define TAG_EXE "EXE"
-#define TAG_APP_TYPE "APP_TYPE"
-#define TAG_DETECTION_METHOD "DETECTION_METHOD"
-#define TAG_ACTIVATION_METHOD "ACTIVATION_METHOD"
-#define TAG_DEACTIVATION_METHOD "DEACTIVATION_METHOD"
-#define TAG_TTL "TTL"
-#define TAG_TIMEOUT "TIMEOUT"
-#define TAG_EXTRA "EXTRA"
-#define TAG_EXTRA_ARRAY "EXTRA_ARRAY"
-#define TAG_EXTRA_ARRAY_VAL "EXTRA_ARRAY_VAL"
-#define TAG_ALTERNATIVE_LOADER "ALTERNATIVE_LOADER"
-#define TAG_HW_ACC "HW_ACC"
-#define TAG_CPU_THRESHOLD_MAX "CPU_THRESHOLD_MAX"
-#define TAG_CPU_THRESHOLD_MIN "CPU_THRESHOLD_MIN"
-#define TAG_ON_BOOT "ON_BOOT"
-#define TAG_HYDRA "HYDRA"
-#define TAG_APP_CHECK "APP_CHECK"
-#define TAG_ON_BOOT_TIMEOUT "ON_BOOT_TIMEOUT"
-#define TAG_SCHED_PRIORITY "SCHED_PRIORITY"
-
-#define VAL_ON "ON"
-#define VAL_OFF "OFF"
-#define VAL_METHOD_TIMEOUT "TIMEOUT"
-#define VAL_METHOD_DEMAND "DEMAND"
-#define VAL_METHOD_VISIBILITY "VISIBILITY"
-#define VAL_METHOD_REQUEST "REQUEST"
-#define VAL_METHOD_AVAILABLE_MEMORY "AVAILABLE_MEMORY"
-#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;
-
- info = calloc(1, sizeof(loader_info_t));
- if (info == NULL) {
- _E("Out of memory");
- return NULL;
- }
-
- info->type = 0;
- info->name = NULL;
- info->exe = NULL;
- info->app_types = NULL;
- info->hw_acc = NULL;
- info->alternative_loaders = NULL;
- info->detection_method = METHOD_TIMEOUT | METHOD_VISIBILITY |
- METHOD_INSTALL;
- info->timeout_val = 5000;
- info->extra = bundle_create();
- info->cpu_threshold_max = DEFAULT_CPU_THRESHOLD_MAX;
- info->cpu_threshold_min = DEFAULT_CPU_THRESHOLD_MIN;
- info->on_boot = true;
- info->app_exists = false;
- info->activation_method = 0;
- info->deactivation_method = 0;
- info->ttl = 600; /* 10 minutes */
- info->is_hydra = false;
- info->app_check = true;
-
- return info;
-}
-
-static void __parse_detection_method(loader_info_t *info, char *line)
-{
- char *token;
- char *savedptr;
-
- token = strtok_r(line, " |\t\r\n", &savedptr);
- info->detection_method = 0;
- while (token) {
- if (!strcmp(token, VAL_METHOD_TIMEOUT))
- info->detection_method |= METHOD_TIMEOUT;
- else if (!strcmp(token, VAL_METHOD_VISIBILITY))
- info->detection_method |= METHOD_VISIBILITY;
- else if (!strcmp(token, VAL_METHOD_DEMAND))
- info->detection_method |= METHOD_DEMAND;
-
- token = strtok_r(NULL, " |\t\r\n", &savedptr);
- }
-
- info->detection_method |= METHOD_INSTALL;
- _D("detection_method:%d", info->detection_method);
-}
-
-static void __parse_activation_method(loader_info_t *info, char *line)
-{
- char *token;
- char *savedptr;
-
- token = strtok_r(line, " |\t\r\n", &savedptr);
- info->activation_method = 0;
- while (token) {
- if (!strcmp(token, VAL_METHOD_REQUEST))
- info->activation_method |= METHOD_REQUEST;
- else if (!strcmp(token, VAL_METHOD_AVAILABLE_MEMORY))
- info->activation_method |= METHOD_AVAILABLE_MEMORY;
-
- token = strtok_r(NULL, " |\t\r\n", &savedptr);
- }
-
- _D("activation_method:%d", info->activation_method);
-}
-
-static void __parse_deactivation_method(loader_info_t *info, char *line)
-{
- char *token;
- char *savedptr;
-
- token = strtok_r(line, " |\t\r\n", &savedptr);
- info->deactivation_method = 0;
- while (token) {
- if (!strcmp(token, VAL_METHOD_TTL))
- info->deactivation_method |= METHOD_TTL;
- else if (!strcmp(token, VAL_METHOD_OUT_OF_MEMORY))
- info->deactivation_method |= METHOD_OUT_OF_MEMORY;
-
- token = strtok_r(NULL, " |\t\r\n", &savedptr);
- }
-
- _D("deactivation_method:%d", info->deactivation_method);
-}
-
-static void __parse_app_types(loader_info_t *info, char *line)
-{
- char *token;
- char *savedptr;
-
- token = strtok_r(line, " |\t\r\n", &savedptr);
- while (token) {
- info->app_types = g_list_append(info->app_types, strdup(token));
- token = strtok_r(NULL, " |\t\r\n", &savedptr);
- }
-}
-
-static void __parse_extra(loader_info_t *info, char *line)
-{
- char *tok1 = NULL;
- char *tok2 = NULL;
- char *tok3 = NULL;
-
- if (info->extra == NULL)
- return;
-
- sscanf(line, "%ms %ms %ms", &tok1, &tok2, &tok3);
-
- if (!tok1 || !tok2 || !tok3)
- goto end;
-
- if (strlen(tok2) == 0 || strlen(tok3) == 0)
- goto end;
-
- bundle_add_str(info->extra, tok2, tok3);
-
-end:
- if (tok1)
- free(tok1);
- if (tok2)
- free(tok2);
- if (tok3)
- free(tok3);
-}
-
-static void __add_extra_array_from_list(bundle *b, const char *key, GList *list)
-{
- const char **array;
- int len;
- int i;
- GList *cur;
-
- if (b == NULL || key == NULL || list == NULL)
- return;
-
- len = g_list_length(list);
- array = malloc(sizeof(const char *) * len);
- if (array == NULL)
- return;
-
- cur = list;
- for (i = 0; i < len; i++) {
- array[i] = cur->data;
- cur = g_list_next(cur);
- }
-
- bundle_add_str_array(b, key, array, len);
- free(array);
-}
-
-static void __flush_extra_array(bundle *b, char *key, GList *list)
-{
- if (list) {
- __add_extra_array_from_list(b, key, list);
- g_list_free_full(list, free);
- }
-
- free(key);
-}
-
-static GList *__parse_file(GList *list, const char *path)
-{
- FILE *fp;
- char buf[LINE_MAX];
- char *tok1 = NULL;
- char *tok2 = NULL;
- loader_info_t *cur_info = NULL;
- char *key = NULL;
- GList *extra_array = NULL;
-
- fp = fopen(path, "rt");
- if (fp == NULL)
- return list;
-
- while (fgets(buf, sizeof(buf), fp) != NULL) {
- FREE_AND_NULL(tok1);
- FREE_AND_NULL(tok2);
- sscanf(buf, "%ms %ms", &tok1, &tok2);
- if (tok1 && strcasecmp(TAG_LOADER, tok1) == 0) {
- if (cur_info != NULL) {
- __flush_extra_array(cur_info->extra, key,
- extra_array);
- extra_array = NULL;
- key = NULL;
- list = g_list_append(list, cur_info);
- }
- cur_info = __create_loader_info();
- if (!cur_info)
- break;
- continue;
- }
-
- if (!tok1 || !tok2 || !cur_info)
- continue;
- if (tok1[0] == '\0' || tok2[0] == '\0' || tok1[0] == '#')
- continue;
-
- if (strcasecmp(TAG_NAME, tok1) == 0) {
- cur_info->name = strdup(tok2);
- } else if (strcasecmp(TAG_EXE, tok1) == 0) {
- cur_info->exe = strdup(tok2);
- } else if (strcasecmp(TAG_APP_TYPE, tok1) == 0) {
- __parse_app_types(cur_info, &buf[strlen(tok1)]);
- } else if (strcasecmp(TAG_DETECTION_METHOD, tok1) == 0) {
- __parse_detection_method(cur_info, &buf[strlen(tok1)]);
- } else if (strcasecmp(TAG_ACTIVATION_METHOD, tok1) == 0) {
- __parse_activation_method(cur_info,
- &buf[strlen(tok1)]);
- } else if (strcasecmp(TAG_DEACTIVATION_METHOD, tok1) == 0) {
- __parse_deactivation_method(cur_info,
- &buf[strlen(tok1)]);
- } else if (strcasecmp(TAG_TTL, tok1) == 0) {
- cur_info->ttl = strtoul(tok2, NULL, 10);
- } else if (strcasecmp(TAG_TIMEOUT, tok1) == 0) {
- cur_info->timeout_val = atoi(tok2);
- } else if (strcasecmp(TAG_EXTRA, tok1) == 0) {
- __parse_extra(cur_info, buf);
- } else if (strcasecmp(TAG_EXTRA_ARRAY, tok1) == 0) {
- __flush_extra_array(cur_info->extra, key, extra_array);
- extra_array = NULL;
- key = strdup(tok2);
- } else if (strcasecmp(TAG_EXTRA_ARRAY_VAL, tok1) == 0) {
- extra_array = g_list_append(extra_array, strdup(tok2));
- } else if (strcasecmp(TAG_HW_ACC, tok1) == 0) {
- cur_info->hw_acc = strdup(tok2);
- } else if (strcasecmp(TAG_ALTERNATIVE_LOADER, tok1) == 0) {
- cur_info->alternative_loaders =
- g_list_append(cur_info->alternative_loaders,
- strdup(tok2));
- } else if (strcasecmp(TAG_CPU_THRESHOLD_MAX, tok1) == 0) {
- cur_info->cpu_threshold_max = atoi(tok2);
- } else if (strcasecmp(TAG_CPU_THRESHOLD_MIN, tok1) == 0) {
- cur_info->cpu_threshold_min = atoi(tok2);
- } else if (strcasecmp(TAG_ON_BOOT, tok1) == 0) {
- if (tok2 && strcasecmp(VAL_OFF, tok2) == 0)
- cur_info->on_boot = false;
- } else if (strcasecmp(TAG_HYDRA, tok1) == 0) {
- if (strcasecmp(VAL_ON, tok2) == 0)
- cur_info->is_hydra = 1;
- else
- cur_info->is_hydra = 0;
- } else if (strcasecmp(TAG_APP_CHECK, tok1) == 0) {
- if (tok2 && strcasecmp(VAL_OFF, tok2) == 0)
- cur_info->app_check = false;
- } else if (strcasecmp(TAG_ON_BOOT_TIMEOUT, tok1) == 0) {
- cur_info->on_boot_timeout = atoi(tok2);
- } else if (strcasecmp(TAG_SCHED_PRIORITY, tok1) == 0) {
- cur_info->sched_priority = atoi(tok2);
- if (cur_info->sched_priority < -20)
- cur_info->sched_priority = -20;
- else if (cur_info->sched_priority > 19)
- cur_info->sched_priority = 19;
- }
- }
-
- if (cur_info != NULL) {
- __flush_extra_array(cur_info->extra, key, extra_array);
- list = g_list_append(list, cur_info);
- }
-
- if (tok1)
- free(tok1);
- if (tok2)
- free(tok2);
-
- fclose(fp);
-
- return list;
-}
-
-GList *_loader_info_load_dir(const char *path)
-{
- DIR *dir_info;
- struct dirent *entry = NULL;
- GList *list = NULL;
- char buf[PATH_MAX];
- char *ext;
-
- dir_info = opendir(path);
- if (dir_info == NULL)
- return NULL;
-
- while ((entry = readdir(dir_info)) != NULL) {
- if (entry->d_name[0] == '.')
- continue;
- ext = strrchr(entry->d_name, '.');
- if (ext && !strcmp(ext, ".loader")) {
- snprintf(buf, sizeof(buf), "%s/%s", path, entry->d_name);
- list = __parse_file(list, buf);
- }
- }
- closedir(dir_info);
-
- 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;
-}
-
-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;
-
- if (data == NULL)
- return;
-
- info = (loader_info_t *)data;
-
- free(info->name);
- free(info->exe);
- if (info->app_types)
- g_list_free_full(info->app_types, free);
- free(info->hw_acc);
- if (info->extra)
- bundle_free(info->extra);
- if (info->alternative_loaders)
- g_list_free_full(info->alternative_loaders, free);
-
- free(info);
-}
-
-void _loader_info_dispose(GList *info)
-{
- g_list_free_full(info, __free_info);
-}
-
-static int __comp_str(gconstpointer a, gconstpointer b)
-{
- if (!a || !b)
- return -1;
- return strcmp(a, b);
-}
-
-static int __comp_app_type_with_hw_acc(gconstpointer a, gconstpointer b)
-{
- loader_info_t *info = (loader_info_t *)a;
-
- if (info == NULL || info->app_types == NULL || b == NULL)
- return -1;
-
- if (g_list_find_custom(info->app_types, b, __comp_str) &&
- (info->hw_acc == NULL || !strcasecmp(VAL_ON, info->hw_acc)))
- return 0;
-
- return -1;
-}
-
-static int __comp_app_type_with_sw_acc(gconstpointer a, gconstpointer b)
-{
- loader_info_t *info = (loader_info_t *)a;
-
- if (info == NULL || info->app_types == NULL || b == NULL)
- return -1;
-
- if (g_list_find_custom(info->app_types, b, __comp_str) &&
- (info->hw_acc == NULL || !strcasecmp(VAL_OFF, info->hw_acc)))
- return 0;
-
- return -1;
-}
-
-static int __comp_name(gconstpointer a, gconstpointer b)
-{
- loader_info_t *info = (loader_info_t *)a;
-
- if (info == NULL || info->name == NULL || b == NULL)
- return -1;
-
- return strcmp(info->name, b);
-}
-
-int _loader_info_find_type(GList *info, const char *app_type, bool hwacc)
-{
- GList *cur;
-
- if (hwacc) {
- cur = g_list_find_custom(info, app_type,
- __comp_app_type_with_hw_acc);
- } else {
- cur = g_list_find_custom(info, app_type,
- __comp_app_type_with_sw_acc);
- }
-
- if (cur == NULL)
- return -1;
-
- loader_info_t *cur_info = (loader_info_t *)cur->data;
-
- return cur_info->type;
-}
-
-int _loader_info_find_type_by_loader_name(GList *info, const char *loader_name)
-{
- GList *cur = NULL;
-
- cur = g_list_find_custom(info, loader_name, __comp_name);
- if (cur == NULL)
- return -1;
-
- loader_info_t *cur_info = (loader_info_t *)cur->data;
-
- return cur_info->type;
-}
-
-static int *__make_type_array(GList *info, GList *loaders, int *len)
-{
- int l;
- int *t;
- loader_info_t *i;
- GList *c;
- GList *cur;
- int j = 0;
-
- l = g_list_length(loaders);
-
- if (l <= 0)
- return NULL;
-
- t = malloc(sizeof(int) * l);
- if (!t)
- return NULL;
-
- *len = l;
-
- cur = loaders;
- while (cur) {
- c = g_list_find_custom(info, cur->data, __comp_name);
-
- if (c) {
- i = (loader_info_t *)c->data;
- t[j] = i->type;
- j++;
- }
-
- cur = g_list_next(cur);
- }
-
- return t;
-}
-
-int *_loader_get_alternative_types(GList *info, int type, int *len)
-{
- GList *cur;
- loader_info_t *i;
-
- if (!info)
- return NULL;
-
- cur = info;
- while (cur) {
- i = (loader_info_t *)cur->data;
- if (i->type == type) {
- if (!i->alternative_loaders)
- return NULL;
-
- return __make_type_array(info, i->alternative_loaders,
- len);
- }
- cur = g_list_next(cur);
- }
-
- return NULL;
-}
-
-int _loader_info_foreach(GList *info, loader_info_foreach_cb callback,
- void *data)
-{
- GList *cur;
- loader_info_t *i;
-
- if (!info || !callback)
- return -1;
-
- cur = info;
- while (cur) {
- i = (loader_info_t *)cur->data;
- callback(i, data);
- cur = g_list_next(cur);
- }
-
- return 0;
-}
-
-bool _loader_info_exist_app_type(loader_info_t *info, const char *app_type)
-{
- GList *list;
-
- list = g_list_find_custom(info->app_types, app_type, __comp_str);
- if (list)
- return true;
-
- return false;
-}
--- /dev/null
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#include <dirent.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <algorithm>
+#include <fstream>
+#include <sstream>
+#include <utility>
+
+#include "launchpad_common.h"
+#include "loader_info.hh"
+#include "util.hh"
+
+namespace launchpad {
+namespace {
+
+constexpr const char kTagLoader[] = "[LOADER]";
+constexpr const char kTagName[] = "NAME";
+constexpr const char kTagExe[] = "EXE";
+constexpr const char kTagAppType[] = "APP_TYPE";
+constexpr const char kTagDetectionMethod[] = "DETECTION_METHOD";
+constexpr const char kTagActivationMethod[] = "ACTIVATION_METHOD";
+constexpr const char kTagDeactivationMethod[] = "DEACTIVATION_METHOD";
+constexpr const char kTagTtl[] = "TTL";
+constexpr const char kTagTimeout[] = "TIMEOUT";
+constexpr const char kTagExtra[] = "EXTRA";
+constexpr const char kTagExtraArray[] = "EXTRA_ARRAY";
+constexpr const char kTagExtraArrayVal[] = "EXTRA_ARRAY_VAL";
+constexpr const char kTagAlternativeLoader[] = "ALTERNATIVE_LOADER";
+constexpr const char kTagHwAcc[] = "HW_ACC";
+constexpr const char kTagCpuThresholdMax[] = "CPU_THRESHOLD_MAX";
+constexpr const char kTagCpuThresholdMin[] = "CPU_THRESHOLD_MIN";
+constexpr const char kTagOnBoot[] = "ON_BOOT";
+constexpr const char kTagHydra[] = "HYDRA";
+constexpr const char kTagAppCheck[] = "APP_CHECK";
+constexpr const char kTagOnBootTimeout[] = "ON_BOOT_TIMEOUT";
+constexpr const char kTagSchedPriority[] = "SCHED_PRIORITY";
+
+constexpr const char kValOn[] = "ON";
+constexpr const char kValOff[] = "OFF";
+constexpr const char kValMethodTimeout[] = "TIMEOUT";
+constexpr const char kValMethodDemand[] = "DEMAND";
+constexpr const char kValMethodVisibility[] = "VISIBILITY";
+constexpr const char kValMethodRequest[] = "REQUEST";
+constexpr const char kValMethodAvailableMemory[] = "AVAILABLE_MEMORY";
+constexpr const char kValMethodTtl[] = "TTL";
+constexpr const char kValMethodOutOfMemory[] = "OUT_OF_MEMORY";
+
+} // namespace
+
+namespace fs = std::filesystem;
+
+void LoaderInfoInflator::ParseDetectionMethod(const LoaderInfoPtr& info,
+ std::string& tok_start,
+ std::istringstream& ss) {
+ std::string line = tok_start;
+ do {
+ auto tokens = Split(line, " |\t\r\n");
+ for (auto& token : tokens) {
+ if (token == kValMethodTimeout)
+ info->detection_method_ =
+ info->detection_method_ | LoaderMethod::Timeout;
+ else if (token == kValMethodVisibility)
+ info->detection_method_ =
+ info->detection_method_ | LoaderMethod::Visibility;
+ else if (token == kValMethodDemand)
+ info->detection_method_ =
+ info->detection_method_ | LoaderMethod::Demand;
+ }
+ } while (std::getline(ss, line));
+
+ info->detection_method_ = info->detection_method_ | LoaderMethod::Install;
+ _D("detection_method:%d", static_cast<int>(info->detection_method_));
+}
+
+void LoaderInfoInflator::ParseActivationMethod(const LoaderInfoPtr& info,
+ std::string& tok_start,
+ std::istringstream& ss) {
+ info->activation_method_ = LoaderMethod::Empty;
+ std::string line = tok_start;
+ do {
+ auto tokens = Split(line, " |\t\r\n");
+ for (auto& token : tokens) {
+ if (token == kValMethodRequest)
+ info->activation_method_ =
+ info->activation_method_ | LoaderMethod::Request;
+ else if (token == kValMethodAvailableMemory)
+ info->activation_method_ =
+ info->activation_method_ | LoaderMethod::AvailableMemory;
+ }
+ } while (std::getline(ss, line));
+
+ _D("activation_method:%d", static_cast<int>(info->activation_method_));
+}
+
+void LoaderInfoInflator::ParseDeactivationMethod(const LoaderInfoPtr& info,
+ std::string& tok_start,
+ std::istringstream& ss) {
+ info->deactivation_method_ = LoaderMethod::Empty;
+ std::string line = tok_start;
+ do {
+ auto tokens = Split(line, " |\t\r\n");
+ for (auto& token : tokens) {
+ if (token == kValMethodTtl)
+ info->deactivation_method_ =
+ info->deactivation_method_ | LoaderMethod::Ttl;
+ else if (token == kValMethodOutOfMemory)
+ info->deactivation_method_ =
+ info->deactivation_method_ | LoaderMethod::OutOfMemory;
+ }
+ } while (std::getline(ss, line));
+
+ _D("deactivation_method:%d", static_cast<int>(info->deactivation_method_));
+}
+
+void LoaderInfoInflator::ParseAppTypes(const LoaderInfoPtr& info,
+ std::string& tok_start,
+ std::istringstream& ss) {
+ std::string line = tok_start;
+ do {
+ auto tokens = Split(line, " |\t\r\n");
+ for (auto& token : tokens) {
+ info->app_types_.push_back(std::move(token));
+ }
+ } while (std::getline(ss, line));
+}
+
+void LoaderInfoInflator::Parse(std::vector<LoaderInfoPtr>& loader_info_list,
+ const fs::path& path) {
+ std::ifstream fp;
+ fp.open(path);
+ if (fp.fail())
+ return;
+
+ LoaderInfoPtr info;
+ std::string input;
+ std::string extra_array_key;
+ std::vector<std::string> extra_array;
+ while (std::getline(fp, input)) {
+ std::istringstream ss(input);
+ std::string tok1, tok2;
+ if (!(ss >> tok1))
+ continue;
+
+ if (strcasecmp(kTagLoader, tok1.c_str()) == 0) {
+ if (info != nullptr) {
+ if (!extra_array.empty()) {
+ info->extra_.Add(std::move(extra_array_key), std::move(extra_array));
+ extra_array.clear();
+ }
+
+ loader_info_list.push_back(std::move(info));
+ }
+
+ info = std::make_shared<LoaderInfo>();
+ continue;
+ }
+
+ if (!(ss >> tok2))
+ continue;
+ if (tok1.front() == '#' || info == nullptr)
+ continue;
+
+ std::string key;
+ std::transform(tok1.begin(), tok1.end(), std::back_inserter(key),
+ [](char ch) { return toupper(ch); });
+ if (kTagName == key) {
+ info->name_ = std::move(tok2);
+ } else if (kTagExe == key) {
+ info->exe_ = std::move(tok2);
+ } else if (kTagAppType == key) {
+ ParseAppTypes(info, tok2, ss);
+ } else if (kTagDetectionMethod == key) {
+ ParseDetectionMethod(info, tok2, ss);
+ } else if (kTagActivationMethod == key) {
+ ParseActivationMethod(info, tok2, ss);
+ } else if (kTagDeactivationMethod == key) {
+ ParseDeactivationMethod(info, tok2, ss);
+ } else if (kTagTtl == key) {
+ info->ttl_ = std::stoul(tok2);
+ } else if (kTagTimeout == key) {
+ info->timeout_val_ = std::stoi(tok2);
+ } else if (kTagExtra == key) {
+ std::string val;
+ if (ss >> val)
+ info->extra_.Add(std::move(tok2), std::move(val));
+ } else if (kTagExtraArray == key) {
+ if (!extra_array.empty()) {
+ info->extra_.Add(std::move(extra_array_key), std::move(extra_array));
+ extra_array.clear();
+ }
+ extra_array_key = std::move(tok2);
+ } else if (kTagExtraArrayVal == key) {
+ extra_array.push_back(std::move(tok2));
+ } else if (kTagHwAcc == key) {
+ info->hw_acc_ = std::move(tok2);
+ } else if (kTagAlternativeLoader == key) {
+ info->alternative_loaders_.push_back(std::move(tok2));
+ } else if (kTagCpuThresholdMax == key) {
+ info->cpu_threshold_max_ = std::stoi(tok2);
+ } else if (kTagCpuThresholdMin == key) {
+ info->cpu_threshold_min_ = std::stoi(tok2);
+ } else if (kTagOnBoot == key) {
+ if (kValOff == tok2)
+ info->on_boot_ = false;
+ } else if (kTagHydra == key) {
+ if (kValOn == tok2)
+ info->is_hydra_ = true;
+ else
+ info->is_hydra_ = false;
+ } else if (kTagAppCheck == key) {
+ if (kValOff == tok2)
+ info->app_check_ = false;
+ } else if (kTagOnBootTimeout == key) {
+ info->on_boot_timeout_ = std::stoi(tok2);
+ } else if (kTagSchedPriority == key) {
+ info->sched_priority_ = std::min(std::max(std::stoi(tok2), -20), 19);
+ }
+ }
+
+ fp.close();
+ if (info != nullptr) {
+ if (!extra_array.empty())
+ info->extra_.Add(std::move(extra_array_key), std::move(extra_array));
+
+ loader_info_list.push_back(std::move(info));
+ }
+}
+
+LoaderType LoaderInfo::GetType() const {
+ return type_;
+}
+
+const std::string& LoaderInfo::GetName() const {
+ return name_;
+}
+
+const std::string& LoaderInfo::GetExe() const {
+ return exe_;
+}
+
+int LoaderInfo::GetCpuThresholdMax() const {
+ return cpu_threshold_max_;
+}
+
+int LoaderInfo::GetCpuThresholdMin() const {
+ return cpu_threshold_min_;
+}
+
+unsigned int LoaderInfo::GetTtl() const {
+ return ttl_;
+}
+
+const std::vector<std::string>& LoaderInfo::GetAppTypes() const {
+ return app_types_;
+}
+
+LoaderMethod LoaderInfo::GetDetectionMethod() const {
+ return detection_method_;
+}
+
+LoaderMethod LoaderInfo::GetActivationMethod() const {
+ return activation_method_;
+}
+
+LoaderMethod LoaderInfo::GetDeactivationMethod() const {
+ return deactivation_method_;
+}
+
+const std::string& LoaderInfo::GetHwAcc() const {
+ return hw_acc_;
+}
+
+int LoaderInfo::GetOnbootTimeout() const {
+ return on_boot_timeout_;
+}
+
+int LoaderInfo::GetTimeoutVal() const {
+ return timeout_val_;
+}
+
+int LoaderInfo::GetSchedPriority() const {
+ return sched_priority_;
+}
+
+bool LoaderInfo::IsAppExists() const {
+ return app_exists_;
+}
+
+bool LoaderInfo::IsOnBoot() const {
+ return on_boot_;
+}
+
+bool LoaderInfo::IsHydraEnabled() const {
+ return is_hydra_;
+}
+
+bool LoaderInfo::IsNeededAppCheck() const {
+ return app_check_;
+}
+
+tizen_base::Bundle& LoaderInfo::GetExtra() {
+ return extra_;
+}
+
+void LoaderInfo::SetType(LoaderType type) {
+ type_ = type;
+}
+
+void LoaderInfo::SetAppExists(bool exists) {
+ app_exists_ = exists;
+}
+
+std::vector<LoaderInfoPtr> LoaderInfoInflator::Inflate(
+ const std::string_view path) {
+ fs::path p(path);
+ if (fs::is_directory(p) == false)
+ return {};
+
+ std::vector<LoaderInfoPtr> result;
+ for (auto& entry : fs::directory_iterator(p)) {
+ fs::path file(entry.path());
+ if (file.extension() == ".loader")
+ Parse(result, file);
+ }
+
+ return result;
+}
+
+LoaderInfoManager::LoaderInfoManager(std::string path): path_(std::move(path)) {
+
+}
+
+void LoaderInfoManager::Load() {
+ if (!loader_list_.empty())
+ return;
+
+ LoaderInfoInflator inflator;
+ loader_list_ = inflator.Inflate(path_);
+}
+
+void LoaderInfoManager::LoadFile(const std::string_view file) {
+ LoaderInfoInflator inflator;
+ fs::path p(path_);
+ inflator.Parse(loader_list_, p / file);
+}
+
+void LoaderInfoManager::Unload(const std::string_view loader_name) {
+ loader_list_.erase(std::remove_if(loader_list_.begin(), loader_list_.end(),
+ [&](const LoaderInfoPtr& info) -> bool {
+ return info->GetName() == loader_name;
+ }), loader_list_.end());
+}
+
+void LoaderInfoManager::Dispose() {
+ loader_list_.clear();
+}
+
+std::string LoaderInfoManager::FindLoaderPath(
+ const std::string_view loader_name) {
+ for (auto& info : loader_list_) {
+ if (info->GetName() == loader_name)
+ return info->GetExe();
+ }
+
+ return "";
+}
+
+LoaderInfoPtr LoaderInfoManager::FindLoaderInfo(
+ const std::string_view loader_name) {
+ for (auto& info : loader_list_) {
+ if (info->GetName() == loader_name)
+ return info;
+ }
+
+ return nullptr;
+}
+
+LoaderType LoaderInfoManager::FindHwType(const std::string_view app_type) {
+ for (auto& info : loader_list_) {
+ if (info->GetHwAcc().empty() || info->GetHwAcc() == kValOn) {
+ auto it = std::find_if(
+ info->GetAppTypes().begin(), info->GetAppTypes().end(),
+ [&](const std::string& type) -> bool { return type == app_type; });
+
+ if (it != info->GetAppTypes().end())
+ return info->GetType();
+ }
+ }
+
+ return LoaderType::Unsupported;
+}
+
+LoaderType LoaderInfoManager::FindSwType(const std::string_view app_type) {
+ for (auto& info : loader_list_) {
+ if (info->GetHwAcc().empty() || info->GetHwAcc() == kValOff) {
+ auto it = std::find_if(
+ info->GetAppTypes().begin(), info->GetAppTypes().end(),
+ [&](const std::string& type) -> bool { return type == app_type; });
+
+ if (it != info->GetAppTypes().end())
+ return info->GetType();
+ }
+ }
+
+ return LoaderType::Unsupported;
+}
+
+std::vector<LoaderType> LoaderInfoManager::GetAlternativeTypes(
+ LoaderType type) {
+ std::vector<LoaderType> result;
+ for (auto& info : loader_list_) {
+ if (info->GetType() == type) {
+ for (auto& alt_loader : info->alternative_loaders_) {
+ auto it = std::find_if(loader_list_.begin(), loader_list_.end(),
+ [&](const auto& li) -> bool {
+ return li->GetName() == alt_loader;
+ });
+
+ if (it != loader_list_.end()) {
+ result.push_back((*it)->GetType());
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+const std::vector<LoaderInfoPtr>& LoaderInfoManager::GetLoaderInfoList() const {
+ return loader_list_;
+}
+
+} // namespace launchpad
/*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2023 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.
* limitations under the License.
*/
-#ifndef __LAUNCHER_INFO_H__
-#define __LAUNCHER_INFO_H__
+#include "util.hh"
-#include <glib.h>
+#include <regex>
-typedef struct launcher_info_s *launcher_info_h;
+namespace launchpad {
-GList *_launcher_info_load(const char *path);
-void _launcher_info_unload(GList *info);
-launcher_info_h _launcher_info_find(GList *info_list, const char *app_type);
-const char *_launcher_info_get_exe(launcher_info_h launcher_info);
-GList *_launcher_info_get_extra_args(launcher_info_h launcher_info);
+std::vector<std::string> Split(const std::string& str,
+ const std::string& delim) {
+ const std::regex deli("[^" + delim + "]+");
+ std::vector<std::string> result;
+ for (auto i = std::sregex_iterator(str.begin(), str.end(), deli);
+ i != std::sregex_iterator(); ++i) {
+ result.push_back((*i).str());
+ }
-#endif /* __LAUNCHER_INFO_H__ */
+ return result;
+}
+
+} // namespace launchpad
#include <bundle.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
int _launchpad_plugin_prepare_app(const char *app_id, bundle *kb);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* __LAUNCHPAD_PLUGIN_H__ */