logd_write.c revision 7e2f83c0bcc3ad8a2840a48be14d302ed79d671c
1/* 2 * Copyright (C) 2007-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#include <errno.h> 17#include <fcntl.h> 18#ifdef HAVE_PTHREADS 19#include <pthread.h> 20#endif 21#include <stdarg.h> 22#include <stdio.h> 23#include <stdlib.h> 24#include <string.h> 25#include <sys/stat.h> 26#include <sys/types.h> 27#if (FAKE_LOG_DEVICE == 0) 28#include <sys/socket.h> 29#include <sys/un.h> 30#endif 31#include <time.h> 32#include <unistd.h> 33 34#include <log/logd.h> 35#include <log/logger.h> 36#include <log/log_read.h> 37#include <private/android_filesystem_config.h> 38 39#define LOG_BUF_SIZE 1024 40 41#if FAKE_LOG_DEVICE 42/* This will be defined when building for the host. */ 43#include "fake_log_device.h" 44#endif 45 46static int __write_to_log_init(log_id_t, struct iovec *vec, size_t nr); 47static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = __write_to_log_init; 48#ifdef HAVE_PTHREADS 49static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER; 50#endif 51 52#define UNUSED __attribute__((__unused__)) 53 54static int logd_fd = -1; 55#if FAKE_LOG_DEVICE 56#define WEAK __attribute__((weak)) 57static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1 }; 58#endif 59 60/* 61 * This is used by the C++ code to decide if it should write logs through 62 * the C code. Basically, if /dev/socket/logd is available, we're running in 63 * the simulator rather than a desktop tool and want to use the device. 64 */ 65static enum { 66 kLogUninitialized, kLogNotAvailable, kLogAvailable 67} g_log_status = kLogUninitialized; 68int __android_log_dev_available(void) 69{ 70 if (g_log_status == kLogUninitialized) { 71 if (access("/dev/socket/logdw", W_OK) == 0) 72 g_log_status = kLogAvailable; 73 else 74 g_log_status = kLogNotAvailable; 75 } 76 77 return (g_log_status == kLogAvailable); 78} 79 80static int __write_to_log_null(log_id_t log_fd UNUSED, struct iovec *vec UNUSED, 81 size_t nr UNUSED) 82{ 83 return -1; 84} 85 86static int __write_to_log_kernel(log_id_t log_id, struct iovec *vec, size_t nr) 87{ 88#if FAKE_LOG_DEVICE 89 ssize_t ret; 90 int log_fd; 91 92 if (/*(int)log_id >= 0 &&*/ (int)log_id < (int)LOG_ID_MAX) { 93 log_fd = log_fds[(int)log_id]; 94 } else { 95 return EBADF; 96 } 97 do { 98 ret = fakeLogWritev(log_fd, vec, nr); 99 } while (ret < 0 && errno == EINTR); 100 101 return ret; 102#else 103 if (logd_fd == -1) { 104 return -1; 105 } 106 if (getuid() == AID_LOGD) { 107 /* 108 * ignore log messages we send to ourself. 109 * Such log messages are often generated by libraries we depend on 110 * which use standard Android logging. 111 */ 112 return 0; 113 } 114 struct iovec newVec[nr + 2]; 115 typeof_log_id_t log_id_buf = log_id; 116 117 newVec[0].iov_base = (unsigned char *) &log_id_buf; 118 newVec[0].iov_len = sizeof_log_id_t; 119 120 struct timespec ts; 121 clock_gettime(CLOCK_REALTIME, &ts); 122 log_time realtime_ts; 123 realtime_ts.tv_sec = ts.tv_sec; 124 realtime_ts.tv_nsec = ts.tv_nsec; 125 126 newVec[1].iov_base = (unsigned char *) &realtime_ts; 127 newVec[1].iov_len = sizeof(log_time); 128 129 size_t i; 130 for (i = 2; i < nr + 2; i++) { 131 newVec[i].iov_base = vec[i-2].iov_base; 132 newVec[i].iov_len = vec[i-2].iov_len; 133 } 134 135 /* The write below could be lost, but will never block. */ 136 return writev(logd_fd, newVec, nr + 2); 137#endif 138} 139 140#if FAKE_LOG_DEVICE 141static const char *LOG_NAME[LOG_ID_MAX] = { 142 [LOG_ID_MAIN] = "main", 143 [LOG_ID_RADIO] = "radio", 144 [LOG_ID_EVENTS] = "events", 145 [LOG_ID_SYSTEM] = "system" 146}; 147 148const WEAK char *android_log_id_to_name(log_id_t log_id) 149{ 150 if (log_id >= LOG_ID_MAX) { 151 log_id = LOG_ID_MAIN; 152 } 153 return LOG_NAME[log_id]; 154} 155#endif 156 157static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr) 158{ 159#ifdef HAVE_PTHREADS 160 pthread_mutex_lock(&log_init_lock); 161#endif 162 163 if (write_to_log == __write_to_log_init) { 164 write_to_log = __write_to_log_kernel; 165 166#if FAKE_LOG_DEVICE 167 int i; 168 for (i = 0; i < LOG_ID_MAX; i++) { 169 char buf[sizeof("/dev/log_system")]; 170 snprintf(buf, sizeof(buf), "/dev/log_%s", android_log_id_to_name(i)); 171 log_fds[i] = fakeLogOpen(buf, O_WRONLY); 172 } 173#else 174 int sock = socket(PF_UNIX, SOCK_DGRAM, 0); 175 if (sock != -1) { 176 if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) { 177 /* NB: Loss of content */ 178 close(sock); 179 sock = -1; 180 } else { 181 struct sockaddr_un un; 182 memset(&un, 0, sizeof(struct sockaddr_un)); 183 un.sun_family = AF_UNIX; 184 strcpy(un.sun_path, "/dev/socket/logdw"); 185 186 connect(sock, (struct sockaddr *)&un, sizeof(struct sockaddr_un)); 187 } 188 } else { 189 write_to_log = __write_to_log_null; 190 } 191 logd_fd = sock; 192#endif 193 } 194 195#ifdef HAVE_PTHREADS 196 pthread_mutex_unlock(&log_init_lock); 197#endif 198 199 return write_to_log(log_id, vec, nr); 200} 201 202int __android_log_write(int prio, const char *tag, const char *msg) 203{ 204 struct iovec vec[3]; 205 log_id_t log_id = LOG_ID_MAIN; 206 char tmp_tag[32]; 207 208 if (!tag) 209 tag = ""; 210 211 /* XXX: This needs to go! */ 212 if (!strcmp(tag, "HTC_RIL") || 213 !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */ 214 !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */ 215 !strcmp(tag, "AT") || 216 !strcmp(tag, "GSM") || 217 !strcmp(tag, "STK") || 218 !strcmp(tag, "CDMA") || 219 !strcmp(tag, "PHONE") || 220 !strcmp(tag, "SMS")) { 221 log_id = LOG_ID_RADIO; 222 // Inform third party apps/ril/radio.. to use Rlog or RLOG 223 snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag); 224 tag = tmp_tag; 225 } 226 227 vec[0].iov_base = (unsigned char *) &prio; 228 vec[0].iov_len = 1; 229 vec[1].iov_base = (void *) tag; 230 vec[1].iov_len = strlen(tag) + 1; 231 vec[2].iov_base = (void *) msg; 232 vec[2].iov_len = strlen(msg) + 1; 233 234 return write_to_log(log_id, vec, 3); 235} 236 237int __android_log_buf_write(int bufID, int prio, const char *tag, const char *msg) 238{ 239 struct iovec vec[3]; 240 char tmp_tag[32]; 241 242 if (!tag) 243 tag = ""; 244 245 /* XXX: This needs to go! */ 246 if ((bufID != LOG_ID_RADIO) && 247 (!strcmp(tag, "HTC_RIL") || 248 !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */ 249 !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */ 250 !strcmp(tag, "AT") || 251 !strcmp(tag, "GSM") || 252 !strcmp(tag, "STK") || 253 !strcmp(tag, "CDMA") || 254 !strcmp(tag, "PHONE") || 255 !strcmp(tag, "SMS"))) { 256 bufID = LOG_ID_RADIO; 257 // Inform third party apps/ril/radio.. to use Rlog or RLOG 258 snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag); 259 tag = tmp_tag; 260 } 261 262 vec[0].iov_base = (unsigned char *) &prio; 263 vec[0].iov_len = 1; 264 vec[1].iov_base = (void *) tag; 265 vec[1].iov_len = strlen(tag) + 1; 266 vec[2].iov_base = (void *) msg; 267 vec[2].iov_len = strlen(msg) + 1; 268 269 return write_to_log(bufID, vec, 3); 270} 271 272int __android_log_vprint(int prio, const char *tag, const char *fmt, va_list ap) 273{ 274 char buf[LOG_BUF_SIZE]; 275 276 vsnprintf(buf, LOG_BUF_SIZE, fmt, ap); 277 278 return __android_log_write(prio, tag, buf); 279} 280 281int __android_log_print(int prio, const char *tag, const char *fmt, ...) 282{ 283 va_list ap; 284 char buf[LOG_BUF_SIZE]; 285 286 va_start(ap, fmt); 287 vsnprintf(buf, LOG_BUF_SIZE, fmt, ap); 288 va_end(ap); 289 290 return __android_log_write(prio, tag, buf); 291} 292 293int __android_log_buf_print(int bufID, int prio, const char *tag, const char *fmt, ...) 294{ 295 va_list ap; 296 char buf[LOG_BUF_SIZE]; 297 298 va_start(ap, fmt); 299 vsnprintf(buf, LOG_BUF_SIZE, fmt, ap); 300 va_end(ap); 301 302 return __android_log_buf_write(bufID, prio, tag, buf); 303} 304 305void __android_log_assert(const char *cond, const char *tag, 306 const char *fmt, ...) 307{ 308 char buf[LOG_BUF_SIZE]; 309 310 if (fmt) { 311 va_list ap; 312 va_start(ap, fmt); 313 vsnprintf(buf, LOG_BUF_SIZE, fmt, ap); 314 va_end(ap); 315 } else { 316 /* Msg not provided, log condition. N.B. Do not use cond directly as 317 * format string as it could contain spurious '%' syntax (e.g. 318 * "%d" in "blocks%devs == 0"). 319 */ 320 if (cond) 321 snprintf(buf, LOG_BUF_SIZE, "Assertion failed: %s", cond); 322 else 323 strcpy(buf, "Unspecified assertion failed"); 324 } 325 326 __android_log_write(ANDROID_LOG_FATAL, tag, buf); 327 328 __builtin_trap(); /* trap so we have a chance to debug the situation */ 329} 330 331int __android_log_bwrite(int32_t tag, const void *payload, size_t len) 332{ 333 struct iovec vec[2]; 334 335 vec[0].iov_base = &tag; 336 vec[0].iov_len = sizeof(tag); 337 vec[1].iov_base = (void*)payload; 338 vec[1].iov_len = len; 339 340 return write_to_log(LOG_ID_EVENTS, vec, 2); 341} 342 343/* 344 * Like __android_log_bwrite, but takes the type as well. Doesn't work 345 * for the general case where we're generating lists of stuff, but very 346 * handy if we just want to dump an integer into the log. 347 */ 348int __android_log_btwrite(int32_t tag, char type, const void *payload, 349 size_t len) 350{ 351 struct iovec vec[3]; 352 353 vec[0].iov_base = &tag; 354 vec[0].iov_len = sizeof(tag); 355 vec[1].iov_base = &type; 356 vec[1].iov_len = sizeof(type); 357 vec[2].iov_base = (void*)payload; 358 vec[2].iov_len = len; 359 360 return write_to_log(LOG_ID_EVENTS, vec, 3); 361} 362