0b1cad5568aaac97914ed83136bd3625f24e5ef6
[platform/core/system/swap-manager.git] / daemon / threads.c
1 /*
2  *  DA manager
3  *
4  * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact:
7  *
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>
13  *
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
17  *
18  * http://www.apache.org/licenses/LICENSE-2.0
19  *
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.
25  *
26  * Contributors:
27  * - S-Core Co., Ltd
28  * - Samsung RnD Institute Russia
29  *
30  */
31
32
33 #include <stdio.h>
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
42
43 #include "daemon.h"
44 #include "utils.h"
45 #include "sys_stat.h"
46
47 #include "da_protocol.h"
48 #include "da_data.h"
49 #include "debug.h"
50 #include "buffer.h"
51
52 static void* recvThread(void* data)
53 {
54         __da_target_info *target = data;
55         int pass = 0;
56         uint64_t event;
57         ssize_t recvLen;
58         msg_target_t log;
59
60         // initialize target variable
61         target->pid = -1;
62         target->allocmem = 0;
63
64         while(1)
65         {
66                 // read from target process
67                 recvLen = recv(target->socket, &log,
68                                 sizeof(log.type) + sizeof(log.length),
69                                MSG_WAITALL);
70
71                 if(unlikely(recvLen < sizeof(log.type) + sizeof(log.length)))
72                 {       // disconnect
73                         event = EVENT_STOP;
74                         write(target->event_fd, &event, sizeof(uint64_t));
75                         break;
76                 }
77                 if (IS_PROBE_MSG(log.type)) {
78                         struct msg_data_t tmp_msg;
79                         int offs = sizeof(log.type) + sizeof(log.length);
80
81                         recvLen = recv(target->socket,
82                                        (char *)&log + offs,
83                                        MSG_DATA_HDR_LEN - offs,
84                                        MSG_WAITALL);
85                         memcpy(&tmp_msg, &log, MSG_DATA_HDR_LEN);
86                         struct msg_data_t *msg = malloc(MSG_DATA_HDR_LEN +
87                                                         tmp_msg.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);
92                         write_to_buf(msg);
93                         free(msg);
94                         continue;
95                 }
96
97                 // send to host
98                 if (likely(log.length > 0))
99                 {
100                         recvLen = recv(target->socket, log.data, log.length,
101                                        MSG_WAITALL);
102                         if(unlikely((recvLen == -1) || (recvLen != log.length)))        // consume as disconnect
103                         {
104                                 event = EVENT_STOP;
105                                 write(target->event_fd, &event, sizeof(uint64_t));
106                                 break;
107                         }
108                 }
109
110                 log.data[log.length] = '\0';
111                 if(log.type == MSG_ALLOC)
112                 {
113                         target->allocmem = str_to_int64(log.data);
114                         continue;               // don't send to host
115                 }
116                 else if(log.type == MSG_PID)
117                 {
118                         LOGI("MSG_PID arrived : %s\n", log.data);
119
120                         // only when first MSG_PID is arrived
121                         if(target->pid == -1)
122                         {
123                                 char* barloc;
124                                 barloc = strchr(log.data, '|');
125                                 if(barloc == NULL)
126                                 {
127                                         /**
128                                          * TODO: complain to host about wrong
129                                          * pid message send stop message to
130                                          * main thread
131                                          */
132                                         event = EVENT_STOP;
133                                         write(target->event_fd, &event,
134                                               sizeof(uint64_t));
135                                         break;
136                                 }
137                                 barloc[0] = '\0';
138                                 barloc++;
139
140                                 target->pid = atoi(log.data);
141                                 event = EVENT_PID;
142                                 write(target->event_fd, &event, sizeof(uint64_t));
143                         }
144                         continue;               // don't send to host
145                 }
146                 else if(log.type == MSG_TERMINATE)
147                 {
148                         // send stop message to main thread
149                         event = EVENT_STOP;
150                         write(target->event_fd, &event,
151                               sizeof(uint64_t));
152
153                         struct msg_data_t *msg = malloc(sizeof(*msg) + /* pid */
154                                                         sizeof(uint32_t));
155                         fill_data_msg_head(msg, NMSG_TERMINATE, 0,
156                                            sizeof(uint32_t));
157                         *(uint32_t *) msg->payload = (uint32_t) target->pid;
158                         write_to_buf(msg);
159                         free(msg);
160                         break;
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);
165                         continue;
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);
170                         continue;
171                 }
172 #ifdef PRINT_TARGET_LOG
173                 else if(log.type == MSG_LOG)
174                 {
175                         switch(log.data[0])
176                         {
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);
183                                         break;
184                                 default:
185                                         break;
186                         }
187                 }
188                 else if(log.type == MSG_IMAGE)
189                 {
190                         LOGI("MSG_IMAGE received\n");
191                 }
192                 else    // not MSG_LOG and not MSG_IMAGE
193                 {
194                         LOGI("Extra MSG TYPE (%d|%d|%s)\n", log.type, log.length, log.data);
195                 }
196 #endif
197
198                 // do not send any message to host until MSG_PID message arrives
199                 if(unlikely(pass == 0))
200                 {
201                         while(target->initial_log == 0)
202                         {
203                                 sleep(0);
204                         }
205                 }
206                 pass = 1;
207         }
208
209         target->recv_thread = -1;
210         return NULL;
211 }
212
213 int makeRecvThread(int index)
214 {
215         if (manager.target[index].socket == -1)
216                 return -1;
217
218         if (pthread_create(&(manager.target[index].recv_thread),
219                 NULL, recvThread, &manager.target[index]) < 0)
220         {
221                 LOGE("Failed to create recv thread for socket (%d)\n",
222                                 manager.target[index].socket);
223                 return -1;
224         }
225
226         return 0;
227 }
228
229 //static
230 void* samplingThread(void* data)
231 {
232         int err, signo, i;
233         sigset_t waitsigmask;
234
235         LOGI("sampling thread started\n");
236
237         sigemptyset(&waitsigmask);
238         sigaddset(&waitsigmask, SIGALRM);
239         sigaddset(&waitsigmask, SIGUSR1);
240
241         while (1) {
242                 err = sigwait(&waitsigmask, &signo);
243                 if (err != 0) {
244                         LOGE("Failed to sigwait() in sampling thread\n");
245                         continue;
246                 }
247
248                 if (signo == SIGALRM) {
249                         int pidarr[MAX_TARGET_COUNT];
250                         int pidcount = 0;
251                         struct system_info_t sys_info;
252                         struct msg_data_t *msg;
253
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;
258                         }
259
260                         if (get_system_info(&sys_info, pidarr, pidcount) == -1) {
261                                 LOGE("Cannot get system info\n");
262                                 //do not send sys_info because
263                                 //it is corrupted
264                                 continue;
265                         }
266
267                         msg = pack_system_info(&sys_info);
268                         if (!msg) {
269                                 LOGE("Cannot pack system info\n");
270                                 reset_system_info(&sys_info);
271                                 continue;
272                         }
273
274                         write_to_buf(msg);
275
276                         printBuf((char *)msg, MSG_DATA_HDR_LEN + msg->len);
277
278                         free_msg_data(msg);
279                         reset_system_info(&sys_info);
280                         flush_buf();
281                 }
282                 else if(signo == SIGUSR1)
283                 {
284                         LOGI("SIGUSR1 catched\n");
285                         // end this thread
286                         break;
287                 }
288                 else
289                 {
290                         // never happen
291                         LOGE("This should never happen in sampling thread\n");
292                 }
293         }
294
295         LOGI("sampling thread ended\n");
296         return NULL;
297 }
298
299 // return 0 if normal case
300 // return minus value if critical error
301 // return plus value if non-critical error
302 int samplingStart()
303 {
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 %
307                 1000000;
308
309         if(manager.sampling_thread != -1)       // already started
310                 return 1;
311
312         if (check_running_status(&prof_session) == 0) {
313                 LOGI("try to start sampling when running_status is 0\n");
314                 return 1;
315         }
316
317         if(pthread_create(&(manager.sampling_thread), NULL, samplingThread, NULL) < 0)
318         {
319                 LOGE("Failed to create sampling thread\n");
320                 return -1;
321         }
322
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);
328
329         return 0;
330 }
331
332 int samplingStop()
333 {
334         if(manager.sampling_thread != -1)
335         {
336                 struct itimerval stopval;
337
338                 // stop timer
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);
344
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");
349
350                 manager.sampling_thread = -1;
351         }
352
353         return 0;
354 }
355
356 static useconds_t time_diff_us(struct timeval *tv1, struct timeval *tv2)
357 {
358         return (tv1->tv_sec - tv2->tv_sec) * 1000000 +
359                 ((int)tv1->tv_usec - (int)tv2->tv_usec);
360 }
361
362 static void *replay_thread(void *arg)
363 {
364         struct replay_event_seq_t *event_seq = (struct replay_event_seq_t *)arg;
365         int i = 0;
366         useconds_t ms;
367         useconds_t prev_event_offset = 0;
368
369         struct replay_event_t * pevent = NULL;
370
371         LOGI_th_rep("replay events thread started\n");
372         if (event_seq->event_num != 0)
373         {
374                 pevent = event_seq->events;
375         }
376
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;
381                 else
382                         ms = 0;
383
384 #ifdef THREAD_REPLAY_DEBUG
385                 print_replay_event(pevent, i + 1, "\t");
386 #endif
387                 LOGI_th_rep("%d) sleep %d\n", i, ms);
388                 usleep(ms);
389
390                 /* filter touch and key events here
391                    and process them separately */
392                 switch (pevent->id)
393                 {
394                 case INPUT_ID_TOUCH:
395                         LOGI_th_rep("event -> %s\n", INPUT_ID_STR_TOUCH);
396                         _device_write(g_touch_dev, &pevent->ev);
397                         break;
398
399                 case INPUT_ID_KEY:
400                         LOGI_th_rep("event -> %s\n", INPUT_ID_STR_KEY);
401                         _device_write(g_key_dev, &pevent->ev);
402                         break;
403                 default:
404                         LOGE("event -> UNKNOWN INPUT ID");
405                 }
406
407                 prev_event_offset = event_offset;
408
409                 pevent++;
410         }
411
412         LOGI("replay events thread finished\n");
413
414         return arg;
415 }
416
417 int start_replay()
418 {
419         if (manager.replay_thread != -1) // already started
420                 return 1;
421
422         if (pthread_create(&(manager.replay_thread),
423                            NULL,
424                            replay_thread,
425                            &prof_session.replay_event_seq) < 0)
426         {
427                 LOGE("Failed to create replay thread\n");
428                 return 1;
429         }
430
431         return 0;
432 }
433
434 void stop_replay()
435 {
436         if (manager.replay_thread == -1) {
437                 LOGI("replay thread not running\n");
438                 return;
439         }
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");
446 }