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