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;
78 static pthread_mutex_t launch_timer_mutex = PTHREAD_MUTEX_INITIALIZER;
80 static void launch_timer_lock()
82 LOGI("lock launch_timer_mutex\n");
83 pthread_mutex_lock(&launch_timer_mutex);
84 LOGI("locked launch_timer_mutex\n");
87 static void launch_timer_unlock()
89 pthread_mutex_unlock(&launch_timer_mutex);
90 LOGI("unlock launch_timer_mutex\n");
93 //stop application launch timer
94 static int stop_app_launch_timer()
99 if (manager.app_launch_timerfd > 0) {
100 ecore_main_fd_handler_del(launch_timer_handler);
101 if (close(manager.app_launch_timerfd)) {
102 LOGE("close app_launch_timerfd failed\n");
105 manager.app_launch_timerfd = -1;
107 LOGW("trying to stop app launch timer when it stoped\n");
110 launch_timer_unlock();
114 static Eina_Bool launch_timer_cb(void *data, Ecore_Fd_Handler *fd_handler)
116 LOGE("Failed to launch application\n");
117 if (stop_app_launch_timer())
118 LOGE("cannot stop app launch timer\n");
120 return ECORE_CALLBACK_CANCEL;
123 //start application launch timer function
124 static int start_app_launch_timer(int apps_count)
128 assert(apps_count >= 0 && "negative apps count");
133 if (manager.app_launch_timerfd > 0) {
134 LOGI("stop previous app launch timer\n");
135 stop_app_launch_timer();
140 manager.app_launch_timerfd =
141 timerfd_create(CLOCK_REALTIME, TFD_CLOEXEC);
142 if (manager.app_launch_timerfd > 0) {
143 struct itimerspec ctime;
144 ctime.it_value.tv_sec = MAX_APP_LAUNCH_TIME * apps_count;
145 ctime.it_value.tv_nsec = 0;
146 ctime.it_interval.tv_sec = 0;
147 ctime.it_interval.tv_nsec = 0;
148 if (timerfd_settime(manager.app_launch_timerfd, 0, &ctime, NULL) < 0) {
149 LOGE("fail to set app launch timer\n");
151 goto unlock_and_stop;
153 launch_timer_handler =
154 ecore_main_fd_handler_add(manager.app_launch_timerfd,
159 if (!launch_timer_handler) {
160 LOGE("fail to add app launch timer fd to \n");
162 goto unlock_and_stop;
164 LOGI("application launch time started\n");
168 LOGE("cannot create launch timer\n");
172 launch_timer_unlock();
176 launch_timer_unlock();
178 stop_app_launch_timer();
182 static inline void inc_apps_to_run()
184 manager.apps_to_run++;
187 static inline void dec_apps_to_run()
189 if (manager.apps_to_run > 0)
190 manager.apps_to_run--;
193 static inline int get_apps_to_run()
195 return manager.apps_to_run;
198 static int kill_app_by_info(const struct app_info_t *app_info)
202 if (app_info == NULL) {
203 LOGE("Cannot exec app. app_info is NULL");
207 switch (app_info->app_type) {
209 res = kill_app(app_info->exe_path);
211 case APP_TYPE_RUNNING:
212 // TODO: nothing, it's running
213 LOGI("already started\n");
215 case APP_TYPE_COMMON:
216 res = kill_app(app_info->exe_path);
219 /* do nothing (it is restarted by itself) */
222 LOGE("Unknown app type %d\n", app_info->app_type);
230 static int exec_app(const struct app_info_t *app_info)
234 if (app_info == NULL) {
235 LOGE("Cannot exec app. app_info is NULL");
239 switch (app_info->app_type) {
241 if (exec_app_tizen(app_info->app_id, app_info->exe_path)) {
242 LOGE("Cannot exec tizen app %s\n", app_info->app_id);
248 case APP_TYPE_RUNNING:
249 // TODO: nothing, it's running
250 LOGI("already started\n");
252 case APP_TYPE_COMMON:
253 if (exec_app_common(app_info->exe_path)) {
254 LOGE("Cannot exec common app %s\n", app_info->exe_path);
261 if (exec_app_web(app_info->app_id)) {
262 LOGE("Cannot exec web app %s\n", app_info->app_id);
267 LOGE("Unknown app type %d\n", app_info->app_type);
272 LOGI("ret=%d\n", res);
276 // just send stop message to all target process
277 static void terminate_all_target()
279 struct msg_target_t msg = {
284 target_send_msg_to_all(&msg);
287 // terminate all target and wait for threads
290 terminate_all_target();
292 // wait for all other thread exit
296 // terminate all profiling by critical error
297 // TODO: don't send data to host
298 static void terminate_error(char *errstr, int send_to_host)
300 LOGE("termination all with err '%s'\n", errstr);
301 struct msg_data_t *msg = NULL;
302 if (send_to_host != 0) {
303 msg = gen_message_error(errstr);
305 if (write_to_buf(msg) != 0)
306 LOGE("write to buf fail\n");
309 LOGI("cannot generate error message\n");
315 static Ecore_Fd_Handler *connect_timer_handler;
317 static Eina_Bool connect_timer_cb(void *data, Ecore_Fd_Handler *fd_handler)
319 terminate_error("no incoming connections", 1);
320 close(manager.connect_timeout_timerfd);
321 manager.connect_timeout_timerfd = -1;
322 LOGE("No connection in %d sec. shutdown.\n",
323 MAX_CONNECT_TIMEOUT_TIME);
324 ecore_main_loop_quit();
326 return ECORE_CALLBACK_CANCEL;
329 static int launch_timer_start(void)
333 manager.connect_timeout_timerfd =
334 timerfd_create(CLOCK_REALTIME, TFD_CLOEXEC);
335 if (manager.connect_timeout_timerfd > 0) {
336 struct itimerspec ctime;
337 ctime.it_value.tv_sec = MAX_CONNECT_TIMEOUT_TIME;
338 ctime.it_value.tv_nsec = 0;
339 ctime.it_interval.tv_sec = 0;
340 ctime.it_interval.tv_nsec = 0;
341 if (timerfd_settime(manager.connect_timeout_timerfd, 0, &ctime, NULL) < 0) {
342 LOGE("fail to set connect timeout timer\n");
343 close(manager.connect_timeout_timerfd);
344 manager.connect_timeout_timerfd = -1;
346 connect_timer_handler =
347 ecore_main_fd_handler_add(manager.connect_timeout_timerfd,
352 if (!connect_timer_handler) {
353 LOGE("fail to add app connection timeout timer fd\n");
354 close(manager.connect_timeout_timerfd);
355 manager.connect_timeout_timerfd = -1;
357 LOGI("connection timeout timer started\n");
361 LOGE("cannot create connection timeout timer\n");
364 LOGI("ret=%d\n", res);
368 int prepare_profiling(void)
370 struct app_list_t *app = NULL;
371 const struct app_info_t *app_info = NULL;
373 app_info = app_info_get_first(&app);
374 if (app_info == NULL) {
375 LOGE("No app info found\n");
380 while (app_info != NULL) {
381 if (kill_app_by_info(app_info) != 0) {
382 LOGE("kill app failed\n");
385 app_info = app_info_get_next(&app);
387 //init rw for systeminfo
388 //init recv send network systeminfo
394 int start_profiling(void)
396 struct app_list_t *app = NULL;
397 const struct app_info_t *app_info = NULL;
400 app_info = app_info_get_first(&app);
401 if (app_info == NULL) {
402 LOGE("No app info found\n");
405 // remove previous screen capture files
406 remove_indir(SCREENSHOT_DIR);
407 if (mkdir(SCREENSHOT_DIR, 0777) == -1 && errno != EEXIST) {
408 GETSTRERROR(errno, buf);
409 LOGW("Failed to create directory for screenshot : %s\n", buf);
412 set_label_for_all(SCREENSHOT_DIR);
414 if (samplingStart() < 0) {
415 LOGE("Cannot start sampling\n");
420 if (IS_OPT_SET(FL_RECORDING))
423 while (app_info != NULL) {
424 if (exec_app(app_info)) {
425 LOGE("Cannot exec app\n");
429 app_info = app_info_get_next(&app);
432 if (start_app_launch_timer(get_apps_to_run()) < 0) {
440 if (IS_OPT_SET(FL_RECORDING))
445 LOGI("return %d\n", res);
449 void stop_profiling(void)
451 if (IS_OPT_SET(FL_RECORDING))
456 static void reconfigure_recording(struct conf_t conf)
458 uint64_t old_features = prof_session.conf.use_features0;
459 uint64_t new_features = conf.use_features0;
460 uint64_t to_enable = (new_features ^ old_features) & new_features;
461 uint64_t to_disable = (new_features ^ old_features) & old_features;
463 if (IS_OPT_SET_IN(FL_RECORDING, to_disable)) {
465 prof_session.conf.use_features0 &= ~FL_RECORDING;
468 if (IS_OPT_SET_IN(FL_RECORDING, to_enable)) {
470 prof_session.conf.use_features0 |= FL_RECORDING;
475 int reconfigure(struct conf_t conf)
477 reconfigure_recording(conf);
480 memcpy(&prof_session.conf, &conf, sizeof(conf));
481 if (samplingStart() < 0) {
482 LOGE("Cannot start sampling\n");
490 static int file2str(const char *filename, char *buf, int len)
494 fd = open(filename, O_RDONLY, 0);
498 num_read = read(fd, buf, len - 1);
505 buf[num_read] = '\0';
510 static pid_t get_lpad_pid(pid_t pid)
512 static pid_t lpad_pid = UNKNOWN_PID;
513 static const char lpad_path[] = DEBUG_LAUNCH_PRELOAD_PATH;
514 enum { lpad_path_len = sizeof(lpad_path) };
516 if (lpad_pid == UNKNOWN_PID) {
518 char buf[lpad_path_len];
520 snprintf(fname, sizeof(fname), "/proc/%d/cmdline", pid);
521 if (-1 == file2str(fname, buf, lpad_path_len))
524 buf[lpad_path_len - 1] = '\0';
526 if (strncmp(buf, lpad_path, lpad_path_len - 1) == 0)
533 static pid_t get_current_pid(void)
535 static pid_t pid = UNKNOWN_PID;
537 if (pid == UNKNOWN_PID)
543 static void target_set_type(struct target *t)
545 pid_t ppid = target_get_ppid(t);
546 enum app_type_t app_type = APP_TYPE_UNKNOWN;
548 if (get_current_pid() == ppid) {
549 app_type = APP_TYPE_COMMON;
550 } else if (get_lpad_pid(ppid) == ppid) {
551 app_type = APP_TYPE_TIZEN;
554 t->app_type = app_type;
558 static int target_event_pid_handler(struct target *target)
560 struct app_list_t *app = NULL;
561 struct app_info_t *app_info = NULL;
563 target_set_type(target);
565 /* posible need some process check right there before start_replay >> */
566 app_info = app_info_get_first(&app);
567 if (app_info == NULL) {
568 LOGE("No app info found\n");
572 while (app_info != NULL) {
573 if (is_same_app_process(app_info->exe_path,
574 target_get_pid(target)))
576 app_info = app_info_get_next(&app);
579 if (app_info == NULL) {
580 LOGE("pid %d not found in app list\n",
581 target_get_pid(target));
585 if (start_replay() != 0) {
586 LOGE("Cannot start replay thread\n");
589 /* posible need some process check right there before start_replay << */
591 target->initial_log = 1;
596 static int target_event_stop_handler(struct target *target)
599 enum app_type_t app_type = target->app_type;
601 LOGI("target[%p] close, pid(%d) : (remaining %d target)\n",
602 target, target_get_pid(target), target_cnt_get() - 1);
604 ecore_main_fd_handler_del(target->handler);
608 // all target client are closed
609 cnt = target_cnt_sub_and_fetch();
613 case APP_TYPE_COMMON:
614 LOGI("all targets are stopped\n");
615 if (stop_all() != ERR_NO)
616 LOGE("Stop failed\n");
624 // return 0 if normal case
625 // return plus value if non critical error occur
626 // return minus value if critical error occur
627 // return -11 if all target process closed
628 static int target_event_handler(struct target *t, uint64_t msg)
632 err = target_event_pid_handler(t);
636 if (msg & EVENT_STOP || msg & EVENT_ERROR)
637 err = target_event_stop_handler(t);
642 static Eina_Bool target_event_cb(void *data, Ecore_Fd_Handler *fd_handler)
646 struct target *target = (struct target *)data;
648 recvLen = read(target->event_fd, &u, sizeof(uint64_t));
649 if (recvLen != sizeof(uint64_t)) {
650 // maybe closed, but ignoring is more safe then
651 // removing fd from event loop
653 if (-11 == target_event_handler(target, u)) {
654 LOGI("all target process is closed\n");
658 return ECORE_CALLBACK_RENEW;
662 * return 0 if normal case
663 * return plus value if non critical error occur
664 * return minus value if critical error occur
666 static int targetServerHandler(void)
669 struct msg_target_t log;
670 struct target *target;
672 target = target_ctor();
673 if (target == NULL) {
674 LOGW("(target == NULL) no more target can connected\n");
678 err = target_accept(target, manager.target_server_socket);
680 /* send config message to target process */
681 log.type = MSG_OPTION;
682 log.length = snprintf(log.data, sizeof(log.data), "%llu",
683 prof_session.conf.use_features0) + 1;
684 if (target_send_msg(target, &log) != 0)
685 LOGE("fail to send data to target %p\n", target);
687 /* send current instrument maps */
688 send_maps_inst_msg_to(target);
691 target->event_fd = eventfd(EFD_CLOEXEC, EFD_NONBLOCK);
692 if (target->event_fd == -1) {
693 // fail to make event fd
694 LOGE("fail to make event fd for target[%p]\n", target);
695 goto TARGET_CONNECT_FAIL;
699 ecore_main_fd_handler_add(target->event_fd,
704 if (!target->handler) {
705 LOGE("fail to add event fd for target[%p]\n", target);
706 goto TARGET_CONNECT_FAIL;
709 // make recv thread for target
710 if (makeRecvThread(target) != 0) {
711 // fail to make recv thread
712 LOGE("fail to make recv thread for target[%p]\n",
714 ecore_main_fd_handler_del(target->handler);
715 goto TARGET_CONNECT_FAIL;
720 if ((manager.app_launch_timerfd > 0) && (get_apps_to_run() == 0)) {
721 if (stop_app_launch_timer())
722 LOGE("cannot stop app launch timer\n");
725 LOGI("target connected target[%p](running %d target)\n",
726 target, target_cnt_get() + 1);
728 target_cnt_set(target_cnt_get() + 1);
732 LOGE("Failed to accept at target server socket\n");
736 if (target_cnt_get() == 0) {
737 // if this connection is main connection
740 // if this connection is not main connection then ignore process by error
746 static void recv_msg_tail(int fd, uint32_t len)
752 for (blocks = len / sizeof(buf); blocks != 0; blocks--) {
753 recv_len = recv(fd, buf, sizeof(buf), MSG_WAITALL);
754 if (recv_len != sizeof(buf))
758 len = len % sizeof(buf);
760 recv_len = recv(fd, buf, len, MSG_WAITALL);
768 LOGE("error or close request from host. recv_len = %d\n",
773 static Ecore_Fd_Handler *host_ctrl_handler;
774 static Ecore_Fd_Handler *host_data_handler;
776 // return plus value if non critical error occur
777 // return minus value if critical error occur
778 // return -11 if socket closed
779 static int controlSocketHandler(int efd)
782 struct msg_t msg_head;
786 if (manager.connect_timeout_timerfd >= 0) {
787 LOGI("release connect timeout timer\n");
788 close(manager.connect_timeout_timerfd);
789 manager.connect_timeout_timerfd = -1;
792 recv_len = recv(manager.host.control_socket,
793 &msg_head, MSG_CMD_HDR_LEN, 0);
795 // error or close request from host
796 if (recv_len == -1 || recv_len == 0) {
797 LOGW("error or close request from host. "
798 "MSG_ID = 0x%08X; recv_len = %d\n",
799 msg_head.id, recv_len);
802 if (msg_head.len > HOST_CTL_MSG_MAX_LEN) {
803 LOGE("Too long message. size = %u\n", msg_head.len);
804 recv_msg_tail(manager.host.control_socket, msg_head.len);
805 sendACKToHost(msg_head.id, ERR_WRONG_MESSAGE_FORMAT, 0, 0);
808 msg = malloc(MSG_CMD_HDR_LEN + msg_head.len);
810 LOGE("Cannot alloc msg\n");
811 recv_msg_tail(manager.host.control_socket, msg_head.len);
812 sendACKToHost(msg_head.id, ERR_WRONG_MESSAGE_FORMAT, 0, 0);
815 msg->id = msg_head.id;
816 msg->len = msg_head.len;
818 // Receive payload (if exists)
819 recv_len = recv(manager.host.control_socket,
820 msg->payload, msg->len, MSG_WAITALL);
821 if (recv_len == -1) {
822 LOGE("error or close request from host. recv_len = %d\n",
828 printBuf((char *)msg, MSG_CMD_HDR_LEN + msg->len);
829 res = host_message_handler(msg);
836 static Eina_Bool host_ctrl_cb(void *data, Ecore_Fd_Handler *fd_handler)
838 int result = controlSocketHandler(manager.efd);
841 //if the host disconnected.
842 //In all other cases daemon must report an error and continue the loop
843 //close connect_timeoutt and host socket and quit
844 LOGI("Connection closed. Termination. (%d)\n",
845 manager.host.control_socket);
846 manager.host.data_socket = -1; //splice will fail without that
847 ecore_main_loop_quit();
848 } else if (result < 0) {
849 LOGE("Control socket handler. err #%d\n", result);
852 return ECORE_CALLBACK_RENEW;
855 static Eina_Bool host_data_cb(void *data, Ecore_Fd_Handler *fd_handler)
860 recvLen = recv(manager.host.data_socket, recvBuf, 32, MSG_DONTWAIT);
863 ecore_main_fd_handler_del(host_data_handler);
864 close(manager.host.data_socket);
865 manager.host.data_socket = -1;
866 // TODO: finish transfer thread
869 LOGI("host message from data socket %d\n", recvLen);
871 return ECORE_CALLBACK_RENEW;
874 // return 0 if normal case
875 // return plus value if non critical error occur
876 // return minus value if critical error occur
877 static int hostServerHandler(void)
879 static int hostserverorder = 0;
882 if (hostserverorder > 1) // control and data socket connected already
885 csocket = accept4(manager.host_server_socket, NULL, NULL, SOCK_CLOEXEC);
890 if (hostserverorder == 0) {
891 manager.host.control_socket = csocket;
893 LOGI("host control socket connected = %d\n", csocket);
895 ecore_main_fd_handler_add(manager.host.control_socket,
900 if (!host_ctrl_handler) {
901 LOGE("Failed to add host control socket fd\n");
906 manager.host.data_socket = csocket;
907 LOGI("host data socket connected = %d\n", csocket);
910 ecore_main_fd_handler_add(manager.host.data_socket,
915 if (!host_data_handler) {
916 LOGE("Failed to add host data socket fd\n");
926 LOGE("Failed to accept from host server socket\n");
931 static Ecore_Fd_Handler *host_connect_handler;
932 static Ecore_Fd_Handler *target_connect_handler;
934 static Eina_Bool host_connect_cb(void *data, Ecore_Fd_Handler *fd_handler)
936 // connect request from host
937 int result = hostServerHandler();
939 LOGE("Internal DA framework error (hostServerHandler)\n");
942 return ECORE_CALLBACK_RENEW;
945 static Eina_Bool target_connect_cb(void *data, Ecore_Fd_Handler *fd_handler)
947 if (targetServerHandler() < 0) {
949 terminate_error("Internal DA framework error, "
950 "Please re-run the profiling "
951 "(targetServerHandler)\n", 1);
954 return ECORE_CALLBACK_RENEW;
957 static bool initialize_events(void)
959 host_connect_handler =
960 ecore_main_fd_handler_add(manager.host_server_socket,
965 if (!host_connect_handler) {
966 LOGE("Host server socket add error\n");
970 target_connect_handler =
971 ecore_main_fd_handler_add(manager.target_server_socket,
976 if (!target_connect_handler) {
977 LOGE("Target server socket add error\n");
984 // return 0 for normal case
987 int return_value = 0;
991 if (init_input_events() == -1) {
996 if (!initialize_events()) {
1001 if (launch_timer_start() < 0) {
1002 LOGE("Launch timer start failed\n");
1007 init_prof_session(&prof_session);
1009 ecore_main_loop_begin();
1013 LOGI("close efd\n");
1016 return return_value;