tizen 2.3 release
[framework/system/deviced.git] / src / logd_grabber / logd-grabber.c
1 #include <Ecore.h>
2 #include <Eina.h>
3 #include <sys/types.h>
4 #include <sys/socket.h>
5 #include <unistd.h>
6 #include <string.h>
7 #include <errno.h>
8
9 #include "core/log.h"
10 #include "core/common.h"
11 #include "core/devices.h"
12 #include "core/device-notifier.h"
13
14 #include "battery.h"
15 #include "config.h"
16 #include "display.h"
17 #include "event.h"
18 #include "events.h"
19 #include "journal-reader.h"
20 #include "logd-db.h"
21 #include "logd.h"
22 #include "macro.h"
23 #include "mmc.h"
24 #include "nlproc-stat.h"
25 #include "socket-helper.h"
26 #include "task-stats.h"
27 #include "timer.h"
28
29
30 static int proc_stat_store_period;
31 static int old_events_rotate_period;
32 static int old_events_del_period;
33
34 static Eina_Hash *sockets;
35 struct socket_info {
36         void (*cb)(void *);
37         void *user_data;
38 };
39
40 static int api_socket;
41 static Ecore_Thread *logd_thread;
42 static struct timer *proc_stat_store_timer;
43 static struct timer *old_event_del_timer;
44 static struct timer *old_proc_power_cons_timer;
45
46 static int send_devices_power_cons(int sock)
47 {
48         size_t i;
49         int ret;
50         struct power_cons {
51                 enum logd_object object;
52                 float total;
53                 float curr;
54         } devices_power_cons[2] = {{
55                 LOGD_DISPLAY,
56                 get_display_total_power_cons(),
57                 get_display_curr_power_cons()
58         }, {
59                 LOGD_MMC,
60                 mmc_power_cons(),
61                 0
62         }};
63         const size_t count = ARRAY_SIZE(devices_power_cons);
64
65         if (write(sock, &count, sizeof(count)) != sizeof(count)) {
66                 ret = -errno;
67                 _E("write failed: %s", strerror(errno));
68                 return ret;
69         }
70
71         for (i = 0; i < count; ++i) {
72                 if (write(sock, &devices_power_cons[i], sizeof(devices_power_cons[i])) !=
73                         sizeof(devices_power_cons[i])) {
74                         ret = -errno;
75                         _E("write failed: %s", strerror(errno));
76                         return ret;
77                 }
78         }
79
80         return 0;
81 }
82
83 static void api_socket_cb(void *user_data)
84 {
85         enum logd_socket_req_type req_type;
86         int ns;
87         int ret;
88
89         if ((ns = accept(api_socket, NULL, NULL)) < 0) {
90                 _E("accept failed: %s", strerror(errno));
91                 return;
92         }
93
94         ret = read(ns, (void*)&req_type, sizeof(req_type));
95         if (ret != sizeof(req_type)) {
96                 _E("failed read API request type");
97                 if (close(ns) < 0) {
98                         _E("close failed: %s", strerror(errno));
99                 }
100                 return;
101         }
102
103         if (req_type == LOGD_DEV_STAT_REQ) { /* devices power consumption */
104                 if (send_devices_power_cons(ns) < 0) {
105                         _E("send_devices_power_cons failed");
106                 }
107         } else if (req_type == LOGD_PROC_STAT_REQ) {
108                 if (send_proc_stat(ns) < 0) {
109                         _E("send_proc_stat failed");
110                 }
111         } else if (req_type == LOGD_EST_TIME_REQ) {
112                 if (battery_send_estimate_lifetime(ns) < 0) {
113                         _E("battery_send_estimate_lifetime failed");
114                 }
115         } else if (req_type == LOGD_BATTERY_LVL_REQ) {
116                 if (battery_send_check_points(ns) < 0) {
117                         _E("battery_send_check_points failed");
118                 }
119         }
120
121         if (close(ns) < 0) {
122                 _E("close failed: %s", strerror(errno));
123         }
124 }
125
126 static void task_stat_socket_cb(void *user_data)
127 {
128         process_task_stats_answer(get_task_stats_sock(), proc_terminated, NULL);
129 }
130
131 static void proc_events_socket_cb(void *user_data)
132 {
133         process_proc_event_answer(get_proc_events_sock(), proc_forked, NULL);
134 }
135
136 static void proc_stat_store_timer_cb(void *user_data)
137 {
138         if (nlproc_stat_store() < 0) {
139                 _E("nlproc_stat_store failed");
140         }
141
142         _I("per-process statistics stored");
143 }
144
145 static void old_event_del_timer_cb(void *usr_data)
146 {
147         time_t t = time(NULL);
148
149         if (t == (time_t) -1) {
150                 _E("time failed: %s", strerror(errno));
151                 return;
152         }
153
154         if (delete_old_events(t - old_events_rotate_period) < 0) {
155                 _E("delete_old_events failed");
156         }
157
158         _I("old events deleted");
159 }
160
161 static int sec_till_new_day()
162 {
163         struct tm *tm;
164         time_t t;
165
166         time(&t);
167         tm = localtime(&t);
168         if (tm == NULL) {
169                 _E("localtime failed");
170                 return SEC_PER_DAY;
171         }
172
173         return SEC_PER_DAY - (tm->tm_sec + tm->tm_min * 60 + tm->tm_hour * 3600);
174 }
175
176 static void old_proc_power_cons_timer_cb(void *user_data)
177 {
178         int time_till_new_day = sec_till_new_day();
179         struct timer *timer = (struct timer *)user_data;
180
181         if (delete_old_proc() < 0) {
182                 _E("delete_old_proc failed");
183         }
184         _I("old cpu power cons deleted");
185
186         update_timer_exp(timer, time_till_new_day <= 10 ?
187                 SEC_PER_DAY - 10 + time_till_new_day : time_till_new_day);
188
189         return;
190 }
191
192 static int init_timers()
193 {
194         int ret;
195         struct socket_info *socket_info;
196
197         /* Timers */
198         proc_stat_store_timer = create_timer(proc_stat_store_period,
199                 proc_stat_store_timer_cb, NULL);
200         if (!proc_stat_store_timer) {
201                 _E("ecore_timer_add failed");
202         } else {
203                 socket_info = calloc(1, sizeof(struct socket_info));
204                 if (!socket_info) {
205                         ret = -errno;
206                         _E("calloc failed: %s", strerror(errno));
207                         return ret;
208                 }
209                 socket_info->cb = (void(*)(void*))process_timer;
210                 socket_info->user_data = proc_stat_store_timer;
211
212                 if (eina_hash_add(sockets, (void*)&proc_stat_store_timer->fd, socket_info) ==
213                         EINA_FALSE) {
214                         _E("eina_hash_add failed: %s", eina_error_msg_get(eina_error_get()));
215                         return -ENOMEM;
216                 }
217         }
218
219
220         old_event_del_timer = create_timer(old_events_del_period,
221                 old_event_del_timer_cb, NULL);
222         if (!old_event_del_timer) {
223                 _E("ecore_timer_add failed");
224         } else {
225                 socket_info = calloc(1, sizeof(struct socket_info));
226                 if (!socket_info) {
227                         ret = -errno;
228                         _E("calloc failed: %s", strerror(errno));
229                         return ret;
230                 }
231                 socket_info->cb = (void(*)(void*))process_timer;
232                 socket_info->user_data = old_event_del_timer;
233
234                 if (eina_hash_add(sockets, (void*)&old_event_del_timer->fd, socket_info) ==
235                         EINA_FALSE) {
236                         _E("eina_hash_add failed: %s", eina_error_msg_get(eina_error_get()));
237                         return -ENOMEM;
238                 }
239         }
240
241
242         old_proc_power_cons_timer = create_timer(sec_till_new_day() - 10,
243                 old_proc_power_cons_timer_cb, NULL);
244         if (!old_proc_power_cons_timer) {
245                 _E("ecore_timer_add failed");
246         } else {
247                 old_proc_power_cons_timer->user_data = old_proc_power_cons_timer;
248                 socket_info = calloc(1, sizeof(struct socket_info));
249                 if (!socket_info) {
250                         ret = -errno;
251                         _E("calloc failed: %s", strerror(errno));
252                         return ret;
253                 }
254                 socket_info->cb = (void(*)(void*))process_timer;
255                 socket_info->user_data = old_proc_power_cons_timer;
256
257                 if (eina_hash_add(sockets, (void*)&old_proc_power_cons_timer->fd, socket_info) ==
258                         EINA_FALSE) {
259                         _E("eina_hash_add failed: %s", eina_error_msg_get(eina_error_get()));
260                         return -ENOMEM;
261                 }
262         }
263
264         return 0;
265 }
266
267 void logd_event_loop(void *user_data, Ecore_Thread *th)
268 {
269         int max_fd = 0;
270         fd_set set;
271         void *data;
272         Eina_Iterator *it;
273
274         if (init_timers() < 0)
275                 _E("init_timers failed");
276
277         it = eina_hash_iterator_key_new(sockets);
278         while (eina_iterator_next(it, &data)) {
279                 int fd = *(int*)data;
280                 max_fd = max(max_fd, fd);
281         }
282         eina_iterator_free(it);
283
284         while (1) {
285                 FD_ZERO(&set);
286                 it = eina_hash_iterator_key_new(sockets);
287                 while (!ecore_thread_check(th) && eina_iterator_next(it, &data)) {
288                         int fd = *(int*)data;
289                         FD_SET(fd, &set);
290                 }
291                 eina_iterator_free(it);
292
293                 if (ecore_thread_check(th))
294                         break;
295
296                 select(max_fd + 1, &set, NULL, NULL, NULL);
297
298                 it = eina_hash_iterator_key_new(sockets);
299                 while (!ecore_thread_check(th) && eina_iterator_next(it, &data)) {
300                         int fd = *(int*)data;
301                         struct socket_info *info;
302
303                         if (FD_ISSET(fd, &set)) {
304                                 info = eina_hash_find(sockets, &fd);
305                                 if (info) {
306                                         info->cb(info->user_data);
307                                 } else {
308                                         _E("eina_hash_find failed: wrong fd");
309                                 }
310                         }
311
312                 }
313                 eina_iterator_free(it);
314                 if (ecore_thread_check(th))
315                         break;
316         }
317         _I("loop exited");
318 }
319
320
321 static int init_sockets()
322 {
323         int ret;
324         int event_socket;
325         int task_stat_socket;
326         int proc_events_socket;
327         struct socket_info *socket_info;
328
329         sockets = eina_hash_pointer_new(free);
330         if (!sockets) {
331                 _E("eina_hash_pointer_new failed");
332                 return -ENOMEM;
333         }
334
335         /* event_socket */
336         ret = jr_init();
337         CHECK_RET(ret, "jr_init");
338         event_socket = jr_get_socket();
339         if (event_socket <= 0) {
340                 _E("jr_get_socket returned wrong socket");
341                 return -ENOTSOCK;
342         }
343
344         socket_info = calloc(1, sizeof(struct socket_info));
345         if (!socket_info) {
346                 ret = -errno;
347                 _E("calloc failed: %s", strerror(errno));
348                 return ret;
349         }
350         socket_info->cb = event_socket_cb;
351
352         if (eina_hash_add(sockets, (void*)&event_socket, socket_info) ==
353                 EINA_FALSE) {
354                 _E("eina_hash_add failed: %s", eina_error_msg_get(eina_error_get()));
355                 return -ENOMEM;
356         }
357
358         /* API socket */
359         if ((api_socket = create_logd_socket()) < 0) {
360                 _E("create_logd_socket failed");
361                 return api_socket;
362         }
363
364         socket_info = calloc(1, sizeof(struct socket_info));
365         if (!socket_info) {
366                 ret = -errno;
367                 _E("calloc failed: %s", strerror(errno));
368                 return ret;
369         }
370         socket_info->cb = api_socket_cb;
371
372         if (eina_hash_add(sockets, (void*)&api_socket, socket_info) ==
373                 EINA_FALSE) {
374                 _E("eina_hash_add failed: %s", eina_error_msg_get(eina_error_get()));
375                 return -ENOMEM;
376         }
377
378         /* Task stat socket */
379         task_stat_socket = get_task_stats_sock();
380
381         socket_info = calloc(1, sizeof(struct socket_info));
382         if (!socket_info) {
383                 ret = -errno;
384                 _E("calloc failed: %s", strerror(errno));
385                 return ret;
386         }
387         socket_info->cb = task_stat_socket_cb;
388
389         if (eina_hash_add(sockets, (void*)&task_stat_socket, socket_info) ==
390                 EINA_FALSE) {
391                 _E("eina_hash_add failed: %s", eina_error_msg_get(eina_error_get()));
392                 return -ENOMEM;
393         }
394
395         /* Proc events socket */
396         proc_events_socket = get_proc_events_sock();
397
398         socket_info = calloc(1, sizeof(struct socket_info));
399         if (!socket_info) {
400                 ret = -errno;
401                 _E("calloc failed: %s", strerror(errno));
402                 return ret;
403         }
404         socket_info->cb = proc_events_socket_cb;
405
406         if (eina_hash_add(sockets, (void*)&proc_events_socket, socket_info) ==
407                 EINA_FALSE) {
408                 _E("eina_hash_add failed: %s", eina_error_msg_get(eina_error_get()));
409                 return -ENOMEM;
410         }
411
412         return 0;
413 }
414
415 static void logd_grabber_exit()
416 {
417         int ret;
418
419         if (!proc_stat_store_timer)
420                 delete_timer(proc_stat_store_timer);
421         if (!old_event_del_timer)
422                 delete_timer(old_event_del_timer);
423         if (!old_proc_power_cons_timer)
424                 delete_timer(old_proc_power_cons_timer);
425
426         if (sockets) {
427                 eina_hash_free(sockets);
428                 sockets = NULL;
429         }
430
431         ret = event_exit();
432         if (ret < 0) {
433                 _E("event_exit failed");
434         }
435 }
436
437 void logd_loop_cancel(void *user_data, Ecore_Thread *th)
438 {
439         _I("logd_loop_cancel called");
440         logd_grabber_exit();
441 }
442
443 static int logd_grabber_init()
444 {
445         int ret = 0;
446         const char *enable;
447
448         tzset();
449
450         ret = config_init();
451         if (ret < 0) {
452                 _E("config_init failed");
453                 return ret;
454         }
455         enable = config_get_string("enable_grabber", "yes", NULL);
456         if (strncmp(enable, "yes", 3)) {
457                 _I("disable logd_grabber");
458                 return ret;
459         }
460
461         log_init();
462
463         proc_stat_store_period =
464                 config_get_int("proc_stat_store_period", 30 * 60, NULL);
465         old_events_rotate_period =
466                 config_get_int("old_events_rotate_period", 60 * 60 *24 * 7, NULL);
467         old_events_del_period =
468                 config_get_int("old_events_del_period", 30 * 60, NULL);
469
470         ret = mmc_init();
471         if (ret < 0) {
472                 _E("mmc_init failed");
473                 return ret;
474         }
475
476         ret = display_init();
477         if (ret < 0) {
478                 _E("display_init failed");
479                 return ret;
480         }
481
482         ret = nlproc_stat_init();
483         if (ret < 0) {
484                 _E("nlproc_stat_init failed");
485                 return ret;
486         }
487
488         ret = battery_init();
489         if (ret < 0) {
490                 _E("battery_init failed");
491                 return ret;
492         }
493
494         ret = event_init();
495         if (ret < 0) {
496                 _E("event_init failed");
497                 return ret;
498         }
499
500         ret = init_sockets();
501         if (ret < 0) {
502                 _E("init_sockets failed");
503                 return ret;
504         }
505
506         logd_thread = ecore_thread_run(logd_event_loop,
507                         NULL, logd_loop_cancel, NULL);
508
509         return 0;
510 }
511
512
513 static void logd_init()
514 {
515         if (logd_grabber_init() < 0)
516                 _E("logd_grabber_init failed");
517 }
518
519 static void logd_exit()
520 {
521         if (logd_thread && !ecore_thread_check(logd_thread)) {
522                 ecore_thread_cancel(logd_thread);
523                 logd_thread = NULL;
524         }
525 }
526
527 static const struct device_ops logd_device_ops = {
528         .priority = DEVICE_PRIORITY_NORMAL,
529         .name     = "logd",
530         .init     = logd_init,
531         .exit     = logd_exit,
532 };
533
534 DEVICE_OPS_REGISTER(&logd_device_ops)