diff options
author | jk7744.park <jk7744.park@samsung.com> | 2015-09-08 22:15:17 +0900 |
---|---|---|
committer | jk7744.park <jk7744.park@samsung.com> | 2015-09-08 22:15:17 +0900 |
commit | 20e0f2493de6339a36ac3fee61cf3d4095413510 (patch) | |
tree | 83c55556ee8cf4f10324da184309ddd518f3bede | |
parent | 180a999662b346e65efdee5ea61d7dfa90ac8d8d (diff) | |
download | launchpad-tizen_2.3.1.tar.gz launchpad-tizen_2.3.1.tar.bz2 launchpad-tizen_2.3.1.zip |
tizen 2.3.1 releasetizen_2.3.1_releasesubmit/tizen_2.3.1/20150915.080252tizen_2.3.1
-rw-r--r-- | CMakeLists.txt | 89 | ||||
-rw-r--r-- | LICENSE | 202 | ||||
-rw-r--r-- | launchpad.manifest | 17 | ||||
-rw-r--r-- | native/launchpad_native.c | 814 | ||||
-rw-r--r-- | native/native_preload.h | 109 | ||||
-rw-r--r-- | packaging/launchpad-native-preload-list.txt | 19 | ||||
-rw-r--r-- | packaging/launchpad-native.service | 13 | ||||
-rw-r--r-- | packaging/launchpad-process-pool-preload-list.txt | 0 | ||||
-rw-r--r-- | packaging/launchpad-process-pool.service | 13 | ||||
-rw-r--r-- | packaging/launchpad.spec | 129 | ||||
-rw-r--r-- | process_pool/launchpad.c | 1381 | ||||
-rw-r--r-- | process_pool/process_pool.c | 283 | ||||
-rw-r--r-- | process_pool/process_pool.h | 44 | ||||
-rw-r--r-- | process_pool/process_pool_preload.h | 109 | ||||
-rw-r--r-- | process_pool/smack_util.c | 241 | ||||
-rw-r--r-- | process_pool/smack_util.h | 22 |
16 files changed, 3485 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..ad5dc07 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,89 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +SET (this_target launchpad) + +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(${this_target} REQUIRED + aul + dlog + ecore + libprivilege-control + libsmack + deviced + elementary + libsystemd-daemon + ) + +FOREACH(flag ${${this_target}_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Wl,-zdefs" ) +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden") +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fpic") +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fdata-sections -ffunction-sections -Wl,--gc-sections") +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -D_FILE_OFFSET_BITS=64") +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -I/usr/include/aul/launch -I/usr/include/aul/launchpad") +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}") +SET(CMAKE_C_FLAGS_DEBUG "-O0 -g") +SET(CMAKE_C_FLAGS_RELEASE "-O2") +SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed") +SET(CMAKE_SKIP_BUILD_RPATH TRUE) + +ADD_DEFINITIONS("-DSHARE_PREFIX=\"/usr/share/aul\"") +IF(_APPFW_FEATURE_PRIORITY_CHANGE) + ADD_DEFINITIONS("-D_APPFW_FEATURE_PRIORITY_CHANGE") +ENDIF(_APPFW_FEATURE_PRIORITY_CHANGE) + +IF(_APPFW_FEATURE_PROCESS_POOL) +IF(_APPFW_FEATURE_PROCESS_POOL_COMMON) + ADD_DEFINITIONS("-D_APPFW_FEATURE_PROCESS_POOL_COMMON") +ENDIF(_APPFW_FEATURE_PROCESS_POOL_COMMON) +ADD_DEFINITIONS("-D_APPFW_FEATURE_PROCESS_POOL") +IF(_APPFW_FEATURE_PROCESS_POOL_HW_RENDERING) + ADD_DEFINITIONS("-D_APPFW_FEATURE_PROCESS_POOL_HW_RENDERING") +ENDIF(_APPFW_FEATURE_PROCESS_POOL_HW_RENDERING) + +SET(LAUNCHPAD_PROCESS_POOL "launchpad-process-pool") + +SET(${LAUNCHPAD_PROCESS_POOL}_SOURCE_FILES + process_pool/launchpad.c + process_pool/process_pool.c + process_pool/smack_util.c + ) +ADD_EXECUTABLE(${LAUNCHPAD_PROCESS_POOL} ${${LAUNCHPAD_PROCESS_POOL}_SOURCE_FILES}) + +TARGET_LINK_LIBRARIES(${LAUNCHPAD_PROCESS_POOL} aul_mods launchpad_common) +TARGET_LINK_LIBRARIES(${LAUNCHPAD_PROCESS_POOL} aul) +TARGET_LINK_LIBRARIES(${LAUNCHPAD_PROCESS_POOL} "-ldl -pie") +TARGET_LINK_LIBRARIES(${LAUNCHPAD_PROCESS_POOL} ${${this_target}_LDFLAGS}) + +SET_TARGET_PROPERTIES(${LAUNCHPAD_PROCESS_POOL} + PROPERTIES SKIP_BUILD_RPATH TRUE + ) # remove rpath option that is automatically generated by cmake. + +INSTALL(TARGETS ${LAUNCHPAD_PROCESS_POOL} DESTINATION bin) +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/packaging/launchpad-process-pool-preload-list.txt DESTINATION share/aul) +ENDIF(_APPFW_FEATURE_PROCESS_POOL) + +IF(_APPFW_FEATURE_NATIVE_LAUNCHPAD) +ADD_DEFINITIONS("-D_APPFW_FEATURE_NATIVE_LAUNCHPAD") + +SET(LAUNCHPAD_NATIVE "launchpad-native") + +SET(${LAUNCHPAD_NATIVE}_SOURCE_FILES + native/launchpad_native.c + ) +ADD_EXECUTABLE(${LAUNCHPAD_NATIVE} ${${LAUNCHPAD_NATIVE}_SOURCE_FILES}) + +TARGET_LINK_LIBRARIES(${LAUNCHPAD_NATIVE} aul_mods launchpad_common) +TARGET_LINK_LIBRARIES(${LAUNCHPAD_NATIVE} aul) +TARGET_LINK_LIBRARIES(${LAUNCHPAD_NATIVE} "-ldl") +TARGET_LINK_LIBRARIES(${LAUNCHPAD_NATIVE} ${${this_target}_LDFLAGS}) + +SET_TARGET_PROPERTIES(${LAUNCHPAD_NATIVE} + PROPERTIES SKIP_BUILD_RPATH TRUE + ) # remove rpath option that is automatically generated by cmake. + +INSTALL(TARGETS ${LAUNCHPAD_NATIVE} DESTINATION bin) +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/packaging/launchpad-native-preload-list.txt DESTINATION share/aul) +ENDIF(_APPFW_FEATURE_NATIVE_LAUNCHPAD) @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/launchpad.manifest b/launchpad.manifest new file mode 100644 index 0000000..4302722 --- /dev/null +++ b/launchpad.manifest @@ -0,0 +1,17 @@ +<manifest> + <define> + <domain name="launchpad"/> + <request> + <smack request="aul::launch" type="x"/> + <smack request="aul::terminate" type="x"/> + <smack request="security-server::api-privilege-by-pid" type="w"/> + <smack request="system::share" type="rwxat"/> + <smack request="sound_server" type="rwx"/> + <smack request="system::homedir" type="rwxat"/> + <smack request="pulseaudio" type="rwxat"/> + </request> + </define> + <request> + <domain name="launchpad"/> + </request> +</manifest> diff --git a/native/launchpad_native.c b/native/launchpad_native.c new file mode 100644 index 0000000..f9409e6 --- /dev/null +++ b/native/launchpad_native.c @@ -0,0 +1,814 @@ +/* + * Copyright (c) 2014 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 <stdio.h> +#include <string.h> +#include <dlfcn.h> +#include <X11/Xlib.h> +#include <sys/types.h> +#include <signal.h> +#include <dirent.h> +#include <fcntl.h> +#include <stdlib.h> +#include <sys/wait.h> +#include <poll.h> +#include <sys/prctl.h> +#include <malloc.h> +#include <sys/resource.h> + +#include "app_sock.h" +#include "aul.h" + +#include "config.h" + +#include "menu_db_util.h" +#include "simple_util.h" +#include "access_control.h" +#include "preload.h" +#include "preexec.h" +#include "perf.h" +#include "sigchild.h" +#include "aul_util.h" + +#include "heap_dbg.h" + +#include "util_x.h" + +#include "gl.h" + +#include <sqlite3.h> + +#include "native_preload.h" + +#define _static_ static inline +#define POLLFD_MAX 1 +#define SQLITE_FLUSH_MAX (1048576) /* (1024*1024) */ +#define AUL_POLL_CNT 15 +#define AUL_PR_NAME 16 + + +static char *launchpad_cmdline; +static char *__appid = NULL; +static int initialized = 0; + +_static_ void __set_env(app_info_from_db * menu_info, bundle * kb); +_static_ int __prepare_exec(const char *pkg_name, + const char *app_path, app_info_from_db * menu_info, + bundle * kb); +_static_ int __fake_launch_app(int cmd, int pid, bundle * kb); +_static_ char **__create_argc_argv(bundle * kb, int *margc); +_static_ int __normal_fork_exec(int argc, char **argv); +_static_ void __real_launch(const char *app_path, bundle * kb); +static inline int __parser(const char *arg, char *out, int out_size); +_static_ void __modify_bundle(bundle * kb, int caller_pid, + app_info_from_db * menu_info, int cmd); +_static_ int __child_raise_win_by_x(int pid, void *priv); +_static_ int __raise_win_by_x(int pid); +_static_ int __send_to_sigkill(int pid); +_static_ int __term_app(int pid); +_static_ int __resume_app(int pid); +_static_ int __real_send(int clifd, int ret); +_static_ void __send_result_to_caller(int clifd, int ret); +_static_ void __launchpad_main_loop(int main_fd); +_static_ int __launchpad_pre_init(int argc, char **argv); +_static_ int __launchpad_post_init(); + +extern ail_error_e ail_db_close(void); + +_static_ void __set_env(app_info_from_db * menu_info, bundle * kb) +{ + const char *str; + + setenv("PKG_NAME", _get_pkgname(menu_info), 1); + + USE_ENGINE("gl") + + str = bundle_get_val(kb, AUL_K_STARTTIME); + if (str != NULL) + setenv("APP_START_TIME", str, 1); + + if (menu_info->hwacc != NULL) + setenv("HWACC", menu_info->hwacc, 1); + if (menu_info->taskmanage != NULL) + setenv("TASKMANAGE", menu_info->taskmanage, 1); +} + +_static_ int __prepare_exec(const char *pkg_name, + const char *app_path, app_info_from_db * menu_info, + bundle * kb) +{ + char *file_name; + 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(); + + __preexec_run(menu_info->pkg_type, pkg_name, app_path); + + /* SET PRIVILEGES*/ + SECURE_LOGD("pkg_name : %s / pkg_type : %s / app_path : %s ", pkg_name, menu_info->pkg_type, app_path); + if ((ret = __set_access(pkg_name, menu_info->pkg_type, app_path)) < 0) { + _D("fail to set privileges - check your package's credential : %d\n", ret); + return -1; + } + /* SET DUMPABLE - for coredump*/ + prctl(PR_SET_DUMPABLE, 1); + + /* SET PROCESS NAME*/ + if (app_path == NULL) { + _D("app_path should not be NULL - check menu db"); + return -1; + } + file_name = strrchr(app_path, '/') + 1; + if (file_name == NULL) { + _D("can't locate file name to execute"); + return -1; + } + 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); + + return 0; +} + +_static_ int __fake_launch_app(int cmd, int pid, bundle * kb) +{ + int datalen; + int ret; + bundle_raw *kb_data; + + bundle_encode(kb, &kb_data, &datalen); + if ((ret = __app_send_raw(pid, cmd, kb_data, datalen)) < 0) + _E("error request fake launch - error code = %d", ret); + free(kb_data); + return ret; +} + +_static_ char **__create_argc_argv(bundle * kb, int *margc) +{ + char **argv; + int argc; + + argc = bundle_export_to_argv(kb, &argv); + + *margc = argc; + return argv; +} + +_static_ int __normal_fork_exec(int argc, char **argv) +{ + _D("start real fork and exec\n"); + +#ifdef _APPFW_FEATURE_PRIORITY_CHANGE + int res = setpriority(PRIO_PROCESS, 0, 0); + if (res == -1) + { + SECURE_LOGE("Setting process (%d) priority to 0 failed, errno: %d (%s)", + getpid(), errno, strerror(errno)); + } +#endif + if (execv(argv[0], argv) < 0) { /* Flawfinder: ignore */ + if (errno == EACCES) + _E("such a file is no executable - %s", argv[0]); + else + _E("unknown executable error - %s", argv[0]); + return -1; + } + /* never reach*/ + return 0; +} + +_static_ void __real_launch(const char *app_path, bundle * kb) +{ + int app_argc; + char **app_argv; + int i; + + app_argv = __create_argc_argv(kb, &app_argc); + app_argv[0] = strdup(app_path); + + for (i = 0; i < app_argc; i++) { + if( (i%2) == 1) + continue; + SECURE_LOGD("input argument %d : %s##", i, app_argv[i]); + } + + PERF("setup argument done"); + + /* Temporary log: launch time checking */ + SECURE_LOG(LOG_DEBUG, "LAUNCH", "[%s:Platform:launchpad:done]", app_path); + + __preload_exec(app_argc, app_argv); + + __normal_fork_exec(app_argc, app_argv); +} + + +/* + * Parsing original app path to retrieve default bundle + * + * -1 : Invalid sequence + * -2 : Buffer overflow + * + */ +static inline int __parser(const char *arg, char *out, int out_size) +{ + register int i; + int state = 1; + char *start_out = out; + + if (arg == NULL || out == NULL) { + /* Handles null buffer*/ + return 0; + } + + for (i = 0; out_size > 1; i++) { + switch (state) { + case 1: + switch (arg[i]) { + case ' ': + case '\t': + state = 5; + break; + case '\0': + state = 7; + break; + case '\"': + state = 2; + break; + case '\\': + state = 4; + break; + default: + *out = arg[i]; + out++; + out_size--; + break; + } + break; + case 2: /* escape start*/ + switch (arg[i]) { + case '\0': + state = 6; + break; + case '\"': + state = 1; + break; + default: + *out = arg[i]; + out++; + out_size--; + break; + } + break; + case 4: /* character escape*/ + if (arg[i] == '\0') { + state = 6; + } else { + *out = arg[i]; + out++; + out_size--; + state = 1; + } + break; + case 5: /* token*/ + if (out != start_out) { + *out = '\0'; + out_size--; + return i; + } + i--; + state = 1; + break; + case 6: + return -1; /* error*/ + case 7: /* terminate*/ + *out = '\0'; + out_size--; + return 0; + default: + state = 6; + break; /* error*/ + } + } + + if (out_size == 1) { + *out = '\0'; + } + /* Buffer overflow*/ + return -2; +} + +_static_ void __modify_bundle(bundle * kb, int caller_pid, + app_info_from_db * menu_info, int cmd) +{ + bundle_del(kb, AUL_K_PKG_NAME); + bundle_del(kb, AUL_K_EXEC); + bundle_del(kb, AUL_K_PACKAGETYPE); + bundle_del(kb, AUL_K_HWACC); + bundle_del(kb, AUL_K_TASKMANAGE); + + /* Parse app_path to retrieve default bundle*/ + if (cmd == APP_START + || cmd == APP_START_RES + || cmd == APP_START_ASYNC +#ifdef _APPFW_FEATURE_MULTI_INSTANCE + || cmd == APP_START_MULTI_INSTANCE +#endif + || cmd == APP_OPEN + || cmd == APP_RESUME + ) { + char *ptr; + char exe[MAX_PATH_LEN]; + int flag; + + ptr = _get_original_app_path(menu_info); + + flag = __parser(ptr, exe, sizeof(exe)); + if (flag > 0) { + char key[256]; + char value[256]; + + ptr += flag; + SECURE_LOGD("parsing app_path: EXEC - %s\n", exe); + + do { + flag = __parser(ptr, key, sizeof(key)); + if (flag <= 0) + break; + ptr += flag; + + flag = __parser(ptr, value, sizeof(value)); + if (flag < 0) + break; + ptr += flag; + + /*bundle_del(kb, key);*/ + bundle_add(kb, key, value); + } while (flag > 0); + } else if (flag == 0) { + _D("parsing app_path: No arguments\n"); + } else { + _D("parsing app_path: Invalid argument\n"); + } + } +} + +_static_ int __child_raise_win_by_x(int pid, void *priv) +{ + return x_util_raise_win(pid); +} + +_static_ int __raise_win_by_x(int pid) +{ + int pgid; + if (x_util_raise_win(pid) == 0) + return 0; + + /* support app launched by shell script*/ + pgid = getpgid(pid); + _D("X raise failed. try to find first child & raise it - c:%d p:%d\n", + pgid, pid); + + if (pgid <= 1) + return -1; + if (__proc_iter_pgid(pgid, __child_raise_win_by_x, NULL) < 0) + return -1; + + return 0; +} + +_static_ int __send_to_sigkill(int pid) +{ + int pgid; + + pgid = getpgid(pid); + if (pgid <= 1) + return -1; + + if (killpg(pgid, SIGKILL) < 0) + return -1; + + return 0; +} + +_static_ int __term_app(int pid) +{ + int dummy; + if (__app_send_raw + (pid, APP_TERM_BY_PID, (unsigned char *)&dummy, sizeof(int)) < 0) { + _D("terminate packet send error - use SIGKILL"); + if (__send_to_sigkill(pid) < 0) { + _E("fail to killing - %d\n", pid); + return -1; + } + } + _D("term done\n"); + return 0; +} + +_static_ int __resume_app(int pid) +{ + int dummy; + int ret; + if ((ret = + __app_send_raw(pid, APP_RESUME_BY_PID, (unsigned char *)&dummy, + sizeof(int))) < 0) { + if (ret == -EAGAIN) + _E("resume packet timeout error"); + else { + _D("resume packet send error - use raise win"); + if (__raise_win_by_x(pid) < 0) { + _E("raise failed - %d resume fail\n", pid); + _E("we will term the app - %d\n", pid); + __send_to_sigkill(pid); + ret = -1; + } else + ret = 0; + } + } + _D("resume done\n"); + return ret; +} + +static int __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) + goto end; + + pid_str = bundle_get_val(kb, AUL_K_CALLER_PID); + if (pid_str == NULL) + return -1; + +end: + pid = atoi(pid_str); + if (pid <= 1) + return -1; + + return pid; +} + +_static_ int __foward_cmd(int cmd, bundle *kb, int cr_pid) +{ + int pid; + char tmp_pid[MAX_PID_STR_BUFSZ]; + int datalen; + bundle_raw *kb_data; + int res; + + if ((pid = __get_caller_pid(kb)) < 0) + return AUL_R_ERROR; + + snprintf(tmp_pid, MAX_PID_STR_BUFSZ, "%d", cr_pid); + + bundle_add(kb, AUL_K_CALLEE_PID, tmp_pid); + + bundle_encode(kb, &kb_data, &datalen); + if ((res = __app_send_raw_with_noreply(pid, cmd, kb_data, datalen)) < 0) + res = AUL_R_ERROR; + + free(kb_data); + + return res; +} + +_static_ int __real_send(int clifd, int ret) +{ + if (send(clifd, &ret, sizeof(int), MSG_NOSIGNAL) < 0) { + if (errno == EPIPE) { + _E("send failed due to EPIPE.\n"); + close(clifd); + return -1; + } + _E("send fail to client"); + } + + close(clifd); + return 0; +} + +_static_ void __send_result_to_caller(int clifd, int ret) +{ + char *cmdline; + int wait_count; + int cmdline_changed = 0; + int cmdline_exist = 0; + int r; + + if (clifd == -1) + return; + + if (ret <= 1) { + __real_send(clifd, ret); + return; + } + /* check normally was launched?*/ + wait_count = 1; + do { + cmdline = __proc_get_cmdline_bypid(ret); + if (cmdline == NULL) { + _E("error founded when being launched with %d", ret); + + } else if (strcmp(cmdline, launchpad_cmdline)) { + free(cmdline); + cmdline_changed = 1; + break; + } else { + cmdline_exist = 1; + free(cmdline); + } + + _D("-- now wait to change cmdline --"); + usleep(100 * 1000); /* 50ms sleep*/ + wait_count++; + } while (wait_count <= 20); /* max 100*20ms will be sleep*/ + + if ((!cmdline_exist) && (!cmdline_changed)) { + __real_send(clifd, -1); /* abnormally launched*/ + return; + } + + if (!cmdline_changed) + _E("process launched, but cmdline not changed"); + + if(__real_send(clifd, ret) < 0) { + r = kill(ret, SIGKILL); + if (r == -1) + _E("send SIGKILL: %s", strerror(errno)); + } + + return; +} + +static app_info_from_db *_get_app_info_from_bundle_by_pkgname( + const char *pkgname, bundle *kb) +{ + app_info_from_db *menu_info; + + menu_info = calloc(1, sizeof(app_info_from_db)); + if (menu_info == NULL) { + return NULL; + } + + menu_info->pkg_name = strdup(pkgname); + menu_info->app_path = strdup(bundle_get_val(kb, AUL_K_EXEC)); + if (menu_info->app_path != NULL) + menu_info->original_app_path = strdup(menu_info->app_path); + menu_info->pkg_type = strdup(bundle_get_val(kb, AUL_K_PACKAGETYPE)); + menu_info->hwacc = strdup(bundle_get_val(kb, AUL_K_HWACC)); + menu_info->taskmanage = strdup(bundle_get_val(kb, AUL_K_TASKMANAGE)); + + if (!_get_app_path(menu_info)) { + _free_app_info_from_db(menu_info); + return NULL; + } + + return menu_info; +} + +static void __release_appid_at_exit(void) +{ + if (__appid != NULL) { + free(__appid); + } +} + +_static_ void __launchpad_main_loop(int main_fd) +{ + bundle *kb = NULL; + app_pkt_t *pkt = NULL; + app_info_from_db *menu_info = NULL; + + const char *pkg_name = NULL; + const char *app_path = NULL; + int pid = -1; + int clifd = -1; + struct ucred cr; + int is_real_launch = 0; + + char sock_path[UNIX_PATH_MAX] = {0,}; + + pkt = __app_recv_raw(main_fd, &clifd, &cr); + if (!pkt) { + _D("packet is NULL"); + goto end; + } + + kb = bundle_decode(pkt->data, pkt->len); + if (!kb) { + _D("bundle decode error"); + goto end; + } + + INIT_PERF(kb); + PERF("packet processing start"); + + pkg_name = bundle_get_val(kb, AUL_K_PKG_NAME); + SECURE_LOGD("pkg name : %s\n", pkg_name); + + menu_info = _get_app_info_from_bundle_by_pkgname(pkg_name, kb); + if (menu_info == NULL) { + _D("such pkg no found"); + goto end; + } + + app_path = _get_app_path(menu_info); + if(app_path == NULL) { + _E("app_path is NULL"); + goto end; + } + if (app_path[0] != '/') { + _D("app_path is not absolute path"); + goto end; + } + + __modify_bundle(kb, cr.pid, menu_info, pkt->cmd); + pkg_name = _get_pkgname(menu_info); + + PERF("get package information & modify bundle done"); + + { + pid = fork(); + if (pid == 0) { + PERF("fork done"); + _D("lock up test log(no error) : fork done"); + + close(clifd); + close(main_fd); + __signal_unset_sigchld(); + __signal_fini(); + + snprintf(sock_path, UNIX_PATH_MAX, "%s/%d", AUL_SOCK_PREFIX, getpid()); + unlink(sock_path); + + PERF("prepare exec - first done"); + _D("lock up test log(no error) : prepare exec - first done"); + + __appid = strdup(pkg_name); + aul_set_preinit_appid(__appid); + atexit(__release_appid_at_exit); + + if (__prepare_exec(pkg_name, app_path, + menu_info, kb) < 0) { + SECURE_LOGE("preparing work fail to launch - " + "can not launch %s\n", pkg_name); + exit(-1); + } + + PERF("prepare exec - second done"); + _D("lock up test log(no error) : prepare exec - second done"); + + __real_launch(app_path, kb); + + exit(-1); + } + SECURE_LOGD("==> real launch pid : %d %s\n", pid, app_path); + is_real_launch = 1; + } + + end: + __send_result_to_caller(clifd, pid); + + if (pid > 0) { + if (is_real_launch) { + /*TODO: retry*/ + __signal_block_sigchld(); + __send_app_launch_signal(pid); + __signal_unblock_sigchld(); + } + } + + if (menu_info != NULL) + _free_app_info_from_db(menu_info); + + if (kb != NULL) + bundle_free(kb); + if (pkt != NULL) + free(pkt); + + /* Active Flusing for Daemon */ + if (initialized > AUL_POLL_CNT) { + sqlite3_release_memory(SQLITE_FLUSH_MAX); + malloc_trim(0); + initialized = 1; + } + +} + +_static_ int __launchpad_pre_init(int argc, char **argv) +{ + int fd; + + /* signal init*/ + __signal_init(); + + /* get my(launchpad) command line*/ + launchpad_cmdline = __proc_get_cmdline_bypid(getpid()); + if (launchpad_cmdline == NULL) { + _E("launchpad cmdline fail to get"); + return -1; + } + _D("launchpad cmdline = %s", launchpad_cmdline); + + /* create launchpad sock */ + fd = __create_server_sock(NATIVE_LAUNCHPAD_PID); + if (fd < 0) { + _E("server sock error"); + return -1; + } + + __preload_init(argc, argv); + + __preload_init_for_native(); + + __preexec_init(argc, argv); + + return fd; +} + +_static_ int __launchpad_post_init() +{ + /* Setting this as a global variable to keep track + of launchpad poll cnt */ + /* static int initialized = 0;*/ + + if (initialized) { + initialized++; + return 0; + } + + if (__signal_set_sigchld() < 0) + return -1; + + initialized++; + + return 0; +} + +int main(int argc, char **argv) +{ + int main_fd; + struct pollfd pfds[POLLFD_MAX]; + int i; + + /* init without concerning X & EFL*/ + main_fd = __launchpad_pre_init(argc, argv); + if (main_fd < 0) { + _E("launchpad pre init failed"); + exit(-1); + } + + pfds[0].fd = main_fd; + pfds[0].events = POLLIN; + pfds[0].revents = 0; + +#ifdef _APPFW_FEATURE_PRIORITY_CHANGE + int res = setpriority(PRIO_PROCESS, 0, -12); + if (res == -1) + { + SECURE_LOGE("Setting process (%d) priority to -12 failed, errno: %d (%s)", + getpid(), errno, strerror(errno)); + } +#endif + while (1) { + if (poll(pfds, POLLFD_MAX, -1) < 0) + continue; + + /* init with concerning X & EFL (because of booting + sequence problem)*/ + if (__launchpad_post_init() < 0) { + _E("launcpad post init failed"); + exit(-1); + } + + for (i = 0; i < POLLFD_MAX; i++) { + if ((pfds[i].revents & POLLIN) != 0) { + __launchpad_main_loop(pfds[i].fd); + } + } + } +} + diff --git a/native/native_preload.h b/native/native_preload.h new file mode 100644 index 0000000..965457c --- /dev/null +++ b/native/native_preload.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2014 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 __NATIVE_PRELOAD_H__ +#define __NATIVE_PRELOAD_H__ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <dlfcn.h> + +#define NATIVE_PRELOAD_FILE SHARE_PREFIX"/launchpad-native-preload-list.txt" + +static int g_dlopen_size = 5; +static int g_dlopen_count = 0; +static void** g_dlopen_handle_list = NULL; + +static inline int __preload_save_dlopen_handle(void *handle) +{ + if (!handle) { + return 1; + } + if (g_dlopen_count == g_dlopen_size || !g_dlopen_handle_list) { + void** tmp = + realloc(g_dlopen_handle_list, 2 * g_dlopen_size * sizeof(void *)); + if (NULL == tmp) { + _E("out of memory\n"); + dlclose(handle); + return 1; + } + g_dlopen_size *= 2; + g_dlopen_handle_list = tmp; + } + g_dlopen_handle_list[g_dlopen_count++] = handle; + return 0; +} + +static inline void __preload_fini_for_native(void) +{ + int i = 0; + if (!g_dlopen_handle_list) { + return; + } + for (i = 0; i < g_dlopen_count; ++i) + { + void *handle = g_dlopen_handle_list[i]; + if (handle) { + if (0 != dlclose(handle)) { + _E("dlclose failed\n"); + } + } + } + free(g_dlopen_handle_list); + g_dlopen_handle_list = NULL; + g_dlopen_size = 5; + g_dlopen_count = 0; +} + +static inline void __preload_init_for_native(void) +{ + if (atexit(__preload_fini_for_native) != 0) { + _E("Cannot register atexit callback. Libraries will not be unloaded"); + } + + void *handle = NULL; + char soname[MAX_LOCAL_BUFSZ] = { 0, }; + FILE *preload_list = NULL; + + preload_list = fopen(NATIVE_PRELOAD_FILE, "rt"); + if (preload_list == NULL) { + _E("no preload\n"); + return; + } + + while (fgets(soname, MAX_LOCAL_BUFSZ, preload_list) > 0) { + size_t len = strnlen(soname, MAX_LOCAL_BUFSZ); + if (len > 0) { + soname[len - 1] = '\0'; + } + handle = dlopen((const char *) soname, RTLD_NOW); + if (handle == NULL) { + _E("dlopen(\"%s\") was failed!", soname); + continue; + } + + if (__preload_save_dlopen_handle(handle) != 0) { + _E("Cannot save handle, no more preloads"); + break; + } + _D("preload %s# - handle : %x\n", soname, handle); + } + + fclose(preload_list); +} + +#endif //__NATIVE_PRELOAD_H__ diff --git a/packaging/launchpad-native-preload-list.txt b/packaging/launchpad-native-preload-list.txt new file mode 100644 index 0000000..bb21d5e --- /dev/null +++ b/packaging/launchpad-native-preload-list.txt @@ -0,0 +1,19 @@ +/usr/lib/osp/libosp-appfw.so.1 +/usr/lib/osp/libosp-uifw.so.1 +/usr/lib/samsung-private/libsamsung-ui.so.1 +/usr/lib/libmirage.so +/usr/lib/libchart-framework.so +/usr/lib/samsung-private/libsamsung-media.so.1 +/usr/lib/samsung-private/libsamsung-net.so.1 +/usr/lib/samsung-private/libsamsung-messaging.so.1 +/usr/lib/osp/libosp-media.so.1 +/usr/lib/osp/libosp-messaging.so.1 +/usr/lib/samsung-private/libsamsung-shell.so.1 +/usr/lib/samsung-private/libsamsung-social.so.1 +/usr/lib/osp/libosp-shell.so.1 +/usr/lib/osp/libosp-wifi.so.1 +/usr/lib/osp/libosp-social.so.1 +/usr/lib/osp/libosp-content.so.1 +/usr/lib/samsung-private/libsamsung-content.so.1 +/usr/lib/osp/libosp-image.so.1 +/usr/lib/osp/libosp-net.so.1 diff --git a/packaging/launchpad-native.service b/packaging/launchpad-native.service new file mode 100644 index 0000000..2ac3288 --- /dev/null +++ b/packaging/launchpad-native.service @@ -0,0 +1,13 @@ +[Unit] +Description=Start native launchpad daemon +After=dbus.service vconf-setup.service ac.service + +[Service] +EnvironmentFile=/run/tizen-mobile-env +ExecStart=/usr/bin/launchpad-native " " +TimeoutStopSec=3s +Restart=always +RestartSec=0 + +[Install] +WantedBy=graphical.target diff --git a/packaging/launchpad-process-pool-preload-list.txt b/packaging/launchpad-process-pool-preload-list.txt new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/packaging/launchpad-process-pool-preload-list.txt diff --git a/packaging/launchpad-process-pool.service b/packaging/launchpad-process-pool.service new file mode 100644 index 0000000..bccc8cb --- /dev/null +++ b/packaging/launchpad-process-pool.service @@ -0,0 +1,13 @@ +[Unit] +Description=Start process-pool launchpad daemon +After=dbus.service vconf-setup.service ac.service + +[Service] +EnvironmentFile=/run/tizen-mobile-env +ExecStart=/usr/bin/launchpad-process-pool " " +TimeoutStopSec=3s +Restart=always +RestartSec=0 + +[Install] +WantedBy=graphical.target diff --git a/packaging/launchpad.spec b/packaging/launchpad.spec new file mode 100644 index 0000000..d225114 --- /dev/null +++ b/packaging/launchpad.spec @@ -0,0 +1,129 @@ +Name: launchpad +Summary: Launchpad for launching applications +Version: 0.0.20 +Release: 1 +Group: Application Framework/Daemons +License: Apache-2.0 +Source0: %{name}-%{version}.tar.gz +Source101: launchpad-process-pool.service +Source102: launchpad-native.service + +BuildRequires: cmake +BuildRequires: pkgconfig(dbus-glib-1) +BuildRequires: pkgconfig(sqlite3) +BuildRequires: pkgconfig(ecore) +BuildRequires: pkgconfig(bundle) +BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(ail) +BuildRequires: pkgconfig(libprivilege-control) +BuildRequires: pkgconfig(libsmack) +BuildRequires: pkgconfig(glib-2.0) +BuildRequires: pkgconfig(deviced) +BuildRequires: pkgconfig(libsystemd-daemon) +BuildRequires: pkgconfig(elementary) +BuildRequires: pkgconfig(eina) +BuildRequires: aul-devel + +Requires: aul +Requires(post): /sbin/ldconfig +Requires(post): /usr/bin/systemctl +Requires(postun): /sbin/ldconfig +Requires(postun): /usr/bin/systemctl +Requires(preun): /usr/bin/systemctl + +%define feature_appfw_process_pool 1 + +%if "%{?tizen_profile_name}" == "wearable" +%define appfw_feature_process_pool_common 1 +%define appfw_feature_hw_rendering 0 +%elseif "%{?tizen_profile_name}" == "mobile" +%define appfw_feature_process_pool_common 0 +%define appfw_feature_hw_rendering 1 +%endif +%define appfw_feature_priority_change 1 +%define appfw_feature_native_launchpad 0 + +%description +Launchpad for launching applications + +%package devel +Summary: Launchpad for launching applications (devel) +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} + +%description devel +Launchpad for launching applications (devel) + +%prep +%setup -q + +%build +%if 0%{?sec_build_binary_debug_enable} +export CFLAGS="$CFLAGS -DTIZEN_DEBUG_ENABLE" +export CXXFLAGS="$CXXFLAGS -DTIZEN_DEBUG_ENABLE" +export FFLAGS="$FFLAGS -DTIZEN_DEBUG_ENABLE" +%endif +%if 0%{?feature_appfw_process_pool} +_APPFW_FEATURE_PROCESS_POOL=ON + %if 0%{?appfw_feature_process_pool_common} + _APPFW_FEATURE_PROCESS_POOL_COMMON=ON + %else + %if 0%{?appfw_feature_hw_rendering} + _APPFW_FEATURE_PROCESS_POOL_HW_RENDERING=ON + %endif + %endif +%endif +%if 0%{?appfw_feature_priority_change} +_APPFW_FEATURE_PRIORITY_CHANGE=ON +%endif +%if 0%{?appfw_feature_native_launchpad} +_APPFW_FEATURE_NATIVE_LAUNCHPAD=ON +%endif + +cmake -DCMAKE_INSTALL_PREFIX=%{_prefix} \ + -D_APPFW_FEATURE_PROCESS_POOL:BOOL=${_APPFW_FEATURE_PROCESS_POOL} \ + -D_APPFW_FEATURE_PROCESS_POOL_COMMON:BOOL=${_APPFW_FEATURE_PROCESS_POOL_COMMON} \ + -D_APPFW_FEATURE_PROCESS_POOL_HW_RENDERING:BOOL=${_APPFW_FEATURE_PROCESS_POOL_HW_RENDERING} \ + -D_APPFW_FEATURE_PRIORITY_CHANGE:BOOL=${_APPFW_FEATURE_PRIORITY_CHANGE} \ + -D_APPFW_FEATURE_NATIVE_LAUNCHPAD:BOOL=${_APPFW_FEATURE_NATIVE_LAUNCHPAD} + +make %{?jobs:-j%jobs} + +%install +rm -rf %{buildroot} +%if 0%{?feature_appfw_process_pool} || 0%{?appfw_feature_native_launchpad} +%make_install +%endif + +%if 0%{?feature_appfw_process_pool} +mkdir -p %{buildroot}%{_libdir}/systemd/system/graphical.target.wants +install -m0644 %SOURCE101 %{buildroot}%{_libdir}/systemd/system/launchpad-process-pool.service +ln -s ../launchpad-process-pool.service %{buildroot}%{_libdir}/systemd/system/graphical.target.wants/launchpad-process-pool.service +%endif + +%if 0%{?appfw_feature_native_launchpad} +mkdir -p %{buildroot}%{_libdir}/systemd/system/graphical.target.wants +install -m0644 %SOURCE102 %{buildroot}%{_libdir}/systemd/system/launchpad-native.service +ln -s ../launchpad-native.service %{buildroot}%{_libdir}/systemd/system/graphical.target.wants/launchpad-native.service +%endif + +mkdir -p %{buildroot}/usr/share/license +cp %{_builddir}/%{name}-%{version}/LICENSE %{buildroot}/usr/share/license/%{name} + +%post + +%files +%manifest launchpad.manifest +%{_prefix}/share/license/%{name} +%if 0%{?feature_appfw_process_pool} +%{_bindir}/launchpad-process-pool +%{_prefix}/share/aul/launchpad-process-pool-preload-list.txt +%{_libdir}/systemd/system/launchpad-process-pool.service +%{_libdir}/systemd/system/graphical.target.wants/launchpad-process-pool.service +%endif +%if 0%{?appfw_feature_native_launchpad} +%{_bindir}/launchpad-native +%{_prefix}/share/aul/launchpad-native-preload-list.txt +%{_libdir}/systemd/system/launchpad-native.service +%{_libdir}/systemd/system/graphical.target.wants/launchpad-native.service +%endif diff --git a/process_pool/launchpad.c b/process_pool/launchpad.c new file mode 100644 index 0000000..a7cdfc2 --- /dev/null +++ b/process_pool/launchpad.c @@ -0,0 +1,1381 @@ +/* + * Copyright (c) 2014 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 <stdio.h> +#include <dlfcn.h> +#include <poll.h> +#include <sys/prctl.h> +#include <sys/resource.h> +#define __USE_GNU +#include <sys/socket.h> + +#include <sqlite3.h> + +#include <aul.h> +#include <Elementary.h> +#include <Ecore.h> + +#include <config.h> //should be included first + +//including aul/launch +#include <access_control.h> +#include <app_sock.h> +#include <aul_util.h> +#include <menu_db_util.h> +#include <perf.h> +#include <simple_util.h> + +//including aul/launchpad +#include <gl.h> +#include <heap_dbg.h> +#include <preexec.h> +#include <preload.h> +#include <sigchild.h> +#include <util_x.h> + +#include "process_pool.h" +#include "process_pool_preload.h" + +#include "smack_util.h" + +#define _static_ static inline +#define SQLITE_FLUSH_MAX (1048576) /* (1024*1024) */ +#define AUL_POLL_CNT 15 +#define AUL_PR_NAME 16 + +#define EXEC_CANDIDATE_EXPIRED 5 +#define DIFF(a,b) (((a)>(b))?(a)-(b):(b)-(a)) +#define LOWEST_PRIO 20 +#define CANDIDATE_NONE 0 +#ifndef _APPFW_FEATURE_PROCESS_POOL_COMMON + #ifndef _APPFW_FEATURE_PROCESS_POOL_HW_RENDERING + #define MAX_LAUNCHPAD_TYPE_NUM 1 + #else + #define MAX_LAUNCHPAD_TYPE_NUM 2 + #endif +#else //_APPFW_FEATURE_PROCESS_POOL_COMMON +#define MAX_LAUNCHPAD_TYPE_NUM 1 +#endif //_APPFW_FEATURE_PROCESS_POOL_COMMON + +typedef struct +{ + int pid; + int send_fd; + int last_exec_time; +} candidate; + +static char *launchpad_cmdline; +static char *__appid = NULL; +static int initialized = 0; +static candidate __candidate[MAX_LAUNCHPAD_TYPE_NUM] = +{ + { CANDIDATE_NONE, -1, 0 }, + { CANDIDATE_NONE, -1, 0 } +}; +const char* const HOME = "HOME"; +const char* const APP_HOME_PATH = "/opt/home/app"; +const char* const ROOT_HOME_PATH = "/opt/home/root"; + +_static_ void __set_env(app_info_from_db *menu_info, bundle *kb); +_static_ int __prepare_exec(const char *pkg_name, + const char *app_path, app_info_from_db * menu_info, + bundle * kb); +_static_ int __fake_launch_app(int cmd, int pid, bundle * kb); +_static_ char **__create_argc_argv(bundle *kb, int *margc); +_static_ int __normal_fork_exec(int argc, char **argv); +_static_ void __real_launch(const char *app_path, bundle * kb); +_static_ int __candidate_process_real_launch(int candidate_fd, app_pkt_t *pkt); +static inline int __parser(const char *arg, char *out, int out_size); +_static_ void __modify_bundle(bundle * kb, int caller_pid, + app_info_from_db * menu_info, int cmd); +_static_ int __child_raise_win_by_x(int pid, void *priv); +_static_ int __raise_win_by_x(int pid); +_static_ int __send_to_sigkill(int pid); +_static_ int __term_app(int pid); +_static_ int __resume_app(int pid); +_static_ int __real_send(int clifd, int ret); +_static_ void __send_result_to_caller(int clifd, int ret); +_static_ void __prepare_candidate_process(int type, int launchpad_fd, int pool_fd, int client_fd); +_static_ void __launchpad_main_loop(int launchpad_fd, int *pool_fd); +_static_ int __launchpad_pre_init(int argc, char **argv); +_static_ int __launchpad_post_init(); + +static app_info_from_db *_get_app_info_from_bundle_by_pkgname( + const char *pkgname, bundle *kb); + +_static_ void __set_env(app_info_from_db * menu_info, bundle * kb) +{ + const char *str; + + setenv("PKG_NAME", _get_pkgname(menu_info), 1); + + USE_ENGINE("gl") + + str = bundle_get_val(kb, AUL_K_STARTTIME); + if (str != NULL) + setenv("APP_START_TIME", str, 1); + + if (menu_info->hwacc != NULL) + setenv("HWACC", menu_info->hwacc, 1); + if (menu_info->taskmanage != NULL) + setenv("TASKMANAGE", menu_info->taskmanage, 1); +} + +_static_ int __prepare_exec(const char *pkg_name, + const char *app_path, app_info_from_db * menu_info, + bundle * kb) +{ + char *file_name; + 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(); + + __preexec_run(menu_info->pkg_type, pkg_name, app_path); + + /* SET PRIVILEGES*/ + SECURE_LOGD("pkg_name : %s / pkg_type : %s / app_path : %s ", pkg_name, menu_info->pkg_type, app_path); + if ((ret = __set_access(pkg_name, menu_info->pkg_type, app_path)) < 0) { + _D("fail to set privileges - check your package's credential : %d\n", ret); + return -1; + } + /* SET DUMPABLE - for coredump*/ + prctl(PR_SET_DUMPABLE, 1); + + /* SET PROCESS NAME*/ + if (app_path == NULL) { + _D("app_path should not be NULL - check menu db"); + return -1; + } + file_name = strrchr(app_path, '/') + 1; + if (file_name == NULL) { + _D("can't locate file name to execute"); + return -1; + } + 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); + + return 0; +} + +_static_ int __fake_launch_app(int cmd, int pid, bundle * kb) +{ + int datalen; + int ret; + bundle_raw *kb_data; + + bundle_encode(kb, &kb_data, &datalen); + if ((ret = __app_send_raw(pid, cmd, kb_data, datalen)) < 0) + _E("error request fake launch - error code = %d", ret); + free(kb_data); + return ret; +} + +_static_ char **__create_argc_argv(bundle * kb, int *margc) +{ + char **argv; + int argc; + + argc = bundle_export_to_argv(kb, &argv); + + *margc = argc; + return argv; +} + +_static_ int __normal_fork_exec(int argc, char **argv) +{ + _D("start real fork and exec\n"); + +#ifdef _APPFW_FEATURE_PRIORITY_CHANGE + int res = setpriority(PRIO_PROCESS, 0, 0); + if (res == -1) + { + SECURE_LOGE("Setting process (%d) priority to 0 failed, errno: %d (%s)", + getpid(), errno, strerror(errno)); + } +#endif + if (execv(argv[0], argv) < 0) { /* Flawfinder: ignore */ + if (errno == EACCES) + _E("such a file is no executable - %s", argv[0]); + else + _E("unknown executable error - %s", argv[0]); + return -1; + } + /* never reach*/ + return 0; +} + +_static_ void __real_launch(const char *app_path, bundle * kb) +{ + int app_argc; + char **app_argv; + int i; + + app_argv = __create_argc_argv(kb, &app_argc); + app_argv[0] = strdup(app_path); + + for (i = 0; i < app_argc; i++) { + if( (i%2) == 1) + continue; + SECURE_LOGD("input argument %d : %s##", i, app_argv[i]); + } + + PERF("setup argument done"); + + /* Temporary log: launch time checking */ + LOG(LOG_DEBUG, "LAUNCH", "[%s:Platform:launchpad:done]", app_path); + + __preload_exec(app_argc, app_argv); + + __normal_fork_exec(app_argc, app_argv); +} + +_static_ int __candidate_process_real_launch(int candidate_fd, app_pkt_t *pkt) +{ + return __send_pkt_raw_data(candidate_fd, pkt); +} + +/* + * Parsing original app path to retrieve default bundle + * + * -1 : Invalid sequence + * -2 : Buffer overflow + * + */ +static inline int __parser(const char *arg, char *out, int out_size) +{ + register int i; + int state = 1; + char *start_out = out; + + if (arg == NULL || out == NULL) { + /* Handles null buffer*/ + return 0; + } + + for (i = 0; out_size > 1; i++) { + switch (state) { + case 1: + switch (arg[i]) { + case ' ': + case '\t': + state = 5; + break; + case '\0': + state = 7; + break; + case '\"': + state = 2; + break; + case '\\': + state = 4; + break; + default: + *out = arg[i]; + out++; + out_size--; + break; + } + break; + case 2: /* escape start*/ + switch (arg[i]) { + case '\0': + state = 6; + break; + case '\"': + state = 1; + break; + default: + *out = arg[i]; + out++; + out_size--; + break; + } + break; + case 4: /* character escape*/ + if (arg[i] == '\0') { + state = 6; + } else { + *out = arg[i]; + out++; + out_size--; + state = 1; + } + break; + case 5: /* token*/ + if (out != start_out) { + *out = '\0'; + out_size--; + return i; + } + i--; + state = 1; + break; + case 6: + return -1; /* error*/ + case 7: /* terminate*/ + *out = '\0'; + out_size--; + return 0; + default: + state = 6; + break; /* error*/ + } + } + + if (out_size == 1) { + *out = '\0'; + } + /* Buffer overflow*/ + return -2; +} + +_static_ void __modify_bundle(bundle * kb, int caller_pid, + app_info_from_db * menu_info, int cmd) +{ + bundle_del(kb, AUL_K_PKG_NAME); + bundle_del(kb, AUL_K_EXEC); + bundle_del(kb, AUL_K_PACKAGETYPE); + bundle_del(kb, AUL_K_HWACC); + bundle_del(kb, AUL_K_TASKMANAGE); + + /* Parse app_path to retrieve default bundle*/ + if (cmd == APP_START + || cmd == APP_START_RES + || cmd == APP_OPEN + || cmd == APP_RESUME + ) { + char *ptr; + char exe[MAX_PATH_LEN]; + int flag; + + ptr = _get_original_app_path(menu_info); + + flag = __parser(ptr, exe, sizeof(exe)); + if (flag > 0) { + char key[256]; + char value[256]; + + ptr += flag; + SECURE_LOGD("parsing app_path: EXEC - %s\n", exe); + + do { + flag = __parser(ptr, key, sizeof(key)); + if (flag <= 0) + break; + ptr += flag; + + flag = __parser(ptr, value, sizeof(value)); + if (flag < 0) + break; + ptr += flag; + + /*bundle_del(kb, key);*/ + bundle_add(kb, key, value); + } while (flag > 0); + } else if (flag == 0) { + _D("parsing app_path: No arguments\n"); + } else { + _D("parsing app_path: Invalid argument\n"); + } + } +} + +_static_ int __child_raise_win_by_x(int pid, void *priv) +{ + return x_util_raise_win(pid); +} + +_static_ int __raise_win_by_x(int pid) +{ + int pgid; + if (x_util_raise_win(pid) == 0) + return 0; + + /* support app launched by shell script*/ + pgid = getpgid(pid); + _D("X raise failed. try to find first child & raise it - c:%d p:%d\n", + pgid, pid); + + if (pgid <= 1) + return -1; + if (__proc_iter_pgid(pgid, __child_raise_win_by_x, NULL) < 0) + return -1; + + return 0; +} + +_static_ int __send_to_sigkill(int pid) +{ + int pgid; + + pgid = getpgid(pid); + if (pgid <= 1) + return -1; + + if (killpg(pgid, SIGKILL) < 0) + return -1; + + return 0; +} + +_static_ int __term_app(int pid) +{ + int dummy; + if (__app_send_raw + (pid, APP_TERM_BY_PID, (unsigned char *)&dummy, sizeof(int)) < 0) { + _D("terminate packet send error - use SIGKILL"); + if (__send_to_sigkill(pid) < 0) { + _E("fail to killing - %d\n", pid); + return -1; + } + } + _D("term done\n"); + return 0; +} + +_static_ int __resume_app(int pid) +{ + int dummy; + int ret; + if ((ret = + __app_send_raw(pid, APP_RESUME_BY_PID, (unsigned char *)&dummy, + sizeof(int))) < 0) { + if (ret == -EAGAIN) + _E("resume packet timeout error"); + else { + _D("resume packet send error - use raise win"); + if (__raise_win_by_x(pid) < 0) { + _E("raise failed - %d resume fail\n", pid); + _E("we will term the app - %d\n", pid); + __send_to_sigkill(pid); + ret = -1; + } else + ret = 0; + } + } + _D("resume done\n"); + return ret; +} + +static int __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) + goto end; + + pid_str = bundle_get_val(kb, AUL_K_CALLER_PID); + if (pid_str == NULL) + return -1; + +end: + pid = atoi(pid_str); + if (pid <= 1) + return -1; + + return pid; +} + +_static_ int __foward_cmd(int cmd, bundle *kb, int cr_pid) +{ + int pid; + char tmp_pid[MAX_PID_STR_BUFSZ]; + int datalen; + bundle_raw *kb_data; + int res; + + if ((pid = __get_caller_pid(kb)) < 0) + return AUL_R_ERROR; + + snprintf(tmp_pid, MAX_PID_STR_BUFSZ, "%d", cr_pid); + + bundle_add(kb, AUL_K_CALLEE_PID, tmp_pid); + + bundle_encode(kb, &kb_data, &datalen); + if ((res = __app_send_raw_with_noreply(pid, cmd, kb_data, datalen)) < 0) + res = AUL_R_ERROR; + + free(kb_data); + + return res; +} + +_static_ int __real_send(int clifd, int ret) +{ + if (send(clifd, &ret, sizeof(int), MSG_NOSIGNAL) < 0) { + if (errno == EPIPE) { + _E("send failed due to EPIPE.\n"); + close(clifd); + return -1; + } + _E("send fail to client"); + } + + close(clifd); + return 0; +} + +_static_ void __send_result_to_caller(int clifd, int ret) +{ + char *cmdline; + int wait_count; + int cmdline_changed = 0; + int cmdline_exist = 0; + int r; + + if (clifd == -1) + return; + + if (ret <= 1) { + __real_send(clifd, ret); + return; + } + /* check normally was launched?*/ + wait_count = 1; + do { + cmdline = __proc_get_cmdline_bypid(ret); + if (cmdline == NULL) { + _E("error founded when being launched with %d", ret); + + } else if (strcmp(cmdline, launchpad_cmdline)) { + free(cmdline); + cmdline_changed = 1; + break; + } else { + cmdline_exist = 1; + free(cmdline); + } + + _D("-- now wait to change cmdline --"); + usleep(100 * 1000); /* 50ms sleep*/ + wait_count++; + } while (wait_count <= 20); /* max 100*20ms will be sleep*/ + + if ((!cmdline_exist) && (!cmdline_changed)) { + __real_send(clifd, -1); /* abnormally launched*/ + return; + } + + if (!cmdline_changed) + _E("process launched, but cmdline not changed"); + + if(__real_send(clifd, ret) < 0) { + r = kill(ret, SIGKILL); + if (r == -1) + _E("send SIGKILL: %s", strerror(errno)); + } + + return; +} + +_static_ int __candidate_process_prepare_exec(const char *pkg_name, + const char *app_path, app_info_from_db *menu_info, + bundle *kb, int type) +{ + const char *file_name = NULL; + char process_name[AUL_PR_NAME] = { 0, }; + int ret = 0; + + if (set_app_smack_label(app_path, type) != 0) + { + _E("set_app_smack_label() failed"); + } + + /* SET PRIVILEGES*/ + SECURE_LOGD("[candidata] pkg_name : %s / pkg_type : %s / app_path : %s ", pkg_name, menu_info->pkg_type, app_path); + if ((ret = __set_access(pkg_name, menu_info->pkg_type, app_path)) < 0) { + _D("fail to set privileges - check your package's credential : %d\n", ret); + return -1; + } + + //XXX: Check CAP_MAC_ADMIN +#if 0 + /* SET INHERIT BIT FOR CAP_MAC_ADMIN TO WHOLE THREAD */ + EXECUTE_ON_WHOLE_THREAD(__set_inherit_bit_for_CAP_MAC_ADMIN, SIGUSR1); +#endif + + /* SET PROCESS NAME*/ + if (app_path == NULL) { + _D("app_path should not be NULL - check menu db"); + return -1; + } + + file_name = strrchr(app_path, '/') + 1; + if (file_name == NULL) { + _D("can't locate file name to execute"); + return -1; + } + 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); + + return 0; +} + +static bundle *_s_bundle = NULL; +static void __at_exit_to_release_bundle() +{ + if (_s_bundle) { + bundle_free(_s_bundle); + _s_bundle = NULL; + } +} + +static void __release_appid_at_exit(void) +{ + if (__appid != NULL) { + free(__appid); + } +} + +_static_ void __candidate_process_launchpad_main_loop(app_pkt_t* pkt, char* out_app_path, int* out_argc, char ***out_argv) +{ + bundle *kb = NULL; + app_info_from_db *menu_info = NULL; + + const char *pkg_name = NULL; + const char *app_path = NULL; + const char *launchpad_type = NULL; + int type = 0; + + kb = bundle_decode(pkt->data, pkt->len); + if (!kb) { + _E("bundle decode error"); + exit(-1); + } + + if (_s_bundle != NULL) { + bundle_free(_s_bundle); + } + _s_bundle = kb; + atexit(__at_exit_to_release_bundle); + + pkg_name = bundle_get_val(kb, AUL_K_PKG_NAME); + menu_info = _get_app_info_from_bundle_by_pkgname(pkg_name, kb); + if (menu_info == NULL) { + _D("such pkg no found"); + exit(-1); + } + + launchpad_type = bundle_get_val(kb, AUL_K_LAUNCHPAD_TYPE); + if (launchpad_type == NULL) + { + _E("Invalid launchpad type"); + exit(-1); + } + type = atoi(launchpad_type); + SECURE_LOGD("pkg name : %s, launchpad type: %d", pkg_name, type); + + app_path = _get_app_path(menu_info); + if (app_path == NULL) { + _E("app_path is NULL"); + exit(-1); + } + + if (app_path[0] != '/') { + _E("app_path is not absolute path"); + exit(-1); + } + + __modify_bundle(kb, /*cr.pid - unused parameter*/ 0, menu_info, pkt->cmd); + pkg_name = _get_pkgname(menu_info); + SECURE_LOGD("pkg name : %s", pkg_name); + + __appid = strdup(pkg_name); + aul_set_preinit_appid(__appid); + atexit(__release_appid_at_exit); + + __candidate_process_prepare_exec(pkg_name, app_path, menu_info, kb, type); + + if (out_app_path != NULL && out_argc != NULL && out_argv != NULL) + { + int i = 0; + + memset(out_app_path, '\0', strlen(out_app_path)); + sprintf(out_app_path, "%s", app_path); + + *out_argv = __create_argc_argv(kb, out_argc); + (*out_argv)[0] = out_app_path; + + for (i = 0; i < *out_argc; i++) + { + SECURE_LOGD("input argument %d : %s##", i, (*out_argv)[i]); + } + } + else + { + exit(-1); + } + + if (menu_info != NULL) { + _free_app_info_from_db(menu_info); + } +} + +static Eina_Bool __candidate_proces_fd_handler(void* data, Ecore_Fd_Handler *handler) +{ + int fd = ecore_main_fd_handler_fd_get(handler); + + if (fd == -1) + { + _D("[candidate] ECORE_FD_GET"); + exit(-1); + } + + if (ecore_main_fd_handler_active_get(handler, ECORE_FD_ERROR)) + { + _D("[candidate] ECORE_FD_ERROR"); + close(fd); + exit(-1); + } + + if (ecore_main_fd_handler_active_get(handler, ECORE_FD_READ)) + { + _D("[candidate] ECORE_FD_READ"); + { + app_pkt_t* pkt = (app_pkt_t*) malloc(sizeof(char) * AUL_SOCK_MAXBUFF); + if (pkt == NULL) { + _E("[candidate] out of memory"); + close(fd); + exit(-1); + } + + memset(pkt, 0, AUL_SOCK_MAXBUFF); + + int recv_ret = recv(fd, pkt, AUL_SOCK_MAXBUFF, 0); + close(fd); + if (recv_ret == -1) + { + _D("[candidate] recv error!"); + free(pkt); + exit(-1); + } + _D("[candidate] recv_ret: %d, pkt->len: %d", recv_ret, pkt->len); + + ecore_main_fd_handler_del(handler); + __candidate_process_launchpad_main_loop(pkt, g_argv[0], &g_argc, &g_argv); + SECURE_LOGD("[candidate] real app argv[0]: %s, real app argc: %d", g_argv[0], g_argc); + free(pkt); + } + ecore_main_loop_quit(); + _D("[candidate] ecore main loop quit"); + } + + return ECORE_CALLBACK_CANCEL; +} + +_static_ void __prepare_candidate_process(int type, int launchpad_fd, int pool_fd, int client_fd) +{ + int pid; + + if (type == 1) + { + __candidate[TYPE1].last_exec_time = time(NULL); + } +#ifndef _APPFW_FEATURE_PROCESS_POOL_COMMON +#ifdef _APPFW_FEATURE_PROCESS_POOL_HW_RENDERING + else if (type == 2) + { + __candidate[TYPE2].last_exec_time = time(NULL); + } +#endif +#endif + + pid = fork(); + + if (pid == 0) // child + { + int res = setpriority(PRIO_PROCESS, 0, LOWEST_PRIO); + if (res == -1) + { + SECURE_LOGE("Setting process (%d) priority to %d failed, errno: %d (%s)", + getpid(), LOWEST_PRIO, errno, strerror(errno)); + } + _D("[candidate] Another candidate process was forked."); + + //temp - this requires some optimization. + sleep(1); + _D("sleeping 1 sec..."); + + /* 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(); + + if (launchpad_fd != -1) + { + close(launchpad_fd); + } + if (pool_fd != -1) + { + close(pool_fd); + } + if (client_fd != -1) + { + close(client_fd); + } + + __signal_unset_sigchld(); + __signal_fini(); + +#if 0 + if (set_SIGUSR1_handler() != 0) + { + _E("Setting signal hanlder failed."); + exit(-1); + } +#endif + + /* SET PR_SET_KEEPCAPS */ + if (prctl(PR_SET_KEEPCAPS, 1) < 0) + { + _E("prctl(PR_SET_KEEPCAPS) failed."); + } + + /* SET DUMPABLE - for coredump*/ + prctl(PR_SET_DUMPABLE, 1); + + { + int client_fd = __connect_to_launchpad(type); + if (client_fd == -1) + { + _D("Connecting to candidate process was failed."); + exit(-1); + } + + // Temporarily change HOME path to app + // This change is needed for getting elementary profile + // /opt/home/app/.elementary/config/mobile/base.cfg + setenv(HOME, APP_HOME_PATH, 1); + _D("[candidate] elm_init()"); + elm_init(g_argc, g_argv); + setenv(HOME, ROOT_HOME_PATH, 1); + +#ifndef _APPFW_FEATURE_PROCESS_POOL_COMMON + #ifdef _APPFW_FEATURE_PROCESS_POOL_HW_RENDERING + if (type == 2) + { + elm_config_preferred_engine_set("opengl_x11"); + } + #endif + Evas_Object* win = elm_win_add(NULL, "package_name", ELM_WIN_BASIC); + aul_set_preinit_window(win); + + Evas_Object* bg = elm_bg_add(win); + evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_win_resize_object_add(win, bg); + + aul_set_preinit_background(bg); + + Evas_Object* conform = elm_conformant_add(win); + aul_set_preinit_conformant(conform); +#else //_APPFW_FEATURE_PROCESS_POOL_COMMON + Eina_Bool is_exist = edje_file_group_exists("/usr/share/elementary/themes/tizen-2.3-wearable-HVGA.edj", "*"); + if(!is_exist) + _D("edje_file_group_exists return false"); +#endif //_APPFW_FEATURE_PROCESS_POOL_COMMON + + Ecore_Fd_Handler* fd_handler = ecore_main_fd_handler_add(client_fd, + (Ecore_Fd_Handler_Flags)(ECORE_FD_READ|ECORE_FD_ERROR), + __candidate_proces_fd_handler, NULL, NULL, NULL); + if (fd_handler == NULL) + { + _D("fd_handler is NULL"); + exit(-1); + } + + res = setpriority(PRIO_PGRP, 0, 0); + if (res == -1) + { + SECURE_LOGE("Setting process (%d) priority to 0 failed, errno: %d (%s)", + getpid(), errno, strerror(errno)); + } + + _D("[candidate] ecore main loop begin"); + ecore_main_loop_begin(); + + void *handle = NULL; + int (*dl_main) (int, char **); + + SECURE_LOGD("[candidate] Launch real application (%s)", g_argv[0]); + handle = dlopen(g_argv[0], RTLD_LAZY | RTLD_GLOBAL); + if (handle == NULL) + { + _E("dlopen failed (%s).", dlerror()); + exit(-1); + } + dlerror(); + + dl_main = dlsym(handle, "main"); + if (dl_main != NULL) + { + dl_main(g_argc, g_argv); + } + else + { + _E("dlsym not founded. bad preloaded app - check fpie pie"); + } + + exit(0); + } + } +} + +static app_info_from_db *_get_app_info_from_bundle_by_pkgname( + const char *pkgname, bundle *kb) +{ + app_info_from_db *menu_info; + + menu_info = calloc(1, sizeof(app_info_from_db)); + if (menu_info == NULL) { + return NULL; + } + + menu_info->pkg_name = strdup(pkgname); + menu_info->app_path = strdup(bundle_get_val(kb, AUL_K_EXEC)); + if (menu_info->app_path != NULL) + menu_info->original_app_path = strdup(menu_info->app_path); + menu_info->pkg_type = strdup(bundle_get_val(kb, AUL_K_PACKAGETYPE)); + menu_info->hwacc = strdup(bundle_get_val(kb, AUL_K_HWACC)); + menu_info->taskmanage = strdup(bundle_get_val(kb, AUL_K_TASKMANAGE)); + + if (!_get_app_path(menu_info)) { + _free_app_info_from_db(menu_info); + return NULL; + } + + return menu_info; +} + +_static_ void __launchpad_main_loop(int launchpad_fd, int *pool_fd) +{ + bundle *kb = NULL; + app_pkt_t *pkt = NULL; + app_info_from_db *menu_info = NULL; + + const char *pkg_name = NULL; + const char *app_path = NULL; + const char *launchpad_type = NULL; + int pid = -1; + int clifd = -1; + struct ucred cr; + int is_real_launch = 0; + char sock_path[UNIX_PATH_MAX] = {0,}; + int type = -1; + + pkt = __app_recv_raw(launchpad_fd, &clifd, &cr); + if (!pkt) { + _D("packet is NULL"); + goto end; + } + + kb = bundle_decode(pkt->data, pkt->len); + if (!kb) { + _D("bundle decode error"); + goto end; + } + + INIT_PERF(kb); + PERF("packet processing start"); + + pkg_name = bundle_get_val(kb, AUL_K_PKG_NAME); + SECURE_LOGD("pkg name : %s\n", pkg_name); + + menu_info = _get_app_info_from_bundle_by_pkgname(pkg_name, kb); + if (menu_info == NULL) { + _D("such pkg no found"); + goto end; + } + + app_path = _get_app_path(menu_info); + if(app_path == NULL) { + _E("app_path is NULL"); + goto end; + } + if (app_path[0] != '/') { + _D("app_path is not absolute path"); + goto end; + } + + launchpad_type = bundle_get_val(kb, AUL_K_LAUNCHPAD_TYPE); + if (launchpad_type == NULL) + { + _E("[launchpad] invalid launchpad type"); + goto end; + } + type = atoi(launchpad_type); + _D("[launchpad] launchpad type: %d", type); + + __modify_bundle(kb, cr.pid, menu_info, pkt->cmd); + pkg_name = _get_pkgname(menu_info); + + PERF("get package information & modify bundle done"); + + if ((type == 1 && __candidate[TYPE1].pid != CANDIDATE_NONE) +#ifndef _APPFW_FEATURE_PROCESS_POOL_COMMON + #ifndef _APPFW_FEATURE_PROCESS_POOL_HW_RENDERING + ) + #else + || (type == 2 && __candidate[TYPE2].pid != CANDIDATE_NONE)) + #endif +#else //_APPFW_FEATURE_PROCESS_POOL_COMMON + ) +#endif //_APPFW_FEATURE_PROCESS_POOL_COMMON + { + int i = type - 1; + snprintf(sock_path, UNIX_PATH_MAX, "%s/%d", AUL_SOCK_PREFIX, __candidate[i].pid); + unlink(sock_path); + + __candidate_process_real_launch(__candidate[i].send_fd, pkt); + _D("Request real launch to candidate_process."); + + pid = __candidate[i].pid; + is_real_launch = 1; + close(__candidate[i].send_fd); + + __candidate[i].pid = CANDIDATE_NONE; + __candidate[i].send_fd = -1; + + /* Temporary log: launch time checking */ + //LOG(LOG_DEBUG, "LAUNCH", "[%s:Platform:launchpad:done]", app_path); + + __prepare_candidate_process(type, launchpad_fd, pool_fd[type - 1], clifd); + + SECURE_LOGD("Prepare candidate process, pid: %d, bin path: %s\n", pid, app_path); + } + else + { + // legacy approach + pid = fork(); + + if (pid == 0) + { + PERF("fork done"); + _E("lock up test log(no error) : fork done"); + + close(clifd); + close(launchpad_fd); + __signal_unset_sigchld(); + __signal_fini(); + + snprintf(sock_path, UNIX_PATH_MAX, "%s/%d", AUL_SOCK_PREFIX, getpid()); + unlink(sock_path); + + PERF("prepare exec - first done"); + _E("lock up test log(no error) : prepare exec - first done"); + + if (__prepare_exec(pkg_name, app_path, menu_info, kb) < 0) + { + SECURE_LOGE("preparing work fail to launch - " + "can not launch %s\n", pkg_name); + exit(-1); + } + + PERF("prepare exec - second done"); + _E("lock up test log(no error) : prepare exec - second done"); + + __real_launch(app_path, kb); + + exit(-1); + } + _D("==> real launch pid : %d %s\n", pid, app_path); + is_real_launch = 1; + } +end: + __send_result_to_caller(clifd, pid); + + if (pid > 0) + { + if (is_real_launch) + { + /*TODO: retry*/ + __signal_block_sigchld(); + __send_app_launch_signal(pid); + __signal_unblock_sigchld(); + } + } + + if (menu_info != NULL) + { + _free_app_info_from_db(menu_info); + } + + if (kb != NULL) + { + bundle_free(kb); + } + if (pkt != NULL) + { + free(pkt); + } + + /* Active Flusing for Daemon */ + if (initialized > AUL_POLL_CNT) + { + sqlite3_release_memory(SQLITE_FLUSH_MAX); + malloc_trim(0); + initialized = 1; + } +} + +_static_ int __launchpad_pre_init(int argc, char **argv) +{ + int fd; + + /* signal init*/ + __signal_init(); + + /* get my(launchpad) command line*/ + launchpad_cmdline = __proc_get_cmdline_bypid(getpid()); + if (launchpad_cmdline == NULL) { + _E("launchpad cmdline fail to get"); + return -1; + } + _D("launchpad cmdline: %s", launchpad_cmdline); + + /* create launchpad sock */ + fd = __create_server_sock(PROCESS_POOL_LAUNCHPAD_PID); + if (fd < 0) + { + _E("server sock error"); + return -1; + } + + __preload_init(argc, argv); + + __preload_init_for_process_pool(); + +// __preexec_init(argc, argv); + + return fd; +} + +_static_ int __launchpad_post_init() +{ + /* Setting this as a global variable to keep track + of launchpad poll cnt */ + /* static int initialized = 0;*/ + + if (initialized) + { + ++initialized; + return 0; + } + + if (__signal_set_sigchld() < 0) + { + return -1; + } + + ++initialized; + + return 0; +} + +int main(int argc, char **argv) +{ + enum { + LAUNCH_PAD = 0, + POOL_TYPE1, +#ifndef _APPFW_FEATURE_PROCESS_POOL_COMMON +#ifdef _APPFW_FEATURE_PROCESS_POOL_HW_RENDERING + POOL_TYPE2, +#endif +#endif + CANDIDATE_TYPE1, +#ifndef _APPFW_FEATURE_PROCESS_POOL_COMMON +#ifdef _APPFW_FEATURE_PROCESS_POOL_HW_RENDERING + CANDIDATE_TYPE2, +#endif +#endif + POLLFD_MAX + }; + int launchpad_fd = -1; + int pool_fd[MAX_LAUNCHPAD_TYPE_NUM] = +#ifndef _APPFW_FEATURE_PROCESS_POOL_COMMON + #ifdef _APPFW_FEATURE_PROCESS_POOL_HW_RENDERING + { -1, -1 }; + #else + { -1 }; + #endif +#else //_APPFW_FEATURE_PROCESS_POOL_COMMON + { -1 }; +#endif //_APPFW_FEATURE_PROCESS_POOL_COMMON + struct pollfd pfds[POLLFD_MAX]; + int i; + + memset(pfds, 0x00, sizeof(pfds)); + + /* init without concerning X & EFL*/ + launchpad_fd = __launchpad_pre_init(argc, argv); + if (launchpad_fd < 0) + { + _E("launchpad pre init failed"); + exit(-1); + } + pfds[LAUNCH_PAD].fd = launchpad_fd; + pfds[LAUNCH_PAD].events = POLLIN; + pfds[LAUNCH_PAD].revents = 0; + + for (i = 0; i < MAX_LAUNCHPAD_TYPE_NUM; ++i) + { + pool_fd[i] = __listen_candidate_process(i + 1); + if (pool_fd[i] == -1) + { + _E("[launchpad] Listening the socket to the type%d candidate process failed.", i + 1); + goto error; + } + pfds[POOL_TYPE1 + i].fd = pool_fd[i]; + pfds[POOL_TYPE1 + i].events = POLLIN; + pfds[POOL_TYPE1 + i].revents = 0; + } + +#ifdef _APPFW_FEATURE_PRIORITY_CHANGE + int res = setpriority(PRIO_PROCESS, 0, -12); + if (res == -1) + { + SECURE_LOGE("Setting process (%d) priority to -12 failed, errno: %d (%s)", + getpid(), errno, strerror(errno)); + } +#endif + while (1) + { + for (i = 0; i < MAX_LAUNCHPAD_TYPE_NUM; ++i) + { + if (__candidate[i].pid == CANDIDATE_NONE) + { + pfds[CANDIDATE_TYPE1 + i].fd = -1; + pfds[CANDIDATE_TYPE1 + i].events = 0; + pfds[CANDIDATE_TYPE1 + i].revents = 0; + + if (DIFF(__candidate[i].last_exec_time, time(NULL)) > EXEC_CANDIDATE_EXPIRED) + { + __prepare_candidate_process(i + 1, launchpad_fd, pool_fd[i], -1); + } + } + } + + if (poll(pfds, POLLFD_MAX, -1) < 0) + continue; + + _D("pfds[LAUNCH_PAD].revent : 0x%x", pfds[LAUNCH_PAD].revents) ; + _D("pfds[POOL_TYPE1].revents : 0x%x", pfds[POOL_TYPE1].revents) ; + _D("pfds[CANDIDATE_TYPE1].revents : 0x%x", pfds[CANDIDATE_TYPE1].revents) ; +#ifndef _APPFW_FEATURE_PROCESS_POOL_COMMON +#ifdef _APPFW_FEATURE_PROCESS_POOL_HW_RENDERING + _D("pfds[POOL_TYPE2].revents : 0x%x", pfds[POOL_TYPE2].revents) ; + _D("pfds[CANDIDATE_TYPE2].revents : 0x%x", pfds[CANDIDATE_TYPE2].revents); +#endif +#endif + /* init with concerning X & EFL (because of booting + * sequence problem)*/ + if (__launchpad_post_init() < 0) + { + _E("launcpad post init failed"); + goto error; + } + + if ((pfds[LAUNCH_PAD].revents & POLLIN) != 0) + { + _D("pfds[LAUNCH_PAD].revents & POLLIN"); + __launchpad_main_loop(pfds[LAUNCH_PAD].fd, pool_fd); + } + + for (i = 0; i < MAX_LAUNCHPAD_TYPE_NUM; ++i) + { + if ((pfds[POOL_TYPE1 + i].revents & POLLIN) != 0) + { + int server_fd, client_fd; + int client_pid; + + server_fd = pfds[POOL_TYPE1 + i].fd; + + _D("pfds[POOL_TYPE%d].revents & POLLIN", i + 1); + + if (__candidate[i].pid == CANDIDATE_NONE) + { + __accept_candidate_process(server_fd, &client_fd, &client_pid); + + __candidate[i].pid = client_pid; + __candidate[i].send_fd = client_fd; + + pfds[CANDIDATE_TYPE1 + i].fd = client_fd; + pfds[CANDIDATE_TYPE1 + i].events = POLLIN | POLLHUP; + pfds[CANDIDATE_TYPE1 + i].revents = 0; + + SECURE_LOGD("Type%d candidate process was connected, pid: %d", i + 1, __candidate[i].pid); + } + else + { + __refuse_candidate_process(server_fd); + _E("Refused candidate process connection"); + } + } + + if ((pfds[CANDIDATE_TYPE1 + i].revents & (POLLHUP | POLLNVAL)) != 0) + { + SECURE_LOGD("pfds[CANDIDATE_TYPE%d].revents & (POLLHUP|POLLNVAL), pid: %d", i + 1, __candidate[i].pid); + + if (pfds[CANDIDATE_TYPE1 + i].fd > -1) + { + close(pfds[CANDIDATE_TYPE1 + i].fd); + } + + __candidate[i].pid = CANDIDATE_NONE; + __candidate[i].send_fd = -1; + + pfds[CANDIDATE_TYPE1 + i].fd = -1; + pfds[CANDIDATE_TYPE1 + i].events = 0; + pfds[CANDIDATE_TYPE1 + i].revents = 0; + } + } + } + + return 0; + +error: + if (launchpad_fd != -1) + { + close(launchpad_fd); + } + + for (i = 0; i < MAX_LAUNCHPAD_TYPE_NUM; ++i) + { + if (pool_fd[i] != -1) + { + close(pool_fd[i]); + } + if (__candidate[i].send_fd != -1) + { + close(__candidate[i].send_fd); + } + } + + return -1; +} diff --git a/process_pool/process_pool.c b/process_pool/process_pool.c new file mode 100644 index 0000000..7e62150 --- /dev/null +++ b/process_pool/process_pool.c @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2014 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 <stdio.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <linux/un.h> +#include <errno.h> +#include <systemd/sd-daemon.h> + +#include <simple_util.h> + +#include "process_pool.h" + +#define TMP_PATH "/tmp" +#define LAUNCHPAD_TYPE1 ".launchpad-type1" +#ifndef _APPFW_FEATURE_PROCESS_POOL_COMMON + #ifdef _APPFW_FEATURE_PROCESS_POOL_HW_RENDERING + #define LAUNCHPAD_TYPE2 ".launchpad-type2" + #endif +#endif //_APPFW_FEATURE_PROCESS_POOL_COMMON +#define MAX_PENDING_CONNECTIONS 10 +#define CONNECT_RETRY_TIME 100 * 1000 +#define CONNECT_RETRY_COUNT 3 + +int __listen_candidate_process(int type) +{ + struct sockaddr_un addr; + int fd = -1; + int listen_fds = 0; + int i; + + _D("[launchpad] enter, type: %d", type); + + memset(&addr, 0x00, sizeof(struct sockaddr_un)); + addr.sun_family = AF_UNIX; + if (type == 1) + { + snprintf(addr.sun_path, UNIX_PATH_MAX, "%s/%s", TMP_PATH, LAUNCHPAD_TYPE1); + } +#ifndef _APPFW_FEATURE_PROCESS_POOL_COMMON +#ifdef _APPFW_FEATURE_PROCESS_POOL_HW_RENDERING + else if (type == 2) + { + snprintf(addr.sun_path, UNIX_PATH_MAX, "%s/%s", TMP_PATH, LAUNCHPAD_TYPE2); + } +#endif +#endif + listen_fds = sd_listen_fds(0); + if (listen_fds < 0) + { + _E("Invalid systemd environment"); + return -1; + } + else if (listen_fds > 0) + { + for (i = 0; i < listen_fds; i++) + { + fd = SD_LISTEN_FDS_START + i; + if (sd_is_socket_unix(fd, SOCK_STREAM, 1, addr.sun_path, 0)) + return fd; + } + _E("Socket not found: %s", addr.sun_path); + return -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(addr)) < 0) + { + _E("bind error"); + goto error; + } + + _D("chmod %s", addr.sun_path); + if (chmod(addr.sun_path, (S_IRWXU | S_IRWXG | S_IRWXO)) < 0) + { + _E("chmod 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; +} + +int __connect_to_launchpad(int type) +{ + struct sockaddr_un addr; + int fd = -1; + int retry = CONNECT_RETRY_COUNT; + int send_ret = -1; + int client_pid = getpid(); + + _D("[launchpad] enter, type: %d", type); + + fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); + if (fd < 0) + { + _E("socket error"); + goto error; + } + + memset(&addr, 0x00, sizeof(struct sockaddr_un)); + addr.sun_family = AF_UNIX; + if (type == 1) + { + snprintf(addr.sun_path, UNIX_PATH_MAX, "%s/%s", TMP_PATH, LAUNCHPAD_TYPE1); + } +#ifndef _APPFW_FEATURE_PROCESS_POOL_COMMON +#ifdef _APPFW_FEATURE_PROCESS_POOL_HW_RENDERING + else if (type == 2) + { + snprintf(addr.sun_path, UNIX_PATH_MAX, "%s/%s", TMP_PATH, LAUNCHPAD_TYPE2); + } +#endif +#endif + _D("connect to %s", addr.sun_path); + while (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) + { + if (errno != ETIMEDOUT || retry <= 0) + { + _E("connect error : %d", errno); + goto error; + } + + usleep(CONNECT_RETRY_TIME); + --retry; + _D("re-connect to %s (%d)", addr.sun_path, retry); + } + + send_ret = send(fd, &client_pid, sizeof(client_pid), 0); + _D("send(%d) : %d", client_pid, send_ret); + + if (send_ret == -1) + { + _E("send error"); + goto error; + } + + SECURE_LOGD("[launchpad] done, connect fd: %d", fd); + return fd; + +error: + if (fd != -1) + { + close(fd); + } + + return -1; +} + +int __accept_candidate_process(int server_fd, int* out_client_fd, int* out_client_pid) +{ + int client_fd = -1, client_pid = 0, recv_ret = 0; + + 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; + } + + recv_ret = recv(client_fd, &client_pid, sizeof(client_pid), MSG_WAITALL); + + if (recv_ret == -1) + { + _E("recv error!"); + goto error; + } + + *out_client_fd = client_fd; + *out_client_pid = client_pid; + + return *out_client_fd; + +error: + if (client_fd != -1) + { + close(client_fd); + } + + return -1; +} + +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; +} + +int __send_pkt_raw_data(int client_fd, app_pkt_t *pkt) +{ + int send_ret = 0; + int pkt_size = 0; + + if (client_fd == -1 || pkt == NULL) + { + _E("arguments error!"); + goto error; + } + + pkt_size = sizeof(pkt->cmd) + sizeof(pkt->len) + pkt->len; + + send_ret = send(client_fd, pkt, pkt_size, 0); + _D("send(%d) : %d / %d", client_fd, send_ret, pkt_size); + + if (send_ret == -1) + { + _E("send error!"); + goto error; + } + else if (send_ret != pkt_size) + { + _E("send byte fail!"); + goto error; + } + + return 0; + +error: + return -1; +} diff --git a/process_pool/process_pool.h b/process_pool/process_pool.h new file mode 100644 index 0000000..a6a2c53 --- /dev/null +++ b/process_pool/process_pool.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2014 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 __PROCESS_POOL_H_ +#define __PROCESS_POOL_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif //__cplusplus + +#include <app_sock.h> + +static const int TYPE1 = 0; +#ifndef _APPFW_FEATURE_PROCESS_POOL_COMMON + #ifdef _APPFW_FEATURE_PROCESS_POOL_HW_RENDERING +static const int TYPE2 = 1; + #endif +#endif //_APPFW_FEATURE_PROCESS_POOL_COMMON + +int __listen_candidate_process(int type); +int __connect_to_launchpad(int type); +int __accept_candidate_process(int server_fd, int* out_client_fd, int* out_client_pid); +void __refuse_candidate_process(int server_fd); +int __send_pkt_raw_data(int client_fd, app_pkt_t* pkt); + +#ifdef __cplusplus +} +#endif //__cplusplus + +#endif //__PROCESS_POOL_H_ diff --git a/process_pool/process_pool_preload.h b/process_pool/process_pool_preload.h new file mode 100644 index 0000000..1fbd55f --- /dev/null +++ b/process_pool/process_pool_preload.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2014 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 __PROCESS_POOL_PRELOAD_H__ +#define __PROCESS_POOL_PRELOAD_H__ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <dlfcn.h> + +#define PROCESS_POOL_PRELOAD_FILE SHARE_PREFIX"/launchpad-process-pool-preload-list.txt" + +static int g_dlopen_size = 5; +static int g_dlopen_count = 0; +static void** g_dlopen_handle_list = NULL; + +static inline int __preload_save_dlopen_handle(void *handle) +{ + if (!handle) { + return 1; + } + if (g_dlopen_count == g_dlopen_size || !g_dlopen_handle_list) { + void** tmp = + realloc(g_dlopen_handle_list, 2 * g_dlopen_size * sizeof(void *)); + if (NULL == tmp) { + _E("out of memory\n"); + dlclose(handle); + return 1; + } + g_dlopen_size *= 2; + g_dlopen_handle_list = tmp; + } + g_dlopen_handle_list[g_dlopen_count++] = handle; + return 0; +} + +static inline void __preload_fini_for_process_pool(void) +{ + int i = 0; + if (!g_dlopen_handle_list) { + return; + } + for (i = 0; i < g_dlopen_count; ++i) + { + void *handle = g_dlopen_handle_list[i]; + if (handle) { + if (0 != dlclose(handle)) { + _E("dlclose failed\n"); + } + } + } + free(g_dlopen_handle_list); + g_dlopen_handle_list = NULL; + g_dlopen_size = 5; + g_dlopen_count = 0; +} + +static inline void __preload_init_for_process_pool(void) +{ + if (atexit(__preload_fini_for_process_pool) != 0) { + _E("Cannot register atexit callback. Libraries will not be unloaded"); + } + + void *handle = NULL; + char soname[MAX_LOCAL_BUFSZ] = { 0, }; + FILE *preload_list = NULL; + + preload_list = fopen(PROCESS_POOL_PRELOAD_FILE, "rt"); + if (preload_list == NULL) { + _E("no preload\n"); + return; + } + + while (fgets(soname, MAX_LOCAL_BUFSZ, preload_list) > 0) { + size_t len = strnlen(soname, MAX_LOCAL_BUFSZ); + if (len > 0) { + soname[len - 1] = '\0'; + } + handle = dlopen((const char *) soname, RTLD_NOW); + if (handle == NULL) { + _E("dlopen(\"%s\") was failed!", soname); + continue; + } + + if (__preload_save_dlopen_handle(handle) != 0) { + _E("Cannot save handle, no more preloads"); + break; + } + _D("preload %s# - handle : %x\n", soname, handle); + } + + fclose(preload_list); +} + +#endif //__PROCESS_POOL_PRELOAD_H__ diff --git a/process_pool/smack_util.c b/process_pool/smack_util.c new file mode 100644 index 0000000..2342556 --- /dev/null +++ b/process_pool/smack_util.c @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2014 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 <unistd.h> +#include <sys/syscall.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/smack.h> +#include <dirent.h> +#include <assert.h> + +#include <simple_util.h> + +#include "smack_util.h" + +#define SMACK_LABEL_LEN 255 +#define FILE_MAX_LEN 1024 +#define MAX_RETRY_CNT 1000 +#define UID_ROOT 0 + +static char s_smack_label[SMACK_LABEL_LEN + 1] = {0,}; +static int signal_cnt = 0; + +static int +smack_set_label_for_tid(const char *label) +{ + int len, fd, ret; + char curren_path[FILE_MAX_LEN + 1] = {0,}; + + len = strnlen(label, SMACK_LABEL_LEN + 1); + + if (len > SMACK_LABEL_LEN) + { + return -1; + } + + snprintf(curren_path, sizeof(curren_path), "/proc/%d/attr/current", (int)syscall(SYS_gettid)); + fd = open(curren_path, O_WRONLY); + if (fd < 0) + { + _E("open() failed. path: %s, errno: %d (%s)", curren_path, errno, strerror(errno)); + return -1; + } + + ret = write(fd, label, len); + close(fd); + + return (ret < 0) ? -1 : 0; +} + +static void +SIGUSR1_handler(int signo) +{ + if (smack_set_label_for_tid(s_smack_label) != 0) + { + _E("smack_set_label_for_tid() failed!"); + } + + SECURE_LOGD("tid: %d, signo: %d", (int)syscall(SYS_gettid), signo); + ++signal_cnt; +} + +static int +set_SIGUSR1_handler() +{ +#if 1 + if (signal(SIGUSR1, SIGUSR1_handler) == SIG_ERR) + { + _E("signal(SIGUSR1) failed."); + return -1; + } +#else + struct sigaction usr_action; + sigset_t usr_mask; + + sigemptyset(&usr_mask); + usr_action.sa_handler = SIGUSR1_handler; + usr_action.sa_mask = usr_mask; + usr_action.sa_flags = 0; + + if (sigaction(SIGUSR1, &usr_action, NULL) != 0) + { + _E("sigaction(SIGUSR1) failed."); + return -1; + } +#endif + return 0; +} + +static int +set_SIGUSR1_to_default() +{ + if (signal(SIGUSR1, SIG_DFL) == SIG_ERR) + { + _E("signal(SIGUSR1, SIG_ERR) failed!"); + return -1; + } + + return 0; +} + +static int +send_SIGUSR1_to_threads() +{ + int ret; + DIR *dir; + struct dirent entry, *result; + char proc_self_task_path[FILE_MAX_LEN + 1] = {0, }; + int main_tid = (int)syscall(SYS_gettid); + + sprintf(proc_self_task_path, "/proc/self/task"); + + dir = opendir(proc_self_task_path); + if (dir) + { + for (ret = readdir_r(dir, &entry, &result); + result != NULL && ret == 0; + ret = readdir_r(dir, &entry, &result)) + { + if (strncmp(entry.d_name, ".", 2) == 0 || + strncmp(entry.d_name, "..", 3) == 0) + { + continue; + } + + int tid = atoi(entry.d_name); + if (main_tid != tid) + { + SECURE_LOGD("Sending SIGUSR1 signal to the thread (%d).", tid); + if (syscall(SYS_tkill, tid, SIGUSR1) != 0) + { + _E("tkill(%d, SIGUSR1) failed.", tid); + closedir(dir); + return -1; + } + } + } + + closedir(dir); + } + else + { + _E("opendir(/proc/self/task) failed!"); + return -1; + } + + return 0; +} + +int +set_app_smack_label(const char* app_path, int type) +{ + if (UID_ROOT != getuid() || app_path == NULL) + { + _E("parameter error!"); + return -1; + } + + // set SIGUSR1 signal handler + if (set_SIGUSR1_handler() != 0) + { + _E("Setting signal hanlder failed."); + return -1; + } + + // get smack label from app_path + char *smack_label = NULL; + + if (smack_lgetlabel(app_path, &smack_label, SMACK_LABEL_EXEC) != 0) + { + _E("smack_lgetlabel() failed!"); + goto error; + } + + if (smack_label) + { + strncpy(s_smack_label, smack_label, sizeof(s_smack_label)); + s_smack_label[SMACK_LABEL_LEN] = '\0'; + + free(smack_label); + smack_label = NULL; + } + else + { + _E("smack_label is NULL!"); + strcpy(s_smack_label, ""); + } + + if (type == 2) + { + signal_cnt = 0; + + if (send_SIGUSR1_to_threads() != 0) + { + _E("Sending SIGUSR1 singnal to sub-threads failed."); + goto error; + } + + // wait for labeling on each tasks + int i = 0; + for (i = 0; signal_cnt < (type - 1) && i < MAX_RETRY_CNT; ++i) + { + usleep(1000); // 1 ms + } + + if (i == MAX_RETRY_CNT) + { + _E("Thread subject label update failed."); + } + + _D("signal count: %d, launchpad type: %d", signal_cnt, type); + } + + // set SIGUSR1 signal defualt handler + set_SIGUSR1_to_default(); + + return 0; + +error: + set_SIGUSR1_to_default(); + + return -1; +} diff --git a/process_pool/smack_util.h b/process_pool/smack_util.h new file mode 100644 index 0000000..a19f6e2 --- /dev/null +++ b/process_pool/smack_util.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2014 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 SMACK_UTIL_H +#define SMACK_UTIL_H + +int set_app_smack_label(const char* app_path, int type); + +#endif // SMACK_UTIL_H |