From: Hawnkyu Jhun Date: Wed, 28 Sep 2016 12:09:56 +0000 (+0900) Subject: Support script file to register static debug tools X-Git-Tag: accepted/tizen/common/20161102.121402^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F85%2F90185%2F23;p=platform%2Fcore%2Fappfw%2Flaunchpad.git Support script file to register static debug tools +---------------+--------------------------------+ | [Debugger] | Description | +---------------+--------------------------------+ | Name | Debug tool name | | Exe | Executable file | | App_type | Application type | | Extra_key | Bundle key of extra arguments | | Extra_env | Bundle key of extra environment| | | variables | | Unlink | Remove the specified file | | Attach | Attach to running process | +---------------+--------------------------------+ Change-Id: I09bf0562375d04b73ad0d076d8328fb70ca7e496 Signed-off-by: Hawnkyu Jhun --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 28ad574..2c0aa51 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,6 +99,8 @@ SET(${LAUNCHPAD_PROCESS_POOL}_SOURCE_FILES src/launchpad_common.c src/loader_info.c src/launcher_info.c + src/debugger_info.c + src/launchpad_debug.c ) ADD_EXECUTABLE(${LAUNCHPAD_PROCESS_POOL} ${${LAUNCHPAD_PROCESS_POOL}_SOURCE_FILES}) @@ -108,6 +110,8 @@ SET_TARGET_PROPERTIES(${LAUNCHPAD_PROCESS_POOL} PROPERTIES SKIP_BUILD_RPATH TRUE ) # remove rpath option that is automatically generated by cmake. +CONFIGURE_FILE(packaging/default.debugger.in packaging/default.debugger @ONLY) +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/packaging/default.debugger DESTINATION share/aul) INSTALL(TARGETS ${LAUNCHPAD_PROCESS_POOL} DESTINATION bin) CONFIGURE_FILE(packaging/default.loader.in packaging/default.loader @ONLY) diff --git a/inc/debugger_info.h b/inc/debugger_info.h new file mode 100644 index 0000000..7f61846 --- /dev/null +++ b/inc/debugger_info.h @@ -0,0 +1,33 @@ +/* + * 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); + +#endif /* __DEBUGGER_INFO_H__ */ diff --git a/inc/key.h b/inc/key.h index 7d0201f..e83bb14 100644 --- a/inc/key.h +++ b/inc/key.h @@ -21,28 +21,30 @@ extern "C" { #endif -#define AUL_K_STARTTIME "__AUL_STARTTIME__" -#define AUL_K_EXEC "__AUL_EXEC__" -#define AUL_K_PACKAGETYPE "__AUL_PACKAGETYPE__" -#define AUL_K_APP_TYPE "__AUL_APP_TYPE__" -#define AUL_K_HWACC "__AUL_HWACC__" -#define AUL_K_APPID "__AUL_APPID__" -#define AUL_K_PID "__AUL_PID__" -#define AUL_K_TASKMANAGE "__AUL_TASKMANAGE__" -#define AUL_K_INTERNAL_POOL "__AUL_INTERNAL_POOL__" -#define AUL_K_PKGID "__AUL_PKGID_" -#define AUL_K_DEBUG "__AUL_DEBUG__" +#define AUL_K_STARTTIME "__AUL_STARTTIME__" +#define AUL_K_EXEC "__AUL_EXEC__" +#define AUL_K_PACKAGETYPE "__AUL_PACKAGETYPE__" +#define AUL_K_APP_TYPE "__AUL_APP_TYPE__" +#define AUL_K_HWACC "__AUL_HWACC__" +#define AUL_K_APPID "__AUL_APPID__" +#define AUL_K_PID "__AUL_PID__" +#define AUL_K_TASKMANAGE "__AUL_TASKMANAGE__" +#define AUL_K_INTERNAL_POOL "__AUL_INTERNAL_POOL__" +#define AUL_K_PKGID "__AUL_PKGID_" +#define AUL_K_DEBUG "__AUL_DEBUG__" #define AUL_K_PRIVACY_APPID "__AUL_PRIVACY_APPID__" -#define AUL_K_COMP_TYPE "__AUL_COMP_TYPE__" -#define AUL_K_CALLER_PID "__AUL_CALLER_PID__" -#define AUL_K_LOADER_ID "__AUL_LOADER_ID__" -#define AUL_K_LOADER_PATH "__AUL_LOADER_PATH__" -#define AUL_K_LOADER_EXTRA "__AUL_LOADER_EXTRA__" -#define AUL_K_WAYLAND_DISPLAY "__AUL_WAYLAND_DISPLAY__" -#define AUL_K_WAYLAND_WORKING_DIR "__AUL_WAYLAND_WORKING_DIR__" -#define AUL_K_ROOT_PATH "__AUL_ROOT_PATH__" -#define AUL_K_API_VERSION "__AUL_API_VERSION__" -#define AUL_K_LOADER_NAME "__AUL_LOADER_NAME__" +#define AUL_K_COMP_TYPE "__AUL_COMP_TYPE__" +#define AUL_K_CALLER_PID "__AUL_CALLER_PID__" +#define AUL_K_LOADER_ID "__AUL_LOADER_ID__" +#define AUL_K_LOADER_PATH "__AUL_LOADER_PATH__" +#define AUL_K_LOADER_EXTRA "__AUL_LOADER_EXTRA__" +#define AUL_K_WAYLAND_DISPLAY "__AUL_WAYLAND_DISPLAY__" +#define AUL_K_WAYLAND_WORKING_DIR "__AUL_WAYLAND_WORKING_DIR__" +#define AUL_K_ROOT_PATH "__AUL_ROOT_PATH__" +#define AUL_K_API_VERSION "__AUL_API_VERSION__" +#define AUL_K_LOADER_NAME "__AUL_LOADER_NAME__" +#define AUL_K_SDK "__AUL_SDK__" +#define AUL_K_ORG_CALLER_PID "__AUL_ORG_CALLER_PID__" #ifdef __cplusplus } diff --git a/inc/launchpad_debug.h b/inc/launchpad_debug.h new file mode 100644 index 0000000..8bdb6ef --- /dev/null +++ b/inc/launchpad_debug.h @@ -0,0 +1,31 @@ +/* + * 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 __LAUNCHPAD_DEBUG_H__ +#define __LAUNCHPAD_DEBUG_H__ + +#include +#include + +int _debug_create_argv(int *argc, char ***argv, bool *attach); +void _debug_destroy_argv(int argc, char **argv); +int _debug_get_caller_pid(bundle *kb); +void _debug_prepare_debugger(bundle *kb); +int _debug_init(void); +void _debug_fini(void); + +#endif /* __LAUNCHPAD_DEBUG_H__ */ + diff --git a/packaging/default.debugger.in b/packaging/default.debugger.in new file mode 100644 index 0000000..ee2e717 --- /dev/null +++ b/packaging/default.debugger.in @@ -0,0 +1,20 @@ +[DEBUGGER] +NAME VALGRIND +EXE /opt/usr/home/owner/share/tmp/sdk_tools/valgrind/usr/bin/valgrind +APP_TYPE capp|c++app +EXTRA_KEY __DLP_VALGRIND_ARG__ +UNLINK /tmp/valgrind_result.txt +UNLINK /tmp/valgrind_result.xml + +[DEBUGGER] +NAME DEBUG +EXE /opt/usr/home/owner/share/tmp/sdk_tools/gdbserver/gdbserver +APP_TYPE capp|c++app +EXTRA_KEY __DLP_DEBUG_ARG__ + +[DEBUGGER] +NAME ATTACH +EXE /opt/usr/home/owner/share/tmp/sdk_tools/gdbserver/gdbserver +APP_TYPE capp|c++app +EXTRA_KEY __DLP_ATTACH_ARG__ +ATTACH true diff --git a/packaging/launchpad.spec b/packaging/launchpad.spec index d11ed9d..06b6eb3 100644 --- a/packaging/launchpad.spec +++ b/packaging/launchpad.spec @@ -79,11 +79,12 @@ cp %{_builddir}/%{name}-%{version}/LICENSE %{buildroot}/usr/share/license/%{nam %manifest launchpad.manifest %{_prefix}/share/license/%{name} %{_prefix}/share/aul/default.loader +%{_prefix}/share/aul/default.debugger %{_unitdir_user}/launchpad-process-pool.service %{_unitdir_user}/launchpad-process-pool.socket %{_unitdir_user}/sockets.target.wants/launchpad-process-pool.socket %{_unitdir_user}/basic.target.wants/launchpad-process-pool.service -%caps(cap_mac_admin,cap_setgid=ei) %{_bindir}/launchpad-process-pool +%caps(cap_mac_admin,cap_dac_override,cap_setgid=ei) %{_bindir}/launchpad-process-pool %caps(cap_setgid=ei) %{_bindir}/launchpad-loader %attr(0644,root,root) %{_libdir}/liblaunchpad.so.* diff --git a/src/debugger_info.c b/src/debugger_info.c new file mode 100644 index 0000000..4af4a2d --- /dev/null +++ b/src/debugger_info.c @@ -0,0 +1,295 @@ +/* + * 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" + +struct debugger_info_s { + char *name; + char *exe; + GList *app_types; + GList *extra_key_list; + GList *extra_env_list; + GList *unlink_list; + char *attach; +}; + +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->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; + char tok[LINE_MAX]; + + token = strtok_r(line, "|", &saveptr); + while (token) { + tok[0] = '\0'; + sscanf(token, "%s", tok); + if (tok[0] != '\0' && strcasecmp(tok, "null") != 0) { + info->app_types = g_list_append(info->app_types, + strdup(tok)); + } + token = strtok_r(NULL, "|", &saveptr); + } +} + +static GList *__parse_file(GList *list, const char *path) +{ + FILE *fp; + char buf[LINE_MAX]; + char tok1[LINE_MAX]; + char tok2[LINE_MAX]; + struct debugger_info_s *info = NULL; + + fp = fopen(path, "rt"); + if (fp == NULL) + return list; + + while (fgets(buf, sizeof(buf), fp) != NULL) { + tok1[0] = '\0'; + tok2[0] = '\0'; + sscanf(buf, "%s %s", tok1, tok2); + + if (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[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; + } + } + } + fclose(fp); + + if (info) { + _D("name: %s, exe: %s", info->name, info->exe); + list = g_list_append(list, info); + } + + return list; +} + +GList *_debugger_info_load(const char *path) +{ + DIR *dp; + struct dirent dentry; + struct dirent *result = NULL; + GList *list = NULL; + char buf[PATH_MAX]; + char *ext; + + if (path == NULL) + return NULL; + + dp = opendir(path); + if (dp == NULL) + return NULL; + + while (readdir_r(dp, &dentry, &result) == 0 && result != 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; +} diff --git a/src/launchpad.c b/src/launchpad.c index 7917433..09e0431 100755 --- a/src/launchpad.c +++ b/src/launchpad.c @@ -42,6 +42,7 @@ #include "launchpad.h" #include "loader_info.h" #include "launcher_info.h" +#include "launchpad_debug.h" #define AUL_PR_NAME 16 #define EXEC_CANDIDATE_EXPIRED 5 @@ -91,6 +92,11 @@ struct app_launch_arg { bundle *kb; }; +struct app_arg { + int argc; + char **argv; +}; + static int __sys_hwacc; static GList *loader_info_list; static int user_slot_offset; @@ -488,16 +494,17 @@ static int __send_launchpad_loader(candidate_process_context_t *cpc, return pid; } -static int __normal_fork_exec(int argc, char **argv) +static int __normal_fork_exec(int argc, char **argv, const char *app_path) { - char *libdir = NULL; + char *libdir; _D("start real fork and exec"); - libdir = _get_libdir(argv[LOADER_ARG_PATH]); - if (libdir) + libdir = _get_libdir(app_path); + if (libdir) { setenv("LD_LIBRARY_PATH", libdir, 1); - free(libdir); + free(libdir); + } _close_all_fds(); if (execv(argv[LOADER_ARG_PATH], argv) < 0) { /* Flawfinder: ignore */ @@ -514,15 +521,14 @@ static int __normal_fork_exec(int argc, char **argv) return 0; } -static int __set_launcher_info(int *argc, char ***argv, const char *app_type) +static int __create_launcher_argv(int *argc, char ***argv, const char *app_type) { + int launcher_argc; + char **launcher_argv; launcher_info_h launcher_info; - char **new_argv; - int new_argc; const char *exe; - GList *extra_args; - int extra_argc; const char *extra_arg; + GList *extra_args; GList *iter; int i; @@ -537,30 +543,111 @@ static int __set_launcher_info(int *argc, char ***argv, const char *app_type) } extra_args = _launcher_info_get_extra_args(launcher_info); - extra_argc = g_list_length(extra_args) + 1; - - new_argc = *argc + extra_argc; - new_argv = (char **)realloc(*argv, sizeof(char *) * new_argc); - if (new_argv == NULL) { - _E("Failed to reallocate memory"); + 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; } - for (i = new_argc; i >= extra_argc; i--) - new_argv[i] = new_argv[i - extra_argc]; - i = LOADER_ARG_PATH; - new_argv[i++] = strdup(exe); + launcher_argv[i++] = strdup(exe); iter = g_list_first(extra_args); while (iter) { - extra_arg = (char *)iter->data; + extra_arg = (const char *)iter->data; if (extra_arg) - new_argv[i++] = strdup(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,}; + 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 = __create_launcher_argv(&launcher_arg.argc, &launcher_arg.argv, + app_type); + if (ret < 0) { + _E("Failed to create launcher 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_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; + 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_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]; + *argc = new_argc; *argv = new_argv; @@ -570,7 +657,7 @@ static int __set_launcher_info(int *argc, char ***argv, const char *app_type) static void __real_launch(const char *app_path, bundle *kb, appinfo_t *menu_info) { - int app_argc; + int app_argc = 0; char **app_argv; int i; int ret; @@ -578,20 +665,18 @@ static void __real_launch(const char *app_path, bundle *kb, if (bundle_get_val(kb, AUL_K_DEBUG) != NULL) putenv("TIZEN_DEBUGGING_PORT=1"); - app_argv = _create_argc_argv(kb, &app_argc); - app_argv[LOADER_ARG_PATH] = strdup(app_path); - - ret = __set_launcher_info(&app_argc, &app_argv, menu_info->app_type); + ret = __create_app_argv(&app_argc, &app_argv, app_path, + kb, menu_info->app_type); if (ret < 0) { - _E("Failed to set launcher info"); + _E("Failed to create app argv"); exit(-1); } - for (i = 0; i < app_argc; i += 2) + 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); + __normal_fork_exec(app_argc, app_argv, app_path); } static int __prepare_exec(const char *appid, const char *app_path, @@ -646,6 +731,9 @@ static int __exec_app_process(void *arg) 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(); __signal_fini(); @@ -1081,7 +1169,9 @@ static int __check_caller_by_pid(int pid) if (ret < 0) return -1; - if (strcmp(buf, "User") == 0) + if (strcmp(buf, "User") == 0 || + strcmp(buf, "System") == 0 || + strcmp(buf, "System::Privileged") == 0) return 0; return -1; @@ -1153,6 +1243,7 @@ static gboolean __handle_launch_event(gpointer data) int type = -1; int loader_id; int ret; + int caller_pid; traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "LAUNCHPAD:LAUNCH"); pkt = _recv_pkt_raw(fd, &clifd, &cr); @@ -1174,6 +1265,17 @@ static gboolean __handle_launch_event(gpointer data) goto end; } + if (bundle_get_type(kb, AUL_K_SDK) != BUNDLE_TYPE_NONE) { + caller_pid = _debug_get_caller_pid(kb); + if (caller_pid > 0) { + if (__check_caller_by_pid(caller_pid) < 0) { + _E("Invalid caller pid"); + goto end; + } + } + _debug_init(); + } + switch (pkt->cmd) { case PAD_CMD_VISIBILITY: ret = __dispatch_cmd_hint(kb, METHOD_VISIBILITY); @@ -1558,6 +1660,7 @@ static int __before_loop(int argc, char **argv) static void __after_loop(void) { + _debug_fini(); _launcher_info_unload(launcher_info_list); if (label_monitor) diff --git a/src/launchpad_debug.c b/src/launchpad_debug.c new file mode 100644 index 0000000..10afec8 --- /dev/null +++ b/src/launchpad_debug.c @@ -0,0 +1,308 @@ +/* + * 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 "launchpad_common.h" +#include "launchpad_debug.h" +#include "debugger_info.h" +#include "key.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 *extra_argv_list; + +int _debug_create_argv(int *argc, char ***argv, bool *attach) +{ + int new_argc; + char **new_argv; + const char *exe; + const char *extra_argv; + const char *attach_str; + GList *iter; + 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 -1; + + attach_str = _debugger_info_get_attach(debugger_info); + if (attach_str && strcasecmp(attach_str, "true") == 0) + *attach = true; + + new_argc = g_list_length(extra_argv_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(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, 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; + } + + /* 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 __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[1], 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; + + _D("[DEBUG] debugger: %s", debugger); + debugger_info = _debugger_info_find(debugger_info_list, debugger); + if (debugger_info == NULL) + return; + + ret = __redirect_std_fds(kb); + if (ret < 0) + _E("[DEBUG] Failed to redirect standard fds"); + + 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_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); +}