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