1 #include "reader_logger.h"
2 #include "reader_common.h"
3 #include "logger_internal.h"
5 #include <buffer_traits.h>
10 static void *reader_logger_thread(void *userdata);
12 static void free_reader_logger(struct reader_common *_reader)
14 struct reader_logger *const reader = (struct reader_logger *) _reader;
17 list_remove(&_reader->server->readers, reader);
19 if (reader->device_fd != -1)
20 close(reader->device_fd);
23 static void handle_single_log(struct reader_logger *reader, struct now_t time, int read_count)
26 assert(read_count > 0);
28 if (reader->skip_count > 0) {
29 reader->skip_count -= read_count;
33 struct android_logger_entry *const ale = (struct android_logger_entry *) reader->read_buffer;
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. */
39 } else if (read_count == sizeof *ale) {
41 /* Invalid entry. Likely a kernel bug.
42 * At any rate, not salvageable. */
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. */
54 reader->read_buffer[read_count] = '\0';
56 struct dlogutil_entry_with_msg entry;
57 parse_androidlogger_message(ale, &entry.header, read_count);
58 add_recv_timestamp(&entry.header, time);
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));
63 // Ignore intermittent write failures. Not a reason to remove the reader.
64 (void) reader_apply_log_to_subs(&reader->common, &entry.header);
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
75 static int service_reader_logger(struct reader_common *_reader, struct now_t time)
77 struct reader_logger *const reader = (struct reader_logger *) _reader;
81 int r = TEMP_FAILURE_RETRY(read(reader->device_fd, reader->read_buffer, sizeof reader->read_buffer - 1));
85 if (errno == EAGAIN) // no data left in the buffer
91 handle_single_log(reader, time, r);
97 static struct reader_logger *reader_logger_alloc(struct logger *server)
99 struct reader_logger *const ret = calloc(1, sizeof *ret);
103 /* The reader nominally belongs to the server,
104 * but is mostly handled by its own thread. */
105 reader_common_init(&ret->common, server);
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;
116 int reader_logger_init(struct reader_logger **reader, log_id_t buf_id, struct logger *server, bool skip)
119 assert(buf_id > LOG_ID_INVALID);
120 assert(buf_id < LOG_ID_MAX);
121 assert(is_core_buffer(buf_id));
123 __attribute__((cleanup(reader_free_ptr))) struct reader_logger *ret = reader_logger_alloc(server);
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)
131 ret->buf_id = buf_id;
133 int r = logger_open_buffer(buf_id, config_list, O_RDONLY | O_NONBLOCK, &ret->device_fd);
137 ret->skip_count = skip ? logger_get_log_len(ret->device_fd) : 0;
144 static void service_and_maybe_flush(struct reader_logger *const reader)
147 int r = get_now(&now);
151 r = reader->common.service_reader(&reader->common, now);
155 (void) reader_flush(&reader->common, now.mono, reader->common.server->buf_params.time);
158 static void *reader_logger_thread(void *userdata)
160 struct reader_logger *reader = (struct reader_logger *) userdata;
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;
168 while (!reader->common.server->sigmar->exit_signal_received) {
169 int r = poll(fds, NELEMS(fds), reader->common.server->epolltime);
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 */
184 service_and_maybe_flush(reader);
187 service_and_maybe_flush(reader);