blob: c3cb7adc13462527c6f5b846a89e973dd4b00f4e [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
231LIBLOG_ABI_PUBLIC struct logger_list *android_logger_list_alloc(
232 int mode,
233 unsigned int tail,
234 pid_t pid)
235{
236 struct android_log_logger_list *logger_list;
237
238 logger_list = calloc(1, sizeof(*logger_list));
239 if (!logger_list) {
240 return NULL;
241 }
242
243 list_init(&logger_list->logger);
244 list_init(&logger_list->transport);
245 logger_list->mode = mode;
246 logger_list->tail = tail;
247 logger_list->pid = pid;
248
249 return (struct logger_list *)logger_list;
250}
251
252LIBLOG_ABI_PUBLIC struct logger_list *android_logger_list_alloc_time(
253 int mode,
254 log_time start,
255 pid_t pid)
256{
257 struct android_log_logger_list *logger_list;
258
259 logger_list = calloc(1, sizeof(*logger_list));
260 if (!logger_list) {
261 return NULL;
262 }
263
264 list_init(&logger_list->logger);
265 list_init(&logger_list->transport);
266 logger_list->mode = mode;
267 logger_list->start = start;
268 logger_list->pid = pid;
269
270 return (struct logger_list *)logger_list;
271}
272
273/* android_logger_list_register unimplemented, no use case */
274/* android_logger_list_unregister unimplemented, no use case */
275
276/* Open the named log and add it to the logger list */
277LIBLOG_ABI_PUBLIC struct logger *android_logger_open(
278 struct logger_list *logger_list,
279 log_id_t logId)
280{
281 struct android_log_logger_list *logger_list_internal =
282 (struct android_log_logger_list *)logger_list;
283 struct android_log_logger *logger;
284
285 if (!logger_list_internal || (logId >= LOG_ID_MAX)) {
286 goto err;
287 }
288
289 logger_for_each(logger, logger_list_internal) {
290 if (logger->logId == logId) {
291 goto ok;
292 }
293 }
294
295 logger = calloc(1, sizeof(*logger));
296 if (!logger) {
297 goto err;
298 }
299
300 logger->logId = logId;
301 list_add_tail(&logger_list_internal->logger, &logger->node);
302 logger->parent = logger_list_internal;
303
304 /* Reset known transports to re-evaluate, we just added one */
305 while (!list_empty(&logger_list_internal->transport)) {
306 struct listnode *node = list_head(&logger_list_internal->transport);
307 struct android_log_transport_context *transp =
308 node_to_item(node, struct android_log_transport_context, node);
309
310 list_remove(&transp->node);
311 free(transp);
312 }
313 goto ok;
314
315err:
316 logger = NULL;
317ok:
318 return (struct logger *)logger;
319}
320
321/* Open the single named log and make it part of a new logger list */
322LIBLOG_ABI_PUBLIC struct logger_list *android_logger_list_open(
323 log_id_t logId,
324 int mode,
325 unsigned int tail,
326 pid_t pid)
327{
328 struct logger_list *logger_list =
329 android_logger_list_alloc(mode, tail, pid);
330
331 if (!logger_list) {
332 return NULL;
333 }
334
335 if (!android_logger_open(logger_list, logId)) {
336 android_logger_list_free(logger_list);
337 return NULL;
338 }
339
340 return logger_list;
341}
342
Mark Salyzyn8fd1faa2016-05-13 12:25:55 -0700343/* Validate log_msg packet, read function has already been null checked */
344static int android_transport_read(struct android_log_logger_list *logger_list,
345 struct android_log_transport_context *transp,
346 struct log_msg *log_msg)
347{
348 int ret = (*transp->transport->read)(logger_list, transp, log_msg);
349
350 if (ret > (int)sizeof(*log_msg)) {
351 ret = sizeof(*log_msg);
352 }
353
354 transp->ret = ret;
355
356 /* propagate errors, or make sure len & hdr_size members visible */
357 if (ret < (int)(sizeof(log_msg->entry.len) +
358 sizeof(log_msg->entry.hdr_size))) {
359 if (ret >= (int)sizeof(log_msg->entry.len)) {
360 log_msg->entry.len = 0;
361 }
362 return ret;
363 }
364
365 /* hdr_size correction (logger_entry -> logger_entry_v2+ conversion) */
366 if (log_msg->entry_v2.hdr_size == 0) {
367 log_msg->entry_v2.hdr_size = sizeof(struct logger_entry);
368 }
Mark Salyzyn305374c2016-08-18 14:59:41 -0700369 if ((log_msg->entry_v2.hdr_size < sizeof(log_msg->entry_v1)) ||
370 (log_msg->entry_v2.hdr_size > sizeof(log_msg->entry))) {
371 return -EINVAL;
372 }
Mark Salyzyn8fd1faa2016-05-13 12:25:55 -0700373
374 /* len validation */
375 if (ret <= log_msg->entry_v2.hdr_size) {
376 log_msg->entry.len = 0;
377 } else {
378 log_msg->entry.len = ret - log_msg->entry_v2.hdr_size;
379 }
380
381 return ret;
382}
383
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800384/* Read from the selected logs */
385LIBLOG_ABI_PUBLIC int android_logger_list_read(struct logger_list *logger_list,
386 struct log_msg *log_msg)
387{
388 struct android_log_transport_context *transp;
389 struct android_log_logger_list *logger_list_internal =
390 (struct android_log_logger_list *)logger_list;
391
392 int ret = init_transport_context(logger_list_internal);
393 if (ret < 0) {
394 return ret;
395 }
396
397 /* at least one transport */
398 transp = node_to_item(logger_list_internal->transport.next,
399 struct android_log_transport_context, node);
400
401 /* more than one transport? */
402 if (transp->node.next != &logger_list_internal->transport) {
403 /* Poll and merge sort the entries if from multiple transports */
404 struct android_log_transport_context *oldest = NULL;
405 int ret;
406 int polled = 0;
407 do {
408 if (polled) {
409 sched_yield();
410 }
411 ret = -1000;
412 polled = 0;
413 do {
414 int retval = transp->ret;
415 if ((retval > 0) && !transp->logMsg.entry.len) {
416 if (!transp->transport->read) {
417 retval = transp->ret = 0;
418 } else if ((logger_list_internal->mode &
419 ANDROID_LOG_NONBLOCK) ||
420 !transp->transport->poll) {
Mark Salyzyn8fd1faa2016-05-13 12:25:55 -0700421 retval = android_transport_read(
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800422 logger_list_internal,
423 transp,
424 &transp->logMsg);
425 } else {
426 int pollval = (*transp->transport->poll)(
427 logger_list_internal, transp);
428 if (pollval <= 0) {
429 sched_yield();
430 pollval = (*transp->transport->poll)(
431 logger_list_internal, transp);
432 }
433 polled = 1;
434 if (pollval < 0) {
435 if ((pollval == -EINTR) || (pollval == -EAGAIN)) {
436 return -EAGAIN;
437 }
438 retval = transp->ret = pollval;
439 } else if (pollval > 0) {
Mark Salyzyn8fd1faa2016-05-13 12:25:55 -0700440 retval = android_transport_read(
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800441 logger_list_internal,
442 transp,
443 &transp->logMsg);
444 }
445 }
446 }
447 if (ret < retval) {
448 ret = retval;
449 }
450 if ((transp->ret > 0) && transp->logMsg.entry.len &&
451 (!oldest ||
452 (oldest->logMsg.entry.sec >
453 transp->logMsg.entry.sec) ||
454 ((oldest->logMsg.entry.sec ==
455 transp->logMsg.entry.sec) &&
456 (oldest->logMsg.entry.nsec >
457 transp->logMsg.entry.nsec)))) {
458 oldest = transp;
459 }
460 transp = node_to_item(transp->node.next,
461 struct android_log_transport_context,
462 node);
463 } while (transp != node_to_item(
464 &logger_list_internal->transport,
465 struct android_log_transport_context,
466 node));
467 if (!oldest &&
468 (logger_list_internal->mode & ANDROID_LOG_NONBLOCK)) {
469 return (ret < 0) ? ret : -EAGAIN;
470 }
471 transp = node_to_item(logger_list_internal->transport.next,
472 struct android_log_transport_context, node);
473 } while (!oldest && (ret > 0));
474 if (!oldest) {
475 return ret;
476 }
Mark Salyzyn8fd1faa2016-05-13 12:25:55 -0700477 // ret is a positive value less than sizeof(struct log_msg)
478 ret = oldest->ret;
479 if (ret < oldest->logMsg.entry.hdr_size) {
480 // zero truncated header fields.
481 memset(log_msg, 0,
482 (oldest->logMsg.entry.hdr_size > sizeof(oldest->logMsg) ?
483 sizeof(oldest->logMsg) :
484 oldest->logMsg.entry.hdr_size));
485 }
486 memcpy(log_msg, &oldest->logMsg, ret);
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800487 oldest->logMsg.entry.len = 0; /* Mark it as copied */
Mark Salyzyn8fd1faa2016-05-13 12:25:55 -0700488 return ret;
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800489 }
490
491 /* if only one, no need to copy into transport_context and merge-sort */
Mark Salyzyn8fd1faa2016-05-13 12:25:55 -0700492 return android_transport_read(logger_list_internal, transp, log_msg);
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800493}
494
495/* Close all the logs */
496LIBLOG_ABI_PUBLIC void android_logger_list_free(struct logger_list *logger_list)
497{
498 struct android_log_logger_list *logger_list_internal =
499 (struct android_log_logger_list *)logger_list;
500
501 if (logger_list_internal == NULL) {
502 return;
503 }
504
505 while (!list_empty(&logger_list_internal->transport)) {
506 struct listnode *node = list_head(&logger_list_internal->transport);
507 struct android_log_transport_context *transp =
508 node_to_item(node, struct android_log_transport_context, node);
509
510 if (transp->transport && transp->transport->close) {
511 (*transp->transport->close)(logger_list_internal, transp);
512 }
513 list_remove(&transp->node);
514 free(transp);
515 }
516
517 while (!list_empty(&logger_list_internal->logger)) {
518 struct listnode *node = list_head(&logger_list_internal->logger);
519 struct android_log_logger *logger =
520 node_to_item(node, struct android_log_logger, node);
521 android_logger_free((struct logger *)logger);
522 }
523
524 free(logger_list_internal);
525}