logd_write.c revision 2a4d05a4e38b84cf287bb2d2266c07b6f10c9dee
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#ifndef __unused 53#define __unused __attribute__((__unused__)) 54#endif 55 56#if FAKE_LOG_DEVICE 57#define WEAK __attribute__((weak)) 58static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1, -1 }; 59#else 60static int logd_fd = -1; 61#endif 62 63/* 64 * This is used by the C++ code to decide if it should write logs through 65 * the C code. Basically, if /dev/socket/logd is available, we're running in 66 * the simulator rather than a desktop tool and want to use the device. 67 */ 68static enum { 69 kLogUninitialized, kLogNotAvailable, kLogAvailable 70} g_log_status = kLogUninitialized; 71int __android_log_dev_available(void) 72{ 73 if (g_log_status == kLogUninitialized) { 74 if (access("/dev/socket/logdw", W_OK) == 0) 75 g_log_status = kLogAvailable; 76 else 77 g_log_status = kLogNotAvailable; 78 } 79 80 return (g_log_status == kLogAvailable); 81} 82 83#if !FAKE_LOG_DEVICE 84/* give up, resources too limited */ 85static int __write_to_log_null(log_id_t log_fd __unused, struct iovec *vec __unused, 86 size_t nr __unused) 87{ 88 return -1; 89} 90#endif 91 92/* log_init_lock assumed */ 93static int __write_to_log_initialize() 94{ 95 int i, ret = 0; 96 97#if FAKE_LOG_DEVICE 98 for (i = 0; i < LOG_ID_MAX; i++) { 99 char buf[sizeof("/dev/log_system")]; 100 snprintf(buf, sizeof(buf), "/dev/log_%s", android_log_id_to_name(i)); 101 log_fds[i] = fakeLogOpen(buf, O_WRONLY); 102 } 103#else 104 if (logd_fd >= 0) { 105 i = logd_fd; 106 logd_fd = -1; 107 close(i); 108 } 109 110 i = socket(PF_UNIX, SOCK_DGRAM, 0); 111 if (i < 0) { 112 ret = -errno; 113 write_to_log = __write_to_log_null; 114 } else if (fcntl(i, F_SETFL, O_NONBLOCK) < 0) { 115 ret = -errno; 116 close(i); 117 i = -1; 118 write_to_log = __write_to_log_null; 119 } else { 120 struct sockaddr_un un; 121 memset(&un, 0, sizeof(struct sockaddr_un)); 122 un.sun_family = AF_UNIX; 123 strcpy(un.sun_path, "/dev/socket/logdw"); 124 125 if (connect(i, (struct sockaddr *)&un, sizeof(struct sockaddr_un)) < 0) { 126 ret = -errno; 127 close(i); 128 i = -1; 129 } 130 } 131 logd_fd = i; 132#endif 133 134 return ret; 135} 136 137static int __write_to_log_kernel(log_id_t log_id, struct iovec *vec, size_t nr) 138{ 139 ssize_t ret; 140#if FAKE_LOG_DEVICE 141 int log_fd; 142 143 if (/*(int)log_id >= 0 &&*/ (int)log_id < (int)LOG_ID_MAX) { 144 log_fd = log_fds[(int)log_id]; 145 } else { 146 return -EBADF; 147 } 148 do { 149 ret = fakeLogWritev(log_fd, vec, nr); 150 if (ret < 0) { 151 ret = -errno; 152 } 153 } while (ret == -EINTR); 154#else 155 static const unsigned header_length = 3; 156 struct iovec newVec[nr + header_length]; 157 typeof_log_id_t log_id_buf; 158 uint16_t tid; 159 struct timespec ts; 160 log_time realtime_ts; 161 size_t i, payload_size; 162 static uid_t last_uid = AID_ROOT; /* logd *always* starts up as AID_ROOT */ 163 164 if (last_uid == AID_ROOT) { /* have we called to get the UID yet? */ 165 last_uid = getuid(); 166 } 167 if (last_uid == AID_LOGD) { /* logd, after initialization and priv drop */ 168 /* 169 * ignore log messages we send to ourself (logd). 170 * Such log messages are often generated by libraries we depend on 171 * which use standard Android logging. 172 */ 173 return 0; 174 } 175 176 if (logd_fd < 0) { 177 return -EBADF; 178 } 179 180 /* 181 * struct { 182 * // what we provide 183 * typeof_log_id_t log_id; 184 * u16 tid; 185 * log_time realtime; 186 * // caller provides 187 * union { 188 * struct { 189 * char prio; 190 * char payload[]; 191 * } string; 192 * struct { 193 * uint32_t tag 194 * char payload[]; 195 * } binary; 196 * }; 197 * }; 198 */ 199 200 clock_gettime(CLOCK_REALTIME, &ts); 201 realtime_ts.tv_sec = ts.tv_sec; 202 realtime_ts.tv_nsec = ts.tv_nsec; 203 204 log_id_buf = log_id; 205 tid = gettid(); 206 207 newVec[0].iov_base = (unsigned char *) &log_id_buf; 208 newVec[0].iov_len = sizeof_log_id_t; 209 newVec[1].iov_base = (unsigned char *) &tid; 210 newVec[1].iov_len = sizeof(tid); 211 newVec[2].iov_base = (unsigned char *) &realtime_ts; 212 newVec[2].iov_len = sizeof(log_time); 213 214 for (payload_size = 0, i = header_length; i < nr + header_length; i++) { 215 newVec[i].iov_base = vec[i - header_length].iov_base; 216 payload_size += newVec[i].iov_len = vec[i - header_length].iov_len; 217 218 if (payload_size > LOGGER_ENTRY_MAX_PAYLOAD) { 219 newVec[i].iov_len -= payload_size - LOGGER_ENTRY_MAX_PAYLOAD; 220 if (newVec[i].iov_len) { 221 ++i; 222 } 223 break; 224 } 225 } 226 227 /* 228 * The write below could be lost, but will never block. 229 * 230 * ENOTCONN occurs if logd dies. 231 * EAGAIN occurs if logd is overloaded. 232 */ 233 ret = writev(logd_fd, newVec, i); 234 if (ret < 0) { 235 ret = -errno; 236 if (ret == -ENOTCONN) { 237#ifdef HAVE_PTHREADS 238 pthread_mutex_lock(&log_init_lock); 239#endif 240 ret = __write_to_log_initialize(); 241#ifdef HAVE_PTHREADS 242 pthread_mutex_unlock(&log_init_lock); 243#endif 244 245 if (ret < 0) { 246 return ret; 247 } 248 249 ret = writev(logd_fd, newVec, nr + header_length); 250 if (ret < 0) { 251 ret = -errno; 252 } 253 } 254 } 255 256 if (ret > (ssize_t)(sizeof_log_id_t + sizeof(tid) + sizeof(log_time))) { 257 ret -= sizeof_log_id_t + sizeof(tid) + sizeof(log_time); 258 } 259#endif 260 261 return ret; 262} 263 264#if FAKE_LOG_DEVICE 265static const char *LOG_NAME[LOG_ID_MAX] = { 266 [LOG_ID_MAIN] = "main", 267 [LOG_ID_RADIO] = "radio", 268 [LOG_ID_EVENTS] = "events", 269 [LOG_ID_SYSTEM] = "system", 270 [LOG_ID_CRASH] = "crash" 271}; 272 273const WEAK char *android_log_id_to_name(log_id_t log_id) 274{ 275 if (log_id >= LOG_ID_MAX) { 276 log_id = LOG_ID_MAIN; 277 } 278 return LOG_NAME[log_id]; 279} 280#endif 281 282static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr) 283{ 284#ifdef HAVE_PTHREADS 285 pthread_mutex_lock(&log_init_lock); 286#endif 287 288 if (write_to_log == __write_to_log_init) { 289 int ret; 290 291 ret = __write_to_log_initialize(); 292 if (ret < 0) { 293#ifdef HAVE_PTHREADS 294 pthread_mutex_unlock(&log_init_lock); 295#endif 296 return ret; 297 } 298 299 write_to_log = __write_to_log_kernel; 300 } 301 302#ifdef HAVE_PTHREADS 303 pthread_mutex_unlock(&log_init_lock); 304#endif 305 306 return write_to_log(log_id, vec, nr); 307} 308 309int __android_log_write(int prio, const char *tag, const char *msg) 310{ 311 struct iovec vec[3]; 312 log_id_t log_id = LOG_ID_MAIN; 313 char tmp_tag[32]; 314 315 if (!tag) 316 tag = ""; 317 318 /* XXX: This needs to go! */ 319 if (!strcmp(tag, "HTC_RIL") || 320 !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */ 321 !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */ 322 !strcmp(tag, "AT") || 323 !strcmp(tag, "GSM") || 324 !strcmp(tag, "STK") || 325 !strcmp(tag, "CDMA") || 326 !strcmp(tag, "PHONE") || 327 !strcmp(tag, "SMS")) { 328 log_id = LOG_ID_RADIO; 329 /* Inform third party apps/ril/radio.. to use Rlog or RLOG */ 330 snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag); 331 tag = tmp_tag; 332 } 333 334#if __BIONIC__ 335 if (prio == ANDROID_LOG_FATAL) { 336 extern void __android_set_abort_message(const char*); 337 __android_set_abort_message(msg); 338 } 339#endif 340 341 vec[0].iov_base = (unsigned char *) &prio; 342 vec[0].iov_len = 1; 343 vec[1].iov_base = (void *) tag; 344 vec[1].iov_len = strlen(tag) + 1; 345 vec[2].iov_base = (void *) msg; 346 vec[2].iov_len = strlen(msg) + 1; 347 348 return write_to_log(log_id, vec, 3); 349} 350 351int __android_log_buf_write(int bufID, int prio, const char *tag, const char *msg) 352{ 353 struct iovec vec[3]; 354 char tmp_tag[32]; 355 356 if (!tag) 357 tag = ""; 358 359 /* XXX: This needs to go! */ 360 if ((bufID != LOG_ID_RADIO) && 361 (!strcmp(tag, "HTC_RIL") || 362 !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */ 363 !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */ 364 !strcmp(tag, "AT") || 365 !strcmp(tag, "GSM") || 366 !strcmp(tag, "STK") || 367 !strcmp(tag, "CDMA") || 368 !strcmp(tag, "PHONE") || 369 !strcmp(tag, "SMS"))) { 370 bufID = LOG_ID_RADIO; 371 /* Inform third party apps/ril/radio.. to use Rlog or RLOG */ 372 snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag); 373 tag = tmp_tag; 374 } 375 376 vec[0].iov_base = (unsigned char *) &prio; 377 vec[0].iov_len = 1; 378 vec[1].iov_base = (void *) tag; 379 vec[1].iov_len = strlen(tag) + 1; 380 vec[2].iov_base = (void *) msg; 381 vec[2].iov_len = strlen(msg) + 1; 382 383 return write_to_log(bufID, vec, 3); 384} 385 386int __android_log_vprint(int prio, const char *tag, const char *fmt, va_list ap) 387{ 388 char buf[LOG_BUF_SIZE]; 389 390 vsnprintf(buf, LOG_BUF_SIZE, fmt, ap); 391 392 return __android_log_write(prio, tag, buf); 393} 394 395int __android_log_print(int prio, const char *tag, const char *fmt, ...) 396{ 397 va_list ap; 398 char buf[LOG_BUF_SIZE]; 399 400 va_start(ap, fmt); 401 vsnprintf(buf, LOG_BUF_SIZE, fmt, ap); 402 va_end(ap); 403 404 return __android_log_write(prio, tag, buf); 405} 406 407int __android_log_buf_print(int bufID, int prio, const char *tag, const char *fmt, ...) 408{ 409 va_list ap; 410 char buf[LOG_BUF_SIZE]; 411 412 va_start(ap, fmt); 413 vsnprintf(buf, LOG_BUF_SIZE, fmt, ap); 414 va_end(ap); 415 416 return __android_log_buf_write(bufID, prio, tag, buf); 417} 418 419void __android_log_assert(const char *cond, const char *tag, 420 const char *fmt, ...) 421{ 422 char buf[LOG_BUF_SIZE]; 423 424 if (fmt) { 425 va_list ap; 426 va_start(ap, fmt); 427 vsnprintf(buf, LOG_BUF_SIZE, fmt, ap); 428 va_end(ap); 429 } else { 430 /* Msg not provided, log condition. N.B. Do not use cond directly as 431 * format string as it could contain spurious '%' syntax (e.g. 432 * "%d" in "blocks%devs == 0"). 433 */ 434 if (cond) 435 snprintf(buf, LOG_BUF_SIZE, "Assertion failed: %s", cond); 436 else 437 strcpy(buf, "Unspecified assertion failed"); 438 } 439 440 __android_log_write(ANDROID_LOG_FATAL, tag, buf); 441 __builtin_trap(); /* trap so we have a chance to debug the situation */ 442 /* NOTREACHED */ 443} 444 445int __android_log_bwrite(int32_t tag, const void *payload, size_t len) 446{ 447 struct iovec vec[2]; 448 449 vec[0].iov_base = &tag; 450 vec[0].iov_len = sizeof(tag); 451 vec[1].iov_base = (void*)payload; 452 vec[1].iov_len = len; 453 454 return write_to_log(LOG_ID_EVENTS, vec, 2); 455} 456 457/* 458 * Like __android_log_bwrite, but takes the type as well. Doesn't work 459 * for the general case where we're generating lists of stuff, but very 460 * handy if we just want to dump an integer into the log. 461 */ 462int __android_log_btwrite(int32_t tag, char type, const void *payload, 463 size_t len) 464{ 465 struct iovec vec[3]; 466 467 vec[0].iov_base = &tag; 468 vec[0].iov_len = sizeof(tag); 469 vec[1].iov_base = &type; 470 vec[1].iov_len = sizeof(type); 471 vec[2].iov_base = (void*)payload; 472 vec[2].iov_len = len; 473 474 return write_to_log(LOG_ID_EVENTS, vec, 3); 475} 476 477/* 478 * Like __android_log_bwrite, but used for writing strings to the 479 * event log. 480 */ 481int __android_log_bswrite(int32_t tag, const char *payload) 482{ 483 struct iovec vec[4]; 484 char type = EVENT_TYPE_STRING; 485 uint32_t len = strlen(payload); 486 487 vec[0].iov_base = &tag; 488 vec[0].iov_len = sizeof(tag); 489 vec[1].iov_base = &type; 490 vec[1].iov_len = sizeof(type); 491 vec[2].iov_base = &len; 492 vec[2].iov_len = sizeof(len); 493 vec[3].iov_base = (void*)payload; 494 vec[3].iov_len = len; 495 496 return write_to_log(LOG_ID_EVENTS, vec, 4); 497} 498