blob: d504342ea6c2a473d0a1db7f28195ae192fb656e [file] [log] [blame]
Mark Salyzyn71002882016-03-08 16:18:26 -08001/*
2 * Copyright (C) 2017 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#if !defined(__MINGW32__)
21#include <pwd.h>
22#endif
23#include <sched.h>
24#include <stdlib.h>
25#include <string.h>
26#include <sys/types.h>
27#include <log/uio.h>
28
29#include <cutils/list.h> /* template, no library dependency */
30#include <log/log_frontend.h>
31#include <private/android_filesystem_config.h>
32#include <private/android_logger.h>
33#include <system/thread_defs.h>
34
35#include "config_read.h"
36#include "config_write.h"
37#include "log_portability.h"
38#include "logger.h"
39
40static const char baseServiceName[] = "android.logd";
41
42static int writeToLocalInit();
43static int writeToLocalAvailable(log_id_t logId);
44static void writeToLocalReset();
45static int writeToLocalWrite(log_id_t logId, struct timespec *ts,
46 struct iovec *vec, size_t nr);
47
48LIBLOG_HIDDEN struct android_log_transport_write localLoggerWrite = {
49 .node = { &localLoggerWrite.node, &localLoggerWrite.node },
50 .context.private = NULL,
51 .name = "local",
52 .available = writeToLocalAvailable,
53 .open = writeToLocalInit,
54 .close = writeToLocalReset,
55 .write = writeToLocalWrite,
56};
57
58static int writeToLocalVersion(struct android_log_logger *logger,
59 struct android_log_transport_context *transp);
60static int writeToLocalRead(struct android_log_logger_list *logger_list,
61 struct android_log_transport_context *transp,
62 struct log_msg *log_msg);
63static int writeToLocalPoll(struct android_log_logger_list *logger_list,
64 struct android_log_transport_context *transp);
65static void writeToLocalClose(struct android_log_logger_list *logger_list,
66 struct android_log_transport_context *transp);
67static int writeToLocalClear(struct android_log_logger *logger,
68 struct android_log_transport_context *transp);
69static ssize_t writeToLocalGetSize(
70 struct android_log_logger *logger,
71 struct android_log_transport_context *transp);
72static ssize_t writeToLocalSetSize(
73 struct android_log_logger *logger,
74 struct android_log_transport_context *transp __unused,
75 size_t size);
76static ssize_t writeToLocalGetReadbleSize(
77 struct android_log_logger *logger,
78 struct android_log_transport_context *transp);
79
80struct android_log_transport_read localLoggerRead = {
81 .node = { &localLoggerRead.node, &localLoggerRead.node },
82 .name = "local",
83 .available = writeToLocalAvailable,
84 .version = writeToLocalVersion,
85 .read = writeToLocalRead,
86 .poll = writeToLocalPoll,
87 .close = writeToLocalClose,
88 .clear = writeToLocalClear,
89 .getSize = writeToLocalGetSize,
90 .setSize = writeToLocalSetSize,
91 .getReadableSize = writeToLocalGetReadbleSize,
92 .getPrune = NULL,
93 .setPrune = NULL,
94 .getStats = NULL,
95};
96
97struct LogBufferElement {
98 struct listnode node;
99 log_id_t logId;
100 pid_t tid;
101 log_time timestamp;
102 unsigned short len;
103 char msg[];
104};
105
106static const size_t MAX_SIZE_DEFAULT = 32768;
107
108/*
109 * Number of log buffers we support with the following assumption:
110 * . . .
111 * LOG_ID_SECURITY = 5, // security logs go to the system logs only
112 * LOG_ID_KERNEL = 6, // place last, third-parties can not use it
113 * LOG_ID_MAX
114 * } log_id_t;
115 *
116 * Confirm the following should <log/log_id.h> be adjusted in the future.
117 */
118#define NUMBER_OF_LOG_BUFFERS ((LOG_ID_SECURITY == (LOG_ID_MAX - 2)) ? \
119 LOG_ID_SECURITY : \
120 LOG_ID_KERNEL)
121#define BLOCK_LOG_BUFFERS(id) (((id) == LOG_ID_SECURITY) || \
122 ((id) == LOG_ID_KERNEL))
123
124static struct LogBuffer {
125 struct listnode head;
126 pthread_rwlock_t listLock;
127 char *serviceName; /* Also indicates ready by having a value */
128 /* Order and proximity important for memset */
129 size_t number[NUMBER_OF_LOG_BUFFERS]; /* clear memset */
130 size_t size[NUMBER_OF_LOG_BUFFERS]; /* clear memset */
131 size_t totalSize[NUMBER_OF_LOG_BUFFERS]; /* init memset */
132 size_t maxSize[NUMBER_OF_LOG_BUFFERS]; /* init MAX_SIZE_DEFAULT */
133 struct listnode *last[NUMBER_OF_LOG_BUFFERS]; /* init &head */
134} logbuf = {
135 .head = { &logbuf.head, &logbuf.head },
136 .listLock = PTHREAD_RWLOCK_INITIALIZER,
137};
138
139static void LogBufferInit(struct LogBuffer *log) {
140 size_t i;
141
142 pthread_rwlock_wrlock(&log->listLock);
143 list_init(&log->head);
144 memset(log->number, 0,
145 sizeof(log->number) + sizeof(log->size) + sizeof(log->totalSize));
146 for (i = 0; i < NUMBER_OF_LOG_BUFFERS; ++i) {
147 log->maxSize[i] = MAX_SIZE_DEFAULT;
148 log->last[i] = &log->head;
149 }
150#ifdef __BIONIC__
151 asprintf(&log->serviceName, "%s@%d:%d", baseServiceName,
152 __android_log_uid(), getpid());
153#else
154 char buffer[sizeof(baseServiceName) + 1 + 5 + 1 + 5 + 8];
155 snprintf(buffer, sizeof(buffer), "%s@%d:%d", baseServiceName,
156 __android_log_uid(), getpid());
157 log->serviceName = strdup(buffer);
158#endif
159 pthread_rwlock_unlock(&log->listLock);
160}
161
162static void LogBufferClear(struct LogBuffer *log) {
163 size_t i;
164 struct listnode *node;
165
166 pthread_rwlock_wrlock(&log->listLock);
167 memset(log->number, 0, sizeof(log->number) + sizeof(log->size));
168 for (i = 0; i < NUMBER_OF_LOG_BUFFERS; ++i) {
169 log->last[i] = &log->head;
170 }
171 while ((node = list_head(&log->head)) != &log->head) {
172 struct LogBufferElement *element;
173
174 element = node_to_item(node, struct LogBufferElement, node);
175 list_remove(node);
176 free(element);
177 }
178 pthread_rwlock_unlock(&log->listLock);
179}
180
181static inline void LogBufferFree(struct LogBuffer *log) {
182 pthread_rwlock_wrlock(&log->listLock);
183 free(log->serviceName);
184 log->serviceName = NULL;
185 pthread_rwlock_unlock(&log->listLock);
186 LogBufferClear(log);
187}
188
189static int LogBufferLog(struct LogBuffer *log,
190 struct LogBufferElement *element) {
191 log_id_t logId = element->logId;
192
193 pthread_rwlock_wrlock(&log->listLock);
194 log->number[logId]++;
195 log->size[logId] += element->len;
196 log->totalSize[logId] += element->len;
197 /* prune entry(s) until enough space is available */
198 if (log->last[logId] == &log->head) {
199 log->last[logId] = list_tail(&log->head);
200 }
201 while (log->size[logId] > log->maxSize[logId]) {
202 struct listnode *node = log->last[logId];
203 struct LogBufferElement *e;
204 struct android_log_logger_list *logger_list;
205
206 e = node_to_item(node, struct LogBufferElement, node);
207 log->number[logId]--;
208 log->size[logId] -= e->len;
209 logger_list_rdlock();
210 logger_list_for_each(logger_list) {
211 struct android_log_transport_context *transp;
212
213 transport_context_for_each(transp, logger_list) {
214 if ((transp->transport == &localLoggerRead) &&
215 (transp->context.node == node)) {
216 if (node == &log->head) {
217 transp->context.node = &log->head;
218 } else {
219 transp->context.node = node->next;
220 }
221 }
222 }
223 }
224 logger_list_unlock();
225 if (node != &log->head) {
226 log->last[logId] = node->prev;
227 }
228 list_remove(node);
229 free(e);
230 }
231 /* add entry to list */
232 list_add_head(&log->head, &element->node);
233 /* ToDo: wake up all readers */
234 pthread_rwlock_unlock(&log->listLock);
235
236 return element->len;
237}
238
239/*
240 * return zero if permitted to log directly to logd,
241 * return 1 if binder server started and
242 * return negative error number if failed to start binder server.
243 */
244static int writeToLocalInit() {
245 pthread_attr_t attr;
246 struct LogBuffer *log;
247
248 if (writeToLocalAvailable(LOG_ID_MAIN) < 0) {
249 return -EPERM;
250 }
251
252 log = &logbuf;
253 if (!log->serviceName) {
254 LogBufferInit(log);
255 }
256
257 if (!log->serviceName) {
258 LogBufferFree(log);
259 return -ENOMEM;
260 }
261
262 return EPERM; /* successful local-only logging */
263}
264
265static void writeToLocalReset() {
266 LogBufferFree(&logbuf);
267}
268
269static int writeToLocalAvailable(log_id_t logId) {
270#if !defined(__MINGW32__)
271 uid_t uid;
272#endif
273
274 if ((logId >= NUMBER_OF_LOG_BUFFERS) || BLOCK_LOG_BUFFERS(logId)) {
275 return -EINVAL;
276 }
277
278 /* Android hard coded permitted, system goes to logd */
279#if !defined(__MINGW32__)
280 if (__android_log_frontend == LOGGER_DEFAULT) {
281 uid = __android_log_uid();
282 if ((uid < AID_APP) && (getpwuid(uid) != NULL)) {
283 return -EPERM;
284 }
285 }
286#endif
287
288 /* ToDo: Ask package manager for LOGD permissions */
289 /* Assume we do _not_ have permissions to go to LOGD, so must go local */
290 return 0;
291}
292
293static int writeToLocalWrite(log_id_t logId, struct timespec *ts,
294 struct iovec *vec, size_t nr) {
295 size_t len, i;
296 struct LogBufferElement *element;
297
298 if ((logId >= NUMBER_OF_LOG_BUFFERS) || BLOCK_LOG_BUFFERS(logId)) {
299 return -EINVAL;
300 }
301
302 len = 0;
303 for (i = 0; i < nr; ++i) {
304 len += vec[i].iov_len;
305 }
306
307 if (len > LOGGER_ENTRY_MAX_PAYLOAD) {
308 len = LOGGER_ENTRY_MAX_PAYLOAD;
309 }
310 element = (struct LogBufferElement *)calloc(1,
311 sizeof(struct LogBufferElement) + len + 1);
312 if (!element) {
313 return errno ? -errno : -ENOMEM;
314 }
315 element->timestamp.tv_sec = ts->tv_sec;
316 element->timestamp.tv_nsec = ts->tv_nsec;
317#ifdef __BIONIC__
318 element->tid = gettid();
319#else
320 element->tid = getpid();
321#endif
322 element->logId = logId;
323 element->len = len;
324
325 char *cp = element->msg;
326 for (i = 0; i < nr; ++i) {
327 size_t iov_len = vec[i].iov_len;
328 if (iov_len > len) {
329 iov_len = len;
330 }
331 memcpy(cp, vec[i].iov_base, iov_len);
332 len -= iov_len;
333 if (len == 0) {
334 break;
335 }
336 cp += iov_len;
337 }
338
339 return LogBufferLog(&logbuf, element);
340}
341
342static int writeToLocalVersion(
343 struct android_log_logger *logger __unused,
344 struct android_log_transport_context *transp __unused) {
345 return 3;
346}
347
348/* within reader lock, serviceName already validated */
349static struct listnode *writeToLocalNode(
350 struct android_log_logger_list *logger_list,
351 struct android_log_transport_context *transp) {
352 struct listnode *node;
353 unsigned logMask;
354 unsigned int tail;
355
356 node = transp->context.node;
357 if (node) {
358 return node;
359 }
360
361 if (!logger_list->tail) {
362 return transp->context.node = &logbuf.head;
363 }
364
365 logMask = transp->logMask;
366 tail = logger_list->tail;
367
368 for (node = list_head(&logbuf.head); node != &logbuf.head; node = node->next) {
369 struct LogBufferElement *element;
370 log_id_t logId;
371
372 element = node_to_item(node, struct LogBufferElement, node);
373 logId = element->logId;
374
375 if ((logMask & (1 << logId)) && !--tail) {
376 node = node->next;
377 break;
378 }
379 }
380 return transp->context.node = node;
381}
382
383static int writeToLocalRead(
384 struct android_log_logger_list *logger_list,
385 struct android_log_transport_context *transp,
386 struct log_msg *log_msg) {
387 int ret;
388 struct listnode *node;
389 unsigned logMask;
390
391 pthread_rwlock_rdlock(&logbuf.listLock);
392 if (!logbuf.serviceName) {
393 pthread_rwlock_unlock(&logbuf.listLock);
394 return (logger_list->mode & ANDROID_LOG_NONBLOCK) ? -ENODEV : 0;
395 }
396
397 logMask = transp->logMask;
398
399 node = writeToLocalNode(logger_list, transp);
400
401 ret = 0;
402
403 while (node != list_head(&logbuf.head)) {
404 struct LogBufferElement *element;
405 log_id_t logId;
406
407 node = node->prev;
408 element = node_to_item(node, struct LogBufferElement, node);
409 logId = element->logId;
410
411 if (logMask & (1 << logId)) {
412 ret = log_msg->entry_v3.len = element->len;
413 log_msg->entry_v3.hdr_size = sizeof(log_msg->entry_v3);
414 log_msg->entry_v3.pid = getpid();
415 log_msg->entry_v3.tid = element->tid;
416 log_msg->entry_v3.sec = element->timestamp.tv_sec;
417 log_msg->entry_v3.nsec = element->timestamp.tv_nsec;
418 log_msg->entry_v3.lid = logId;
419 memcpy(log_msg->entry_v3.msg, element->msg, ret);
420 ret += log_msg->entry_v3.hdr_size;
421 break;
422 }
423 }
424
425 transp->context.node = node;
426
427 /* ToDo: if blocking, and no entry, put reader to sleep */
428 pthread_rwlock_unlock(&logbuf.listLock);
429 return ret;
430}
431
432static int writeToLocalPoll(
433 struct android_log_logger_list *logger_list,
434 struct android_log_transport_context *transp) {
435 int ret = (logger_list->mode & ANDROID_LOG_NONBLOCK) ? -ENODEV : 0;
436
437 pthread_rwlock_rdlock(&logbuf.listLock);
438
439 if (logbuf.serviceName) {
440 unsigned logMask = transp->logMask;
441 struct listnode *node = writeToLocalNode(logger_list, transp);
442
443 ret = (node != list_head(&logbuf.head));
444 if (ret) {
445 do {
446 ret = !!(logMask & (1 << (node_to_item(node->prev,
447 struct LogBufferElement,
448 node))->logId));
449 } while (!ret && ((node = node->prev) != list_head(&logbuf.head)));
450 }
451
452 transp->context.node = node;
453 }
454
455 pthread_rwlock_unlock(&logbuf.listLock);
456
457 return ret;
458}
459
460static void writeToLocalClose(
461 struct android_log_logger_list *logger_list __unused,
462 struct android_log_transport_context *transp) {
463 pthread_rwlock_wrlock(&logbuf.listLock);
464 transp->context.node = list_head(&logbuf.head);
465 pthread_rwlock_unlock(&logbuf.listLock);
466}
467
468static int writeToLocalClear(
469 struct android_log_logger *logger,
470 struct android_log_transport_context *unused __unused) {
471 log_id_t logId = logger->logId;
472 struct listnode *node, *n;
473
474 if ((logId >= NUMBER_OF_LOG_BUFFERS) || BLOCK_LOG_BUFFERS(logId)) {
475 return -EINVAL;
476 }
477
478 pthread_rwlock_wrlock(&logbuf.listLock);
479 logbuf.number[logId] = 0;
480 logbuf.last[logId] = &logbuf.head;
481 list_for_each_safe(node, n, &logbuf.head) {
482 struct LogBufferElement *element;
483 element = node_to_item(node, struct LogBufferElement, node);
484
485 if (logId == element->logId) {
486 struct android_log_logger_list *logger_list;
487
488 logger_list_rdlock();
489 logger_list_for_each(logger_list) {
490 struct android_log_transport_context *transp;
491
492 transport_context_for_each(transp, logger_list) {
493 if ((transp->transport == &localLoggerRead) &&
494 (transp->context.node == node)) {
495 transp->context.node = node->next;
496 }
497 }
498 }
499 logger_list_unlock();
500 list_remove(node);
501 free(element);
502 }
503 }
504
505 pthread_rwlock_unlock(&logbuf.listLock);
506
507 return 0;
508}
509
510static ssize_t writeToLocalGetSize(
511 struct android_log_logger *logger,
512 struct android_log_transport_context *transp __unused) {
513 ssize_t ret = -EINVAL;
514 log_id_t logId = logger->logId;
515
516 if ((logId < NUMBER_OF_LOG_BUFFERS) && !BLOCK_LOG_BUFFERS(logId)) {
517 pthread_rwlock_rdlock(&logbuf.listLock);
518 ret = logbuf.maxSize[logId];
519 pthread_rwlock_unlock(&logbuf.listLock);
520 }
521
522 return ret;
523}
524
525static ssize_t writeToLocalSetSize(
526 struct android_log_logger *logger,
527 struct android_log_transport_context *transp __unused,
528 size_t size) {
529 ssize_t ret = -EINVAL;
530
531 if ((size > LOGGER_ENTRY_MAX_LEN) || (size < (4 * 1024 * 1024))) {
532 log_id_t logId = logger->logId;
533 if ((logId < NUMBER_OF_LOG_BUFFERS) || !BLOCK_LOG_BUFFERS(logId)) {
534 pthread_rwlock_wrlock(&logbuf.listLock);
535 ret = logbuf.maxSize[logId] = size;
536 pthread_rwlock_unlock(&logbuf.listLock);
537 }
538 }
539
540 return ret;
541}
542
543static ssize_t writeToLocalGetReadbleSize(
544 struct android_log_logger *logger,
545 struct android_log_transport_context *transp __unused) {
546 ssize_t ret = -EINVAL;
547 log_id_t logId = logger->logId;
548
549 if ((logId < NUMBER_OF_LOG_BUFFERS) && !BLOCK_LOG_BUFFERS(logId)) {
550 pthread_rwlock_rdlock(&logbuf.listLock);
551 ret = logbuf.serviceName ? (ssize_t)logbuf.size[logId] : -EBADF;
552 pthread_rwlock_unlock(&logbuf.listLock);
553 }
554
555 return ret;
556}