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