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 <sys/timerfd.h> // for timerfd
41 #include <unistd.h> // for access, sleep
46 #include <attr/xattr.h> // for fsetxattr
47 #include <sys/smack.h>
50 #include <linux/input.h>
56 #include "da_protocol.h"
59 #define DA_WORK_DIR "/home/developer/sdk_tools/da/"
60 #define DA_READELF_PATH "/home/developer/sdk_tools/da/readelf"
61 #define SCREENSHOT_DIR "/tmp/da"
64 #define MAX_CONNECT_SIZE 12
65 #define MAX_APP_LAUNCH_TIME 6
68 #define MAX_FILENAME 128
70 #define ARRAY_END (-11)
72 input_dev g_key_dev[MAX_DEVICE];
73 input_dev g_touch_dev[MAX_DEVICE];
75 // return bytes size of readed data
76 // return 0 if no data readed or error occurred
77 static int _file_read(FILE* fp, char *buffer, int size)
81 if(fp != NULL && size > 0)
83 ret = fread((void*)buffer, sizeof(char), size, fp);
91 ret = 0; // error case
97 // get input id of given input device
98 static int get_input_id(char* inputname)
100 static int query_cmd_type = 0; // 1 if /lib/udev/input_id, 2 if udevadm
102 char buffer[BUF_SIZE];
103 char command[MAX_FILENAME];
106 // determine input_id query command
107 if(unlikely(query_cmd_type == 0))
109 if(access("/lib/udev/input_id", F_OK) == 0) // there is /lib/udev/input_id
113 else // there is not /lib/udev/input_id
119 // make command string
120 if(query_cmd_type == 1)
122 sprintf(command, "/lib/udev/input_id /class/input/%s", inputname);
126 sprintf(command, "udevadm info --name=input/%s --query=property", inputname);
130 cmd_fp = popen(command, "r");
131 _file_read(cmd_fp, buffer, BUF_SIZE);
133 // determine input id
134 if(strstr(buffer, INPUT_ID_STR_KEY)) // key
138 else if(strstr(buffer, INPUT_ID_STR_TOUCH)) // touch
140 ret = INPUT_ID_TOUCH;
142 else if(strstr(buffer, INPUT_ID_STR_KEYBOARD)) // keyboard
146 else if(strstr(buffer, INPUT_ID_STR_TABLET)) // touch (emulator)
148 ret = INPUT_ID_TOUCH;
156 // get filename and fd of given input type devices
157 static void _get_fds(input_dev *dev, int input_id)
163 dp = opendir("/sys/class/input");
167 while((d = readdir(dp)) != NULL)
169 if(!strncmp(d->d_name, "event", 5)) // start with "event"
172 if(input_id == get_input_id(d->d_name))
174 sprintf(dev[count].fileName, "/dev/input/%s", d->d_name);
175 dev[count].fd = open(dev[count].fileName, O_RDWR | O_NONBLOCK);
183 dev[count].fd = ARRAY_END; // end of input_dev array
187 void _device_write(input_dev *dev, struct input_event* in_ev)
190 for(i = 0; dev[i].fd != ARRAY_END; i++)
194 write(dev[i].fd, in_ev, sizeof(struct input_event));
195 LOGI("write(%d, %d, %d)\n",dev[i].fd, (int)in_ev, sizeof(struct input_event));
200 long long get_total_alloc_size()
203 long long allocsize = 0;
205 for(i = 0; i < MAX_TARGET_COUNT; i++)
207 if(manager.target[i].socket != -1 && manager.target[i].allocmem > 0)
208 allocsize += manager.target[i].allocmem;
213 static int getEmptyTargetSlot()
216 for(i = 0; i < MAX_TARGET_COUNT; i++)
218 if(manager.target[i].socket == -1)
225 static void setEmptyTargetSlot(int index)
227 if(index >= 0 && index < MAX_TARGET_COUNT)
229 manager.target[index].pid = -1;
230 manager.target[index].recv_thread = -1;
231 manager.target[index].allocmem = 0;
232 manager.target[index].starttime = 0;
233 manager.target[index].initial_log = 0;
234 if(manager.target[index].event_fd != -1)
235 close(manager.target[index].event_fd);
236 manager.target[index].event_fd = -1;
237 if(manager.target[index].socket != -1)
238 close(manager.target[index].socket);
239 manager.target[index].socket = -1;
243 // ======================================================================================
244 // send functions to host
245 // ======================================================================================
248 int sendACKCodeToHost(enum HostMessageType resp, int msgcode)
251 //disabled string protocol
253 if (manager.host.control_socket != -1)
256 char logstr[DA_MSG_MAX];
259 codelen = sprintf(codestr, "%d", msgcode);
260 loglen = sprintf(logstr, "%d|%d|%s", (int)resp, codelen, codestr);
262 send(manager.host.control_socket, logstr, loglen, MSG_NOSIGNAL);
269 // ========================================================================================
270 // start and terminate control functions
271 // ========================================================================================
273 int startProfiling(long launchflag)
275 const struct app_info_t *app_info = &prof_session.app_info;
277 // remove previous screen capture files
278 remove_indir(SCREENSHOT_DIR);
279 mkdir(SCREENSHOT_DIR, 0777);
281 smack_lsetlabel(SCREENSHOT_DIR, "*", SMACK_LABEL_ACCESS);
283 manager.config_flag = launchflag;
285 if (samplingStart() < 0)
288 switch (app_info->app_type) {
290 kill_app(app_info->exe_path);
291 if (exec_app_tizen(app_info->app_id, app_info->exe_path)) {
292 LOGE("Cannot exec tizen app %s\n", app_info->app_id);
297 case APP_TYPE_RUNNING:
298 // TODO: nothing, it's running
300 case APP_TYPE_COMMON:
301 kill_app(app_info->exe_path);
302 if (exec_app_common(app_info->exe_path)) {
303 LOGE("Cannot exec common app %s\n", app_info->exe_path);
309 LOGE("Unknown app type %d\n", app_info->app_type);
318 // just send stop message to all target process
319 static void terminate_all_target()
325 sendlog.type = MSG_STOP;
328 for (i = 0; i < MAX_TARGET_COUNT; i++)
330 if(manager.target[i].socket != -1)
332 sendlen = send(manager.target[i].socket, &sendlog, sizeof(sendlog.type) + sizeof(sendlog.length), MSG_NOSIGNAL);
335 LOGI("TERMINATE send exit msg (socket %d) by terminate_all_target()\n", manager.target[i].socket);
341 // terminate all target and wait for threads
346 terminate_all_target();
349 // wait for all other thread exit
350 for(i = 0; i < MAX_TARGET_COUNT; i++)
352 if(manager.target[i].recv_thread != -1)
354 pthread_join(manager.target[i].recv_thread, NULL);
359 // terminate all profiling by critical error
360 // TODO: don't send data to host
361 static void terminate_error(char* errstr, int sendtohost)
366 #define MAX_EVENTS_NUM 10
367 static int deviceEventHandler(input_dev* dev, int input_type)
372 struct input_event in_ev[MAX_EVENTS_NUM];
373 struct msg_data_t *log;
375 if(input_type == INPUT_ID_TOUCH || input_type == INPUT_ID_KEY)
378 size = read(dev->fd, &in_ev[count], sizeof(*in_ev) );
381 } while (count < MAX_EVENTS_NUM && size > 0);
384 LOGI("read %d %s events\n",
386 input_type == INPUT_ID_KEY ? STR_KEY : STR_TOUCH);
387 log = gen_message_event(in_ev, count, input_type);
388 printBuf((char *)log, MSG_DATA_HDR_LEN + log->len);
395 LOGW("unknown input_type\n");
401 // return 0 if normal case
402 // return plus value if non critical error occur
403 // return minus value if critical error occur
404 // return -11 if all target process closed
405 static int targetEventHandler(int epollfd, int index, uint64_t msg)
409 if (index == 0) { // main application
410 if (start_replay() != 0) {
411 LOGE("Cannot start replay thread\n");
415 manager.target[index].initial_log = 1;
418 if(msg & EVENT_STOP || msg & EVENT_ERROR)
420 LOGI("target close, socket(%d), pid(%d) : (remaining %d target)\n",
421 manager.target[index].socket,
422 manager.target[index].pid,
423 manager.target_count - 1);
424 if (index == 0) { // main application
427 epoll_ctl(epollfd, EPOLL_CTL_DEL, manager.target[index].event_fd, NULL);
428 setEmptyTargetSlot(index);
429 if (0 == __sync_sub_and_fetch(&manager.target_count, 1)) // all target client are closed
436 // return 0 if normal case
437 // return plus value if non critical error occur
438 // return minus value if critical error occur
439 static int targetServerHandler(int efd)
442 struct epoll_event ev;
444 int index = getEmptyTargetSlot();
445 if(index == MAX_TARGET_COUNT)
447 LOGW("Max target number(8) reached, no more target can connected\n");
451 manager.target[index].socket = accept(manager.target_server_socket, NULL, NULL);
453 if(manager.target[index].socket >= 0) // accept succeed
456 // set smack attribute for certification
457 fsetxattr(manager.target[index].socket, "security.SMACK64IPIN", "*", 1, 0);
458 fsetxattr(manager.target[index].socket, "security.SMACK64IPOUT", "*", 1, 0);
459 #endif /* LOCALTEST */
461 // send config message to target process
462 log.type = MSG_OPTION;
463 log.length = sprintf(log.data, "%u", manager.config_flag);
464 send(manager.target[index].socket, &log, sizeof(log.type) + sizeof(log.length) + log.length, MSG_NOSIGNAL);
467 manager.target[index].event_fd = eventfd(0, EFD_NONBLOCK);
468 if(manager.target[index].event_fd == -1)
470 // fail to make event fd
471 LOGE("fail to make event fd for socket (%d)\n", manager.target[index].socket);
472 goto TARGET_CONNECT_FAIL;
475 // add event fd to epoll list
477 ev.data.fd = manager.target[index].event_fd;
478 if(epoll_ctl(efd, EPOLL_CTL_ADD, manager.target[index].event_fd, &ev) < 0)
480 // fail to add event fd
481 LOGE("fail to add event fd to epoll list for socket (%d)\n", manager.target[index].socket);
482 goto TARGET_CONNECT_FAIL;
485 // make recv thread for target
486 if(makeRecvThread(index) != 0)
488 // fail to make recv thread
489 LOGE("fail to make recv thread for socket (%d)\n", manager.target[index].socket);
490 epoll_ctl(efd, EPOLL_CTL_DEL, manager.target[index].event_fd, NULL);
491 goto TARGET_CONNECT_FAIL;
494 if(manager.app_launch_timerfd >= 0)
496 epoll_ctl(efd, EPOLL_CTL_DEL, manager.app_launch_timerfd, NULL);
497 close(manager.app_launch_timerfd);
498 manager.app_launch_timerfd = -1;
501 LOGI("target connected = %d(running %d target)\n",
502 manager.target[index].socket, manager.target_count + 1);
504 manager.target_count++;
509 LOGE("Failed to accept at target server socket\n");
513 if(manager.target_count == 0) // if this connection is main connection
517 else // if this connection is not main connection then ignore process by error
519 setEmptyTargetSlot(index);
524 // return 0 if normal case
525 // return plus value if non critical error occur
526 // return minus value if critical error occur
527 static int hostServerHandler(int efd)
529 static int hostserverorder = 0;
531 struct epoll_event ev;
533 if(hostserverorder > 1) // control and data socket connected already
536 csocket = accept(manager.host_server_socket, NULL, NULL);
538 if(csocket >= 0) // accept succeed
541 ev.data.fd = csocket;
542 if(epoll_ctl(efd, EPOLL_CTL_ADD, csocket, &ev) < 0)
544 // consider as accept fail
545 LOGE("Failed to add socket fd to epoll list\n");
550 if(hostserverorder == 0)
552 manager.host.control_socket = csocket;
554 LOGI("host control socket connected = %d\n", csocket);
558 manager.host.data_socket = csocket;
559 LOGI("host data socket connected = %d\n", csocket);
567 LOGE("Failed to accept from host server socket\n");
573 //TODO del it or move to debug section
574 void printBuf (char * buf, int len)
578 char local_buf[3*16 + 2*16 + 1];
581 for ( i = 0; i < len/16 + 1; i++)
583 memset(local_buf, ' ', 5*16);
585 p2 = local_buf + 3*17;
586 for ( j = 0; j < 16; j++)
589 sprintf(p1, "%02X ",(unsigned char) *buf);
592 sprintf(p2, "%c ",(int)*buf);
601 LOGI("%s\n",local_buf);
607 // return 0 if normal case
608 // return plus value if non critical error occur
609 // return minus value if critical error occur
610 // return -11 if socket closed
612 static int controlSocketHandler(int efd)
619 recv_len = recv(manager.host.control_socket,
622 // error or close request from host
623 if (recv_len == -1 || recv_len == 0)
627 msg.payload = malloc(msg.len);
629 LOGE("Cannot alloc msg payload\n");
630 sendACKCodeToHost(MSG_NOTOK, ERR_WRONG_MESSAGE_FORMAT);
633 // Receive payload (if exists)
634 recv_len = recv(manager.host.control_socket,
636 msg.len, MSG_WAITALL);
638 res = host_message_handler(&msg);
645 // return 0 for normal case
648 int ret = 0; // return value
652 struct epoll_event ev, *events;
654 int numevent; // number of occured events
656 _get_fds(g_key_dev, INPUT_ID_KEY);
657 _get_fds(g_touch_dev, INPUT_ID_TOUCH);
659 // initialize epoll event pool
660 events = (struct epoll_event*) malloc(sizeof(struct epoll_event) * EPOLL_SIZE);
663 LOGE("Out of memory when allocate epoll event pool\n");
667 if((efd = epoll_create(MAX_CONNECT_SIZE)) < 0)
669 LOGE("epoll creation error\n");
674 // add server sockets to epoll event pool
676 ev.data.fd = manager.host_server_socket;
677 if(epoll_ctl(efd, EPOLL_CTL_ADD, manager.host_server_socket, &ev) < 0)
679 LOGE("Host server socket epoll_ctl error\n");
684 ev.data.fd = manager.target_server_socket;
685 if(epoll_ctl(efd, EPOLL_CTL_ADD, manager.target_server_socket, &ev) < 0)
687 LOGE("Target server socket epoll_ctl error\n");
692 // add device fds to epoll event pool
694 for(i = 0; g_key_dev[i].fd != ARRAY_END; i++)
696 if(g_key_dev[i].fd >= 0)
698 ev.data.fd = g_key_dev[i].fd;
699 if(epoll_ctl(efd, EPOLL_CTL_ADD, g_key_dev[i].fd, &ev) < 0)
701 LOGE("keyboard device file epoll_ctl error\n");
707 for(i = 0; g_touch_dev[i].fd != ARRAY_END; i++)
709 if(g_touch_dev[i].fd >= 0)
711 ev.data.fd = g_touch_dev[i].fd;
712 if(epoll_ctl(efd, EPOLL_CTL_ADD, g_touch_dev[i].fd, &ev) < 0)
714 LOGE("touch device file epoll_ctl error\n");
722 numevent = epoll_wait(efd, events, EPOLL_SIZE, -1);
725 LOGE("Failed to epoll_wait : num of event(%d), errno(%d)\n", numevent, errno);
729 for(i = 0; i < numevent; i++)
731 // check for request from event fd
732 for(k = 0; k < MAX_TARGET_COUNT; k++)
734 if(manager.target[k].socket != -1 &&
735 events[i].data.fd == manager.target[k].event_fd)
738 recvLen = read(manager.target[k].event_fd, &u, sizeof(uint64_t));
739 if(recvLen != sizeof(uint64_t))
741 // maybe closed, but ignoring is more safe then removing fd from epoll list
745 if(-11 == targetEventHandler(efd, k, u))
747 LOGI("all target process is closed\n");
755 if(k != MAX_TARGET_COUNT)
758 // check for request from device fd
759 for(k = 0; g_touch_dev[k].fd != ARRAY_END; k++)
761 if(g_touch_dev[k].fd >= 0 &&
762 events[i].data.fd == g_touch_dev[k].fd)
764 if(deviceEventHandler(&g_touch_dev[k], INPUT_ID_TOUCH) < 0)
766 terminate_error("Internal DA framework error, Please re-run the profiling.", 1);
774 if(g_touch_dev[k].fd != ARRAY_END)
777 for(k = 0; g_key_dev[k].fd != ARRAY_END; k++)
779 if(g_key_dev[k].fd >= 0 &&
780 events[i].data.fd == g_key_dev[k].fd)
782 if(deviceEventHandler(&g_key_dev[k], INPUT_ID_KEY) < 0)
784 terminate_error("Internal DA framework error, Please re-run the profiling.", 1);
792 if(g_key_dev[k].fd != ARRAY_END)
795 // connect request from target
796 if(events[i].data.fd == manager.target_server_socket)
798 if(targetServerHandler(efd) < 0) // critical error
800 terminate_error("Internal DA framework error, Please re-run the profiling.", 1);
805 // connect request from host
806 else if(events[i].data.fd == manager.host_server_socket)
808 int result = hostServerHandler(efd);
811 terminate_error("Internal DA framework error, Please re-run the profiling.", 1);
816 // control message from host
817 else if(events[i].data.fd == manager.host.control_socket)
819 int result = controlSocketHandler(efd);
820 if(result == -11) // socket close
822 // close target and host socket and quit
823 LOGI("host close = %d\n", manager.host.control_socket);
829 terminate_error("Internal DA framework error, Please re-run the profiling.", 1);
834 else if(events[i].data.fd == manager.host.data_socket)
837 recvLen = recv(manager.host.data_socket, recvBuf, 32, MSG_DONTWAIT);
839 { // close data socket
840 epoll_ctl(efd, EPOLL_CTL_DEL, manager.host.data_socket, NULL);
841 close(manager.host.data_socket);
842 manager.host.data_socket = -1;
843 // TODO: finish transfer thread
846 LOGW("host message from data socket %d\n", recvLen);
848 // check for application launch timerfd
849 else if(events[i].data.fd == manager.app_launch_timerfd)
851 // send to host timeout error message for launching application
852 terminate_error("Failed to launch application", 1);
853 epoll_ctl(efd, EPOLL_CTL_DEL, manager.app_launch_timerfd, NULL);
854 close(manager.app_launch_timerfd);
855 manager.app_launch_timerfd = -1;
863 LOGW("Unknown socket fd (%d)\n", events[i].data.fd);