e390edd9d5c021c4d5e0253bbec2681d7c9b925b
[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 #include <buffer_traits.h>
6
7 #include <assert.h>
8 #include <poll.h>
9
10 static void *reader_logger_thread(void *userdata);
11
12 static void free_reader_logger(struct reader_common *_reader)
13 {
14         struct reader_logger *const reader = (struct reader_logger *) _reader;
15
16         if (_reader->server)
17                 list_remove(&_reader->server->readers, reader);
18
19         if (reader->device_fd != -1)
20                 close(reader->device_fd);
21 }
22
23 static void handle_single_log(struct reader_logger *reader, struct now_t time, int read_count)
24 {
25         assert(reader);
26         assert(read_count > 0);
27
28         if (reader->skip_count > 0) {
29                 reader->skip_count -= read_count;
30                 return;
31         }
32
33         struct android_logger_entry *const ale = (struct android_logger_entry *) reader->read_buffer;
34
35         if (read_count < sizeof *ale) {
36                 /* This should not happen, but don't treat this as a hard
37                  * invariant because kernel bugs happen. Not salvageable. */
38                 return;
39         } else if (read_count == sizeof *ale) {
40                 if (ale->len != 0) {
41                         /* Invalid entry. Likely a kernel bug.
42                          * At any rate, not salvageable. */
43                         return;
44                 } else {
45                         /* A "valid" empty entry. Is probably
46                          * salvageable (so that the information
47                          * that a program tried to log something
48                          * and the relevant timestamp are not
49                          * completely lost). Maybe later though. */
50                         return;
51                 }
52         }
53
54         reader->read_buffer[read_count] = '\0';
55
56         struct dlogutil_entry_with_msg entry;
57         parse_androidlogger_message(ale, &entry.header, read_count);
58         add_recv_timestamp(&entry.header, time);
59
60         // TODO: Consider calling this in a more robust way (and not having pipe in the name)
61         fixup_pipe_msg(&entry, read_count - sizeof(*ale));
62
63         // Ignore intermittent write failures. Not a reason to remove the reader.
64         (void) reader_apply_log_to_subs(&reader->common, &entry.header);
65 }
66
67 /**
68  * @brief Service reader file
69  * @details Handles readers reading directly from file
70  * @param[in] reader The reader to service
71  * @param[in] time Timestamps
72  * @return 0 on success, else an errno value
73  * @return 1 if the reader is to be removed, 0 if kept, -errno on error
74  */
75 static int service_reader_logger(struct reader_common *_reader, struct now_t time)
76 {
77         struct reader_logger *const reader = (struct reader_logger *) _reader;
78         assert(reader);
79
80         while (true) {
81                 int r = TEMP_FAILURE_RETRY(read(reader->device_fd, reader->read_buffer, sizeof reader->read_buffer - 1));
82                 if (r == 0)
83                         break;
84                 else if (r == -1) {
85                         if (errno == EAGAIN) // no data left in the buffer
86                                 break;
87                         else
88                                 return -errno;
89                 }
90
91                 handle_single_log(reader, time, r);
92         }
93
94         return 0;
95 }
96
97 static struct reader_logger *reader_logger_alloc(struct logger *server)
98 {
99         struct reader_logger *const ret = calloc(1, sizeof *ret);
100         if (!ret)
101                 return NULL;
102
103         /* The reader nominally belongs to the server,
104          * but is mostly handled by its own thread. */
105         reader_common_init(&ret->common, server);
106
107         ret->device_fd = -1;
108         ret->buf_id = LOG_ID_INVALID;
109         ret->common.thread_func = reader_logger_thread;
110         ret->common.service_reader = service_reader_logger;
111         ret->common.free_reader = free_reader_logger;
112
113         return ret;
114 }
115
116 int reader_logger_init(struct reader_logger **reader, log_id_t buf_id, struct logger *server, bool skip)
117 {
118         assert(reader);
119         assert(buf_id > LOG_ID_INVALID);
120         assert(buf_id < LOG_ID_MAX);
121         assert(is_core_buffer(buf_id));
122
123         __attribute__((cleanup(reader_free_ptr))) struct reader_logger *ret = reader_logger_alloc(server);
124         if (!ret)
125                 return -ENOMEM;
126
127         assert(buf_id >= 0 && (unsigned) buf_id < NELEMS(g_backend.logger_devices));
128         char const *config_list = g_backend.logger_devices[buf_id];
129         if (strlen(config_list) == 0)
130                 return -ENOENT;
131         ret->buf_id = buf_id;
132
133         int r = logger_open_buffer(buf_id, config_list, O_RDONLY | O_NONBLOCK, &ret->device_fd);
134         if (r <= 0)
135                 return r;
136
137         ret->skip_count = skip ? logger_get_log_len(ret->device_fd) : 0;
138
139         *reader = ret;
140         ret = NULL;
141         return 0;
142 }
143
144 static void service_and_maybe_flush(struct reader_logger *const reader)
145 {
146         struct now_t now;
147         int r = get_now(&now);
148         if (r < 0)
149                 return;
150
151         r = reader->common.service_reader(&reader->common, now);
152         if (r > 0)
153                 return;
154
155         (void) reader_flush(&reader->common, now.mono, reader->common.server->buf_params.time);
156 }
157
158 static void *reader_logger_thread(void *userdata)
159 {
160         struct reader_logger *reader = (struct reader_logger *) userdata;
161
162         struct pollfd fds[2];
163         fds[0].fd = reader->device_fd;
164         fds[0].events = POLLIN;
165         fds[1].fd = reader->common.server->sigmar->wakeup_fde.fd;
166         fds[1].events = POLLIN;
167
168         while (!reader->common.server->sigmar->exit_signal_received) {
169                 int r = poll(fds, NELEMS(fds), reader->common.server->epolltime);
170                 if (r < 0) {
171                         if (errno == EINTR)
172                                 continue;
173
174                         /* In theory we spin here; in practice memory
175                          * gets overcommitted and mistakes are sorted
176                          * by the OOM killer, so spinning is unlikely */
177                         if (errno == ENOMEM)
178                                 continue;
179
180                         assert(false);
181                         break;
182                 }
183
184                 service_and_maybe_flush(reader);
185         }
186
187         service_and_maybe_flush(reader);
188         return NULL;
189 }
190