4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
8 * Jaewon Lim <jaewon81.lim@samsung.com>
9 * Woojin Jung <woojin2.jung@samsung.com>
10 * Juyoung Kim <j0.kim@samsung.com>
12 * Licensed under the Apache License, Version 2.0 (the "License");
13 * you may not use this file except in compliance with the License.
14 * You may obtain a copy of the License at
16 * http://www.apache.org/licenses/LICENSE-2.0
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
30 #include <stdlib.h> // for realpath
31 #include <string.h> // for strtok, strcpy, strncpy
32 #include <limits.h> // for realpath
34 #include <errno.h> // for errno
35 #include <sys/types.h> // for accept, mkdir, opendir, readdir
36 #include <sys/socket.h> // for accept
37 #include <sys/stat.h> // for mkdir
38 #include <sys/eventfd.h> // for eventfd
39 #include <sys/epoll.h> // for epoll apis
40 #include <unistd.h> // for access, sleep
41 #include <attr/xattr.h> // for fsetxattr
47 #define DA_WORK_DIR "/home/developer/sdk_tools/da/"
48 #define DA_READELF_PATH "/home/developer/sdk_tools/da/readelf"
49 #define SCREENSHOT_DIR "/tmp/da"
52 #define MAX_CONNECT_SIZE 12
54 static void terminate_error(char* errstr, int sendtohost);
56 long long get_total_alloc_size()
59 long long allocsize = 0;
61 for(i = 0; i < MAX_TARGET_COUNT; i++)
63 if(manager.target[i].socket != -1 && manager.target[i].allocmem > 0)
64 allocsize += manager.target[i].allocmem;
69 static int getEmptyTargetSlot()
72 for(i = 0; i < MAX_TARGET_COUNT; i++)
74 if(manager.target[i].socket == -1)
81 static void setEmptyTargetSlot(int index)
83 if(index >= 0 && index < MAX_TARGET_COUNT)
85 manager.target[index].pid = -1;
86 manager.target[index].recv_thread = -1;
87 manager.target[index].allocmem = 0;
88 manager.target[index].starttime = 0;
89 manager.target[index].initial_log = 0;
90 if(manager.target[index].event_fd != -1)
91 close(manager.target[index].event_fd);
92 manager.target[index].event_fd = -1;
93 if(manager.target[index].socket != -1)
94 close(manager.target[index].socket);
95 manager.target[index].socket = -1;
99 // ======================================================================================
100 // send functions to host
101 // ======================================================================================
103 int sendDataToHost(msg_t* log)
105 if (manager.host.data_socket != -1)
107 char logstr[DA_MSG_MAX];
111 loglen = sprintf(logstr, "%d|%d|%s\n", log->type, log->length + 1, log->data);
113 loglen = sprintf(logstr, "%d|%d|\n", log->type, log->length + 1);
115 // loglen = sprintf(logstr, "%d|%s\n", log->type, log->data);
117 pthread_mutex_lock(&(manager.host.data_socket_mutex));
118 send(manager.host.data_socket, logstr, loglen, MSG_NOSIGNAL);
119 pthread_mutex_unlock(&(manager.host.data_socket_mutex));
126 // msgstr can be NULL
127 static int sendACKStrToHost(enum HostMessageType resp, char* msgstr)
129 if (manager.host.control_socket != -1)
131 char logstr[DA_MSG_MAX];
135 loglen = sprintf(logstr, "%d|%d|%s", (int)resp, strlen(msgstr), msgstr);
137 loglen = sprintf(logstr, "%d|0|", (int)resp);
139 send(manager.host.control_socket, logstr, loglen, MSG_NOSIGNAL);
146 static int sendACKCodeToHost(enum HostMessageType resp, int msgcode)
148 if (manager.host.control_socket != -1)
151 char logstr[DA_MSG_MAX];
154 codelen = sprintf(codestr, "%d", msgcode);
155 loglen = sprintf(logstr, "%d|%d|%s", (int)resp, codelen, codestr);
157 send(manager.host.control_socket, logstr, loglen, MSG_NOSIGNAL);
164 // ========================================================================================
165 // start and terminate control functions
166 // ========================================================================================
168 static int startProfiling(long launchflag)
170 char execPath[PATH_MAX];
172 // remove previous screen capture files
173 remove_indir(SCREENSHOT_DIR);
174 mkdir(SCREENSHOT_DIR, 0777);
176 manager.config_flag = launchflag;
178 #ifdef RUN_APP_LOADER
179 strcpy(execPath, manager.appPath);
181 get_executable(manager.appPath, execPath, PATH_MAX);
183 if(exec_app(execPath, get_app_type(manager.appPath)))
185 if(samplingStart() < 0)
189 LOGI("Timer Started\n");
197 // terminate single target
198 // just send stop message to target process
199 static void terminate_target(int index)
203 sendlog.type = MSG_STOP;
206 if(manager.target[index].socket != -1)
208 // result of sending to disconnected socket is not expected
209 sendlen = send(manager.target[index].socket, &sendlog, sizeof(sendlog.type) + sizeof(sendlog.length), MSG_NOSIGNAL);
212 LOGI("TERMINATE send exit msg (socket %d) by terminate_target()\n", manager.target[index].socket);
217 // just send stop message to all target process
218 static void terminate_all_target()
224 sendlog.type = MSG_STOP;
227 for (i = 0; i < MAX_TARGET_COUNT; i++)
229 if(manager.target[i].socket != -1)
231 sendlen = send(manager.target[i].socket, &sendlog, sizeof(sendlog.type) + sizeof(sendlog.length), MSG_NOSIGNAL);
234 LOGI("TERMINATE send exit msg (socket %d) by terminate_all_target()\n", manager.target[i].socket);
240 // terminate all target and wait for threads
241 static void terminate_all()
244 terminate_all_target();
247 // wait for all other thread exit
248 for(i = 0; i < MAX_TARGET_COUNT; i++)
250 if(manager.target[i].recv_thread != -1)
252 pthread_join(manager.target[i].recv_thread, NULL);
257 // terminate all profiling by critical error
258 static void terminate_error(char* errstr, int sendtohost)
262 LOGE("TERMINATE ERROR: %s\n", errstr);
265 log.type = MSG_ERROR;
266 log.length = sprintf(log.data, "%s", errstr);
267 sendDataToHost(&log);
273 // ===========================================================================================
274 // message parsing and handling functions
275 // ===========================================================================================
277 // return 0 for normal case
278 // return negative value for error case
279 static int parseHostMessage(msg_t* log, char* msg)
283 int ret = 0; // parsing success
285 if(log == NULL || msg == NULL)
288 // Host message looks like this
289 // MSG_TYPE|MSG_LENGTH|MSG_STRING
290 // MSG_TYPE is always 3 digits number
294 log->type = atoi(msg);
297 for(i = 0; msg[i] != '\0'; i++)
306 log->length = atoi(msg);
318 msglen = strlen(msg);
320 if(msglen == log->length)
322 strcpy(log->data, msg);
323 log->data[log->length] = '\0';
325 // else if(msglen > log->length)
327 // strncpy(log->data, msg, log->length);
328 // log->data[log->length] = '\0';
332 ret = -1; // parsing error
337 ret = -1; // parsing error
343 ret = -1; // parsing error
349 // return 0 if normal case
350 // return plus value if non critical error occur
351 // return minus value if critical error occur
352 static int hostMessageHandler(msg_t* log)
356 char *barloc, *tmploc;
357 char execPath[PATH_MAX];
365 if(strcmp(PROTOCOL_VERSION, log->data) != 0)
367 sendACKCodeToHost(MSG_NOTOK, ERR_WRONG_PROTOCOL_VERSION);
371 sendACKStrToHost(MSG_OK, NULL);
375 LOGI("MSG_START handling : %s\n", log->data);
378 sendACKCodeToHost(MSG_NOTOK, ERR_WRONG_MESSAGE_DATA);
379 return -1; // wrong message format
382 // parsing for host start status
384 barloc = strchr(tmploc, '|');
387 sendACKCodeToHost(MSG_NOTOK, ERR_WRONG_MESSAGE_FORMAT);
388 return -1; // wrong message format
391 // parsing for target launch option flag
393 barloc = strchr(tmploc, '|');
396 while(tmploc < barloc)
398 flag = (flag * 10) + (*tmploc - '0');
404 sendACKCodeToHost(MSG_NOTOK, ERR_WRONG_MESSAGE_FORMAT);
405 return -1; // wrong message format
407 LOGI("launch flag : %lx\n", flag);
409 // parsing for application package name
411 strcpy(manager.appPath, tmploc);
413 get_executable(manager.appPath, execPath, PATH_MAX); // get exact app executable file name
414 LOGI("executable app path %s\n", manager.appPath);
416 #ifdef RUN_APP_LOADER
417 kill_app(manager.appPath);
423 char command[PATH_MAX];
425 //save app install path
426 mkdir(DA_WORK_DIR, 0775);
428 "%s -Wwi %s | grep DW_AT_comp_dir > %s", DA_READELF_PATH,
429 execPath, DA_INSTALL_PATH);
430 LOGI("appInstallCommand %s\n", command);
434 "%s -h %s | grep Type | cut -d\" \" -f33 > %s", DA_READELF_PATH,
435 execPath, DA_BUILD_OPTION);
436 LOGI("appInstallCommand %s\n", command);
439 if(startProfiling(flag) < 0)
441 sendACKCodeToHost(MSG_NOTOK, ERR_CANNOT_START_PROFILING);
445 sendACKStrToHost(MSG_OK, NULL);
448 LOGI("MSG_STOP handling\n");
449 sendACKStrToHost(MSG_OK, NULL);
457 manager.config_flag = atoi(log->data);
458 sendACKStrToHost(MSG_OK, NULL);
460 LOGI("MSG_OPTION : str(%s), flag(%x)\n", log->data, manager.config_flag);
462 sendlog.type = MSG_OPTION;
463 sendlog.length = sprintf(sendlog.data, "%u", manager.config_flag);
465 for(i = 0; i < MAX_TARGET_COUNT; i++)
467 if(manager.target[i].socket != -1)
469 send(manager.target[i].socket, &sendlog, sizeof(sendlog.type) + sizeof(sendlog.length) + sendlog.length, MSG_NOSIGNAL);
475 sendACKCodeToHost(MSG_NOTOK, ERR_WRONG_MESSAGE_DATA);
480 sendACKStrToHost(MSG_OK, NULL);
483 LOGW("Unknown msg\n");
484 sendACKCodeToHost(MSG_NOTOK, ERR_WRONG_MESSAGE_TYPE);
492 // ========================================================================================
493 // socket and event_fd handling functions
494 // ========================================================================================
496 // return 0 if normal case
497 // return plus value if non critical error occur
498 // return minus value if critical error occur
499 // return -11 if all target process closed
500 static int targetEventHandler(int epollfd, int index, uint64_t msg)
506 if(index == 0) // assume index 0 is main application process
509 char tempBuff[DA_MSG_MAX];
510 char tempBuff2[DA_MSG_MAX];
511 char tempPath[PATH_MAX];
513 get_executable(manager.appPath, tempPath, PATH_MAX);
514 if(realpath(tempPath, tempBuff) == NULL)
516 LOGW("Failed to get realpath of app\n");
517 strcpy(tempBuff, tempPath);
520 sprintf(tempPath, "/proc/%d/maps", manager.target[index].pid);
521 sprintf(tempBuff2, "cat %s | grep %s | cut -d\"-\" -f1 > %s",
522 tempPath, tempBuff, DA_BASE_ADDRESS);
523 LOGI("base address command is %s\n", tempBuff2);
526 if(access(tempPath, F_OK) != 0)
528 if(is_same_app_process(manager.appPath, manager.target[index].pid) == 0)
532 if(get_app_base_address(&base_address) == 1)
538 get_app_install_path(tempPath, PATH_MAX);
539 get_device_info(tempBuff, DA_MSG_MAX);
540 log.type = MSG_DEVICE;
541 if (strlen(tempPath) > 0)
543 get_executable(manager.appPath, tempBuff2, DA_MSG_MAX);
544 log.length = sprintf(log.data, "%s`,%d`,%Lu`,%d`,%u`,%d`,%s/%s", tempBuff,
545 manager.target[index].pid, manager.target[index].starttime,
546 is_app_built_pie(), base_address, get_app_type(manager.appPath),
547 tempPath, get_app_name(tempBuff2));
551 log.length = sprintf(log.data, "%s`,%d`,%Lu`,%d`,%u`,%d`,", tempBuff,
552 manager.target[index].pid, manager.target[index].starttime,
553 is_app_built_pie(), base_address, get_app_type(manager.appPath));
556 LOGI("%s\n", log.data);
561 log.length = sprintf(log.data, "%d`,%Lu", manager.target[index].pid, manager.target[index].starttime);
564 manager.target[index].initial_log = 1;
565 sendDataToHost(&log);
568 if(msg & EVENT_STOP || msg & EVENT_ERROR)
570 LOGI("target close, socket(%d), pid(%d) : (remaining %d target)\n",
571 manager.target[index].socket, manager.target[index].pid, manager.target_count - 1);
573 terminate_target(index);
574 epoll_ctl(epollfd, EPOLL_CTL_DEL, manager.target[index].event_fd, NULL);
575 setEmptyTargetSlot(index);
576 if (0 == __sync_sub_and_fetch(&manager.target_count, 1)) // all target client are closed
578 log.type = MSG_TERMINATE;
581 sendDataToHost(&log);
589 // return 0 if normal case
590 // return plus value if non critical error occur
591 // return minus value if critical error occur
592 static int targetServerHandler(int efd)
595 struct epoll_event ev;
597 int index = getEmptyTargetSlot();
598 if(index == MAX_TARGET_COUNT)
600 LOGW("Max target number(8) reached, no more target can connected\n");
604 manager.target[index].socket = accept(manager.target_server_socket, NULL, NULL);
606 if(manager.target[index].socket >= 0) // accept succeed
608 // set smack attribute for certification
609 fsetxattr(manager.target[index].socket, "security.SMACK64IPIN", "*", 1, 0);
610 fsetxattr(manager.target[index].socket, "security.SMACK64IPOUT", "*", 1, 0);
612 // send config message to target process
613 log.type = MSG_OPTION;
614 log.length = sprintf(log.data, "%u", manager.config_flag);
615 send(manager.target[index].socket, &log, sizeof(log.type) + sizeof(log.length) + log.length, MSG_NOSIGNAL);
618 manager.target[index].event_fd = eventfd(0, EFD_NONBLOCK);
619 if(manager.target[index].event_fd == -1)
621 // fail to make event fd
622 LOGE("fail to make event fd for socket (%d)\n", manager.target[index].socket);
623 goto TARGET_CONNECT_FAIL;
626 // add event fd to epoll list
628 ev.data.fd = manager.target[index].event_fd;
629 if(epoll_ctl(efd, EPOLL_CTL_ADD, manager.target[index].event_fd, &ev) < 0)
631 // fail to add event fd
632 LOGE("fail to add event fd to epoll list for socket (%d)\n", manager.target[index].socket);
633 goto TARGET_CONNECT_FAIL;
636 // make recv thread for target
637 if(makeRecvThread(index) != 0)
639 // fail to make recv thread
640 LOGE("fail to make recv thread for socket (%d)\n", manager.target[index].socket);
641 epoll_ctl(efd, EPOLL_CTL_DEL, manager.target[index].event_fd, NULL);
642 goto TARGET_CONNECT_FAIL;
645 LOGI("target connected = %d(running %d target)\n",
646 manager.target[index].socket, manager.target_count + 1);
648 manager.target_count++;
653 LOGE("Failed to accept at target server socket\n");
657 if(manager.target_count == 0) // if this connection is main connection
661 else // if this connection is not main connection then ignore process by error
663 setEmptyTargetSlot(index);
668 // return 0 if normal case
669 // return plus value if non critical error occur
670 // return minus value if critical error occur
671 static int hostServerHandler(int efd)
673 static int hostserverorder = 0;
675 struct epoll_event ev;
677 if(hostserverorder > 1) // control and data socket connected already
680 csocket = accept(manager.host_server_socket, NULL, NULL);
682 if(csocket >= 0) // accept succeed
685 ev.data.fd = csocket;
686 if(epoll_ctl(efd, EPOLL_CTL_ADD, csocket, &ev) < 0)
688 // consider as accept fail
689 LOGE("Failed to add socket fd to epoll list\n");
694 if(hostserverorder == 0)
696 manager.host.control_socket = csocket;
697 LOGI("host control socket connected = %d\n", csocket);
701 manager.host.data_socket = csocket;
702 LOGI("host data socket connected = %d\n", csocket);
710 LOGE("Failed to accept from host server socket\n");
715 // return 0 if normal case
716 // return plus value if non critical error occur
717 // return minus value if critical error occur
718 // return -11 if socket closed
719 static int controlSocketHandler()
722 char recvBuf[DA_MSG_MAX];
725 // host log format xxx|length|str
726 recvLen = recv(manager.host.control_socket, recvBuf, RECV_BUF_MAX, 0);
730 recvBuf[recvLen] = '\0';
731 LOGI("host sent control msg str(%s)\n", recvBuf);
733 if(parseHostMessage(&log, recvBuf) < 0)
735 // error to parse host message
736 sendACKCodeToHost(MSG_NOTOK, ERR_WRONG_MESSAGE_FORMAT);
740 // host msg command handling
741 return hostMessageHandler(&log);
743 else // close request from HOST
749 // return 0 for normal case
752 int ret = 0; // return value
756 struct epoll_event ev, *events;
758 int numevent; // number of occured events
760 // initialize epoll event pool
761 events = (struct epoll_event*) malloc(sizeof(struct epoll_event) * EPOLL_SIZE);
764 LOGE("Out of memory when allocate epoll event pool\n");
768 if((efd = epoll_create(MAX_CONNECT_SIZE)) < 0)
770 LOGE("epoll creation error\n");
775 // add server sockets to epoll event pool
777 ev.data.fd = manager.host_server_socket;
778 if(epoll_ctl(efd, EPOLL_CTL_ADD, manager.host_server_socket, &ev) < 0)
780 LOGE("Host server socket epoll_ctl error\n");
785 ev.data.fd = manager.target_server_socket;
786 if(epoll_ctl(efd, EPOLL_CTL_ADD, manager.target_server_socket, &ev) < 0)
788 LOGE("Target server socket epoll_ctl error\n");
796 numevent = epoll_wait(efd, events, EPOLL_SIZE, -1);
799 LOGE("Failed to epoll_wait : num of event(%d), errno(%d)\n", numevent, errno);
803 for(i = 0; i < numevent; i++)
805 // check for request from event fd
806 for(k = 0; k < MAX_TARGET_COUNT; k++)
808 if(manager.target[k].socket != -1 &&
809 events[i].data.fd == manager.target[k].event_fd)
812 recvLen = read(manager.target[k].event_fd, &u, sizeof(uint64_t));
813 if(recvLen != sizeof(uint64_t))
815 // maybe closed, but ignoring is more safe then removing fd from epoll list
819 if(-11 == targetEventHandler(efd, k, u))
821 LOGI("all target process is closed\n");
831 if(k != MAX_TARGET_COUNT)
834 // connect request from target
835 if(events[i].data.fd == manager.target_server_socket)
837 if(targetServerHandler(efd) < 0) // critical error
839 terminate_error("Internal DA framework error, Please re-run the profiling.", 1);
844 // connect request from host
845 else if(events[i].data.fd == manager.host_server_socket)
847 int result = hostServerHandler(efd);
850 terminate_error("Internal DA framework error, Please re-run the profiling.", 1);
855 // control message from host
856 else if(events[i].data.fd == manager.host.control_socket)
858 int result = controlSocketHandler();
859 if(result == -11) // socket close
861 // close target and host socket and quit
862 LOGI("host close = %d\n", manager.host.control_socket);
869 terminate_error("Internal DA framework error, Please re-run the profiling.", 1);
874 else if(events[i].data.fd == manager.host.data_socket)
877 recvLen = recv(manager.host.data_socket, recvBuf, RECV_BUF_MAX, MSG_DONTWAIT);
879 { // close data socket
880 epoll_ctl(efd, EPOLL_CTL_DEL, manager.host.data_socket, NULL);
881 close(manager.host.data_socket);
882 manager.host.data_socket = -1;
885 LOGW("host message from data socket %d\n", recvLen);
891 LOGW("Unknown socket fd (%d)\n", events[i].data.fd);