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 !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */ 145 !strcmp(tag, "AT") || 146 !strcmp(tag, "GSM") || 147 !strcmp(tag, "STK") || 148 !strcmp(tag, "CDMA") || 149 !strcmp(tag, "PHONE") || 150 !strcmp(tag, "SMS")) 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 163 int __android_log_buf_write(int bufID, int prio, const char *tag, const char *msg) 164 { 165 struct iovec vec[3]; 166 167 if (!tag) 168 tag = ""; 169 170 /* XXX: This needs to go! */ 171 if (!strcmp(tag, "HTC_RIL") || 172 !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */ 173 !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */ 174 !strcmp(tag, "AT") || 175 !strcmp(tag, "GSM") || 176 !strcmp(tag, "STK") || 177 !strcmp(tag, "CDMA") || 178 !strcmp(tag, "PHONE") || 179 !strcmp(tag, "SMS")) 180 bufID = LOG_ID_RADIO; 181 182 vec[0].iov_base = (unsigned char *) &prio; 183 vec[0].iov_len = 1; 184 vec[1].iov_base = (void *) tag; 185 vec[1].iov_len = strlen(tag) + 1; 186 vec[2].iov_base = (void *) msg; 187 vec[2].iov_len = strlen(msg) + 1; 188 189 return write_to_log(bufID, vec, 3); 190 } 191 192 int __android_log_vprint(int prio, const char *tag, const char *fmt, va_list ap) 193 { 194 char buf[LOG_BUF_SIZE]; 195 196 vsnprintf(buf, LOG_BUF_SIZE, fmt, ap); 197 198 return __android_log_write(prio, tag, buf); 199 } 200 201 int __android_log_print(int prio, const char *tag, const char *fmt, ...) 202 { 203 va_list ap; 204 char buf[LOG_BUF_SIZE]; 205 206 va_start(ap, fmt); 207 vsnprintf(buf, LOG_BUF_SIZE, fmt, ap); 208 va_end(ap); 209 210 return __android_log_write(prio, tag, buf); 211 } 212 213 int __android_log_buf_print(int bufID, int prio, const char *tag, const char *fmt, ...) 214 { 215 va_list ap; 216 char buf[LOG_BUF_SIZE]; 217 218 va_start(ap, fmt); 219 vsnprintf(buf, LOG_BUF_SIZE, fmt, ap); 220 va_end(ap); 221 222 return __android_log_buf_write(bufID, prio, tag, buf); 223 } 224 225 void __android_log_assert(const char *cond, const char *tag, 226 const char *fmt, ...) 227 { 228 char buf[LOG_BUF_SIZE]; 229 230 if (fmt) { 231 va_list ap; 232 va_start(ap, fmt); 233 vsnprintf(buf, LOG_BUF_SIZE, fmt, ap); 234 va_end(ap); 235 } else { 236 /* Msg not provided, log condition. N.B. Do not use cond directly as 237 * format string as it could contain spurious '%' syntax (e.g. 238 * "%d" in "blocks%devs == 0"). 239 */ 240 if (cond) 241 snprintf(buf, LOG_BUF_SIZE, "Assertion failed: %s", cond); 242 else 243 strcpy(buf, "Unspecified assertion failed"); 244 } 245 246 __android_log_write(ANDROID_LOG_FATAL, tag, buf); 247 248 __builtin_trap(); /* trap so we have a chance to debug the situation */ 249 } 250 251 int __android_log_bwrite(int32_t tag, const void *payload, size_t len) 252 { 253 struct iovec vec[2]; 254 255 vec[0].iov_base = &tag; 256 vec[0].iov_len = sizeof(tag); 257 vec[1].iov_base = (void*)payload; 258 vec[1].iov_len = len; 259 260 return write_to_log(LOG_ID_EVENTS, vec, 2); 261 } 262 263 /* 264 * Like __android_log_bwrite, but takes the type as well. Doesn't work 265 * for the general case where we're generating lists of stuff, but very 266 * handy if we just want to dump an integer into the log. 267 */ 268 int __android_log_btwrite(int32_t tag, char type, const void *payload, 269 size_t len) 270 { 271 struct iovec vec[3]; 272 273 vec[0].iov_base = &tag; 274 vec[0].iov_len = sizeof(tag); 275 vec[1].iov_base = &type; 276 vec[1].iov_len = sizeof(type); 277 vec[2].iov_base = (void*)payload; 278 vec[2].iov_len = len; 279 280 return write_to_log(LOG_ID_EVENTS, vec, 3); 281 } 282