blob: f15c7cd6235501a5c8b02f420a3844c90e60d25a [file] [log] [blame]
Mark Salyzynfacf94c2016-03-01 13:45:42 -08001/*
2** Copyright 2013-2014, The Android Open Source Project
3**
4** Licensed under the Apache License, Version 2.0 (the "License");
5** you may not use this file except in compliance with the License.
6** You may obtain a copy of the License at
7**
8** http://www.apache.org/licenses/LICENSE-2.0
9**
10** Unless required by applicable law or agreed to in writing, software
11** distributed under the License is distributed on an "AS IS" BASIS,
12** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13** See the License for the specific language governing permissions and
14** limitations under the License.
15*/
16
17#include <errno.h>
18#include <fcntl.h>
19#include <pthread.h>
20#include <sched.h>
21#include <stddef.h>
22#include <stdlib.h>
23#include <string.h>
24#include <unistd.h>
25
26#include <cutils/list.h>
27#include <log/log.h>
28#include <log/logger.h>
29
30#include "config_read.h"
31#include "log_portability.h"
32#include "logger.h"
33
34/* android_logger_alloc unimplemented, no use case */
35/* android_logger_free not exported */
36static void android_logger_free(struct logger *logger)
37{
38 struct android_log_logger *logger_internal =
39 (struct android_log_logger *)logger;
40
41 if (!logger_internal) {
42 return;
43 }
44
45 list_remove(&logger_internal->node);
46
47 free(logger_internal);
48}
49
50/* android_logger_alloc unimplemented, no use case */
51
52/* method for getting the associated sublog id */
53LIBLOG_ABI_PUBLIC log_id_t android_logger_get_id(struct logger *logger)
54{
55 return ((struct android_log_logger *)logger)->logId;
56}
57
58static int init_transport_context(struct android_log_logger_list *logger_list)
59{
60 struct android_log_transport_read *transport;
61 struct listnode *node;
62
63 if (!logger_list) {
64 return -EINVAL;
65 }
66
67 if (list_empty(&logger_list->logger)) {
68 return -EINVAL;
69 }
70
71 if (!list_empty(&logger_list->transport)) {
72 return 0;
73 }
74
75 __android_log_lock();
76 /* mini __write_to_log_initialize() to populate transports */
77 if (list_empty(&__android_log_transport_read) &&
78 list_empty(&__android_log_persist_read)) {
79 __android_log_config_read();
80 }
81 __android_log_unlock();
82
83 node = (logger_list->mode & ANDROID_LOG_PSTORE) ?
84 &__android_log_persist_read : &__android_log_transport_read;
85
86 read_transport_for_each(transport, node) {
87 struct android_log_transport_context *transp;
88 struct android_log_logger *logger;
89 unsigned logMask = 0;
90
91 logger_for_each(logger, logger_list) {
92 log_id_t logId = logger->logId;
93
94 if (transport->read &&
95 (!transport->available ||
96 (transport->available(logId) >= 0))) {
97 logMask |= 1 << logId;
98 }
99 }
100 if (!logMask) {
101 continue;
102 }
103 transp = calloc(1, sizeof(*transp));
104 if (!transp) {
105 return -ENOMEM;
106 }
107 transp->parent = logger_list;
108 transp->transport = transport;
109 transp->logMask = logMask;
110 transp->ret = 1;
111 list_add_tail(&logger_list->transport, &transp->node);
112 }
113 if (list_empty(&logger_list->transport)) {
114 return -ENODEV;
115 }
116 return 0;
117}
118
119#define LOGGER_FUNCTION(logger, def, func, args...) \
120 ssize_t ret = -EINVAL; \
121 struct android_log_transport_context *transp; \
122 struct android_log_logger *logger_internal = \
123 (struct android_log_logger *)logger; \
124 \
125 if (!logger_internal) { \
126 return ret; \
127 } \
128 ret = init_transport_context(logger_internal->parent); \
129 if (ret < 0) { \
130 return ret; \
131 } \
132 \
133 ret = (def); \
134 transport_context_for_each(transp, logger_internal->parent) { \
135 if ((transp->logMask & (1 << logger_internal->logId)) && \
136 transp->transport && transp->transport->func) { \
137 ssize_t retval = (transp->transport->func)(logger_internal, \
138 transp, ## args); \
139 if ((ret >= 0) || (ret == (def))) { \
140 ret = retval; \
141 } \
142 } \
143 } \
144 return ret
145
146LIBLOG_ABI_PUBLIC int android_logger_clear(struct logger *logger)
147{
148 LOGGER_FUNCTION(logger, -ENODEV, clear);
149}
150
151/* returns the total size of the log's ring buffer */
152LIBLOG_ABI_PUBLIC long android_logger_get_log_size(struct logger *logger)
153{
154 LOGGER_FUNCTION(logger, -ENODEV, getSize);
155}
156
157LIBLOG_ABI_PUBLIC int android_logger_set_log_size(struct logger *logger,
158 unsigned long size)
159{
160 LOGGER_FUNCTION(logger, -ENODEV, setSize, size);
161}
162
163/*
164 * returns the readable size of the log's ring buffer (that is, amount of the
165 * log consumed)
166 */
167LIBLOG_ABI_PUBLIC long android_logger_get_log_readable_size(
168 struct logger *logger)
169{
170 LOGGER_FUNCTION(logger, -ENODEV, getReadableSize);
171}
172
173/*
174 * returns the logger version
175 */
176LIBLOG_ABI_PUBLIC int android_logger_get_log_version(struct logger *logger)
177{
178 LOGGER_FUNCTION(logger, 4, version);
179}
180
181#define LOGGER_LIST_FUNCTION(logger_list, def, func, args...) \
182 struct android_log_transport_context *transp; \
183 struct android_log_logger_list *logger_list_internal = \
184 (struct android_log_logger_list *)logger_list; \
185 \
186 ssize_t ret = init_transport_context(logger_list_internal); \
187 if (ret < 0) { \
188 return ret; \
189 } \
190 \
191 ret = (def); \
192 transport_context_for_each(transp, logger_list_internal) { \
193 if (transp->transport && (transp->transport->func)) { \
194 ssize_t retval = (transp->transport->func)(logger_list_internal, \
195 transp, ## args); \
196 if ((ret >= 0) || (ret == (def))) { \
197 ret = retval; \
198 } \
199 } \
200 } \
201 return ret
202
203/*
204 * returns statistics
205 */
206LIBLOG_ABI_PUBLIC ssize_t android_logger_get_statistics(
207 struct logger_list *logger_list,
208 char *buf, size_t len)
209{
210 LOGGER_LIST_FUNCTION(logger_list, -ENODEV, getStats, buf, len);
211}
212
213LIBLOG_ABI_PUBLIC ssize_t android_logger_get_prune_list(
214 struct logger_list *logger_list,
215 char *buf, size_t len)
216{
217 LOGGER_LIST_FUNCTION(logger_list, -ENODEV, getPrune, buf, len);
218}
219
220LIBLOG_ABI_PUBLIC int android_logger_set_prune_list(
221 struct logger_list *logger_list,
222 char *buf, size_t len)
223{
224 LOGGER_LIST_FUNCTION(logger_list, -ENODEV, setPrune, buf, len);
225}
226
227LIBLOG_ABI_PUBLIC struct logger_list *android_logger_list_alloc(
228 int mode,
229 unsigned int tail,
230 pid_t pid)
231{
232 struct android_log_logger_list *logger_list;
233
234 logger_list = calloc(1, sizeof(*logger_list));
235 if (!logger_list) {
236 return NULL;
237 }
238
239 list_init(&logger_list->logger);
240 list_init(&logger_list->transport);
241 logger_list->mode = mode;
242 logger_list->tail = tail;
243 logger_list->pid = pid;
244
245 return (struct logger_list *)logger_list;
246}
247
248LIBLOG_ABI_PUBLIC struct logger_list *android_logger_list_alloc_time(
249 int mode,
250 log_time start,
251 pid_t pid)
252{
253 struct android_log_logger_list *logger_list;
254
255 logger_list = calloc(1, sizeof(*logger_list));
256 if (!logger_list) {
257 return NULL;
258 }
259
260 list_init(&logger_list->logger);
261 list_init(&logger_list->transport);
262 logger_list->mode = mode;
263 logger_list->start = start;
264 logger_list->pid = pid;
265
266 return (struct logger_list *)logger_list;
267}
268
269/* android_logger_list_register unimplemented, no use case */
270/* android_logger_list_unregister unimplemented, no use case */
271
272/* Open the named log and add it to the logger list */
273LIBLOG_ABI_PUBLIC struct logger *android_logger_open(
274 struct logger_list *logger_list,
275 log_id_t logId)
276{
277 struct android_log_logger_list *logger_list_internal =
278 (struct android_log_logger_list *)logger_list;
279 struct android_log_logger *logger;
280
281 if (!logger_list_internal || (logId >= LOG_ID_MAX)) {
282 goto err;
283 }
284
285 logger_for_each(logger, logger_list_internal) {
286 if (logger->logId == logId) {
287 goto ok;
288 }
289 }
290
291 logger = calloc(1, sizeof(*logger));
292 if (!logger) {
293 goto err;
294 }
295
296 logger->logId = logId;
297 list_add_tail(&logger_list_internal->logger, &logger->node);
298 logger->parent = logger_list_internal;
299
300 /* Reset known transports to re-evaluate, we just added one */
301 while (!list_empty(&logger_list_internal->transport)) {
302 struct listnode *node = list_head(&logger_list_internal->transport);
303 struct android_log_transport_context *transp =
304 node_to_item(node, struct android_log_transport_context, node);
305
306 list_remove(&transp->node);
307 free(transp);
308 }
309 goto ok;
310
311err:
312 logger = NULL;
313ok:
314 return (struct logger *)logger;
315}
316
317/* Open the single named log and make it part of a new logger list */
318LIBLOG_ABI_PUBLIC struct logger_list *android_logger_list_open(
319 log_id_t logId,
320 int mode,
321 unsigned int tail,
322 pid_t pid)
323{
324 struct logger_list *logger_list =
325 android_logger_list_alloc(mode, tail, pid);
326
327 if (!logger_list) {
328 return NULL;
329 }
330
331 if (!android_logger_open(logger_list, logId)) {
332 android_logger_list_free(logger_list);
333 return NULL;
334 }
335
336 return logger_list;
337}
338
339/* Read from the selected logs */
340LIBLOG_ABI_PUBLIC int android_logger_list_read(struct logger_list *logger_list,
341 struct log_msg *log_msg)
342{
343 struct android_log_transport_context *transp;
344 struct android_log_logger_list *logger_list_internal =
345 (struct android_log_logger_list *)logger_list;
346
347 int ret = init_transport_context(logger_list_internal);
348 if (ret < 0) {
349 return ret;
350 }
351
352 /* at least one transport */
353 transp = node_to_item(logger_list_internal->transport.next,
354 struct android_log_transport_context, node);
355
356 /* more than one transport? */
357 if (transp->node.next != &logger_list_internal->transport) {
358 /* Poll and merge sort the entries if from multiple transports */
359 struct android_log_transport_context *oldest = NULL;
360 int ret;
361 int polled = 0;
362 do {
363 if (polled) {
364 sched_yield();
365 }
366 ret = -1000;
367 polled = 0;
368 do {
369 int retval = transp->ret;
370 if ((retval > 0) && !transp->logMsg.entry.len) {
371 if (!transp->transport->read) {
372 retval = transp->ret = 0;
373 } else if ((logger_list_internal->mode &
374 ANDROID_LOG_NONBLOCK) ||
375 !transp->transport->poll) {
376 retval = transp->ret = (*transp->transport->read)(
377 logger_list_internal,
378 transp,
379 &transp->logMsg);
380 } else {
381 int pollval = (*transp->transport->poll)(
382 logger_list_internal, transp);
383 if (pollval <= 0) {
384 sched_yield();
385 pollval = (*transp->transport->poll)(
386 logger_list_internal, transp);
387 }
388 polled = 1;
389 if (pollval < 0) {
390 if ((pollval == -EINTR) || (pollval == -EAGAIN)) {
391 return -EAGAIN;
392 }
393 retval = transp->ret = pollval;
394 } else if (pollval > 0) {
395 retval = transp->ret = (*transp->transport->read)(
396 logger_list_internal,
397 transp,
398 &transp->logMsg);
399 }
400 }
401 }
402 if (ret < retval) {
403 ret = retval;
404 }
405 if ((transp->ret > 0) && transp->logMsg.entry.len &&
406 (!oldest ||
407 (oldest->logMsg.entry.sec >
408 transp->logMsg.entry.sec) ||
409 ((oldest->logMsg.entry.sec ==
410 transp->logMsg.entry.sec) &&
411 (oldest->logMsg.entry.nsec >
412 transp->logMsg.entry.nsec)))) {
413 oldest = transp;
414 }
415 transp = node_to_item(transp->node.next,
416 struct android_log_transport_context,
417 node);
418 } while (transp != node_to_item(
419 &logger_list_internal->transport,
420 struct android_log_transport_context,
421 node));
422 if (!oldest &&
423 (logger_list_internal->mode & ANDROID_LOG_NONBLOCK)) {
424 return (ret < 0) ? ret : -EAGAIN;
425 }
426 transp = node_to_item(logger_list_internal->transport.next,
427 struct android_log_transport_context, node);
428 } while (!oldest && (ret > 0));
429 if (!oldest) {
430 return ret;
431 }
432 memcpy(log_msg, &oldest->logMsg, oldest->logMsg.entry.len +
433 (oldest->logMsg.entry.hdr_size ?
434 oldest->logMsg.entry.hdr_size :
435 sizeof(struct logger_entry)));
436 oldest->logMsg.entry.len = 0; /* Mark it as copied */
437 return oldest->ret;
438 }
439
440 /* if only one, no need to copy into transport_context and merge-sort */
441 return (transp->transport->read)(logger_list_internal, transp, log_msg);
442}
443
444/* Close all the logs */
445LIBLOG_ABI_PUBLIC void android_logger_list_free(struct logger_list *logger_list)
446{
447 struct android_log_logger_list *logger_list_internal =
448 (struct android_log_logger_list *)logger_list;
449
450 if (logger_list_internal == NULL) {
451 return;
452 }
453
454 while (!list_empty(&logger_list_internal->transport)) {
455 struct listnode *node = list_head(&logger_list_internal->transport);
456 struct android_log_transport_context *transp =
457 node_to_item(node, struct android_log_transport_context, node);
458
459 if (transp->transport && transp->transport->close) {
460 (*transp->transport->close)(logger_list_internal, transp);
461 }
462 list_remove(&transp->node);
463 free(transp);
464 }
465
466 while (!list_empty(&logger_list_internal->logger)) {
467 struct listnode *node = list_head(&logger_list_internal->logger);
468 struct android_log_logger *logger =
469 node_to_item(node, struct android_log_logger, node);
470 android_logger_free((struct logger *)logger);
471 }
472
473 free(logger_list_internal);
474}