logd_write.c revision dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0
1/* 2 * Copyright (C) 2007 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 <time.h> 17#include <stdio.h> 18#ifdef HAVE_PTHREADS 19#include <pthread.h> 20#endif 21#include <unistd.h> 22#include <errno.h> 23#include <fcntl.h> 24#include <string.h> 25#include <stdlib.h> 26#include <stdarg.h> 27 28#include <cutils/logger.h> 29#include <cutils/logd.h> 30 31#define LOG_BUF_SIZE 1024 32 33#if FAKE_LOG_DEVICE 34// This will be defined when building for the host. 35#define log_open(pathname, flags) fakeLogOpen(pathname, flags) 36#define log_writev(filedes, vector, count) fakeLogWritev(filedes, vector, count) 37#define log_close(filedes) fakeLogClose(filedes) 38#else 39#define log_open(pathname, flags) open(pathname, flags) 40#define log_writev(filedes, vector, count) writev(filedes, vector, count) 41#define log_close(filedes) close(filedes) 42#endif 43 44typedef enum { 45 LOG_ID_MAIN = 0, 46 LOG_ID_RADIO, 47 LOG_ID_EVENTS, 48 LOG_ID_MAX 49} log_id_t; 50 51static int __write_to_log_init(log_id_t, struct iovec *vec, size_t nr); 52static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = 53 __write_to_log_init; 54#ifdef HAVE_PTHREADS 55static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER; 56#endif 57 58static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1 }; 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/log/... 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/"LOGGER_LOG_MAIN, 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, struct iovec *vec, size_t nr) 81{ 82 return -1; 83} 84 85static int __write_to_log_kernel(log_id_t log_id, struct iovec *vec, size_t nr) 86{ 87 ssize_t ret; 88 int log_fd; 89 90 if (/*(int)log_id >= 0 &&*/ (int)log_id < (int)LOG_ID_MAX) { 91 log_fd = log_fds[(int)log_id]; 92 } else { 93 return EBADF; 94 } 95 96 do { 97 ret = log_writev(log_fd, vec, nr); 98 } while (ret < 0 && errno == EINTR); 99 100 return ret; 101} 102 103static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr) 104{ 105#ifdef HAVE_PTHREADS 106 pthread_mutex_lock(&log_init_lock); 107#endif 108 109 if (write_to_log == __write_to_log_init) { 110 log_fds[LOG_ID_MAIN] = log_open("/dev/"LOGGER_LOG_MAIN, O_WRONLY); 111 log_fds[LOG_ID_RADIO] = log_open("/dev/"LOGGER_LOG_RADIO, O_WRONLY); 112 log_fds[LOG_ID_EVENTS] = log_open("/dev/"LOGGER_LOG_EVENTS, O_WRONLY); 113 114 write_to_log = __write_to_log_kernel; 115 116 if (log_fds[LOG_ID_MAIN] < 0 || log_fds[LOG_ID_RADIO] < 0 || 117 log_fds[LOG_ID_EVENTS] < 0) { 118 log_close(log_fds[LOG_ID_MAIN]); 119 log_close(log_fds[LOG_ID_RADIO]); 120 log_close(log_fds[LOG_ID_EVENTS]); 121 log_fds[LOG_ID_MAIN] = -1; 122 log_fds[LOG_ID_RADIO] = -1; 123 log_fds[LOG_ID_EVENTS] = -1; 124 write_to_log = __write_to_log_null; 125 } 126 } 127 128#ifdef HAVE_PTHREADS 129 pthread_mutex_unlock(&log_init_lock); 130#endif 131 132 return write_to_log(log_id, vec, nr); 133} 134 135int __android_log_write(int prio, const char *tag, const char *msg) 136{ 137 struct iovec vec[3]; 138 log_id_t log_id = LOG_ID_MAIN; 139 140 if (!tag) 141 tag = ""; 142 143 /* XXX: This needs to go! */ 144 if (!strcmp(tag, "HTC_RIL") || 145 !strcmp(tag, "RILJ") || 146 !strcmp(tag, "RILC") || 147 !strcmp(tag, "RILD") || 148 !strcmp(tag, "RIL") || 149 !strcmp(tag, "AT") || 150 !strcmp(tag, "GSM") || 151 !strcmp(tag, "STK")) 152 log_id = LOG_ID_RADIO; 153 154 vec[0].iov_base = (unsigned char *) &prio; 155 vec[0].iov_len = 1; 156 vec[1].iov_base = (void *) tag; 157 vec[1].iov_len = strlen(tag) + 1; 158 vec[2].iov_base = (void *) msg; 159 vec[2].iov_len = strlen(msg) + 1; 160 161 return write_to_log(log_id, vec, 3); 162} 163 164int __android_log_vprint(int prio, const char *tag, const char *fmt, va_list ap) 165{ 166 char buf[LOG_BUF_SIZE]; 167 168 vsnprintf(buf, LOG_BUF_SIZE, fmt, ap); 169 170 return __android_log_write(prio, tag, buf); 171} 172 173int __android_log_print(int prio, const char *tag, const char *fmt, ...) 174{ 175 va_list ap; 176 char buf[LOG_BUF_SIZE]; 177 178 va_start(ap, fmt); 179 vsnprintf(buf, LOG_BUF_SIZE, fmt, ap); 180 va_end(ap); 181 182 return __android_log_write(prio, tag, buf); 183} 184 185void __android_log_assert(const char *cond, const char *tag, 186 const char *fmt, ...) 187{ 188 va_list ap; 189 char buf[LOG_BUF_SIZE]; 190 191 va_start(ap, fmt); 192 vsnprintf(buf, LOG_BUF_SIZE, fmt, ap); 193 va_end(ap); 194 195 __android_log_write(ANDROID_LOG_FATAL, tag, buf); 196 197 __builtin_trap(); /* trap so we have a chance to debug the situation */ 198} 199 200int __android_log_bwrite(int32_t tag, const void *payload, size_t len) 201{ 202 struct iovec vec[2]; 203 204 vec[0].iov_base = &tag; 205 vec[0].iov_len = sizeof(tag); 206 vec[1].iov_base = (void*)payload; 207 vec[1].iov_len = len; 208 209 return write_to_log(LOG_ID_EVENTS, vec, 2); 210} 211 212/* 213 * Like __android_log_bwrite, but takes the type as well. Doesn't work 214 * for the general case where we're generating lists of stuff, but very 215 * handy if we just want to dump an integer into the log. 216 */ 217int __android_log_btwrite(int32_t tag, char type, const void *payload, 218 size_t len) 219{ 220 struct iovec vec[3]; 221 222 vec[0].iov_base = &tag; 223 vec[0].iov_len = sizeof(tag); 224 vec[1].iov_base = &type; 225 vec[1].iov_len = sizeof(type); 226 vec[2].iov_base = (void*)payload; 227 vec[2].iov_len = len; 228 229 return write_to_log(LOG_ID_EVENTS, vec, 3); 230} 231