From 442b9022b042b51b1f2af1783e21b93ed3ea9c60 Mon Sep 17 00:00:00 2001 From: greatim Date: Wed, 10 Apr 2013 20:00:29 +0900 Subject: [PATCH] [Title] apply runtime config and new protocol [Desc.] [Issue] Change-Id: I898f630aaa4494647ce5fa7dd73e2cba0b7e3c69 --- daemon/Makefile | 8 +- daemon/da_daemon.c | 1670 ------------------------------- daemon/{da_debug.h => da_debug.c} | 47 +- daemon/daemon.c | 891 +++++++++++++++++ daemon/daemon.h | 195 ++++ daemon/main.c | 329 ++++++ daemon/sys_stat.c | 27 +- daemon/sys_stat.h | 13 - daemon/threads.c | 299 ++++++ daemon/utils.c | 539 +++++++--- daemon/utils.h | 43 +- packaging/dynamic-analysis-manager.spec | 3 +- 12 files changed, 2198 insertions(+), 1866 deletions(-) delete mode 100644 daemon/da_daemon.c rename daemon/{da_debug.h => da_debug.c} (60%) create mode 100644 daemon/daemon.c create mode 100644 daemon/daemon.h create mode 100644 daemon/main.c create mode 100644 daemon/threads.c diff --git a/daemon/Makefile b/daemon/Makefile index d08072e..c5889ca 100644 --- a/daemon/Makefile +++ b/daemon/Makefile @@ -21,8 +21,11 @@ INC := -I/usr/include \ -I/usr/include/vconf DAEMON_SRCS := \ - da_daemon.c \ - utils.c \ + main.c \ + daemon.c \ + threads.c \ + da_debug.c \ + utils.c \ sys_stat.c LDLIBS_PATH := -L/usr/lib -L./lib/ @@ -38,7 +41,6 @@ LIBS_TIZEN :=# -lcapi-system-runtime-info \ -lSLP-db-util LIBS_COMMON := -lglib-2.0 \ -lvconf \ - -laul \ -lcapi-system-info DEBUG_ON := -DDEBUG=1 diff --git a/daemon/da_daemon.c b/daemon/da_daemon.c deleted file mode 100644 index 10f6e89..0000000 --- a/daemon/da_daemon.c +++ /dev/null @@ -1,1670 +0,0 @@ -/* -* DA manager -* -* Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. -* -* Contact: -* -* Jaewon Lim -* Woojin Jung -* Juyoung Kim -* - * 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. -* -* Contributors: -* - S-Core Co., Ltd -* -*/ - -#include -#include // for realpath -#include // for strtok, strcpy, strncpy -#include // for assert -#include // for realpath - -#define __USE_GNU -#include // for socket, mkdir, opendir, readdir -#include // for socket -#include // for sockaddr_un -#include // for sockaddr_in, socklen_t -#include // for chmod, mkdir -#include // for setitimer -#include // for sigemptyset, sigset_t, sigaddset, ... -#include // for unlink -#include // for pthread_mutex_t -#include // for epoll apis -#include // for shmctl -#include // for shared memory operation -#include // for opendir, readdir - -#include "utils.h" -#include "sys_stat.h" -#include "da_debug.h" - -#define MAX_PATH_LENGTH 256 -#define TARGET_CLIENT_COUNT_MAX 8 -#define READ_BUF_MAX 4096+8 -#define DA_LOG_MAX 4096 -#define APP_INSTALL_PATH_MAX 1024 -#define UDS_NAME "/tmp/da.socket" -#define DA_INSTALL_DIR "/home/developer/sdk_tools/da/" -#define DA_INSTALL_PATH "/home/developer/sdk_tools/da/da_install_path" -#define DA_BUILD_OPTION "/home/developer/sdk_tools/da/da_build_option" -#define DA_BASE_ADDRESS "/home/developer/sdk_tools/da/da_base_address" -#define DA_READELF_PATH "/home/developer/sdk_tools/da/readelf" -#define SCREENSHOT_DIR "/tmp/da" -#define HOST_MSG_LENGTH 3 -#define SHAREDMEMKEY ((key_t)463825) - -#define TIMER_INTERVAL_SEC 1 -#define TIMER_INTERVAL_USEC 0 - -#define SECOND_INTERVAL -#define MONITORING_INTERVAL 1 // 1 second - -#ifdef SECOND_INTERVAL -#define __sleep sleep -#else -#define __sleep usleep -#endif - -#define RUN_APP_LOADER 1 - -enum TargetMessageType -{ - MSG_DEVICE = 1, - MSG_TIME = 2, - MSG_SAMPLE = 3, - MSG_RESOURCE = 4, - MSG_LOG = 5, - MSG_IMAGE = 6, - MSG_TERMINATE = 7, - MSG_PID = 8, - MSG_MSG = 9, - MSG_APPNAME = 10, - MSG_ERROR = 11 -}; - -enum HostMessageType -{ - MSG_HOST_BEGIN = 100, - MSG_START = 100, - MSG_STOP = 101, - MSG_PAUSE = 102, - MSG_OPTION = 103, - MSG_ISALIVE = 104, - MSG_ALIVE = 105, - MSG_BATT_START = 106, - MSG_BATT_STOP = 107, - MSG_HOST_END = 107 -}; - -enum DAState -{ - DAS_NONE = 0, - DAS_START_BEGIN = 1, - DAS_TARGET_ARM_START = 1, - DAS_TARGET_X86_START = 2, - DAS_EMUL_ARM_START = 3, - DAS_EMUL_X86_START = 4, - DAS_TARGET_ARM_BATT_START = 5, - DAS_TARGET_X86_BATT_START = 6, - DAS_EMUL_ARM_BATT_START = 7, - DAS_EMUL_X86_BATT_START = 8, - DAS_START_END = 8, - DAS_STOP = 9, - DAS_TERMINATE = 10 -}; - -typedef struct -{ - int type; - int length; - char data[DA_LOG_MAX]; -} log_t; - -//TODO : -typedef struct -{ - enum DAState status; - int serverSockFD; - int clientSockFD; -} __daHostInfo; - -typedef struct -{ - enum DAState status; - int serverSockFD; - int connectCount; - int pidCount; - int clientSockFD[TARGET_CLIENT_COUNT_MAX]; - int execPID[TARGET_CLIENT_COUNT_MAX]; // exec PID by target -} __daTargetInfo; - -typedef struct -{ - long long allocsize; - long launch_flag; -} __daSharedInfo; - -typedef struct -{ - int memid; - __daSharedInfo* pvalue; -} __daSharedMem; - -typedef struct -{ - pthread_t timer_thread; - pthread_mutex_t sendMutex; - char appPath[128]; // application executable path - __daSharedMem sharedmem; - __daHostInfo iHost; - __daTargetInfo iTarget; -}__daManager; - -__daManager manager = -{ - -1, // timer_thread handle - PTHREAD_MUTEX_INITIALIZER, // pthread_mutex_t sendMutex - { 0, }, // char appPath[128] - { -1, (void*)-1 }, // __daSharedMem sharedmem - { DAS_NONE, -1, -1 }, // __daHostInfo iHost - { DAS_NONE, -1, 0, 0, {0, }, {0, }} // __daTargetInfo iTarget -}; - -int aul_terminate_pid(int pid); -static void* terminate_thread(void* data); -static void terminate_error(char* errstr, int sendtohost); - -#ifdef LOCALTEST -int aul_terminate_pid(int pid) -{ - return kill(pid, SIGTERM); -} -#endif - -int _terminate_pid(int pid) -{ - int ret; - pid_t* pids; - pthread_t term_thread; - - ret = aul_terminate_pid(pid); - - pids = (pid_t*)malloc(2 * sizeof(pid_t)); - pids[0] = pid; - pids[1] = -2; - - pthread_create(&term_thread, NULL, terminate_thread, pids); - - return ret; -} - -// return 0 if succeed -// return -1 if error occured -static int remove_indir(const char *dirname) -{ - DIR *dir; - struct dirent *entry; - char path[MAX_PATH_LENGTH]; - - dir = opendir(dirname); - if(dir == NULL) - { - return -1; - } - - while((entry = readdir(dir)) != NULL) - { - if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")) - { - snprintf(path, (size_t) MAX_PATH_LENGTH, "%s/%s", dirname, entry->d_name); - if (entry->d_type != DT_DIR) // file - { - unlink(path); - } - else { } // directory - } - } - closedir(dir); - - return 0; -} - -// index is started from 0 -int set_launch_flag(int index, int bOn) -{ - int ret = 0; - // set launch flag before execute application - if(__builtin_expect(manager.sharedmem.pvalue != (void*)-1, 1)) - { - if(bOn != 0) - manager.sharedmem.pvalue->launch_flag |= (1 << index); - else - manager.sharedmem.pvalue->launch_flag &= ~(1 << index); - } - else - ret = -1; - - return ret; -} - -long long get_total_alloc_size() -{ - if(__builtin_expect(manager.sharedmem.pvalue != (void*)-1, 1)) - { - return manager.sharedmem.pvalue->allocsize; - } - else - { - return 0L; - } -} - -// return 0 for normal case -static int __makeTargetServerSockFD() -{ - struct sockaddr_un serverAddrUn; - - if(manager.iTarget.serverSockFD != -1) - return -1; // should be never happend - - // remove pre unix domain socket file - // remove(UDS_NAME); - unlink(UDS_NAME); - - if ((manager.iTarget.serverSockFD = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) - { - LOGE("Target server socket creation failed\n"); - return -1; - } - bzero(&serverAddrUn, sizeof(serverAddrUn)); - serverAddrUn.sun_family = AF_UNIX; - sprintf(serverAddrUn.sun_path, "%s", UDS_NAME); - - if (-1 == bind(manager.iTarget.serverSockFD, (struct sockaddr*) &serverAddrUn, - sizeof(serverAddrUn))) - { - LOGE("Target server socket binding failed\n"); - close(manager.iTarget.serverSockFD); - return -1; - } - - chmod(serverAddrUn.sun_path, 0777); - - if (-1 == listen(manager.iTarget.serverSockFD, 5)) - { - LOGE("Target server socket listening failed\n"); - close(manager.iTarget.serverSockFD); - return -1; - } - - LOGI("Created TargetSock %d\n", manager.iTarget.serverSockFD); - return 0; -} - -// return 0 for normal case -static int __makeHostServerSockFD() -{ - struct sockaddr_in serverAddrIn; - int opt = 1; - - if(manager.iHost.serverSockFD != -1) - return -1; // should be never happened - - if ((manager.iHost.serverSockFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) - { - LOGE("Host server socket creation failed\n"); - return -1; - } - - setsockopt(manager.iHost.serverSockFD, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); - memset(&serverAddrIn, 0, sizeof(serverAddrIn)); - serverAddrIn.sin_family = AF_INET; - serverAddrIn.sin_addr.s_addr = htonl(INADDR_ANY); - serverAddrIn.sin_port = htons(8001); - - // bind address to server socket - if (-1 == bind(manager.iHost.serverSockFD, (struct sockaddr*) &serverAddrIn, sizeof(serverAddrIn))) - { - LOGE("Host server socket binding failed\n"); - close(manager.iHost.serverSockFD); - return -1; - } - - // enter listen state from client - if (-1 == listen(manager.iHost.serverSockFD, 5)) - { - LOGE("Host server socket listening failed\n"); - close(manager.iHost.serverSockFD); - return -1; - } - - LOGI("Created HostSock %d\n", manager.iHost.serverSockFD); - return 0; -} - -static int __destroySharedMemory() -{ - int ret = 0; - if(manager.sharedmem.pvalue != (void*)-1) - { - ret = shmdt(manager.sharedmem.pvalue); - if(ret == 0) - manager.sharedmem.pvalue = (void*)-1; - } - - if(manager.sharedmem.memid != -1) - { - ret = shmctl(manager.sharedmem.memid, IPC_RMID, 0); - if(ret == 0) - manager.sharedmem.memid = -1; - } - - return ret; -} - -// return 0 for normal case -// return -1 for error case -static int __createSharedMemory() -{ - manager.sharedmem.memid = shmget(SHAREDMEMKEY, sizeof(__daSharedInfo), IPC_CREAT | 0666); - if(manager.sharedmem.memid == -1) - { - return -1; - } - else - { - manager.sharedmem.pvalue = (__daSharedInfo*)shmat(manager.sharedmem.memid, NULL, 0); - if(manager.sharedmem.pvalue == (void*)-1) - { - __destroySharedMemory(); - return -1; - } - else - { - manager.sharedmem.pvalue->allocsize = 0; - manager.sharedmem.pvalue->launch_flag = 0; - return 0; - } - } -} - -/* -static log_t * parsLogData(log_t * log, char* logStr) -{ -#if 1 - int i, nPos; - - if (logStr == NULL || log == NULL) - return NULL; - - //msgType - for (i = 0, nPos = 0; i < READ_BUF_MAX; i++) - { - if (logStr[i] == '|') - { - logStr[i] = '\0'; - log->type = atoi(&logStr[nPos]); - i++; - break; - } - if (logStr[i] == '\0') - return NULL; - } - //length - for (nPos = i; i < READ_BUF_MAX; i++) - { - if (logStr[i] == '|' || logStr[i] == '\0') - { - logStr[i] = '\0'; - log->length = atoi(&logStr[nPos]); - i++; - break; - } - } - //data - if ((log->length > 0) && (log->length < DA_LOG_MAX)) - { - strncpy(log->data, &logStr[i], log->length); - log->data[log->length] = '\0'; - } - - return log; - -#else - - int i; - char * startPos = logStr; - char tempBuf[READ_BUF_MAX]; - - if(logStr && log) - { - log->type = -1; - log->length = 0; - log->data[0]='\0'; - //type,length - for(i=0; itype == -1) - { - log->type = atoi(startPos); - startPos = &logStr[i+1]; - } - else { - log->length = atoi(startPos); - startPos = &logStr[i+1]; - break; - } - } - } - //data - if((log->length > 0) && (log->length < DA_LOG_MAX) && (startPos)) - { - strncpy(log->data, startPos, log->length); - log->data[log->length] = '\0'; - } - LOGI("log type : %d, length : %d, data : %s\n", log->type, log->length, log->data); - return log; - } - else - return NULL; -#endif -} -*/ - -static int get_app_type(void) -{ - int fd; - char buf[DA_LOG_MAX]; - - sprintf(buf, "%s.exe", manager.appPath); - fd = open(buf, O_RDONLY); - if(fd != -1) - { - close(fd); - return APP_TYPE_OSP; - } - else - { - return APP_TYPE_TIZEN; - } -} - -static int get_executable(char* buf, int buflen) -{ - int fd; - - sprintf(buf, "%s.exe", manager.appPath); - fd = open(buf, O_RDONLY); - if(fd != -1) - { - close(fd); - } - else - { - strcpy(buf, manager.appPath); - } - return 0; -} - -static int get_app_install_path(char *strAppInstall, int length) -{ - FILE *fp; - char buf[DA_LOG_MAX]; - char *p; - int i; - - if ((fp = fopen(DA_INSTALL_PATH, "r")) == NULL) - { - LOGE("Failed to open %s\n", DA_INSTALL_PATH); - return -1; - } - - /*ex : <15> DW_AT_comp_dir : (indirect string, offset: 0x25f): /home/yt/workspace/templatetest/Debug-Tizen-Emulator */ - while (fgets(buf, DA_LOG_MAX, fp) != NULL) - { - //name - p = buf; - for (i = 0; i < DA_LOG_MAX; i++) - { - if (*p == ':') - break; - p++; - } - - if (*p != ':') - break; - else - p++; - - //(...,offset:...) - for (; i < DA_LOG_MAX; i++) - { - if (*p == '(') - { - while (*p != ')') - { - p++; - } - } - if (*p == ':') - break; - p++; - } - - //find - if (*p != ':') - break; - for (; i < DA_LOG_MAX; i++) - { - if (*p == ':' || *p == ' ' || *p == '\t') - p++; - else - break; - } - - //name - if (strlen(p) <= length) - { - sprintf(strAppInstall, "%s", p); - for (i = 0; i < strlen(p); i++) - { - if (strAppInstall[i] == '\n' || strAppInstall[i] == '\t') - { - strAppInstall[i] = '\0'; - break; - } - } - fclose(fp); - return 1; - } - } - fclose(fp); - return -1; -} - -static int is_app_built_pie(void) -{ - int result; - FILE *fp; - char buf[DA_LOG_MAX]; - - if((fp = fopen(DA_BUILD_OPTION, "r")) == NULL) - { - LOGE("Failed to open %s\n", DA_BUILD_OPTION); - return -1; - } - - if(fgets(buf, DA_LOG_MAX, fp) != NULL) - { - if(strcmp(buf, "DYN\n") == 0) - result = 1; - else if(strcmp(buf, "EXEC\n") == 0) - result = 0; - else - result = -1; - } - else - { - result = -1; - } - fclose(fp); - - return result; -} - -static int get_app_base_address(int *baseAddress) -{ - int res; - FILE *fp; - char buf[DA_LOG_MAX]; - - if((fp = fopen(DA_BASE_ADDRESS, "r")) == NULL) - { - LOGE("Failed to open %s\n", DA_BASE_ADDRESS); - return -1; - } - - if(fgets(buf, DA_LOG_MAX, fp) != NULL) - { - res = sscanf(buf, "%x", baseAddress); - } - else - { - res = -1; - } - fclose(fp); - - return res; -} - -static int is_same_app_process(int pid) -{ - int ret = 0; - FILE *fp; - char buf[DA_LOG_MAX]; - char cmdPath[PATH_MAX]; - char execPath[PATH_MAX]; - - get_executable(execPath, PATH_MAX); - sprintf(cmdPath, "/proc/%d/cmdline", pid); - - if((fp = fopen(cmdPath, "r")) == NULL) - { - return 0; - } - - if(fgets(buf, DA_LOG_MAX, fp) != NULL) - { -#if RUN_APP_LOADER - if(strcmp(buf, manager.appPath) == 0) -#else - // use execPath instead of manager.appPath - if(strcmp(buf, execPath) == 0) -#endif - ret = 1; - else - ret = 0; - } - fclose(fp); - - return ret; -} - -static int sendMsgStrToHost(char* str, int msgType, int targetNo) -{ - static int initialized = 0; - int pid; - int is_pie_build; - int base_address; - int app_type; - char log[DA_LOG_MAX]; - char bufDeviceInfo[DA_LOG_MAX]; - char bufAppInstall[APP_INSTALL_PATH_MAX]; - - switch (msgType) - { - case MSG_LOG: - case MSG_RESOURCE: - case MSG_SAMPLE: - case MSG_ERROR: - if(__builtin_expect(initialized == 0, 0)) - return -1; - sprintf(log, "%d|%s\n", msgType, str); - break; - case MSG_PID: - LOGI("MSG_PID handling : %s\n", str); - pid = atoi(str); - if ((manager.iTarget.execPID[targetNo] != -1) && (pid != manager.iTarget.execPID[targetNo])) - { - LOGE("Failed to check pid, pid of msg(%d), stored pid(%d)\n", pid, manager.iTarget.execPID[targetNo]); - return -1; - } - LOGI("pid[%d]=%d\n",targetNo,pid); - manager.iTarget.execPID[targetNo] = pid; - manager.iTarget.pidCount++; - - { - char execPath[PATH_MAX]; - char realPath[PATH_MAX]; - char mapsPath[PATH_MAX]; - char appInstallCommand[PATH_MAX]; - - get_executable(execPath, PATH_MAX); - if(realpath(execPath, realPath) == NULL) - { - LOGW("Failed to get realpath of app\n"); - strcpy(realPath, execPath); - } - - sprintf(mapsPath, "/proc/%d/maps", manager.iTarget.execPID[targetNo]); - sprintf(appInstallCommand, - "cat %s | grep %s | cut -d\"-\" -f1 > %s", mapsPath, - realPath, DA_BASE_ADDRESS); - LOGI("appInstallCommand is %s\n", appInstallCommand); - - do { - if(access(mapsPath, F_OK) != 0) - return -1; - if(is_same_app_process(manager.iTarget.execPID[targetNo]) == 0) - return -1; - - system(appInstallCommand); - if(get_app_base_address(&base_address) == 1) - break; - sleep(0); - } - while(1); - } - return 0; - break; - case MSG_TIME: - LOGI("MSG_TIME handling : %s\n", str); - if (strlen(manager.appPath) > 0) - { - is_pie_build = is_app_built_pie(); - get_app_base_address(&base_address); - app_type = get_app_type(); - bufAppInstall[0] = '\0'; - get_app_install_path(bufAppInstall, APP_INSTALL_PATH_MAX); - get_device_info(bufDeviceInfo, DA_LOG_MAX); - if (strlen(bufAppInstall) > 0) - { - char buf[PATH_MAX]; - get_executable(buf, PATH_MAX); - sprintf(log, "%d|%s`,%d`,%s`,%d`,%u`,%d`,%s/%s\n", MSG_DEVICE, bufDeviceInfo, - manager.iTarget.execPID[targetNo], str, is_pie_build, base_address, app_type, - bufAppInstall, get_app_name(buf)); - } - else - sprintf(log, "%d|%s`,%d`,%s`,%d`,%u`,%d`,\n", MSG_DEVICE, bufDeviceInfo, - manager.iTarget.execPID[targetNo], str, is_pie_build, base_address, app_type); - LOGI("MSG_DEVICE msg : %s\n", log); - } - else - { - sprintf(log, "%d|%d`,%s", MSG_PID, manager.iTarget.execPID[targetNo], str); - LOGI("MSG_DEVICE msg without appname : %s\n", log); - } - initialized = 1; - break; - case MSG_TERMINATE: - LOGI("MSG_TERMINATE handling : connectCount(%d)\n", manager.iTarget.connectCount); - if(manager.iTarget.connectCount == 1 ){ - sprintf(log, "%d|\n", msgType); - pthread_mutex_lock(&(manager.sendMutex)); -#ifndef LOCALTEST - send(manager.iHost.clientSockFD, log, strlen(log), 0); -#else - LOGI("send to host : %s\n", log); -#endif - pthread_mutex_unlock(&(manager.sendMutex)); - } - return 0; - default: - sprintf(log, "%d|%s\n", msgType, str); - break; - } - - if(manager.iHost.status >= DAS_TARGET_ARM_BATT_START && manager.iHost.status <= DAS_EMUL_X86_BATT_START) - { - LOGI("write batt log\n"); - write_batt_log(log); - } - else - { - if (manager.iHost.clientSockFD != -1) - { - pthread_mutex_lock(&(manager.sendMutex)); -#ifndef LOCALTEST - send(manager.iHost.clientSockFD, log, strlen(log), 0); -#else - LOGI("send to host : %s\n", log); -#endif - pthread_mutex_unlock(&(manager.sendMutex)); - } - } - return 0; -} - -static void* timerThread(void* data) -{ - int err, signo; - char buf[DA_LOG_MAX]; - sigset_t waitsigmask; - - LOGI("Timer thread started\n"); - - sigemptyset(&waitsigmask); - sigaddset(&waitsigmask, SIGALRM); - sigaddset(&waitsigmask, SIGUSR1); - - while(1) - { - err = sigwait(&waitsigmask, &signo); - if(err != 0) - { - LOGE("Failed to sigwait() in timer thread\n"); - continue; - } - - if(signo == SIGALRM) - { - get_resource_info(buf, DA_LOG_MAX, manager.iTarget.execPID, manager.iTarget.pidCount); - sendMsgStrToHost(buf, MSG_RESOURCE, -1); - - if (manager.iTarget.status < DAS_START_BEGIN || manager.iTarget.status > DAS_START_END ) - break; - } - else if(signo == SIGUSR1) - { - // end this thread - break; - } - else - { - // not happened - LOGE("This should not be happend in timer thread\n"); - } - } - - LOGI("Timer thread ended\n"); - return NULL; -} - -// return 0 if normal case -// return minus value if critical error -// return plus value if non-critical error -static int timerStart() -{ - sigset_t newsigmask; - struct itimerval timerval; -// char buf[DA_LOG_MAX]; - - if(manager.timer_thread != -1) // already started - return 1; - - sigemptyset(&newsigmask); - sigaddset(&newsigmask, SIGALRM); - sigaddset(&newsigmask, SIGUSR1); - if(pthread_sigmask(SIG_BLOCK, &newsigmask, NULL) != 0) - { - LOGE("Failed to signal masking for main thread\n"); - return -1; - } - - if(pthread_create(&(manager.timer_thread), NULL, timerThread, NULL) < 0) - { - LOGE("Failed to create timer thread\n"); - return -1; - } - - timerval.it_interval.tv_sec = TIMER_INTERVAL_SEC; - timerval.it_interval.tv_usec = TIMER_INTERVAL_USEC; - timerval.it_value.tv_sec = TIMER_INTERVAL_SEC; - timerval.it_value.tv_usec = TIMER_INTERVAL_USEC; - setitimer(ITIMER_REAL, &timerval, NULL); - - // commected because this resource log send to host before receiving MSG_TIME message from target process - // send initial value of profiling -// get_resource_info(buf, DA_LOG_MAX, manager.iTarget.execPID, manager.iTarget.pidCount); -// sendMsgStrToHost(buf, MSG_RESOURCE, -1); - - return 0; -} - -static int timerStop() -{ - if(manager.timer_thread != -1) - { -// int status; -// sigset_t oldsigmask; - struct itimerval stopval; - -// sigemptyset(&oldsigmask); -// sigaddset(&oldsigmask, SIGALRM); -// sigaddset(&oldsigmask, SIGUSR1); - - stopval.it_interval.tv_sec = 0; - stopval.it_interval.tv_usec = 0; - stopval.it_value.tv_sec = 0; - stopval.it_value.tv_usec = 0; - - // stop timer - setitimer(ITIMER_REAL, &stopval, NULL); - - pthread_kill(manager.timer_thread, SIGUSR1); -// pthread_join(manager.timer_thread, (void**) &status); - -// if(sigprocmask(SIG_UNBLOCK, &oldsigmask, NULL) < 0) -// { -// LOGE("Failed to pthread_sigmask\n"); -// } - manager.timer_thread = -1; - } - __destroySharedMemory(); - - return 0; -} - -#ifdef USE_BATT_LOG -static void wait_for_starting() -{ - static int chargerfd = -1; - while (get_file_status(&chargerfd, CHARGERFD)) - { - LOGI("wait for starting ... \n"); - __sleep(MONITORING_INTERVAL); - } -} -#endif - -static int startProfiling(char* execpath, enum DAState status, long launchflag) -{ - if(__createSharedMemory() < 0) - { - LOGE("Failed to create shared memory\n"); - return -1; - } - - // set launch flag before execute application - manager.sharedmem.pvalue->launch_flag = launchflag; - - // remove previous screen capture files - remove_indir(SCREENSHOT_DIR); - mkdir(SCREENSHOT_DIR, 0777); - - // execute application - if (exec_app(execpath, get_app_type())) - { - manager.iTarget.status = status; - if(timerStart() < 0) - { - return -1; - } - LOGI("Timer Started\n"); - } - else - { - return -1; - } - - return 0; -} - -static void* terminate_thread(void* data) -{ - int i; - FILE* fp; - size_t readbyte; - char cmd[MAX_PATH_LENGTH]; - pid_t* pids = (pid_t*)data; - - sleep(1); - for(i = 0; pids[i] != -2; i++) - { - if(pids[i] != -1) - { - sprintf(cmd, "ps ax | grep %d | grep -v grep", pids[i]); - fp = popen(cmd, "r"); - if(fp) - { - readbyte = fread(cmd, MAX_PATH_LENGTH - 1, 1, fp); - if(readbyte > 0) // process is still alive - { - sprintf(cmd, "kill -9 %d", pids[i]); - system(cmd); - } - pclose(fp); - } - } - } - - free(pids); - - return NULL; -} - -static void terminate_all_target() -{ - int i; - pthread_t term_thread; - pid_t* pids; - - pids = (pid_t*)malloc((manager.iTarget.pidCount + 1) * sizeof(pid_t)); - - for (i = 0; i < manager.iTarget.pidCount; i++) - { - pids[i] = manager.iTarget.execPID[i]; - if(manager.iTarget.execPID[i] != -1) - { - LOGI("TERMINATE process(%d) by terminate_all_target()\n", manager.iTarget.execPID[i]); - aul_terminate_pid(manager.iTarget.execPID[i]); - manager.iTarget.execPID[i] = -1; - } - } - pids[manager.iTarget.pidCount] = -2; - - pthread_create(&term_thread, NULL, terminate_thread, pids); - - manager.iTarget.pidCount = 0; -} - -static void terminate_error(char* errstr, int sendtohost) -{ - LOGE("%s, status(%d)\n", errstr, manager.iHost.status); - manager.iHost.status = DAS_STOP; - - terminate_all_target(); - - timerStop(); - - if(sendtohost) - sendMsgStrToHost(errstr, MSG_ERROR, -1); -} - - -// return 0 if normal case -// return plus value if non critical error occur -// return minus value if critical error occur -static int hostMessageHandler(log_t * log) -{ - int ret = 0; - long flag = 0; - char *barloc, *tmploc; - char execPath[PATH_MAX]; - - if (log == NULL) - return 1; - - switch (log->type) - { - case MSG_START: - LOGI("MSG_START handling : %s\n", log->data); - if (manager.iHost.status >= DAS_START_BEGIN && manager.iHost.status <= DAS_START_END) - { - LOGE("MSG_START status check : %d\n", manager.iHost.status); - return 1; // already started, then ignore this MSG_START message - } - - if(log->length == 0) - return -1; // wrong message format - - // parsing for host start status - tmploc = log->data; - barloc = strchr(tmploc, '|'); - if(barloc != NULL) - { - manager.iHost.status = 0; - while(tmploc < barloc) - { - manager.iHost.status = (manager.iHost.status * 2) + (*tmploc - '0'); - tmploc++; - } - manager.iHost.status += 1; - - if(manager.iHost.status < DAS_START_BEGIN || manager.iHost.status > DAS_START_END) - { - manager.iHost.status = DAS_EMUL_X86_START; - ret = 1; - } - } - else - { - return -1; // wrong message format - } - - // parsing for target launch option flag - tmploc = barloc + 1; - barloc = strchr(tmploc, '|'); - if(barloc != NULL) - { - while(tmploc < barloc) - { - flag = (flag * 2) + (*tmploc - '0'); - tmploc++; - } - } - else - { - return -1; // wrong message format - } - - // parsing for application package name - tmploc = barloc + 1; - strcpy(manager.appPath, tmploc); - -#ifdef USE_BATT_LOG - if(manager.iHost.status == DAS_EMUL_ARM_BATT_START || - manager.iHost.status == DAS_EMUL_X86_BATT_START) - wait_for_starting(); -#endif - - get_executable(execPath, PATH_MAX); // get exact app executable file name -#if RUN_APP_LOADER - kill_app(manager.appPath); -#else - // use execPath instead of manager.appPath - kill_app(execPath); -#endif - sleep(0); - - LOGI("executable app path %s\n", manager.appPath); - - { - char appInstallCommand[PATH_MAX]; - - //save app install path - mkdir(DA_INSTALL_DIR, 0775); - sprintf(appInstallCommand, - "%s -Wwi %s | grep DW_AT_comp_dir > %s", DA_READELF_PATH, - execPath, DA_INSTALL_PATH); - LOGI("appInstallCommand %s\n", appInstallCommand); - system(appInstallCommand); - - sprintf(appInstallCommand, - "%s -h %s | grep Type | cut -d\" \" -f33 > %s", DA_READELF_PATH, - execPath, DA_BUILD_OPTION); - LOGI("appInstallCommand %s\n", appInstallCommand); - system(appInstallCommand); - -#if RUN_APP_LOADER - if(startProfiling(manager.appPath, manager.iHost.status, flag) < 0) -#else - // use execPath instead of manager.appPath - if(startProfiling(execPath, manager.iHost.status, flag) < 0) -#endif - { - terminate_error("Cannot start profiling", 1); - return -1; - } - } - break; - case MSG_STOP: - LOGI("MSG_STOP handling\n"); - if (manager.iHost.status < DAS_START_BEGIN || manager.iHost.status > DAS_START_END) - { - // already stopped, not possible, ignore MSG_STOP message - LOGE("MSG_STOP status check : %d\n", manager.iHost.status); - return 1; - } - - manager.iHost.status = DAS_STOP; - terminate_all_target(); - timerStop(); - break; - case MSG_OPTION: - if(log->length > 0) - { - if(log->data[0] == '0') - { - set_launch_flag(1, 0); - LOGI("Snapshot disabled\n"); - } - else if(log->data[0] == '1') - { - set_launch_flag(1, 1); - LOGI("Snapshot enabled\n"); - } - else - { - LOGI("Wrong option message from host\n"); - } - } - break; - case MSG_ISALIVE: - sendMsgStrToHost(NULL, MSG_ALIVE, 0); - break; - -#ifdef USE_BATT_LOG - case MSG_BATT_START: - { - manager.iHost.status = DAS_BATT_START; - sprintf(manager.appPath, "%s", log->data); - create_open_batt_log(get_app_name(manager.appPath)); - wait_for_starting(); - if(startProfiling(manager.appPath, DAS_BATT_START, flag) < 0) - { - terminate_error("Cannot start profiling", 1); - return -1; - } -// batt_start(manager.appPath); - } - break; - case MSG_BATT_STOP: - manager.iHost.status = DAS_BATT_STOP; - timerStop(); -// batt_stop(); - break; -#endif - - default: - LOGW("Unknown msg\n"); - } - - return ret; -} - -static int parseHostMessage(log_t* log, char* msg) -{ - int i; - int bfind = 0; - - if(log == NULL || msg == NULL) - return 0; - - // Host message looks like this - // MSG_TYPE|MSG_LENGTH|MSG_STRING - // MSG_TYPE is always 3 digits number - if(msg[3] == '|') - { - msg[3] = '\0'; - log->type = atoi(msg); - - if(log->type < MSG_HOST_BEGIN || log->type > MSG_HOST_END) - return 0; - - msg = msg + 4; - for(i = 0; msg[i] != '\0'; i++) - { - if(msg[i] == '|') - { - bfind = 1; - msg[i] = '\0'; - break; - } - } - - if(bfind != 0) - { - int msglen; - log->length = atoi(msg); - msg = msg + i + 1; - msglen = strlen(msg); - - if(log->length == 0) - { - log->data[0] = '\0'; - } - else - { - if(msglen == log->length) - strcpy(log->data, msg); - else if(msglen > log->length) // parsing error but deal as nonerror - strncpy(log->data, msg, log->length); - else - return 0; // parsing error - - log->data[log->length] = '\0'; - } - } - else - { - return 0; // parsing error - } - - return 1; // parsing success - } - else - { - return 0; // parsing error - } -} - -#define EPOLL_SIZE 10 -#define MAX_CONNECT_SIZE 12 -#define MAX_INAROW_TARGET_MSG 10 - -// return 0 for normal case -static int work() -{ - struct sockaddr_un clientAddrUn; //target - struct sockaddr_in clientAddrIn; //host - int i, k, find; - ssize_t recvLen; - char recvBuf[READ_BUF_MAX]; - log_t log; - - struct epoll_event ev, *events; - int efd; // epoll fd - int numevent; // number of occured events - - // initialize epoll event pool - events = (struct epoll_event*) malloc(sizeof(struct epoll_event) * EPOLL_SIZE); - if(events == NULL) - { - LOGE("Out of memory when allocate epoll event pool\n"); - return -1; - } - if((efd = epoll_create(MAX_CONNECT_SIZE)) < 0) - { - LOGE("epoll creation error\n"); - free(events); - return -1; - } - - // add server sockets to epoll event pool - ev.events = EPOLLIN; - ev.data.fd = manager.iHost.serverSockFD; - if(epoll_ctl(efd, EPOLL_CTL_ADD, manager.iHost.serverSockFD, &ev) < 0) - { - LOGE("Host server socket epoll_ctl error\n"); - free(events); - close(efd); - return -1; - } - ev.events = EPOLLIN; - ev.data.fd = manager.iTarget.serverSockFD; - if(epoll_ctl(efd, EPOLL_CTL_ADD, manager.iTarget.serverSockFD, &ev) < 0) - { - LOGE("Target server socket epoll_ctl error\n"); - free(events); - close(efd); - return -1; - } - - // handler loop - while (1) - { - numevent = epoll_wait(efd, events, EPOLL_SIZE, -1); - if(numevent <= 0) - { - LOGE("Failed to epoll_wait : num of event(%d), errno(%d)\n", numevent, errno); - continue; - } - - for(i = 0; i < numevent; i++) - { - find = 0; - for(k = 0; k < manager.iTarget.connectCount; k++) - { - if(events[i].data.fd == manager.iTarget.clientSockFD[k]) - { - // read from target process - recvLen = recv(manager.iTarget.clientSockFD[k], &log, - sizeof(log.type) + sizeof(log.length), 0); - - // send to host - if (recvLen > 0) - { - int count = 0; - do { - if (log.length > 0) - recv(manager.iTarget.clientSockFD[k], log.data, log.length, 0); - log.data[log.length] = '\0'; - if(log.type == 5) // MSG_LOG - { - switch(log.data[0]) - { - case '2': // UI control creation log - case '3': // UI event log - case '6': // UI lifecycle log - case '7': // screnshot log - case '8': // scene transition log - LOGI("%dclass|%s\n", log.data[0] - '0', log.data); - break; - default: - break; - } - } - else if(log.type == 6) // MSG_IMAGE - { - LOGI("MSG_IMAGE received\n"); - } - else // not MSG_LOG and not MSG_IMAGE - { - LOGI("Extra MSG TYPE (%d|%d|%s)\n", log.type, log.length, log.data); - } - sendMsgStrToHost(log.data, log.type, k); - if(count++ > MAX_INAROW_TARGET_MSG) - break; - } while ((recvLen = recv(manager.iTarget.clientSockFD[k], - &log, sizeof(log.type) + sizeof(log.length), MSG_DONTWAIT)) > 0); - } - - // close request from target client socket - if(recvLen == 0) - { - LOGI("target close = %d(total %d)\n", manager.iTarget.clientSockFD[k], manager.iTarget.connectCount - 1); - if(epoll_ctl(efd, EPOLL_CTL_DEL, manager.iTarget.clientSockFD[k], NULL) < 0) - { - LOGE("Failed to epoll_ctl delete fd from event poll\n"); - } - close(manager.iTarget.clientSockFD[k]); - LOGI("Terminate %dth pid(%d)\n", k, manager.iTarget.execPID[k]); - // consume that target process is already in terminating phase -// _terminate_pid(manager.iTarget.execPID[k]); - manager.iTarget.connectCount--; - if(manager.iTarget.execPID[k] != -1) - manager.iTarget.pidCount--; -// assert(manager.iTarget.connectCount == manager.iTarget.pidCount); - if (manager.iTarget.connectCount == 0) // all target client are closed - { - manager.iTarget.status = DAS_TERMINATE; - - LOGI("Exit daemon process\n"); - manager.iTarget.clientSockFD[k] = -1; - manager.iTarget.execPID[k] = -1; - timerStop(); - free(events); - close(efd); - return 0; - } - else - { - manager.iTarget.clientSockFD[k] = manager.iTarget.clientSockFD[manager.iTarget.connectCount]; - manager.iTarget.clientSockFD[manager.iTarget.connectCount] = -1; - manager.iTarget.execPID[k] = manager.iTarget.execPID[manager.iTarget.pidCount]; - manager.iTarget.execPID[manager.iTarget.pidCount] = -1; - } - } - - find = 1; - break; - } - } - if(find == 0) // this event is not from target client socket - { - // connect request from target - if(events[i].data.fd == manager.iTarget.serverSockFD) - { - socklen_t addrlen; - addrlen = sizeof(clientAddrUn); - manager.iTarget.clientSockFD[manager.iTarget.connectCount] = - accept(manager.iTarget.serverSockFD, (struct sockaddr *) &clientAddrUn, &addrlen); - - if(manager.iTarget.clientSockFD[manager.iTarget.connectCount] >= 0) // accept succeed - { - ev.events = EPOLLIN; - ev.data.fd = manager.iTarget.clientSockFD[manager.iTarget.connectCount]; - if(epoll_ctl(efd, EPOLL_CTL_ADD, manager.iTarget.clientSockFD[manager.iTarget.connectCount], &ev) < 0) - { - // consider as accept fail - LOGE("Target client epoll_ctl error\n"); - manager.iTarget.clientSockFD[manager.iTarget.connectCount] = -1; - } - else - { - LOGI("target connect = %d(total%d)\n", - manager.iTarget.clientSockFD[manager.iTarget.connectCount], manager.iTarget.connectCount + 1); - manager.iTarget.connectCount++; - } - } - else // accept error - { - LOGE("Failed to accept from target server socket\n"); - } - } - // connect request from host - else if(events[i].data.fd == manager.iHost.serverSockFD) - { - socklen_t addrlen; - addrlen = sizeof(clientAddrIn); - if(manager.iHost.clientSockFD != -1) - { - if(epoll_ctl(efd, EPOLL_CTL_DEL, manager.iHost.clientSockFD, NULL) < 0) - { - LOGE("Failed to delete host client socket from epoll ctrl queue\n"); - } - close(manager.iHost.clientSockFD); - LOGI("Host client socket is closed, fd(%d)\n", manager.iHost.clientSockFD); - } - manager.iHost.clientSockFD = accept(manager.iHost.serverSockFD, (struct sockaddr *) &clientAddrIn, &addrlen); - - if(manager.iHost.clientSockFD >= 0) // accept succeed - { - ev.events = EPOLLIN; - ev.data.fd = manager.iHost.clientSockFD; - if(epoll_ctl(efd, EPOLL_CTL_ADD, manager.iHost.clientSockFD, &ev) < 0) - { - // consider as accept fail - close(manager.iHost.clientSockFD); - manager.iHost.clientSockFD = -1; - terminate_error("Host client epoll_ctl error", 1); - } - else - { - LOGI("host connect = %d\n", manager.iHost.clientSockFD); - } - } - else // accept error - { - LOGE("Failed to accept from host server socket\n"); - } - } - // message from host - else if(events[i].data.fd == manager.iHost.clientSockFD) - { - // host log format xxx|length|str - LOGI("Host client socket selected(Message from host)\n"); - recvLen = recv(manager.iHost.clientSockFD, recvBuf, READ_BUF_MAX, 0); - - if (recvLen > 0) - { - recvBuf[recvLen] = '\0'; - LOGI("host sent this msg len(%d) str(%s)\n", recvLen, recvBuf); - if(parseHostMessage(&log, recvBuf) == 0) - { - // error to parse host message - sendMsgStrToHost("host log message is unrecognizable", MSG_ERROR, -1); - continue; - } - - //host msg command handling - if(hostMessageHandler(&log) < 0) - { - terminate_error("Host message handling error", 1); - free(events); - close(efd); - return 0; - } - } - else // close request from HOST - { - // work loop quit - if(manager.iHost.status >= DAS_START_BEGIN && manager.iHost.status <= DAS_START_END) - { - // host client socket end unexpectly - terminate_error("Host client socket closed unexpectly", 0); - } - LOGI("host close = %d\n", manager.iHost.clientSockFD); - free(events); - close(efd); - return 0; - } - } - else - { - // never happened - LOGW("Unknown socket fd\n"); - } - } - } - } - - free(events); - close(efd); - return 0; -} - -// return 0 for normal case -static int initialize_manager() -{ - int i; - // make server socket - if(__makeTargetServerSockFD() != 0) - return -1; - if(__makeHostServerSockFD() != 0) - return -1; - - // initialize target client sockets - for (i = 0; i < TARGET_CLIENT_COUNT_MAX; i++) - { - manager.iTarget.clientSockFD[i] = -1; - manager.iTarget.execPID[i] = -1; - } - - // initialize sendMutex - pthread_mutex_init(&(manager.sendMutex), NULL); - - if(initialize_system_info() < 0) - return -1; - - return 0; -} - -static int finalize_manager() -{ - int i; - - finalize_system_info(); - - terminate_all_target(); - - LOGI("Finalize daemon\n"); - - // finalize target client sockets - for (i = 0; i < TARGET_CLIENT_COUNT_MAX; i++) - { - if(manager.iTarget.clientSockFD[i] != -1) - close(manager.iTarget.clientSockFD[i]); - } - - // close host client socket - if(manager.iHost.clientSockFD != -1) - close(manager.iHost.clientSockFD); - - // close server socket - if(manager.iHost.serverSockFD != -1) - close(manager.iHost.serverSockFD); - if(manager.iTarget.serverSockFD != -1) - close(manager.iTarget.serverSockFD); - - return 0; -} - -static void __attribute((destructor)) exit_func() -{ - __destroySharedMemory(); -} - -int main() -{ -#if DEBUG - write_log(); -#endif - - //for terminal exit - signal(SIGHUP, SIG_IGN); - chdir("/"); - - //new session reader - setsid(); - - // initialize manager - if(initialize_manager() == 0) - { - //daemon work - work(); - - finalize_manager(); - return 0; - } - else - return 1; -} diff --git a/daemon/da_debug.h b/daemon/da_debug.c similarity index 60% rename from daemon/da_debug.h rename to daemon/da_debug.c index 9d53da9..f4b02ce 100644 --- a/daemon/da_debug.h +++ b/daemon/da_debug.c @@ -3,12 +3,12 @@ * * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. * -* Contact: +* Contact: * * Jaewon Lim * Woojin Jung * Juyoung Kim -* +* * 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 @@ -24,31 +24,38 @@ * Contributors: * - S-Core Co., Ltd * -*/ +*/ -#ifndef _DA_DEBUG_H_ -#define _DA_DEBUG_H_ +#include +#include +#include +#include +#include -#ifdef __cplusplus -extern "C" { -#endif - -#if DEBUG - #define LOGI(...) do{ fprintf(stderr, "[INF]" __VA_ARGS__ ); fflush(stderr); } while(0) - #define LOGE(...) do{ fprintf(stderr, "[ERR]" __VA_ARGS__ ); fflush(stderr); } while(0) - #define LOGW(...) do{ fprintf(stderr, "[WRN]" __VA_ARGS__ ); fflush(stderr); } while(0) -#else - #define LOGI(...) do{} while(0) - #define LOGE(...) do{} while(0) - #define LOGW(...) do{} while(0) -#endif +#include "daemon.h" +#define DEBUG_LOGFILE "/tmp/daemonlog.da" +#if DEBUG +void initialize_log() +{ + int fd; + fd = open("/dev/null", O_RDONLY); + dup2(fd, 0); + fd = open(DEBUG_LOGFILE, O_WRONLY | O_CREAT | O_TRUNC, 0777); + if(fd < 0) { + fd = open("/dev/null", O_WRONLY); + } + dup2(fd, 1); + dup2(fd, 2); -#ifdef __cplusplus + fprintf(stderr, "--- daemon starting (pid %d) ---\n", getpid()); +} +#else +void initialize_log() +{ } #endif -#endif // _DA_DEBUG_H_ diff --git a/daemon/daemon.c b/daemon/daemon.c new file mode 100644 index 0000000..d77ce44 --- /dev/null +++ b/daemon/daemon.c @@ -0,0 +1,891 @@ +/* +* DA manager +* +* Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. +* +* Contact: +* +* Jaewon Lim +* Woojin Jung +* Juyoung Kim +* + * 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. +* +* Contributors: +* - S-Core Co., Ltd +* +*/ + +#include +#include // for realpath +#include // for strtok, strcpy, strncpy +#include // for realpath + +#include // for errno +#include // for accept, mkdir, opendir, readdir +#include // for accept +#include // for mkdir +#include // for eventfd +#include // for epoll apis +#include // for access, sleep +#include // for fsetxattr + +#include "daemon.h" +#include "sys_stat.h" +#include "utils.h" + +#define DA_WORK_DIR "/home/developer/sdk_tools/da/" +#define DA_READELF_PATH "/home/developer/sdk_tools/da/readelf" +#define SCREENSHOT_DIR "/tmp/da" + +#define EPOLL_SIZE 10 +#define MAX_CONNECT_SIZE 12 + +static void terminate_error(char* errstr, int sendtohost); + +long long get_total_alloc_size() +{ + int i; + long long allocsize = 0; + + for(i = 0; i < MAX_TARGET_COUNT; i++) + { + if(manager.target[i].socket != -1 && manager.target[i].allocmem > 0) + allocsize += manager.target[i].allocmem; + } + return allocsize; +} + +static int getEmptyTargetSlot() +{ + int i; + for(i = 0; i < MAX_TARGET_COUNT; i++) + { + if(manager.target[i].socket == -1) + break; + } + + return i; +} + +static void setEmptyTargetSlot(int index) +{ + if(index >= 0 && index < MAX_TARGET_COUNT) + { + manager.target[index].pid = -1; + manager.target[index].recv_thread = -1; + manager.target[index].allocmem = 0; + manager.target[index].starttime = 0; + if(manager.target[index].event_fd != -1) + close(manager.target[index].event_fd); + manager.target[index].event_fd = -1; + if(manager.target[index].socket != -1) + close(manager.target[index].socket); + manager.target[index].socket = -1; + } +} + +// ====================================================================================== +// send functions to host +// ====================================================================================== + +int sendDataToHost(msg_t* log) +{ + if (manager.host.data_socket != -1) + { + char logstr[DA_MSG_MAX]; + int loglen; + + if(log->length != 0) + loglen = sprintf(logstr, "%d|%d|%s\n", log->type, log->length + 1, log->data); + else + loglen = sprintf(logstr, "%d|%d|\n", log->type, log->length + 1); + +// loglen = sprintf(logstr, "%d|%s\n", log->type, log->data); + + pthread_mutex_lock(&(manager.host.data_socket_mutex)); + send(manager.host.data_socket, logstr, loglen, MSG_NOSIGNAL); + pthread_mutex_unlock(&(manager.host.data_socket_mutex)); + return 0; + } + else + return 1; +} + +// msgstr can be NULL +static int sendACKStrToHost(enum HostMessageType resp, char* msgstr) +{ + if (manager.host.control_socket != -1) + { + char logstr[DA_MSG_MAX]; + int loglen; + + if(msgstr != NULL) + loglen = sprintf(logstr, "%d|%d|%s", (int)resp, strlen(msgstr), msgstr); + else + loglen = sprintf(logstr, "%d|0|", (int)resp); + + send(manager.host.control_socket, logstr, loglen, MSG_NOSIGNAL); + return 0; + } + else + return 1; +} + +static int sendACKCodeToHost(enum HostMessageType resp, int msgcode) +{ + if (manager.host.control_socket != -1) + { + char codestr[16]; + char logstr[DA_MSG_MAX]; + int loglen, codelen; + + codelen = sprintf(codestr, "%d", msgcode); + loglen = sprintf(logstr, "%d|%d|%s", (int)resp, codelen, codestr); + + send(manager.host.control_socket, logstr, loglen, MSG_NOSIGNAL); + return 0; + } + else + return 1; +} + +// ======================================================================================== +// start and terminate control functions +// ======================================================================================== + +static int startProfiling(long launchflag) +{ + char execPath[PATH_MAX]; + + // remove previous screen capture files + remove_indir(SCREENSHOT_DIR); + mkdir(SCREENSHOT_DIR, 0777); + + manager.config_flag = launchflag; + +#ifdef RUN_APP_LOADER + strcpy(execPath, manager.appPath); +#else + get_executable(manager.appPath, execPath, PATH_MAX); +#endif + if(exec_app(execPath, get_app_type(manager.appPath))) + { + if(samplingStart() < 0) + { + return -1; + } + LOGI("Timer Started\n"); + } + else + return -1; + + return 0; +} + +// terminate single target +// just send stop message to target process +static void terminate_target(int index) +{ + ssize_t sendlen; + msg_t sendlog; + sendlog.type = MSG_STOP; + sendlog.length = 0; + + if(manager.target[index].socket != -1) + { + // result of sending to disconnected socket is not expected + sendlen = send(manager.target[index].socket, &sendlog, sizeof(sendlog.type) + sizeof(sendlog.length), MSG_NOSIGNAL); + if(sendlen != -1) + { + LOGI("TERMINATE send exit msg (socket %d) by terminate_target()\n", manager.target[index].socket); + } + } +} + +// just send stop message to all target process +static void terminate_all_target() +{ + int i; + ssize_t sendlen; + msg_t sendlog; + + sendlog.type = MSG_STOP; + sendlog.length = 0; + + for (i = 0; i < MAX_TARGET_COUNT; i++) + { + if(manager.target[i].socket != -1) + { + sendlen = send(manager.target[i].socket, &sendlog, sizeof(sendlog.type) + sizeof(sendlog.length), MSG_NOSIGNAL); + if(sendlen != -1) + { + LOGI("TERMINATE send exit msg (socket %d) by terminate_all_target()\n", manager.target[i].socket); + } + } + } +} + +// terminate all target and wait for threads +static void terminate_all() +{ + int i; + terminate_all_target(); + samplingStop(); + + // wait for all other thread exit + for(i = 0; i < MAX_TARGET_COUNT; i++) + { + if(manager.target[i].recv_thread != -1) + { + pthread_join(manager.target[i].recv_thread, NULL); + } + } +} + +// terminate all profiling by critical error +static void terminate_error(char* errstr, int sendtohost) +{ + msg_t log; + + LOGE("TERMINATE ERROR: %s\n", errstr); + if(sendtohost) + { + log.type = MSG_ERROR; + log.length = sprintf(log.data, "%s", errstr); + sendDataToHost(&log); + } + + terminate_all(); +} + +// =========================================================================================== +// message parsing and handling functions +// =========================================================================================== + +// return 0 for normal case +// return negative value for error case +static int parseHostMessage(msg_t* log, char* msg) +{ + int i; + int bfind = 0; + int ret = 0; // parsing success + + if(log == NULL || msg == NULL) + return -1; + + // Host message looks like this + // MSG_TYPE|MSG_LENGTH|MSG_STRING + // MSG_TYPE is always 3 digits number + if(msg[3] == '|') + { + msg[3] = '\0'; + log->type = atoi(msg); + + msg = msg + 4; + for(i = 0; msg[i] != '\0'; i++) + { + if(msg[i] == '|') + { + bfind = 1; + msg[i] = '\0'; + break; + } + } + log->length = atoi(msg); + + if(log->length == 0) + { + log->data[0] = '\0'; + } + else + { + if(bfind != 0) + { + int msglen; + msg = msg + i + 1; + msglen = strlen(msg); + + if(msglen == log->length) + { + strcpy(log->data, msg); + log->data[log->length] = '\0'; + } +// else if(msglen > log->length) +// { +// strncpy(log->data, msg, log->length); +// log->data[log->length] = '\0'; +// } + else + { + ret = -1; // parsing error + } + } + else + { + ret = -1; // parsing error + } + } + } + else + { + ret = -1; // parsing error + } + + return ret; +} + +// return 0 if normal case +// return plus value if non critical error occur +// return minus value if critical error occur +static int hostMessageHandler(msg_t* log) +{ + int ret = 0; + long flag = 0; + char *barloc, *tmploc; + char execPath[PATH_MAX]; + + if (log == NULL) + return 1; + + switch (log->type) + { + case MSG_VERSION: + if(strcmp(PROTOCOL_VERSION, log->data) != 0) + { + sendACKCodeToHost(MSG_NOTOK, ERR_WRONG_PROTOCOL_VERSION); + } + else + { + sendACKStrToHost(MSG_OK, NULL); + } + break; + case MSG_START: + LOGI("MSG_START handling : %s\n", log->data); + if(log->length == 0) + { + sendACKCodeToHost(MSG_NOTOK, ERR_WRONG_MESSAGE_DATA); + return -1; // wrong message format + } + + // parsing for host start status + tmploc = log->data; + barloc = strchr(tmploc, '|'); + if(barloc == NULL) + { + sendACKCodeToHost(MSG_NOTOK, ERR_WRONG_MESSAGE_FORMAT); + return -1; // wrong message format + } + + // parsing for target launch option flag + tmploc = barloc + 1; + barloc = strchr(tmploc, '|'); + if(barloc != NULL) + { + while(tmploc < barloc) + { + flag = (flag * 10) + (*tmploc - '0'); + tmploc++; + } + } + else + { + sendACKCodeToHost(MSG_NOTOK, ERR_WRONG_MESSAGE_FORMAT); + return -1; // wrong message format + } + LOGI("launch flag : %lx\n", flag); + + // parsing for application package name + tmploc = barloc + 1; + strcpy(manager.appPath, tmploc); + + get_executable(manager.appPath, execPath, PATH_MAX); // get exact app executable file name + LOGI("executable app path %s\n", manager.appPath); + +#ifdef RUN_APP_LOADER + kill_app(manager.appPath); +#else + kill_app(execPath); +#endif + + { + char command[PATH_MAX]; + + //save app install path + mkdir(DA_WORK_DIR, 0775); + sprintf(command, + "%s -Wwi %s | grep DW_AT_comp_dir > %s", DA_READELF_PATH, + execPath, DA_INSTALL_PATH); + LOGI("appInstallCommand %s\n", command); + system(command); + + sprintf(command, + "%s -h %s | grep Type | cut -d\" \" -f33 > %s", DA_READELF_PATH, + execPath, DA_BUILD_OPTION); + LOGI("appInstallCommand %s\n", command); + system(command); + + if(startProfiling(flag) < 0) + { + sendACKCodeToHost(MSG_NOTOK, ERR_CANNOT_START_PROFILING); + return -1; + } + } + sendACKStrToHost(MSG_OK, NULL); + break; + case MSG_STOP: + LOGI("MSG_STOP handling\n"); + sendACKStrToHost(MSG_OK, NULL); + terminate_all(); + break; + case MSG_OPTION: + if(log->length > 0) + { + int i; + msg_t sendlog; + manager.config_flag = atoi(log->data); + sendACKStrToHost(MSG_OK, NULL); + + LOGI("MSG_OPTION : str(%s), flag(%x)\n", log->data, manager.config_flag); + + sendlog.type = MSG_OPTION; + sendlog.length = sprintf(sendlog.data, "%u", manager.config_flag); + + for(i = 0; i < MAX_TARGET_COUNT; i++) + { + if(manager.target[i].socket != -1) + { + send(manager.target[i].socket, &sendlog, sizeof(sendlog.type) + sizeof(sendlog.length) + sendlog.length, MSG_NOSIGNAL); + } + } + } + else + { + sendACKCodeToHost(MSG_NOTOK, ERR_WRONG_MESSAGE_DATA); + ret = 1; + } + break; + case MSG_ISALIVE: + sendACKStrToHost(MSG_OK, NULL); + break; + default: + LOGW("Unknown msg\n"); + sendACKCodeToHost(MSG_NOTOK, ERR_WRONG_MESSAGE_TYPE); + ret = 1; + break; + } + + return ret; +} + +// ======================================================================================== +// socket and event_fd handling functions +// ======================================================================================== + +// return 0 if normal case +// return plus value if non critical error occur +// return minus value if critical error occur +// return -11 if all target process closed +static int targetEventHandler(int epollfd, int index, uint64_t msg) +{ + msg_t log; + + if(msg & EVENT_PID) + { + if(index == 0) // assume index 0 is main application process + { + int base_address; + char tempBuff[DA_MSG_MAX]; + char tempBuff2[DA_MSG_MAX]; + char tempPath[PATH_MAX]; + + get_executable(manager.appPath, tempPath, PATH_MAX); + if(realpath(tempPath, tempBuff) == NULL) + { + LOGW("Failed to get realpath of app\n"); + strcpy(tempBuff, tempPath); + } + + sprintf(tempPath, "/proc/%d/maps", manager.target[index].pid); + sprintf(tempBuff2, "cat %s | grep %s | cut -d\"-\" -f1 > %s", + tempPath, tempBuff, DA_BASE_ADDRESS); + LOGI("base address command is %s\n", tempBuff2); + + do { + if(access(tempPath, F_OK) != 0) + return -1; + if(is_same_app_process(manager.appPath, manager.target[index].pid) == 0) + return -1; + + system(tempBuff2); + if(get_app_base_address(&base_address) == 1) + break; + sleep(0); + } while(1); + + tempPath[0] = '\0'; + get_app_install_path(tempPath, PATH_MAX); + get_device_info(tempBuff, DA_MSG_MAX); + log.type = MSG_DEVICE; + if (strlen(tempPath) > 0) + { + get_executable(manager.appPath, tempBuff2, DA_MSG_MAX); + log.length = sprintf(log.data, "%s`,%d`,%Lu`,%d`,%u`,%d`,%s/%s", tempBuff, + manager.target[index].pid, manager.target[index].starttime, + is_app_built_pie(), base_address, get_app_type(manager.appPath), + tempPath, get_app_name(tempBuff2)); + } + else + { + log.length = sprintf(log.data, "%s`,%d`,%Lu`,%d`,%u`,%d`,", tempBuff, + manager.target[index].pid, manager.target[index].starttime, + is_app_built_pie(), base_address, get_app_type(manager.appPath)); + } + + LOGI("%s\n", log.data); + } + else + { + log.type = MSG_PID; + log.length = sprintf(log.data, "%d`,%Lu", manager.target[index].pid, manager.target[index].starttime); + } + + sendDataToHost(&log); + } + + if(msg & EVENT_STOP || msg & EVENT_ERROR) + { + LOGI("target close, socket(%d), pid(%d) : (remaining %d target)\n", + manager.target[index].socket, manager.target[index].pid, manager.target_count - 1); + + terminate_target(index); + epoll_ctl(epollfd, EPOLL_CTL_DEL, manager.target[index].event_fd, NULL); + setEmptyTargetSlot(index); + if (0 == __sync_sub_and_fetch(&manager.target_count, 1)) // all target client are closed + { + log.type = MSG_TERMINATE; + log.length = 0; + log.data[0] = '\0'; + sendDataToHost(&log); + return -11; + } + } + + return 0; +} + +// return 0 if normal case +// return plus value if non critical error occur +// return minus value if critical error occur +static int targetServerHandler(int efd) +{ + msg_t log; + struct epoll_event ev; + + int index = getEmptyTargetSlot(); + if(index == MAX_TARGET_COUNT) + { + LOGW("Max target number(8) reached, no more target can connected\n"); + return 1; + } + + manager.target[index].socket = accept(manager.target_server_socket, NULL, NULL); + + if(manager.target[index].socket >= 0) // accept succeed + { + // set smack attribute for certification + fsetxattr(manager.target[index].socket, "security.SMACK64IPIN", "*", 1, 0); + fsetxattr(manager.target[index].socket, "security.SMACK64IPOUT", "*", 1, 0); + + // send config message to target process + log.type = MSG_OPTION; + log.length = sprintf(log.data, "%u", manager.config_flag); + send(manager.target[index].socket, &log, sizeof(log.type) + sizeof(log.length) + log.length, MSG_NOSIGNAL); + + // make event fd + manager.target[index].event_fd = eventfd(0, EFD_NONBLOCK); + if(manager.target[index].event_fd == -1) + { + // fail to make event fd + LOGE("fail to make event fd for socket (%d)\n", manager.target[index].socket); + goto TARGET_CONNECT_FAIL; + } + + // add event fd to epoll list + ev.events = EPOLLIN; + ev.data.fd = manager.target[index].event_fd; + if(epoll_ctl(efd, EPOLL_CTL_ADD, manager.target[index].event_fd, &ev) < 0) + { + // fail to add event fd + LOGE("fail to add event fd to epoll list for socket (%d)\n", manager.target[index].socket); + goto TARGET_CONNECT_FAIL; + } + + // make recv thread for target + if(makeRecvThread(index) != 0) + { + // fail to make recv thread + LOGE("fail to make recv thread for socket (%d)\n", manager.target[index].socket); + epoll_ctl(efd, EPOLL_CTL_DEL, manager.target[index].event_fd, NULL); + goto TARGET_CONNECT_FAIL; + } + + LOGI("target connected = %d(running %d target)\n", + manager.target[index].socket, manager.target_count + 1); + + manager.target_count++; + return 0; + } + else // accept error + { + LOGE("Failed to accept at target server socket\n"); + } + +TARGET_CONNECT_FAIL: + if(manager.target_count == 0) // if this connection is main connection + { + return -1; + } + else // if this connection is not main connection then ignore process by error + { + setEmptyTargetSlot(index); + return 1; + } +} + +// return 0 if normal case +// return plus value if non critical error occur +// return minus value if critical error occur +static int hostServerHandler(int efd) +{ + static int hostserverorder = 0; + int csocket; + struct epoll_event ev; + + if(hostserverorder > 1) // control and data socket connected already + return 1; // ignore + + csocket = accept(manager.host_server_socket, NULL, NULL); + + if(csocket >= 0) // accept succeed + { + ev.events = EPOLLIN; + ev.data.fd = csocket; + if(epoll_ctl(efd, EPOLL_CTL_ADD, csocket, &ev) < 0) + { + // consider as accept fail + LOGE("Failed to add socket fd to epoll list\n"); + close(csocket); + return -1; + } + + if(hostserverorder == 0) + { + manager.host.control_socket = csocket; + LOGI("host control socket connected = %d\n", csocket); + } + else + { + manager.host.data_socket = csocket; + LOGI("host data socket connected = %d\n", csocket); + } + + hostserverorder++; + return 0; + } + else // accept error + { + LOGE("Failed to accept from host server socket\n"); + return -1; + } +} + +// return 0 if normal case +// return plus value if non critical error occur +// return minus value if critical error occur +// return -11 if socket closed +static int controlSocketHandler() +{ + ssize_t recvLen; + char recvBuf[DA_MSG_MAX]; + msg_t log; + + // host log format xxx|length|str + recvLen = recv(manager.host.control_socket, recvBuf, RECV_BUF_MAX, 0); + + if (recvLen > 0) + { + recvBuf[recvLen] = '\0'; + LOGI("host sent control msg str(%s)\n", recvBuf); + + if(parseHostMessage(&log, recvBuf) < 0) + { + // error to parse host message + sendACKCodeToHost(MSG_NOTOK, ERR_WRONG_MESSAGE_FORMAT); + return 1; + } + + // host msg command handling + return hostMessageHandler(&log); + } + else // close request from HOST + { + return -11; + } +} + +// return 0 for normal case +int daemonLoop() +{ + int ret = 0; // return value + int i, k; + ssize_t recvLen; + + struct epoll_event ev, *events; + int efd; // epoll fd + int numevent; // number of occured events + + // initialize epoll event pool + events = (struct epoll_event*) malloc(sizeof(struct epoll_event) * EPOLL_SIZE); + if(events == NULL) + { + LOGE("Out of memory when allocate epoll event pool\n"); + ret = -1; + goto END_RETURN; + } + if((efd = epoll_create(MAX_CONNECT_SIZE)) < 0) + { + LOGE("epoll creation error\n"); + ret = -1; + goto END_EVENT; + } + + // add server sockets to epoll event pool + ev.events = EPOLLIN; + ev.data.fd = manager.host_server_socket; + if(epoll_ctl(efd, EPOLL_CTL_ADD, manager.host_server_socket, &ev) < 0) + { + LOGE("Host server socket epoll_ctl error\n"); + ret = -1; + goto END_EFD; + } + ev.events = EPOLLIN; + ev.data.fd = manager.target_server_socket; + if(epoll_ctl(efd, EPOLL_CTL_ADD, manager.target_server_socket, &ev) < 0) + { + LOGE("Target server socket epoll_ctl error\n"); + ret = -1; + goto END_EFD; + } + + // handler loop + while (1) + { + numevent = epoll_wait(efd, events, EPOLL_SIZE, -1); + if(numevent <= 0) + { + LOGE("Failed to epoll_wait : num of event(%d), errno(%d)\n", numevent, errno); + continue; + } + + for(i = 0; i < numevent; i++) + { + // check for request from event fd + for(k = 0; k < MAX_TARGET_COUNT; k++) + { + if(manager.target[k].socket != -1 && + events[i].data.fd == manager.target[k].event_fd) + { + uint64_t u; + recvLen = read(manager.target[k].event_fd, &u, sizeof(uint64_t)); + if(recvLen != sizeof(uint64_t)) + { + // maybe closed, but ignoring is more safe then removing fd from epoll list + } + else + { + if(-11 == targetEventHandler(efd, k, u)) + { + LOGI("all target process is closed\n"); + terminate_all(); + ret = 0; + goto END_EFD; + } + } + break; + } + } + + if(k != MAX_TARGET_COUNT) + continue; + + // connect request from target + if(events[i].data.fd == manager.target_server_socket) + { + if(targetServerHandler(efd) < 0) // critical error + { + terminate_error("Internal DA framework error, Please re-run the profiling.", 1); + ret = -1; + goto END_EFD; + } + } + // connect request from host + else if(events[i].data.fd == manager.host_server_socket) + { + int result = hostServerHandler(efd); + if(result < 0) + { + terminate_error("Internal DA framework error, Please re-run the profiling.", 1); + ret = -1; + goto END_EFD; + } + } + // control message from host + else if(events[i].data.fd == manager.host.control_socket) + { + int result = controlSocketHandler(); + if(result == -11) // socket close + { + // close target and host socket and quit + LOGI("host close = %d\n", manager.host.control_socket); + terminate_all(); + ret = 0; + goto END_EFD; + } + else if(result < 0) + { + terminate_error("Internal DA framework error, Please re-run the profiling.", 1); + ret = -1; + goto END_EFD; + } + } + else if(events[i].data.fd == manager.host.data_socket) + { + LOGW("host message from data socket\n"); + } + // unknown socket + else + { + // never happened + LOGW("Unknown socket fd (%d)\n", events[i].data.fd); + } + } + } + +END_EFD: + close(efd); +END_EVENT: + free(events); +END_RETURN: + return ret; +} diff --git a/daemon/daemon.h b/daemon/daemon.h new file mode 100644 index 0000000..4c70209 --- /dev/null +++ b/daemon/daemon.h @@ -0,0 +1,195 @@ +/* +* DA manager +* +* Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. +* +* Contact: +* +* Jaewon Lim +* Woojin Jung +* Juyoung Kim +* + * 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. +* +* Contributors: +* - S-Core Co., Ltd +* +*/ + +#include // for uint64_t, int64_t +#include // for pthread_mutex_t + +#ifndef _DAEMON_H_ +#define _DAEMON_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define PROTOCOL_VERSION "2.1" + +#define RUN_APP_LOADER + +#define MAX_TARGET_COUNT 8 +#define DA_MSG_MAX 4096 +#define RECV_BUF_MAX 4104 // = sizeof(msg_t) + +enum ErrorCode +{ + ERR_LOCKFILE_CREATE_FAILED = -101, + ERR_ALREADY_RUNNING = -102, + ERR_INITIALIZE_SYSTEM_INFO_FAILED = -103, + ERR_HOST_SERVER_SOCKET_CREATE_FAILED = -104, + ERR_TARGET_SERVER_SOCKET_CREATE_FAILED = -105, + ERR_WRONG_MESSAGE_FORMAT = -201, + ERR_WRONG_MESSAGE_TYPE = -202, + ERR_WRONG_MESSAGE_DATA = -203, + ERR_CANNOT_START_PROFILING = -204, + ERR_WRONG_PROTOCOL_VERSION = -205 +}; + +enum TargetMessageType +{ + MSG_DEVICE = 1, + MSG_TIME = 2, + MSG_SAMPLE = 3, + MSG_RESOURCE = 4, + MSG_LOG = 5, + MSG_IMAGE = 6, + MSG_TERMINATE = 7, + MSG_PID = 8, + MSG_MSG = 9, + MSG_ALLOC = 10, + MSG_ERROR = 11 +}; + +enum HostMessageType +{ + MSG_HOST_BEGIN = 100, + MSG_START = 100, + MSG_STOP = 101, + MSG_PAUSE = 102, + MSG_OPTION = 103, + MSG_ISALIVE = 104, + MSG_ALIVE = 105, + MSG_BATT_START = 106, + MSG_BATT_STOP = 107, + MSG_OK = 901, + MSG_NOTOK = 902, + MSG_VERSION = 999, + MSG_HOST_END = 999 +}; + +enum DaOptions +{ + OPT_CPUMEM = 0x00000001, + OPT_FUNC = 0x00000002, + OPT_ALLOC = 0x00000004, + OPT_FILE = 0x00000008, + OPT_THREAD = 0x00000010, + OPT_UI = 0x00000020, + OPT_SNAPSHOT = 0x00000040, + OPT_EVENT = 0x00000080, + OPT_RECORD = 0x00000100 +}; + +enum DAState +{ + DAS_NONE = 0, + DAS_START_BEGIN = 1, + DAS_TARGET_ARM_START = 1, + DAS_TARGET_X86_START = 2, + DAS_EMUL_ARM_START = 3, + DAS_EMUL_X86_START = 4, + DAS_TARGET_ARM_BATT_START = 5, + DAS_TARGET_X86_BATT_START = 6, + DAS_EMUL_ARM_BATT_START = 7, + DAS_EMUL_X86_BATT_START = 8, + DAS_START_END = 8, + DAS_STOP = 9, + DAS_TERMINATE = 10 +}; + + +#ifndef likely +#define likely(x) __builtin_expect((x), 1) +#define unlikely(x) __builtin_expect((x), 0) +#endif + +#if DEBUG + #define LOGI(...) do{ fprintf(stderr, "[INF]" __VA_ARGS__ ); fflush(stderr); } while(0) + #define LOGE(...) do{ fprintf(stderr, "[ERR]" __VA_ARGS__ ); fflush(stderr); } while(0) + #define LOGW(...) do{ fprintf(stderr, "[WRN]" __VA_ARGS__ ); fflush(stderr); } while(0) +#else + #define LOGI(...) do{} while(0) + #define LOGE(...) do{} while(0) + #define LOGW(...) do{} while(0) +#endif + +#define EVENT_STOP 0x00000001 +#define EVENT_PID 0x00000002 +#define EVENT_ERROR 0x00000004 + +typedef struct +{ + unsigned int type; + unsigned int length; + char data[DA_MSG_MAX]; +} msg_t; + +typedef struct +{ + int control_socket; + int data_socket; + pthread_mutex_t data_socket_mutex; +} __da_host_info; + +typedef struct +{ + uint64_t starttime; // written only by recv thread + int64_t allocmem; // written only by recv thread + int pid; // written only by recv thread + int socket; // written only by main thread + pthread_t recv_thread; // written only by main thread + int event_fd; // for thread communication (from recv thread to main thread) +} __da_target_info; + +typedef struct +{ + FILE* portfile; + int host_server_socket; + int target_server_socket; + int target_count; + unsigned int config_flag; + pthread_t sampling_thread; + __da_host_info host; + __da_target_info target[MAX_TARGET_COUNT]; + char appPath[128]; // application executable path +} __da_manager; + +extern __da_manager manager; + +void initialize_log(); +int daemonLoop(); +int sendDataToHost(msg_t* log); +long long get_total_alloc_size(); + +int makeRecvThread(int index); +int samplingStart(); +int samplingStop(); + +#ifdef __cplusplus +} +#endif + +#endif // _DAEMON_H_ diff --git a/daemon/main.c b/daemon/main.c new file mode 100644 index 0000000..f3b78f8 --- /dev/null +++ b/daemon/main.c @@ -0,0 +1,329 @@ +/* +* DA manager +* +* Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. +* +* Contact: +* +* Jaewon Lim +* Woojin Jung +* Juyoung Kim +* + * 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. +* +* Contributors: +* - S-Core Co., Ltd +* +*/ + +#include // for fopen, fprintf +#include // for atexit +#include // for open +#include // for open +#include // for socket +#include // for sockaddr_un +#include // for sockaddr_in, socklen_t + +#include // for signal +#include // for unlink +#include // for open, fcntl +#include // for fsetxattr + +#include "daemon.h" +#include "sys_stat.h" + +#define SINGLETON_LOCKFILE "/tmp/lockfile.da" +#define PORTFILE "/tmp/port.da" +#define UDS_NAME "/tmp/da.socket" + +#define INIT_PORT 8001 +#define LIMIT_PORT 8100 + +// initialize global variable +__da_manager manager = +{ + NULL, -1, -1, // portfile pointer, host / target server socket + 0, // target count + 0, // config_flag + -1, // sampling_thread handle + {-1, -1, PTHREAD_MUTEX_INITIALIZER}, // host + {{0L, }, }, // target + {0, } // appPath +}; + +// ============================================================================== +// util functions +// ============================================================================== + +static void writeToPortfile(int code) +{ + if(unlikely(manager.portfile == 0)) + return; + + fprintf(manager.portfile, "%d", code); +} + +// ============================================================================== +// atexit functions +// ============================================================================== + +void _close_server_socket(void) +{ + LOGI("close_server_socket\n"); + // close server socket + if(manager.host_server_socket != -1) + close(manager.host_server_socket); + if(manager.target_server_socket != -1) + close(manager.target_server_socket); +} + +static void _unlink_file(void) +{ + LOGI("unlink files\n"); + unlink(PORTFILE); + unlink(SINGLETON_LOCKFILE); +} + +// =============================================================================== +// making sockets +// =============================================================================== + +// return 0 for normal case +static int makeTargetServerSocket() +{ + struct sockaddr_un serverAddrUn; + + if(manager.target_server_socket != -1) + return -1; // should be never happend + + // remove existed unix domain socket file + unlink(UDS_NAME); + + if ((manager.target_server_socket = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + { + LOGE("Target server socket creation failed\n"); + return -1; + } + + // set smack attribute for certification + fsetxattr(manager.target_server_socket, "security.SMACK64IPIN", "*", 1, 0); + fsetxattr(manager.target_server_socket, "security.SMACK64IPOUT", "*", 1, 0); + + bzero(&serverAddrUn, sizeof(serverAddrUn)); + serverAddrUn.sun_family = AF_UNIX; + sprintf(serverAddrUn.sun_path, "%s", UDS_NAME); + + if (-1 == bind(manager.target_server_socket, (struct sockaddr*) &serverAddrUn, + sizeof(serverAddrUn))) + { + LOGE("Target server socket binding failed\n"); + return -1; + } + + chmod(serverAddrUn.sun_path, 0777); + + if (-1 == listen(manager.target_server_socket, 5)) + { + LOGE("Target server socket listening failed\n"); + return -1; + } + + LOGI("Created TargetSock %d\n", manager.target_server_socket); + return 0; +} + +// return port number for normal case +// return negative value for error case +static int makeHostServerSocket() +{ + struct sockaddr_in serverAddrIn; + int opt = 1; + int port; + + if(manager.host_server_socket != -1) + return -1; // should be never happened + + if ((manager.host_server_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) + { + LOGE("Host server socket creation failed\n"); + return -1; + } + + setsockopt(manager.host_server_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); + memset(&serverAddrIn, 0, sizeof(serverAddrIn)); + serverAddrIn.sin_family = AF_INET; + serverAddrIn.sin_addr.s_addr = htonl(INADDR_ANY); + + // bind address to server socket + for(port = INIT_PORT; port < LIMIT_PORT; port++) + { + serverAddrIn.sin_port = htons(port); + if (0 == bind(manager.host_server_socket, (struct sockaddr*) &serverAddrIn, sizeof(serverAddrIn))) + break; + } + + if(port == LIMIT_PORT) + { + LOGE("Host server socket binding failed\n"); + return -1; + } + + // enter listen state from client + if (-1 == listen(manager.host_server_socket, 5)) + { + LOGE("Host server socket listening failed\n"); + return -1; + } + + LOGI("Created HostSock %d\n", manager.host_server_socket); + return port; +} + +// =============================================================================== +// initializing / finalizing functions +// =============================================================================== + +static int singleton(void) +{ + struct flock fl; + int fd; + + fd = open(SINGLETON_LOCKFILE, O_RDWR | O_CREAT, 0600); + if(fd < 0) + { + writeToPortfile(ERR_LOCKFILE_CREATE_FAILED); + LOGE("singleton lock file creation failed"); + return -1; + } + + fl.l_start = 0; + fl.l_len = 0; + fl.l_type = F_WRLCK; + fl.l_whence = SEEK_SET; + if(fcntl(fd, F_SETLK, &fl) < 0) + { + writeToPortfile(ERR_ALREADY_RUNNING); + LOGE("another instance of daemon is already running"); + return -1; + } + + return 0; +} + +// return 0 for normal case +static int initializeManager() +{ + int i; + + atexit(_close_server_socket); + + if(initialize_system_info() < 0) + { + writeToPortfile(ERR_INITIALIZE_SYSTEM_INFO_FAILED); + return -1; + } + + // make server socket + if(makeTargetServerSocket() != 0) + { + writeToPortfile(ERR_TARGET_SERVER_SOCKET_CREATE_FAILED); + return -1; + } + + i = makeHostServerSocket(); + if(i < 0) + { + writeToPortfile(ERR_HOST_SERVER_SOCKET_CREATE_FAILED); + return -1; + } + else // host server socket creation succeed + { + writeToPortfile(i); + } + + LOGI("SUCCESS to write port\n"); + + // initialize target client sockets + for (i = 0; i < MAX_TARGET_COUNT; i++) + { + manager.target[i].pid = -1; + manager.target[i].socket = -1; + manager.target[i].event_fd = -1; + manager.target[i].recv_thread = -1; + manager.target[i].allocmem = 0; + manager.target[i].starttime = 0; + } + manager.target_count = 0; + + // initialize sendMutex + pthread_mutex_init(&(manager.host.data_socket_mutex), NULL); + + return 0; +} + +static int finalizeManager() +{ + finalize_system_info(); + + LOGI("Finalize daemon\n"); + + // close host client socket + if(manager.host.control_socket != -1) + close(manager.host.control_socket); + if(manager.host.data_socket != -1) + close(manager.host.data_socket); + + return 0; +} + +// main function +int main() +{ + int result; + initialize_log(); + + atexit(_unlink_file); + + manager.portfile = fopen(PORTFILE, "w"); + if(manager.portfile == NULL) + { + LOGE("cannot create portfile"); + return 1; + } + + if(singleton() < 0) + return 1; + + //for terminal exit + signal(SIGHUP, SIG_IGN); + chdir("/"); + + //new session reader + setsid(); + + // initialize manager + result = initializeManager(); + fclose(manager.portfile); + if(result == 0) + { + //daemon work + daemonLoop(); + + finalizeManager(); + return 0; + } + else + { + return 1; + } +} diff --git a/daemon/sys_stat.c b/daemon/sys_stat.c index 9bc4350..1562957 100644 --- a/daemon/sys_stat.c +++ b/daemon/sys_stat.c @@ -27,10 +27,14 @@ */ #include +#include +#include #include #include #include #include +#include +#include #include #include #include @@ -49,12 +53,11 @@ #endif #include "sys_stat.h" -#include "da_debug.h" +#include "daemon.h" // defines for runtime environment #define FOR_EACH_CPU - #define BUFFER_MAX 1024 #define LARGE_BUFFER 512 #define MIDDLE_BUFFER 256 @@ -77,19 +80,12 @@ #define DA_PROBE_TIZEN_SONAME "da_probe_tizen.so" #define DA_PROBE_OSP_SONAME "da_probe_osp.so" -#ifndef likely -#define likely(x) __builtin_expect((x), 1) -#define unlikely(x) __builtin_expect((x), 0) -#endif - enum PROCESS_DATA { PROCDATA_STAT, PROCDATA_SMAPS }; -long long get_total_alloc_size(); - // declared by greatim static int Hertz = 0; static int num_of_cpu = 0; @@ -98,19 +94,6 @@ static unsigned long mem_slot_array[MEM_SLOT_MAX]; static CPU_t* cpus = NULL; static unsigned long probe_so_size = 0; -// utility function -int get_flag_num(unsigned int flag) -{ - int i; - for(i = 0; flag != 0; i++) - { - flag &= (flag - 1); - } - return i; -} - - - // daemon api : get status from file // pfd must not be null int get_file_status(int* pfd, const char* filename) diff --git a/daemon/sys_stat.h b/daemon/sys_stat.h index 91e2091..d714cd4 100644 --- a/daemon/sys_stat.h +++ b/daemon/sys_stat.h @@ -33,19 +33,6 @@ extern "C" { #endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #define CHARGERFD "/sys/class/power_supply/battery/charge_now" #define VOLTAGEFD "/sys/class/power_supply/battery/voltage_now" diff --git a/daemon/threads.c b/daemon/threads.c new file mode 100644 index 0000000..1c50934 --- /dev/null +++ b/daemon/threads.c @@ -0,0 +1,299 @@ +/* +* DA manager +* +* Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. +* +* Contact: +* +* Jaewon Lim +* Woojin Jung +* Juyoung Kim +* + * 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. +* +* Contributors: +* - S-Core Co., Ltd +* +*/ + +#include +#include // for atoi, atol +#include // for strchr +#include // for uint64_t +#include // for recv +#include // for recv +#include // for setitimer +#include // for sigemptyset, sigset_t, sigaddset, ... +#include // for write + +#include "daemon.h" +#include "utils.h" +#include "sys_stat.h" + +#define TIMER_INTERVAL_SEC 1 +#define TIMER_INTERVAL_USEC 0 + +static void* recvThread(void* data) +{ + int index = (int)data; + uint64_t event; + ssize_t recvLen; + msg_t log; + + // initialize target variable + manager.target[index].pid = -1; + manager.target[index].starttime = 0; + manager.target[index].allocmem = 0; + + while(1) + { + // read from target process + recvLen = recv(manager.target[index].socket, &log, + sizeof(log.type) + sizeof(log.length), MSG_WAITALL); + + if(unlikely(recvLen < sizeof(log.type) + sizeof(log.length))) + { // disconnect + event = EVENT_STOP; + write(manager.target[index].event_fd, &event, sizeof(uint64_t)); + break; + } + + // send to host + if (likely(log.length > 0)) + { + recvLen = recv(manager.target[index].socket, log.data, log.length, MSG_WAITALL); + if(unlikely(recvLen != log.length)) // consume as disconnect + { + event = EVENT_STOP; + write(manager.target[index].event_fd, &event, sizeof(uint64_t)); + break; + } + } + + log.data[log.length] = '\0'; + if(log.type == MSG_ALLOC) + { + manager.target[index].allocmem = str_to_int64(log.data); + continue; // don't send to host + } + else if(log.type == MSG_PID) + { + LOGI("MSG_PID arrived : %s\n", log.data); + + // only when first MSG_PID is arrived + if(manager.target[index].pid == -1) + { + char* barloc; + barloc = strchr(log.data, '|'); + if(barloc == NULL) + { + // MSG_PID parsing error + // send error message to host + log.type = MSG_ERROR; + log.length = sprintf(log.data, "Process id information of target application is not correct."); + sendDataToHost(&log); + + // send stop message to main thread + event = EVENT_STOP; + write(manager.target[index].event_fd, &event, sizeof(uint64_t)); + break; + } + barloc[0] = '\0'; + barloc++; + + manager.target[index].pid = atoi(log.data); + manager.target[index].starttime = str_to_uint64(barloc); + + event = EVENT_PID; + write(manager.target[index].event_fd, &event, sizeof(uint64_t)); + } + continue; // don't send to host + } + else if(log.type == MSG_TERMINATE) + { + // send stop message to main thread + event = EVENT_STOP; + write(manager.target[index].event_fd, &event, sizeof(uint64_t)); + break; + } +#ifdef PRINT_TARGET_LOG + else if(log.type == MSG_LOG) + { + switch(log.data[0]) + { + case '2': // UI control creation log + case '3': // UI event log + case '6': // UI lifecycle log + case '7': // screenshot log + case '8': // scene transition log + LOGI("%dclass|%s\n", log.data[0] - '0', log.data); + break; + default: + break; + } + } + else if(log.type == MSG_IMAGE) + { + LOGI("MSG_IMAGE received\n"); + } + else // not MSG_LOG and not MSG_IMAGE + { + LOGI("Extra MSG TYPE (%d|%d|%s)\n", log.type, log.length, log.data); + } +#endif + + // any message before MSG_PID message arrived did not be sent to host + if(manager.target[index].pid != -1) + sendDataToHost(&log); + } + + manager.target[index].recv_thread = -1; + return NULL; +} + +int makeRecvThread(int index) +{ + if(manager.target[index].socket == -1) + return -1; + + if(pthread_create(&(manager.target[index].recv_thread), NULL, recvThread, (void*)index) < 0) + { + LOGE("Failed to create recv thread for socket (%d)\n", manager.target[index].socket); + return -1; + } + + return 0; +} + +static void* samplingThread(void* data) +{ + int err, signo, i; + int pidarray[MAX_TARGET_COUNT]; + int pidcount; + sigset_t waitsigmask; + msg_t log; + + LOGI("sampling thread started\n"); + + sigemptyset(&waitsigmask); + sigaddset(&waitsigmask, SIGALRM); + sigaddset(&waitsigmask, SIGUSR1); + + while(1) + { + err = sigwait(&waitsigmask, &signo); + if(err != 0) + { + LOGE("Failed to sigwait() in sampling thread\n"); + continue; + } + + if(signo == SIGALRM) + { + pidcount = 0; + for(i = 0; i < MAX_TARGET_COUNT; i++) + { + if(manager.target[i].socket != -1 && manager.target[i].pid != -1) + pidarray[pidcount++] = manager.target[i].pid; + } + + log.length = get_resource_info(log.data, DA_MSG_MAX, pidarray, pidcount); + if(log.length >= 0) + { + log.type = MSG_RESOURCE; + sendDataToHost(&log); + } + } + else if(signo == SIGUSR1) + { + // end this thread + break; + } + else + { + // not happened + LOGE("This should not be happend in sampling thread\n"); + } + } + + LOGI("sampling thread ended\n"); + return NULL; +} + + +// return 0 if normal case +// return minus value if critical error +// return plus value if non-critical error +int samplingStart() +{ + sigset_t newsigmask; + struct itimerval timerval; + + if(manager.sampling_thread != -1) // already started + return 1; + + sigemptyset(&newsigmask); + sigaddset(&newsigmask, SIGALRM); + sigaddset(&newsigmask, SIGUSR1); + if(pthread_sigmask(SIG_BLOCK, &newsigmask, NULL) != 0) + { + LOGE("Failed to signal masking for main thread\n"); + return -1; + } + + if(pthread_create(&(manager.sampling_thread), NULL, samplingThread, NULL) < 0) + { + LOGE("Failed to create sampling thread\n"); + return -1; + } + + timerval.it_interval.tv_sec = TIMER_INTERVAL_SEC; + timerval.it_interval.tv_usec = TIMER_INTERVAL_USEC; + timerval.it_value.tv_sec = TIMER_INTERVAL_SEC; + timerval.it_value.tv_usec = TIMER_INTERVAL_USEC; + setitimer(ITIMER_REAL, &timerval, NULL); + + return 0; +} + +int samplingStop() +{ + if(manager.sampling_thread != -1) + { + struct itimerval stopval; +// int status; +// sigset_t oldsigmask; +// sigemptyset(&oldsigmask); +// sigaddset(&oldsigmask, SIGALRM); +// sigaddset(&oldsigmask, SIGUSR1); + + // stop timer + stopval.it_interval.tv_sec = 0; + stopval.it_interval.tv_usec = 0; + stopval.it_value.tv_sec = 0; + stopval.it_value.tv_usec = 0; + setitimer(ITIMER_REAL, &stopval, NULL); + + pthread_kill(manager.sampling_thread, SIGUSR1); + pthread_join(manager.sampling_thread, NULL); + + // this code commented because this phrase occurs an error +// if(sigprocmask(SIG_UNBLOCK, &oldsigmask, NULL) < 0) +// { +// LOGE("Failed to pthread_sigmask\n"); +// } + manager.sampling_thread = -1; + } + + return 0; +} diff --git a/daemon/utils.c b/daemon/utils.c index 13070ff..c6278db 100644 --- a/daemon/utils.c +++ b/daemon/utils.c @@ -26,126 +26,300 @@ * */ +#include #include +#include +#include + #include +#include // for unlink +#include // for opendir, readdir +#include // for open +#include // for open +#include // for open +#include // for setgroups + +#include "daemon.h" #include "utils.h" -#include "da_debug.h" -#define BUFFER_MAX 1024 +#define BUFFER_MAX 1024 +#define APP_GROUPS_MAX 100 +#define APP_GROUP_LIST "/usr/share/privilege-control/app_group_list" +#define SELF_LABEL_FILE "/proc/self/attr/current" +#define SMACK_LABEL_LEN 255 +#define SID_APP 5000 -static int file_fd = -1; +#define APPDIR1 "/opt/apps/" +#define APPDIR2 "/opt/usr/apps/" -static pthread_mutex_t write_mutex; +uint64_t str_to_uint64(char* str) +{ + uint64_t res = 0; + + if(str != NULL) + { + while(*str >= '0' && *str <= '9') + { + res = res * 10 + (*str - '0'); + str++; + } + } -// get application name from executable binary path -char* get_app_name(char* binary_path) + return res; +} + +int64_t str_to_int64(char* str) { - char* pos; + int64_t res = 0; + int64_t factor = 1; + + if(str != NULL) + { + if(*str == '-') + { + factor = -1; + str++; + } + else if(*str == '+') + { + factor = 1; + str++; + } - pos = strrchr(binary_path, '/'); - if(pos != NULL) - pos++; + while(*str >= '0' && *str <= '9') + { + res = res * 10 + (*str - '0'); + str++; + } + } - return pos; + return (res * factor); } -// execute applcation with executable binary path -// return 0 to fail to execute -// return 1 to succeed to execute -int exec_app(const char* exec_path, int app_type) +int read_line(const int fd, char* ptr, const unsigned int maxlen) { - pid_t pid; - char command[PATH_MAX]; + unsigned int n = 0; + char c[2]; + int rc; - if (exec_path == NULL || strlen(exec_path) <= 0) + while(n != maxlen) { - LOGE("Executable path is not correct\n"); - return 0; + if((rc = read(fd, c, 1)) != 1) + return -1; // eof or read err + + if(*c == '\n') + { + ptr[n] = 0; + return n; + } + ptr[n++] = *c; } + return -1; // no space +} - if (( pid = fork()) < 0) // fork error - return 0; +int smack_set_label_for_self(const char *label) +{ + int len; + int fd; + int ret; - else if(pid > 0) - return 1; // exit parent process with successness + len = strnlen(label, SMACK_LABEL_LEN + 1); + if (len > SMACK_LABEL_LEN) + return -1; + + fd = open(SELF_LABEL_FILE, O_WRONLY); + if (fd < 0) + return -1; - sprintf(command, "%s %s", DA_PRELOAD(app_type), exec_path); - LOGI("launch app path is %s, executable path is %s\n", LAUNCH_APP_PATH, exec_path); - execl(SHELL_CMD, SHELL_CMD, "-c", command, NULL); + ret = write(fd, label, len); + close(fd); - return 1; + return (ret < 0) ? -1 : 0; } -#ifdef USE_LAUNCH_PAD -// execute application by launch pad -// return 0 to fail to execute -// return 1 to succeed to execute -int exec_app_by_launchpad(const char* pkg_name) +void set_appuser_groups(void) { - pid_t pid; - - if (pkg_name == NULL || strlen(pkg_name) <= 0) + int fd = 0; + char buffer[5]; + gid_t t_gid = -1; + gid_t groups[APP_GROUPS_MAX] = {0, }; + int cnt = 0; + + // groups[cnt++] = SID_DEVELOPER; + fd = open(APP_GROUP_LIST, O_RDONLY); + if(fd < 0) { - LOGE("Package name is not correct\n"); - return 0; + LOGE("cannot get app's group lists from %s", APP_GROUP_LIST); + return; } - if (( pid = fork()) < 0) // fork error - return 0; + for(;;) + { + if(read_line(fd, buffer, sizeof buffer) < 0) + { + break; + } - else if(pid > 0) - return 1; // exit parent process with successness + t_gid = strtoul(buffer, 0, 10); + errno = 0; + if(errno != 0) + { + LOGE("cannot change string to integer: [%s]\n", buffer); + continue; + } - LOGI("launch app path is %s, pkg name is %s\n", LAUNCH_APP_PATH, pkg_name); - execl(LAUNCH_APP_PATH, LAUNCH_APP_NAME, pkg_name, DA_PRELOAD_EXEC, NULL); + if(t_gid) + { + if(cnt < APP_GROUPS_MAX) + { + groups[cnt++] = t_gid; + } + else + { + LOGE("cannot add groups more than %d", APP_GROUPS_MAX); + break; + } + } + } - return 1; + if(cnt > 0) + { + if(setgroups(sizeof(groups) / sizeof(groups[0]), groups) != 0) + { + fprintf(stderr, "set groups failed errno: %d\n", errno); + exit(1); + } + } } -#endif -#if 0 -void kill_app(const char* binary_path) // fork version +int get_smack_label(const char* execpath, char* buffer, int buflen) { - pid_t pid; - pid_t pkg_pid; - char command[PATH_MAX]; + int i, ret = 0; + char* temp; + if(strncmp(execpath, APPDIR1, strlen(APPDIR1)) == 0) + { + execpath = execpath + strlen(APPDIR1); + temp = strchr(execpath, '/'); + for(i = 0; i < strlen(execpath) ; i++) + { + if(execpath + i == temp) + break; + buffer[i] = execpath[i]; + } + buffer[i] = '\0'; + } + else if(strncmp(execpath, APPDIR2, strlen(APPDIR2)) == 0) + { + execpath = execpath + strlen(APPDIR2); + temp = strchr(execpath, '/'); + for(i = 0; i < strlen(execpath) ; i++) + { + if(execpath + i == temp) + break; + buffer[i] = execpath[i]; + } + buffer[i] = '\0'; + } + else + { + ret = -1; + } - if (( pid = fork()) < 0) - return; + return ret; +} - //exit parent process - else if(pid > 0) - return; - - pkg_pid = find_pid_from_path(binary_path); +// return 0 if succeed +// return -1 if error occured +int remove_indir(const char *dirname) +{ + DIR *dir; + struct dirent *entry; + char path[PATH_MAX]; - if(pkg_pid > 0) + dir = opendir(dirname); + if(dir == NULL) { - sprintf(command, "kill -9 %d", pkg_pid); - LOGI(" : %s\n", command); - execl(SHELL_CMD, SHELL_CMD, "-c", command, NULL); + return -1; } - else + + while((entry = readdir(dir)) != NULL) { - exit(0); + if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")) + { + snprintf(path, (size_t) PATH_MAX, "%s/%s", dirname, entry->d_name); + if (entry->d_type != DT_DIR) // file + { + unlink(path); + } + else { } // directory + } } + closedir(dir); + + return 0; } -#else -void kill_app(const char* binary_path) // non fork version + +// get application name from executable binary path +char* get_app_name(char* binary_path) { - pid_t pkg_pid; + char* pos; + + pos = strrchr(binary_path, '/'); + if(pos != NULL) + pos++; + + return pos; +} + +// execute applcation with executable binary path +// return 0 to fail to execute +// return 1 to succeed to execute +int exec_app(const char* exec_path, int app_type) +{ + pid_t pid; char command[PATH_MAX]; + char appid[SMACK_LABEL_LEN]; - pkg_pid = find_pid_from_path(binary_path); + if (exec_path == NULL || strlen(exec_path) <= 0) + { + LOGE("Executable path is not correct\n"); + return 0; + } - if(pkg_pid > 0) + if (( pid = fork()) < 0) // fork error + return 0; + + else if(pid > 0) + return 1; // exit parent process with successness + + if(get_smack_label(exec_path, appid, SMACK_LABEL_LEN) < 0) { - sprintf(command, "kill -9 %d", pkg_pid); - LOGI("kill app : %s\n", command); - system(command); + LOGE("failed to get smack label\n"); + return 0; + } + else + { + LOGI("smack lable is %s\n", appid); + if(smack_set_label_for_self(appid) < 0) + { + LOGE("failed to set label for self\n"); + } + + set_appuser_groups(); + if(setgid(SID_APP) < 0) + { + LOGE("failed to setgid\n"); + } + if(setuid(SID_APP) < 0) + { + LOGE("failed to setuid\n"); + } + sprintf(command, "%s %s", DA_PRELOAD(app_type), exec_path); + LOGI("launch app path is %s, executable path is %s\n", LAUNCH_APP_PATH, exec_path); + execl(SHELL_CMD, SHELL_CMD, "-c", command, NULL); + return 1; } } -#endif // find process id from executable binary path pid_t find_pid_from_path(const char* path) @@ -183,78 +357,215 @@ pid_t find_pid_from_path(const char* path) return status; } -static void mkdirs() +void kill_app(const char* binary_path) { - mkdir("/home/developer/sdk_tools/da", 0775); - mkdir("/home/developer/sdk_tools/da/battery", 0775); + pid_t pkg_pid; + char command[PATH_MAX]; + + pkg_pid = find_pid_from_path(binary_path); + if(pkg_pid > 0) + { + sprintf(command, "kill -9 %d", pkg_pid); + system(command); + } } -int create_open_batt_log(const char* app_name) +int get_app_type(char* appPath) { - char log_path[PATH_MAX]; + int fd; + char buf[BUFFER_MAX]; - pthread_mutex_init(&write_mutex, NULL); - sprintf(log_path, "%s%s", BATT_LOG_FILE, app_name); - - if ((file_fd = open(log_path, O_WRONLY|O_CREAT|O_TRUNC)) == -1) + sprintf(buf, "%s.exe", appPath); + fd = open(buf, O_RDONLY); + if(fd != -1) { - mkdirs(); - if ((file_fd = open(log_path, O_WRONLY|O_CREAT|O_TRUNC)) == -1) - { - LOGE("Failed to open batt log file\n"); - return 0; - } + close(fd); + return APP_TYPE_OSP; + } + else + { + return APP_TYPE_TIZEN; } - - return file_fd; } -int get_batt_fd() +int get_executable(char* appPath, char* buf, int buflen) { - return file_fd; + int fd; + + sprintf(buf, "%s.exe", appPath); + fd = open(buf, O_RDONLY); + if(fd != -1) + { + close(fd); + } + else + { + strcpy(buf, appPath); + } + return 0; } -int write_batt_log(const char* msg) +int get_app_install_path(char *strAppInstall, int length) { - int length = -1; + FILE *fp; + char buf[BUFFER_MAX]; + char *p; + int i; - if (file_fd == -1 ) + if ((fp = fopen(DA_INSTALL_PATH, "r")) == NULL) { + LOGE("Failed to open %s\n", DA_INSTALL_PATH); return -1; } - pthread_mutex_lock(&write_mutex); + /*ex : <15> DW_AT_comp_dir : (indirect string, offset: 0x25f): /home/yt/workspace/templatetest/Debug-Tizen-Emulator */ + while (fgets(buf, BUFFER_MAX, fp) != NULL) + { + //name + p = buf; + for (i = 0; i < BUFFER_MAX; i++) + { + if (*p == ':') + break; + p++; + } + + if (*p != ':') + break; + else + p++; - length = write(file_fd, msg, strlen(msg)); + //(...,offset:...) + for (; i < BUFFER_MAX; i++) + { + if (*p == '(') + { + while (*p != ')') + { + p++; + } + } + if (*p == ':') + break; + p++; + } - pthread_mutex_unlock(&write_mutex); + //find + if (*p != ':') + break; + for (; i < BUFFER_MAX; i++) + { + if (*p == ':' || *p == ' ' || *p == '\t') + p++; + else + break; + } - return length; + //name + if (strlen(p) <= length) + { + sprintf(strAppInstall, "%s", p); + for (i = 0; i < strlen(p); i++) + { + if (strAppInstall[i] == '\n' || strAppInstall[i] == '\t') + { + strAppInstall[i] = '\0'; + break; + } + } + fclose(fp); + return 1; + } + } + fclose(fp); + return -1; } -void close_batt_fd() +int is_app_built_pie(void) { - close(file_fd); - file_fd = -1; + int result; + FILE *fp; + char buf[BUFFER_MAX]; + + if((fp = fopen(DA_BUILD_OPTION, "r")) == NULL) + { + LOGE("Failed to open %s\n", DA_BUILD_OPTION); + return -1; + } + + if(fgets(buf, BUFFER_MAX, fp) != NULL) + { + if(strcmp(buf, "DYN\n") == 0) + result = 1; + else if(strcmp(buf, "EXEC\n") == 0) + result = 0; + else + result = -1; + } + else + { + result = -1; + } + fclose(fp); + + return result; } -#if DEBUG -void write_log() +int get_app_base_address(int *baseAddress) { - int fd; + int res; + FILE *fp; + char buf[BUFFER_MAX]; - fd = open("/dev/null", O_RDONLY); - dup2(fd, 0); + if((fp = fopen(DA_BASE_ADDRESS, "r")) == NULL) + { + LOGE("Failed to open %s\n", DA_BASE_ADDRESS); + return -1; + } - fd = open("/tmp/da_daemon.log", O_WRONLY | O_CREAT | O_TRUNC, 0640); - if(fd < 0) { - fd = open("/dev/null", O_WRONLY); - } - dup2(fd, 1); - dup2(fd, 2); + if(fgets(buf, BUFFER_MAX, fp) != NULL) + { + res = sscanf(buf, "%x", baseAddress); + } + else + { + res = -1; + } + fclose(fp); - fprintf(stderr,"--- da starting (pid %d) ---\n", getpid()); + return res; } + +int is_same_app_process(char* appPath, int pid) +{ + int ret = 0; + FILE *fp; + char buf[BUFFER_MAX]; + char cmdPath[PATH_MAX]; + char execPath[PATH_MAX]; + + get_executable(appPath, execPath, PATH_MAX); + sprintf(cmdPath, "/proc/%d/cmdline", pid); + + if((fp = fopen(cmdPath, "r")) == NULL) + { + return 0; + } + + if(fgets(buf, BUFFER_MAX, fp) != NULL) + { +#ifdef RUN_APP_LOADER + if(strcmp(buf, appPath) == 0) +#else + // use execPath instead of manager.appPath + if(strcmp(buf, execPath) == 0) #endif + ret = 1; + else + ret = 0; + } + fclose(fp); + return ret; +} diff --git a/daemon/utils.h b/daemon/utils.h index 1df092a..b0f72b9 100644 --- a/daemon/utils.h +++ b/daemon/utils.h @@ -26,22 +26,16 @@ * */ -#ifndef _UTILS_ -#define _UTILS_ +#include +#include + +#ifndef _UTILS_H_ +#define _UTILS_H_ #ifdef __cplusplus extern "C" { #endif -#include -#include -#include -#include -#include -#include -#include -#include - #define LAUNCH_APP_PATH "/usr/bin/launch_app" #define KILL_APP_PATH "/usr/bin/pkill" #define LAUNCH_APP_NAME "launch_app" @@ -52,12 +46,21 @@ extern "C" { #define BATT_LOG_FILE "/home/developer/sdk_tools/da/battery/" #define SHELL_CMD "/bin/sh" +#define DA_INSTALL_PATH "/home/developer/sdk_tools/da/da_install_path" +#define DA_BUILD_OPTION "/home/developer/sdk_tools/da/da_build_option" +#define DA_BASE_ADDRESS "/home/developer/sdk_tools/da/da_base_address" + enum ApplicationType { APP_TYPE_TIZEN = 0, APP_TYPE_OSP = 1 }; +uint64_t str_to_uint64(char* str); +int64_t str_to_int64(char* str); + +int remove_indir(const char *dirname); + char* get_app_name(char* binary_path); int exec_app(const char* exec_path, int app_type); @@ -66,18 +69,12 @@ void kill_app(const char* binary_path); pid_t find_pid_from_path(const char* path); -int create_open_batt_log(const char* app_name); - -int get_batt_fd(); - -int write_batt_log(const char* message); - -void close_batt_fd(); - -#if DEBUG -void write_log(); -#endif - +int get_app_type(char* appPath); +int get_executable(char* appPath, char* buf, int buflen); +int get_app_install_path(char *strAppInstall, int length); +int is_app_built_pie(void); +int get_app_base_address(int *baseAddress); +int is_same_app_process(char* appPath, int pid); #ifdef __cplusplus } diff --git a/packaging/dynamic-analysis-manager.spec b/packaging/dynamic-analysis-manager.spec index 9e4a606..86d2e79 100644 --- a/packaging/dynamic-analysis-manager.spec +++ b/packaging/dynamic-analysis-manager.spec @@ -1,10 +1,11 @@ Name: dynamic-analysis-manager Summary: dynamic analyzer manager -Version: 2.1.0 +Version: 2.1.1 Release: 1 Group: System/Libraries License: Apache License, Version 2 Source: %{name}_%{version}.tar.gz +BuildRequires: libattr-devel BuildRequires: glib2-devel BuildRequires: aul-devel BuildRequires: vconf-devel -- 2.7.4