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