blob: bff77f8ef07cbe9a2cc520ddc5ed5e52eadd4373 [file] [log] [blame]
Mark Salyzyn018a96d2016-03-01 13:45:42 -08001/*
2 * Copyright (C) 2007-2016 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 <stdatomic.h>
19#include <stdlib.h>
20#include <string.h>
21#include <sys/time.h>
22
23#ifdef __BIONIC__
24#include <android/set_abort_message.h>
25#endif
26
27#include <log/event_tag_map.h>
Mark Salyzyn850d06e2015-02-04 12:39:57 -080028#include <log/log_frontend.h>
Mark Salyzyn018a96d2016-03-01 13:45:42 -080029#include <private/android_filesystem_config.h>
30#include <private/android_logger.h>
31
32#include "config_write.h"
33#include "log_portability.h"
34#include "logger.h"
35
36#define LOG_BUF_SIZE 1024
37
38static int __write_to_log_init(log_id_t, struct iovec *vec, size_t nr);
39static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = __write_to_log_init;
40
41/*
42 * This is used by the C++ code to decide if it should write logs through
43 * the C code. Basically, if /dev/socket/logd is available, we're running in
44 * the simulator rather than a desktop tool and want to use the device.
45 */
46static enum {
47 kLogUninitialized, kLogNotAvailable, kLogAvailable
48} g_log_status = kLogUninitialized;
49
Mark Salyzync33103c2016-03-28 16:20:29 -070050static int check_log_uid_permissions()
51{
Dan Willemsen0910d2d2016-11-29 13:39:55 -080052#if defined(__ANDROID__)
Mark Salyzync33103c2016-03-28 16:20:29 -070053 uid_t uid = __android_log_uid();
54
55 /* Matches clientHasLogCredentials() in logd */
56 if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)) {
57 uid = geteuid();
58 if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)) {
59 gid_t gid = getgid();
60 if ((gid != AID_SYSTEM) &&
61 (gid != AID_ROOT) &&
62 (gid != AID_LOG)) {
63 gid = getegid();
64 if ((gid != AID_SYSTEM) &&
65 (gid != AID_ROOT) &&
66 (gid != AID_LOG)) {
67 int num_groups;
68 gid_t *groups;
69
70 num_groups = getgroups(0, NULL);
71 if (num_groups <= 0) {
72 return -EPERM;
73 }
74 groups = calloc(num_groups, sizeof(gid_t));
75 if (!groups) {
76 return -ENOMEM;
77 }
78 num_groups = getgroups(num_groups, groups);
79 while (num_groups > 0) {
80 if (groups[num_groups - 1] == AID_LOG) {
81 break;
82 }
83 --num_groups;
84 }
85 free(groups);
86 if (num_groups <= 0) {
87 return -EPERM;
88 }
89 }
90 }
91 }
92 }
93#endif
94 return 0;
95}
96
97static void __android_log_cache_available(
98 struct android_log_transport_write *node)
99{
100 size_t i;
101
102 if (node->logMask) {
103 return;
104 }
105
106 for (i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
107 if (node->write &&
108 (i != LOG_ID_KERNEL) &&
109 ((i != LOG_ID_SECURITY) ||
110 (check_log_uid_permissions() == 0)) &&
111 (!node->available || ((*node->available)(i) >= 0))) {
112 node->logMask |= 1 << i;
113 }
114 }
115}
116
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800117LIBLOG_ABI_PUBLIC int __android_log_dev_available()
118{
119 struct android_log_transport_write *node;
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800120
121 if (list_empty(&__android_log_transport_write)) {
122 return kLogUninitialized;
123 }
Mark Salyzync33103c2016-03-28 16:20:29 -0700124
125 write_transport_for_each(node, &__android_log_transport_write) {
126 __android_log_cache_available(node);
127 if (node->logMask) {
128 return kLogAvailable;
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800129 }
130 }
131 return kLogNotAvailable;
132}
Mark Salyzynba1a7982016-09-13 07:28:21 -0700133
Dan Willemsen0910d2d2016-11-29 13:39:55 -0800134#if defined(__ANDROID__)
Mark Salyzynba1a7982016-09-13 07:28:21 -0700135static atomic_uintptr_t tagMap;
136#endif
137
Mark Salyzyndf7a4c62016-08-23 10:23:36 -0700138/*
139 * Release any logger resources. A new log write will immediately re-acquire.
140 */
141LIBLOG_ABI_PUBLIC void __android_log_close()
142{
143 struct android_log_transport_write *transport;
Dan Willemsen0910d2d2016-11-29 13:39:55 -0800144#if defined(__ANDROID__)
Mark Salyzynba1a7982016-09-13 07:28:21 -0700145 EventTagMap *m;
146#endif
Mark Salyzyndf7a4c62016-08-23 10:23:36 -0700147
148 __android_log_lock();
149
150 write_to_log = __write_to_log_init;
151
152 /*
153 * Threads that are actively writing at this point are not held back
154 * by a lock and are at risk of dropping the messages with a return code
155 * -EBADF. Prefer to return error code than add the overhead of a lock to
156 * each log writing call to guarantee delivery. In addition, anyone
157 * calling this is doing so to release the logging resources and shut down,
158 * for them to do so with outstanding log requests in other threads is a
159 * disengenuous use of this function.
160 */
161
162 write_transport_for_each(transport, &__android_log_persist_write) {
163 if (transport->close) {
164 (*transport->close)();
165 }
166 }
167
168 write_transport_for_each(transport, &__android_log_transport_write) {
169 if (transport->close) {
170 (*transport->close)();
171 }
172 }
173
Dan Willemsen0910d2d2016-11-29 13:39:55 -0800174#if defined(__ANDROID__)
Mark Salyzynba1a7982016-09-13 07:28:21 -0700175 /*
176 * Additional risk here somewhat mitigated by immediately unlock flushing
177 * the processor cache. The multi-threaded race that we choose to accept,
178 * to minimize locking, is an atomic_load in a writer picking up a value
179 * just prior to entering this routine. There will be an use after free.
180 *
181 * Again, anyone calling this is doing so to release the logging resources
182 * is most probably going to quiesce then shut down; or to restart after
183 * a fork so the risk should be non-existent. For this reason we
184 * choose a mitigation stance for efficiency instead of incuring the cost
185 * of a lock for every log write.
186 */
187 m = (EventTagMap *)atomic_exchange(&tagMap, (uintptr_t)0);
188#endif
189
Mark Salyzyndf7a4c62016-08-23 10:23:36 -0700190 __android_log_unlock();
Mark Salyzynba1a7982016-09-13 07:28:21 -0700191
Dan Willemsen0910d2d2016-11-29 13:39:55 -0800192#if defined(__ANDROID__)
Mark Salyzyn53e9fc72016-11-09 10:14:35 -0800193 if (m != (EventTagMap *)(uintptr_t)-1LL) android_closeEventTagMap(m);
Mark Salyzynba1a7982016-09-13 07:28:21 -0700194#endif
195
Mark Salyzyndf7a4c62016-08-23 10:23:36 -0700196}
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800197
198/* log_init_lock assumed */
199static int __write_to_log_initialize()
200{
201 struct android_log_transport_write *transport;
202 struct listnode *n;
203 int i = 0, ret = 0;
204
205 __android_log_config_write();
206 write_transport_for_each_safe(transport, n, &__android_log_transport_write) {
Mark Salyzync33103c2016-03-28 16:20:29 -0700207 __android_log_cache_available(transport);
208 if (!transport->logMask) {
209 list_remove(&transport->node);
210 continue;
211 }
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800212 if (!transport->open || ((*transport->open)() < 0)) {
213 if (transport->close) {
214 (*transport->close)();
215 }
216 list_remove(&transport->node);
217 continue;
218 }
219 ++ret;
220 }
221 write_transport_for_each_safe(transport, n, &__android_log_persist_write) {
Mark Salyzync33103c2016-03-28 16:20:29 -0700222 __android_log_cache_available(transport);
223 if (!transport->logMask) {
224 list_remove(&transport->node);
225 continue;
226 }
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800227 if (!transport->open || ((*transport->open)() < 0)) {
228 if (transport->close) {
229 (*transport->close)();
230 }
231 list_remove(&transport->node);
232 continue;
233 }
234 ++i;
235 }
236 if (!ret && !i) {
237 return -ENODEV;
238 }
239
240 return ret;
241}
242
243/*
244 * Extract a 4-byte value from a byte stream. le32toh open coded
245 */
246static inline uint32_t get4LE(const uint8_t* src)
247{
248 return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
249}
250
251static int __write_to_log_daemon(log_id_t log_id, struct iovec *vec, size_t nr)
252{
253 struct android_log_transport_write *node;
254 int ret;
255 struct timespec ts;
256 size_t len, i;
257
258 for (len = i = 0; i < nr; ++i) {
259 len += vec[i].iov_len;
260 }
261 if (!len) {
262 return -EINVAL;
263 }
264
Dan Willemsen0910d2d2016-11-29 13:39:55 -0800265#if defined(__ANDROID__)
Mark Salyzyn142b43d2016-12-28 10:30:57 -0800266 clock_gettime(android_log_clockid(), &ts);
267
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800268 if (log_id == LOG_ID_SECURITY) {
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800269 if (vec[0].iov_len < 4) {
270 return -EINVAL;
271 }
272
Mark Salyzync33103c2016-03-28 16:20:29 -0700273 ret = check_log_uid_permissions();
274 if (ret < 0) {
275 return ret;
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800276 }
277 if (!__android_log_security()) {
278 /* If only we could reset downstream logd counter */
279 return -EPERM;
280 }
281 } else if (log_id == LOG_ID_EVENTS) {
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800282 const char *tag;
Mark Salyzyn807e40e2016-09-22 09:56:51 -0700283 size_t len;
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800284 EventTagMap *m, *f;
285
286 if (vec[0].iov_len < 4) {
287 return -EINVAL;
288 }
289
290 tag = NULL;
Mark Salyzyn807e40e2016-09-22 09:56:51 -0700291 len = 0;
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800292 f = NULL;
Mark Salyzynba1a7982016-09-13 07:28:21 -0700293 m = (EventTagMap *)atomic_load(&tagMap);
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800294
295 if (!m) {
296 ret = __android_log_trylock();
Mark Salyzynba1a7982016-09-13 07:28:21 -0700297 m = (EventTagMap *)atomic_load(&tagMap); /* trylock flush cache */
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800298 if (!m) {
Mark Salyzyn1179eb82016-11-11 09:48:56 -0800299 m = android_openEventTagMap(NULL);
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800300 if (ret) { /* trylock failed, use local copy, mark for close */
301 f = m;
302 } else {
303 if (!m) { /* One chance to open map file */
304 m = (EventTagMap *)(uintptr_t)-1LL;
305 }
Mark Salyzynba1a7982016-09-13 07:28:21 -0700306 atomic_store(&tagMap, (uintptr_t)m);
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800307 }
308 }
309 if (!ret) { /* trylock succeeded, unlock */
310 __android_log_unlock();
311 }
312 }
313 if (m && (m != (EventTagMap *)(uintptr_t)-1LL)) {
Mark Salyzyn807e40e2016-09-22 09:56:51 -0700314 tag = android_lookupEventTag_len(m, &len, get4LE(vec[0].iov_base));
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800315 }
Mark Salyzyn807e40e2016-09-22 09:56:51 -0700316 ret = __android_log_is_loggable_len(ANDROID_LOG_INFO,
317 tag, len,
318 ANDROID_LOG_VERBOSE);
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800319 if (f) { /* local copy marked for close */
320 android_closeEventTagMap(f);
321 }
322 if (!ret) {
323 return -EPERM;
324 }
325 } else {
326 /* Validate the incoming tag, tag content can not split across iovec */
327 char prio = ANDROID_LOG_VERBOSE;
328 const char *tag = vec[0].iov_base;
329 size_t len = vec[0].iov_len;
330 if (!tag) {
331 len = 0;
332 }
333 if (len > 0) {
334 prio = *tag;
335 if (len > 1) {
336 --len;
337 ++tag;
338 } else {
339 len = vec[1].iov_len;
340 tag = ((const char *)vec[1].iov_base);
341 if (!tag) {
342 len = 0;
343 }
344 }
345 }
346 /* tag must be nul terminated */
Ting-Yuan Huang6efb8772017-02-07 16:40:35 -0800347 if (tag && strnlen(tag, len) >= len) {
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800348 tag = NULL;
349 }
350
Mark Salyzyn807e40e2016-09-22 09:56:51 -0700351 if (!__android_log_is_loggable_len(prio,
352 tag, len - 1,
353 ANDROID_LOG_VERBOSE)) {
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800354 return -EPERM;
355 }
356 }
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800357#else
358 /* simulate clock_gettime(CLOCK_REALTIME, &ts); */
359 {
360 struct timeval tv;
361 gettimeofday(&tv, NULL);
362 ts.tv_sec = tv.tv_sec;
363 ts.tv_nsec = tv.tv_usec * 1000;
364 }
365#endif
366
367 ret = 0;
Mark Salyzync33103c2016-03-28 16:20:29 -0700368 i = 1 << log_id;
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800369 write_transport_for_each(node, &__android_log_transport_write) {
Mark Salyzync33103c2016-03-28 16:20:29 -0700370 if (node->logMask & i) {
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800371 ssize_t retval;
372 retval = (*node->write)(log_id, &ts, vec, nr);
373 if (ret >= 0) {
374 ret = retval;
375 }
376 }
377 }
378
379 write_transport_for_each(node, &__android_log_persist_write) {
Mark Salyzync33103c2016-03-28 16:20:29 -0700380 if (node->logMask & i) {
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800381 (void)(*node->write)(log_id, &ts, vec, nr);
382 }
383 }
384
385 return ret;
386}
387
388static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr)
389{
390 __android_log_lock();
391
392 if (write_to_log == __write_to_log_init) {
393 int ret;
394
395 ret = __write_to_log_initialize();
396 if (ret < 0) {
397 __android_log_unlock();
398 if (!list_empty(&__android_log_persist_write)) {
399 __write_to_log_daemon(log_id, vec, nr);
400 }
401 return ret;
402 }
403
404 write_to_log = __write_to_log_daemon;
405 }
406
407 __android_log_unlock();
408
409 return write_to_log(log_id, vec, nr);
410}
411
412LIBLOG_ABI_PUBLIC int __android_log_write(int prio, const char *tag,
413 const char *msg)
414{
415 return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg);
416}
417
418LIBLOG_ABI_PUBLIC int __android_log_buf_write(int bufID, int prio,
419 const char *tag, const char *msg)
420{
421 struct iovec vec[3];
422 char tmp_tag[32];
423
424 if (!tag)
425 tag = "";
426
427 /* XXX: This needs to go! */
428 if ((bufID != LOG_ID_RADIO) &&
429 (!strcmp(tag, "HTC_RIL") ||
430 !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */
431 !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */
432 !strcmp(tag, "AT") ||
433 !strcmp(tag, "GSM") ||
434 !strcmp(tag, "STK") ||
435 !strcmp(tag, "CDMA") ||
436 !strcmp(tag, "PHONE") ||
437 !strcmp(tag, "SMS"))) {
438 bufID = LOG_ID_RADIO;
439 /* Inform third party apps/ril/radio.. to use Rlog or RLOG */
440 snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag);
441 tag = tmp_tag;
442 }
443
444#if __BIONIC__
445 if (prio == ANDROID_LOG_FATAL) {
446 android_set_abort_message(msg);
447 }
448#endif
449
Mark Salyzync33103c2016-03-28 16:20:29 -0700450 vec[0].iov_base = (unsigned char *)&prio;
451 vec[0].iov_len = 1;
452 vec[1].iov_base = (void *)tag;
453 vec[1].iov_len = strlen(tag) + 1;
454 vec[2].iov_base = (void *)msg;
455 vec[2].iov_len = strlen(msg) + 1;
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800456
457 return write_to_log(bufID, vec, 3);
458}
459
460LIBLOG_ABI_PUBLIC int __android_log_vprint(int prio, const char *tag,
461 const char *fmt, va_list ap)
462{
463 char buf[LOG_BUF_SIZE];
464
465 vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
466
467 return __android_log_write(prio, tag, buf);
468}
469
470LIBLOG_ABI_PUBLIC int __android_log_print(int prio, const char *tag,
471 const char *fmt, ...)
472{
473 va_list ap;
474 char buf[LOG_BUF_SIZE];
475
476 va_start(ap, fmt);
477 vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
478 va_end(ap);
479
480 return __android_log_write(prio, tag, buf);
481}
482
483LIBLOG_ABI_PUBLIC int __android_log_buf_print(int bufID, int prio,
484 const char *tag,
485 const char *fmt, ...)
486{
487 va_list ap;
488 char buf[LOG_BUF_SIZE];
489
490 va_start(ap, fmt);
491 vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
492 va_end(ap);
493
494 return __android_log_buf_write(bufID, prio, tag, buf);
495}
496
497LIBLOG_ABI_PUBLIC void __android_log_assert(const char *cond, const char *tag,
498 const char *fmt, ...)
499{
500 char buf[LOG_BUF_SIZE];
501
502 if (fmt) {
503 va_list ap;
504 va_start(ap, fmt);
505 vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
506 va_end(ap);
507 } else {
508 /* Msg not provided, log condition. N.B. Do not use cond directly as
509 * format string as it could contain spurious '%' syntax (e.g.
510 * "%d" in "blocks%devs == 0").
511 */
512 if (cond)
513 snprintf(buf, LOG_BUF_SIZE, "Assertion failed: %s", cond);
514 else
515 strcpy(buf, "Unspecified assertion failed");
516 }
517
Elliott Hughes5bae1b82017-02-06 10:54:00 -0800518 // Log assertion failures to stderr for the benefit of "adb shell" users
519 // and gtests (http://b/23675822).
520 struct iovec iov[2] = {
521 { buf, strlen(buf) },
522 { (char*) "\n", 1 },
523 };
524 TEMP_FAILURE_RETRY(writev(2, iov, 2));
525
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800526 __android_log_write(ANDROID_LOG_FATAL, tag, buf);
527 abort(); /* abort so we have a chance to debug the situation */
528 /* NOTREACHED */
529}
530
531LIBLOG_ABI_PUBLIC int __android_log_bwrite(int32_t tag,
532 const void *payload, size_t len)
533{
534 struct iovec vec[2];
535
536 vec[0].iov_base = &tag;
537 vec[0].iov_len = sizeof(tag);
538 vec[1].iov_base = (void*)payload;
539 vec[1].iov_len = len;
540
541 return write_to_log(LOG_ID_EVENTS, vec, 2);
542}
543
544LIBLOG_ABI_PUBLIC int __android_log_security_bwrite(int32_t tag,
545 const void *payload,
546 size_t len)
547{
548 struct iovec vec[2];
549
550 vec[0].iov_base = &tag;
551 vec[0].iov_len = sizeof(tag);
552 vec[1].iov_base = (void*)payload;
553 vec[1].iov_len = len;
554
555 return write_to_log(LOG_ID_SECURITY, vec, 2);
556}
557
558/*
559 * Like __android_log_bwrite, but takes the type as well. Doesn't work
560 * for the general case where we're generating lists of stuff, but very
561 * handy if we just want to dump an integer into the log.
562 */
563LIBLOG_ABI_PUBLIC int __android_log_btwrite(int32_t tag, char type,
564 const void *payload, size_t len)
565{
566 struct iovec vec[3];
567
568 vec[0].iov_base = &tag;
569 vec[0].iov_len = sizeof(tag);
570 vec[1].iov_base = &type;
571 vec[1].iov_len = sizeof(type);
572 vec[2].iov_base = (void*)payload;
573 vec[2].iov_len = len;
574
575 return write_to_log(LOG_ID_EVENTS, vec, 3);
576}
577
578/*
579 * Like __android_log_bwrite, but used for writing strings to the
580 * event log.
581 */
582LIBLOG_ABI_PUBLIC int __android_log_bswrite(int32_t tag, const char *payload)
583{
584 struct iovec vec[4];
585 char type = EVENT_TYPE_STRING;
586 uint32_t len = strlen(payload);
587
588 vec[0].iov_base = &tag;
589 vec[0].iov_len = sizeof(tag);
590 vec[1].iov_base = &type;
591 vec[1].iov_len = sizeof(type);
592 vec[2].iov_base = &len;
593 vec[2].iov_len = sizeof(len);
594 vec[3].iov_base = (void*)payload;
595 vec[3].iov_len = len;
596
597 return write_to_log(LOG_ID_EVENTS, vec, 4);
598}
599
600/*
601 * Like __android_log_security_bwrite, but used for writing strings to the
602 * security log.
603 */
604LIBLOG_ABI_PUBLIC int __android_log_security_bswrite(int32_t tag,
605 const char *payload)
606{
607 struct iovec vec[4];
608 char type = EVENT_TYPE_STRING;
609 uint32_t len = strlen(payload);
610
611 vec[0].iov_base = &tag;
612 vec[0].iov_len = sizeof(tag);
613 vec[1].iov_base = &type;
614 vec[1].iov_len = sizeof(type);
615 vec[2].iov_base = &len;
616 vec[2].iov_len = sizeof(len);
617 vec[3].iov_base = (void*)payload;
618 vec[3].iov_len = len;
619
620 return write_to_log(LOG_ID_SECURITY, vec, 4);
621}
Mark Salyzyn850d06e2015-02-04 12:39:57 -0800622
623static int __write_to_log_null(log_id_t log_id, struct iovec* vec, size_t nr)
624{
625 size_t len, i;
626
627 if ((log_id < LOG_ID_MIN) || (log_id >= LOG_ID_MAX)) {
628 return -EINVAL;
629 }
630
631 for (len = i = 0; i < nr; ++i) {
632 len += vec[i].iov_len;
633 }
634 if (!len) {
635 return -EINVAL;
636 }
637 return len;
638}
639
640/* Following functions need access to our internal write_to_log status */
641
642LIBLOG_ABI_PUBLIC int android_set_log_frontend(int frontend_flag)
643{
644 if (frontend_flag < 0) {
645 return -EINVAL;
646 }
647
648 __android_log_lock();
649
650 if (frontend_flag & LOGGER_NULL) {
651 write_to_log = __write_to_log_null;
652
653 __android_log_unlock();
654
655 return LOGGER_NULL;
656 }
657
658 /* Anything else, act as if LOGGER_DEFAULT */
659
660 /* generically we only expect these two values for write_to_log */
661 if ((write_to_log != __write_to_log_init) &&
662 (write_to_log != __write_to_log_daemon)) {
663 write_to_log = __write_to_log_init;
664 }
665
666 __android_log_unlock();
667
668 return LOGGER_DEFAULT;
669}
670
671LIBLOG_ABI_PUBLIC int android_get_log_frontend()
672{
673 int ret = LOGGER_DEFAULT;
674
675 __android_log_lock();
676 if (write_to_log == __write_to_log_null) {
677 ret = LOGGER_NULL;
678 } else if ((write_to_log != __write_to_log_init) &&
679 (write_to_log != __write_to_log_daemon)) {
680 ret = -EINVAL;
681 }
682 __android_log_unlock();
683
684 return ret;
685}