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