From 00c0107f79d35b0f20e4aa3e0759e8aa56f2d5f9 Mon Sep 17 00:00:00 2001 From: Changgyu Choi Date: Wed, 1 Feb 2023 16:05:39 +0900 Subject: [PATCH] Refactor launchpad to c++ We will refactor launchpad to c++ step by step. Changes: - debugger_info - launcher_info - loader_info Change-Id: I973d98b0669c4b752ba6cf7203f83e8c83085dc0 Signed-off-by: Changgyu Choi --- CMakeLists.txt | 2 +- src/launchpad-process-pool/CMakeLists.txt | 1 + src/launchpad-process-pool/inc/debugger_info.h | 35 - src/launchpad-process-pool/inc/debugger_info.hh | 66 + src/launchpad-process-pool/inc/launcher_info.hh | 56 + src/launchpad-process-pool/inc/launchpad_config.h | 8 + src/launchpad-process-pool/inc/launchpad_debug.h | 9 +- src/launchpad-process-pool/inc/launchpad_inotify.h | 8 + .../inc/launchpad_io_channel.h | 8 + src/launchpad-process-pool/inc/loader_info.h | 74 - src/launchpad-process-pool/inc/loader_info.hh | 153 + src/launchpad-process-pool/inc/util.hh | 40 + src/launchpad-process-pool/src/debugger_info.c | 326 -- src/launchpad-process-pool/src/debugger_info.cc | 180 + src/launchpad-process-pool/src/launcher_info.c | 257 -- src/launchpad-process-pool/src/launcher_info.cc | 145 + src/launchpad-process-pool/src/launchpad.c | 3571 -------------------- src/launchpad-process-pool/src/launchpad.cc | 3451 +++++++++++++++++++ .../{launchpad_config.c => launchpad_config.cc} | 1 - src/launchpad-process-pool/src/launchpad_dbus.c | 299 -- src/launchpad-process-pool/src/launchpad_dbus.cc | 277 ++ src/launchpad-process-pool/src/launchpad_debug.c | 451 --- src/launchpad-process-pool/src/launchpad_debug.cc | 412 +++ src/launchpad-process-pool/src/launchpad_inotify.c | 191 -- .../src/launchpad_inotify.cc | 187 + .../src/launchpad_io_channel.c | 174 - .../src/launchpad_io_channel.cc | 154 + .../src/{launchpad_log.c => launchpad_log.cc} | 66 +- src/launchpad-process-pool/src/launchpad_logger.c | 248 -- src/launchpad-process-pool/src/launchpad_logger.cc | 240 ++ .../src/launchpad_memory_monitor.c | 151 - .../src/launchpad_memory_monitor.cc | 141 + src/launchpad-process-pool/src/launchpad_signal.c | 413 --- src/launchpad-process-pool/src/launchpad_signal.cc | 395 +++ src/launchpad-process-pool/src/launchpad_worker.c | 186 - src/launchpad-process-pool/src/launchpad_worker.cc | 179 + src/launchpad-process-pool/src/loader_info.c | 609 ---- src/launchpad-process-pool/src/loader_info.cc | 452 +++ .../{inc/launcher_info.h => src/util.cc} | 27 +- src/lib/common/inc/launchpad_plugin.h | 8 + 40 files changed, 6617 insertions(+), 7034 deletions(-) delete mode 100644 src/launchpad-process-pool/inc/debugger_info.h create mode 100644 src/launchpad-process-pool/inc/debugger_info.hh create mode 100644 src/launchpad-process-pool/inc/launcher_info.hh delete mode 100644 src/launchpad-process-pool/inc/loader_info.h create mode 100644 src/launchpad-process-pool/inc/loader_info.hh create mode 100644 src/launchpad-process-pool/inc/util.hh delete mode 100644 src/launchpad-process-pool/src/debugger_info.c create mode 100644 src/launchpad-process-pool/src/debugger_info.cc delete mode 100644 src/launchpad-process-pool/src/launcher_info.c create mode 100644 src/launchpad-process-pool/src/launcher_info.cc delete mode 100644 src/launchpad-process-pool/src/launchpad.c create mode 100644 src/launchpad-process-pool/src/launchpad.cc rename src/launchpad-process-pool/src/{launchpad_config.c => launchpad_config.cc} (99%) delete mode 100644 src/launchpad-process-pool/src/launchpad_dbus.c create mode 100644 src/launchpad-process-pool/src/launchpad_dbus.cc delete mode 100644 src/launchpad-process-pool/src/launchpad_debug.c create mode 100644 src/launchpad-process-pool/src/launchpad_debug.cc delete mode 100644 src/launchpad-process-pool/src/launchpad_inotify.c create mode 100644 src/launchpad-process-pool/src/launchpad_inotify.cc delete mode 100644 src/launchpad-process-pool/src/launchpad_io_channel.c create mode 100644 src/launchpad-process-pool/src/launchpad_io_channel.cc rename src/launchpad-process-pool/src/{launchpad_log.c => launchpad_log.cc} (52%) delete mode 100644 src/launchpad-process-pool/src/launchpad_logger.c create mode 100644 src/launchpad-process-pool/src/launchpad_logger.cc delete mode 100644 src/launchpad-process-pool/src/launchpad_memory_monitor.c create mode 100644 src/launchpad-process-pool/src/launchpad_memory_monitor.cc delete mode 100644 src/launchpad-process-pool/src/launchpad_signal.c create mode 100644 src/launchpad-process-pool/src/launchpad_signal.cc delete mode 100644 src/launchpad-process-pool/src/launchpad_worker.c create mode 100644 src/launchpad-process-pool/src/launchpad_worker.cc delete mode 100644 src/launchpad-process-pool/src/loader_info.c create mode 100644 src/launchpad-process-pool/src/loader_info.cc rename src/launchpad-process-pool/{inc/launcher_info.h => src/util.cc} (52%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1708bfa..7c79e5f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,7 +26,7 @@ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_FILE_OFFSET_BITS=64") 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") diff --git a/src/launchpad-process-pool/CMakeLists.txt b/src/launchpad-process-pool/CMakeLists.txt index b0af4fe..3175dac 100644 --- a/src/launchpad-process-pool/CMakeLists.txt +++ b/src/launchpad-process-pool/CMakeLists.txt @@ -2,6 +2,7 @@ AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/src 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} diff --git a/src/launchpad-process-pool/inc/debugger_info.h b/src/launchpad-process-pool/inc/debugger_info.h deleted file mode 100644 index ecaae3a..0000000 --- a/src/launchpad-process-pool/inc/debugger_info.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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 - -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__ */ diff --git a/src/launchpad-process-pool/inc/debugger_info.hh b/src/launchpad-process-pool/inc/debugger_info.hh new file mode 100644 index 0000000..83a578d --- /dev/null +++ b/src/launchpad-process-pool/inc/debugger_info.hh @@ -0,0 +1,66 @@ +/* + * 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 +#include +#include +#include +#include + +namespace launchpad { + +class DebuggerInfo { + public: + const std::string& GetName() const; + const std::string& GetExe() const; + const std::vector& GetAppTypes() const; + const std::vector& GetExtraKeyList() const; + const std::vector& GetExtraEnvList() const; + const std::vector& GetUnlinkList() const; + const std::string& GetAttachInfo() const; + const std::vector& GetLastExtraKeyList() const; + const std::vector& GetDefaultOptList() const; + + private: + std::string name_; + std::string exe_; + std::vector app_types_; + std::vector extra_key_list_; + std::vector extra_env_list_; + std::vector unlink_list_; + std::string attach_; + std::vector last_extra_key_list_; + std::vector default_opt_list_; + + friend class DebuggerInfoInflator; +}; + +using DebuggerInfoPtr = std::shared_ptr; + +class DebuggerInfoInflator { + public: + std::vector Inflate(const std::string_view path); + private: + void Parse(std::vector& debugger_info_list, + const std::filesystem::path& path); +}; + +} // namespace launchpad + +#endif // DEBUGGER_INFO_HH_ diff --git a/src/launchpad-process-pool/inc/launcher_info.hh b/src/launchpad-process-pool/inc/launcher_info.hh new file mode 100644 index 0000000..0a7c178 --- /dev/null +++ b/src/launchpad-process-pool/inc/launcher_info.hh @@ -0,0 +1,56 @@ +/* + * 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 +#include +#include +#include +#include + +namespace launchpad { + +class LauncherInfo { + public: + const std::string& GetName() const; + const std::string& GetExe() const; + const std::vector& GetAppTypes() const; + const std::vector& GetExtraArgs() const; + + private: + std::string name_; + std::string exe_; + std::vector app_types_; + std::vector extra_args_; + friend class LauncherInfoInflator; +}; + +using LauncherInfoPtr = std::shared_ptr; + +class LauncherInfoInflator { + public: + std::vector Inflate(const std::string_view path); + + private: + void Parse(std::vector& launcher_info_list, + const std::filesystem::path& path); +}; + +} // namespace launchpad + +#endif /* LAUNCHER_INFO_HH_ */ diff --git a/src/launchpad-process-pool/inc/launchpad_config.h b/src/launchpad-process-pool/inc/launchpad_config.h index 0f769db..23fd60b 100644 --- a/src/launchpad-process-pool/inc/launchpad_config.h +++ b/src/launchpad-process-pool/inc/launchpad_config.h @@ -17,6 +17,10 @@ #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, @@ -37,4 +41,8 @@ int _config_init(void); void _config_fini(void); +#ifdef __cplusplus +} +#endif + #endif /* __LAUNCHPAD_CONFIG_H__ */ diff --git a/src/launchpad-process-pool/inc/launchpad_debug.h b/src/launchpad-process-pool/inc/launchpad_debug.h index 1697900..7411ba1 100644 --- a/src/launchpad-process-pool/inc/launchpad_debug.h +++ b/src/launchpad-process-pool/inc/launchpad_debug.h @@ -20,6 +20,10 @@ #include #include +#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); @@ -29,5 +33,8 @@ void _debug_prepare_debugger(bundle *kb); int _debug_init(void); void _debug_fini(void); -#endif /* __LAUNCHPAD_DEBUG_H__ */ +#ifdef __cplusplus +} +#endif +#endif /* __LAUNCHPAD_DEBUG_H__ */ diff --git a/src/launchpad-process-pool/inc/launchpad_inotify.h b/src/launchpad-process-pool/inc/launchpad_inotify.h index 4db903e..77d1122 100644 --- a/src/launchpad-process-pool/inc/launchpad_inotify.h +++ b/src/launchpad-process-pool/inc/launchpad_inotify.h @@ -19,6 +19,10 @@ #include #include +#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, @@ -32,3 +36,7 @@ void _inotify_rm_watch(inotify_watch_info_h handle); int _inotify_init(void); void _inotify_fini(void); + +#ifdef __cplusplus +} +#endif diff --git a/src/launchpad-process-pool/inc/launchpad_io_channel.h b/src/launchpad-process-pool/inc/launchpad_io_channel.h index b9ae867..25fab13 100644 --- a/src/launchpad-process-pool/inc/launchpad_io_channel.h +++ b/src/launchpad-process-pool/inc/launchpad_io_channel.h @@ -27,6 +27,10 @@ typedef enum { 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); @@ -38,3 +42,7 @@ io_channel_h _io_channel_create(int fd, io_condition_e condition, 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 diff --git a/src/launchpad-process-pool/inc/loader_info.h b/src/launchpad-process-pool/inc/loader_info.h deleted file mode 100644 index 6d44b1d..0000000 --- a/src/launchpad-process-pool/inc/loader_info.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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 -#include -#include - -#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); diff --git a/src/launchpad-process-pool/inc/loader_info.hh b/src/launchpad-process-pool/inc/loader_info.hh new file mode 100644 index 0000000..d96e029 --- /dev/null +++ b/src/launchpad-process-pool/inc/loader_info.hh @@ -0,0 +1,153 @@ +/* + * 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 + +#include +#include +#include +#include +#include + +#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& 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 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 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; + +class LoaderInfoInflator { + public: + std::vector Inflate(const std::string_view path); + void Parse(std::vector& 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 GetAlternativeTypes(LoaderType type); + const std::vector& GetLoaderInfoList() const; + + private: + std::string path_; + std::vector loader_list_; +}; + +} // namespace launchpad + +#endif // LOADER_INFO_HH_ diff --git a/src/launchpad-process-pool/inc/util.hh b/src/launchpad-process-pool/inc/util.hh new file mode 100644 index 0000000..3fffdf0 --- /dev/null +++ b/src/launchpad-process-pool/inc/util.hh @@ -0,0 +1,40 @@ +/* + * 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 +#include + +namespace launchpad { + +template +E operator|(E a, E b) { + return static_cast(static_cast(a) | static_cast(b)); +} + +template +bool operator==(E a, int x) { + return static_cast(a) == x; +} + +std::vector Split(const std::string& str, + const std::string& delim); + +} // namespace launchpad + +#endif // UTIL_HH_ diff --git a/src/launchpad-process-pool/src/debugger_info.c b/src/launchpad-process-pool/src/debugger_info.c deleted file mode 100644 index e043e58..0000000 --- a/src/launchpad-process-pool/src/debugger_info.c +++ /dev/null @@ -1,326 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include - -#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; -} diff --git a/src/launchpad-process-pool/src/debugger_info.cc b/src/launchpad-process-pool/src/debugger_info.cc new file mode 100644 index 0000000..8cbeaf7 --- /dev/null +++ b/src/launchpad-process-pool/src/debugger_info.cc @@ -0,0 +1,180 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#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& 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(); + 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& DebuggerInfo::GetAppTypes() const { + return app_types_; +} + +const std::vector& DebuggerInfo::GetExtraKeyList() const { + return extra_key_list_; +} + +const std::vector& DebuggerInfo::GetExtraEnvList() const { + return extra_env_list_; +} + +const std::vector& DebuggerInfo::GetUnlinkList() const { + return unlink_list_; +} + +const std::string& DebuggerInfo::GetAttachInfo() const { + return attach_; +} + +const std::vector& DebuggerInfo::GetLastExtraKeyList() const { + return last_extra_key_list_; +} + +const std::vector& DebuggerInfo::GetDefaultOptList() const { + return default_opt_list_; +} + +std::vector DebuggerInfoInflator::Inflate( + const std::string_view path) { + fs::path p(path); + if (fs::is_directory(p) == false) + return {}; + + std::vector result; + for (auto& entry : fs::directory_iterator(p)) { + fs::path file(entry.path()); + if (file.extension() == ".debugger") + Parse(result, file); + } + + return result; +} + +} // namespace launchpad diff --git a/src/launchpad-process-pool/src/launcher_info.c b/src/launchpad-process-pool/src/launcher_info.c deleted file mode 100644 index 89a7ccd..0000000 --- a/src/launchpad-process-pool/src/launcher_info.c +++ /dev/null @@ -1,257 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include - -#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; -} diff --git a/src/launchpad-process-pool/src/launcher_info.cc b/src/launchpad-process-pool/src/launcher_info.cc new file mode 100644 index 0000000..7387323 --- /dev/null +++ b/src/launchpad-process-pool/src/launcher_info.cc @@ -0,0 +1,145 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#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& LauncherInfo::GetAppTypes() const { + return app_types_; +} + +const std::vector& LauncherInfo::GetExtraArgs() const { + return extra_args_; +} + +void LauncherInfoInflator::Parse( + std::vector& 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(); + 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 LauncherInfoInflator::Inflate( + const std::string_view path) { + fs::path p(path); + if (fs::is_directory(p) == false) + return {}; + + std::vector result; + for (auto& entry : fs::directory_iterator(p)) { + fs::path file(entry.path()); + if (file.extension() == ".launcher") { + Parse(result, file); + } + } + + return result; +} + +} // namespace launchpad diff --git a/src/launchpad-process-pool/src/launchpad.c b/src/launchpad-process-pool/src/launchpad.c deleted file mode 100644 index e5ca890..0000000 --- a/src/launchpad-process-pool/src/launchpad.c +++ /dev/null @@ -1,3571 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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; -} diff --git a/src/launchpad-process-pool/src/launchpad.cc b/src/launchpad-process-pool/src/launchpad.cc new file mode 100644 index 0000000..a71168f --- /dev/null +++ b/src/launchpad-process-pool/src/launchpad.cc @@ -0,0 +1,3451 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#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 loader_info_manager; +std::unique_ptr app_defined_loader_info_manager; +int user_slot_offset; +GList* candidate_slot_list; +app_labels_monitor* label_monitor; +std::vector 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(launchpad::LoaderType::Dynamic) || + type == static_cast(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(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(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(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(calloc(1, sizeof(candidate_info_t))); + if (info == nullptr) { + _E("calloc() is failed"); + return -ENOMEM; + } + + info->argv = static_cast(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(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(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(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(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(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(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(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_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(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_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(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( + 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(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(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(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( + launchpad::LoaderMethod::Timeout | launchpad::LoaderMethod::Visibility); + slot_info.activation_method = + static_cast(launchpad::LoaderMethod::Request | + launchpad::LoaderMethod::AvailableMemory); + slot_info.deactivation_method = static_cast( + 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(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(launchpad::LoaderMethod::Timeout) | static_cast(launchpad::LoaderMethod::Visibility); + slot_info.activation_method = static_cast(launchpad::LoaderMethod::Request) | static_cast(launchpad::LoaderMethod::AvailableMemory); + slot_info.deactivation_method = static_cast(launchpad::LoaderMethod::Ttl) | static_cast(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(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(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(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(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(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(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(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(method)) + __deactivate_slot(cpc); + break; + case launchpad::LoaderMethod::AvailableMemory: + if (force || cpc->activation_method & static_cast(method)) + __activate_slot(cpc); + break; + case launchpad::LoaderMethod::Request: + if (force || cpc->activation_method & static_cast(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(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(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(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(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(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( + 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(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(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(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(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( + static_cast(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(info->GetDetectionMethod()); + slot_info.activation_method = static_cast(info->GetActivationMethod()); + slot_info.deactivation_method = static_cast(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( + static_cast(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(info->GetType())); + _print_hwc_log("candidate slot. app-type(%s) loader-type(%d)", buf, + static_cast(info->GetType())); + } +} + +static int __add_default_slots(void) { + loader_info_manager = + std::make_unique(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( + 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(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(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(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; +} diff --git a/src/launchpad-process-pool/src/launchpad_config.c b/src/launchpad-process-pool/src/launchpad_config.cc similarity index 99% rename from src/launchpad-process-pool/src/launchpad_config.c rename to src/launchpad-process-pool/src/launchpad_config.cc index b1be6ea..33a448f 100644 --- a/src/launchpad-process-pool/src/launchpad_config.c +++ b/src/launchpad-process-pool/src/launchpad_config.cc @@ -14,7 +14,6 @@ * limitations under the License. */ -#define _GNU_SOURCE #include #include #include diff --git a/src/launchpad-process-pool/src/launchpad_dbus.c b/src/launchpad-process-pool/src/launchpad_dbus.c deleted file mode 100644 index 0b3f298..0000000 --- a/src/launchpad-process-pool/src/launchpad_dbus.c +++ /dev/null @@ -1,299 +0,0 @@ -/* - * 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 -#include -#include -#include - -#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); -} diff --git a/src/launchpad-process-pool/src/launchpad_dbus.cc b/src/launchpad-process-pool/src/launchpad_dbus.cc new file mode 100644 index 0000000..7beff3d --- /dev/null +++ b/src/launchpad-process-pool/src/launchpad_dbus.cc @@ -0,0 +1,277 @@ +/* + * 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 +#include +#include +#include + +#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(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(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); +} diff --git a/src/launchpad-process-pool/src/launchpad_debug.c b/src/launchpad-process-pool/src/launchpad_debug.c deleted file mode 100644 index da59159..0000000 --- a/src/launchpad-process-pool/src/launchpad_debug.c +++ /dev/null @@ -1,451 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include -#include -#include - -#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); -} diff --git a/src/launchpad-process-pool/src/launchpad_debug.cc b/src/launchpad-process-pool/src/launchpad_debug.cc new file mode 100644 index 0000000..12f8bdc --- /dev/null +++ b/src/launchpad-process-pool/src/launchpad_debug.cc @@ -0,0 +1,412 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#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 __debugger_info_list; +launchpad::DebuggerInfoPtr __debugger_info; +std::vector __debug_argv_list; +std::vector __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(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(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(); +} diff --git a/src/launchpad-process-pool/src/launchpad_inotify.c b/src/launchpad-process-pool/src/launchpad_inotify.c deleted file mode 100644 index 9130fa2..0000000 --- a/src/launchpad-process-pool/src/launchpad_inotify.c +++ /dev/null @@ -1,191 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include - -#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); -} diff --git a/src/launchpad-process-pool/src/launchpad_inotify.cc b/src/launchpad-process-pool/src/launchpad_inotify.cc new file mode 100644 index 0000000..2afc91a --- /dev/null +++ b/src/launchpad-process-pool/src/launchpad_inotify.cc @@ -0,0 +1,187 @@ +/* + * 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 +#include +#include +#include +#include +#include + +#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(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( + 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(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); +} diff --git a/src/launchpad-process-pool/src/launchpad_io_channel.c b/src/launchpad-process-pool/src/launchpad_io_channel.c deleted file mode 100644 index 31529a3..0000000 --- a/src/launchpad-process-pool/src/launchpad_io_channel.c +++ /dev/null @@ -1,174 +0,0 @@ -/* - * 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 -#include -#include -#include - -#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; -} diff --git a/src/launchpad-process-pool/src/launchpad_io_channel.cc b/src/launchpad-process-pool/src/launchpad_io_channel.cc new file mode 100644 index 0000000..5987793 --- /dev/null +++ b/src/launchpad-process-pool/src/launchpad_io_channel.cc @@ -0,0 +1,154 @@ +/* + * 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 +#include +#include +#include + +#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(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(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(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; +} diff --git a/src/launchpad-process-pool/src/launchpad_log.c b/src/launchpad-process-pool/src/launchpad_log.cc similarity index 52% rename from src/launchpad-process-pool/src/launchpad_log.c rename to src/launchpad-process-pool/src/launchpad_log.cc index fc5d698..59128ab 100644 --- a/src/launchpad-process-pool/src/launchpad_log.c +++ b/src/launchpad-process-pool/src/launchpad_log.cc @@ -14,10 +14,9 @@ * limitations under the License. */ -#define _GNU_SOURCE +#include #include #include -#include #include "launchpad_config.h" #include "launchpad_log.h" @@ -29,47 +28,44 @@ 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); } diff --git a/src/launchpad-process-pool/src/launchpad_logger.c b/src/launchpad-process-pool/src/launchpad_logger.c deleted file mode 100644 index d6b99d8..0000000 --- a/src/launchpad-process-pool/src/launchpad_logger.c +++ /dev/null @@ -1,248 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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; -} diff --git a/src/launchpad-process-pool/src/launchpad_logger.cc b/src/launchpad-process-pool/src/launchpad_logger.cc new file mode 100644 index 0000000..592d73e --- /dev/null +++ b/src/launchpad-process-pool/src/launchpad_logger.cc @@ -0,0 +1,240 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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(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; +} diff --git a/src/launchpad-process-pool/src/launchpad_memory_monitor.c b/src/launchpad-process-pool/src/launchpad_memory_monitor.c deleted file mode 100644 index d4d4b2d..0000000 --- a/src/launchpad-process-pool/src/launchpad_memory_monitor.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * 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 -#include -#include -#include -#include - -#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(); -} diff --git a/src/launchpad-process-pool/src/launchpad_memory_monitor.cc b/src/launchpad-process-pool/src/launchpad_memory_monitor.cc new file mode 100644 index 0000000..d2b60ca --- /dev/null +++ b/src/launchpad-process-pool/src/launchpad_memory_monitor.cc @@ -0,0 +1,141 @@ +/* + * 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 +#include +#include +#include +#include + +#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(); +} diff --git a/src/launchpad-process-pool/src/launchpad_signal.c b/src/launchpad-process-pool/src/launchpad_signal.c deleted file mode 100644 index 6212ca4..0000000 --- a/src/launchpad-process-pool/src/launchpad_signal.c +++ /dev/null @@ -1,413 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include -#include -#include - -#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(); -} diff --git a/src/launchpad-process-pool/src/launchpad_signal.cc b/src/launchpad-process-pool/src/launchpad_signal.cc new file mode 100644 index 0000000..ca305b0 --- /dev/null +++ b/src/launchpad-process-pool/src/launchpad_signal.cc @@ -0,0 +1,395 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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(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(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(); +} diff --git a/src/launchpad-process-pool/src/launchpad_worker.c b/src/launchpad-process-pool/src/launchpad_worker.c deleted file mode 100644 index 019e4a2..0000000 --- a/src/launchpad-process-pool/src/launchpad_worker.c +++ /dev/null @@ -1,186 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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); -} diff --git a/src/launchpad-process-pool/src/launchpad_worker.cc b/src/launchpad-process-pool/src/launchpad_worker.cc new file mode 100644 index 0000000..15b53a5 --- /dev/null +++ b/src/launchpad-process-pool/src/launchpad_worker.cc @@ -0,0 +1,179 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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(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(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); +} diff --git a/src/launchpad-process-pool/src/loader_info.c b/src/launchpad-process-pool/src/loader_info.c deleted file mode 100644 index c43986f..0000000 --- a/src/launchpad-process-pool/src/loader_info.c +++ /dev/null @@ -1,609 +0,0 @@ -/* - * 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 -#include -#include -#include -#include - -#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; -} diff --git a/src/launchpad-process-pool/src/loader_info.cc b/src/launchpad-process-pool/src/loader_info.cc new file mode 100644 index 0000000..548dfe1 --- /dev/null +++ b/src/launchpad-process-pool/src/loader_info.cc @@ -0,0 +1,452 @@ +/* + * 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 +#include +#include +#include +#include + +#include +#include +#include +#include + +#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(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(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(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& 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 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(); + 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& 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 LoaderInfoInflator::Inflate( + const std::string_view path) { + fs::path p(path); + if (fs::is_directory(p) == false) + return {}; + + std::vector 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 LoaderInfoManager::GetAlternativeTypes( + LoaderType type) { + std::vector 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& LoaderInfoManager::GetLoaderInfoList() const { + return loader_list_; +} + +} // namespace launchpad diff --git a/src/launchpad-process-pool/inc/launcher_info.h b/src/launchpad-process-pool/src/util.cc similarity index 52% rename from src/launchpad-process-pool/inc/launcher_info.h rename to src/launchpad-process-pool/src/util.cc index c8a470b..172d1bd 100644 --- a/src/launchpad-process-pool/inc/launcher_info.h +++ b/src/launchpad-process-pool/src/util.cc @@ -1,5 +1,5 @@ /* - * 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. @@ -14,17 +14,22 @@ * limitations under the License. */ -#ifndef __LAUNCHER_INFO_H__ -#define __LAUNCHER_INFO_H__ +#include "util.hh" -#include +#include -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 Split(const std::string& str, + const std::string& delim) { + const std::regex deli("[^" + delim + "]+"); + std::vector 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 diff --git a/src/lib/common/inc/launchpad_plugin.h b/src/lib/common/inc/launchpad_plugin.h index f2cf987..d8b7123 100644 --- a/src/lib/common/inc/launchpad_plugin.h +++ b/src/lib/common/inc/launchpad_plugin.h @@ -19,6 +19,14 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + int _launchpad_plugin_prepare_app(const char *app_id, bundle *kb); +#ifdef __cplusplus +} +#endif + #endif /* __LAUNCHPAD_PLUGIN_H__ */ -- 2.7.4