4 * Copyright (c) 2000 - 2013 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>
11 * Cherepanov Vitaliy <v.cherepanov@samsung.com>
12 * Nikita Kalyazin <n.kalyazin@samsung.com>
14 * Licensed under the Apache License, Version 2.0 (the "License");
15 * you may not use this file except in compliance with the License.
16 * You may obtain a copy of the License at
18 * http://www.apache.org/licenses/LICENSE-2.0
20 * Unless required by applicable law or agreed to in writing, software
21 * distributed under the License is distributed on an "AS IS" BASIS,
22 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23 * See the License for the specific language governing permissions and
24 * limitations under the License.
28 * - Samsung RnD Institute Russia
31 #define __STDC_FORMAT_MACROS
33 #include <stdlib.h> // for realpath
34 #include <string.h> // for strtok, strcpy, strncpy
35 #include <limits.h> // for realpath
38 #include <errno.h> // for errno
39 #include <sys/types.h> // for accept, mkdir, opendir, readdir
40 #include <sys/socket.h> // for accept
41 #include <sys/stat.h> // for mkdir
42 #include <sys/eventfd.h> // for eventfd
43 #include <sys/timerfd.h> // for timerfd
44 #include <unistd.h> // for access, sleep
58 #include "da_protocol.h"
61 #include "input_events.h"
65 #define DA_WORK_DIR "/home/developer/sdk_tools/da/"
66 #define DA_READELF_PATH "/home/developer/sdk_tools/da/readelf"
67 #define SCREENSHOT_DIR "/tmp/da"
69 #define MAX_APP_LAUNCH_TIME 60
70 #define MAX_CONNECT_TIMEOUT_TIME 5*60
73 // =============================================================================
74 // start and terminate control functions
75 // =============================================================================
77 static Ecore_Fd_Handler *launch_timer_handler;
79 //stop application launch timer
80 static int stop_app_launch_timer()
82 close(manager.app_launch_timerfd);
83 manager.app_launch_timerfd = -1;
88 static Eina_Bool launch_timer_cb(void *data, Ecore_Fd_Handler *fd_handler)
90 LOGE("Failed to launch application\n");
91 if (stop_app_launch_timer() < 0)
92 LOGE("cannot stop app launch timer\n");
94 return ECORE_CALLBACK_CANCEL;
97 //start application launch timer function
98 static int start_app_launch_timer(int apps_count)
102 assert(apps_count >= 0 && "negative apps count");
107 manager.app_launch_timerfd =
108 timerfd_create(CLOCK_REALTIME, TFD_CLOEXEC);
109 if (manager.app_launch_timerfd > 0) {
110 struct itimerspec ctime;
111 ctime.it_value.tv_sec = MAX_APP_LAUNCH_TIME * apps_count;
112 ctime.it_value.tv_nsec = 0;
113 ctime.it_interval.tv_sec = 0;
114 ctime.it_interval.tv_nsec = 0;
115 if (timerfd_settime(manager.app_launch_timerfd, 0, &ctime, NULL) < 0) {
116 LOGE("fail to set app launch timer\n");
117 stop_app_launch_timer();
120 launch_timer_handler =
121 ecore_main_fd_handler_add(manager.app_launch_timerfd,
126 if (!launch_timer_handler) {
127 LOGE("fail to add app launch timer fd to \n");
128 stop_app_launch_timer();
131 LOGI("application launch time started\n");
135 LOGE("cannot create launch timer\n");
142 static inline void inc_apps_to_run()
144 manager.apps_to_run++;
147 static inline void dec_apps_to_run()
149 if (manager.apps_to_run > 0)
150 manager.apps_to_run--;
153 static inline int get_apps_to_run()
155 return manager.apps_to_run;
158 static int kill_app_by_info(const struct app_info_t *app_info)
162 if (app_info == NULL) {
163 LOGE("Cannot exec app. app_info is NULL");
167 switch (app_info->app_type) {
169 res = kill_app(app_info->exe_path);
171 case APP_TYPE_RUNNING:
172 // TODO: nothing, it's running
173 LOGI("already started\n");
175 case APP_TYPE_COMMON:
176 res = kill_app(app_info->exe_path);
179 /* do nothing (it is restarted by itself) */
182 LOGE("Unknown app type %d\n", app_info->app_type);
190 static int exec_app(const struct app_info_t *app_info)
194 if (app_info == NULL) {
195 LOGE("Cannot exec app. app_info is NULL");
199 switch (app_info->app_type) {
201 if (exec_app_tizen(app_info->app_id, app_info->exe_path)) {
202 LOGE("Cannot exec tizen app %s\n", app_info->app_id);
208 case APP_TYPE_RUNNING:
209 // TODO: nothing, it's running
210 LOGI("already started\n");
212 case APP_TYPE_COMMON:
213 if (exec_app_common(app_info->exe_path)) {
214 LOGE("Cannot exec common app %s\n", app_info->exe_path);
221 if (exec_app_web(app_info->app_id)) {
222 LOGE("Cannot exec web app %s\n", app_info->app_id);
227 LOGE("Unknown app type %d\n", app_info->app_type);
232 LOGI("ret=%d\n", res);
236 // just send stop message to all target process
237 static void terminate_all_target()
239 struct msg_target_t msg = {
244 target_send_msg_to_all(&msg);
247 // terminate all target and wait for threads
250 terminate_all_target();
252 // wait for all other thread exit
256 // terminate all profiling by critical error
257 // TODO: don't send data to host
258 static void terminate_error(char *errstr, int send_to_host)
260 LOGE("termination all with err '%s'\n", errstr);
261 struct msg_data_t *msg = NULL;
262 if (send_to_host != 0) {
263 msg = gen_message_error(errstr);
265 if (write_to_buf(msg) != 0)
266 LOGE("write to buf fail\n");
269 LOGI("cannot generate error message\n");
275 static Ecore_Fd_Handler *connect_timer_handler;
277 static Eina_Bool connect_timer_cb(void *data, Ecore_Fd_Handler *fd_handler)
279 terminate_error("no incoming connections", 1);
280 close(manager.connect_timeout_timerfd);
281 manager.connect_timeout_timerfd = -1;
282 LOGE("No connection in %d sec. shutdown.\n",
283 MAX_CONNECT_TIMEOUT_TIME);
284 ecore_main_loop_quit();
286 return ECORE_CALLBACK_CANCEL;
289 static int launch_timer_start(void)
293 manager.connect_timeout_timerfd =
294 timerfd_create(CLOCK_REALTIME, TFD_CLOEXEC);
295 if (manager.connect_timeout_timerfd > 0) {
296 struct itimerspec ctime;
297 ctime.it_value.tv_sec = MAX_CONNECT_TIMEOUT_TIME;
298 ctime.it_value.tv_nsec = 0;
299 ctime.it_interval.tv_sec = 0;
300 ctime.it_interval.tv_nsec = 0;
301 if (timerfd_settime(manager.connect_timeout_timerfd, 0, &ctime, NULL) < 0) {
302 LOGE("fail to set connect timeout timer\n");
303 close(manager.connect_timeout_timerfd);
304 manager.connect_timeout_timerfd = -1;
306 connect_timer_handler =
307 ecore_main_fd_handler_add(manager.connect_timeout_timerfd,
312 if (!connect_timer_handler) {
313 LOGE("fail to add app connection timeout timer fd\n");
314 close(manager.connect_timeout_timerfd);
315 manager.connect_timeout_timerfd = -1;
317 LOGI("connection timeout timer started\n");
321 LOGE("cannot create connection timeout timer\n");
324 LOGI("ret=%d\n", res);
328 int prepare_profiling(void)
330 struct app_list_t *app = NULL;
331 const struct app_info_t *app_info = NULL;
333 app_info = app_info_get_first(&app);
334 if (app_info == NULL) {
335 LOGE("No app info found\n");
340 while (app_info != NULL) {
341 if (kill_app_by_info(app_info) != 0) {
342 LOGE("kill app failed\n");
345 app_info = app_info_get_next(&app);
347 //init rw for systeminfo
348 //init recv send network systeminfo
354 int start_profiling(void)
356 struct app_list_t *app = NULL;
357 const struct app_info_t *app_info = NULL;
360 app_info = app_info_get_first(&app);
361 if (app_info == NULL) {
362 LOGE("No app info found\n");
365 // remove previous screen capture files
366 remove_indir(SCREENSHOT_DIR);
367 if (mkdir(SCREENSHOT_DIR, 0777) == -1 && errno != EEXIST)
368 LOGW("Failed to create directory for screenshot : %s\n",
371 set_label_for_all(SCREENSHOT_DIR);
373 if (samplingStart() < 0) {
374 LOGE("Cannot start sampling\n");
379 if (IS_OPT_SET(FL_RECORDING))
382 while (app_info != NULL) {
383 if (exec_app(app_info)) {
384 LOGE("Cannot exec app\n");
388 app_info = app_info_get_next(&app);
391 if (start_app_launch_timer(get_apps_to_run()) < 0) {
399 if (IS_OPT_SET(FL_RECORDING))
404 LOGI("return %d\n", res);
408 void stop_profiling(void)
410 if (IS_OPT_SET(FL_RECORDING))
415 static void reconfigure_recording(struct conf_t conf)
417 uint64_t old_features = prof_session.conf.use_features0;
418 uint64_t new_features = conf.use_features0;
419 uint64_t to_enable = (new_features ^ old_features) & new_features;
420 uint64_t to_disable = (new_features ^ old_features) & old_features;
422 if (IS_OPT_SET_IN(FL_RECORDING, to_disable)) {
424 prof_session.conf.use_features0 &= ~FL_RECORDING;
427 if (IS_OPT_SET_IN(FL_RECORDING, to_enable)) {
429 prof_session.conf.use_features0 |= FL_RECORDING;
434 int reconfigure(struct conf_t conf)
436 reconfigure_recording(conf);
439 memcpy(&prof_session.conf, &conf, sizeof(conf));
440 if (samplingStart() < 0) {
441 LOGE("Cannot start sampling\n");
449 static int file2str(const char *filename, char *buf, int len)
453 fd = open(filename, O_RDONLY, 0);
457 num_read = read(fd, buf, len - 1);
464 buf[num_read] = '\0';
469 static pid_t get_lpad_pid(pid_t pid)
471 static pid_t lpad_pid = UNKNOWN_PID;
472 static const char lpad_path[] = DEBUG_LAUNCH_PRELOAD_PATH;
473 enum { lpad_path_len = sizeof(lpad_path) };
475 if (lpad_pid == UNKNOWN_PID) {
477 char buf[lpad_path_len];
479 sprintf(fname, "/proc/%d/cmdline", pid);
480 if (-1 == file2str(fname, buf, lpad_path_len))
483 buf[lpad_path_len - 1] = '\0';
485 if (strncmp(buf, lpad_path, lpad_path_len - 1) == 0)
492 static pid_t get_current_pid(void)
494 static pid_t pid = UNKNOWN_PID;
496 if (pid == UNKNOWN_PID)
502 static void target_set_type(struct target *t)
504 pid_t ppid = target_get_ppid(t);
506 if (get_current_pid() == ppid) {
507 t->app_type = APP_TYPE_COMMON;
508 } else if (get_lpad_pid(ppid) == ppid) {
509 t->app_type = APP_TYPE_TIZEN;
514 static int target_event_pid_handler(struct target *target)
516 struct app_list_t *app = NULL;
517 struct app_info_t *app_info = NULL;
519 target_set_type(target);
521 if (0) { // main application (index == 0)
522 app_info = app_info_get_first(&app);
523 if (app_info == NULL) {
524 LOGE("No app info found\n");
528 while (app_info != NULL) {
529 if (is_same_app_process(app_info->exe_path,
530 target_get_pid(target)))
532 app_info = app_info_get_next(&app);
535 if (app_info == NULL) {
536 LOGE("pid %d not found in app list\n",
537 target_get_pid(target));
541 if (start_replay() != 0) {
542 LOGE("Cannot start replay thread\n");
547 target->initial_log = 1;
552 static int target_event_stop_handler(struct target *target)
555 enum app_type_t app_type = target->app_type;
557 LOGI("target[%p] close, pid(%d) : (remaining %d target)\n",
558 target, target_get_pid(target), target_cnt_get() - 1);
560 if (0) // main application (index == 0)
563 ecore_main_fd_handler_del(target->handler);
566 // all target client are closed
567 cnt = target_cnt_sub_and_fetch();
571 case APP_TYPE_COMMON:
572 LOGI("all targets are stopped\n");
573 if (stop_all() != ERR_NO)
574 LOGE("Stop failed\n");
582 // return 0 if normal case
583 // return plus value if non critical error occur
584 // return minus value if critical error occur
585 // return -11 if all target process closed
586 static int target_event_handler(struct target *t, uint64_t msg)
590 err = target_event_pid_handler(t);
594 if (msg & EVENT_STOP || msg & EVENT_ERROR)
595 err = target_event_stop_handler(t);
600 static Eina_Bool target_event_cb(void *data, Ecore_Fd_Handler *fd_handler)
604 struct target *target = (struct target *)data;
606 recvLen = read(target->event_fd, &u, sizeof(uint64_t));
607 if (recvLen != sizeof(uint64_t)) {
608 // maybe closed, but ignoring is more safe then
609 // removing fd from event loop
611 if (-11 == target_event_handler(target, u)) {
612 LOGI("all target process is closed\n");
616 return ECORE_CALLBACK_RENEW;
620 * return 0 if normal case
621 * return plus value if non critical error occur
622 * return minus value if critical error occur
624 static int targetServerHandler(void)
627 struct msg_target_t log;
628 struct target *target;
630 target = target_ctor();
631 if (target == NULL) {
632 LOGW("(target == NULL) no more target can connected\n");
636 err = target_accept(target, manager.target_server_socket);
638 /* send config message to target process */
639 log.type = MSG_OPTION;
640 log.length = sprintf(log.data, "%llu\0",
641 prof_session.conf.use_features0) + 1;
642 if (target_send_msg(target, &log) != 0)
643 LOGE("fail to send data to target %p\n", target);
645 /* send current instrument maps */
646 send_maps_inst_msg_to(target);
649 target->event_fd = eventfd(EFD_CLOEXEC, EFD_NONBLOCK);
650 if (target->event_fd == -1) {
651 // fail to make event fd
652 LOGE("fail to make event fd for target[%p]\n", target);
653 goto TARGET_CONNECT_FAIL;
657 ecore_main_fd_handler_add(target->event_fd,
662 if (!target->handler) {
663 LOGE("fail to add event fd for target[%p]\n", target);
664 goto TARGET_CONNECT_FAIL;
667 // make recv thread for target
668 if (makeRecvThread(target) != 0) {
669 // fail to make recv thread
670 LOGE("fail to make recv thread for target[%p]\n",
672 ecore_main_fd_handler_del(target->handler);
673 goto TARGET_CONNECT_FAIL;
678 if ((manager.app_launch_timerfd > 0) && (get_apps_to_run() == 0)) {
679 if (stop_app_launch_timer() < 0)
680 LOGE("cannot stop app launch timer\n");
683 LOGI("target connected target[%p](running %d target)\n",
684 target, target_cnt_get() + 1);
686 target_cnt_set(target_cnt_get() + 1);
690 LOGE("Failed to accept at target server socket\n");
694 if (target_cnt_get() == 0) {
695 // if this connection is main connection
698 // if this connection is not main connection then ignore process by error
704 static Ecore_Fd_Handler *host_ctrl_handler;
705 static Ecore_Fd_Handler *host_data_handler;
707 // return plus value if non critical error occur
708 // return minus value if critical error occur
709 // return -11 if socket closed
710 static int controlSocketHandler(int efd)
713 struct msg_t msg_head;
717 if (manager.connect_timeout_timerfd >= 0) {
718 LOGI("release connect timeout timer\n");
719 close(manager.connect_timeout_timerfd);
720 manager.connect_timeout_timerfd = -1;
723 recv_len = recv(manager.host.control_socket,
724 &msg_head, MSG_CMD_HDR_LEN, 0);
725 // error or close request from host
726 if (recv_len == -1 || recv_len == 0)
729 if (msg_head.len > RECV_BUF_MAX)
731 msg = malloc(MSG_CMD_HDR_LEN + msg_head.len);
733 LOGE("Cannot alloc msg\n");
734 sendACKToHost(msg_head.id, ERR_WRONG_MESSAGE_FORMAT, 0, 0);
737 msg->id = msg_head.id;
738 msg->len = msg_head.len;
740 // Receive payload (if exists)
741 recv_len = recv(manager.host.control_socket,
742 msg->payload, msg->len, MSG_WAITALL);
743 if (recv_len == -1) {
748 printBuf((char *)msg, MSG_CMD_HDR_LEN + msg->len);
749 res = host_message_handler(msg);
756 static Eina_Bool host_ctrl_cb(void *data, Ecore_Fd_Handler *fd_handler)
758 int result = controlSocketHandler(manager.efd);
761 //if the host disconnected.
762 //In all other cases daemon must report an error and continue the loop
763 //close connect_timeoutt and host socket and quit
764 LOGI("Connection closed. Termination. (%d)\n",
765 manager.host.control_socket);
766 manager.host.data_socket = -1; //splice will fail without that
767 ecore_main_loop_quit();
768 } else if (result < 0) {
769 LOGE("Control socket handler.\n");
772 return ECORE_CALLBACK_RENEW;
775 static Eina_Bool host_data_cb(void *data, Ecore_Fd_Handler *fd_handler)
780 recvLen = recv(manager.host.data_socket, recvBuf, 32, MSG_DONTWAIT);
783 ecore_main_fd_handler_del(host_data_handler);
784 close(manager.host.data_socket);
785 manager.host.data_socket = -1;
786 // TODO: finish transfer thread
789 LOGI("host message from data socket %d\n", recvLen);
791 return ECORE_CALLBACK_RENEW;
794 // return 0 if normal case
795 // return plus value if non critical error occur
796 // return minus value if critical error occur
797 static int hostServerHandler(void)
799 static int hostserverorder = 0;
802 if (hostserverorder > 1) // control and data socket connected already
805 csocket = accept4(manager.host_server_socket, NULL, NULL, SOCK_CLOEXEC);
810 if (hostserverorder == 0) {
811 manager.host.control_socket = csocket;
813 LOGI("host control socket connected = %d\n", csocket);
815 ecore_main_fd_handler_add(manager.host.control_socket,
820 if (!host_ctrl_handler) {
821 LOGE("Failed to add host control socket fd\n");
826 manager.host.data_socket = csocket;
827 LOGI("host data socket connected = %d\n", csocket);
830 ecore_main_fd_handler_add(manager.host.data_socket,
835 if (!host_data_handler) {
836 LOGE("Failed to add host data socket fd\n");
846 LOGE("Failed to accept from host server socket\n");
851 static Ecore_Fd_Handler *host_connect_handler;
852 static Ecore_Fd_Handler *target_connect_handler;
854 static Eina_Bool host_connect_cb(void *data, Ecore_Fd_Handler *fd_handler)
856 // connect request from host
857 int result = hostServerHandler();
859 LOGE("Internal DA framework error (hostServerHandler)\n");
862 return ECORE_CALLBACK_RENEW;
865 static Eina_Bool target_connect_cb(void *data, Ecore_Fd_Handler *fd_handler)
867 if (targetServerHandler() < 0) {
869 terminate_error("Internal DA framework error, "
870 "Please re-run the profiling "
871 "(targetServerHandler)\n", 1);
874 return ECORE_CALLBACK_RENEW;
877 static bool initialize_events(void)
879 host_connect_handler =
880 ecore_main_fd_handler_add(manager.host_server_socket,
885 if (!host_connect_handler) {
886 LOGE("Host server socket add error\n");
890 target_connect_handler =
891 ecore_main_fd_handler_add(manager.target_server_socket,
896 if (!target_connect_handler) {
897 LOGE("Target server socket add error\n");
904 // return 0 for normal case
907 int return_value = 0;
911 if (init_input_events() == -1) {
916 if (!initialize_events()) {
921 if (launch_timer_start() < 0) {
922 LOGE("Launch timer start failed\n");
927 init_prof_session(&prof_session);
929 ecore_main_loop_begin();