From e30355d93562b2edc8ad596149ccf3aa7140a906 Mon Sep 17 00:00:00 2001 From: Kim Gunsoo Date: Wed, 4 May 2016 13:33:23 +0900 Subject: [PATCH] Add the appcmd protocol for product extended routine. - In order to reduce the platform-dependent implementation, it is added to appcmd protocol that is a product extension structure. Conflicts: src/sdb.c Change-Id: I5ad12f8f3db0afdb588dbcaf49f98c7390cb794f Signed-off-by: Kim Gunsoo --- CMakeLists.txt | 1 + src/default_plugin.h | 1 + src/default_plugin_appcmd.c | 779 ++++++++++++++++++++++++++++++++++++ src/default_plugin_basic.c | 2 + src/default_plugin_event.c | 2 +- src/default_plugin_main.c | 8 +- src/log.h | 3 +- src/plugin.c | 91 +++++ src/plugin.h | 5 + src/sdb.c | 29 +- src/sdb.h | 9 +- src/sdbd_plugin.h | 6 +- src/services.c | 21 +- 13 files changed, 939 insertions(+), 18 deletions(-) create mode 100644 src/default_plugin_appcmd.c diff --git a/CMakeLists.txt b/CMakeLists.txt index ae6f310..6c88b77 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,6 +55,7 @@ SET(SDBD_SRCS src/default_plugin_basic.c src/default_plugin_main.c src/default_plugin_event.c + src/default_plugin_appcmd.c src/hashtable.c src/plugin.c ) diff --git a/src/default_plugin.h b/src/default_plugin.h index b8d44f3..800e495 100644 --- a/src/default_plugin.h +++ b/src/default_plugin.h @@ -31,6 +31,7 @@ int auth_support ( parameters* in, parameters* out ); int auth_get_key_file_paths ( parameters* in, parameters* out ); int confirm_public_key ( parameters* in, int out_fd ); +int appcmd_service ( parameters* in, int out_fd ); void create_pwlock_thread(); diff --git a/src/default_plugin_appcmd.c b/src/default_plugin_appcmd.c new file mode 100644 index 0000000..947a8e5 --- /dev/null +++ b/src/default_plugin_appcmd.c @@ -0,0 +1,779 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +#define TRACE_TAG TRACE_APPCMD + +#include "sysdeps.h" +#include "sdb.h" +#include "strutils.h" +#include "utils.h" +#include "log.h" + +#include "parameter.h" +#include "sdbd_plugin.h" + +#if APPCMD_USING_PKGMGR +#include +#include +#endif + +#include + +#define APPCMD_RESULT_BUFSIZE (4096) + +typedef struct appcmd_info appcmd_info; +typedef int (*appcmd_gen_shellcmd)(appcmd_info*); +typedef void (*appcmd_receiver)(int, int); +struct appcmd_info { + int fd; + + char* args[MAX_TOKENS]; + size_t args_cnt; + char* raw_command; + + appcmd_gen_shellcmd gen_cmd_func; + appcmd_receiver receiver_func; + + char shell_cmd[SDBD_SHELL_CMD_MAX]; + + int exitcode; +}; + +static int appcmd_install_gen_shellcmd(appcmd_info* p_info) { + char *type = NULL; + char *pkgpath = NULL; + char *pkgid = NULL; + char *teppath = NULL; + char *buf = p_info->shell_cmd; + int len = sizeof(p_info->shell_cmd); + + if (p_info->args_cnt != 5) { + D("failed to parse appcmd.(cnt=%d)\n", p_info->args_cnt); + return -1; + } + + type = p_info->args[1]; + pkgpath = p_info->args[2]; + pkgid = p_info->args[3]; + teppath = p_info->args[4]; + + D("args: type=%s, pkgpath=%s, pkgid=%s, teppath=%s\n", type, pkgpath, pkgid, teppath); + + if (strncmp(pkgid, "null", 4) == 0) { + if (strncmp(teppath, "null", 4) == 0) { + /* Normal install case */ + snprintf(buf, len, "pkgcmd -i -q -t %s -p %s -G", type, pkgpath); + } else { + /* TEP install case */ + snprintf(buf, len, "pkgcmd -i -q -p %s -e %s -G", pkgpath, teppath); + } + } else { + /* Re-install case */ + snprintf(buf, len, "pkgcmd -r -q -t %s -n %s", type, pkgid); + } + + return 0; +} + +static int appcmd_uninstall_gen_shellcmd(appcmd_info* p_info) { + char *type = NULL; + char *pkgid = NULL; + char *buf = p_info->shell_cmd; + int len = sizeof(p_info->shell_cmd); + + if (p_info->args_cnt != 3) { + D("failed to parse appcmd.(cnt=%d)\n", p_info->args_cnt); + return -1; + } + + type = p_info->args[1]; + pkgid = p_info->args[2]; + + D("args: type=%s, pkgid=%s\n", type, pkgid); + + snprintf(buf, len, "pkgcmd -u -q -t %s -n %s", type, pkgid); + + return 0; +} + +static int appcmd_runapp_gen_shellcmd(appcmd_info* p_info) { + char *appid = NULL; + char *buf = p_info->shell_cmd; + int len = sizeof(p_info->shell_cmd); + + if (p_info->args_cnt != 2) { + D("failed to parse appcmd.(cnt=%d)\n", p_info->args_cnt); + return -1; + } + + appid = p_info->args[1]; + + D("args: appid=%s\n", appid); + + snprintf(buf, len, "/usr/bin/app_launcher --start %s", appid); + + return 0; +} + +static int appcmd_rununittestapp_gen_shellcmd(appcmd_info* p_info) { + char *appid = NULL; + char *usr_args = NULL; + char *buf = p_info->shell_cmd; + int len = sizeof(p_info->shell_cmd); + char *ptr = NULL; + char *p_service = NULL; + char *p_appid = NULL; + + free_strings(p_info->args, p_info->args_cnt); + + p_service = strtok_r(p_info->raw_command, ":", &ptr); + p_appid = strtok_r(NULL, ":", &ptr); + if (p_service == NULL || p_appid == NULL) { + D("failed to parse appcmd.(cnt=%d)\n", p_info->args_cnt); + return -1; + } + + p_info->args_cnt = 3; + p_info->args[0] = strdup(p_service); + p_info->args[1] = strdup(p_appid); + p_info->args[2] = strdup(ptr); + + appid = p_info->args[1]; + usr_args = p_info->args[2]; + + D("args: appid=%s, usr_args=%s\n", appid, usr_args); + + snprintf(buf, len, "/usr/bin/app_launcher -s %s __AUL_SDK__ UNIT_TEST __LAUNCH_APP_MODE__ SYNC __DLP_UNIT_TEST_ARG__ \'%s\'", appid, usr_args); + + return 0; +} + +static int appcmd_killapp_gen_shellcmd(appcmd_info* p_info) { + char *appid = NULL; + char *buf = p_info->shell_cmd; + int len = sizeof(p_info->shell_cmd); + + if (p_info->args_cnt != 2) { + D("failed to parse appcmd.(cnt=%d)\n", p_info->args_cnt); + return -1; + } + + appid = p_info->args[1]; + + D("args: appid=%s\n", appid); + + snprintf(buf, len, "/usr/bin/app_launcher --kill %s", appid); + + return 0; +} + +static int appcmd_packagelist_gen_shellcmd(appcmd_info* p_info) { + char *type = NULL; + char *buf = p_info->shell_cmd; + int len = sizeof(p_info->shell_cmd); + + if (p_info->args_cnt != 2) { + D("failed to parse appcmd.(cnt=%d)\n", p_info->args_cnt); + return -1; + } + + type = p_info->args[1]; + + D("args: type=%s\n", type); + + snprintf(buf, len, "/usr/bin/pkgcmd -l -t %s", type); + + return 0; +} + +static int appcmd_debugwebapp_gen_shellcmd(appcmd_info* p_info) { + char *appid = NULL; + char *buf = p_info->shell_cmd; + int len = sizeof(p_info->shell_cmd); + + if (p_info->args_cnt != 2) { + D("failed to parse appcmd.(cnt=%d)\n", p_info->args_cnt); + return -1; + } + + appid = p_info->args[1]; + + D("args: appid=%s\n", appid); + + snprintf(buf, len, "/usr/bin/app_launcher --start %s -w", appid); + + return 0; +} + +static int appcmd_debugnativeapp_gen_shellcmd(appcmd_info* p_info) { + char *debug_port = NULL; + char *appid= NULL; + char *pid_str = NULL; + char *gdbserver_path = NULL; + char *buf = p_info->shell_cmd; + int pid = -1; + int len = sizeof(p_info->shell_cmd); + + if (p_info->args_cnt != 5) { + D("failed to parse appcmd.(cnt=%d)\n", p_info->args_cnt); + return -1; + } + + debug_port = p_info->args[1]; + appid= p_info->args[2]; + pid_str = p_info->args[3]; + gdbserver_path = p_info->args[4]; // not used. for 3.0 platform. + + pid = atoi(pid_str); + D("args: debug_port=%s, appid=%s, pid=%d, gdbserver_path=%s\n", debug_port, appid, pid, gdbserver_path); + + if (pid == -1) { + snprintf(buf, len, "/usr/bin/app_launcher --start %s __AUL_SDK__ DEBUG __DLP_DEBUG_ARG__ :%s __DLP_GDBSERVER_PATH__ %s", appid, debug_port, gdbserver_path); + } else { + /* attach mode */ + snprintf(buf, len, "/usr/bin/launch_debug %s __AUL_SDK__ ATTACH __DLP_GDBSERVER_PATH__ %s __DLP_ATTACH_ARG__ --attach,:%s,%d", appid, gdbserver_path, debug_port, pid); + } + + return 0; +} + +static int appcmd_appinfo_gen_shellcmd(appcmd_info* p_info) { + char *pkgid = NULL; + char *buf = p_info->shell_cmd; + int len = sizeof(p_info->shell_cmd); + + if (p_info->args_cnt != 2) { + D("failed to parse appcmd.(cnt=%d)\n", p_info->args_cnt); + return -1; + } + + pkgid = p_info->args[1]; + + D("args: pkgid=%s\n", pkgid); + + snprintf(buf, len, "/usr/bin/pkginfo --list %s", pkgid); + + return 0; +} + +static void appcmd_receiver_debugwebapp(int fd_in, int fd_out) +{ + char buf[4096] = {0,}; + char port_str[32] = {0,}; + char out_buf[128] = {0,}; + char* sub_str = NULL; + int r; + + for(;;) { + memset(buf, 0, sizeof(buf)); + r = read_line(fd_in, buf, sizeof(buf)); + if (r == 0) { + break; + } else if(r < 0) { + if (errno == EINTR) { + continue; + } else { + break; + } + } + + D("debug webapp output : %s\n", buf); + sub_str = strstr(buf, "port: "); + if (sub_str != NULL && sscanf(sub_str, "port: %s", port_str) == 1) { + snprintf(out_buf, sizeof(out_buf), "\n%s:%s\n", MESSAGE_PREFIX_APPCMD_RETURN, port_str); + writex(fd_out, out_buf, strlen(out_buf)+1); + break; + } + } +} + +static void appcmd_receiver_default(int fd_in, int fd_out) +{ + char buf[4096] = {0,}; + int r; + + for(;;) { + memset(buf, 0, sizeof(buf)); + r = sdb_read(fd_in, buf, sizeof(buf)); + if (r == 0) { + break; + } else if(r < 0) { + if (errno == EINTR) { + continue; + } else { + break; + } + } + + writex(fd_out, buf, strlen(buf)+1); + } +} + +static void appcmd_receiver_packagelist(int fd_in, int fd_out) +{ + char buf[4096] = {0,}; + char out_buf[4096] = {0,}; + int out_ptr = 0; + int r; + + snprintf(out_buf, sizeof(out_buf), "\n%s", MESSAGE_PREFIX_APPCMD_RETURN); + out_ptr = strlen(out_buf); + + for(;;) { + memset(buf, 0, sizeof(buf)); + r = read_line(fd_in, buf, sizeof(buf)); + if (r == 0) { + break; + } else if(r < 0) { + if (errno == EINTR) { + continue; + } else { + break; + } + } + + D("pkgcmd output : %s\n", buf); + char* sub1 = NULL; + char* sub2 = NULL; + sub1 = strstr(buf, "pkgid ["); + if (sub1 != NULL) { + sub1 = strstr(sub1, "[")+1; + sub2 = strstr(sub1, "]"); + sub2[0] = '\0'; + + snprintf(out_buf+out_ptr, sizeof(out_buf)-out_ptr, ":%s", sub1); + out_ptr += strlen(sub1)+1; + } + } + + snprintf(out_buf+out_ptr, sizeof(out_buf)-out_ptr, "\n"); + + D("package list: %s\n", out_buf); + writex(fd_out, out_buf, strlen(out_buf)+1); +} + +static void appcmd_receiver_appinfo(int fd_in, int fd_out) +{ + char buf[4096] = {0,}; + char out_buf[4096] = {0,}; + char appid[128] = {0,}; + char apptype[128] = {0,}; + int out_ptr = 0; + int r; + + snprintf(out_buf, sizeof(out_buf), "\n%s", MESSAGE_PREFIX_APPCMD_RETURN); + out_ptr = strlen(out_buf); + + for(;;) { + memset(buf, 0, sizeof(buf)); + r = read_line(fd_in, buf, sizeof(buf)); + if (r == 0) { + break; + } else if(r < 0) { + if (errno == EINTR) { + continue; + } else { + break; + } + } + + D("pkginfo output : %s\n", buf); + + if (!strncmp(buf, "Appid: ", 7)) { + memset(appid, 0, sizeof(appid)); + sscanf(buf, "Appid: %s", appid); + + snprintf(out_buf+out_ptr, sizeof(out_buf)-out_ptr, ":%s", appid); + out_ptr += strlen(appid)+1; + } else if (!strncmp(buf, "Apptype: ", 9)) { + memset(apptype, 0, sizeof(apptype)); + sscanf(buf, "Apptype: %s", apptype); + + snprintf(out_buf+out_ptr, sizeof(out_buf)-out_ptr, ":%s", apptype); + out_ptr += strlen(apptype)+1; + } + } + + snprintf(out_buf+out_ptr, sizeof(out_buf)-out_ptr, "\n"); + + D("app info: %s\n", out_buf); + writex(fd_out, out_buf, strlen(out_buf)+1); +} + +static int exec_appcmd_shell_process(appcmd_info* p_info) { + int ptm_fd = -1; + pid_t pid; + char *value = NULL; + char *trim_value = NULL; + char path[PATH_MAX]; + memset(path, 0, sizeof(path)); + + char *envp[] = { + "TERM=linux", /* without this, some programs based on screen can't work, e.g. top */ + "DISPLAY=:0", /* without this, some programs based on without launchpad can't work */ + NULL, + NULL, + NULL, + NULL, + NULL + }; + + // For the SDK user privilege. + envp[2] = "HOME=/home/developer"; + get_env("ENV_PATH", &value); + if (value != NULL) { + trim_value = str_trim(value); + if (trim_value != NULL) { + // if string is not including 'PATH=', append it. + if (strncmp(trim_value, "PATH", 4)) { + snprintf(path, sizeof(path), "PATH=%s", trim_value); + } else { + snprintf(path, sizeof(path), "%s", trim_value); + } + envp[3] = path; + free(trim_value); + } else { + envp[3] = value; + } + } + + D("path env:%s,%s,%s,%s\n", envp[0], envp[1], envp[2], envp[3]); + + char *args[] = { + SHELL_COMMAND, + "-c", + NULL, + NULL, + }; + args[2] = p_info->shell_cmd; + + ptm_fd = create_subprocess(SHELL_COMMAND, &pid, (char * const*)args, (char * const*)envp); + D("create_subprocess() ptm_fd=%d pid=%d\n", ptm_fd, pid); + if (ptm_fd < 0) { + D("cannot create service thread\n"); + return -1; + } + + if (p_info->receiver_func != NULL) { + p_info->receiver_func(ptm_fd, p_info->fd); + } + + // wait for shell process + for (;;) { + int status; + pid_t p = waitpid(pid, &status, 0); + if (p == pid) { + D("fd=%d, post waitpid(pid=%d) status=%04x\n", p_info->fd, p, status); + + if (WIFEXITED(status)) { + p_info->exitcode = WEXITSTATUS(status); + D("*** Exit code %d\n", p_info->exitcode); + break; + } + } + } + D("shell exited fd=%d of pid=%d err=%d\n", p_info->fd, pid, errno); + + return 0; +} + +#if APPCMD_USING_PKGMGR +static int get_pkg_info(char* pkgid, char* pkginfo_buf, int buf_size) { + pkgmgrinfo_pkginfo_h handle; + pkgmgr_client* pc = NULL; + char* pkgname = NULL; + char* type = NULL; + bool is_removable = 0; + int is_running = 0; + int ret = -1; + int pid = -1; + + ret = pkgmgrinfo_pkginfo_get_pkginfo(pkgid, &handle); + if (ret < 0) { + D("failed to get pkginfo handle.\n"); + return -1; + } + + ret = pkgmgrinfo_pkginfo_get_mainappid(handle, &pkgname); + if (ret < 0) { + D("failed to get pkg name\n"); + return -1; + } + + ret = pkgmgrinfo_pkginfo_get_type(handle, &type); + if (ret < 0) { + D("failed to get pkg type.\n"); + return -1; + } + + ret = pkgmgrinfo_pkginfo_is_removable(handle, &is_removable); + if (ret < 0) { + D("failed to get removable info.\n"); + return -1; + } + + pc = pkgmgr_client_new(PC_REQUEST); + if (pc == NULL) { + D("failed to create pkgmgr client.\n"); + return -1; + } + + ret = pkgmgr_client_request_service(PM_REQUEST_CHECK_APP, 0, pc, NULL, pkgid, NULL, NULL, &pid); + if (ret < 0) { + D("failed to get running state.\n"); + return -1; + } + is_running = ((pid > 0) ? 1:0); + + D("pkginfo: pkgname=%s, type=%s, is_removagle=%d, is_running=%d, pid=%d\n", pkgname, type, is_removable, is_running, pid); + snprintf(pkginfo_buf, buf_size, "%s:%s:%d:%d", pkgname, type, is_removable, is_running); + return 0; +} + +static void run_appcmd_packageinfo(appcmd_info* p_info) { + char result_buf[APPCMD_RESULT_BUFSIZE] = {0,}; + char pkginfo_buf[256] = {0,}; + char *type = NULL; + char *pkgid = NULL; + + p_info->exitcode = -1; + + if (p_info->args_cnt != 3) { + D("failed to parse appcmd.(cnt=%d)\n", p_info->args_cnt); + return; + } + + type = p_info->args[1]; + pkgid= p_info->args[2]; + + D("args: type=%s, pkgid=%s\n", type, pkgid); + + if (get_pkg_info(pkgid, pkginfo_buf, sizeof(pkginfo_buf)) == 0) { + D("success to get pkginfo. (%s)\n", pkginfo_buf); + p_info->exitcode = 0; + snprintf(result_buf, sizeof(result_buf), "\n%s:%s\n", MESSAGE_PREFIX_APPCMD_RETURN, pkginfo_buf); + writex(p_info->fd, result_buf, strlen(result_buf)); + } else { + D("failed to get pkginfo.\n"); + } +} +#else +static int appcmd_packageinfo_gen_shellcmd(appcmd_info* p_info) { + char *pkgid = NULL; + char *buf = p_info->shell_cmd; + int len = sizeof(p_info->shell_cmd); + + if (p_info->args_cnt != 2) { + D("failed to parse appcmd.(cnt=%d)\n", p_info->args_cnt); + return -1; + } + + pkgid = p_info->args[1]; + + D("args: pkgid=%s\n", pkgid); + + snprintf(buf, len, "/usr/bin/pkginfo --pkg %s;/usr/bin/pkgcmd -C -n %s", pkgid, pkgid); + + return 0; +} + +static void appcmd_receiver_packageinfo(int fd_in, int fd_out) +{ + char buf[4096] = {0,}; + char mainapp_id[128] = {0,}; + char type[128] = {0,}; + int is_removable = 0; + int is_running = 0; + int r; + + for(;;) { + memset(buf, 0, sizeof(buf)); + r = read_line(fd_in, buf, sizeof(buf)); + if (r == 0) { + break; + } else if(r < 0) { + if (errno == EINTR) { + continue; + } else { + break; + } + } + + if (!strncmp(buf, "mainappid : ", 12)) { + sscanf(buf, "mainappid : %s", mainapp_id); + } else if (!strncmp(buf, "Type: ", 6)) { + sscanf(buf, "Type: %s", type); + } else if (!strncmp(buf, "Removable: ", 11)) { + sscanf(buf, "Removable: %d", &is_removable); + } else if (strstr(buf, " is Running") != NULL) { + is_running = 1; + } + } + + memset(buf, 0, sizeof(buf)); + snprintf(buf, sizeof(buf), "\n%s:%s:%s:%d:%d\n", + MESSAGE_PREFIX_APPCMD_RETURN, mainapp_id, type, is_removable, is_running); + + D("package info: %s\n", buf); + writex(fd_out, buf, strlen(buf)+1); +} +#endif + +static void run_appcmd_appinstallpath(appcmd_info* p_info) { + char result_buf[APPCMD_RESULT_BUFSIZE] = {0,}; + + p_info->exitcode = -1; + + const char* path = tzplatform_getenv(TZ_SDK_HOME); + if (path != NULL) { + p_info->exitcode = 0; + snprintf(result_buf, sizeof(result_buf), "\n%s:%s/apps_rw/\n", MESSAGE_PREFIX_APPCMD_RETURN, path); + writex(p_info->fd, result_buf, strlen(result_buf)); + } else { + D("failed to get application install path from tzplatform_getenv."); + } +} + +static void run_appcmd_with_shell_process(appcmd_info* p_info) { + int ret = -1; + + if (p_info == NULL || p_info->gen_cmd_func == NULL) { + D("Invalid arguments.\n"); + p_info->exitcode = -1; + return; + } + + ret = p_info->gen_cmd_func(p_info); + if (ret < 0) { + D("failed to generate install shell command.\n"); + p_info->exitcode = -1; + } else { + ret = exec_appcmd_shell_process(p_info); + D("exec_appcmd_shell_process: ret=%d, exitcode=%d\n", ret, p_info->exitcode); + if (ret < 0) { + D("failed to run shell process\n"); + p_info->exitcode = -1; + } + } +} + +int appcmd_service( parameters* in, int out_fd ) { + appcmd_info info; + char result_buf[APPCMD_RESULT_BUFSIZE] = {0,}; + char* service_name = NULL; + char* command = NULL; + + if (in == NULL || in->number_of_parameter != 1 || in->array_of_parameter == NULL + || in->array_of_parameter[0].type != type_string) { + D ( "Invalid argument\n" ); + return PLUGIN_CMD_FAIL; + } + + command = in->array_of_parameter[0].v_string.data; + D("command=%s(FD:%d)\n", command, out_fd); + + memset(&info, 0, sizeof(info)); + + /* appcmd parameter data map + * "service name:arg1:arg2:...:argN" */ + info.args_cnt = tokenize(command, ":", info.args, MAX_TOKENS); + D("args_cnt=%d\n", info.args_cnt); + if (info.args_cnt < 1) { + D("failed to parse appcmd for install. (%s)\n", command); + info.exitcode = -1; + goto appcmd_done; + } + + info.fd = out_fd; + info.exitcode = -1; + info.raw_command = command; + + service_name = info.args[0]; + D("service name=%s\n", service_name); + + if (strncmp(service_name, "install", 7) == 0) { + info.receiver_func = appcmd_receiver_default; + info.gen_cmd_func = appcmd_install_gen_shellcmd; + run_appcmd_with_shell_process(&info); + // remove pkg files + if (info.args[2] != NULL) { + sdb_unlink(info.args[2]); + } + } else if (strncmp(service_name, "uninstall", 9) == 0) { + info.receiver_func = appcmd_receiver_default; + info.gen_cmd_func = appcmd_uninstall_gen_shellcmd; + run_appcmd_with_shell_process(&info); + } else if (strncmp(service_name, "appinfo", 7) == 0) { + info.gen_cmd_func = appcmd_appinfo_gen_shellcmd; + info.receiver_func = appcmd_receiver_appinfo; + run_appcmd_with_shell_process(&info); + } else if (strncmp(service_name, "packageinfo", 11) == 0) { +#if APPCMD_USING_PKGMGR + run_appcmd_packageinfo(&info); +#else + info.gen_cmd_func = appcmd_packageinfo_gen_shellcmd; + info.receiver_func = appcmd_receiver_packageinfo; + run_appcmd_with_shell_process(&info); +#endif + } else if (strncmp(service_name, "packagelist", 11) == 0) { + info.gen_cmd_func = appcmd_packagelist_gen_shellcmd; + info.receiver_func = appcmd_receiver_packagelist; + run_appcmd_with_shell_process(&info); + } else if (strncmp(service_name, "appinstallpath", 14) == 0) { + run_appcmd_appinstallpath(&info); + } else if (strncmp(service_name, "runapp", 6) == 0) { + info.receiver_func = appcmd_receiver_default; + info.gen_cmd_func = appcmd_runapp_gen_shellcmd; + run_appcmd_with_shell_process(&info); + } else if (strncmp(service_name, "rununittestapp", 14) == 0) { + info.receiver_func = appcmd_receiver_default; + info.gen_cmd_func = appcmd_rununittestapp_gen_shellcmd; + run_appcmd_with_shell_process(&info); + } else if (strncmp(service_name, "killapp", 7) == 0) { + info.receiver_func = appcmd_receiver_default; + info.gen_cmd_func = appcmd_killapp_gen_shellcmd; + run_appcmd_with_shell_process(&info); + } else if (strncmp(service_name, "debugwebapp", 11) == 0) { + info.gen_cmd_func = appcmd_debugwebapp_gen_shellcmd; + info.receiver_func = appcmd_receiver_debugwebapp; + run_appcmd_with_shell_process(&info); + } else if (strncmp(service_name, "debugnativeapp", 14) == 0) { + info.gen_cmd_func = appcmd_debugnativeapp_gen_shellcmd; + run_appcmd_with_shell_process(&info); + } else { + D("not supported appcmd service. (%s)\n", service_name); + info.exitcode = -1; + goto appcmd_done; + } + +appcmd_done: + free_strings(info.args, info.args_cnt); + + snprintf(result_buf, sizeof(result_buf), "\n%s:%d\n", MESSAGE_PREFIX_APPCMD_EXITCODE, info.exitcode); + writex(out_fd, result_buf, strlen(result_buf)); + + if (info.exitcode != 0) { + return PLUGIN_CMD_FAIL; + } + + return PLUGIN_CMD_SUCCESS; +} diff --git a/src/default_plugin_basic.c b/src/default_plugin_basic.c index 58464c7..f8ceba0 100644 --- a/src/default_plugin_basic.c +++ b/src/default_plugin_basic.c @@ -80,6 +80,8 @@ int get_plugin_capability ( parameters* in, parameters* out ) make_string_parameter ( & ( out->array_of_parameter[0] ), "%s", PLUGIN_RET_DISABLED ); } else if ( capability == CAPABILITY_LOG_PATH ) { make_string_parameter ( & ( out->array_of_parameter[0] ), "%s", LOG_DIRECTORY ); + } else if ( capability == CAPABILITY_APPCMD ) { + make_string_parameter ( & ( out->array_of_parameter[0] ), "%s", PLUGIN_RET_ENABLED ); } else { out->number_of_parameter = 0; free ( out->array_of_parameter ); diff --git a/src/default_plugin_event.c b/src/default_plugin_event.c index a336f94..2f7d745 100644 --- a/src/default_plugin_event.c +++ b/src/default_plugin_event.c @@ -37,7 +37,7 @@ int get_lock_state ( parameters* in, parameters* out ) return PLUGIN_CMD_FAIL; } - D ( "shell command : %s\n", in->array_of_parameter[0].v_string.data ); + D ( "lock type: %d\n", in->array_of_parameter[0].v_int32); out->number_of_parameter = 1; out->array_of_parameter = ( parameter* ) malloc ( sizeof ( parameter ) ); diff --git a/src/default_plugin_main.c b/src/default_plugin_main.c index 4bcecb0..a118fe7 100644 --- a/src/default_plugin_main.c +++ b/src/default_plugin_main.c @@ -28,11 +28,11 @@ int default_plugin_init ( eventfunc event_cb, registerfunc register_func ) // default plugin do not need to register command // because unsupported command by plugin should be called with default plugin anyway event_handler = event_cb; - + if (is_supported_by_plugin(PLUGIN_EVENT_PWLOCK) == 0) { create_pwlock_thread(); - } - + } + return PLUGIN_CMD_SUCCESS; } @@ -71,6 +71,8 @@ int default_plugin_async_proc ( int cmd, parameters* in, int out_fd ) if ( cmd == PLUGIN_ASYNC_CMD_AUTH_CONFIRM_PUBLIC ) { ret = confirm_public_key ( in, out_fd ); + } else if ( cmd == PLUGIN_ASYNC_CMD_APPCMD_SERVICE ) { + ret = appcmd_service ( in, out_fd ); } else { ret = PLUGIN_CMD_NOT_SUPPORT; } diff --git a/src/log.h b/src/log.h index f910f90..3d55707 100644 --- a/src/log.h +++ b/src/log.h @@ -41,7 +41,8 @@ typedef enum { TRACE_JDWP, TRACE_SERVICES, TRACE_PROPERTIES, - TRACE_SDKTOOLS + TRACE_SDKTOOLS, + TRACE_APPCMD } SdbTrace; #if SDB_TRACE diff --git a/src/plugin.c b/src/plugin.c index 7ef796f..1cf11f7 100644 --- a/src/plugin.c +++ b/src/plugin.c @@ -35,6 +35,12 @@ PLUGIN_ASYNCHRONOUS_CMD_PROC plugin_async_proc = NULL; hashtable* plugin_cmd_hashtable = NULL; +typedef struct _async_parameter { + int cmd; + parameters* in; + int out_fd; +} async_parameter; + // handler of event to be detected by plugin int plugin_event_handler ( int event_type, parameters* data ) { @@ -183,6 +189,66 @@ static int request_sync_cmd ( int cmd, parameters* in, parameters* out ) return ret; } +static void request_async_cmd ( int cmd, parameters* in, int out_fd ) +{ + int ret, pr; + + ret = hashtable_get ( plugin_cmd_hashtable, cmd, &pr ); + if ( ret == 1 ) { + // supported by plugin + ret = plugin_async_proc ( cmd, in, out_fd ); + if ( ret == PLUGIN_CMD_NOT_SUPPORT ) { + // not supported by plugin + ret = default_plugin_async_proc ( cmd, in, out_fd ); + } + } else { + // not supported by plugin + ret = default_plugin_async_proc ( cmd, in, out_fd ); + } + + release_parameters ( in ); + if ( in != NULL ) { + free( in ); + } + sdb_close(out_fd); +} + +static void *async_proc_bootstrap_func(void *x) +{ + async_parameter *p = x; + request_async_cmd(p->cmd, p->in, p->out_fd); + free(p); + return 0; +} + +static int create_async_proc_thread( int cmd, parameters* in ) +{ + async_parameter* async_param; + sdb_thread_t t; + int s[2]; + + if( sdb_socketpair(s) ) { + D("cannot create async proc socket pair\n"); + return -1; + } + + async_param = ( async_parameter* ) malloc(sizeof(async_parameter)); + if( async_param == NULL ) fatal("cannot allocate async_parameter"); + async_param->cmd = cmd; + async_param->in = in; + async_param->out_fd = s[1]; + + if(sdb_thread_create( &t, async_proc_bootstrap_func, async_param)){ + free(async_param); + sdb_close(s[0]); + sdb_close(s[1]); + D("cannot create async proc thread\n"); + return -1; + } + + D("async proc thread started, %d:%d\n",s[0], s[1]); + return s[0]; +} // return 1 if succeed to get capability from plugin // return 0 otherwise @@ -293,3 +359,28 @@ int request_lock_state_to_plugin ( int lock_type ) return result; } + +// return nonnegative integer that is a socket descriptor for communication +// with async proc thread if success to create async proc thread +// return -1 if failed to create async proc thread +int request_appcmd_to_plugin ( const char* in_buf ) +{ + parameters* in; + int fd; + + in = ( parameters* ) malloc ( sizeof ( parameters ) ); + if ( in_buf != NULL ) { + in->number_of_parameter = 1; + in->array_of_parameter = ( parameter* ) malloc ( sizeof ( parameter ) ); + in->array_of_parameter[0].type = type_string; + in->array_of_parameter[0].v_string.length = strlen ( in_buf ); + in->array_of_parameter[0].v_string.data = strdup ( in_buf ); + } else { + in->number_of_parameter = 0; + in->array_of_parameter = NULL; + } + + fd = create_async_proc_thread( PLUGIN_ASYNC_CMD_APPCMD_SERVICE, in ); + + return fd; +} diff --git a/src/plugin.h b/src/plugin.h index a553e95..fa8288e 100644 --- a/src/plugin.h +++ b/src/plugin.h @@ -49,4 +49,9 @@ int request_conversion_to_plugin ( int cmd, const char* in_buf, char* out_buf, u // return -1 if request failed int request_lock_state_to_plugin ( int lock_type ); +// return nonnegative integer that is a socket descriptor for communication +// with async proc thread if success to create async proc thread +// return -1 if failed to create async proc thread +int request_appcmd_to_plugin ( const char* in_buf ); + #endif //__PLUGIN_H diff --git a/src/sdb.c b/src/sdb.c index 727a7aa..e282ced 100644 --- a/src/sdb.c +++ b/src/sdb.c @@ -203,6 +203,7 @@ void sdb_trace_init(void) { "services", TRACE_SERVICES }, { "properties", TRACE_PROPERTIES }, { "sdktools", TRACE_SDKTOOLS }, + { "appcmd", TRACE_APPCMD }, { NULL, 0 } }; @@ -1809,7 +1810,7 @@ static void init_capabilities(void) { "%s", DISABLED); } - // sdbd log path + // sdbd log path if(!request_capability_to_plugin(CAPABILITY_LOG_PATH, g_capabilities.log_path, sizeof(g_capabilities.log_path))) { D("failed to request. (%d:%d) \n", PLUGIN_SYNC_CMD_CAPABILITY, CAPABILITY_LOG_PATH); @@ -1817,6 +1818,13 @@ static void init_capabilities(void) { "%s", UNKNOWN); } + // Application command support + if(!request_capability_to_plugin(CAPABILITY_APPCMD, g_capabilities.appcmd_support, + sizeof(g_capabilities.appcmd_support))) { + D("failed to request. (%d:%d) \n", PLUGIN_SYNC_CMD_CAPABILITY, CAPABILITY_APPCMD); + snprintf(g_capabilities.appcmd_support, sizeof(g_capabilities.appcmd_support), + "%s", UNKNOWN); + } // Capability version snprintf(g_capabilities.sdbd_cap_version, sizeof(g_capabilities.sdbd_cap_version), @@ -1855,13 +1863,28 @@ static void check_emulator_or_device() } } +static void fork_prepare_handler(void) +{ + sdb_mutex_lock(&D_lock); +} + +static void fork_parent_handler(void) +{ + sdb_mutex_unlock(&D_lock); +} + +static void fork_child_handler(void) +{ + sdb_mutex_unlock(&D_lock); +} + int sdb_main(int is_daemon, int server_port) { #if !SDB_HOST check_emulator_or_device(); load_sdbd_plugin(); - + init_capabilities(); sdb_trace_init(); @@ -1875,6 +1898,8 @@ int sdb_main(int is_daemon, int server_port) } umask(000); + + pthread_atfork(fork_prepare_handler, fork_parent_handler, fork_child_handler); #endif atexit(sdb_cleanup); diff --git a/src/sdb.h b/src/sdb.h index 5d7bd94..fec1a5d 100644 --- a/src/sdb.h +++ b/src/sdb.h @@ -256,9 +256,10 @@ typedef struct platform_capabilities char syncwinsz_support[CAPBUF_ITEMSIZE]; // enabled or disabled char usbproto_support[CAPBUF_ITEMSIZE]; // enabled or disabled char sockproto_support[CAPBUF_ITEMSIZE]; // enabled or disabled + char appcmd_support[CAPBUF_ITEMSIZE]; // enabled or disabled - char log_enable[CAPBUF_ITEMSIZE]; // enabled or disabled - char log_path[CAPBUF_LL_ITEMSIZE]; // path of sdbd log + char log_enable[CAPBUF_ITEMSIZE]; // enabled or disabled + char log_path[CAPBUF_LL_ITEMSIZE]; // path of sdbd log char cpu_arch[CAPBUF_ITEMSIZE]; // cpu architecture (ex. x86) char profile_name[CAPBUF_ITEMSIZE]; // profile name (ex. mobile) @@ -523,3 +524,7 @@ int read_line(const int fd, char* ptr, const size_t maxlen); #define USB_FUNCFS_SDB_PATH "/dev/usbgadget/sdb" #define USB_NODE_FILE "/dev/samsung_sdb" +#define SHELL_COMMAND "/bin/sh" +int create_subprocess(const char *cmd, pid_t *pid, char * const argv[], char * const envp[]); +void get_env(char *key, char **env); + diff --git a/src/sdbd_plugin.h b/src/sdbd_plugin.h index 45f2be2..5159928 100644 --- a/src/sdbd_plugin.h +++ b/src/sdbd_plugin.h @@ -36,13 +36,16 @@ // asynchronous command #define PLUGIN_ASYNC_CMD_AUTH_CONFIRM_PUBLIC 2000 +#define PLUGIN_ASYNC_CMD_APPCMD_SERVICE 2001 // event #define PLUGIN_EVENT_PWLOCK 3000 #define PLUGIN_EVENT_FMMLOCK 3001 // message -#define PLUGIN_MESSAGE_CONFIRM_PUBLIC 4000 +#define MESSAGE_PREFIX_CONFIRM_PUBLIC "auth_confirm_return" +#define MESSAGE_PREFIX_APPCMD_EXITCODE "appcmd_exitcode" +#define MESSAGE_PREFIX_APPCMD_RETURN "appcmd_returnstr" // ============================================================================== // capability definition @@ -58,6 +61,7 @@ #define CAPABILITY_PRODUCT_VER 10008 #define CAPABILITY_LOG_ENABLE 10009 #define CAPABILITY_LOG_PATH 10010 +#define CAPABILITY_APPCMD 10011 // =============================================================================== // priority definition diff --git a/src/services.c b/src/services.c index 22b9dda..5d40ce9 100644 --- a/src/services.c +++ b/src/services.c @@ -310,6 +310,7 @@ void inoti_service(int fd, void *arg) if ( ifd < 0 ) { D( "inotify_init failed\n"); + sdb_close(fd); return; } @@ -437,7 +438,7 @@ static void redirect_and_exec(int pts, const char *cmd, char * const argv[], cha execve(cmd, argv, envp); } -static int create_subprocess(const char *cmd, pid_t *pid, char * const argv[], char * const envp[]) +int create_subprocess(const char *cmd, pid_t *pid, char * const argv[], char * const envp[]) { char devname[64]; int ptm; @@ -518,7 +519,6 @@ static int create_subprocess(const char *cmd, pid_t *pid, char * const argv[], c } #endif /* !SDB_HOST */ -#define SHELL_COMMAND "/bin/sh" #define LOGIN_COMMAND "/bin/login" #define SUPER_USER "root" #define LOGIN_CONFIG "/etc/login.defs" @@ -555,7 +555,7 @@ static void subproc_waiter_service(int fd, void *cookie) } } -static void get_env(char *key, char **env) +void get_env(char *key, char **env) { FILE *fp; char buf[1024]; @@ -842,7 +842,6 @@ static int create_syncproc_thread() return ret_fd; } - #endif static void get_platforminfo(int fd, void *cookie) { @@ -995,12 +994,16 @@ static void get_capability(int fd, void *cookie) { "sdbd_cap_version", g_capabilities.sdbd_cap_version); // Sdbd log enable - offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE, - "log_enable", g_capabilities.log_enable); + offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE, + "log_enable", g_capabilities.log_enable); // Sdbd log path - offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE, - "log_path", g_capabilities.log_path); + offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE, + "log_path", g_capabilities.log_path); + + // Application command support + offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE, + "appcmd_support", g_capabilities.appcmd_support); offset++; // for '\0' character @@ -1165,6 +1168,8 @@ int service_to_fd(const char *name) char* env_variable = NULL; env_variable = strdup(name+14); ret = create_service_thread(get_tzplatform_env, (void *)(env_variable)); + } else if(!strncmp(name, "appcmd:", 7)){ + ret = request_appcmd_to_plugin(name+7); } if (ret >= 0) { -- 2.34.1