blob: 7e50a23fe73cef6773eb7192c3f5334b74483559 [file] [log] [blame]
Mark Salyzyn018a96d2016-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
Mark Salyzyn6584d0a2016-09-28 13:26:55 -070026#include <android/log.h>
Mark Salyzyn018a96d2016-03-01 13:45:42 -080027#include <cutils/list.h>
Mark Salyzync33103c2016-03-28 16:20:29 -070028#include <private/android_filesystem_config.h>
Mark Salyzyn018a96d2016-03-01 13:45:42 -080029
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
Mark Salyzync33103c2016-03-28 16:20:29 -070094 if ((logId == LOG_ID_SECURITY) &&
95 (__android_log_uid() != AID_SYSTEM)) {
96 continue;
97 }
Mark Salyzyn018a96d2016-03-01 13:45:42 -080098 if (transport->read &&
99 (!transport->available ||
100 (transport->available(logId) >= 0))) {
101 logMask |= 1 << logId;
102 }
103 }
104 if (!logMask) {
105 continue;
106 }
107 transp = calloc(1, sizeof(*transp));
108 if (!transp) {
109 return -ENOMEM;
110 }
111 transp->parent = logger_list;
112 transp->transport = transport;
113 transp->logMask = logMask;
114 transp->ret = 1;
115 list_add_tail(&logger_list->transport, &transp->node);
116 }
117 if (list_empty(&logger_list->transport)) {
118 return -ENODEV;
119 }
120 return 0;
121}
122
123#define LOGGER_FUNCTION(logger, def, func, args...) \
124 ssize_t ret = -EINVAL; \
125 struct android_log_transport_context *transp; \
126 struct android_log_logger *logger_internal = \
Chih-Hung Hsiehf0f94fe2016-05-18 15:47:19 -0700127 (struct android_log_logger *)(logger); \
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800128 \
129 if (!logger_internal) { \
130 return ret; \
131 } \
132 ret = init_transport_context(logger_internal->parent); \
133 if (ret < 0) { \
134 return ret; \
135 } \
136 \
137 ret = (def); \
138 transport_context_for_each(transp, logger_internal->parent) { \
139 if ((transp->logMask & (1 << logger_internal->logId)) && \
140 transp->transport && transp->transport->func) { \
141 ssize_t retval = (transp->transport->func)(logger_internal, \
142 transp, ## args); \
143 if ((ret >= 0) || (ret == (def))) { \
144 ret = retval; \
145 } \
146 } \
147 } \
148 return ret
149
150LIBLOG_ABI_PUBLIC int android_logger_clear(struct logger *logger)
151{
152 LOGGER_FUNCTION(logger, -ENODEV, clear);
153}
154
155/* returns the total size of the log's ring buffer */
156LIBLOG_ABI_PUBLIC long android_logger_get_log_size(struct logger *logger)
157{
158 LOGGER_FUNCTION(logger, -ENODEV, getSize);
159}
160
161LIBLOG_ABI_PUBLIC int android_logger_set_log_size(struct logger *logger,
162 unsigned long size)
163{
164 LOGGER_FUNCTION(logger, -ENODEV, setSize, size);
165}
166
167/*
168 * returns the readable size of the log's ring buffer (that is, amount of the
169 * log consumed)
170 */
171LIBLOG_ABI_PUBLIC long android_logger_get_log_readable_size(
172 struct logger *logger)
173{
174 LOGGER_FUNCTION(logger, -ENODEV, getReadableSize);
175}
176
177/*
178 * returns the logger version
179 */
180LIBLOG_ABI_PUBLIC int android_logger_get_log_version(struct logger *logger)
181{
182 LOGGER_FUNCTION(logger, 4, version);
183}
184
185#define LOGGER_LIST_FUNCTION(logger_list, def, func, args...) \
186 struct android_log_transport_context *transp; \
187 struct android_log_logger_list *logger_list_internal = \
Chih-Hung Hsiehf0f94fe2016-05-18 15:47:19 -0700188 (struct android_log_logger_list *)(logger_list); \
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800189 \
190 ssize_t ret = init_transport_context(logger_list_internal); \
191 if (ret < 0) { \
192 return ret; \
193 } \
194 \
195 ret = (def); \
196 transport_context_for_each(transp, logger_list_internal) { \
197 if (transp->transport && (transp->transport->func)) { \
198 ssize_t retval = (transp->transport->func)(logger_list_internal, \
199 transp, ## args); \
200 if ((ret >= 0) || (ret == (def))) { \
201 ret = retval; \
202 } \
203 } \
204 } \
205 return ret
206
207/*
208 * returns statistics
209 */
210LIBLOG_ABI_PUBLIC ssize_t android_logger_get_statistics(
211 struct logger_list *logger_list,
212 char *buf, size_t len)
213{
214 LOGGER_LIST_FUNCTION(logger_list, -ENODEV, getStats, buf, len);
215}
216
217LIBLOG_ABI_PUBLIC ssize_t android_logger_get_prune_list(
218 struct logger_list *logger_list,
219 char *buf, size_t len)
220{
221 LOGGER_LIST_FUNCTION(logger_list, -ENODEV, getPrune, buf, len);
222}
223
224LIBLOG_ABI_PUBLIC int android_logger_set_prune_list(
225 struct logger_list *logger_list,
226 char *buf, size_t len)
227{
228 LOGGER_LIST_FUNCTION(logger_list, -ENODEV, setPrune, buf, len);
229}
230
Mark Salyzyncf983bc2016-03-08 16:18:26 -0800231LIBLOG_HIDDEN struct listnode __android_log_readers =
232 { &__android_log_readers, &__android_log_readers };
233#if !defined(_WIN32)
234LIBLOG_HIDDEN pthread_rwlock_t __android_log_readers_lock =
235 PTHREAD_RWLOCK_INITIALIZER;
236#endif
237
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800238LIBLOG_ABI_PUBLIC struct logger_list *android_logger_list_alloc(
239 int mode,
240 unsigned int tail,
241 pid_t pid)
242{
243 struct android_log_logger_list *logger_list;
244
245 logger_list = calloc(1, sizeof(*logger_list));
246 if (!logger_list) {
247 return NULL;
248 }
249
250 list_init(&logger_list->logger);
251 list_init(&logger_list->transport);
252 logger_list->mode = mode;
253 logger_list->tail = tail;
254 logger_list->pid = pid;
255
Mark Salyzyncf983bc2016-03-08 16:18:26 -0800256 logger_list_wrlock();
257 list_add_tail(&__android_log_readers, &logger_list->node);
258 logger_list_unlock();
259
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800260 return (struct logger_list *)logger_list;
261}
262
263LIBLOG_ABI_PUBLIC struct logger_list *android_logger_list_alloc_time(
264 int mode,
265 log_time start,
266 pid_t pid)
267{
268 struct android_log_logger_list *logger_list;
269
270 logger_list = calloc(1, sizeof(*logger_list));
271 if (!logger_list) {
272 return NULL;
273 }
274
275 list_init(&logger_list->logger);
276 list_init(&logger_list->transport);
277 logger_list->mode = mode;
278 logger_list->start = start;
279 logger_list->pid = pid;
280
Mark Salyzyncf983bc2016-03-08 16:18:26 -0800281 logger_list_wrlock();
282 list_add_tail(&__android_log_readers, &logger_list->node);
283 logger_list_unlock();
284
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800285 return (struct logger_list *)logger_list;
286}
287
288/* android_logger_list_register unimplemented, no use case */
289/* android_logger_list_unregister unimplemented, no use case */
290
291/* Open the named log and add it to the logger list */
292LIBLOG_ABI_PUBLIC struct logger *android_logger_open(
293 struct logger_list *logger_list,
294 log_id_t logId)
295{
296 struct android_log_logger_list *logger_list_internal =
297 (struct android_log_logger_list *)logger_list;
298 struct android_log_logger *logger;
299
300 if (!logger_list_internal || (logId >= LOG_ID_MAX)) {
301 goto err;
302 }
303
304 logger_for_each(logger, logger_list_internal) {
305 if (logger->logId == logId) {
306 goto ok;
307 }
308 }
309
310 logger = calloc(1, sizeof(*logger));
311 if (!logger) {
312 goto err;
313 }
314
315 logger->logId = logId;
316 list_add_tail(&logger_list_internal->logger, &logger->node);
317 logger->parent = logger_list_internal;
318
319 /* Reset known transports to re-evaluate, we just added one */
320 while (!list_empty(&logger_list_internal->transport)) {
321 struct listnode *node = list_head(&logger_list_internal->transport);
322 struct android_log_transport_context *transp =
323 node_to_item(node, struct android_log_transport_context, node);
324
325 list_remove(&transp->node);
326 free(transp);
327 }
328 goto ok;
329
330err:
331 logger = NULL;
332ok:
333 return (struct logger *)logger;
334}
335
336/* Open the single named log and make it part of a new logger list */
337LIBLOG_ABI_PUBLIC struct logger_list *android_logger_list_open(
338 log_id_t logId,
339 int mode,
340 unsigned int tail,
341 pid_t pid)
342{
343 struct logger_list *logger_list =
344 android_logger_list_alloc(mode, tail, pid);
345
346 if (!logger_list) {
347 return NULL;
348 }
349
350 if (!android_logger_open(logger_list, logId)) {
351 android_logger_list_free(logger_list);
352 return NULL;
353 }
354
355 return logger_list;
356}
357
Mark Salyzyn8fd1faa2016-05-13 12:25:55 -0700358/* Validate log_msg packet, read function has already been null checked */
359static int android_transport_read(struct android_log_logger_list *logger_list,
360 struct android_log_transport_context *transp,
361 struct log_msg *log_msg)
362{
363 int ret = (*transp->transport->read)(logger_list, transp, log_msg);
364
365 if (ret > (int)sizeof(*log_msg)) {
366 ret = sizeof(*log_msg);
367 }
368
369 transp->ret = ret;
370
371 /* propagate errors, or make sure len & hdr_size members visible */
372 if (ret < (int)(sizeof(log_msg->entry.len) +
373 sizeof(log_msg->entry.hdr_size))) {
374 if (ret >= (int)sizeof(log_msg->entry.len)) {
375 log_msg->entry.len = 0;
376 }
377 return ret;
378 }
379
380 /* hdr_size correction (logger_entry -> logger_entry_v2+ conversion) */
381 if (log_msg->entry_v2.hdr_size == 0) {
382 log_msg->entry_v2.hdr_size = sizeof(struct logger_entry);
383 }
Mark Salyzyn305374c2016-08-18 14:59:41 -0700384 if ((log_msg->entry_v2.hdr_size < sizeof(log_msg->entry_v1)) ||
385 (log_msg->entry_v2.hdr_size > sizeof(log_msg->entry))) {
386 return -EINVAL;
387 }
Mark Salyzyn8fd1faa2016-05-13 12:25:55 -0700388
389 /* len validation */
390 if (ret <= log_msg->entry_v2.hdr_size) {
391 log_msg->entry.len = 0;
392 } else {
393 log_msg->entry.len = ret - log_msg->entry_v2.hdr_size;
394 }
395
396 return ret;
397}
398
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800399/* Read from the selected logs */
400LIBLOG_ABI_PUBLIC int android_logger_list_read(struct logger_list *logger_list,
401 struct log_msg *log_msg)
402{
403 struct android_log_transport_context *transp;
404 struct android_log_logger_list *logger_list_internal =
405 (struct android_log_logger_list *)logger_list;
406
407 int ret = init_transport_context(logger_list_internal);
408 if (ret < 0) {
409 return ret;
410 }
411
412 /* at least one transport */
413 transp = node_to_item(logger_list_internal->transport.next,
414 struct android_log_transport_context, node);
415
416 /* more than one transport? */
417 if (transp->node.next != &logger_list_internal->transport) {
418 /* Poll and merge sort the entries if from multiple transports */
419 struct android_log_transport_context *oldest = NULL;
420 int ret;
421 int polled = 0;
422 do {
423 if (polled) {
424 sched_yield();
425 }
426 ret = -1000;
427 polled = 0;
428 do {
429 int retval = transp->ret;
430 if ((retval > 0) && !transp->logMsg.entry.len) {
431 if (!transp->transport->read) {
432 retval = transp->ret = 0;
433 } else if ((logger_list_internal->mode &
434 ANDROID_LOG_NONBLOCK) ||
435 !transp->transport->poll) {
Mark Salyzyn8fd1faa2016-05-13 12:25:55 -0700436 retval = android_transport_read(
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800437 logger_list_internal,
438 transp,
439 &transp->logMsg);
440 } else {
441 int pollval = (*transp->transport->poll)(
442 logger_list_internal, transp);
443 if (pollval <= 0) {
444 sched_yield();
445 pollval = (*transp->transport->poll)(
446 logger_list_internal, transp);
447 }
448 polled = 1;
449 if (pollval < 0) {
450 if ((pollval == -EINTR) || (pollval == -EAGAIN)) {
451 return -EAGAIN;
452 }
453 retval = transp->ret = pollval;
454 } else if (pollval > 0) {
Mark Salyzyn8fd1faa2016-05-13 12:25:55 -0700455 retval = android_transport_read(
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800456 logger_list_internal,
457 transp,
458 &transp->logMsg);
459 }
460 }
461 }
462 if (ret < retval) {
463 ret = retval;
464 }
465 if ((transp->ret > 0) && transp->logMsg.entry.len &&
466 (!oldest ||
467 (oldest->logMsg.entry.sec >
468 transp->logMsg.entry.sec) ||
469 ((oldest->logMsg.entry.sec ==
470 transp->logMsg.entry.sec) &&
471 (oldest->logMsg.entry.nsec >
472 transp->logMsg.entry.nsec)))) {
473 oldest = transp;
474 }
475 transp = node_to_item(transp->node.next,
476 struct android_log_transport_context,
477 node);
478 } while (transp != node_to_item(
479 &logger_list_internal->transport,
480 struct android_log_transport_context,
481 node));
482 if (!oldest &&
483 (logger_list_internal->mode & ANDROID_LOG_NONBLOCK)) {
484 return (ret < 0) ? ret : -EAGAIN;
485 }
486 transp = node_to_item(logger_list_internal->transport.next,
487 struct android_log_transport_context, node);
488 } while (!oldest && (ret > 0));
489 if (!oldest) {
490 return ret;
491 }
Mark Salyzyn8fd1faa2016-05-13 12:25:55 -0700492 // ret is a positive value less than sizeof(struct log_msg)
493 ret = oldest->ret;
494 if (ret < oldest->logMsg.entry.hdr_size) {
495 // zero truncated header fields.
496 memset(log_msg, 0,
497 (oldest->logMsg.entry.hdr_size > sizeof(oldest->logMsg) ?
498 sizeof(oldest->logMsg) :
499 oldest->logMsg.entry.hdr_size));
500 }
501 memcpy(log_msg, &oldest->logMsg, ret);
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800502 oldest->logMsg.entry.len = 0; /* Mark it as copied */
Mark Salyzyn8fd1faa2016-05-13 12:25:55 -0700503 return ret;
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800504 }
505
506 /* if only one, no need to copy into transport_context and merge-sort */
Mark Salyzyn8fd1faa2016-05-13 12:25:55 -0700507 return android_transport_read(logger_list_internal, transp, log_msg);
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800508}
509
510/* Close all the logs */
511LIBLOG_ABI_PUBLIC void android_logger_list_free(struct logger_list *logger_list)
512{
513 struct android_log_logger_list *logger_list_internal =
514 (struct android_log_logger_list *)logger_list;
515
516 if (logger_list_internal == NULL) {
517 return;
518 }
519
Mark Salyzyncf983bc2016-03-08 16:18:26 -0800520 logger_list_wrlock();
521 list_remove(&logger_list_internal->node);
522 logger_list_unlock();
523
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800524 while (!list_empty(&logger_list_internal->transport)) {
525 struct listnode *node = list_head(&logger_list_internal->transport);
526 struct android_log_transport_context *transp =
527 node_to_item(node, struct android_log_transport_context, node);
528
529 if (transp->transport && transp->transport->close) {
530 (*transp->transport->close)(logger_list_internal, transp);
531 }
532 list_remove(&transp->node);
533 free(transp);
534 }
535
536 while (!list_empty(&logger_list_internal->logger)) {
537 struct listnode *node = list_head(&logger_list_internal->logger);
538 struct android_log_logger *logger =
539 node_to_item(node, struct android_log_logger, node);
540 android_logger_free((struct logger *)logger);
541 }
542
543 free(logger_list_internal);
544}