logd_write.c revision 4f6e8d7a00cbeda1e70cc15be9c4af1018bdad53
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 <utils/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, "RIL") || 148 !strcmp(tag, "AT") || 149 !strcmp(tag, "GSM") || 150 !strcmp(tag, "STK")) 151 log_id = LOG_ID_RADIO; 152 153 vec[0].iov_base = (unsigned char *) &prio; 154 vec[0].iov_len = 1; 155 vec[1].iov_base = (void *) tag; 156 vec[1].iov_len = strlen(tag) + 1; 157 vec[2].iov_base = (void *) msg; 158 vec[2].iov_len = strlen(msg) + 1; 159 160 return write_to_log(log_id, vec, 3); 161} 162 163int __android_log_vprint(int prio, const char *tag, const char *fmt, va_list ap) 164{ 165 char buf[LOG_BUF_SIZE]; 166 167 vsnprintf(buf, LOG_BUF_SIZE, fmt, ap); 168 169 return __android_log_write(prio, tag, buf); 170} 171 172int __android_log_print(int prio, const char *tag, const char *fmt, ...) 173{ 174 va_list ap; 175 char buf[LOG_BUF_SIZE]; 176 177 va_start(ap, fmt); 178 vsnprintf(buf, LOG_BUF_SIZE, fmt, ap); 179 va_end(ap); 180 181 return __android_log_write(prio, tag, buf); 182} 183 184void __android_log_assert(const char *cond, const char *tag, 185 const char *fmt, ...) 186{ 187 va_list ap; 188 char buf[LOG_BUF_SIZE]; 189 190 va_start(ap, fmt); 191 vsnprintf(buf, LOG_BUF_SIZE, fmt, ap); 192 va_end(ap); 193 194 __android_log_write(ANDROID_LOG_FATAL, tag, buf); 195 196 __builtin_trap(); /* trap so we have a chance to debug the situation */ 197} 198 199int __android_log_bwrite(int32_t tag, const void *payload, size_t len) 200{ 201 struct iovec vec[2]; 202 203 vec[0].iov_base = &tag; 204 vec[0].iov_len = sizeof(tag); 205 vec[1].iov_base = (void*)payload; 206 vec[1].iov_len = len; 207 208 return write_to_log(LOG_ID_EVENTS, vec, 2); 209} 210 211/* 212 * Like __android_log_bwrite, but takes the type as well. Doesn't work 213 * for the general case where we're generating lists of stuff, but very 214 * handy if we just want to dump an integer into the log. 215 */ 216int __android_log_btwrite(int32_t tag, char type, const void *payload, 217 size_t len) 218{ 219 struct iovec vec[3]; 220 221 vec[0].iov_base = &tag; 222 vec[0].iov_len = sizeof(tag); 223 vec[1].iov_base = &type; 224 vec[1].iov_len = sizeof(type); 225 vec[2].iov_base = (void*)payload; 226 vec[2].iov_len = len; 227 228 return write_to_log(LOG_ID_EVENTS, vec, 3); 229} 230