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 17 #include <errno.h> 18 #include <fcntl.h> 19 #ifdef HAVE_PTHREADS 20 #include <pthread.h> 21 #endif 22 #include <stdarg.h> 23 #include <stdio.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include <sys/stat.h> 27 #include <sys/types.h> 28 #include <time.h> 29 #include <unistd.h> 30 31 #ifdef __BIONIC__ 32 #include <android/set_abort_message.h> 33 #endif 34 35 #include <log/log.h> 36 #include <log/logd.h> 37 #include <log/logger.h> 38 39 #define LOGGER_LOG_MAIN "log/main" 40 #define LOGGER_LOG_RADIO "log/radio" 41 #define LOGGER_LOG_EVENTS "log/events" 42 #define LOGGER_LOG_SYSTEM "log/system" 43 44 #define LOG_BUF_SIZE 1024 45 46 #if FAKE_LOG_DEVICE 47 /* This will be defined when building for the host. */ 48 #include "fake_log_device.h" 49 #define log_open(pathname, flags) fakeLogOpen(pathname, flags) 50 #define log_writev(filedes, vector, count) fakeLogWritev(filedes, vector, count) 51 #define log_close(filedes) fakeLogClose(filedes) 52 #else 53 #define log_open(pathname, flags) open(pathname, (flags) | O_CLOEXEC) 54 #define log_writev(filedes, vector, count) writev(filedes, vector, count) 55 #define log_close(filedes) close(filedes) 56 #endif 57 58 static int __write_to_log_init(log_id_t, struct iovec *vec, size_t nr); 59 static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = __write_to_log_init; 60 #ifdef HAVE_PTHREADS 61 static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER; 62 #endif 63 64 #ifndef __unused 65 #define __unused __attribute__((__unused__)) 66 #endif 67 68 static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1 }; 69 70 /* 71 * This is used by the C++ code to decide if it should write logs through 72 * the C code. Basically, if /dev/log/... is available, we're running in 73 * the simulator rather than a desktop tool and want to use the device. 74 */ 75 static enum { 76 kLogUninitialized, kLogNotAvailable, kLogAvailable 77 } g_log_status = kLogUninitialized; 78 int __android_log_dev_available(void) 79 { 80 if (g_log_status == kLogUninitialized) { 81 if (access("/dev/"LOGGER_LOG_MAIN, W_OK) == 0) 82 g_log_status = kLogAvailable; 83 else 84 g_log_status = kLogNotAvailable; 85 } 86 87 return (g_log_status == kLogAvailable); 88 } 89 90 static int __write_to_log_null(log_id_t log_fd __unused, struct iovec *vec __unused, 91 size_t nr __unused) 92 { 93 return -1; 94 } 95 96 static int __write_to_log_kernel(log_id_t log_id, struct iovec *vec, size_t nr) 97 { 98 ssize_t ret; 99 int log_fd; 100 101 if (/*(int)log_id >= 0 &&*/ (int)log_id < (int)LOG_ID_MAX) { 102 if (log_id == LOG_ID_CRASH) { 103 log_id = LOG_ID_MAIN; 104 } 105 log_fd = log_fds[(int)log_id]; 106 } else { 107 return -EBADF; 108 } 109 110 do { 111 ret = log_writev(log_fd, vec, nr); 112 if (ret < 0) { 113 ret = -errno; 114 } 115 } while (ret == -EINTR); 116 117 return ret; 118 } 119 120 static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr) 121 { 122 #ifdef HAVE_PTHREADS 123 pthread_mutex_lock(&log_init_lock); 124 #endif 125 126 if (write_to_log == __write_to_log_init) { 127 log_fds[LOG_ID_MAIN] = log_open("/dev/"LOGGER_LOG_MAIN, O_WRONLY); 128 log_fds[LOG_ID_RADIO] = log_open("/dev/"LOGGER_LOG_RADIO, O_WRONLY); 129 log_fds[LOG_ID_EVENTS] = log_open("/dev/"LOGGER_LOG_EVENTS, O_WRONLY); 130 log_fds[LOG_ID_SYSTEM] = log_open("/dev/"LOGGER_LOG_SYSTEM, O_WRONLY); 131 132 write_to_log = __write_to_log_kernel; 133 134 if (log_fds[LOG_ID_MAIN] < 0 || log_fds[LOG_ID_RADIO] < 0 || 135 log_fds[LOG_ID_EVENTS] < 0) { 136 log_close(log_fds[LOG_ID_MAIN]); 137 log_close(log_fds[LOG_ID_RADIO]); 138 log_close(log_fds[LOG_ID_EVENTS]); 139 log_fds[LOG_ID_MAIN] = -1; 140 log_fds[LOG_ID_RADIO] = -1; 141 log_fds[LOG_ID_EVENTS] = -1; 142 write_to_log = __write_to_log_null; 143 } 144 145 if (log_fds[LOG_ID_SYSTEM] < 0) { 146 log_fds[LOG_ID_SYSTEM] = log_fds[LOG_ID_MAIN]; 147 } 148 } 149 150 #ifdef HAVE_PTHREADS 151 pthread_mutex_unlock(&log_init_lock); 152 #endif 153 154 return write_to_log(log_id, vec, nr); 155 } 156 157 int __android_log_write(int prio, const char *tag, const char *msg) 158 { 159 struct iovec vec[3]; 160 log_id_t log_id = LOG_ID_MAIN; 161 char tmp_tag[32]; 162 163 if (!tag) 164 tag = ""; 165 166 /* XXX: This needs to go! */ 167 if (!strcmp(tag, "HTC_RIL") || 168 !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */ 169 !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */ 170 !strcmp(tag, "AT") || 171 !strcmp(tag, "GSM") || 172 !strcmp(tag, "STK") || 173 !strcmp(tag, "CDMA") || 174 !strcmp(tag, "PHONE") || 175 !strcmp(tag, "SMS")) { 176 log_id = LOG_ID_RADIO; 177 /* Inform third party apps/ril/radio.. to use Rlog or RLOG */ 178 snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag); 179 tag = tmp_tag; 180 } 181 182 #if __BIONIC__ 183 if (prio == ANDROID_LOG_FATAL) { 184 android_set_abort_message(msg); 185 } 186 #endif 187 188 vec[0].iov_base = (unsigned char *) &prio; 189 vec[0].iov_len = 1; 190 vec[1].iov_base = (void *) tag; 191 vec[1].iov_len = strlen(tag) + 1; 192 vec[2].iov_base = (void *) msg; 193 vec[2].iov_len = strlen(msg) + 1; 194 195 return write_to_log(log_id, vec, 3); 196 } 197 198 int __android_log_buf_write(int bufID, int prio, const char *tag, const char *msg) 199 { 200 struct iovec vec[3]; 201 char tmp_tag[32]; 202 203 if (!tag) 204 tag = ""; 205 206 /* XXX: This needs to go! */ 207 if ((bufID != LOG_ID_RADIO) && 208 (!strcmp(tag, "HTC_RIL") || 209 !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */ 210 !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */ 211 !strcmp(tag, "AT") || 212 !strcmp(tag, "GSM") || 213 !strcmp(tag, "STK") || 214 !strcmp(tag, "CDMA") || 215 !strcmp(tag, "PHONE") || 216 !strcmp(tag, "SMS"))) { 217 bufID = LOG_ID_RADIO; 218 /* Inform third party apps/ril/radio.. to use Rlog or RLOG */ 219 snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag); 220 tag = tmp_tag; 221 } 222 223 vec[0].iov_base = (unsigned char *) &prio; 224 vec[0].iov_len = 1; 225 vec[1].iov_base = (void *) tag; 226 vec[1].iov_len = strlen(tag) + 1; 227 vec[2].iov_base = (void *) msg; 228 vec[2].iov_len = strlen(msg) + 1; 229 230 return write_to_log(bufID, vec, 3); 231 } 232 233 int __android_log_vprint(int prio, const char *tag, const char *fmt, va_list ap) 234 { 235 char buf[LOG_BUF_SIZE]; 236 237 vsnprintf(buf, LOG_BUF_SIZE, fmt, ap); 238 239 return __android_log_write(prio, tag, buf); 240 } 241 242 int __android_log_print(int prio, const char *tag, const char *fmt, ...) 243 { 244 va_list ap; 245 char buf[LOG_BUF_SIZE]; 246 247 va_start(ap, fmt); 248 vsnprintf(buf, LOG_BUF_SIZE, fmt, ap); 249 va_end(ap); 250 251 return __android_log_write(prio, tag, buf); 252 } 253 254 int __android_log_buf_print(int bufID, int prio, const char *tag, const char *fmt, ...) 255 { 256 va_list ap; 257 char buf[LOG_BUF_SIZE]; 258 259 va_start(ap, fmt); 260 vsnprintf(buf, LOG_BUF_SIZE, fmt, ap); 261 va_end(ap); 262 263 return __android_log_buf_write(bufID, prio, tag, buf); 264 } 265 266 void __android_log_assert(const char *cond, const char *tag, 267 const char *fmt, ...) 268 { 269 char buf[LOG_BUF_SIZE]; 270 271 if (fmt) { 272 va_list ap; 273 va_start(ap, fmt); 274 vsnprintf(buf, LOG_BUF_SIZE, fmt, ap); 275 va_end(ap); 276 } else { 277 /* Msg not provided, log condition. N.B. Do not use cond directly as 278 * format string as it could contain spurious '%' syntax (e.g. 279 * "%d" in "blocks%devs == 0"). 280 */ 281 if (cond) 282 snprintf(buf, LOG_BUF_SIZE, "Assertion failed: %s", cond); 283 else 284 strcpy(buf, "Unspecified assertion failed"); 285 } 286 287 __android_log_write(ANDROID_LOG_FATAL, tag, buf); 288 __builtin_trap(); /* trap so we have a chance to debug the situation */ 289 /* NOTREACHED */ 290 } 291 292 int __android_log_bwrite(int32_t tag, const void *payload, size_t len) 293 { 294 struct iovec vec[2]; 295 296 vec[0].iov_base = &tag; 297 vec[0].iov_len = sizeof(tag); 298 vec[1].iov_base = (void*)payload; 299 vec[1].iov_len = len; 300 301 return write_to_log(LOG_ID_EVENTS, vec, 2); 302 } 303 304 /* 305 * Like __android_log_bwrite, but takes the type as well. Doesn't work 306 * for the general case where we're generating lists of stuff, but very 307 * handy if we just want to dump an integer into the log. 308 */ 309 int __android_log_btwrite(int32_t tag, char type, const void *payload, 310 size_t len) 311 { 312 struct iovec vec[3]; 313 314 vec[0].iov_base = &tag; 315 vec[0].iov_len = sizeof(tag); 316 vec[1].iov_base = &type; 317 vec[1].iov_len = sizeof(type); 318 vec[2].iov_base = (void*)payload; 319 vec[2].iov_len = len; 320 321 return write_to_log(LOG_ID_EVENTS, vec, 3); 322 } 323 324 /* 325 * Like __android_log_bwrite, but used for writing strings to the 326 * event log. 327 */ 328 int __android_log_bswrite(int32_t tag, const char *payload) 329 { 330 struct iovec vec[4]; 331 char type = EVENT_TYPE_STRING; 332 uint32_t len = strlen(payload); 333 334 vec[0].iov_base = &tag; 335 vec[0].iov_len = sizeof(tag); 336 vec[1].iov_base = &type; 337 vec[1].iov_len = sizeof(type); 338 vec[2].iov_base = &len; 339 vec[2].iov_len = sizeof(len); 340 vec[3].iov_base = (void*)payload; 341 vec[3].iov_len = len; 342 343 return write_to_log(LOG_ID_EVENTS, vec, 4); 344 } 345