1 #include "reader_logger.h"
2 #include "reader_common.h"
3 #include "logger_internal.h"
5 static void free_reader_logger(struct reader_common *reader)
7 /* Nothing to cleanup. The Android Logger reader
8 * does everything via sub-readers. */
11 static void handle_single_log(struct reader_logger *reader, struct now_t time, int read_count)
14 assert(read_count > 0);
16 if (reader->skip_count > 0) {
17 reader->skip_count -= read_count;
21 struct android_logger_entry *const ale = (struct android_logger_entry *) reader->read_buffer;
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. */
27 } else if (read_count == sizeof *ale) {
29 /* Invalid entry. Likely a kernel bug.
30 * At any rate, not salvageable. */
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. */
42 reader->read_buffer[read_count] = '\0';
44 struct dlogutil_entry_with_msg entry;
45 parse_androidlogger_message(ale, &entry.header, read_count);
46 add_recv_timestamp(&entry.header, time);
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));
51 // Ignore intermittent write failures. Not a reason to remove the reader.
52 (void) reader_apply_log_to_subs(&reader->common, &entry.header);
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
63 static int service_reader_logger(struct reader_common *_reader, struct now_t time)
65 struct reader_logger *const reader = (struct reader_logger *) _reader;
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));
81 if (errno == EAGAIN) // no data left in the buffer
87 handle_single_log(reader, time, r);
93 static struct reader_logger *reader_logger_alloc(void)
95 struct reader_logger *const ret = calloc(1, sizeof *ret);
99 reader_common_init(&ret->common);
101 ret->buf_id = LOG_ID_INVALID;
102 ret->common.service_reader = service_reader_logger;
103 ret->common.free_reader = free_reader_logger;
108 static void dispatch_event_reader_logger(struct logger *server, struct epoll_event *event, void *userdata)
110 struct reader_logger *const rl = (struct reader_logger *) userdata;
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);
121 int r = get_now(&now);
123 return; // Don't remove the reader, not its fault.
125 r = service_reader_logger(&rl->common, now);
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);
133 int reader_logger_init(struct reader_logger **reader, log_id_t buf_id, struct logger *server, bool skip)
136 assert(buf_id > LOG_ID_INVALID);
137 assert(buf_id < LOG_ID_MAX);
138 assert(is_core_buffer(buf_id));
141 __attribute__((cleanup(reader_free_ptr))) struct reader_logger *ret = reader_logger_alloc();
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)
149 ret->buf_id = buf_id;
152 int r = logger_open_buffer(buf_id, config_list, O_RDONLY | O_NONBLOCK, &read_fd);
156 ret->skip_count = skip ? logger_get_log_len(read_fd) : 0;
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);