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