summaryrefslogtreecommitdiffstats
path: root/liblog
diff options
context:
space:
mode:
Diffstat (limited to 'liblog')
-rw-r--r--liblog/Android.mk8
-rw-r--r--liblog/config_read.c62
-rw-r--r--liblog/config_read.h50
-rw-r--r--liblog/config_write.c66
-rw-r--r--liblog/config_write.h50
-rw-r--r--liblog/event_tag_map.c2
-rw-r--r--liblog/fake_log_device.c2
-rw-r--r--liblog/fake_log_device.h2
-rw-r--r--liblog/fake_writer.c82
-rw-r--r--liblog/log_event_list.c2
-rw-r--r--liblog/log_event_write.c2
-rw-r--r--liblog/log_is_loggable.c2
-rw-r--r--liblog/log_portability.h (renamed from liblog/log_cdefs.h)34
-rw-r--r--liblog/log_read.c917
-rw-r--r--liblog/log_time.cpp2
-rw-r--r--liblog/logd_reader.c670
-rw-r--r--liblog/logd_writer.c267
-rw-r--r--liblog/logger.h159
-rw-r--r--liblog/logger_lock.c82
-rw-r--r--liblog/logger_name.c65
-rw-r--r--liblog/logger_read.c474
-rw-r--r--liblog/logger_write.c (renamed from liblog/logd_write.c)415
-rw-r--r--liblog/logprint.c2
-rw-r--r--liblog/pmsg_reader.c255
-rw-r--r--liblog/pmsg_writer.c159
-rw-r--r--liblog/uio.c2
26 files changed, 2587 insertions, 1246 deletions
diff --git a/liblog/Android.mk b/liblog/Android.mk
index 6d53a4af0..01c8e77b2 100644
--- a/liblog/Android.mk
+++ b/liblog/Android.mk
@@ -24,10 +24,14 @@ include $(CLEAR_VARS)
24# so make sure we do not regret hard-coding it as follows: 24# so make sure we do not regret hard-coding it as follows:
25liblog_cflags := -DLIBLOG_LOG_TAG=1005 25liblog_cflags := -DLIBLOG_LOG_TAG=1005
26 26
27liblog_sources := logd_write.c log_event_list.c log_event_write.c 27liblog_sources := log_event_list.c log_event_write.c logger_write.c
28liblog_sources += config_write.c logger_name.c logger_lock.c
28liblog_host_sources := $(liblog_sources) fake_log_device.c event.logtags 29liblog_host_sources := $(liblog_sources) fake_log_device.c event.logtags
30liblog_host_sources += fake_writer.c
29liblog_target_sources := $(liblog_sources) event_tag_map.c 31liblog_target_sources := $(liblog_sources) event_tag_map.c
30liblog_target_sources += log_time.cpp log_is_loggable.c logprint.c log_read.c 32liblog_target_sources += config_read.c log_time.cpp log_is_loggable.c logprint.c
33liblog_target_sources += pmsg_reader.c pmsg_writer.c
34liblog_target_sources += logd_reader.c logd_writer.c logger_read.c
31 35
32# Shared and static library for host 36# Shared and static library for host
33# ======================================================== 37# ========================================================
diff --git a/liblog/config_read.c b/liblog/config_read.c
new file mode 100644
index 000000000..1f54152b0
--- /dev/null
+++ b/liblog/config_read.c
@@ -0,0 +1,62 @@
1/*
2 * Copyright (C) 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 "config_read.h"
18#include "logger.h"
19
20LIBLOG_HIDDEN struct listnode __android_log_transport_read =
21 { &__android_log_transport_read, &__android_log_transport_read };
22LIBLOG_HIDDEN struct listnode __android_log_persist_read =
23 { &__android_log_persist_read, &__android_log_persist_read };
24
25static void __android_log_add_transport(
26 struct listnode *list, struct android_log_transport_read *transport) {
27 size_t i;
28
29 /* Try to keep one functioning transport for each log buffer id */
30 for (i = LOG_ID_MIN; i < LOG_ID_MAX; i++) {
31 struct android_log_transport_read *transp;
32
33 if (list_empty(list)) {
34 if (!transport->available || ((*transport->available)(i) >= 0)) {
35 list_add_tail(list, &transport->node);
36 return;
37 }
38 } else {
39 read_transport_for_each(transp, list) {
40 if (!transp->available) {
41 return;
42 }
43 if (((*transp->available)(i) < 0) &&
44 (!transport->available ||
45 ((*transport->available)(i) >= 0))) {
46 list_add_tail(list, &transport->node);
47 return;
48 }
49 }
50 }
51 }
52}
53
54LIBLOG_HIDDEN void __android_log_config_read() {
55#if (FAKE_LOG_DEVICE == 0)
56 extern struct android_log_transport_read logdLoggerRead;
57 extern struct android_log_transport_read pmsgLoggerRead;
58
59 __android_log_add_transport(&__android_log_transport_read, &logdLoggerRead);
60 __android_log_add_transport(&__android_log_persist_read, &pmsgLoggerRead);
61#endif
62}
diff --git a/liblog/config_read.h b/liblog/config_read.h
new file mode 100644
index 000000000..67f4c20d0
--- /dev/null
+++ b/liblog/config_read.h
@@ -0,0 +1,50 @@
1/*
2 * Copyright (C) 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#ifndef _LIBLOG_CONFIG_READ_H__
18#define _LIBLOG_CONFIG_READ_H__
19
20#include <cutils/list.h>
21
22#include "log_portability.h"
23
24__BEGIN_DECLS
25
26extern LIBLOG_HIDDEN struct listnode __android_log_transport_read;
27extern LIBLOG_HIDDEN struct listnode __android_log_persist_read;
28
29#define read_transport_for_each(transp, transports) \
30 for (transp = node_to_item((transports)->next, \
31 struct android_log_transport_read, node); \
32 (transp != node_to_item(transports, \
33 struct android_log_transport_read, node)); \
34 transp = node_to_item(transp->node.next, \
35 struct android_log_transport_read, node)) \
36
37#define read_transport_for_each_safe(transp, n, transports) \
38 for (transp = node_to_item((transports)->next, \
39 struct android_log_transport_read, node), \
40 n = transp->node.next; \
41 (transp != node_to_item(transports, \
42 struct android_log_transport_read, node)); \
43 transp = node_to_item(n, struct android_log_transport_read, node), \
44 n = transp->node.next)
45
46LIBLOG_HIDDEN void __android_log_config_read();
47
48__END_DECLS
49
50#endif /* _LIBLOG_CONFIG_READ_H__ */
diff --git a/liblog/config_write.c b/liblog/config_write.c
new file mode 100644
index 000000000..d689f631b
--- /dev/null
+++ b/liblog/config_write.c
@@ -0,0 +1,66 @@
1/*
2 * Copyright (C) 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 "config_write.h"
18#include "logger.h"
19
20LIBLOG_HIDDEN struct listnode __android_log_transport_write =
21 { &__android_log_transport_write, &__android_log_transport_write };
22LIBLOG_HIDDEN struct listnode __android_log_persist_write =
23 { &__android_log_persist_write, &__android_log_persist_write};
24
25static void __android_log_add_transport(
26 struct listnode *list, struct android_log_transport_write *transport) {
27 size_t i;
28
29 /* Try to keep one functioning transport for each log buffer id */
30 for (i = LOG_ID_MIN; i < LOG_ID_MAX; i++) {
31 struct android_log_transport_write *transp;
32
33 if (list_empty(list)) {
34 if (!transport->available || ((*transport->available)(i) >= 0)) {
35 list_add_tail(list, &transport->node);
36 return;
37 }
38 } else {
39 write_transport_for_each(transp, list) {
40 if (!transp->available) {
41 return;
42 }
43 if (((*transp->available)(i) < 0) &&
44 (!transport->available ||
45 ((*transport->available)(i) >= 0))) {
46 list_add_tail(list, &transport->node);
47 return;
48 }
49 }
50 }
51 }
52}
53
54LIBLOG_HIDDEN void __android_log_config_write() {
55#if (FAKE_LOG_DEVICE == 0)
56 extern struct android_log_transport_write logdLoggerWrite;
57 extern struct android_log_transport_write pmsgLoggerWrite;
58
59 __android_log_add_transport(&__android_log_transport_write, &logdLoggerWrite);
60 __android_log_add_transport(&__android_log_persist_write, &pmsgLoggerWrite);
61#else
62 extern struct android_log_transport_write fakeLoggerWrite;
63
64 __android_log_add_transport(&__android_log_transport_write, &fakeLoggerWrite);
65#endif
66}
diff --git a/liblog/config_write.h b/liblog/config_write.h
new file mode 100644
index 000000000..3a02a4e79
--- /dev/null
+++ b/liblog/config_write.h
@@ -0,0 +1,50 @@
1/*
2 * Copyright (C) 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#ifndef _LIBLOG_CONFIG_WRITE_H__
18#define _LIBLOG_CONFIG_WRITE_H__
19
20#include <cutils/list.h>
21
22#include "log_portability.h"
23
24__BEGIN_DECLS
25
26extern LIBLOG_HIDDEN struct listnode __android_log_transport_write;
27extern LIBLOG_HIDDEN struct listnode __android_log_persist_write;
28
29#define write_transport_for_each(transp, transports) \
30 for (transp = node_to_item((transports)->next, \
31 struct android_log_transport_write, node); \
32 (transp != node_to_item(transports, \
33 struct android_log_transport_write, node)); \
34 transp = node_to_item(transp->node.next, \
35 struct android_log_transport_write, node)) \
36
37#define write_transport_for_each_safe(transp, n, transports) \
38 for (transp = node_to_item((transports)->next, \
39 struct android_log_transport_write, node), \
40 n = transp->node.next; \
41 (transp != node_to_item(transports, \
42 struct android_log_transport_write, node)); \
43 transp = node_to_item(n, struct android_log_transport_write, node), \
44 n = transp->node.next)
45
46LIBLOG_HIDDEN void __android_log_config_write();
47
48__END_DECLS
49
50#endif /* _LIBLOG_CONFIG_WRITE_H__ */
diff --git a/liblog/event_tag_map.c b/liblog/event_tag_map.c
index 870c69aa2..64d872a25 100644
--- a/liblog/event_tag_map.c
+++ b/liblog/event_tag_map.c
@@ -24,7 +24,7 @@
24#include <log/event_tag_map.h> 24#include <log/event_tag_map.h>
25#include <log/log.h> 25#include <log/log.h>
26 26
27#include "log_cdefs.h" 27#include "log_portability.h"
28 28
29#define OUT_TAG "EventTagMap" 29#define OUT_TAG "EventTagMap"
30 30
diff --git a/liblog/fake_log_device.c b/liblog/fake_log_device.c
index c73e03e21..cc67f3eba 100644
--- a/liblog/fake_log_device.c
+++ b/liblog/fake_log_device.c
@@ -31,7 +31,7 @@
31#include <log/logd.h> 31#include <log/logd.h>
32 32
33#include "fake_log_device.h" 33#include "fake_log_device.h"
34#include "log_cdefs.h" 34#include "log_portability.h"
35 35
36#define kMaxTagLen 16 /* from the long-dead utils/Log.cpp */ 36#define kMaxTagLen 16 /* from the long-dead utils/Log.cpp */
37 37
diff --git a/liblog/fake_log_device.h b/liblog/fake_log_device.h
index 672b446f3..4529b5d95 100644
--- a/liblog/fake_log_device.h
+++ b/liblog/fake_log_device.h
@@ -19,7 +19,7 @@
19 19
20#include <sys/types.h> 20#include <sys/types.h>
21 21
22#include "log_cdefs.h" 22#include "log_portability.h"
23 23
24struct iovec; 24struct iovec;
25 25
diff --git a/liblog/fake_writer.c b/liblog/fake_writer.c
new file mode 100644
index 000000000..dab8bc54e
--- /dev/null
+++ b/liblog/fake_writer.c
@@ -0,0 +1,82 @@
1/*
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 <fcntl.h>
19#include <unistd.h>
20
21#include <log/log.h>
22
23#include "config_write.h"
24#include "fake_log_device.h"
25#include "log_portability.h"
26#include "logger.h"
27
28static int fakeOpen();
29static void fakeClose();
30static int fakeWrite(log_id_t log_id, struct timespec *ts,
31 struct iovec *vec, size_t nr);
32
33static int logFds[(int)LOG_ID_MAX] = { -1, -1, -1, -1, -1, -1 };
34
35LIBLOG_HIDDEN struct android_log_transport_write fakeLoggerWrite = {
36 .node = { &fakeLoggerWrite.node, &fakeLoggerWrite.node },
37 .context.private = &logFds,
38 .name = "fake",
39 .available = NULL,
40 .open = fakeOpen,
41 .close = fakeClose,
42 .write = fakeWrite,
43};
44
45static int fakeOpen() {
46 int i;
47
48 for (i = 0; i < LOG_ID_MAX; i++) {
49 char buf[sizeof("/dev/log_security")];
50 snprintf(buf, sizeof(buf), "/dev/log_%s", android_log_id_to_name(i));
51 logFds[i] = fakeLogOpen(buf, O_WRONLY);
52 }
53 return 0;
54}
55
56static void fakeClose() {
57 int i;
58
59 for (i = 0; i < LOG_ID_MAX; i++) {
60 fakeLogClose(logFds[i]);
61 logFds[i] = -1;
62 }
63}
64
65static int fakeWrite(log_id_t log_id, struct timespec *ts __unused,
66 struct iovec *vec, size_t nr)
67{
68 ssize_t ret;
69 int logFd;
70
71 if (/*(int)log_id >= 0 &&*/ (int)log_id >= (int)LOG_ID_MAX) {
72 return -EBADF;
73 }
74
75 logFd = logFds[(int)log_id];
76 ret = TEMP_FAILURE_RETRY(fakeLogWritev(logFd, vec, nr));
77 if (ret < 0) {
78 ret = -errno;
79 }
80
81 return ret;
82}
diff --git a/liblog/log_event_list.c b/liblog/log_event_list.c
index a77c56eb1..64d9024c6 100644
--- a/liblog/log_event_list.c
+++ b/liblog/log_event_list.c
@@ -25,7 +25,7 @@
25#include <log/log.h> 25#include <log/log.h>
26#include <log/logger.h> 26#include <log/logger.h>
27 27
28#include "log_cdefs.h" 28#include "log_portability.h"
29 29
30#define MAX_EVENT_PAYLOAD (LOGGER_ENTRY_MAX_PAYLOAD - sizeof(int32_t)) 30#define MAX_EVENT_PAYLOAD (LOGGER_ENTRY_MAX_PAYLOAD - sizeof(int32_t))
31 31
diff --git a/liblog/log_event_write.c b/liblog/log_event_write.c
index 3535b94c1..b9827a16d 100644
--- a/liblog/log_event_write.c
+++ b/liblog/log_event_write.c
@@ -18,7 +18,7 @@
18 18
19#include <log/log.h> 19#include <log/log.h>
20 20
21#include "log_cdefs.h" 21#include "log_portability.h"
22 22
23#define MAX_SUBTAG_LEN 32 23#define MAX_SUBTAG_LEN 32
24 24
diff --git a/liblog/log_is_loggable.c b/liblog/log_is_loggable.c
index 47fde204e..551fa7684 100644
--- a/liblog/log_is_loggable.c
+++ b/liblog/log_is_loggable.c
@@ -23,7 +23,7 @@
23 23
24#include <android/log.h> 24#include <android/log.h>
25 25
26#include "log_cdefs.h" 26#include "log_portability.h"
27 27
28static pthread_mutex_t lock_loggable = PTHREAD_MUTEX_INITIALIZER; 28static pthread_mutex_t lock_loggable = PTHREAD_MUTEX_INITIALIZER;
29 29
diff --git a/liblog/log_cdefs.h b/liblog/log_portability.h
index 3a526256e..3ad20601e 100644
--- a/liblog/log_cdefs.h
+++ b/liblog/log_portability.h
@@ -14,10 +14,13 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17#ifndef _LIBLOG_CDEFS_H__ 17#ifndef _LIBLOG_PORTABILITY_H__
18#define _LIBLOG_CDEFS_H__ 18#define _LIBLOG_PORTABILITY_H__
19 19
20#include <sys/cdefs.h> 20#include <sys/cdefs.h>
21#include <unistd.h>
22
23/* Helpful private sys/cdefs.h like definitions */
21 24
22/* Declare this library function hidden and internal */ 25/* Declare this library function hidden and internal */
23#if defined(_WIN32) 26#if defined(_WIN32)
@@ -46,9 +49,34 @@
46#define LIBLOG_WEAK __attribute__((weak,visibility("default"))) 49#define LIBLOG_WEAK __attribute__((weak,visibility("default")))
47#endif 50#endif
48 51
52/* possible missing definitions in sys/cdefs.h */
53
54/* DECLS */
55#ifndef __BEGIN_DECLS
56#if defined(__cplusplus)
57#define __BEGIN_DECLS extern "C" {
58#define __END_DECLS }
59#else
60#define __BEGIN_DECLS
61#define __END_DECLS
62#endif
63#endif
64
49/* Unused argument. For C code only, remove symbol name for C++ */ 65/* Unused argument. For C code only, remove symbol name for C++ */
50#ifndef __unused 66#ifndef __unused
51#define __unused __attribute__((__unused__)) 67#define __unused __attribute__((__unused__))
52#endif 68#endif
53 69
54#endif /* _LIBLOG_CDEFS_H__ */ 70/* possible missing definitions in unistd.h */
71
72#ifndef TEMP_FAILURE_RETRY
73/* Used to retry syscalls that can return EINTR. */
74#define TEMP_FAILURE_RETRY(exp) ({ \
75 __typeof__(exp) _rc; \
76 do { \
77 _rc = (exp); \
78 } while (_rc == -1 && errno == EINTR); \
79 _rc; })
80#endif
81
82#endif /* _LIBLOG_PORTABILITY_H__ */
diff --git a/liblog/log_read.c b/liblog/log_read.c
deleted file mode 100644
index 4b839443d..000000000
--- a/liblog/log_read.c
+++ /dev/null
@@ -1,917 +0,0 @@
1/*
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 <inttypes.h>
20#include <poll.h>
21#include <signal.h>
22#include <stdbool.h>
23#include <stddef.h>
24#define NOMINMAX /* for windows to suppress definition of min in stdlib.h */
25#include <stdlib.h>
26#include <string.h>
27#include <unistd.h>
28
29#include <cutils/list.h>
30#include <cutils/sockets.h>
31#include <log/log.h>
32#include <log/logger.h>
33#include <private/android_filesystem_config.h>
34#include <private/android_logger.h>
35
36#include "log_cdefs.h"
37
38/* branchless on many architectures. */
39#define min(x,y) ((y) ^ (((x) ^ (y)) & -((x) < (y))))
40
41/* Private copy of ../libcutils/socket_local_client.c prevent library loops */
42
43#if defined(_WIN32)
44
45LIBLOG_WEAK int socket_local_client(const char *name, int namespaceId, int type)
46{
47 errno = ENOSYS;
48 return -ENOSYS;
49}
50
51#else /* !_WIN32 */
52
53#include <sys/socket.h>
54#include <sys/un.h>
55#include <sys/select.h>
56#include <sys/types.h>
57
58/* Private copy of ../libcutils/socket_local.h prevent library loops */
59#define FILESYSTEM_SOCKET_PREFIX "/tmp/"
60#define ANDROID_RESERVED_SOCKET_PREFIX "/dev/socket/"
61/* End of ../libcutils/socket_local.h */
62
63#define LISTEN_BACKLOG 4
64
65/* Documented in header file. */
66LIBLOG_WEAK int socket_make_sockaddr_un(const char *name, int namespaceId,
67 struct sockaddr_un *p_addr,
68 socklen_t *alen)
69{
70 memset (p_addr, 0, sizeof (*p_addr));
71 size_t namelen;
72
73 switch (namespaceId) {
74 case ANDROID_SOCKET_NAMESPACE_ABSTRACT:
75#if defined(__linux__)
76 namelen = strlen(name);
77
78 /* Test with length +1 for the *initial* '\0'. */
79 if ((namelen + 1) > sizeof(p_addr->sun_path)) {
80 goto error;
81 }
82
83 /*
84 * Note: The path in this case is *not* supposed to be
85 * '\0'-terminated. ("man 7 unix" for the gory details.)
86 */
87
88 p_addr->sun_path[0] = 0;
89 memcpy(p_addr->sun_path + 1, name, namelen);
90#else
91 /* this OS doesn't have the Linux abstract namespace */
92
93 namelen = strlen(name) + strlen(FILESYSTEM_SOCKET_PREFIX);
94 /* unix_path_max appears to be missing on linux */
95 if (namelen > sizeof(*p_addr)
96 - offsetof(struct sockaddr_un, sun_path) - 1) {
97 goto error;
98 }
99
100 strcpy(p_addr->sun_path, FILESYSTEM_SOCKET_PREFIX);
101 strcat(p_addr->sun_path, name);
102#endif
103 break;
104
105 case ANDROID_SOCKET_NAMESPACE_RESERVED:
106 namelen = strlen(name) + strlen(ANDROID_RESERVED_SOCKET_PREFIX);
107 /* unix_path_max appears to be missing on linux */
108 if (namelen > sizeof(*p_addr)
109 - offsetof(struct sockaddr_un, sun_path) - 1) {
110 goto error;
111 }
112
113 strcpy(p_addr->sun_path, ANDROID_RESERVED_SOCKET_PREFIX);
114 strcat(p_addr->sun_path, name);
115 break;
116
117 case ANDROID_SOCKET_NAMESPACE_FILESYSTEM:
118 namelen = strlen(name);
119 /* unix_path_max appears to be missing on linux */
120 if (namelen > sizeof(*p_addr)
121 - offsetof(struct sockaddr_un, sun_path) - 1) {
122 goto error;
123 }
124
125 strcpy(p_addr->sun_path, name);
126 break;
127
128 default:
129 /* invalid namespace id */
130 return -1;
131 }
132
133 p_addr->sun_family = AF_LOCAL;
134 *alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;
135 return 0;
136error:
137 return -1;
138}
139
140/**
141 * connect to peer named "name" on fd
142 * returns same fd or -1 on error.
143 * fd is not closed on error. that's your job.
144 *
145 * Used by AndroidSocketImpl
146 */
147LIBLOG_WEAK int socket_local_client_connect(int fd, const char *name,
148 int namespaceId, int type __unused)
149{
150 struct sockaddr_un addr;
151 socklen_t alen;
152 int err;
153
154 err = socket_make_sockaddr_un(name, namespaceId, &addr, &alen);
155
156 if (err < 0) {
157 goto error;
158 }
159
160 if(connect(fd, (struct sockaddr *) &addr, alen) < 0) {
161 goto error;
162 }
163
164 return fd;
165
166error:
167 return -1;
168}
169
170/**
171 * connect to peer named "name"
172 * returns fd or -1 on error
173 */
174LIBLOG_WEAK int socket_local_client(const char *name, int namespaceId, int type)
175{
176 int s;
177
178 s = socket(AF_LOCAL, type, 0);
179 if(s < 0) return -1;
180
181 if ( 0 > socket_local_client_connect(s, name, namespaceId, type)) {
182 close(s);
183 return -1;
184 }
185
186 return s;
187}
188
189#endif /* !_WIN32 */
190/* End of ../libcutils/socket_local_client.c */
191
192#define logger_for_each(logger, logger_list) \
193 for (logger = node_to_item((logger_list)->node.next, struct logger, node); \
194 logger != node_to_item(&(logger_list)->node, struct logger, node); \
195 logger = node_to_item((logger)->node.next, struct logger, node))
196
197/* In the future, we would like to make this list extensible */
198static const char *LOG_NAME[LOG_ID_MAX] = {
199 [LOG_ID_MAIN] = "main",
200 [LOG_ID_RADIO] = "radio",
201 [LOG_ID_EVENTS] = "events",
202 [LOG_ID_SYSTEM] = "system",
203 [LOG_ID_CRASH] = "crash",
204 [LOG_ID_SECURITY] = "security",
205 [LOG_ID_KERNEL] = "kernel",
206};
207
208LIBLOG_ABI_PUBLIC const char *android_log_id_to_name(log_id_t log_id)
209{
210 if (log_id >= LOG_ID_MAX) {
211 log_id = LOG_ID_MAIN;
212 }
213 return LOG_NAME[log_id];
214}
215
216LIBLOG_ABI_PUBLIC log_id_t android_name_to_log_id(const char *logName)
217{
218 const char *b;
219 int ret;
220
221 if (!logName) {
222 return -1; /* NB: log_id_t is unsigned */
223 }
224 b = strrchr(logName, '/');
225 if (!b) {
226 b = logName;
227 } else {
228 ++b;
229 }
230
231 for(ret = LOG_ID_MIN; ret < LOG_ID_MAX; ++ret) {
232 const char *l = LOG_NAME[ret];
233 if (l && !strcmp(b, l)) {
234 return ret;
235 }
236 }
237 return -1; /* should never happen */
238}
239
240struct logger_list {
241 struct listnode node;
242 int mode;
243 unsigned int tail;
244 log_time start;
245 pid_t pid;
246 int sock;
247};
248
249struct logger {
250 struct listnode node;
251 struct logger_list *top;
252 log_id_t id;
253};
254
255/* android_logger_alloc unimplemented, no use case */
256/* android_logger_free not exported */
257static void android_logger_free(struct logger *logger)
258{
259 if (!logger) {
260 return;
261 }
262
263 list_remove(&logger->node);
264
265 free(logger);
266}
267
268/* android_logger_alloc unimplemented, no use case */
269
270/* method for getting the associated sublog id */
271LIBLOG_ABI_PUBLIC log_id_t android_logger_get_id(struct logger *logger)
272{
273 return logger->id;
274}
275
276/* worker for sending the command to the logger */
277static ssize_t send_log_msg(struct logger *logger,
278 const char *msg, char *buf, size_t buf_size)
279{
280 ssize_t ret;
281 size_t len;
282 char *cp;
283 int errno_save = 0;
284 int sock = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED,
285 SOCK_STREAM);
286 if (sock < 0) {
287 return sock;
288 }
289
290 if (msg) {
291 snprintf(buf, buf_size, msg, logger ? logger->id : (unsigned) -1);
292 }
293
294 len = strlen(buf) + 1;
295 ret = TEMP_FAILURE_RETRY(write(sock, buf, len));
296 if (ret <= 0) {
297 goto done;
298 }
299
300 len = buf_size;
301 cp = buf;
302 while ((ret = TEMP_FAILURE_RETRY(read(sock, cp, len))) > 0) {
303 struct pollfd p;
304
305 if (((size_t)ret == len) || (buf_size < PAGE_SIZE)) {
306 break;
307 }
308
309 len -= ret;
310 cp += ret;
311
312 memset(&p, 0, sizeof(p));
313 p.fd = sock;
314 p.events = POLLIN;
315
316 /* Give other side 20ms to refill pipe */
317 ret = TEMP_FAILURE_RETRY(poll(&p, 1, 20));
318
319 if (ret <= 0) {
320 break;
321 }
322
323 if (!(p.revents & POLLIN)) {
324 ret = 0;
325 break;
326 }
327 }
328
329 if (ret >= 0) {
330 ret += buf_size - len;
331 }
332
333done:
334 if ((ret == -1) && errno) {
335 errno_save = errno;
336 }
337 close(sock);
338 if (errno_save) {
339 errno = errno_save;
340 }
341 return ret;
342}
343
344static int check_log_success(char *buf, ssize_t ret)
345{
346 if (ret < 0) {
347 return ret;
348 }
349
350 if (strncmp(buf, "success", 7)) {
351 errno = EINVAL;
352 return -1;
353 }
354
355 return 0;
356}
357
358/* Determine the credentials of the caller */
359static bool uid_has_log_permission(uid_t uid)
360{
361 return (uid == AID_SYSTEM) || (uid == AID_LOG) || (uid == AID_ROOT);
362}
363
364static uid_t get_best_effective_uid()
365{
366 uid_t euid;
367 uid_t uid;
368 gid_t gid;
369 ssize_t i;
370 static uid_t last_uid = (uid_t) -1;
371
372 if (last_uid != (uid_t) -1) {
373 return last_uid;
374 }
375 uid = getuid();
376 if (uid_has_log_permission(uid)) {
377 return last_uid = uid;
378 }
379 euid = geteuid();
380 if (uid_has_log_permission(euid)) {
381 return last_uid = euid;
382 }
383 gid = getgid();
384 if (uid_has_log_permission(gid)) {
385 return last_uid = gid;
386 }
387 gid = getegid();
388 if (uid_has_log_permission(gid)) {
389 return last_uid = gid;
390 }
391 i = getgroups((size_t) 0, NULL);
392 if (i > 0) {
393 gid_t list[i];
394
395 getgroups(i, list);
396 while (--i >= 0) {
397 if (uid_has_log_permission(list[i])) {
398 return last_uid = list[i];
399 }
400 }
401 }
402 return last_uid = uid;
403}
404
405LIBLOG_ABI_PUBLIC int android_logger_clear(struct logger *logger)
406{
407 char buf[512];
408
409 if (logger->top->mode & ANDROID_LOG_PSTORE) {
410 if (uid_has_log_permission(get_best_effective_uid())) {
411 return unlink("/sys/fs/pstore/pmsg-ramoops-0");
412 }
413 errno = EPERM;
414 return -1;
415 }
416 return check_log_success(buf,
417 send_log_msg(logger, "clear %d", buf, sizeof(buf)));
418}
419
420/* returns the total size of the log's ring buffer */
421LIBLOG_ABI_PUBLIC long android_logger_get_log_size(struct logger *logger)
422{
423 char buf[512];
424
425 ssize_t ret = send_log_msg(logger, "getLogSize %d", buf, sizeof(buf));
426 if (ret < 0) {
427 return ret;
428 }
429
430 if ((buf[0] < '0') || ('9' < buf[0])) {
431 return -1;
432 }
433
434 return atol(buf);
435}
436
437LIBLOG_ABI_PUBLIC int android_logger_set_log_size(struct logger *logger,
438 unsigned long size)
439{
440 char buf[512];
441
442 snprintf(buf, sizeof(buf), "setLogSize %d %lu",
443 logger ? logger->id : (unsigned) -1, size);
444
445 return check_log_success(buf, send_log_msg(NULL, NULL, buf, sizeof(buf)));
446}
447
448/*
449 * returns the readable size of the log's ring buffer (that is, amount of the
450 * log consumed)
451 */
452LIBLOG_ABI_PUBLIC long android_logger_get_log_readable_size(
453 struct logger *logger)
454{
455 char buf[512];
456
457 ssize_t ret = send_log_msg(logger, "getLogSizeUsed %d", buf, sizeof(buf));
458 if (ret < 0) {
459 return ret;
460 }
461
462 if ((buf[0] < '0') || ('9' < buf[0])) {
463 return -1;
464 }
465
466 return atol(buf);
467}
468
469/*
470 * returns the logger version
471 */
472LIBLOG_ABI_PUBLIC int android_logger_get_log_version(
473 struct logger *logger __unused)
474{
475 return 4;
476}
477
478/*
479 * returns statistics
480 */
481LIBLOG_ABI_PUBLIC ssize_t android_logger_get_statistics(
482 struct logger_list *logger_list,
483 char *buf, size_t len)
484{
485 struct logger *logger;
486 char *cp = buf;
487 size_t remaining = len;
488 size_t n;
489
490 n = snprintf(cp, remaining, "getStatistics");
491 n = min(n, remaining);
492 remaining -= n;
493 cp += n;
494
495 logger_for_each(logger, logger_list) {
496 n = snprintf(cp, remaining, " %d", logger->id);
497 n = min(n, remaining);
498 remaining -= n;
499 cp += n;
500 }
501
502 if (logger_list->pid) {
503 snprintf(cp, remaining, " pid=%u", logger_list->pid);
504 }
505
506 return send_log_msg(NULL, NULL, buf, len);
507}
508
509LIBLOG_ABI_PUBLIC ssize_t android_logger_get_prune_list(
510 struct logger_list *logger_list __unused,
511 char *buf, size_t len)
512{
513 return send_log_msg(NULL, "getPruneList", buf, len);
514}
515
516LIBLOG_ABI_PUBLIC int android_logger_set_prune_list(
517 struct logger_list *logger_list __unused,
518 char *buf, size_t len)
519{
520 const char cmd[] = "setPruneList ";
521 const size_t cmdlen = sizeof(cmd) - 1;
522
523 if (strlen(buf) > (len - cmdlen)) {
524 return -ENOMEM; /* KISS */
525 }
526 memmove(buf + cmdlen, buf, len - cmdlen);
527 buf[len - 1] = '\0';
528 memcpy(buf, cmd, cmdlen);
529
530 return check_log_success(buf, send_log_msg(NULL, NULL, buf, len));
531}
532
533LIBLOG_ABI_PUBLIC struct logger_list *android_logger_list_alloc(
534 int mode,
535 unsigned int tail,
536 pid_t pid)
537{
538 struct logger_list *logger_list;
539
540 logger_list = calloc(1, sizeof(*logger_list));
541 if (!logger_list) {
542 return NULL;
543 }
544
545 list_init(&logger_list->node);
546 logger_list->mode = mode;
547 logger_list->start.tv_sec = 0;
548 logger_list->start.tv_nsec = 0;
549 logger_list->tail = tail;
550 logger_list->pid = pid;
551 logger_list->sock = -1;
552
553 return logger_list;
554}
555
556LIBLOG_ABI_PUBLIC struct logger_list *android_logger_list_alloc_time(
557 int mode,
558 log_time start,
559 pid_t pid)
560{
561 struct logger_list *logger_list;
562
563 logger_list = calloc(1, sizeof(*logger_list));
564 if (!logger_list) {
565 return NULL;
566 }
567
568 list_init(&logger_list->node);
569 logger_list->mode = mode;
570 logger_list->start = start;
571 logger_list->tail = 0;
572 logger_list->pid = pid;
573 logger_list->sock = -1;
574
575 return logger_list;
576}
577
578/* android_logger_list_register unimplemented, no use case */
579/* android_logger_list_unregister unimplemented, no use case */
580
581/* Open the named log and add it to the logger list */
582LIBLOG_ABI_PUBLIC struct logger *android_logger_open(
583 struct logger_list *logger_list,
584 log_id_t id)
585{
586 struct logger *logger;
587
588 if (!logger_list || (id >= LOG_ID_MAX)) {
589 goto err;
590 }
591
592 logger_for_each(logger, logger_list) {
593 if (logger->id == id) {
594 goto ok;
595 }
596 }
597
598 logger = calloc(1, sizeof(*logger));
599 if (!logger) {
600 goto err;
601 }
602
603 logger->id = id;
604 list_add_tail(&logger_list->node, &logger->node);
605 logger->top = logger_list;
606 goto ok;
607
608err:
609 logger = NULL;
610ok:
611 return logger;
612}
613
614/* Open the single named log and make it part of a new logger list */
615LIBLOG_ABI_PUBLIC struct logger_list *android_logger_list_open(
616 log_id_t id,
617 int mode,
618 unsigned int tail,
619 pid_t pid)
620{
621 struct logger_list *logger_list = android_logger_list_alloc(mode, tail, pid);
622 if (!logger_list) {
623 return NULL;
624 }
625
626 if (!android_logger_open(logger_list, id)) {
627 android_logger_list_free(logger_list);
628 return NULL;
629 }
630
631 return logger_list;
632}
633
634static int android_logger_list_read_pstore(struct logger_list *logger_list,
635 struct log_msg *log_msg)
636{
637 ssize_t ret;
638 off_t current, next;
639 uid_t uid;
640 struct logger *logger;
641 struct __attribute__((__packed__)) {
642 android_pmsg_log_header_t p;
643 android_log_header_t l;
644 } buf;
645 static uint8_t preread_count;
646 bool is_system;
647
648 memset(log_msg, 0, sizeof(*log_msg));
649
650 if (logger_list->sock < 0) {
651 int fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY);
652
653 if (fd < 0) {
654 return -errno;
655 }
656 logger_list->sock = fd;
657 preread_count = 0;
658 }
659
660 while(1) {
661 if (preread_count < sizeof(buf)) {
662 ret = TEMP_FAILURE_RETRY(read(logger_list->sock,
663 &buf.p.magic + preread_count,
664 sizeof(buf) - preread_count));
665 if (ret < 0) {
666 return -errno;
667 }
668 preread_count += ret;
669 }
670 if (preread_count != sizeof(buf)) {
671 return preread_count ? -EIO : -EAGAIN;
672 }
673 if ((buf.p.magic != LOGGER_MAGIC)
674 || (buf.p.len <= sizeof(buf))
675 || (buf.p.len > (sizeof(buf) + LOGGER_ENTRY_MAX_PAYLOAD))
676 || (buf.l.id >= LOG_ID_MAX)
677 || (buf.l.realtime.tv_nsec >= NS_PER_SEC)) {
678 do {
679 memmove(&buf.p.magic, &buf.p.magic + 1, --preread_count);
680 } while (preread_count && (buf.p.magic != LOGGER_MAGIC));
681 continue;
682 }
683 preread_count = 0;
684
685 logger_for_each(logger, logger_list) {
686 if (buf.l.id != logger->id) {
687 continue;
688 }
689
690 if ((logger_list->start.tv_sec || logger_list->start.tv_nsec)
691 && ((logger_list->start.tv_sec > buf.l.realtime.tv_sec)
692 || ((logger_list->start.tv_sec == buf.l.realtime.tv_sec)
693 && (logger_list->start.tv_nsec > buf.l.realtime.tv_nsec)))) {
694 break;
695 }
696
697 if (logger_list->pid && (logger_list->pid != buf.p.pid)) {
698 break;
699 }
700
701 uid = get_best_effective_uid();
702 is_system = uid_has_log_permission(uid);
703 if (!is_system && (uid != buf.p.uid)) {
704 break;
705 }
706
707 ret = TEMP_FAILURE_RETRY(read(logger_list->sock,
708 is_system ?
709 log_msg->entry_v4.msg :
710 log_msg->entry_v3.msg,
711 buf.p.len - sizeof(buf)));
712 if (ret < 0) {
713 return -errno;
714 }
715 if (ret != (ssize_t)(buf.p.len - sizeof(buf))) {
716 return -EIO;
717 }
718
719 log_msg->entry_v4.len = buf.p.len - sizeof(buf);
720 log_msg->entry_v4.hdr_size = is_system ?
721 sizeof(log_msg->entry_v4) :
722 sizeof(log_msg->entry_v3);
723 log_msg->entry_v4.pid = buf.p.pid;
724 log_msg->entry_v4.tid = buf.l.tid;
725 log_msg->entry_v4.sec = buf.l.realtime.tv_sec;
726 log_msg->entry_v4.nsec = buf.l.realtime.tv_nsec;
727 log_msg->entry_v4.lid = buf.l.id;
728 if (is_system) {
729 log_msg->entry_v4.uid = buf.p.uid;
730 }
731
732 return ret;
733 }
734
735 current = TEMP_FAILURE_RETRY(lseek(logger_list->sock,
736 (off_t)0, SEEK_CUR));
737 if (current < 0) {
738 return -errno;
739 }
740 next = TEMP_FAILURE_RETRY(lseek(logger_list->sock,
741 (off_t)(buf.p.len - sizeof(buf)),
742 SEEK_CUR));
743 if (next < 0) {
744 return -errno;
745 }
746 if ((next - current) != (ssize_t)(buf.p.len - sizeof(buf))) {
747 return -EIO;
748 }
749 }
750}
751
752static void caught_signal(int signum __unused)
753{
754}
755
756/* Read from the selected logs */
757LIBLOG_ABI_PUBLIC int android_logger_list_read(
758 struct logger_list *logger_list,
759 struct log_msg *log_msg)
760{
761 int ret, e;
762 struct logger *logger;
763 struct sigaction ignore;
764 struct sigaction old_sigaction;
765 unsigned int old_alarm = 0;
766
767 if (!logger_list) {
768 return -EINVAL;
769 }
770
771 if (logger_list->mode & ANDROID_LOG_PSTORE) {
772 return android_logger_list_read_pstore(logger_list, log_msg);
773 }
774
775 if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
776 memset(&ignore, 0, sizeof(ignore));
777 ignore.sa_handler = caught_signal;
778 sigemptyset(&ignore.sa_mask);
779 }
780
781 if (logger_list->sock < 0) {
782 char buffer[256], *cp, c;
783
784 int sock = socket_local_client("logdr",
785 ANDROID_SOCKET_NAMESPACE_RESERVED,
786 SOCK_SEQPACKET);
787 if (sock < 0) {
788 if ((sock == -1) && errno) {
789 return -errno;
790 }
791 return sock;
792 }
793
794 strcpy(buffer,
795 (logger_list->mode & ANDROID_LOG_NONBLOCK) ? "dumpAndClose" : "stream");
796 cp = buffer + strlen(buffer);
797
798 strcpy(cp, " lids");
799 cp += 5;
800 c = '=';
801 int remaining = sizeof(buffer) - (cp - buffer);
802 logger_for_each(logger, logger_list) {
803 ret = snprintf(cp, remaining, "%c%u", c, logger->id);
804 ret = min(ret, remaining);
805 remaining -= ret;
806 cp += ret;
807 c = ',';
808 }
809
810 if (logger_list->tail) {
811 ret = snprintf(cp, remaining, " tail=%u", logger_list->tail);
812 ret = min(ret, remaining);
813 remaining -= ret;
814 cp += ret;
815 }
816
817 if (logger_list->start.tv_sec || logger_list->start.tv_nsec) {
818 if (logger_list->mode & ANDROID_LOG_WRAP) {
819 // ToDo: alternate API to allow timeout to be adjusted.
820 ret = snprintf(cp, remaining, " timeout=%u",
821 ANDROID_LOG_WRAP_DEFAULT_TIMEOUT);
822 ret = min(ret, remaining);
823 remaining -= ret;
824 cp += ret;
825 }
826 ret = snprintf(cp, remaining, " start=%" PRIu32 ".%09" PRIu32,
827 logger_list->start.tv_sec,
828 logger_list->start.tv_nsec);
829 ret = min(ret, remaining);
830 remaining -= ret;
831 cp += ret;
832 }
833
834 if (logger_list->pid) {
835 ret = snprintf(cp, remaining, " pid=%u", logger_list->pid);
836 ret = min(ret, remaining);
837 cp += ret;
838 }
839
840 if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
841 /* Deal with an unresponsive logd */
842 sigaction(SIGALRM, &ignore, &old_sigaction);
843 old_alarm = alarm(30);
844 }
845 ret = write(sock, buffer, cp - buffer);
846 e = errno;
847 if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
848 if (e == EINTR) {
849 e = ETIMEDOUT;
850 }
851 alarm(old_alarm);
852 sigaction(SIGALRM, &old_sigaction, NULL);
853 }
854
855 if (ret <= 0) {
856 close(sock);
857 if ((ret == -1) && e) {
858 return -e;
859 }
860 if (ret == 0) {
861 return -EIO;
862 }
863 return ret;
864 }
865
866 logger_list->sock = sock;
867 }
868
869 while(1) {
870 memset(log_msg, 0, sizeof(*log_msg));
871
872 if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
873 /* particularily useful if tombstone is reporting for logd */
874 sigaction(SIGALRM, &ignore, &old_sigaction);
875 old_alarm = alarm(30);
876 }
877 /* NOTE: SOCK_SEQPACKET guarantees we read exactly one full entry */
878 ret = recv(logger_list->sock, log_msg, LOGGER_ENTRY_MAX_LEN, 0);
879 e = errno;
880 if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
881 if ((ret == 0) || (e == EINTR)) {
882 e = EAGAIN;
883 ret = -1;
884 }
885 alarm(old_alarm);
886 sigaction(SIGALRM, &old_sigaction, NULL);
887 }
888
889 if ((ret == -1) && e) {
890 return -e;
891 }
892 return ret;
893 }
894 /* NOTREACH */
895 return ret;
896}
897
898/* Close all the logs */
899LIBLOG_ABI_PUBLIC void android_logger_list_free(
900 struct logger_list *logger_list)
901{
902 if (logger_list == NULL) {
903 return;
904 }
905
906 while (!list_empty(&logger_list->node)) {
907 struct listnode *node = list_head(&logger_list->node);
908 struct logger *logger = node_to_item(node, struct logger, node);
909 android_logger_free(logger);
910 }
911
912 if (logger_list->sock >= 0) {
913 close (logger_list->sock);
914 }
915
916 free(logger_list);
917}
diff --git a/liblog/log_time.cpp b/liblog/log_time.cpp
index b6af2221c..d2bf18166 100644
--- a/liblog/log_time.cpp
+++ b/liblog/log_time.cpp
@@ -21,7 +21,7 @@
21 21
22#include <log/log_read.h> 22#include <log/log_read.h>
23 23
24#include "log_cdefs.h" 24#include "log_portability.h"
25 25
26LIBLOG_ABI_PRIVATE const char log_time::default_format[] = "%m-%d %H:%M:%S.%q"; 26LIBLOG_ABI_PRIVATE const char log_time::default_format[] = "%m-%d %H:%M:%S.%q";
27LIBLOG_ABI_PRIVATE const timespec log_time::EPOCH = { 0, 0 }; 27LIBLOG_ABI_PRIVATE const timespec log_time::EPOCH = { 0, 0 };
diff --git a/liblog/logd_reader.c b/liblog/logd_reader.c
new file mode 100644
index 000000000..d8441040c
--- /dev/null
+++ b/liblog/logd_reader.c
@@ -0,0 +1,670 @@
1/*
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 <endian.h>
18#include <errno.h>
19#include <fcntl.h>
20#include <inttypes.h>
21#include <poll.h>
22#include <stdarg.h>
23#include <stdatomic.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <sys/stat.h>
28#include <sys/types.h>
29#include <sys/socket.h>
30#include <sys/un.h>
31#include <time.h>
32#include <unistd.h>
33
34#include <cutils/sockets.h>
35#include <log/logd.h>
36#include <log/logger.h>
37#include <log/log_read.h>
38#include <private/android_filesystem_config.h>
39#include <private/android_logger.h>
40
41#include "config_read.h"
42#include "log_portability.h"
43#include "logger.h"
44
45/* branchless on many architectures. */
46#define min(x,y) ((y) ^ (((x) ^ (y)) & -((x) < (y))))
47
48static int logdAvailable(log_id_t LogId);
49static int logdVersion(struct android_log_logger *logger,
50 struct android_log_transport_context *transp);
51static int logdRead(struct android_log_logger_list *logger_list,
52 struct android_log_transport_context *transp,
53 struct log_msg *log_msg);
54static int logdPoll(struct android_log_logger_list *logger_list,
55 struct android_log_transport_context *transp);
56static void logdClose(struct android_log_logger_list *logger_list,
57 struct android_log_transport_context *transp);
58static int logdClear(struct android_log_logger *logger,
59 struct android_log_transport_context *transp);
60static ssize_t logdSetSize(struct android_log_logger *logger,
61 struct android_log_transport_context *transp,
62 size_t size);
63static ssize_t logdGetSize(struct android_log_logger *logger,
64 struct android_log_transport_context *transp);
65static ssize_t logdGetReadableSize(struct android_log_logger *logger,
66 struct android_log_transport_context *transp);
67static ssize_t logdGetPrune(struct android_log_logger_list *logger,
68 struct android_log_transport_context *transp,
69 char *buf, size_t len);
70static ssize_t logdSetPrune(struct android_log_logger_list *logger,
71 struct android_log_transport_context *transp,
72 char *buf, size_t len);
73static ssize_t logdGetStats(struct android_log_logger_list *logger,
74 struct android_log_transport_context *transp,
75 char *buf, size_t len);
76
77LIBLOG_HIDDEN struct android_log_transport_read logdLoggerRead = {
78 .node = { &logdLoggerRead.node, &logdLoggerRead.node },
79 .name = "logd",
80 .available = logdAvailable,
81 .version = logdVersion,
82 .read = logdRead,
83 .poll = logdPoll,
84 .close = logdClose,
85 .clear = logdClear,
86 .getSize = logdGetSize,
87 .setSize = logdSetSize,
88 .getReadableSize = logdGetSize,
89 .getPrune = logdGetPrune,
90 .setPrune = logdSetPrune,
91 .getStats = logdGetStats,
92};
93
94static int logdAvailable(log_id_t logId)
95{
96 if (logId > LOG_ID_KERNEL) {
97 return -EINVAL;
98 }
99 if (logId == LOG_ID_SECURITY) {
100 uid_t uid = __android_log_uid();
101 if (uid != AID_SYSTEM) {
102 return -EPERM;
103 }
104 }
105 if (access("/dev/socket/logdw", W_OK) == 0) {
106 return 0;
107 }
108 return -EBADF;
109}
110
111/* Private copy of ../libcutils/socket_local_client.c prevent library loops */
112
113#if defined(_WIN32)
114
115LIBLOG_WEAK int socket_local_client(const char *name, int namespaceId, int type)
116{
117 errno = ENOSYS;
118 return -ENOSYS;
119}
120
121#else /* !_WIN32 */
122
123#include <sys/socket.h>
124#include <sys/un.h>
125#include <sys/select.h>
126#include <sys/types.h>
127
128/* Private copy of ../libcutils/socket_local.h prevent library loops */
129#define FILESYSTEM_SOCKET_PREFIX "/tmp/"
130#define ANDROID_RESERVED_SOCKET_PREFIX "/dev/socket/"
131/* End of ../libcutils/socket_local.h */
132
133#define LISTEN_BACKLOG 4
134
135/* Documented in header file. */
136LIBLOG_WEAK int socket_make_sockaddr_un(const char *name, int namespaceId,
137 struct sockaddr_un *p_addr,
138 socklen_t *alen)
139{
140 memset (p_addr, 0, sizeof (*p_addr));
141 size_t namelen;
142
143 switch (namespaceId) {
144 case ANDROID_SOCKET_NAMESPACE_ABSTRACT:
145#if defined(__linux__)
146 namelen = strlen(name);
147
148 /* Test with length +1 for the *initial* '\0'. */
149 if ((namelen + 1) > sizeof(p_addr->sun_path)) {
150 goto error;
151 }
152
153 /*
154 * Note: The path in this case is *not* supposed to be
155 * '\0'-terminated. ("man 7 unix" for the gory details.)
156 */
157
158 p_addr->sun_path[0] = 0;
159 memcpy(p_addr->sun_path + 1, name, namelen);
160#else
161 /* this OS doesn't have the Linux abstract namespace */
162
163 namelen = strlen(name) + strlen(FILESYSTEM_SOCKET_PREFIX);
164 /* unix_path_max appears to be missing on linux */
165 if (namelen > sizeof(*p_addr)
166 - offsetof(struct sockaddr_un, sun_path) - 1) {
167 goto error;
168 }
169
170 strcpy(p_addr->sun_path, FILESYSTEM_SOCKET_PREFIX);
171 strcat(p_addr->sun_path, name);
172#endif
173 break;
174
175 case ANDROID_SOCKET_NAMESPACE_RESERVED:
176 namelen = strlen(name) + strlen(ANDROID_RESERVED_SOCKET_PREFIX);
177 /* unix_path_max appears to be missing on linux */
178 if (namelen > sizeof(*p_addr)
179 - offsetof(struct sockaddr_un, sun_path) - 1) {
180 goto error;
181 }
182
183 strcpy(p_addr->sun_path, ANDROID_RESERVED_SOCKET_PREFIX);
184 strcat(p_addr->sun_path, name);
185 break;
186
187 case ANDROID_SOCKET_NAMESPACE_FILESYSTEM:
188 namelen = strlen(name);
189 /* unix_path_max appears to be missing on linux */
190 if (namelen > sizeof(*p_addr)
191 - offsetof(struct sockaddr_un, sun_path) - 1) {
192 goto error;
193 }
194
195 strcpy(p_addr->sun_path, name);
196 break;
197
198 default:
199 /* invalid namespace id */
200 return -1;
201 }
202
203 p_addr->sun_family = AF_LOCAL;
204 *alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;
205 return 0;
206error:
207 return -1;
208}
209
210/**
211 * connect to peer named "name" on fd
212 * returns same fd or -1 on error.
213 * fd is not closed on error. that's your job.
214 *
215 * Used by AndroidSocketImpl
216 */
217LIBLOG_WEAK int socket_local_client_connect(int fd, const char *name,
218 int namespaceId, int type __unused)
219{
220 struct sockaddr_un addr;
221 socklen_t alen;
222 int err;
223
224 err = socket_make_sockaddr_un(name, namespaceId, &addr, &alen);
225
226 if (err < 0) {
227 goto error;
228 }
229
230 if(connect(fd, (struct sockaddr *) &addr, alen) < 0) {
231 goto error;
232 }
233
234 return fd;
235
236error:
237 return -1;
238}
239
240/**
241 * connect to peer named "name"
242 * returns fd or -1 on error
243 */
244LIBLOG_WEAK int socket_local_client(const char *name, int namespaceId, int type)
245{
246 int s;
247
248 s = socket(AF_LOCAL, type, 0);
249 if(s < 0) return -1;
250
251 if ( 0 > socket_local_client_connect(s, name, namespaceId, type)) {
252 close(s);
253 return -1;
254 }
255
256 return s;
257}
258
259#endif /* !_WIN32 */
260/* End of ../libcutils/socket_local_client.c */
261
262/* worker for sending the command to the logger */
263static ssize_t send_log_msg(struct android_log_logger *logger,
264 const char *msg, char *buf, size_t buf_size)
265{
266 ssize_t ret;
267 size_t len;
268 char *cp;
269 int errno_save = 0;
270 int sock = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED,
271 SOCK_STREAM);
272 if (sock < 0) {
273 return sock;
274 }
275
276 if (msg) {
277 snprintf(buf, buf_size, msg, logger ? logger->logId : (unsigned) -1);
278 }
279
280 len = strlen(buf) + 1;
281 ret = TEMP_FAILURE_RETRY(write(sock, buf, len));
282 if (ret <= 0) {
283 goto done;
284 }
285
286 len = buf_size;
287 cp = buf;
288 while ((ret = TEMP_FAILURE_RETRY(read(sock, cp, len))) > 0) {
289 struct pollfd p;
290
291 if (((size_t)ret == len) || (buf_size < PAGE_SIZE)) {
292 break;
293 }
294
295 len -= ret;
296 cp += ret;
297
298 memset(&p, 0, sizeof(p));
299 p.fd = sock;
300 p.events = POLLIN;
301
302 /* Give other side 20ms to refill pipe */
303 ret = TEMP_FAILURE_RETRY(poll(&p, 1, 20));
304
305 if (ret <= 0) {
306 break;
307 }
308
309 if (!(p.revents & POLLIN)) {
310 ret = 0;
311 break;
312 }
313 }
314
315 if (ret >= 0) {
316 ret += buf_size - len;
317 }
318
319done:
320 if ((ret == -1) && errno) {
321 errno_save = errno;
322 }
323 close(sock);
324 if (errno_save) {
325 errno = errno_save;
326 }
327 return ret;
328}
329
330static int check_log_success(char *buf, ssize_t ret)
331{
332 if (ret < 0) {
333 return ret;
334 }
335
336 if (strncmp(buf, "success", 7)) {
337 errno = EINVAL;
338 return -1;
339 }
340
341 return 0;
342}
343
344static int logdClear(struct android_log_logger *logger,
345 struct android_log_transport_context *transp __unused)
346{
347 char buf[512];
348
349 return check_log_success(buf,
350 send_log_msg(logger, "clear %d", buf, sizeof(buf)));
351}
352
353/* returns the total size of the log's ring buffer */
354static ssize_t logdGetSize(struct android_log_logger *logger,
355 struct android_log_transport_context *transp __unused)
356{
357 char buf[512];
358
359 ssize_t ret = send_log_msg(logger, "getLogSize %d", buf, sizeof(buf));
360 if (ret < 0) {
361 return ret;
362 }
363
364 if ((buf[0] < '0') || ('9' < buf[0])) {
365 return -1;
366 }
367
368 return atol(buf);
369}
370
371static ssize_t logdSetSize(
372 struct android_log_logger *logger,
373 struct android_log_transport_context *transp __unused,
374 size_t size)
375{
376 char buf[512];
377
378 snprintf(buf, sizeof(buf), "setLogSize %d %zu", logger->logId, size);
379
380 return check_log_success(buf, send_log_msg(NULL, NULL, buf, sizeof(buf)));
381}
382
383/*
384 * returns the readable size of the log's ring buffer (that is, amount of the
385 * log consumed)
386 */
387static ssize_t logdGetReadableSize(
388 struct android_log_logger *logger,
389 struct android_log_transport_context *transp __unused)
390{
391 char buf[512];
392
393 ssize_t ret = send_log_msg(logger, "getLogSizeUsed %d", buf, sizeof(buf));
394 if (ret < 0) {
395 return ret;
396 }
397
398 if ((buf[0] < '0') || ('9' < buf[0])) {
399 return -1;
400 }
401
402 return atol(buf);
403}
404
405/*
406 * returns the logger version
407 */
408static int logdVersion(
409 struct android_log_logger *logger __unused,
410 struct android_log_transport_context *transp __unused)
411{
412 uid_t uid = __android_log_uid();
413 return ((uid != AID_ROOT) && (uid != AID_LOG) && (uid != AID_SYSTEM)) ? 3 : 4;
414}
415
416/*
417 * returns statistics
418 */
419static ssize_t logdGetStats(struct android_log_logger_list *logger_list,
420 struct android_log_transport_context *transp __unused,
421 char *buf, size_t len)
422{
423 struct android_log_logger *logger;
424 char *cp = buf;
425 size_t remaining = len;
426 size_t n;
427
428 n = snprintf(cp, remaining, "getStatistics");
429 n = min(n, remaining);
430 remaining -= n;
431 cp += n;
432
433 logger_for_each(logger, logger_list) {
434 n = snprintf(cp, remaining, " %d", logger->logId);
435 n = min(n, remaining);
436 remaining -= n;
437 cp += n;
438 }
439
440 if (logger_list->pid) {
441 snprintf(cp, remaining, " pid=%u", logger_list->pid);
442 }
443
444 return send_log_msg(NULL, NULL, buf, len);
445}
446
447static ssize_t logdGetPrune(
448 struct android_log_logger_list *logger_list __unused,
449 struct android_log_transport_context *transp __unused,
450 char *buf, size_t len)
451{
452 return send_log_msg(NULL, "getPruneList", buf, len);
453}
454
455static ssize_t logdSetPrune(
456 struct android_log_logger_list *logger_list __unused,
457 struct android_log_transport_context *transp __unused,
458 char *buf, size_t len)
459{
460 const char cmd[] = "setPruneList ";
461 const size_t cmdlen = sizeof(cmd) - 1;
462
463 if (strlen(buf) > (len - cmdlen)) {
464 return -ENOMEM; /* KISS */
465 }
466 memmove(buf + cmdlen, buf, len - cmdlen);
467 buf[len - 1] = '\0';
468 memcpy(buf, cmd, cmdlen);
469
470 return check_log_success(buf, send_log_msg(NULL, NULL, buf, len));
471}
472
473
474static void caught_signal(int signum __unused)
475{
476}
477
478static int logdOpen(struct android_log_logger_list *logger_list,
479 struct android_log_transport_context *transp)
480{
481 struct android_log_logger *logger;
482 struct sigaction ignore;
483 struct sigaction old_sigaction;
484 unsigned int old_alarm = 0;
485 char buffer[256], *cp, c;
486 int e, ret, remaining;
487
488 int sock = transp->context.sock;
489 if (sock > 0) {
490 return sock;
491 }
492
493 if (!logger_list) {
494 return -EINVAL;
495 }
496
497 sock = socket_local_client("logdr",
498 ANDROID_SOCKET_NAMESPACE_RESERVED,
499 SOCK_SEQPACKET);
500 if (sock == 0) {
501 /* Guarantee not file descriptor zero */
502 int newsock = socket_local_client("logdr",
503 ANDROID_SOCKET_NAMESPACE_RESERVED,
504 SOCK_SEQPACKET);
505 close(sock);
506 sock = newsock;
507 }
508 if (sock <= 0) {
509 if ((sock == -1) && errno) {
510 return -errno;
511 }
512 return sock;
513 }
514
515 strcpy(buffer, (logger_list->mode & ANDROID_LOG_NONBLOCK) ?
516 "dumpAndClose" : "stream");
517 cp = buffer + strlen(buffer);
518
519 strcpy(cp, " lids");
520 cp += 5;
521 c = '=';
522 remaining = sizeof(buffer) - (cp - buffer);
523 logger_for_each(logger, logger_list) {
524 ret = snprintf(cp, remaining, "%c%u", c, logger->logId);
525 ret = min(ret, remaining);
526 remaining -= ret;
527 cp += ret;
528 c = ',';
529 }
530
531 if (logger_list->tail) {
532 ret = snprintf(cp, remaining, " tail=%u", logger_list->tail);
533 ret = min(ret, remaining);
534 remaining -= ret;
535 cp += ret;
536 }
537
538 if (logger_list->start.tv_sec || logger_list->start.tv_nsec) {
539 if (logger_list->mode & ANDROID_LOG_WRAP) {
540 // ToDo: alternate API to allow timeout to be adjusted.
541 ret = snprintf(cp, remaining, " timeout=%u",
542 ANDROID_LOG_WRAP_DEFAULT_TIMEOUT);
543 ret = min(ret, remaining);
544 remaining -= ret;
545 cp += ret;
546 }
547 ret = snprintf(cp, remaining, " start=%" PRIu32 ".%09" PRIu32,
548 logger_list->start.tv_sec,
549 logger_list->start.tv_nsec);
550 ret = min(ret, remaining);
551 remaining -= ret;
552 cp += ret;
553 }
554
555 if (logger_list->pid) {
556 ret = snprintf(cp, remaining, " pid=%u", logger_list->pid);
557 ret = min(ret, remaining);
558 cp += ret;
559 }
560
561 if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
562 /* Deal with an unresponsive logd */
563 memset(&ignore, 0, sizeof(ignore));
564 ignore.sa_handler = caught_signal;
565 sigemptyset(&ignore.sa_mask);
566 /* particularily useful if tombstone is reporting for logd */
567 sigaction(SIGALRM, &ignore, &old_sigaction);
568 old_alarm = alarm(30);
569 }
570 ret = write(sock, buffer, cp - buffer);
571 e = errno;
572 if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
573 if (e == EINTR) {
574 e = ETIMEDOUT;
575 }
576 alarm(old_alarm);
577 sigaction(SIGALRM, &old_sigaction, NULL);
578 }
579
580 if (ret <= 0) {
581 close(sock);
582 if ((ret == -1) && e) {
583 return -e;
584 }
585 if (ret == 0) {
586 return -EIO;
587 }
588 return ret;
589 }
590
591 return transp->context.sock = sock;
592}
593
594/* Read from the selected logs */
595static int logdRead(struct android_log_logger_list *logger_list,
596 struct android_log_transport_context *transp,
597 struct log_msg *log_msg)
598{
599 int ret, e;
600 struct sigaction ignore;
601 struct sigaction old_sigaction;
602 unsigned int old_alarm = 0;
603
604 ret = logdOpen(logger_list, transp);
605 if (ret < 0) {
606 return ret;
607 }
608
609 memset(log_msg, 0, sizeof(*log_msg));
610
611 if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
612 memset(&ignore, 0, sizeof(ignore));
613 ignore.sa_handler = caught_signal;
614 sigemptyset(&ignore.sa_mask);
615 /* particularily useful if tombstone is reporting for logd */
616 sigaction(SIGALRM, &ignore, &old_sigaction);
617 old_alarm = alarm(30);
618 }
619
620 /* NOTE: SOCK_SEQPACKET guarantees we read exactly one full entry */
621 ret = recv(ret, log_msg, LOGGER_ENTRY_MAX_LEN, 0);
622 e = errno;
623
624 if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
625 if ((ret == 0) || (e == EINTR)) {
626 e = EAGAIN;
627 ret = -1;
628 }
629 alarm(old_alarm);
630 sigaction(SIGALRM, &old_sigaction, NULL);
631 }
632
633 if ((ret == -1) && e) {
634 return -e;
635 }
636 return ret;
637}
638
639static int logdPoll(struct android_log_logger_list *logger_list,
640 struct android_log_transport_context *transp)
641{
642 struct pollfd p;
643
644 int ret = logdOpen(logger_list, transp);
645 if (ret < 0) {
646 return ret;
647 }
648
649 memset(&p, 0, sizeof(p));
650 p.fd = ret;
651 p.events = POLLIN;
652 ret = poll(&p, 1, 20);
653 if ((ret > 0) && !(p.revents & POLLIN)) {
654 ret = 0;
655 }
656 if ((ret == -1) && errno) {
657 return -errno;
658 }
659 return ret;
660}
661
662/* Close all the logs */
663static void logdClose(struct android_log_logger_list *logger_list __unused,
664 struct android_log_transport_context *transp)
665{
666 if (transp->context.sock > 0) {
667 close (transp->context.sock);
668 transp->context.sock = -1;
669 }
670}
diff --git a/liblog/logd_writer.c b/liblog/logd_writer.c
new file mode 100644
index 000000000..696237d34
--- /dev/null
+++ b/liblog/logd_writer.c
@@ -0,0 +1,267 @@
1/*
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 <endian.h>
18#include <errno.h>
19#include <fcntl.h>
20#include <inttypes.h>
21#include <poll.h>
22#include <stdarg.h>
23#include <stdatomic.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <sys/stat.h>
28#include <sys/types.h>
29#include <sys/socket.h>
30#include <sys/un.h>
31#include <time.h>
32#include <unistd.h>
33
34#include <cutils/sockets.h>
35#include <log/logd.h>
36#include <log/logger.h>
37#include <log/log_read.h>
38#include <private/android_filesystem_config.h>
39#include <private/android_logger.h>
40
41#include "config_write.h"
42#include "log_portability.h"
43#include "logger.h"
44
45/* branchless on many architectures. */
46#define min(x,y) ((y) ^ (((x) ^ (y)) & -((x) < (y))))
47
48static int logdAvailable(log_id_t LogId);
49static int logdOpen();
50static void logdClose();
51static int logdWrite(log_id_t logId, struct timespec *ts,
52 struct iovec *vec, size_t nr);
53
54LIBLOG_HIDDEN struct android_log_transport_write logdLoggerWrite = {
55 .node = { &logdLoggerWrite.node, &logdLoggerWrite.node },
56 .context.sock = -1,
57 .name = "logd",
58 .available = logdAvailable,
59 .open = logdOpen,
60 .close = logdClose,
61 .write = logdWrite,
62};
63
64/* log_init_lock assumed */
65static int logdOpen()
66{
67 int i, ret = 0;
68
69 if (logdLoggerWrite.context.sock < 0) {
70 i = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0));
71 if (i < 0) {
72 ret = -errno;
73 } else if (TEMP_FAILURE_RETRY(fcntl(i, F_SETFL, O_NONBLOCK)) < 0) {
74 ret = -errno;
75 close(i);
76 } else {
77 struct sockaddr_un un;
78 memset(&un, 0, sizeof(struct sockaddr_un));
79 un.sun_family = AF_UNIX;
80 strcpy(un.sun_path, "/dev/socket/logdw");
81
82 if (TEMP_FAILURE_RETRY(connect(i, (struct sockaddr *)&un,
83 sizeof(struct sockaddr_un))) < 0) {
84 ret = -errno;
85 close(i);
86 } else {
87 logdLoggerWrite.context.sock = i;
88 }
89 }
90 }
91
92 return ret;
93}
94
95static void logdClose()
96{
97 if (logdLoggerWrite.context.sock >= 0) {
98 close(logdLoggerWrite.context.sock);
99 logdLoggerWrite.context.sock = -1;
100 }
101}
102
103static int logdAvailable(log_id_t logId)
104{
105 if (logId > LOG_ID_SECURITY) {
106 return -EINVAL;
107 }
108 if (logId == LOG_ID_SECURITY) {
109 uid_t uid = __android_log_uid();
110 if ((uid != AID_LOG) && (uid != AID_ROOT) && (uid != AID_SYSTEM)) {
111 return -EPERM;
112 }
113 }
114 if (logdLoggerWrite.context.sock < 0) {
115 if (access("/dev/socket/logdw", W_OK) == 0) {
116 return 0;
117 }
118 return -EBADF;
119 }
120 return 1;
121}
122
123static int logdWrite(log_id_t logId, struct timespec *ts,
124 struct iovec *vec, size_t nr)
125{
126 ssize_t ret;
127 static const unsigned headerLength = 1;
128 struct iovec newVec[nr + headerLength];
129 android_log_header_t header;
130 size_t i, payloadSize;
131 static atomic_int_fast32_t dropped;
132 static atomic_int_fast32_t droppedSecurity;
133
134 if (logdLoggerWrite.context.sock < 0) {
135 return -EBADF;
136 }
137
138 /* logd, after initialization and priv drop */
139 if (__android_log_uid() == AID_LOGD) {
140 /*
141 * ignore log messages we send to ourself (logd).
142 * Such log messages are often generated by libraries we depend on
143 * which use standard Android logging.
144 */
145 return 0;
146 }
147
148 /*
149 * struct {
150 * // what we provide to socket
151 * android_log_header_t header;
152 * // caller provides
153 * union {
154 * struct {
155 * char prio;
156 * char payload[];
157 * } string;
158 * struct {
159 * uint32_t tag
160 * char payload[];
161 * } binary;
162 * };
163 * };
164 */
165
166 header.tid = gettid();
167 header.realtime.tv_sec = ts->tv_sec;
168 header.realtime.tv_nsec = ts->tv_nsec;
169
170 newVec[0].iov_base = (unsigned char *)&header;
171 newVec[0].iov_len = sizeof(header);
172
173 if (logdLoggerWrite.context.sock > 0) {
174 int32_t snapshot = atomic_exchange_explicit(&droppedSecurity, 0,
175 memory_order_relaxed);
176 if (snapshot) {
177 android_log_event_int_t buffer;
178
179 header.id = LOG_ID_SECURITY;
180 buffer.header.tag = htole32(LIBLOG_LOG_TAG);
181 buffer.payload.type = EVENT_TYPE_INT;
182 buffer.payload.data = htole32(snapshot);
183
184 newVec[headerLength].iov_base = &buffer;
185 newVec[headerLength].iov_len = sizeof(buffer);
186
187 ret = TEMP_FAILURE_RETRY(writev(logdLoggerWrite.context.sock, newVec, 2));
188 if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
189 atomic_fetch_add_explicit(&droppedSecurity, snapshot,
190 memory_order_relaxed);
191 }
192 }
193 snapshot = atomic_exchange_explicit(&dropped, 0, memory_order_relaxed);
194 if (snapshot && __android_log_is_loggable(ANDROID_LOG_INFO,
195 "liblog",
196 ANDROID_LOG_VERBOSE)) {
197 android_log_event_int_t buffer;
198
199 header.id = LOG_ID_EVENTS;
200 buffer.header.tag = htole32(LIBLOG_LOG_TAG);
201 buffer.payload.type = EVENT_TYPE_INT;
202 buffer.payload.data = htole32(snapshot);
203
204 newVec[headerLength].iov_base = &buffer;
205 newVec[headerLength].iov_len = sizeof(buffer);
206
207 ret = TEMP_FAILURE_RETRY(writev(logdLoggerWrite.context.sock, newVec, 2));
208 if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
209 atomic_fetch_add_explicit(&dropped, snapshot,
210 memory_order_relaxed);
211 }
212 }
213 }
214
215 header.id = logId;
216
217 for (payloadSize = 0, i = headerLength; i < nr + headerLength; i++) {
218 newVec[i].iov_base = vec[i - headerLength].iov_base;
219 payloadSize += newVec[i].iov_len = vec[i - headerLength].iov_len;
220
221 if (payloadSize > LOGGER_ENTRY_MAX_PAYLOAD) {
222 newVec[i].iov_len -= payloadSize - LOGGER_ENTRY_MAX_PAYLOAD;
223 if (newVec[i].iov_len) {
224 ++i;
225 }
226 break;
227 }
228 }
229
230 /*
231 * The write below could be lost, but will never block.
232 *
233 * ENOTCONN occurs if logd dies.
234 * EAGAIN occurs if logd is overloaded.
235 */
236 ret = TEMP_FAILURE_RETRY(writev(logdLoggerWrite.context.sock, newVec, i));
237 if (ret < 0) {
238 ret = -errno;
239 if (ret == -ENOTCONN) {
240 __android_log_lock();
241 logdClose();
242 ret = logdOpen();
243 __android_log_unlock();
244
245 if (ret < 0) {
246 return ret;
247 }
248
249 ret = TEMP_FAILURE_RETRY(writev(logdLoggerWrite.context.sock, newVec, i));
250 if (ret < 0) {
251 ret = -errno;
252 }
253 }
254 }
255
256 if (ret > (ssize_t)sizeof(header)) {
257 ret -= sizeof(header);
258 } else if (ret == -EAGAIN) {
259 atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed);
260 if (logId == LOG_ID_SECURITY) {
261 atomic_fetch_add_explicit(&droppedSecurity, 1,
262 memory_order_relaxed);
263 }
264 }
265
266 return ret;
267}
diff --git a/liblog/logger.h b/liblog/logger.h
new file mode 100644
index 000000000..61bc3968a
--- /dev/null
+++ b/liblog/logger.h
@@ -0,0 +1,159 @@
1/*
2 * Copyright (C) 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#ifndef _LIBLOG_LOGGER_H__
18#define _LIBLOG_LOGGER_H__
19
20#include <stdbool.h>
21#include <log/uio.h>
22
23#include <cutils/list.h>
24#include <log/log.h>
25#include <log/log_read.h>
26#include <log/logger.h>
27
28#include "log_portability.h"
29
30__BEGIN_DECLS
31
32/* Union, sock or fd of zero is not allowed unless static initialized */
33union android_log_context {
34 void *private;
35 int sock;
36 int fd;
37 struct listnode *node;
38};
39
40struct android_log_transport_write {
41 struct listnode node;
42 const char *name;
43 union android_log_context context; /* Initialized by static allocation */
44
45 int (*available)(log_id_t logId);
46 int (*open)();
47 void (*close)();
48 int (*write)(log_id_t logId, struct timespec *ts, struct iovec *vec, size_t nr);
49};
50
51struct android_log_logger_list;
52struct android_log_transport_context;
53struct android_log_logger;
54
55struct android_log_transport_read {
56 struct listnode node;
57 const char *name;
58
59 int (*available)(log_id_t logId);
60 int (*version)(struct android_log_logger *logger,
61 struct android_log_transport_context *transp);
62 void (*close)(struct android_log_logger_list *logger_list,
63 struct android_log_transport_context *transp);
64
65 /*
66 * Expect all to instantiate open on any call, so we do not have
67 * an expicit open call
68 */
69 int (*read)(struct android_log_logger_list *logger_list,
70 struct android_log_transport_context *transp,
71 struct log_msg *log_msg);
72 /* Assumption is only called if not ANDROID_LOG_NONBLOCK */
73 int (*poll)(struct android_log_logger_list *logger_list,
74 struct android_log_transport_context *transp);
75
76 int (*clear)(struct android_log_logger *logger,
77 struct android_log_transport_context *transp);
78 ssize_t (*setSize)(struct android_log_logger *logger,
79 struct android_log_transport_context *transp,
80 size_t size);
81 ssize_t (*getSize)(struct android_log_logger *logger,
82 struct android_log_transport_context *transp);
83 ssize_t (*getReadableSize)(struct android_log_logger *logger,
84 struct android_log_transport_context *transp);
85
86 ssize_t (*getPrune)(struct android_log_logger_list *logger_list,
87 struct android_log_transport_context *transp,
88 char *buf, size_t len);
89 ssize_t (*setPrune)(struct android_log_logger_list *logger_list,
90 struct android_log_transport_context *transp,
91 char *buf, size_t len);
92 ssize_t (*getStats)(struct android_log_logger_list *logger_list,
93 struct android_log_transport_context *transp,
94 char *buf, size_t len);
95};
96
97struct android_log_logger_list {
98 struct listnode logger;
99 struct listnode transport;
100 int mode;
101 unsigned int tail;
102 log_time start;
103 pid_t pid;
104};
105
106struct android_log_logger {
107 struct listnode node;
108 struct android_log_logger_list *parent;
109
110 log_id_t logId;
111};
112
113struct android_log_transport_context {
114 struct listnode node;
115 union android_log_context context; /* zero init per-transport context */
116 struct android_log_logger_list *parent;
117
118 struct android_log_transport_read *transport;
119 unsigned logMask;
120 int ret;
121 struct log_msg logMsg; /* valid is logMsg.len != 0 */
122};
123
124/* assumes caller has structures read-locked, single threaded, or fenced */
125#define transport_context_for_each(transp, logger_list) \
126 for (transp = node_to_item((logger_list)->transport.next, \
127 struct android_log_transport_context, \
128 node); \
129 (transp != node_to_item(&(logger_list)->transport, \
130 struct android_log_transport_context, \
131 node)) && \
132 (transp->parent == (logger_list)); \
133 transp = node_to_item(transp->node.next, \
134 struct android_log_transport_context, node))
135
136#define logger_for_each(logp, logger_list) \
137 for (logp = node_to_item((logger_list)->logger.next, \
138 struct android_log_logger, node); \
139 (logp != node_to_item(&(logger_list)->logger, \
140 struct android_log_logger, node)) && \
141 (logp->parent == (logger_list)); \
142 logp = node_to_item((logp)->node.next, \
143 struct android_log_logger, node))
144
145/* OS specific dribs and drabs */
146
147#if defined(_WIN32)
148typedef uint32_t uid_t;
149#endif
150
151LIBLOG_HIDDEN uid_t __android_log_uid();
152LIBLOG_HIDDEN pid_t __android_log_pid();
153LIBLOG_HIDDEN void __android_log_lock();
154LIBLOG_HIDDEN int __android_log_trylock();
155LIBLOG_HIDDEN void __android_log_unlock();
156
157__END_DECLS
158
159#endif /* _LIBLOG_LOGGER_H__ */
diff --git a/liblog/logger_lock.c b/liblog/logger_lock.c
new file mode 100644
index 000000000..ee979bd5e
--- /dev/null
+++ b/liblog/logger_lock.c
@@ -0,0 +1,82 @@
1/*
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/*
18 * Some OS specific dribs and drabs (locking etc).
19 */
20
21#if !defined(_WIN32)
22#include <pthread.h>
23#endif
24
25#include <private/android_filesystem_config.h>
26
27#include "logger.h"
28
29LIBLOG_HIDDEN uid_t __android_log_uid()
30{
31#if defined(_WIN32)
32 return AID_SYSTEM;
33#else
34 static uid_t last_uid = AID_ROOT; /* logd *always* starts up as AID_ROOT */
35
36 if (last_uid == AID_ROOT) { /* have we called to get the UID yet? */
37 last_uid = getuid();
38 }
39 return last_uid;
40#endif
41}
42
43LIBLOG_HIDDEN pid_t __android_log_pid()
44{
45 static pid_t last_pid = (pid_t) -1;
46
47 if (last_pid == (pid_t) -1) {
48 last_pid = getpid();
49 }
50 return last_pid;
51}
52
53#if !defined(_WIN32)
54static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
55#endif
56
57LIBLOG_HIDDEN void __android_log_lock()
58{
59#if !defined(_WIN32)
60 /*
61 * If we trigger a signal handler in the middle of locked activity and the
62 * signal handler logs a message, we could get into a deadlock state.
63 */
64 pthread_mutex_lock(&log_init_lock);
65#endif
66}
67
68LIBLOG_HIDDEN int __android_log_trylock()
69{
70#if !defined(_WIN32)
71 return pthread_mutex_trylock(&log_init_lock);
72#else
73 return 0;
74#endif
75}
76
77LIBLOG_HIDDEN void __android_log_unlock()
78{
79#if !defined(_WIN32)
80 pthread_mutex_unlock(&log_init_lock);
81#endif
82}
diff --git a/liblog/logger_name.c b/liblog/logger_name.c
new file mode 100644
index 000000000..b7ccac51f
--- /dev/null
+++ b/liblog/logger_name.c
@@ -0,0 +1,65 @@
1/*
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 <string.h>
18
19#include <log/log.h>
20#include <log/logger.h>
21
22#include "log_portability.h"
23
24/* In the future, we would like to make this list extensible */
25static const char *LOG_NAME[LOG_ID_MAX] = {
26 [LOG_ID_MAIN] = "main",
27 [LOG_ID_RADIO] = "radio",
28 [LOG_ID_EVENTS] = "events",
29 [LOG_ID_SYSTEM] = "system",
30 [LOG_ID_CRASH] = "crash",
31 [LOG_ID_SECURITY] = "security",
32 [LOG_ID_KERNEL] = "kernel",
33};
34
35LIBLOG_ABI_PUBLIC const char *android_log_id_to_name(log_id_t log_id)
36{
37 if (log_id >= LOG_ID_MAX) {
38 log_id = LOG_ID_MAIN;
39 }
40 return LOG_NAME[log_id];
41}
42
43LIBLOG_ABI_PUBLIC log_id_t android_name_to_log_id(const char *logName)
44{
45 const char *b;
46 int ret;
47
48 if (!logName) {
49 return -1; /* NB: log_id_t is unsigned */
50 }
51 b = strrchr(logName, '/');
52 if (!b) {
53 b = logName;
54 } else {
55 ++b;
56 }
57
58 for(ret = LOG_ID_MIN; ret < LOG_ID_MAX; ++ret) {
59 const char *l = LOG_NAME[ret];
60 if (l && !strcmp(b, l)) {
61 return ret;
62 }
63 }
64 return -1; /* should never happen */
65}
diff --git a/liblog/logger_read.c b/liblog/logger_read.c
new file mode 100644
index 000000000..f15c7cd62
--- /dev/null
+++ b/liblog/logger_read.c
@@ -0,0 +1,474 @@
1/*
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}
diff --git a/liblog/logd_write.c b/liblog/logger_write.c
index 85a4aab52..a4155e927 100644
--- a/liblog/logd_write.c
+++ b/liblog/logger_write.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (C) 2007-2014 The Android Open Source Project 2 * Copyright (C) 2007-2016 The Android Open Source Project
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -13,27 +13,12 @@
13 * See the License for the specific language governing permissions and 13 * See the License for the specific language governing permissions and
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16#if (FAKE_LOG_DEVICE == 0) 16
17#include <endian.h>
18#endif
19#include <errno.h> 17#include <errno.h>
20#include <fcntl.h>
21#if !defined(_WIN32)
22#include <pthread.h>
23#endif
24#include <stdarg.h>
25#include <stdatomic.h> 18#include <stdatomic.h>
26#include <stdio.h>
27#include <stdlib.h> 19#include <stdlib.h>
28#include <string.h> 20#include <string.h>
29#include <sys/stat.h> 21#include <sys/time.h>
30#include <sys/types.h>
31#if (FAKE_LOG_DEVICE == 0)
32#include <sys/socket.h>
33#include <sys/un.h>
34#endif
35#include <time.h>
36#include <unistd.h>
37 22
38#ifdef __BIONIC__ 23#ifdef __BIONIC__
39#include <android/set_abort_message.h> 24#include <android/set_abort_message.h>
@@ -46,55 +31,15 @@
46#include <private/android_filesystem_config.h> 31#include <private/android_filesystem_config.h>
47#include <private/android_logger.h> 32#include <private/android_logger.h>
48 33
49#include "log_cdefs.h" 34#include "config_write.h"
35#include "log_portability.h"
36#include "logger.h"
50 37
51#define LOG_BUF_SIZE 1024 38#define LOG_BUF_SIZE 1024
52 39
53#if FAKE_LOG_DEVICE
54/* This will be defined when building for the host. */
55#include "fake_log_device.h"
56#endif
57
58static int __write_to_log_init(log_id_t, struct iovec *vec, size_t nr); 40static int __write_to_log_init(log_id_t, struct iovec *vec, size_t nr);
59static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = __write_to_log_init; 41static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = __write_to_log_init;
60 42
61#if !defined(_WIN32)
62static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
63
64static void lock()
65{
66 /*
67 * If we trigger a signal handler in the middle of locked activity and the
68 * signal handler logs a message, we could get into a deadlock state.
69 */
70 pthread_mutex_lock(&log_init_lock);
71}
72
73static int trylock()
74{
75 return pthread_mutex_trylock(&log_init_lock);
76}
77
78static void unlock()
79{
80 pthread_mutex_unlock(&log_init_lock);
81}
82
83#else /* !defined(_WIN32) */
84
85#define lock() ((void)0)
86#define trylock() (0) /* success */
87#define unlock() ((void)0)
88
89#endif /* !defined(_WIN32) */
90
91#if FAKE_LOG_DEVICE
92static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1, -1, -1 };
93#else
94static int logd_fd = -1;
95static int pstore_fd = -1;
96#endif
97
98/* 43/*
99 * This is used by the C++ code to decide if it should write logs through 44 * This is used by the C++ code to decide if it should write logs through
100 * the C code. Basically, if /dev/socket/logd is available, we're running in 45 * the C code. Basically, if /dev/socket/logd is available, we're running in
@@ -106,110 +51,101 @@ static enum {
106 51
107LIBLOG_ABI_PUBLIC int __android_log_dev_available() 52LIBLOG_ABI_PUBLIC int __android_log_dev_available()
108{ 53{
109 if (g_log_status == kLogUninitialized) { 54 struct android_log_transport_write *node;
110 if (access("/dev/socket/logdw", W_OK) == 0) 55 size_t i;
111 g_log_status = kLogAvailable;
112 else
113 g_log_status = kLogNotAvailable;
114 }
115 56
116 return (g_log_status == kLogAvailable); 57 if (list_empty(&__android_log_transport_write)) {
58 return kLogUninitialized;
59 }
60 for (i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
61 write_transport_for_each(node, &__android_log_transport_write) {
62 if (node->write &&
63 (!node->available || ((*node->available)(i) >= 0))) {
64 return kLogAvailable;
65 }
66 }
67 }
68 return kLogNotAvailable;
117} 69}
118 70
119/* log_init_lock assumed */ 71/* log_init_lock assumed */
120static int __write_to_log_initialize() 72static int __write_to_log_initialize()
121{ 73{
122 int i, ret = 0; 74 struct android_log_transport_write *transport;
123 75 struct listnode *n;
124#if FAKE_LOG_DEVICE 76 int i = 0, ret = 0;
125 for (i = 0; i < LOG_ID_MAX; i++) { 77
126 char buf[sizeof("/dev/log_security")]; 78 __android_log_config_write();
127 snprintf(buf, sizeof(buf), "/dev/log_%s", android_log_id_to_name(i)); 79 write_transport_for_each_safe(transport, n, &__android_log_transport_write) {
128 log_fds[i] = fakeLogOpen(buf, O_WRONLY); 80 if (!transport->open || ((*transport->open)() < 0)) {
129 } 81 if (transport->close) {
130#else 82 (*transport->close)();
131 if (pstore_fd < 0) { 83 }
132 pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY)); 84 list_remove(&transport->node);
85 continue;
86 }
87 ++ret;
133 } 88 }
134 89 write_transport_for_each_safe(transport, n, &__android_log_persist_write) {
135 if (logd_fd < 0) { 90 if (!transport->open || ((*transport->open)() < 0)) {
136 i = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0)); 91 if (transport->close) {
137 if (i < 0) { 92 (*transport->close)();
138 ret = -errno;
139 } else if (TEMP_FAILURE_RETRY(fcntl(i, F_SETFL, O_NONBLOCK)) < 0) {
140 ret = -errno;
141 close(i);
142 } else {
143 struct sockaddr_un un;
144 memset(&un, 0, sizeof(struct sockaddr_un));
145 un.sun_family = AF_UNIX;
146 strcpy(un.sun_path, "/dev/socket/logdw");
147
148 if (TEMP_FAILURE_RETRY(connect(i, (struct sockaddr *)&un,
149 sizeof(struct sockaddr_un))) < 0) {
150 ret = -errno;
151 close(i);
152 } else {
153 logd_fd = i;
154 } 93 }
94 list_remove(&transport->node);
95 continue;
155 } 96 }
97 ++i;
98 }
99 if (!ret && !i) {
100 return -ENODEV;
156 } 101 }
157#endif
158 102
159 return ret; 103 return ret;
160} 104}
161 105
162static int __write_to_log_daemon(log_id_t log_id, struct iovec *vec, size_t nr) 106/*
107 * Extract a 4-byte value from a byte stream. le32toh open coded
108 */
109static inline uint32_t get4LE(const uint8_t* src)
163{ 110{
164 ssize_t ret; 111 return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
165#if FAKE_LOG_DEVICE 112}
166 int log_fd;
167 113
168 if (/*(int)log_id >= 0 &&*/ (int)log_id < (int)LOG_ID_MAX) { 114static int __write_to_log_daemon(log_id_t log_id, struct iovec *vec, size_t nr)
169 log_fd = log_fds[(int)log_id]; 115{
170 } else { 116 struct android_log_transport_write *node;
171 return -EBADF; 117 int ret;
172 }
173 do {
174 ret = fakeLogWritev(log_fd, vec, nr);
175 if (ret < 0) {
176 ret = -errno;
177 }
178 } while (ret == -EINTR);
179#else
180 static const unsigned header_length = 2;
181 struct iovec newVec[nr + header_length];
182 android_log_header_t header;
183 android_pmsg_log_header_t pmsg_header;
184 struct timespec ts; 118 struct timespec ts;
185 size_t i, payload_size; 119 size_t len, i;
186 static uid_t last_uid = AID_ROOT; /* logd *always* starts up as AID_ROOT */
187 static pid_t last_pid = (pid_t) -1;
188 static atomic_int_fast32_t dropped;
189 static atomic_int_fast32_t dropped_security;
190 120
191 if (!nr) { 121 for (len = i = 0; i < nr; ++i) {
122 len += vec[i].iov_len;
123 }
124 if (!len) {
192 return -EINVAL; 125 return -EINVAL;
193 } 126 }
194 127
195 if (last_uid == AID_ROOT) { /* have we called to get the UID yet? */ 128#if defined(__BIONIC__)
196 last_uid = getuid();
197 }
198 if (last_pid == (pid_t) -1) {
199 last_pid = getpid();
200 }
201 if (log_id == LOG_ID_SECURITY) { 129 if (log_id == LOG_ID_SECURITY) {
130 uid_t uid;
131
202 if (vec[0].iov_len < 4) { 132 if (vec[0].iov_len < 4) {
203 return -EINVAL; 133 return -EINVAL;
204 } 134 }
135
136 uid = __android_log_uid();
205 /* Matches clientHasLogCredentials() in logd */ 137 /* Matches clientHasLogCredentials() in logd */
206 if ((last_uid != AID_SYSTEM) && (last_uid != AID_ROOT) && (last_uid != AID_LOG)) { 138 if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)) {
207 uid_t uid = geteuid(); 139 uid = geteuid();
208 if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)) { 140 if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)) {
209 gid_t gid = getgid(); 141 gid_t gid = getgid();
210 if ((gid != AID_SYSTEM) && (gid != AID_ROOT) && (gid != AID_LOG)) { 142 if ((gid != AID_SYSTEM) &&
143 (gid != AID_ROOT) &&
144 (gid != AID_LOG)) {
211 gid = getegid(); 145 gid = getegid();
212 if ((gid != AID_SYSTEM) && (gid != AID_ROOT) && (gid != AID_LOG)) { 146 if ((gid != AID_SYSTEM) &&
147 (gid != AID_ROOT) &&
148 (gid != AID_LOG)) {
213 int num_groups; 149 int num_groups;
214 gid_t *groups; 150 gid_t *groups;
215 151
@@ -237,12 +173,11 @@ static int __write_to_log_daemon(log_id_t log_id, struct iovec *vec, size_t nr)
237 } 173 }
238 } 174 }
239 if (!__android_log_security()) { 175 if (!__android_log_security()) {
240 atomic_store(&dropped_security, 0); 176 /* If only we could reset downstream logd counter */
241 return -EPERM; 177 return -EPERM;
242 } 178 }
243 } else if (log_id == LOG_ID_EVENTS) { 179 } else if (log_id == LOG_ID_EVENTS) {
244 static atomic_uintptr_t map; 180 static atomic_uintptr_t map;
245 int ret;
246 const char *tag; 181 const char *tag;
247 EventTagMap *m, *f; 182 EventTagMap *m, *f;
248 183
@@ -255,7 +190,7 @@ static int __write_to_log_daemon(log_id_t log_id, struct iovec *vec, size_t nr)
255 m = (EventTagMap *)atomic_load(&map); 190 m = (EventTagMap *)atomic_load(&map);
256 191
257 if (!m) { 192 if (!m) {
258 ret = trylock(); 193 ret = __android_log_trylock();
259 m = (EventTagMap *)atomic_load(&map); /* trylock flush cache */ 194 m = (EventTagMap *)atomic_load(&map); /* trylock flush cache */
260 if (!m) { 195 if (!m) {
261 m = android_openEventTagMap(EVENT_TAG_MAP_FILE); 196 m = android_openEventTagMap(EVENT_TAG_MAP_FILE);
@@ -269,13 +204,11 @@ static int __write_to_log_daemon(log_id_t log_id, struct iovec *vec, size_t nr)
269 } 204 }
270 } 205 }
271 if (!ret) { /* trylock succeeded, unlock */ 206 if (!ret) { /* trylock succeeded, unlock */
272 unlock(); 207 __android_log_unlock();
273 } 208 }
274 } 209 }
275 if (m && (m != (EventTagMap *)(uintptr_t)-1LL)) { 210 if (m && (m != (EventTagMap *)(uintptr_t)-1LL)) {
276 tag = android_lookupEventTag( 211 tag = android_lookupEventTag(m, get4LE(vec[0].iov_base));
277 m,
278 htole32(((uint32_t *)vec[0].iov_base)[0]));
279 } 212 }
280 ret = __android_log_is_loggable(ANDROID_LOG_INFO, 213 ret = __android_log_is_loggable(ANDROID_LOG_INFO,
281 tag, 214 tag,
@@ -317,203 +250,57 @@ static int __write_to_log_daemon(log_id_t log_id, struct iovec *vec, size_t nr)
317 } 250 }
318 } 251 }
319 252
320 /*
321 * struct {
322 * // what we provide to pstore
323 * android_pmsg_log_header_t pmsg_header;
324 * // what we provide to socket
325 * android_log_header_t header;
326 * // caller provides
327 * union {
328 * struct {
329 * char prio;
330 * char payload[];
331 * } string;
332 * struct {
333 * uint32_t tag
334 * char payload[];
335 * } binary;
336 * };
337 * };
338 */
339
340 clock_gettime(android_log_clockid(), &ts); 253 clock_gettime(android_log_clockid(), &ts);
341 254#else
342 pmsg_header.magic = LOGGER_MAGIC; 255 /* simulate clock_gettime(CLOCK_REALTIME, &ts); */
343 pmsg_header.len = sizeof(pmsg_header) + sizeof(header); 256 {
344 pmsg_header.uid = last_uid; 257 struct timeval tv;
345 pmsg_header.pid = last_pid; 258 gettimeofday(&tv, NULL);
346 259 ts.tv_sec = tv.tv_sec;
347 header.tid = gettid(); 260 ts.tv_nsec = tv.tv_usec * 1000;
348 header.realtime.tv_sec = ts.tv_sec;
349 header.realtime.tv_nsec = ts.tv_nsec;
350
351 newVec[0].iov_base = (unsigned char *) &pmsg_header;
352 newVec[0].iov_len = sizeof(pmsg_header);
353 newVec[1].iov_base = (unsigned char *) &header;
354 newVec[1].iov_len = sizeof(header);
355
356 if (logd_fd > 0) {
357 int32_t snapshot = atomic_exchange_explicit(&dropped_security, 0,
358 memory_order_relaxed);
359 if (snapshot) {
360 android_log_event_int_t buffer;
361
362 header.id = LOG_ID_SECURITY;
363 buffer.header.tag = htole32(LIBLOG_LOG_TAG);
364 buffer.payload.type = EVENT_TYPE_INT;
365 buffer.payload.data = htole32(snapshot);
366
367 newVec[2].iov_base = &buffer;
368 newVec[2].iov_len = sizeof(buffer);
369
370 ret = TEMP_FAILURE_RETRY(writev(logd_fd, newVec + 1, 2));
371 if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
372 atomic_fetch_add_explicit(&dropped_security, snapshot,
373 memory_order_relaxed);
374 }
375 }
376 snapshot = atomic_exchange_explicit(&dropped, 0, memory_order_relaxed);
377 if (snapshot && __android_log_is_loggable(ANDROID_LOG_INFO,
378 "liblog",
379 ANDROID_LOG_VERBOSE)) {
380 android_log_event_int_t buffer;
381
382 header.id = LOG_ID_EVENTS;
383 buffer.header.tag = htole32(LIBLOG_LOG_TAG);
384 buffer.payload.type = EVENT_TYPE_INT;
385 buffer.payload.data = htole32(snapshot);
386
387 newVec[2].iov_base = &buffer;
388 newVec[2].iov_len = sizeof(buffer);
389
390 ret = TEMP_FAILURE_RETRY(writev(logd_fd, newVec + 1, 2));
391 if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
392 atomic_fetch_add_explicit(&dropped, snapshot,
393 memory_order_relaxed);
394 }
395 }
396 }
397
398 header.id = log_id;
399
400 for (payload_size = 0, i = header_length; i < nr + header_length; i++) {
401 newVec[i].iov_base = vec[i - header_length].iov_base;
402 payload_size += newVec[i].iov_len = vec[i - header_length].iov_len;
403
404 if (payload_size > LOGGER_ENTRY_MAX_PAYLOAD) {
405 newVec[i].iov_len -= payload_size - LOGGER_ENTRY_MAX_PAYLOAD;
406 if (newVec[i].iov_len) {
407 ++i;
408 }
409 payload_size = LOGGER_ENTRY_MAX_PAYLOAD;
410 break;
411 }
412 }
413 pmsg_header.len += payload_size;
414
415 if (pstore_fd >= 0) {
416 TEMP_FAILURE_RETRY(writev(pstore_fd, newVec, i));
417 }
418
419 if (last_uid == AID_LOGD) { /* logd, after initialization and priv drop */
420 /*
421 * ignore log messages we send to ourself (logd).
422 * Such log messages are often generated by libraries we depend on
423 * which use standard Android logging.
424 */
425 return 0;
426 }
427
428 if (logd_fd < 0) {
429 return -EBADF;
430 } 261 }
262#endif
431 263
432 /* 264 ret = 0;
433 * The write below could be lost, but will never block. 265 write_transport_for_each(node, &__android_log_transport_write) {
434 * 266 if (node->write) {
435 * To logd, we drop the pmsg_header 267 ssize_t retval;
436 * 268 retval = (*node->write)(log_id, &ts, vec, nr);
437 * ENOTCONN occurs if logd dies. 269 if (ret >= 0) {
438 * EAGAIN occurs if logd is overloaded. 270 ret = retval;
439 */
440 ret = TEMP_FAILURE_RETRY(writev(logd_fd, newVec + 1, i - 1));
441 if (ret < 0) {
442 ret = -errno;
443 if (ret == -ENOTCONN) {
444 lock();
445 close(logd_fd);
446 logd_fd = -1;
447 ret = __write_to_log_initialize();
448 unlock();
449
450 if (ret < 0) {
451 return ret;
452 }
453
454 ret = TEMP_FAILURE_RETRY(writev(logd_fd, newVec + 1, i - 1));
455 if (ret < 0) {
456 ret = -errno;
457 } 271 }
458 } 272 }
459 } 273 }
460 274
461 if (ret > (ssize_t)sizeof(header)) { 275 write_transport_for_each(node, &__android_log_persist_write) {
462 ret -= sizeof(header); 276 if (node->write) {
463 } else if (ret == -EAGAIN) { 277 (void)(*node->write)(log_id, &ts, vec, nr);
464 atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed);
465 if (log_id == LOG_ID_SECURITY) {
466 atomic_fetch_add_explicit(&dropped_security, 1,
467 memory_order_relaxed);
468 } 278 }
469 } 279 }
470#endif
471 280
472 return ret; 281 return ret;
473} 282}
474 283
475#if FAKE_LOG_DEVICE
476static const char *LOG_NAME[LOG_ID_MAX] = {
477 [LOG_ID_MAIN] = "main",
478 [LOG_ID_RADIO] = "radio",
479 [LOG_ID_EVENTS] = "events",
480 [LOG_ID_SYSTEM] = "system",
481 [LOG_ID_CRASH] = "crash",
482 [LOG_ID_SECURITY] = "security",
483 [LOG_ID_KERNEL] = "kernel",
484};
485
486LIBLOG_ABI_PUBLIC const char *android_log_id_to_name(log_id_t log_id)
487{
488 if (log_id >= LOG_ID_MAX) {
489 log_id = LOG_ID_MAIN;
490 }
491 return LOG_NAME[log_id];
492}
493#endif
494
495static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr) 284static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr)
496{ 285{
497 lock(); 286 __android_log_lock();
498 287
499 if (write_to_log == __write_to_log_init) { 288 if (write_to_log == __write_to_log_init) {
500 int ret; 289 int ret;
501 290
502 ret = __write_to_log_initialize(); 291 ret = __write_to_log_initialize();
503 if (ret < 0) { 292 if (ret < 0) {
504 unlock(); 293 __android_log_unlock();
505#if (FAKE_LOG_DEVICE == 0) 294 if (!list_empty(&__android_log_persist_write)) {
506 if (pstore_fd >= 0) {
507 __write_to_log_daemon(log_id, vec, nr); 295 __write_to_log_daemon(log_id, vec, nr);
508 } 296 }
509#endif
510 return ret; 297 return ret;
511 } 298 }
512 299
513 write_to_log = __write_to_log_daemon; 300 write_to_log = __write_to_log_daemon;
514 } 301 }
515 302
516 unlock(); 303 __android_log_unlock();
517 304
518 return write_to_log(log_id, vec, nr); 305 return write_to_log(log_id, vec, nr);
519} 306}
@@ -603,10 +390,8 @@ LIBLOG_ABI_PUBLIC int __android_log_buf_print(int bufID, int prio,
603 return __android_log_buf_write(bufID, prio, tag, buf); 390 return __android_log_buf_write(bufID, prio, tag, buf);
604} 391}
605 392
606LIBLOG_ABI_PUBLIC void __android_log_assert( 393LIBLOG_ABI_PUBLIC void __android_log_assert(const char *cond, const char *tag,
607 const char *cond, 394 const char *fmt, ...)
608 const char *tag,
609 const char *fmt, ...)
610{ 395{
611 char buf[LOG_BUF_SIZE]; 396 char buf[LOG_BUF_SIZE];
612 397
diff --git a/liblog/logprint.c b/liblog/logprint.c
index 02df8ddd6..d7de8648b 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -34,7 +34,7 @@
34#include <log/logprint.h> 34#include <log/logprint.h>
35#include <private/android_filesystem_config.h> 35#include <private/android_filesystem_config.h>
36 36
37#include "log_cdefs.h" 37#include "log_portability.h"
38 38
39#define MS_PER_NSEC 1000000 39#define MS_PER_NSEC 1000000
40#define US_PER_NSEC 1000 40#define US_PER_NSEC 1000
diff --git a/liblog/pmsg_reader.c b/liblog/pmsg_reader.c
new file mode 100644
index 000000000..de435f7ed
--- /dev/null
+++ b/liblog/pmsg_reader.c
@@ -0,0 +1,255 @@
1/*
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 <fcntl.h>
19#include <stdbool.h>
20#include <string.h>
21#include <sys/types.h>
22
23#include <private/android_filesystem_config.h>
24#include <private/android_logger.h>
25
26#include "config_read.h"
27#include "logger.h"
28
29static int pmsgAvailable(log_id_t logId);
30static int pmsgVersion(struct android_log_logger *logger,
31 struct android_log_transport_context *transp);
32static int pmsgRead(struct android_log_logger_list *logger_list,
33 struct android_log_transport_context *transp,
34 struct log_msg *log_msg);
35static void pmsgClose(struct android_log_logger_list *logger_list,
36 struct android_log_transport_context *transp);
37static int pmsgClear(struct android_log_logger *logger,
38 struct android_log_transport_context *transp);
39
40LIBLOG_HIDDEN struct android_log_transport_read pmsgLoggerRead = {
41 .node = { &pmsgLoggerRead.node, &pmsgLoggerRead.node },
42 .name = "pmsg",
43 .available = pmsgAvailable,
44 .version = pmsgVersion,
45 .read = pmsgRead,
46 .poll = NULL,
47 .close = pmsgClose,
48 .clear = pmsgClear,
49 .setSize = NULL,
50 .getSize = NULL,
51 .getReadableSize = NULL,
52 .getPrune = NULL,
53 .setPrune = NULL,
54 .getStats = NULL,
55};
56
57static int pmsgAvailable(log_id_t logId)
58{
59 if (logId > LOG_ID_SECURITY) {
60 return -EINVAL;
61 }
62 if (access("/dev/pmsg0", W_OK) == 0) {
63 return 0;
64 }
65 return -EBADF;
66}
67
68/* Determine the credentials of the caller */
69static bool uid_has_log_permission(uid_t uid)
70{
71 return (uid == AID_SYSTEM) || (uid == AID_LOG) || (uid == AID_ROOT);
72}
73
74static uid_t get_best_effective_uid()
75{
76 uid_t euid;
77 uid_t uid;
78 gid_t gid;
79 ssize_t i;
80 static uid_t last_uid = (uid_t) -1;
81
82 if (last_uid != (uid_t) -1) {
83 return last_uid;
84 }
85 uid = __android_log_uid();
86 if (uid_has_log_permission(uid)) {
87 return last_uid = uid;
88 }
89 euid = geteuid();
90 if (uid_has_log_permission(euid)) {
91 return last_uid = euid;
92 }
93 gid = getgid();
94 if (uid_has_log_permission(gid)) {
95 return last_uid = gid;
96 }
97 gid = getegid();
98 if (uid_has_log_permission(gid)) {
99 return last_uid = gid;
100 }
101 i = getgroups((size_t) 0, NULL);
102 if (i > 0) {
103 gid_t list[i];
104
105 getgroups(i, list);
106 while (--i >= 0) {
107 if (uid_has_log_permission(list[i])) {
108 return last_uid = list[i];
109 }
110 }
111 }
112 return last_uid = uid;
113}
114
115static int pmsgClear(struct android_log_logger *logger __unused,
116 struct android_log_transport_context *transp __unused)
117{
118 if (uid_has_log_permission(get_best_effective_uid())) {
119 return unlink("/sys/fs/pstore/pmsg-ramoops-0");
120 }
121 errno = EPERM;
122 return -1;
123}
124
125/*
126 * returns the logger version
127 */
128static int pmsgVersion(struct android_log_logger *logger __unused,
129 struct android_log_transport_context *transp __unused)
130{
131 return 4;
132}
133
134static int pmsgRead(struct android_log_logger_list *logger_list,
135 struct android_log_transport_context *transp,
136 struct log_msg *log_msg)
137{
138 ssize_t ret;
139 off_t current, next;
140 uid_t uid;
141 struct android_log_logger *logger;
142 struct __attribute__((__packed__)) {
143 android_pmsg_log_header_t p;
144 android_log_header_t l;
145 } buf;
146 static uint8_t preread_count;
147 bool is_system;
148
149 memset(log_msg, 0, sizeof(*log_msg));
150
151 if (transp->context.fd <= 0) {
152 int fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY);
153
154 if (fd < 0) {
155 return -errno;
156 }
157 if (fd == 0) { /* Argggg */
158 fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY);
159 close(0);
160 if (fd < 0) {
161 return -errno;
162 }
163 }
164 transp->context.fd = fd;
165 preread_count = 0;
166 }
167
168 while(1) {
169 if (preread_count < sizeof(buf)) {
170 ret = TEMP_FAILURE_RETRY(read(transp->context.fd,
171 &buf.p.magic + preread_count,
172 sizeof(buf) - preread_count));
173 if (ret < 0) {
174 return -errno;
175 }
176 preread_count += ret;
177 }
178 if (preread_count != sizeof(buf)) {
179 return preread_count ? -EIO : -EAGAIN;
180 }
181 if ((buf.p.magic != LOGGER_MAGIC)
182 || (buf.p.len <= sizeof(buf))
183 || (buf.p.len > (sizeof(buf) + LOGGER_ENTRY_MAX_PAYLOAD))
184 || (buf.l.id >= LOG_ID_MAX)
185 || (buf.l.realtime.tv_nsec >= NS_PER_SEC)) {
186 do {
187 memmove(&buf.p.magic, &buf.p.magic + 1, --preread_count);
188 } while (preread_count && (buf.p.magic != LOGGER_MAGIC));
189 continue;
190 }
191 preread_count = 0;
192
193 if ((transp->logMask & (1 << buf.l.id)) &&
194 ((!logger_list->start.tv_sec && !logger_list->start.tv_nsec) ||
195 ((logger_list->start.tv_sec <= buf.l.realtime.tv_sec) &&
196 ((logger_list->start.tv_sec != buf.l.realtime.tv_sec) ||
197 (logger_list->start.tv_nsec <=
198 buf.l.realtime.tv_nsec)))) &&
199 (!logger_list->pid || (logger_list->pid == buf.p.pid))) {
200 uid = get_best_effective_uid();
201 is_system = uid_has_log_permission(uid);
202 if (is_system || (uid == buf.p.uid)) {
203 ret = TEMP_FAILURE_RETRY(read(transp->context.fd,
204 is_system ?
205 log_msg->entry_v4.msg :
206 log_msg->entry_v3.msg,
207 buf.p.len - sizeof(buf)));
208 if (ret < 0) {
209 return -errno;
210 }
211 if (ret != (ssize_t)(buf.p.len - sizeof(buf))) {
212 return -EIO;
213 }
214
215 log_msg->entry_v4.len = buf.p.len - sizeof(buf);
216 log_msg->entry_v4.hdr_size = is_system ?
217 sizeof(log_msg->entry_v4) :
218 sizeof(log_msg->entry_v3);
219 log_msg->entry_v4.pid = buf.p.pid;
220 log_msg->entry_v4.tid = buf.l.tid;
221 log_msg->entry_v4.sec = buf.l.realtime.tv_sec;
222 log_msg->entry_v4.nsec = buf.l.realtime.tv_nsec;
223 log_msg->entry_v4.lid = buf.l.id;
224 if (is_system) {
225 log_msg->entry_v4.uid = buf.p.uid;
226 }
227
228 return ret;
229 }
230 }
231
232 current = TEMP_FAILURE_RETRY(lseek(transp->context.fd,
233 (off_t)0, SEEK_CUR));
234 if (current < 0) {
235 return -errno;
236 }
237 next = TEMP_FAILURE_RETRY(lseek(transp->context.fd,
238 (off_t)(buf.p.len - sizeof(buf)),
239 SEEK_CUR));
240 if (next < 0) {
241 return -errno;
242 }
243 if ((next - current) != (ssize_t)(buf.p.len - sizeof(buf))) {
244 return -EIO;
245 }
246 }
247}
248
249static void pmsgClose(struct android_log_logger_list *logger_list __unused,
250 struct android_log_transport_context *transp) {
251 if (transp->context.fd > 0) {
252 close (transp->context.fd);
253 }
254 transp->context.fd = 0;
255}
diff --git a/liblog/pmsg_writer.c b/liblog/pmsg_writer.c
new file mode 100644
index 000000000..7a89e5d54
--- /dev/null
+++ b/liblog/pmsg_writer.c
@@ -0,0 +1,159 @@
1/*
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/*
18 * pmsg write handler
19 */
20
21#include <errno.h>
22#include <fcntl.h>
23#include <stdlib.h>
24#include <string.h>
25#include <sys/types.h>
26#include <time.h>
27
28#include <log/log.h>
29#include <log/logger.h>
30
31#include <private/android_filesystem_config.h>
32#include <private/android_logger.h>
33
34#include "config_write.h"
35#include "log_portability.h"
36#include "logger.h"
37
38static int pmsgOpen();
39static void pmsgClose();
40static int pmsgAvailable(log_id_t logId);
41static int pmsgWrite(log_id_t logId, struct timespec *ts,
42 struct iovec *vec, size_t nr);
43
44LIBLOG_HIDDEN struct android_log_transport_write pmsgLoggerWrite = {
45 .node = { &pmsgLoggerWrite.node, &pmsgLoggerWrite.node },
46 .context.fd = -1,
47 .name = "pmsg",
48 .available = pmsgAvailable,
49 .open = pmsgOpen,
50 .close = pmsgClose,
51 .write = pmsgWrite,
52};
53
54static int pmsgOpen()
55{
56 if (pmsgLoggerWrite.context.fd < 0) {
57 pmsgLoggerWrite.context.fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY));
58 }
59
60 return pmsgLoggerWrite.context.fd;
61}
62
63static void pmsgClose()
64{
65 if (pmsgLoggerWrite.context.fd >= 0) {
66 close(pmsgLoggerWrite.context.fd);
67 pmsgLoggerWrite.context.fd = -1;
68 }
69}
70
71static int pmsgAvailable(log_id_t logId)
72{
73 if (logId > LOG_ID_SECURITY) {
74 return -EINVAL;
75 }
76 if (pmsgLoggerWrite.context.fd < 0) {
77 if (access("/dev/pmsg0", W_OK) == 0) {
78 return 0;
79 }
80 return -EBADF;
81 }
82 return 1;
83}
84
85static int pmsgWrite(log_id_t logId, struct timespec *ts,
86 struct iovec *vec, size_t nr)
87{
88 static const unsigned headerLength = 2;
89 struct iovec newVec[nr + headerLength];
90 android_log_header_t header;
91 android_pmsg_log_header_t pmsgHeader;
92 size_t i, payloadSize;
93 ssize_t ret;
94
95 if (pmsgLoggerWrite.context.fd < 0) {
96 return -EBADF;
97 }
98
99 /*
100 * struct {
101 * // what we provide to pstore
102 * android_pmsg_log_header_t pmsgHeader;
103 * // what we provide to file
104 * android_log_header_t header;
105 * // caller provides
106 * union {
107 * struct {
108 * char prio;
109 * char payload[];
110 * } string;
111 * struct {
112 * uint32_t tag
113 * char payload[];
114 * } binary;
115 * };
116 * };
117 */
118
119 pmsgHeader.magic = LOGGER_MAGIC;
120 pmsgHeader.len = sizeof(pmsgHeader) + sizeof(header);
121 pmsgHeader.uid = __android_log_uid();
122 pmsgHeader.pid = __android_log_pid();
123
124 header.id = logId;
125 header.tid = gettid();
126 header.realtime.tv_sec = ts->tv_sec;
127 header.realtime.tv_nsec = ts->tv_nsec;
128
129 newVec[0].iov_base = (unsigned char *)&pmsgHeader;
130 newVec[0].iov_len = sizeof(pmsgHeader);
131 newVec[1].iov_base = (unsigned char *)&header;
132 newVec[1].iov_len = sizeof(header);
133
134 for (payloadSize = 0, i = headerLength; i < nr + headerLength; i++) {
135 newVec[i].iov_base = vec[i - headerLength].iov_base;
136 payloadSize += newVec[i].iov_len = vec[i - headerLength].iov_len;
137
138 if (payloadSize > LOGGER_ENTRY_MAX_PAYLOAD) {
139 newVec[i].iov_len -= payloadSize - LOGGER_ENTRY_MAX_PAYLOAD;
140 if (newVec[i].iov_len) {
141 ++i;
142 }
143 payloadSize = LOGGER_ENTRY_MAX_PAYLOAD;
144 break;
145 }
146 }
147 pmsgHeader.len += payloadSize;
148
149 ret = TEMP_FAILURE_RETRY(writev(pmsgLoggerWrite.context.fd, newVec, i));
150 if (ret < 0) {
151 ret = errno ? -errno : -ENOTCONN;
152 }
153
154 if (ret > (ssize_t)(sizeof(header) + sizeof(pmsgHeader))) {
155 ret -= sizeof(header) - sizeof(pmsgHeader);
156 }
157
158 return ret;
159}
diff --git a/liblog/uio.c b/liblog/uio.c
index d0184dc90..ac0558f3f 100644
--- a/liblog/uio.c
+++ b/liblog/uio.c
@@ -20,7 +20,7 @@
20 20
21#include <log/uio.h> 21#include <log/uio.h>
22 22
23#include "log_cdefs.h" 23#include "log_portability.h"
24 24
25LIBLOG_ABI_PUBLIC int readv(int fd, struct iovec *vecs, int count) 25LIBLOG_ABI_PUBLIC int readv(int fd, struct iovec *vecs, int count)
26{ 26{