Support script file to register static debug tools 85/90185/23 accepted/tizen/common/20161102.121402 accepted/tizen/ivi/20161101.005513 accepted/tizen/mobile/20161101.005427 accepted/tizen/tv/20161101.005434 accepted/tizen/wearable/20161101.005453 submit/tizen/20161031.132039
authorHawnkyu Jhun <h.jhun@samsung.com>
Wed, 28 Sep 2016 12:09:56 +0000 (21:09 +0900)
committerHwankyu Jhun <h.jhun@samsung.com>
Sun, 30 Oct 2016 23:18:01 +0000 (08:18 +0900)
+---------------+--------------------------------+
| [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 <h.jhun@samsung.com>
CMakeLists.txt
inc/debugger_info.h [new file with mode: 0644]
inc/key.h
inc/launchpad_debug.h [new file with mode: 0644]
packaging/default.debugger.in [new file with mode: 0644]
packaging/launchpad.spec
src/debugger_info.c [new file with mode: 0644]
src/launchpad.c
src/launchpad_debug.c [new file with mode: 0644]

index 28ad574..2c0aa51 100755 (executable)
@@ -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 (file)
index 0000000..7f61846
--- /dev/null
@@ -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 <glib.h>
+
+typedef struct debugger_info_s *debugger_info_h;
+
+GList *_debugger_info_load(const char *path);
+void _debugger_info_unload(GList *info);
+debugger_info_h _debugger_info_find(GList *info_list, const char *name);
+const char *_debugger_info_get_exe(debugger_info_h info);
+GList *_debugger_info_get_extra_key_list(debugger_info_h info);
+GList *_debugger_info_get_extra_env_list(debugger_info_h info);
+GList *_debugger_info_get_unlink_list(debugger_info_h info);
+const char *_debugger_info_get_attach(debugger_info_h info);
+
+#endif /* __DEBUGGER_INFO_H__ */
index 7d0201f..e83bb14 100644 (file)
--- a/inc/key.h
+++ b/inc/key.h
 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 (file)
index 0000000..8bdb6ef
--- /dev/null
@@ -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 <stdbool.h>
+#include <bundle.h>
+
+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 (file)
index 0000000..ee2e717
--- /dev/null
@@ -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
index d11ed9d..06b6eb3 100644 (file)
@@ -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 (file)
index 0000000..4af4a2d
--- /dev/null
@@ -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 <stdio.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "launchpad_common.h"
+#include "debugger_info.h"
+
+#define TAG_DEBUGGER   "[DEBUGGER]"
+#define TAG_NAME       "NAME"
+#define TAG_EXE                "EXE"
+#define TAG_APP_TYPE   "APP_TYPE"
+#define TAG_EXTRA_KEY  "EXTRA_KEY"
+#define TAG_EXTRA_ENV  "EXTRA_ENV"
+#define TAG_UNLINK     "UNLINK"
+#define TAG_ATTACH     "ATTACH"
+
+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;
+}
index 7917433..09e0431 100755 (executable)
@@ -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 (file)
index 0000000..10afec8
--- /dev/null
@@ -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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <linux/limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <bundle_internal.h>
+
+#include "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);
+}