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"
60 #define DA_WORK_DIR "/home/developer/sdk_tools/da/"
61 #define DA_READELF_PATH "/home/developer/sdk_tools/da/readelf"
62 #define SCREENSHOT_DIR "/tmp/da"
65 #define MAX_CONNECT_SIZE 12
66 #define MAX_APP_LAUNCH_TIME 6
69 #define MAX_FILENAME 128
71 #define ARRAY_END (-11)
73 input_dev g_key_dev[MAX_DEVICE];
74 input_dev g_touch_dev[MAX_DEVICE];
76 // return bytes size of readed data
77 // return 0 if no data readed or error occurred
78 static int _file_read(FILE* fp, char *buffer, int size)
82 if(fp != NULL && size > 0)
84 ret = fread((void*)buffer, sizeof(char), size, fp);
92 ret = 0; // error case
98 // get input id of given input device
99 static int get_input_id(char* inputname)
101 static int query_cmd_type = 0; // 1 if /lib/udev/input_id, 2 if udevadm
103 char buffer[BUF_SIZE];
104 char command[MAX_FILENAME];
107 // determine input_id query command
108 if(unlikely(query_cmd_type == 0))
110 if(access("/lib/udev/input_id", F_OK) == 0) // there is /lib/udev/input_id
114 else // there is not /lib/udev/input_id
120 // make command string
121 if(query_cmd_type == 1)
123 sprintf(command, "/lib/udev/input_id /class/input/%s", inputname);
127 sprintf(command, "udevadm info --name=input/%s --query=property", inputname);
131 cmd_fp = popen(command, "r");
132 _file_read(cmd_fp, buffer, BUF_SIZE);
134 // determine input id
135 if(strstr(buffer, INPUT_ID_STR_KEY)) // key
139 else if(strstr(buffer, INPUT_ID_STR_TOUCH)) // touch
141 ret = INPUT_ID_TOUCH;
143 else if(strstr(buffer, INPUT_ID_STR_KEYBOARD)) // keyboard
147 else if(strstr(buffer, INPUT_ID_STR_TABLET)) // touch (emulator)
149 ret = INPUT_ID_TOUCH;
157 // get filename and fd of given input type devices
158 static void _get_fds(input_dev *dev, int input_id)
164 dp = opendir("/sys/class/input");
168 while((d = readdir(dp)) != NULL)
170 if(!strncmp(d->d_name, "event", 5)) // start with "event"
173 if(input_id == get_input_id(d->d_name))
175 sprintf(dev[count].fileName, "/dev/input/%s", d->d_name);
176 dev[count].fd = open(dev[count].fileName, O_RDWR | O_NONBLOCK);
184 dev[count].fd = ARRAY_END; // end of input_dev array
188 void _device_write(input_dev *dev, struct input_event* in_ev)
191 for(i = 0; dev[i].fd != ARRAY_END; i++)
195 write(dev[i].fd, in_ev, sizeof(struct input_event));
196 LOGI("write(%d, %d, %d)\n",dev[i].fd, (int)in_ev, sizeof(struct input_event));
201 long long get_total_alloc_size()
204 long long allocsize = 0;
206 for(i = 0; i < MAX_TARGET_COUNT; i++)
208 if(manager.target[i].socket != -1 && manager.target[i].allocmem > 0)
209 allocsize += manager.target[i].allocmem;
214 static int getEmptyTargetSlot()
217 for(i = 0; i < MAX_TARGET_COUNT; i++)
219 if(manager.target[i].socket == -1)
226 static void setEmptyTargetSlot(int index)
228 if(index >= 0 && index < MAX_TARGET_COUNT)
230 manager.target[index].pid = -1;
231 manager.target[index].recv_thread = -1;
232 manager.target[index].allocmem = 0;
233 manager.target[index].starttime = 0;
234 manager.target[index].initial_log = 0;
235 if(manager.target[index].event_fd != -1)
236 close(manager.target[index].event_fd);
237 manager.target[index].event_fd = -1;
238 if(manager.target[index].socket != -1)
239 close(manager.target[index].socket);
240 manager.target[index].socket = -1;
244 // ======================================================================================
245 // send functions to host
246 // ======================================================================================
249 int sendACKCodeToHost(enum HostMessageType resp, int msgcode)
252 //disabled string protocol
254 if (manager.host.control_socket != -1)
257 char logstr[DA_MSG_MAX];
260 codelen = sprintf(codestr, "%d", msgcode);
261 loglen = sprintf(logstr, "%d|%d|%s", (int)resp, codelen, codestr);
263 send(manager.host.control_socket, logstr, loglen, MSG_NOSIGNAL);
270 // ========================================================================================
271 // start and terminate control functions
272 // ========================================================================================
274 static int exec_app(const struct app_info_t *app_info)
278 switch (app_info->app_type) {
280 kill_app(app_info->exe_path);
281 if (exec_app_tizen(app_info->app_id, app_info->exe_path)) {
282 LOGE("Cannot exec tizen app %s\n", app_info->app_id);
286 case APP_TYPE_RUNNING:
287 // TODO: nothing, it's running
289 case APP_TYPE_COMMON:
290 kill_app(app_info->exe_path);
291 if (exec_app_common(app_info->exe_path)) {
292 LOGE("Cannot exec common app %s\n", app_info->exe_path);
297 LOGE("Unknown app type %d\n", app_info->app_type);
305 static void epoll_add_input_events();
306 static void epoll_del_input_events();
308 int start_profiling()
310 const struct app_info_t *app_info = &prof_session.app_info;
313 // remove previous screen capture files
314 remove_indir(SCREENSHOT_DIR);
315 mkdir(SCREENSHOT_DIR, 0777);
317 smack_lsetlabel(SCREENSHOT_DIR, "*", SMACK_LABEL_ACCESS);
320 if (IS_OPT_SET(FL_CPU | FL_MEMORY)) {
321 if (samplingStart() < 0) {
322 LOGE("Cannot start sampling\n");
328 if (IS_OPT_SET(FL_RECORDING))
329 epoll_add_input_events();
331 if (exec_app(app_info)) {
332 LOGE("Cannot exec app\n");
340 if (IS_OPT_SET(FL_RECORDING))
341 epoll_del_input_events();
342 if (IS_OPT_SET(FL_CPU | FL_MEMORY))
349 void stop_profiling(void)
351 if (IS_OPT_SET(FL_RECORDING))
352 epoll_del_input_events();
353 if (IS_OPT_SET(FL_CPU | FL_MEMORY))
357 static void reconfigure_recording(struct conf_t conf)
359 uint64_t old_features = prof_session.conf.use_features;
360 uint64_t new_features = conf.use_features;
361 uint64_t to_enable = (new_features ^ old_features) & new_features;
362 uint64_t to_disable = (new_features ^ old_features) & old_features;
364 if (IS_OPT_SET_IN(FL_RECORDING, to_disable)) {
365 epoll_del_input_events();
366 prof_session.conf.use_features &= ~FL_RECORDING;
369 if (IS_OPT_SET_IN(FL_RECORDING, to_enable)) {
370 epoll_add_input_events();
371 prof_session.conf.use_features |= FL_RECORDING;
376 static int reconfigure_cpu_and_memory(struct conf_t conf)
378 uint64_t old_features = prof_session.conf.use_features;
379 uint64_t new_features = conf.use_features;
380 uint64_t to_enable = (new_features ^ old_features) & new_features;
381 uint64_t to_disable = (new_features ^ old_features) & old_features;
383 prof_session.conf.system_trace_period = conf.system_trace_period;
385 if (IS_OPT_SET(FL_CPU | FL_MEMORY))
388 if (IS_OPT_SET_IN(FL_CPU | FL_MEMORY, to_disable)) {
389 prof_session.conf.use_features &= ~(FL_CPU | FL_MEMORY);
393 if (IS_OPT_SET_IN(FL_CPU | FL_MEMORY, to_enable)) {
394 if (samplingStart() < 0) {
395 LOGE("Cannot start sampling\n");
398 prof_session.conf.use_features |= (FL_CPU | FL_MEMORY);
404 int reconfigure(struct conf_t conf)
406 reconfigure_recording(conf);
407 if (reconfigure_cpu_and_memory(conf)) {
408 LOGE("Cannot reconf cpu and memory\n");
415 // just send stop message to all target process
416 static void terminate_all_target()
420 msg_target_t sendlog;
422 sendlog.type = MSG_STOP;
425 for (i = 0; i < MAX_TARGET_COUNT; i++)
427 if(manager.target[i].socket != -1)
429 sendlen = send(manager.target[i].socket, &sendlog, sizeof(sendlog.type) + sizeof(sendlog.length), MSG_NOSIGNAL);
432 LOGI("TERMINATE send exit msg (socket %d) by terminate_all_target()\n", manager.target[i].socket);
438 // terminate all target and wait for threads
443 terminate_all_target();
445 // wait for all other thread exit
446 for(i = 0; i < MAX_TARGET_COUNT; i++)
448 if(manager.target[i].recv_thread != -1)
450 pthread_join(manager.target[i].recv_thread, NULL);
455 // terminate all profiling by critical error
456 // TODO: don't send data to host
457 static void terminate_error(char* errstr, int sendtohost)
462 #define MAX_EVENTS_NUM 10
463 static int deviceEventHandler(input_dev* dev, int input_type)
468 struct input_event in_ev[MAX_EVENTS_NUM];
469 struct msg_data_t *log;
471 if(input_type == INPUT_ID_TOUCH || input_type == INPUT_ID_KEY)
474 size = read(dev->fd, &in_ev[count], sizeof(*in_ev) );
477 } while (count < MAX_EVENTS_NUM && size > 0);
480 LOGI("read %d %s events\n",
482 input_type == INPUT_ID_KEY ? STR_KEY : STR_TOUCH);
483 log = gen_message_event(in_ev, count, input_type);
484 printBuf((char *)log, MSG_DATA_HDR_LEN + log->len);
491 LOGW("unknown input_type\n");
497 // return 0 if normal case
498 // return plus value if non critical error occur
499 // return minus value if critical error occur
500 // return -11 if all target process closed
501 static int targetEventHandler(int epollfd, int index, uint64_t msg)
505 if (index == 0) { // main application
506 if (start_replay() != 0) {
507 LOGE("Cannot start replay thread\n");
511 manager.target[index].initial_log = 1;
514 if(msg & EVENT_STOP || msg & EVENT_ERROR)
516 LOGI("target close, socket(%d), pid(%d) : (remaining %d target)\n",
517 manager.target[index].socket,
518 manager.target[index].pid,
519 manager.target_count - 1);
520 if (index == 0) { // main application
523 epoll_ctl(epollfd, EPOLL_CTL_DEL, manager.target[index].event_fd, NULL);
524 setEmptyTargetSlot(index);
525 if (0 == __sync_sub_and_fetch(&manager.target_count, 1)) // all target client are closed
532 // return 0 if normal case
533 // return plus value if non critical error occur
534 // return minus value if critical error occur
535 static int targetServerHandler(int efd)
538 struct epoll_event ev;
540 int index = getEmptyTargetSlot();
541 if(index == MAX_TARGET_COUNT)
543 LOGW("Max target number(8) reached, no more target can connected\n");
547 manager.target[index].socket = accept(manager.target_server_socket, NULL, NULL);
549 if(manager.target[index].socket >= 0) // accept succeed
552 // set smack attribute for certification
553 fsetxattr(manager.target[index].socket, "security.SMACK64IPIN", "*", 1, 0);
554 fsetxattr(manager.target[index].socket, "security.SMACK64IPOUT", "*", 1, 0);
555 #endif /* LOCALTEST */
557 // send config message to target process
558 log.type = MSG_OPTION;
559 log.length = sprintf(log.data, "%u",
560 prof_session.conf.use_features);
561 send(manager.target[index].socket, &log,
562 sizeof(log.type) + sizeof(log.length) + log.length,
566 manager.target[index].event_fd = eventfd(0, EFD_NONBLOCK);
567 if(manager.target[index].event_fd == -1)
569 // fail to make event fd
570 LOGE("fail to make event fd for socket (%d)\n", manager.target[index].socket);
571 goto TARGET_CONNECT_FAIL;
574 // add event fd to epoll list
576 ev.data.fd = manager.target[index].event_fd;
577 if(epoll_ctl(efd, EPOLL_CTL_ADD, manager.target[index].event_fd, &ev) < 0)
579 // fail to add event fd
580 LOGE("fail to add event fd to epoll list for socket (%d)\n", manager.target[index].socket);
581 goto TARGET_CONNECT_FAIL;
584 // make recv thread for target
585 if(makeRecvThread(index) != 0)
587 // fail to make recv thread
588 LOGE("fail to make recv thread for socket (%d)\n", manager.target[index].socket);
589 epoll_ctl(efd, EPOLL_CTL_DEL, manager.target[index].event_fd, NULL);
590 goto TARGET_CONNECT_FAIL;
593 if(manager.app_launch_timerfd >= 0)
595 epoll_ctl(efd, EPOLL_CTL_DEL, manager.app_launch_timerfd, NULL);
596 close(manager.app_launch_timerfd);
597 manager.app_launch_timerfd = -1;
600 LOGI("target connected = %d(running %d target)\n",
601 manager.target[index].socket, manager.target_count + 1);
603 manager.target_count++;
608 LOGE("Failed to accept at target server socket\n");
612 if(manager.target_count == 0) // if this connection is main connection
616 else // if this connection is not main connection then ignore process by error
618 setEmptyTargetSlot(index);
623 // return 0 if normal case
624 // return plus value if non critical error occur
625 // return minus value if critical error occur
626 static int hostServerHandler(int efd)
628 static int hostserverorder = 0;
630 struct epoll_event ev;
632 if(hostserverorder > 1) // control and data socket connected already
635 csocket = accept(manager.host_server_socket, NULL, NULL);
637 if(csocket >= 0) // accept succeed
640 ev.data.fd = csocket;
641 if(epoll_ctl(efd, EPOLL_CTL_ADD, csocket, &ev) < 0)
643 // consider as accept fail
644 LOGE("Failed to add socket fd to epoll list\n");
649 if(hostserverorder == 0)
651 manager.host.control_socket = csocket;
653 LOGI("host control socket connected = %d\n", csocket);
657 manager.host.data_socket = csocket;
658 LOGI("host data socket connected = %d\n", csocket);
666 LOGE("Failed to accept from host server socket\n");
672 // return 0 if normal case
673 // return plus value if non critical error occur
674 // return minus value if critical error occur
675 // return -11 if socket closed
677 static int controlSocketHandler(int efd)
680 struct msg_t msg_head;
685 recv_len = recv(manager.host.control_socket,
688 // error or close request from host
689 if (recv_len == -1 || recv_len == 0)
692 msg = malloc(MSG_CMD_HDR_LEN + msg_head.len);
694 LOGE("Cannot alloc msg\n");
695 sendACKCodeToHost(MSG_NOTOK, ERR_WRONG_MESSAGE_FORMAT);
698 msg->id = msg_head.id;
699 msg->len = msg_head.len;
701 // Receive payload (if exists)
702 recv_len = recv(manager.host.control_socket,
704 msg->len, MSG_WAITALL);
706 res = host_message_handler(msg);
713 static void epoll_add_input_events()
715 struct epoll_event ev;
718 // add device fds to epoll event pool
720 for (i = 0; g_key_dev[i].fd != ARRAY_END; i++) {
721 if (g_key_dev[i].fd >= 0) {
722 ev.data.fd = g_key_dev[i].fd;
723 if (epoll_ctl(manager.efd,
725 g_key_dev[i].fd, &ev) < 0)
726 LOGE("keyboard device file epoll_ctl error\n");
731 for (i = 0; g_touch_dev[i].fd != ARRAY_END; i++) {
732 if (g_touch_dev[i].fd >= 0) {
733 ev.data.fd = g_touch_dev[i].fd;
734 if (epoll_ctl(manager.efd,
736 g_touch_dev[i].fd, &ev) < 0)
737 LOGE("touch device file epoll_ctl error\n");
742 static void epoll_del_input_events()
746 // remove device fds from epoll event pool
747 for (i = 0; g_key_dev[i].fd != ARRAY_END; i++)
748 if (g_key_dev[i].fd >= 0)
749 if (epoll_ctl(manager.efd,
751 g_key_dev[i].fd, NULL) < 0)
752 LOGE("keyboard device file epoll_ctl error\n");
754 for (i = 0; g_touch_dev[i].fd != ARRAY_END; i++)
755 if (g_touch_dev[i].fd >= 0)
756 if (epoll_ctl(manager.efd,
758 g_touch_dev[i].fd, NULL) < 0)
759 LOGE("touch device file epoll_ctl error\n");
762 // return 0 for normal case
765 int ret = 0; // return value
769 struct epoll_event ev, *events;
770 int numevent; // number of occured events
772 _get_fds(g_key_dev, INPUT_ID_KEY);
773 _get_fds(g_touch_dev, INPUT_ID_TOUCH);
775 // initialize epoll event pool
776 events = (struct epoll_event*) malloc(sizeof(struct epoll_event) * EPOLL_SIZE);
779 LOGE("Out of memory when allocate epoll event pool\n");
783 if((manager.efd = epoll_create(MAX_CONNECT_SIZE)) < 0)
785 LOGE("epoll creation error\n");
790 // add server sockets to epoll event pool
792 ev.data.fd = manager.host_server_socket;
793 if (epoll_ctl(manager.efd, EPOLL_CTL_ADD,
794 manager.host_server_socket, &ev) < 0)
796 LOGE("Host server socket epoll_ctl error\n");
801 ev.data.fd = manager.target_server_socket;
802 if (epoll_ctl(manager.efd, EPOLL_CTL_ADD,
803 manager.target_server_socket, &ev) < 0)
805 LOGE("Target server socket epoll_ctl error\n");
813 numevent = epoll_wait(manager.efd, events, EPOLL_SIZE, -1);
816 LOGE("Failed to epoll_wait : num of event(%d), errno(%d)\n", numevent, errno);
820 for(i = 0; i < numevent; i++)
822 // check for request from event fd
823 for(k = 0; k < MAX_TARGET_COUNT; k++)
825 if(manager.target[k].socket != -1 &&
826 events[i].data.fd == manager.target[k].event_fd)
829 recvLen = read(manager.target[k].event_fd, &u, sizeof(uint64_t));
830 if(recvLen != sizeof(uint64_t))
832 // maybe closed, but ignoring is more safe then removing fd from epoll list
836 if(-11 == targetEventHandler(manager.efd, k, u))
838 LOGI("all target process is closed\n");
846 if(k != MAX_TARGET_COUNT)
849 // check for request from device fd
850 for(k = 0; g_touch_dev[k].fd != ARRAY_END; k++)
852 if(g_touch_dev[k].fd >= 0 &&
853 events[i].data.fd == g_touch_dev[k].fd)
855 if(deviceEventHandler(&g_touch_dev[k], INPUT_ID_TOUCH) < 0)
857 terminate_error("Internal DA framework error, Please re-run the profiling.", 1);
865 if(g_touch_dev[k].fd != ARRAY_END)
868 for(k = 0; g_key_dev[k].fd != ARRAY_END; k++)
870 if(g_key_dev[k].fd >= 0 &&
871 events[i].data.fd == g_key_dev[k].fd)
873 if(deviceEventHandler(&g_key_dev[k], INPUT_ID_KEY) < 0)
875 terminate_error("Internal DA framework error, Please re-run the profiling.", 1);
883 if(g_key_dev[k].fd != ARRAY_END)
886 // connect request from target
887 if(events[i].data.fd == manager.target_server_socket)
889 if(targetServerHandler(manager.efd) < 0) // critical error
891 terminate_error("Internal DA framework error, Please re-run the profiling.", 1);
896 // connect request from host
897 else if(events[i].data.fd == manager.host_server_socket)
899 int result = hostServerHandler(manager.efd);
902 terminate_error("Internal DA framework error, Please re-run the profiling.", 1);
907 // control message from host
908 else if(events[i].data.fd == manager.host.control_socket)
910 int result = controlSocketHandler(manager.efd);
911 if(result == -11) // socket close
913 // close target and host socket and quit
914 LOGI("host close = %d\n", manager.host.control_socket);
920 terminate_error("Internal DA framework error, Please re-run the profiling.", 1);
925 else if(events[i].data.fd == manager.host.data_socket)
928 recvLen = recv(manager.host.data_socket, recvBuf, 32, MSG_DONTWAIT);
930 { // close data socket
931 epoll_ctl(manager.efd, EPOLL_CTL_DEL,
932 manager.host.data_socket,
934 close(manager.host.data_socket);
935 manager.host.data_socket = -1;
936 // TODO: finish transfer thread
939 LOGW("host message from data socket %d\n", recvLen);
941 // check for application launch timerfd
942 else if(events[i].data.fd == manager.app_launch_timerfd)
944 // send to host timeout error message for launching application
945 terminate_error("Failed to launch application", 1);
946 epoll_ctl(manager.efd, EPOLL_CTL_DEL,
947 manager.app_launch_timerfd, NULL);
948 close(manager.app_launch_timerfd);
949 manager.app_launch_timerfd = -1;
957 LOGW("Unknown socket fd (%d)\n", events[i].data.fd);