[FEATURE] Implement kernel -> user connection
[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 #include "input_events.h"
52
53 static void* recvThread(void* data)
54 {
55         __da_target_info *target = data;
56         int pass = 0;
57         uint64_t event;
58         ssize_t recvLen;
59         msg_target_t log;
60
61         // initialize target variable
62         target->pid = -1;
63         target->allocmem = 0;
64
65         while(1)
66         {
67                 // read from target process
68                 recvLen = recv(target->socket, &log,
69                                 sizeof(log.type) + sizeof(log.length),
70                                MSG_WAITALL);
71
72                 if(unlikely(recvLen < sizeof(log.type) + sizeof(log.length)))
73                 {       // disconnect
74                         event = EVENT_STOP;
75                         write(target->event_fd, &event, sizeof(uint64_t));
76                         break;
77                 }
78                 if (IS_PROBE_MSG(log.type)) {
79                         struct msg_data_t tmp_msg;
80                         int offs = sizeof(log.type) + sizeof(log.length);
81
82                         recvLen = recv(target->socket,
83                                        (char *)&log + offs,
84                                        MSG_DATA_HDR_LEN - offs,
85                                        MSG_WAITALL);
86                         memcpy(&tmp_msg, &log, MSG_DATA_HDR_LEN);
87                         struct msg_data_t *msg = malloc(MSG_DATA_HDR_LEN +
88                                                         tmp_msg.len);
89                         memcpy(msg, &tmp_msg, MSG_DATA_HDR_LEN);
90                         recvLen = recv(target->socket,
91                                        (char *)msg + MSG_DATA_HDR_LEN,
92                                        msg->len, MSG_WAITALL);
93                         write_to_buf(msg);
94                         free(msg);
95                         continue;
96                 }
97
98                 // send to host
99                 if (likely(log.length > 0))
100                 {
101                         recvLen = recv(target->socket, log.data, log.length,
102                                        MSG_WAITALL);
103                         if(unlikely((recvLen == -1) || (recvLen != log.length)))        // consume as disconnect
104                         {
105                                 event = EVENT_STOP;
106                                 write(target->event_fd, &event, sizeof(uint64_t));
107                                 break;
108                         }
109                 }
110
111                 log.data[log.length] = '\0';
112                 if(log.type == MSG_ALLOC)
113                 {
114                         target->allocmem = str_to_int64(log.data);
115                         continue;               // don't send to host
116                 }
117                 else if(log.type == MSG_PID)
118                 {
119                         LOGI("MSG_PID arrived : %s\n", log.data);
120
121                         // only when first MSG_PID is arrived
122                         if(target->pid == -1)
123                         {
124                                 char* barloc;
125                                 barloc = strchr(log.data, '|');
126                                 if(barloc == NULL)
127                                 {
128                                         /**
129                                          * TODO: complain to host about wrong
130                                          * pid message send stop message to
131                                          * main thread
132                                          */
133                                         event = EVENT_STOP;
134                                         write(target->event_fd, &event,
135                                               sizeof(uint64_t));
136                                         break;
137                                 }
138                                 barloc[0] = '\0';
139                                 barloc++;
140
141                                 target->pid = atoi(log.data);
142                                 event = EVENT_PID;
143                                 write(target->event_fd, &event, sizeof(uint64_t));
144                         }
145                         continue;               // don't send to host
146                 }
147                 else if(log.type == MSG_TERMINATE)
148                 {
149                         // send stop message to main thread
150                         event = EVENT_STOP;
151                         write(target->event_fd, &event,
152                               sizeof(uint64_t));
153
154                         struct msg_data_t *msg = malloc(sizeof(*msg) + /* pid */
155                                                         sizeof(uint32_t));
156                         fill_data_msg_head(msg, NMSG_TERMINATE, 0,
157                                            sizeof(uint32_t));
158                         *(uint32_t *) msg->payload = (uint32_t) target->pid;
159                         write_to_buf(msg);
160                         free(msg);
161                         break;
162                 } else if (log.type == MSG_MSG) {
163                         // don't send to host
164                         LOGI("EXTRA MSG(%u) len=%u data='%s'\n", log.type,
165                              log.length, log.data);
166                         continue;
167                 } else if (log.type == MSG_ERROR) {
168                         // don't send to host
169                         LOGE("EXTRA MSG(%u) len=%u data='%s'\n", log.type,
170                              log.length, log.data);
171                         continue;
172                 }
173 #ifdef PRINT_TARGET_LOG
174                 else if(log.type == MSG_LOG)
175                 {
176                         switch(log.data[0])
177                         {
178                                 case '2':       // UI control creation log
179                                 case '3':       // UI event log
180                                 case '6':       // UI lifecycle log
181                                 case '7':       // screenshot log
182                                 case '8':       // scene transition log
183                                         LOGI("%dclass|%s\n", log.data[0] - '0', log.data);
184                                         break;
185                                 default:
186                                         break;
187                         }
188                 }
189                 else if(log.type == MSG_IMAGE)
190                 {
191                         LOGI("MSG_IMAGE received\n");
192                 }
193                 else    // not MSG_LOG and not MSG_IMAGE
194                 {
195                         LOGI("Extra MSG TYPE (%d|%d|%s)\n", log.type, log.length, log.data);
196                 }
197 #endif
198
199                 // do not send any message to host until MSG_PID message arrives
200                 if(unlikely(pass == 0))
201                 {
202                         while(target->initial_log == 0)
203                         {
204                                 sleep(0);
205                         }
206                 }
207                 pass = 1;
208         }
209
210         target->recv_thread = -1;
211         return NULL;
212 }
213
214 int makeRecvThread(int index)
215 {
216         if (manager.target[index].socket == -1)
217                 return -1;
218
219         if (pthread_create(&(manager.target[index].recv_thread),
220                 NULL, recvThread, &manager.target[index]) < 0)
221         {
222                 LOGE("Failed to create recv thread for socket (%d)\n",
223                                 manager.target[index].socket);
224                 return -1;
225         }
226
227         return 0;
228 }
229
230 static void *samplingThread(void *data)
231 {
232         int err, signo;
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                         struct system_info_t sys_info;
250                         struct msg_data_t *msg;
251
252                         if (get_system_info(&sys_info) == -1) {
253                                 LOGE("Cannot get system info\n");
254                                 //do not send sys_info because
255                                 //it is corrupted
256                                 continue;
257                         }
258
259                         msg = pack_system_info(&sys_info);
260                         if (!msg) {
261                                 LOGE("Cannot pack system info\n");
262                                 reset_system_info(&sys_info);
263                                 continue;
264                         }
265
266                         write_to_buf(msg);
267
268                         printBuf((char *)msg, MSG_DATA_HDR_LEN + msg->len);
269
270                         free_msg_data(msg);
271                         reset_system_info(&sys_info);
272                         flush_buf();
273                 }
274                 else if(signo == SIGUSR1)
275                 {
276                         LOGI("SIGUSR1 catched\n");
277                         // end this thread
278                         break;
279                 }
280                 else
281                 {
282                         // never happen
283                         LOGE("This should never happen in sampling thread\n");
284                 }
285         }
286
287         LOGI("sampling thread ended\n");
288         return NULL;
289 }
290
291 // return 0 if normal case
292 // return minus value if critical error
293 // return plus value if non-critical error
294 int samplingStart(void)
295 {
296         struct itimerval timerval;
297         time_t sec = prof_session.conf.system_trace_period / 1000;
298         suseconds_t usec = prof_session.conf.system_trace_period * 1000 %
299                 1000000;
300
301         if(manager.sampling_thread != -1)       // already started
302                 return 1;
303
304         if (check_running_status(&prof_session) == 0) {
305                 LOGI("try to start sampling when running_status is 0\n");
306                 return 1;
307         }
308
309         if(pthread_create(&(manager.sampling_thread), NULL, samplingThread, NULL) < 0)
310         {
311                 LOGE("Failed to create sampling thread\n");
312                 return -1;
313         }
314
315         timerval.it_interval.tv_sec = sec;
316         timerval.it_interval.tv_usec = usec;
317         timerval.it_value.tv_sec = sec;
318         timerval.it_value.tv_usec = usec;
319         setitimer(ITIMER_REAL, &timerval, NULL);
320
321         return 0;
322 }
323
324 int samplingStop(void)
325 {
326         if(manager.sampling_thread != -1)
327         {
328                 struct itimerval stopval;
329
330                 // stop timer
331                 stopval.it_interval.tv_sec = 0;
332                 stopval.it_interval.tv_usec = 0;
333                 stopval.it_value.tv_sec = 0;
334                 stopval.it_value.tv_usec = 0;
335                 setitimer(ITIMER_REAL, &stopval, NULL);
336
337                 pthread_kill(manager.sampling_thread, SIGUSR1);
338                 LOGI("join sampling thread started\n");
339                 pthread_join(manager.sampling_thread, NULL);
340                 LOGI("join sampling thread done\n");
341
342                 manager.sampling_thread = -1;
343         }
344
345         return 0;
346 }
347
348 static useconds_t time_diff_us(struct timeval *tv1, struct timeval *tv2)
349 {
350         return (tv1->tv_sec - tv2->tv_sec) * 1000000 +
351                 ((int)tv1->tv_usec - (int)tv2->tv_usec);
352 }
353
354 static void *replay_thread(void *arg)
355 {
356         struct replay_event_seq_t *event_seq = (struct replay_event_seq_t *)arg;
357         int i = 0;
358         useconds_t ms;
359         useconds_t prev_event_offset = 0;
360
361         struct replay_event_t * pevent = NULL;
362
363         LOGI_th_rep("replay events thread started\n");
364         if (event_seq->event_num != 0)
365         {
366                 pevent = event_seq->events;
367         }
368
369         for (i = 0; i < event_seq->event_num; i++) {
370                 useconds_t event_offset = time_diff_us(&pevent->ev.time, &event_seq->tv);
371                 if (event_offset >= prev_event_offset)
372                         ms = event_offset - prev_event_offset;
373                 else
374                         ms = 0;
375
376 #ifdef THREAD_REPLAY_DEBUG
377                 print_replay_event(pevent, i + 1, "\t");
378 #endif
379                 LOGI_th_rep("%d) sleep %d\n", i, ms);
380                 usleep(ms);
381
382                 write_input_event(pevent->id, &pevent->ev);
383
384                 prev_event_offset = event_offset;
385
386                 pevent++;
387         }
388
389         LOGI("replay events thread finished\n");
390
391         return arg;
392 }
393
394 int start_replay()
395 {
396         if (manager.replay_thread != -1) // already started
397                 return 1;
398
399         if (pthread_create(&(manager.replay_thread),
400                            NULL,
401                            replay_thread,
402                            &prof_session.replay_event_seq) < 0)
403         {
404                 LOGE("Failed to create replay thread\n");
405                 return 1;
406         }
407
408         return 0;
409 }
410
411 void stop_replay()
412 {
413         if (manager.replay_thread == -1) {
414                 LOGI("replay thread not running\n");
415                 return;
416         }
417         LOGI("stopping replay thread\n");
418         pthread_cancel(manager.replay_thread);
419         pthread_join(manager.replay_thread, NULL);
420         manager.replay_thread = -1;
421         reset_replay_event_seq(&prof_session.replay_event_seq);
422         LOGI("replay thread joined\n");
423 }