logd_write.c revision e9c4196980208124066fb45fa03bfb85fe1d8581
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 <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#include <sys/types.h> 28#include <sys/stat.h> 29 30#include <log/logger.h> 31#include <log/logd.h> 32#include <log/log.h> 33 34#define LOGGER_LOG_MAIN "log/main" 35#define LOGGER_LOG_RADIO "log/radio" 36#define LOGGER_LOG_EVENTS "log/events" 37#define LOGGER_LOG_SYSTEM "log/system" 38 39#define LOG_BUF_SIZE 1024 40 41#if FAKE_LOG_DEVICE 42// This will be defined when building for the host. 43#define log_open(pathname, flags) fakeLogOpen(pathname, flags) 44#define log_writev(filedes, vector, count) fakeLogWritev(filedes, vector, count) 45#define log_close(filedes) fakeLogClose(filedes) 46#else 47#define log_open(pathname, flags) open(pathname, (flags) | O_CLOEXEC) 48#define log_writev(filedes, vector, count) writev(filedes, vector, count) 49#define log_close(filedes) close(filedes) 50#endif 51 52static int __write_to_log_init(log_id_t, struct iovec *vec, size_t nr); 53static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = __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, -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 log_fds[LOG_ID_SYSTEM] = log_open("/dev/"LOGGER_LOG_SYSTEM, O_WRONLY); 114 115 write_to_log = __write_to_log_kernel; 116 117 if (log_fds[LOG_ID_MAIN] < 0 || log_fds[LOG_ID_RADIO] < 0 || 118 log_fds[LOG_ID_EVENTS] < 0) { 119 log_close(log_fds[LOG_ID_MAIN]); 120 log_close(log_fds[LOG_ID_RADIO]); 121 log_close(log_fds[LOG_ID_EVENTS]); 122 log_fds[LOG_ID_MAIN] = -1; 123 log_fds[LOG_ID_RADIO] = -1; 124 log_fds[LOG_ID_EVENTS] = -1; 125 write_to_log = __write_to_log_null; 126 } 127 128 if (log_fds[LOG_ID_SYSTEM] < 0) { 129 log_fds[LOG_ID_SYSTEM] = log_fds[LOG_ID_MAIN]; 130 } 131 } 132 133#ifdef HAVE_PTHREADS 134 pthread_mutex_unlock(&log_init_lock); 135#endif 136 137 return write_to_log(log_id, vec, nr); 138} 139 140int __android_log_write(int prio, const char *tag, const char *msg) 141{ 142 struct iovec vec[3]; 143 log_id_t log_id = LOG_ID_MAIN; 144 char tmp_tag[32]; 145 146 if (!tag) 147 tag = ""; 148 149 /* XXX: This needs to go! */ 150 if (!strcmp(tag, "HTC_RIL") || 151 !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */ 152 !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */ 153 !strcmp(tag, "AT") || 154 !strcmp(tag, "GSM") || 155 !strcmp(tag, "STK") || 156 !strcmp(tag, "CDMA") || 157 !strcmp(tag, "PHONE") || 158 !strcmp(tag, "SMS")) { 159 log_id = LOG_ID_RADIO; 160 // Inform third party apps/ril/radio.. to use Rlog or RLOG 161 snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag); 162 tag = tmp_tag; 163 } 164 165 vec[0].iov_base = (unsigned char *) &prio; 166 vec[0].iov_len = 1; 167 vec[1].iov_base = (void *) tag; 168 vec[1].iov_len = strlen(tag) + 1; 169 vec[2].iov_base = (void *) msg; 170 vec[2].iov_len = strlen(msg) + 1; 171 172 return write_to_log(log_id, vec, 3); 173} 174 175int __android_log_buf_write(int bufID, int prio, const char *tag, const char *msg) 176{ 177 struct iovec vec[3]; 178 char tmp_tag[32]; 179 180 if (!tag) 181 tag = ""; 182 183 /* XXX: This needs to go! */ 184 if ((bufID != LOG_ID_RADIO) && 185 (!strcmp(tag, "HTC_RIL") || 186 !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */ 187 !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */ 188 !strcmp(tag, "AT") || 189 !strcmp(tag, "GSM") || 190 !strcmp(tag, "STK") || 191 !strcmp(tag, "CDMA") || 192 !strcmp(tag, "PHONE") || 193 !strcmp(tag, "SMS"))) { 194 bufID = LOG_ID_RADIO; 195 // Inform third party apps/ril/radio.. to use Rlog or RLOG 196 snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag); 197 tag = tmp_tag; 198 } 199 200 vec[0].iov_base = (unsigned char *) &prio; 201 vec[0].iov_len = 1; 202 vec[1].iov_base = (void *) tag; 203 vec[1].iov_len = strlen(tag) + 1; 204 vec[2].iov_base = (void *) msg; 205 vec[2].iov_len = strlen(msg) + 1; 206 207 return write_to_log(bufID, vec, 3); 208} 209 210int __android_log_vprint(int prio, const char *tag, const char *fmt, va_list ap) 211{ 212 char buf[LOG_BUF_SIZE]; 213 214 vsnprintf(buf, LOG_BUF_SIZE, fmt, ap); 215 216 return __android_log_write(prio, tag, buf); 217} 218 219int __android_log_print(int prio, const char *tag, const char *fmt, ...) 220{ 221 va_list ap; 222 char buf[LOG_BUF_SIZE]; 223 224 va_start(ap, fmt); 225 vsnprintf(buf, LOG_BUF_SIZE, fmt, ap); 226 va_end(ap); 227 228 return __android_log_write(prio, tag, buf); 229} 230 231int __android_log_buf_print(int bufID, int prio, const char *tag, const char *fmt, ...) 232{ 233 va_list ap; 234 char buf[LOG_BUF_SIZE]; 235 236 va_start(ap, fmt); 237 vsnprintf(buf, LOG_BUF_SIZE, fmt, ap); 238 va_end(ap); 239 240 return __android_log_buf_write(bufID, prio, tag, buf); 241} 242 243void __android_log_assert(const char *cond, const char *tag, 244 const char *fmt, ...) 245{ 246 char buf[LOG_BUF_SIZE]; 247 248 if (fmt) { 249 va_list ap; 250 va_start(ap, fmt); 251 vsnprintf(buf, LOG_BUF_SIZE, fmt, ap); 252 va_end(ap); 253 } else { 254 /* Msg not provided, log condition. N.B. Do not use cond directly as 255 * format string as it could contain spurious '%' syntax (e.g. 256 * "%d" in "blocks%devs == 0"). 257 */ 258 if (cond) 259 snprintf(buf, LOG_BUF_SIZE, "Assertion failed: %s", cond); 260 else 261 strcpy(buf, "Unspecified assertion failed"); 262 } 263 264 __android_log_write(ANDROID_LOG_FATAL, tag, buf); 265 266 __builtin_trap(); /* trap so we have a chance to debug the situation */ 267} 268 269int __android_log_bwrite(int32_t tag, const void *payload, size_t len) 270{ 271 struct iovec vec[2]; 272 273 vec[0].iov_base = &tag; 274 vec[0].iov_len = sizeof(tag); 275 vec[1].iov_base = (void*)payload; 276 vec[1].iov_len = len; 277 278 return write_to_log(LOG_ID_EVENTS, vec, 2); 279} 280 281/* 282 * Like __android_log_bwrite, but takes the type as well. Doesn't work 283 * for the general case where we're generating lists of stuff, but very 284 * handy if we just want to dump an integer into the log. 285 */ 286int __android_log_btwrite(int32_t tag, char type, const void *payload, 287 size_t len) 288{ 289 struct iovec vec[3]; 290 291 vec[0].iov_base = &tag; 292 vec[0].iov_len = sizeof(tag); 293 vec[1].iov_base = &type; 294 vec[1].iov_len = sizeof(type); 295 vec[2].iov_base = (void*)payload; 296 vec[2].iov_len = len; 297 298 return write_to_log(LOG_ID_EVENTS, vec, 3); 299} 300