d06138722f016e85b0dfa5430f1844689ea1b6de
[platform/core/system/dlog.git] / src / logger / reader_logger.c
1 #include "reader_logger.h"
2 #include "reader_common.h"
3 #include "logger_internal.h"
4
5 static void free_reader_logger(struct reader_common *reader)
6 {
7         /* Nothing to cleanup. The Android Logger reader
8          * does everything via sub-readers. */
9 }
10
11 static void handle_single_log(struct reader_logger *reader, struct now_t time, int read_count)
12 {
13         assert(reader);
14         assert(read_count > 0);
15
16         if (reader->skip_count > 0) {
17                 reader->skip_count -= read_count;
18                 return;
19         }
20
21         struct android_logger_entry *const ale = (struct android_logger_entry *) reader->read_buffer;
22
23         if (read_count < sizeof *ale) {
24                 /* This should not happen, but don't treat this as a hard
25                  * invariant because kernel bugs happen. Not salvageable. */
26                 return;
27         } else if (read_count == sizeof *ale) {
28                 if (ale->len != 0) {
29                         /* Invalid entry. Likely a kernel bug.
30                          * At any rate, not salvageable. */
31                         return;
32                 } else {
33                         /* A "valid" empty entry. Is probably
34                          * salvageable (so that the information
35                          * that a program tried to log something
36                          * and the relevant timestamp are not
37                          * completely lost). Maybe later though. */
38                         return;
39                 }
40         }
41
42         reader->read_buffer[read_count] = '\0';
43
44         struct dlogutil_entry_with_msg entry;
45         parse_androidlogger_message(ale, &entry.header, read_count);
46         add_recv_timestamp(&entry.header, time);
47
48         // TODO: Consider calling this in a more robust way (and not having pipe in the name)
49         fixup_pipe_msg(&entry, read_count - sizeof(*ale));
50
51         // Ignore intermittent write failures. Not a reason to remove the reader.
52         (void) reader_apply_log_to_subs(&reader->common, &entry.header);
53 }
54
55 /**
56  * @brief Service reader file
57  * @details Handles readers reading directly from file
58  * @param[in] reader The reader to service
59  * @param[in] time Timestamps
60  * @return 0 on success, else an errno value
61  * @return 1 if the reader is to be removed, 0 if kept, -errno on error
62  */
63 static int service_reader_logger(struct reader_common *_reader, struct now_t time)
64 {
65         struct reader_logger *const reader = (struct reader_logger *) _reader;
66         assert(reader);
67
68         /* The devices for the Android Logger only return one log per read().
69          * So using an 'if' here would be wasteful and, more importantly, too slow in the case where other logs come in.
70          * However, with an unlimited loop, if there are extreme amounts of logs incoming,
71          * the loop handles them slower than they come so the program stays in the loop
72          * for a very long time, starving all other log sources. Using a limited loop
73          * makes sure that the daemon works efficiently in the usual case while preventing
74          * starvation under heavy load. */
75         int max_loop_iterations = g_backend.logger_device_throttling[reader->buf_id];
76         while (max_loop_iterations--) {
77                 int r = TEMP_FAILURE_RETRY(read(reader->common.fd_entity_source.fd, reader->read_buffer, sizeof reader->read_buffer - 1));
78                 if (r == 0)
79                         break;
80                 else if (r == -1) {
81                         if (errno == EAGAIN) // no data left in the buffer
82                                 break;
83                         else
84                                 return -errno;
85                 }
86
87                 handle_single_log(reader, time, r);
88         }
89
90         return 0;
91 }
92
93 static struct reader_logger *reader_logger_alloc(void)
94 {
95         struct reader_logger *const ret = calloc(1, sizeof *ret);
96         if (!ret)
97                 return NULL;
98
99         reader_common_init(&ret->common);
100
101         ret->buf_id = LOG_ID_INVALID;
102         ret->common.service_reader = service_reader_logger;
103         ret->common.free_reader = free_reader_logger;
104
105         return ret;
106 }
107
108 static void dispatch_event_reader_logger(struct logger *server, struct epoll_event *event, void *userdata)
109 {
110         struct reader_logger *const rl = (struct reader_logger *) userdata;
111         assert(rl);
112
113         if (event->events & (EPOLLHUP | EPOLLERR)) {
114                 remove_reader_fd_entities(server, &rl->common);
115                 list_remove(&server->readers_logger, rl);
116                 reader_free(&rl->common);
117                 return;
118         }
119
120         struct now_t now;
121         int r = get_now(&now);
122         if (r < 0)
123                 return; // Don't remove the reader, not its fault.
124
125         r = service_reader_logger(&rl->common, now);
126         if (r != 0) {
127                 /* TODO: There is no reason not to free the reader in full. However, when I do so, some tests start to
128                  * fail without any reasonable reason. You are welcome to *try* to figure out why does this happen. */
129                 remove_reader_fd_entities(server, &rl->common);
130         }
131 }
132
133 int reader_logger_init(struct reader_logger **reader, log_id_t buf_id, struct logger *server, bool skip)
134 {
135         assert(reader);
136         assert(buf_id > LOG_ID_INVALID);
137         assert(buf_id < LOG_ID_MAX);
138         assert(is_core_buffer(buf_id));
139         assert(server);
140
141         __attribute__((cleanup(reader_free_ptr))) struct reader_logger *ret = reader_logger_alloc();
142         if (!ret)
143                 return -ENOMEM;
144
145         assert(buf_id >= 0 && (unsigned) buf_id < NELEMS(g_backend.logger_devices));
146         char const *config_list = g_backend.logger_devices[buf_id];
147         if (strlen(config_list) == 0)
148                 return -ENOENT;
149         ret->buf_id = buf_id;
150
151         int read_fd = -1;
152         int r = logger_open_buffer(buf_id, config_list, O_RDONLY | O_NONBLOCK, &read_fd);
153         if (r <= 0)
154                 return r;
155
156         ret->skip_count = skip ? logger_get_log_len(read_fd) : 0;
157
158         init_fd_entity(&ret->common.fd_entity_sink, dispatch_event_reader_logger, ret);
159         init_fd_entity(&ret->common.fd_entity_source, dispatch_event_reader_logger, ret);
160         set_read_fd_entity(&ret->common.fd_entity_source, read_fd);
161
162         *reader = ret;
163         ret = NULL;
164         return 0;
165 }
166