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
46 #include <linux/netlink.h>
47 #include <linux/connector.h>
60 #include "da_protocol.h"
63 #include "input_events.h"
65 #include "us_interaction_msg.h"
69 #define DA_WORK_DIR "/home/developer/sdk_tools/da/"
70 #define DA_READELF_PATH "/home/developer/sdk_tools/da/readelf"
71 #define SCREENSHOT_DIR "/tmp/da"
73 #define MAX_APP_LAUNCH_TIME 60
74 #define MAX_CONNECT_TIMEOUT_TIME 5*60
76 uint64_t get_total_alloc_size(void)
79 uint64_t allocsize = 0;
81 for (i = 0; i < MAX_TARGET_COUNT; i++) {
82 if (manager.target[i].socket != -1 &&
83 manager.target[i].allocmem > 0)
84 allocsize += manager.target[i].allocmem;
89 static int getEmptyTargetSlot()
92 for (i = 0; i < MAX_TARGET_COUNT; i++) {
93 if (manager.target[i].socket == -1)
100 static void setEmptyTargetSlot(int index)
102 if (index >= 0 && index < MAX_TARGET_COUNT) {
103 manager.target[index].pid = -1;
104 manager.target[index].recv_thread = -1;
105 manager.target[index].allocmem = 0;
106 manager.target[index].initial_log = 0;
107 if (manager.target[index].event_fd != -1)
108 close(manager.target[index].event_fd);
109 manager.target[index].event_fd = -1;
110 if (manager.target[index].socket != -1)
111 close(manager.target[index].socket);
112 manager.target[index].socket = -1;
116 // =============================================================================
117 // start and terminate control functions
118 // =============================================================================
120 static Ecore_Fd_Handler *launch_timer_handler;
122 //stop application launch timer
123 static int stop_app_launch_timer()
125 close(manager.app_launch_timerfd);
126 manager.app_launch_timerfd = -1;
131 static Eina_Bool launch_timer_cb(void *data, Ecore_Fd_Handler *fd_handler)
133 LOGE("Failed to launch application\n");
134 if (stop_app_launch_timer() < 0)
135 LOGE("cannot stop app launch timer\n");
137 return ECORE_CALLBACK_CANCEL;
140 //start application launch timer function
141 static int start_app_launch_timer(int apps_count)
145 assert(apps_count >= 0 && "negative apps count");
150 manager.app_launch_timerfd =
151 timerfd_create(CLOCK_REALTIME, TFD_CLOEXEC);
152 if (manager.app_launch_timerfd > 0) {
153 struct itimerspec ctime;
154 ctime.it_value.tv_sec = MAX_APP_LAUNCH_TIME * apps_count;
155 ctime.it_value.tv_nsec = 0;
156 ctime.it_interval.tv_sec = 0;
157 ctime.it_interval.tv_nsec = 0;
158 if (timerfd_settime(manager.app_launch_timerfd, 0, &ctime, NULL) < 0) {
159 LOGE("fail to set app launch timer\n");
160 stop_app_launch_timer();
163 launch_timer_handler =
164 ecore_main_fd_handler_add(manager.app_launch_timerfd,
169 if (!launch_timer_handler) {
170 LOGE("fail to add app launch timer fd to \n");
171 stop_app_launch_timer();
174 LOGI("application launch time started\n");
178 LOGE("cannot create launch timer\n");
185 static inline void inc_apps_to_run()
187 manager.apps_to_run++;
190 static inline void dec_apps_to_run()
192 if (manager.apps_to_run > 0)
193 manager.apps_to_run--;
196 static inline int get_apps_to_run()
198 return manager.apps_to_run;
201 static int kill_app_by_info(const struct app_info_t *app_info)
205 if (app_info == NULL) {
206 LOGE("Cannot exec app. app_info is NULL");
210 switch (app_info->app_type) {
212 res = kill_app(app_info->exe_path);
214 case APP_TYPE_RUNNING:
215 // TODO: nothing, it's running
216 LOGI("already started\n");
218 case APP_TYPE_COMMON:
219 res = kill_app(app_info->exe_path);
222 /* do nothing (it is restarted by itself) */
225 LOGE("Unknown app type %d\n", app_info->app_type);
233 static int exec_app(const struct app_info_t *app_info)
237 if (app_info == NULL) {
238 LOGE("Cannot exec app. app_info is NULL");
242 switch (app_info->app_type) {
244 if (exec_app_tizen(app_info->app_id, app_info->exe_path)) {
245 LOGE("Cannot exec tizen app %s\n", app_info->app_id);
251 case APP_TYPE_RUNNING:
252 // TODO: nothing, it's running
253 LOGI("already started\n");
255 case APP_TYPE_COMMON:
256 if (exec_app_common(app_info->exe_path)) {
257 LOGE("Cannot exec common app %s\n", app_info->exe_path);
264 if (exec_app_web(app_info->app_id)) {
265 LOGE("Cannot exec web app %s\n", app_info->app_id);
270 LOGE("Unknown app type %d\n", app_info->app_type);
275 LOGI("ret=%d\n", res);
279 // just send stop message to all target process
280 static void terminate_all_target()
284 msg_target_t sendlog;
286 sendlog.type = MSG_STOP;
289 for (i = 0; i < MAX_TARGET_COUNT; i++) {
290 if (manager.target[i].socket != -1) {
291 sendlen = send(manager.target[i].socket, &sendlog,
292 sizeof(sendlog.type) +
293 sizeof(sendlog.length), MSG_NOSIGNAL);
295 LOGI("TERMINATE send exit msg (socket %d) "
296 "by terminate_all_target()\n",
297 manager.target[i].socket);
303 // terminate all target and wait for threads
307 terminate_all_target();
309 // wait for all other thread exit
310 for (i = 0; i < MAX_TARGET_COUNT; i++) {
311 if (manager.target[i].recv_thread != -1) {
312 LOGI("join recv thread [%d] is started\n", i);
313 pthread_join(manager.target[i].recv_thread, NULL);
314 LOGI("join recv thread %d. done\n", i);
319 // terminate all profiling by critical error
320 // TODO: don't send data to host
321 static void terminate_error(char *errstr, int send_to_host)
323 LOGE("termination all with err '%s'\n", errstr);
324 struct msg_data_t *msg = NULL;
325 if (send_to_host != 0) {
326 msg = gen_message_error(errstr);
331 LOGI("cannot generate error message\n");
337 static Ecore_Fd_Handler *connect_timer_handler;
339 static Eina_Bool connect_timer_cb(void *data, Ecore_Fd_Handler *fd_handler)
341 terminate_error("no incoming connections", 1);
342 close(manager.connect_timeout_timerfd);
343 manager.connect_timeout_timerfd = -1;
344 LOGE("No connection in %d sec. shutdown.\n",
345 MAX_CONNECT_TIMEOUT_TIME);
346 ecore_main_loop_quit();
348 return ECORE_CALLBACK_CANCEL;
351 static int launch_timer_start(void)
355 manager.connect_timeout_timerfd =
356 timerfd_create(CLOCK_REALTIME, TFD_CLOEXEC);
357 if (manager.connect_timeout_timerfd > 0) {
358 struct itimerspec ctime;
359 ctime.it_value.tv_sec = MAX_CONNECT_TIMEOUT_TIME;
360 ctime.it_value.tv_nsec = 0;
361 ctime.it_interval.tv_sec = 0;
362 ctime.it_interval.tv_nsec = 0;
363 if (timerfd_settime(manager.connect_timeout_timerfd, 0, &ctime, NULL) < 0) {
364 LOGE("fail to set connect timeout timer\n");
365 close(manager.connect_timeout_timerfd);
366 manager.connect_timeout_timerfd = -1;
368 connect_timer_handler =
369 ecore_main_fd_handler_add(manager.connect_timeout_timerfd,
374 if (!connect_timer_handler) {
375 LOGE("fail to add app connection timeout timer fd\n");
376 close(manager.connect_timeout_timerfd);
377 manager.connect_timeout_timerfd = -1;
379 LOGI("connection timeout timer started\n");
383 LOGE("cannot create connection timeout timer\n");
386 LOGI("ret=%d\n", res);
390 int prepare_profiling(void)
392 struct app_list_t *app = NULL;
393 const struct app_info_t *app_info = NULL;
395 app_info = app_info_get_first(&app);
396 if (app_info == NULL) {
397 LOGE("No app info found\n");
402 while (app_info != NULL) {
403 if (kill_app_by_info(app_info) != 0) {
404 LOGE("kill app failed\n");
407 app_info = app_info_get_next(&app);
409 //init rw for systeminfo
410 //init recv send network systeminfo
416 int start_profiling(void)
418 struct app_list_t *app = NULL;
419 const struct app_info_t *app_info = NULL;
422 app_info = app_info_get_first(&app);
423 if (app_info == NULL) {
424 LOGE("No app info found\n");
427 // remove previous screen capture files
428 remove_indir(SCREENSHOT_DIR);
429 if (mkdir(SCREENSHOT_DIR, 0777) == -1 && errno != EEXIST)
430 LOGW("Failed to create directory for screenshot : %s\n",
433 set_label_for_all(SCREENSHOT_DIR);
435 if (samplingStart() < 0) {
436 LOGE("Cannot start sampling\n");
441 if (IS_OPT_SET(FL_RECORDING))
444 while (app_info != NULL) {
445 if (exec_app(app_info)) {
446 LOGE("Cannot exec app\n");
450 app_info = app_info_get_next(&app);
453 if (start_app_launch_timer(get_apps_to_run()) < 0) {
461 if (IS_OPT_SET(FL_RECORDING))
466 LOGI("return %d\n", res);
470 void stop_profiling(void)
472 if (IS_OPT_SET(FL_RECORDING))
477 static void reconfigure_recording(struct conf_t conf)
479 uint64_t old_features = prof_session.conf.use_features0;
480 uint64_t new_features = conf.use_features0;
481 uint64_t to_enable = (new_features ^ old_features) & new_features;
482 uint64_t to_disable = (new_features ^ old_features) & old_features;
484 if (IS_OPT_SET_IN(FL_RECORDING, to_disable)) {
486 prof_session.conf.use_features0 &= ~FL_RECORDING;
489 if (IS_OPT_SET_IN(FL_RECORDING, to_enable)) {
491 prof_session.conf.use_features0 |= FL_RECORDING;
496 int reconfigure(struct conf_t conf)
498 reconfigure_recording(conf);
501 memcpy(&prof_session.conf, &conf, sizeof(conf));
502 if (samplingStart() < 0) {
503 LOGE("Cannot start sampling\n");
510 static Ecore_Fd_Handler *target_handlers[MAX_TARGET_COUNT];
512 static int target_event_pid_handler(int index, uint64_t msg)
514 struct app_list_t *app = NULL;
515 struct app_info_t *app_info = NULL;
516 if (index == 0) { // main application
517 app_info = app_info_get_first(&app);
518 if (app_info == NULL) {
519 LOGE("No app info found\n");
523 while (app_info != NULL) {
524 if (is_same_app_process(app_info->exe_path,
525 manager.target[index].pid))
527 app_info = app_info_get_next(&app);
530 if (app_info == NULL) {
531 LOGE("pid %d not found in app list\n",
532 manager.target[index].pid);
536 if (start_replay() != 0) {
537 LOGE("Cannot start replay thread\n");
541 manager.target[index].initial_log = 1;
545 static int target_event_stop_handler(int index, uint64_t msg)
547 LOGI("target close, socket(%d), pid(%d) : (remaining %d target)\n",
548 manager.target[index].socket, manager.target[index].pid,
549 manager.target_count - 1);
551 if (index == 0) // main application
554 ecore_main_fd_handler_del(target_handlers[index]);
556 setEmptyTargetSlot(index);
557 // all target client are closed
558 if (0 == __sync_sub_and_fetch(&manager.target_count, 1)) {
559 LOGI("all targets are stopped\n");
560 if (stop_all() != ERR_NO)
561 LOGE("Stop failed\n");
568 // return 0 if normal case
569 // return plus value if non critical error occur
570 // return minus value if critical error occur
571 // return -11 if all target process closed
572 static int target_event_handler(int index, uint64_t msg)
576 err = target_event_pid_handler(index, msg);
580 if (msg & EVENT_STOP || msg & EVENT_ERROR)
581 err = target_event_stop_handler(index, msg);
586 static Eina_Bool target_event_cb(void *data, Ecore_Fd_Handler *fd_handler)
590 int index = (int)data;
592 recvLen = read(manager.target[index].event_fd, &u, sizeof(uint64_t));
593 if (recvLen != sizeof(uint64_t)) {
594 // maybe closed, but ignoring is more safe then
595 // removing fd from event loop
597 if (-11 == target_event_handler(index, u)) {
598 LOGI("all target process is closed\n");
602 return ECORE_CALLBACK_RENEW;
606 * return 0 if normal case
607 * return plus value if non critical error occur
608 * return minus value if critical error occur
610 static int targetServerHandler(void)
612 msg_target_t log, pid_msg;
615 int index = getEmptyTargetSlot();
616 if (index == MAX_TARGET_COUNT) {
617 LOGW("Max target number(8) reached, no more target can connected\n");
621 manager.target[index].socket =
622 accept(manager.target_server_socket, NULL, NULL);
624 if (manager.target[index].socket >= 0) {
626 fd_setup_attributes(manager.target[index].socket);
628 /* send config message to target process */
629 log.type = MSG_OPTION;
630 log.length = sprintf(log.data, "%llu",
631 prof_session.conf.use_features0);
632 if (0 > send(manager.target[index].socket, &log,
633 sizeof(log.type) + sizeof(log.length) + log.length,
635 LOGE("fail to send data to target index(%d)\n", index);
638 manager.target[index].event_fd = eventfd(EFD_CLOEXEC, EFD_NONBLOCK);
639 if (manager.target[index].event_fd == -1) {
640 // fail to make event fd
641 LOGE("fail to make event fd for socket (%d)\n",
642 manager.target[index].socket);
643 goto TARGET_CONNECT_FAIL;
646 target_handlers[index] =
647 ecore_main_fd_handler_add(manager.target[index].event_fd,
652 if (!target_handlers[index]) {
653 LOGE("fail to add event fd for socket (%d)\n",
654 manager.target[index].socket);
655 goto TARGET_CONNECT_FAIL;
658 // make recv thread for target
659 if (makeRecvThread(index) != 0) {
660 // fail to make recv thread
661 LOGE("fail to make recv thread for socket (%d)\n",
662 manager.target[index].socket);
663 ecore_main_fd_handler_del(target_handlers[index]);
664 goto TARGET_CONNECT_FAIL;
669 if ((manager.app_launch_timerfd > 0) && (get_apps_to_run() == 0)) {
670 if (stop_app_launch_timer() < 0)
671 LOGE("cannot stop app launch timer\n");
674 LOGI("target connected = %d(running %d target)\n",
675 manager.target[index].socket, manager.target_count + 1);
677 manager.target_count++;
681 LOGE("Failed to accept at target server socket\n");
685 if (manager.target_count == 0) {
686 // if this connection is main connection
689 // if this connection is not main connection then ignore process by error
690 setEmptyTargetSlot(index);
695 static Ecore_Fd_Handler *host_ctrl_handler;
696 static Ecore_Fd_Handler *host_data_handler;
698 // return plus value if non critical error occur
699 // return minus value if critical error occur
700 // return -11 if socket closed
701 static int controlSocketHandler(int efd)
704 struct msg_t msg_head;
708 if (manager.connect_timeout_timerfd >= 0) {
709 LOGI("release connect timeout timer\n");
710 close(manager.connect_timeout_timerfd);
711 manager.connect_timeout_timerfd = -1;
714 recv_len = recv(manager.host.control_socket,
715 &msg_head, MSG_CMD_HDR_LEN, 0);
716 // error or close request from host
717 if (recv_len == -1 || recv_len == 0)
720 msg = malloc(MSG_CMD_HDR_LEN + msg_head.len);
722 LOGE("Cannot alloc msg\n");
723 sendACKToHost(msg_head.id, ERR_WRONG_MESSAGE_FORMAT, 0, 0);
726 msg->id = msg_head.id;
727 msg->len = msg_head.len;
729 // Receive payload (if exists)
730 recv_len = recv(manager.host.control_socket,
731 msg->payload, msg->len, MSG_WAITALL);
735 printBuf((char *)msg, MSG_CMD_HDR_LEN + msg->len);
736 res = host_message_handler(msg);
743 static Eina_Bool host_ctrl_cb(void *data, Ecore_Fd_Handler *fd_handler)
745 int result = controlSocketHandler(manager.efd);
748 //if the host disconnected.
749 //In all other cases daemon must report an error and continue the loop
750 //close connect_timeoutt and host socket and quit
751 LOGI("Connection closed. Termination. (%d)\n",
752 manager.host.control_socket);
753 ecore_main_loop_quit();
754 } else if (result < 0) {
755 LOGE("Control socket handler.\n");
758 return ECORE_CALLBACK_RENEW;
761 static Eina_Bool host_data_cb(void *data, Ecore_Fd_Handler *fd_handler)
766 recvLen = recv(manager.host.data_socket, recvBuf, 32, MSG_DONTWAIT);
769 ecore_main_fd_handler_del(host_data_handler);
770 close(manager.host.data_socket);
771 manager.host.data_socket = -1;
772 // TODO: finish transfer thread
775 LOGI("host message from data socket %d\n", recvLen);
777 return ECORE_CALLBACK_RENEW;
780 // return 0 if normal case
781 // return plus value if non critical error occur
782 // return minus value if critical error occur
783 static int hostServerHandler(void)
785 static int hostserverorder = 0;
788 if (hostserverorder > 1) // control and data socket connected already
791 csocket = accept(manager.host_server_socket, NULL, NULL);
796 if (hostserverorder == 0) {
797 manager.host.control_socket = csocket;
799 LOGI("host control socket connected = %d\n", csocket);
801 ecore_main_fd_handler_add(manager.host.control_socket,
806 if (!host_ctrl_handler) {
807 LOGE("Failed to add host control socket fd\n");
812 manager.host.data_socket = csocket;
813 LOGI("host data socket connected = %d\n", csocket);
816 ecore_main_fd_handler_add(manager.host.data_socket,
821 if (!host_data_handler) {
822 LOGE("Failed to add host data socket fd\n");
832 LOGE("Failed to accept from host server socket\n");
837 static int kernel_handler(void)
841 struct nlmsghdr *nlh;
845 /* Get buffer size */
846 optlen = sizeof(size);
848 /* We're using SOCK_DGRAM, so, get it maximum size */
849 res = getsockopt(manager.kernel_socket, SOL_SOCKET, SO_SNDBUF, &size,
853 LOGE("Get maximum buffer size failed\n");
857 /* Alloc mem for nlh message struct and receive it */
861 len = recv(manager.kernel_socket, nlh, size, 0);
862 if ((len <= 0) || (nlh->nlmsg_len == 0)) {
867 /* nlh data field contains connectors message */
868 msg = NLMSG_DATA(nlh);
874 switch(*(enum us_interaction_k2u_msg_t *) msg->data) {
875 case US_INT_PAUSE_APPS:
878 case US_INT_CONT_APPS:
882 LOGE("Unknown command\n");
885 /* Insert your message handler here */
896 static Ecore_Fd_Handler *host_connect_handler;
897 static Ecore_Fd_Handler *target_connect_handler;
898 static Ecore_Fd_Handler *kernel_connect_handler;
900 static Eina_Bool host_connect_cb(void *data, Ecore_Fd_Handler *fd_handler)
902 // connect request from host
903 int result = hostServerHandler();
905 LOGE("Internal DA framework error (hostServerHandler)\n");
908 return ECORE_CALLBACK_RENEW;
911 static Eina_Bool target_connect_cb(void *data, Ecore_Fd_Handler *fd_handler)
913 if (targetServerHandler() < 0) {
915 terminate_error("Internal DA framework error, "
916 "Please re-run the profiling "
917 "(targetServerHandler)\n", 1);
920 return ECORE_CALLBACK_RENEW;
923 static Eina_Bool kernel_connect_cb(void *data, Ecore_Fd_Handler *fd_handler)
925 if (kernel_handler() < 0) {
926 LOGE("Internal DA framework error (kernel_handler)\n");
929 return ECORE_CALLBACK_RENEW;
932 static bool initialize_events(void)
934 host_connect_handler =
935 ecore_main_fd_handler_add(manager.host_server_socket,
940 if (!host_connect_handler) {
941 LOGE("Host server socket add error\n");
945 target_connect_handler =
946 ecore_main_fd_handler_add(manager.target_server_socket,
951 if (!target_connect_handler) {
952 LOGE("Target server socket add error\n");
956 kernel_connect_handler =
957 ecore_main_fd_handler_add(manager.kernel_socket,
962 if (!kernel_connect_handler) {
963 LOGE("Kernel socket add error\n");
970 // return 0 for normal case
973 int return_value = 0;
977 if (init_input_events() == -1) {
982 if (!initialize_events()) {
987 if (launch_timer_start() < 0) {
988 LOGE("Launch timer start failed\n");
993 init_prof_session(&prof_session);
995 ecore_main_loop_begin();
1002 return return_value;