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
34 #include <stdlib.h> // for atoi, atol
35 #include <string.h> // for strchr
36 #include <stdint.h> // for uint64_t
37 #include <sys/types.h> // for recv
38 #include <sys/socket.h> // for recv
39 #include <sys/time.h> // for setitimer
40 #include <signal.h> // for sigemptyset, sigset_t, sigaddset, ...
41 #include <unistd.h> // for write
47 #include "da_protocol.h"
52 static void* recvThread(void* data)
54 __da_target_info *target = data;
60 // initialize target variable
66 // read from target process
67 recvLen = recv(target->socket, &log,
68 sizeof(log.type) + sizeof(log.length),
71 if(unlikely(recvLen < sizeof(log.type) + sizeof(log.length)))
74 write(target->event_fd, &event, sizeof(uint64_t));
77 if (IS_PROBE_MSG(log.type)) {
78 struct msg_data_t tmp_msg;
79 int offs = sizeof(log.type) + sizeof(log.length);
81 recvLen = recv(target->socket,
83 MSG_DATA_HDR_LEN - offs,
85 memcpy(&tmp_msg, &log, MSG_DATA_HDR_LEN);
86 struct msg_data_t *msg = malloc(MSG_DATA_HDR_LEN +
88 memcpy(msg, &tmp_msg, MSG_DATA_HDR_LEN);
89 recvLen = recv(target->socket,
90 (char *)msg + MSG_DATA_HDR_LEN,
91 msg->len, MSG_WAITALL);
98 if (likely(log.length > 0))
100 recvLen = recv(target->socket, log.data, log.length,
102 if(unlikely((recvLen == -1) || (recvLen != log.length))) // consume as disconnect
105 write(target->event_fd, &event, sizeof(uint64_t));
110 log.data[log.length] = '\0';
111 if(log.type == MSG_ALLOC)
113 target->allocmem = str_to_int64(log.data);
114 continue; // don't send to host
116 else if(log.type == MSG_PID)
118 LOGI("MSG_PID arrived : %s\n", log.data);
120 // only when first MSG_PID is arrived
121 if(target->pid == -1)
124 barloc = strchr(log.data, '|');
128 * TODO: complain to host about wrong
129 * pid message send stop message to
133 write(target->event_fd, &event,
140 target->pid = atoi(log.data);
142 write(target->event_fd, &event, sizeof(uint64_t));
144 continue; // don't send to host
146 else if(log.type == MSG_TERMINATE)
148 // send stop message to main thread
150 write(target->event_fd, &event,
153 struct msg_data_t *msg = malloc(sizeof(*msg) + /* pid */
155 fill_data_msg_head(msg, NMSG_TERMINATE, 0,
157 *(uint32_t *) msg->payload = (uint32_t) target->pid;
161 } else if (log.type == MSG_MSG) {
162 // don't send to host
163 LOGI("EXTRA MSG(%u) len=%u data='%s'\n", log.type,
164 log.length, log.data);
166 } else if (log.type == MSG_ERROR) {
167 // don't send to host
168 LOGE("EXTRA MSG(%u) len=%u data='%s'\n", log.type,
169 log.length, log.data);
172 #ifdef PRINT_TARGET_LOG
173 else if(log.type == MSG_LOG)
177 case '2': // UI control creation log
178 case '3': // UI event log
179 case '6': // UI lifecycle log
180 case '7': // screenshot log
181 case '8': // scene transition log
182 LOGI("%dclass|%s\n", log.data[0] - '0', log.data);
188 else if(log.type == MSG_IMAGE)
190 LOGI("MSG_IMAGE received\n");
192 else // not MSG_LOG and not MSG_IMAGE
194 LOGI("Extra MSG TYPE (%d|%d|%s)\n", log.type, log.length, log.data);
198 // do not send any message to host until MSG_PID message arrives
199 if(unlikely(pass == 0))
201 while(target->initial_log == 0)
209 target->recv_thread = -1;
213 int makeRecvThread(int index)
215 if (manager.target[index].socket == -1)
218 if (pthread_create(&(manager.target[index].recv_thread),
219 NULL, recvThread, &manager.target[index]) < 0)
221 LOGE("Failed to create recv thread for socket (%d)\n",
222 manager.target[index].socket);
230 void* samplingThread(void* data)
233 sigset_t waitsigmask;
235 LOGI("sampling thread started\n");
237 sigemptyset(&waitsigmask);
238 sigaddset(&waitsigmask, SIGALRM);
239 sigaddset(&waitsigmask, SIGUSR1);
242 err = sigwait(&waitsigmask, &signo);
244 LOGE("Failed to sigwait() in sampling thread\n");
248 if (signo == SIGALRM) {
249 int pidarr[MAX_TARGET_COUNT];
251 struct system_info_t sys_info;
252 struct msg_data_t *msg;
254 for (i = 0; i < MAX_TARGET_COUNT; i++) {
255 if (manager.target[i].socket != -1 &&
256 manager.target[i].pid != -1)
257 pidarr[pidcount++] = manager.target[i].pid;
260 if (get_system_info(&sys_info, pidarr, pidcount) == -1) {
261 LOGE("Cannot get system info\n");
262 //do not send sys_info because
267 msg = pack_system_info(&sys_info);
269 LOGE("Cannot pack system info\n");
270 reset_system_info(&sys_info);
276 printBuf((char *)msg, MSG_DATA_HDR_LEN + msg->len);
279 reset_system_info(&sys_info);
282 else if(signo == SIGUSR1)
284 LOGI("SIGUSR1 catched\n");
291 LOGE("This should never happen in sampling thread\n");
295 LOGI("sampling thread ended\n");
299 // return 0 if normal case
300 // return minus value if critical error
301 // return plus value if non-critical error
304 struct itimerval timerval;
305 time_t sec = prof_session.conf.system_trace_period / 1000;
306 suseconds_t usec = prof_session.conf.system_trace_period * 1000 %
309 if(manager.sampling_thread != -1) // already started
312 if (check_running_status(&prof_session) == 0) {
313 LOGI("try to start sampling when running_status is 0\n");
317 if(pthread_create(&(manager.sampling_thread), NULL, samplingThread, NULL) < 0)
319 LOGE("Failed to create sampling thread\n");
323 timerval.it_interval.tv_sec = sec;
324 timerval.it_interval.tv_usec = usec;
325 timerval.it_value.tv_sec = sec;
326 timerval.it_value.tv_usec = usec;
327 setitimer(ITIMER_REAL, &timerval, NULL);
334 if(manager.sampling_thread != -1)
336 struct itimerval stopval;
339 stopval.it_interval.tv_sec = 0;
340 stopval.it_interval.tv_usec = 0;
341 stopval.it_value.tv_sec = 0;
342 stopval.it_value.tv_usec = 0;
343 setitimer(ITIMER_REAL, &stopval, NULL);
345 pthread_kill(manager.sampling_thread, SIGUSR1);
346 LOGI("join sampling thread started\n");
347 pthread_join(manager.sampling_thread, NULL);
348 LOGI("join sampling thread done\n");
350 manager.sampling_thread = -1;
356 static useconds_t time_diff_us(struct timeval *tv1, struct timeval *tv2)
358 return (tv1->tv_sec - tv2->tv_sec) * 1000000 +
359 ((int)tv1->tv_usec - (int)tv2->tv_usec);
362 static void *replay_thread(void *arg)
364 struct replay_event_seq_t *event_seq = (struct replay_event_seq_t *)arg;
367 useconds_t prev_event_offset = 0;
369 struct replay_event_t * pevent = NULL;
371 LOGI_th_rep("replay events thread started\n");
372 if (event_seq->event_num != 0)
374 pevent = event_seq->events;
377 for (i = 0; i < event_seq->event_num; i++) {
378 useconds_t event_offset = time_diff_us(&pevent->ev.time, &event_seq->tv);
379 if (event_offset >= prev_event_offset)
380 ms = event_offset - prev_event_offset;
384 #ifdef THREAD_REPLAY_DEBUG
385 print_replay_event(pevent, i + 1, "\t");
387 LOGI_th_rep("%d) sleep %d\n", i, ms);
390 /* filter touch and key events here
391 and process them separately */
395 LOGI_th_rep("event -> %s\n", INPUT_ID_STR_TOUCH);
396 _device_write(g_touch_dev, &pevent->ev);
400 LOGI_th_rep("event -> %s\n", INPUT_ID_STR_KEY);
401 _device_write(g_key_dev, &pevent->ev);
404 LOGE("event -> UNKNOWN INPUT ID");
407 prev_event_offset = event_offset;
412 LOGI("replay events thread finished\n");
419 if (manager.replay_thread != -1) // already started
422 if (pthread_create(&(manager.replay_thread),
425 &prof_session.replay_event_seq) < 0)
427 LOGE("Failed to create replay thread\n");
436 if (manager.replay_thread == -1) {
437 LOGI("replay thread not running\n");
440 LOGI("stopping replay thread\n");
441 pthread_cancel(manager.replay_thread);
442 pthread_join(manager.replay_thread, NULL);
443 manager.replay_thread = -1;
444 reset_replay_event_seq(&prof_session.replay_event_seq);
445 LOGI("replay thread joined\n");