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
49 #include <attr/xattr.h> // for fsetxattr
50 #include <sys/smack.h>
61 #include "da_protocol.h"
64 #include "input_events.h"
67 #define DA_WORK_DIR "/home/developer/sdk_tools/da/"
68 #define DA_READELF_PATH "/home/developer/sdk_tools/da/readelf"
69 #define SCREENSHOT_DIR "/tmp/da"
71 #define MAX_APP_LAUNCH_TIME 60
72 #define MAX_CONNECT_TIMEOUT_TIME 5*60
74 uint64_t get_total_alloc_size(void)
77 uint64_t allocsize = 0;
79 for (i = 0; i < MAX_TARGET_COUNT; i++) {
80 if (manager.target[i].socket != -1 &&
81 manager.target[i].allocmem > 0)
82 allocsize += manager.target[i].allocmem;
87 static int getEmptyTargetSlot()
90 for (i = 0; i < MAX_TARGET_COUNT; i++) {
91 if (manager.target[i].socket == -1)
98 static void setEmptyTargetSlot(int index)
100 if (index >= 0 && index < MAX_TARGET_COUNT) {
101 manager.target[index].pid = -1;
102 manager.target[index].recv_thread = -1;
103 manager.target[index].allocmem = 0;
104 manager.target[index].initial_log = 0;
105 if (manager.target[index].event_fd != -1)
106 close(manager.target[index].event_fd);
107 manager.target[index].event_fd = -1;
108 if (manager.target[index].socket != -1)
109 close(manager.target[index].socket);
110 manager.target[index].socket = -1;
114 // =============================================================================
115 // start and terminate control functions
116 // =============================================================================
118 static Ecore_Fd_Handler *launch_timer_handler;
120 //stop application launch timer
121 static int stop_app_launch_timer()
123 close(manager.app_launch_timerfd);
124 manager.app_launch_timerfd = -1;
129 static Eina_Bool launch_timer_cb(void *data, Ecore_Fd_Handler *fd_handler)
131 LOGE("Failed to launch application\n");
132 if (stop_app_launch_timer() < 0)
133 LOGE("cannot stop app launch timer\n");
135 return ECORE_CALLBACK_CANCEL;
138 //start application launch timer function
139 static int start_app_launch_timer(int apps_count)
143 assert(apps_count >= 0 && "negative apps count");
148 manager.app_launch_timerfd =
149 timerfd_create(CLOCK_REALTIME, TFD_CLOEXEC);
150 if (manager.app_launch_timerfd > 0) {
151 struct itimerspec ctime;
152 ctime.it_value.tv_sec = MAX_APP_LAUNCH_TIME * apps_count;
153 ctime.it_value.tv_nsec = 0;
154 ctime.it_interval.tv_sec = 0;
155 ctime.it_interval.tv_nsec = 0;
156 if (timerfd_settime(manager.app_launch_timerfd, 0, &ctime, NULL) < 0) {
157 LOGE("fail to set app launch timer\n");
158 stop_app_launch_timer();
161 launch_timer_handler =
162 ecore_main_fd_handler_add(manager.app_launch_timerfd,
167 if (!launch_timer_handler) {
168 LOGE("fail to add app launch timer fd to \n");
169 stop_app_launch_timer();
172 LOGI("application launch time started\n");
176 LOGE("cannot create launch timer\n");
183 static inline void inc_apps_to_run()
185 manager.apps_to_run++;
188 static inline void dec_apps_to_run()
190 if (manager.apps_to_run > 0)
191 manager.apps_to_run--;
194 static inline int get_apps_to_run()
196 return manager.apps_to_run;
199 static int kill_app_by_info(const struct app_info_t *app_info)
203 if (app_info == NULL) {
204 LOGE("Cannot exec app. app_info is NULL");
208 switch (app_info->app_type) {
210 res = kill_app(app_info->exe_path);
212 case APP_TYPE_RUNNING:
213 // TODO: nothing, it's running
214 LOGI("already started\n");
216 case APP_TYPE_COMMON:
217 res = kill_app(app_info->exe_path);
220 LOGE("Unknown app type %d\n", app_info->app_type);
228 static int exec_app(const struct app_info_t *app_info)
232 if (app_info == NULL) {
233 LOGE("Cannot exec app. app_info is NULL");
237 switch (app_info->app_type) {
239 if (exec_app_tizen(app_info->app_id, app_info->exe_path)) {
240 LOGE("Cannot exec tizen app %s\n", app_info->app_id);
246 case APP_TYPE_RUNNING:
247 // TODO: nothing, it's running
248 LOGI("already started\n");
250 case APP_TYPE_COMMON:
251 if (exec_app_common(app_info->exe_path)) {
252 LOGE("Cannot exec common app %s\n", app_info->exe_path);
259 LOGE("Unknown app type %d\n", app_info->app_type);
264 LOGI("ret=%d\n", res);
268 // just send stop message to all target process
269 static void terminate_all_target()
273 msg_target_t sendlog;
275 sendlog.type = MSG_STOP;
278 for (i = 0; i < MAX_TARGET_COUNT; i++) {
279 if (manager.target[i].socket != -1) {
280 sendlen = send(manager.target[i].socket, &sendlog,
281 sizeof(sendlog.type) +
282 sizeof(sendlog.length), MSG_NOSIGNAL);
284 LOGI("TERMINATE send exit msg (socket %d) "
285 "by terminate_all_target()\n",
286 manager.target[i].socket);
292 // terminate all target and wait for threads
296 terminate_all_target();
298 // wait for all other thread exit
299 for (i = 0; i < MAX_TARGET_COUNT; i++) {
300 if (manager.target[i].recv_thread != -1) {
301 LOGI("join recv thread [%d] is started\n", i);
302 pthread_join(manager.target[i].recv_thread, NULL);
303 LOGI("join recv thread %d. done\n", i);
308 // terminate all profiling by critical error
309 // TODO: don't send data to host
310 static void terminate_error(char *errstr, int send_to_host)
312 LOGE("termination all with err '%s'\n", errstr);
313 struct msg_data_t *msg = NULL;
314 if (send_to_host != 0) {
315 msg = gen_message_error(errstr);
320 LOGI("cannot generate error message\n");
326 static Ecore_Fd_Handler *connect_timer_handler;
328 static Eina_Bool connect_timer_cb(void *data, Ecore_Fd_Handler *fd_handler)
330 terminate_error("no incoming connections", 1);
331 close(manager.connect_timeout_timerfd);
332 manager.connect_timeout_timerfd = -1;
333 LOGE("No connection in %d sec. shutdown.\n",
334 MAX_CONNECT_TIMEOUT_TIME);
335 ecore_main_loop_quit();
337 return ECORE_CALLBACK_CANCEL;
340 static int launch_timer_start(void)
344 manager.connect_timeout_timerfd =
345 timerfd_create(CLOCK_REALTIME, TFD_CLOEXEC);
346 if (manager.connect_timeout_timerfd > 0) {
347 struct itimerspec ctime;
348 ctime.it_value.tv_sec = MAX_CONNECT_TIMEOUT_TIME;
349 ctime.it_value.tv_nsec = 0;
350 ctime.it_interval.tv_sec = 0;
351 ctime.it_interval.tv_nsec = 0;
352 if (timerfd_settime(manager.connect_timeout_timerfd, 0, &ctime, NULL) < 0) {
353 LOGE("fail to set connect timeout timer\n");
354 close(manager.connect_timeout_timerfd);
355 manager.connect_timeout_timerfd = -1;
357 connect_timer_handler =
358 ecore_main_fd_handler_add(manager.connect_timeout_timerfd,
363 if (!connect_timer_handler) {
364 LOGE("fail to add app connection timeout timer fd\n");
365 close(manager.connect_timeout_timerfd);
366 manager.connect_timeout_timerfd = -1;
368 LOGI("connection timeout timer started\n");
372 LOGE("cannot create connection timeout timer\n");
375 LOGI("ret=%d\n", res);
379 int prepare_profiling(void)
381 struct app_list_t *app = NULL;
382 const struct app_info_t *app_info = NULL;
384 app_info = app_info_get_first(&app);
385 if (app_info == NULL) {
386 LOGE("No app info found\n");
391 while (app_info != NULL) {
392 if (kill_app_by_info(app_info) != 0) {
393 LOGE("kill app failed\n");
396 app_info = app_info_get_next(&app);
398 //init rw for systeminfo
399 //init recv send network systeminfo
405 int start_profiling(void)
407 struct app_list_t *app = NULL;
408 const struct app_info_t *app_info = NULL;
411 app_info = app_info_get_first(&app);
412 if (app_info == NULL) {
413 LOGE("No app info found\n");
416 // remove previous screen capture files
417 remove_indir(SCREENSHOT_DIR);
418 if (mkdir(SCREENSHOT_DIR, 0777) == -1 && errno != EEXIST)
419 LOGW("Failed to create directory for screenshot : %s\n",
422 smack_lsetlabel(SCREENSHOT_DIR, "*", SMACK_LABEL_ACCESS);
424 if (samplingStart() < 0) {
425 LOGE("Cannot start sampling\n");
430 if (IS_OPT_SET(FL_RECORDING))
433 while (app_info != NULL) {
434 if (exec_app(app_info)) {
435 LOGE("Cannot exec app\n");
439 app_info = app_info_get_next(&app);
442 if (start_app_launch_timer(get_apps_to_run()) < 0) {
450 if (IS_OPT_SET(FL_RECORDING))
455 LOGI("return %d\n", res);
459 void stop_profiling(void)
461 if (IS_OPT_SET(FL_RECORDING))
466 static void reconfigure_recording(struct conf_t conf)
468 uint64_t old_features = prof_session.conf.use_features0;
469 uint64_t new_features = conf.use_features0;
470 uint64_t to_enable = (new_features ^ old_features) & new_features;
471 uint64_t to_disable = (new_features ^ old_features) & old_features;
473 if (IS_OPT_SET_IN(FL_RECORDING, to_disable)) {
475 prof_session.conf.use_features0 &= ~FL_RECORDING;
478 if (IS_OPT_SET_IN(FL_RECORDING, to_enable)) {
480 prof_session.conf.use_features0 |= FL_RECORDING;
485 int reconfigure(struct conf_t conf)
487 reconfigure_recording(conf);
490 memcpy(&prof_session.conf, &conf, sizeof(conf));
491 if (samplingStart() < 0) {
492 LOGE("Cannot start sampling\n");
499 static Ecore_Fd_Handler *target_handlers[MAX_TARGET_COUNT];
501 static int target_event_pid_handler(int index, uint64_t msg)
503 struct app_list_t *app = NULL;
504 struct app_info_t *app_info = NULL;
505 if (index == 0) { // main application
506 app_info = app_info_get_first(&app);
507 if (app_info == NULL) {
508 LOGE("No app info found\n");
512 while (app_info != NULL) {
513 if (is_same_app_process(app_info->exe_path,
514 manager.target[index].pid))
516 app_info = app_info_get_next(&app);
519 if (app_info == NULL) {
520 LOGE("pid %d not found in app list\n",
521 manager.target[index].pid);
525 if (start_replay() != 0) {
526 LOGE("Cannot start replay thread\n");
530 manager.target[index].initial_log = 1;
534 static int target_event_stop_handler(int index, uint64_t msg)
536 LOGI("target close, socket(%d), pid(%d) : (remaining %d target)\n",
537 manager.target[index].socket, manager.target[index].pid,
538 manager.target_count - 1);
540 if (index == 0) // main application
543 ecore_main_fd_handler_del(target_handlers[index]);
545 setEmptyTargetSlot(index);
546 // all target client are closed
547 if (0 == __sync_sub_and_fetch(&manager.target_count, 1)) {
548 LOGI("all targets are stopped\n");
549 if (stop_all() != ERR_NO)
550 LOGE("Stop failed\n");
557 // return 0 if normal case
558 // return plus value if non critical error occur
559 // return minus value if critical error occur
560 // return -11 if all target process closed
561 static int target_event_handler(int index, uint64_t msg)
565 err = target_event_pid_handler(index, msg);
569 if (msg & EVENT_STOP || msg & EVENT_ERROR)
570 err = target_event_stop_handler(index, msg);
575 static Eina_Bool target_event_cb(void *data, Ecore_Fd_Handler *fd_handler)
579 int index = (int)data;
581 recvLen = read(manager.target[index].event_fd, &u, sizeof(uint64_t));
582 if (recvLen != sizeof(uint64_t)) {
583 // maybe closed, but ignoring is more safe then
584 // removing fd from event loop
586 if (-11 == target_event_handler(index, u)) {
587 LOGI("all target process is closed\n");
591 return ECORE_CALLBACK_RENEW;
595 * return 0 if normal case
596 * return plus value if non critical error occur
597 * return minus value if critical error occur
599 static int targetServerHandler(void)
603 int index = getEmptyTargetSlot();
604 if (index == MAX_TARGET_COUNT) {
605 LOGW("Max target number(8) reached, no more target can connected\n");
609 manager.target[index].socket =
610 accept(manager.target_server_socket, NULL, NULL);
612 if (manager.target[index].socket >= 0) {
614 fd_setup_smack_attributes(manager.target[index].socket);
616 /* send config message to target process */
617 log.type = MSG_OPTION;
618 log.length = sprintf(log.data, "%llu",
619 prof_session.conf.use_features0);
620 if (0 > send(manager.target[index].socket, &log,
621 sizeof(log.type) + sizeof(log.length) + log.length,
623 LOGE("fail to send data to target index(%d)\n", index);
626 manager.target[index].event_fd = eventfd(EFD_CLOEXEC, EFD_NONBLOCK);
627 if (manager.target[index].event_fd == -1) {
628 // fail to make event fd
629 LOGE("fail to make event fd for socket (%d)\n",
630 manager.target[index].socket);
631 goto TARGET_CONNECT_FAIL;
634 target_handlers[index] =
635 ecore_main_fd_handler_add(manager.target[index].event_fd,
640 if (!target_handlers[index]) {
641 LOGE("fail to add event fd for socket (%d)\n",
642 manager.target[index].socket);
643 goto TARGET_CONNECT_FAIL;
646 // make recv thread for target
647 if (makeRecvThread(index) != 0) {
648 // fail to make recv thread
649 LOGE("fail to make recv thread for socket (%d)\n",
650 manager.target[index].socket);
651 ecore_main_fd_handler_del(target_handlers[index]);
652 goto TARGET_CONNECT_FAIL;
657 if ((manager.app_launch_timerfd > 0) && (get_apps_to_run() == 0)) {
658 if (stop_app_launch_timer() < 0)
659 LOGE("cannot stop app launch timer\n");
662 LOGI("target connected = %d(running %d target)\n",
663 manager.target[index].socket, manager.target_count + 1);
665 manager.target_count++;
669 LOGE("Failed to accept at target server socket\n");
673 if (manager.target_count == 0) {
674 // if this connection is main connection
677 // if this connection is not main connection then ignore process by error
678 setEmptyTargetSlot(index);
683 static Ecore_Fd_Handler *host_ctrl_handler;
684 static Ecore_Fd_Handler *host_data_handler;
686 // return plus value if non critical error occur
687 // return minus value if critical error occur
688 // return -11 if socket closed
689 static int controlSocketHandler(int efd)
692 struct msg_t msg_head;
696 if (manager.connect_timeout_timerfd >= 0) {
697 LOGI("release connect timeout timer\n");
698 close(manager.connect_timeout_timerfd);
699 manager.connect_timeout_timerfd = -1;
702 recv_len = recv(manager.host.control_socket,
703 &msg_head, MSG_CMD_HDR_LEN, 0);
704 // error or close request from host
705 if (recv_len == -1 || recv_len == 0)
708 msg = malloc(MSG_CMD_HDR_LEN + msg_head.len);
710 LOGE("Cannot alloc msg\n");
711 sendACKToHost(msg_head.id, ERR_WRONG_MESSAGE_FORMAT, 0, 0);
714 msg->id = msg_head.id;
715 msg->len = msg_head.len;
717 // Receive payload (if exists)
718 recv_len = recv(manager.host.control_socket,
719 msg->payload, msg->len, MSG_WAITALL);
723 printBuf((char *)msg, MSG_CMD_HDR_LEN + msg->len);
724 res = host_message_handler(msg);
731 static Eina_Bool host_ctrl_cb(void *data, Ecore_Fd_Handler *fd_handler)
733 int result = controlSocketHandler(manager.efd);
736 //if the host disconnected.
737 //In all other cases daemon must report an error and continue the loop
738 //close connect_timeoutt and host socket and quit
739 LOGI("Connection closed. Termination. (%d)\n",
740 manager.host.control_socket);
741 ecore_main_loop_quit();
742 } else if (result < 0) {
743 LOGE("Control socket handler.\n");
746 return ECORE_CALLBACK_RENEW;
749 static Eina_Bool host_data_cb(void *data, Ecore_Fd_Handler *fd_handler)
754 recvLen = recv(manager.host.data_socket, recvBuf, 32, MSG_DONTWAIT);
757 ecore_main_fd_handler_del(host_data_handler);
758 close(manager.host.data_socket);
759 manager.host.data_socket = -1;
760 // TODO: finish transfer thread
763 LOGI("host message from data socket %d\n", recvLen);
765 return ECORE_CALLBACK_RENEW;
768 // return 0 if normal case
769 // return plus value if non critical error occur
770 // return minus value if critical error occur
771 static int hostServerHandler(void)
773 static int hostserverorder = 0;
776 if (hostserverorder > 1) // control and data socket connected already
779 csocket = accept(manager.host_server_socket, NULL, NULL);
784 if (hostserverorder == 0) {
785 manager.host.control_socket = csocket;
787 LOGI("host control socket connected = %d\n", csocket);
789 ecore_main_fd_handler_add(manager.host.control_socket,
794 if (!host_ctrl_handler) {
795 LOGE("Failed to add host control socket fd\n");
800 manager.host.data_socket = csocket;
801 LOGI("host data socket connected = %d\n", csocket);
804 ecore_main_fd_handler_add(manager.host.data_socket,
809 if (!host_data_handler) {
810 LOGE("Failed to add host data socket fd\n");
820 LOGE("Failed to accept from host server socket\n");
825 static Ecore_Fd_Handler *host_connect_handler;
826 static Ecore_Fd_Handler *target_connect_handler;
828 static Eina_Bool host_connect_cb(void *data, Ecore_Fd_Handler *fd_handler)
830 // connect request from host
831 int result = hostServerHandler();
833 LOGE("Internal DA framework error (hostServerHandler)\n");
836 return ECORE_CALLBACK_RENEW;
839 static Eina_Bool target_connect_cb(void *data, Ecore_Fd_Handler *fd_handler)
841 if (targetServerHandler() < 0) {
843 terminate_error("Internal DA framework error, "
844 "Please re-run the profiling "
845 "(targetServerHandler)\n", 1);
848 return ECORE_CALLBACK_RENEW;
851 static bool initialize_events(void)
853 host_connect_handler =
854 ecore_main_fd_handler_add(manager.host_server_socket,
859 if (!host_connect_handler) {
860 LOGE("Host server socket add error\n");
864 target_connect_handler =
865 ecore_main_fd_handler_add(manager.target_server_socket,
870 if (!target_connect_handler) {
871 LOGE("Target server socket add error\n");
878 // return 0 for normal case
881 int return_value = 0;
885 if (init_input_events() == -1) {
890 if (!initialize_events()) {
895 if (launch_timer_start() < 0) {
896 LOGE("Launch timer start failed\n");
901 init_prof_session(&prof_session);
903 ecore_main_loop_begin();