logd_writer.c revision d69e801fe890d1732906aaadb8aa06244bb4ac52
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 <private/android_filesystem_config.h>
36#include <private/android_logger.h>
37
38#include "config_write.h"
39#include "log_portability.h"
40#include "logger.h"
41
42/* branchless on many architectures. */
43#define min(x,y) ((y) ^ (((x) ^ (y)) & -((x) < (y))))
44
45static int logdAvailable(log_id_t LogId);
46static int logdOpen();
47static void logdClose();
48static int logdWrite(log_id_t logId, struct timespec *ts,
49                     struct iovec *vec, size_t nr);
50
51LIBLOG_HIDDEN struct android_log_transport_write logdLoggerWrite = {
52    .node = { &logdLoggerWrite.node, &logdLoggerWrite.node },
53    .context.sock = -EBADF,
54    .name = "logd",
55    .available = logdAvailable,
56    .open = logdOpen,
57    .close = logdClose,
58    .write = logdWrite,
59};
60
61/* log_init_lock assumed */
62static int logdOpen()
63{
64    int i, ret = 0;
65
66    i = atomic_load(&logdLoggerWrite.context.sock);
67    if (i < 0) {
68        int sock = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM |
69                                                      SOCK_CLOEXEC |
70                                                      SOCK_NONBLOCK, 0));
71        if (sock < 0) {
72            ret = -errno;
73        } else {
74            struct sockaddr_un un;
75            memset(&un, 0, sizeof(struct sockaddr_un));
76            un.sun_family = AF_UNIX;
77            strcpy(un.sun_path, "/dev/socket/logdw");
78
79            if (TEMP_FAILURE_RETRY(connect(sock, (struct sockaddr *)&un,
80                                           sizeof(struct sockaddr_un))) < 0) {
81                ret = -errno;
82                switch (ret) {
83                case -ENOTCONN:
84                case -ECONNREFUSED:
85                case -ENOENT:
86                    i = atomic_exchange(&logdLoggerWrite.context.sock, ret);
87                    /* FALLTHRU */
88                default:
89                    break;
90                }
91                close(sock);
92            } else {
93                ret = atomic_exchange(&logdLoggerWrite.context.sock, sock);
94                if ((ret >= 0) && (ret != sock)) {
95                    close(ret);
96                }
97                ret = 0;
98            }
99        }
100    }
101
102    return ret;
103}
104
105static void __logdClose(int negative_errno)
106{
107    int sock = atomic_exchange(&logdLoggerWrite.context.sock, negative_errno);
108    if (sock >= 0) {
109        close(sock);
110    }
111}
112
113static void logdClose()
114{
115    __logdClose(-EBADF);
116}
117
118static int logdAvailable(log_id_t logId)
119{
120    if (logId >= LOG_ID_MAX || logId == LOG_ID_KERNEL) {
121        return -EINVAL;
122    }
123    if (atomic_load(&logdLoggerWrite.context.sock) < 0) {
124        if (access("/dev/socket/logdw", W_OK) == 0) {
125            return 0;
126        }
127        return -EBADF;
128    }
129    return 1;
130}
131
132static int logdWrite(log_id_t logId, struct timespec *ts,
133                     struct iovec *vec, size_t nr)
134{
135    ssize_t ret;
136    int sock;
137    static const unsigned headerLength = 1;
138    struct iovec newVec[nr + headerLength];
139    android_log_header_t header;
140    size_t i, payloadSize;
141    static atomic_int_fast32_t dropped;
142    static atomic_int_fast32_t droppedSecurity;
143
144    sock = atomic_load(&logdLoggerWrite.context.sock);
145    if (sock < 0) switch (sock) {
146    case -ENOTCONN:
147    case -ECONNREFUSED:
148    case -ENOENT:
149        break;
150    default:
151        return -EBADF;
152    }
153
154    /* logd, after initialization and priv drop */
155    if (__android_log_uid() == AID_LOGD) {
156        /*
157         * ignore log messages we send to ourself (logd).
158         * Such log messages are often generated by libraries we depend on
159         * which use standard Android logging.
160         */
161        return 0;
162    }
163
164    /*
165     *  struct {
166     *      // what we provide to socket
167     *      android_log_header_t header;
168     *      // caller provides
169     *      union {
170     *          struct {
171     *              char     prio;
172     *              char     payload[];
173     *          } string;
174     *          struct {
175     *              uint32_t tag
176     *              char     payload[];
177     *          } binary;
178     *      };
179     *  };
180     */
181
182    header.tid = gettid();
183    header.realtime.tv_sec = ts->tv_sec;
184    header.realtime.tv_nsec = ts->tv_nsec;
185
186    newVec[0].iov_base = (unsigned char *)&header;
187    newVec[0].iov_len  = sizeof(header);
188
189    if (sock >= 0) {
190        int32_t snapshot = atomic_exchange_explicit(&droppedSecurity, 0,
191                                                    memory_order_relaxed);
192        if (snapshot) {
193            android_log_event_int_t buffer;
194
195            header.id = LOG_ID_SECURITY;
196            buffer.header.tag = htole32(LIBLOG_LOG_TAG);
197            buffer.payload.type = EVENT_TYPE_INT;
198            buffer.payload.data = htole32(snapshot);
199
200            newVec[headerLength].iov_base = &buffer;
201            newVec[headerLength].iov_len  = sizeof(buffer);
202
203            ret = TEMP_FAILURE_RETRY(writev(sock, newVec, 2));
204            if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
205                atomic_fetch_add_explicit(&droppedSecurity, snapshot,
206                                          memory_order_relaxed);
207            }
208        }
209        snapshot = atomic_exchange_explicit(&dropped, 0, memory_order_relaxed);
210        if (snapshot && __android_log_is_loggable_len(ANDROID_LOG_INFO,
211                                                      "liblog",
212                                                      strlen("liblog"),
213                                                      ANDROID_LOG_VERBOSE)) {
214            android_log_event_int_t buffer;
215
216            header.id = LOG_ID_EVENTS;
217            buffer.header.tag = htole32(LIBLOG_LOG_TAG);
218            buffer.payload.type = EVENT_TYPE_INT;
219            buffer.payload.data = htole32(snapshot);
220
221            newVec[headerLength].iov_base = &buffer;
222            newVec[headerLength].iov_len  = sizeof(buffer);
223
224            ret = TEMP_FAILURE_RETRY(writev(sock, newVec, 2));
225            if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
226                atomic_fetch_add_explicit(&dropped, snapshot,
227                                          memory_order_relaxed);
228            }
229        }
230    }
231
232    header.id = logId;
233
234    for (payloadSize = 0, i = headerLength; i < nr + headerLength; i++) {
235        newVec[i].iov_base = vec[i - headerLength].iov_base;
236        payloadSize += newVec[i].iov_len = vec[i - headerLength].iov_len;
237
238        if (payloadSize > LOGGER_ENTRY_MAX_PAYLOAD) {
239            newVec[i].iov_len -= payloadSize - LOGGER_ENTRY_MAX_PAYLOAD;
240            if (newVec[i].iov_len) {
241                ++i;
242            }
243            break;
244        }
245    }
246
247    /*
248     * The write below could be lost, but will never block.
249     *
250     * ENOTCONN occurs if logd has died.
251     * ENOENT occurs if logd is not running and socket is missing.
252     * ECONNREFUSED occurs if we can not reconnect to logd.
253     * EAGAIN occurs if logd is overloaded.
254     */
255    if (sock < 0) {
256        ret = sock;
257    } else {
258        ret = TEMP_FAILURE_RETRY(writev(sock, newVec, i));
259        if (ret < 0) {
260            ret = -errno;
261        }
262    }
263    switch(ret) {
264    case -ENOTCONN:
265    case -ECONNREFUSED:
266    case -ENOENT:
267        if (__android_log_trylock()) {
268            return ret; /* in a signal handler? try again when less stressed */
269        }
270        __logdClose(ret);
271        ret = logdOpen();
272        __android_log_unlock();
273
274        if (ret < 0) {
275            return ret;
276        }
277
278        ret = TEMP_FAILURE_RETRY(writev(
279                atomic_load(&logdLoggerWrite.context.sock), newVec, i));
280        if (ret < 0) {
281            ret = -errno;
282        }
283        /* FALLTHRU */
284    default:
285        break;
286    }
287
288    if (ret > (ssize_t)sizeof(header)) {
289        ret -= sizeof(header);
290    } else if (ret == -EAGAIN) {
291        atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed);
292        if (logId == LOG_ID_SECURITY) {
293            atomic_fetch_add_explicit(&droppedSecurity, 1,
294                                      memory_order_relaxed);
295        }
296    }
297
298    return ret;
299}
300