1 /* 2 * Copyright (C) 2015 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 #ifdef _WIN32 18 #include <windows.h> 19 #endif 20 21 #include "android-base/logging.h" 22 23 #include <libgen.h> 24 25 // For getprogname(3) or program_invocation_short_name. 26 #if defined(__ANDROID__) || defined(__APPLE__) 27 #include <stdlib.h> 28 #elif defined(__GLIBC__) 29 #include <errno.h> 30 #endif 31 32 #include <iostream> 33 #include <limits> 34 #include <sstream> 35 #include <string> 36 #include <utility> 37 #include <vector> 38 39 #ifndef _WIN32 40 #include <mutex> 41 #endif 42 43 #include "android-base/macros.h" 44 #include "android-base/strings.h" 45 #include "cutils/threads.h" 46 47 // Headers for LogMessage::LogLine. 48 #ifdef __ANDROID__ 49 #include <android/set_abort_message.h> 50 #include "cutils/log.h" 51 #else 52 #include <sys/types.h> 53 #include <unistd.h> 54 #endif 55 56 // For gettid. 57 #if defined(__APPLE__) 58 #include "AvailabilityMacros.h" // For MAC_OS_X_VERSION_MAX_ALLOWED 59 #include <stdint.h> 60 #include <stdlib.h> 61 #include <sys/syscall.h> 62 #include <sys/time.h> 63 #include <unistd.h> 64 #elif defined(__linux__) && !defined(__ANDROID__) 65 #include <syscall.h> 66 #include <unistd.h> 67 #elif defined(_WIN32) 68 #include <windows.h> 69 #endif 70 71 #if defined(_WIN32) 72 typedef uint32_t thread_id; 73 #else 74 typedef pid_t thread_id; 75 #endif 76 77 static thread_id GetThreadId() { 78 #if defined(__BIONIC__) 79 return gettid(); 80 #elif defined(__APPLE__) 81 return syscall(SYS_thread_selfid); 82 #elif defined(__linux__) 83 return syscall(__NR_gettid); 84 #elif defined(_WIN32) 85 return GetCurrentThreadId(); 86 #endif 87 } 88 89 namespace { 90 #ifndef _WIN32 91 using std::mutex; 92 using std::lock_guard; 93 94 #if defined(__GLIBC__) 95 const char* getprogname() { 96 return program_invocation_short_name; 97 } 98 #endif 99 100 #else 101 const char* getprogname() { 102 static bool first = true; 103 static char progname[MAX_PATH] = {}; 104 105 if (first) { 106 CHAR longname[MAX_PATH]; 107 DWORD nchars = GetModuleFileNameA(nullptr, longname, arraysize(longname)); 108 if ((nchars >= arraysize(longname)) || (nchars == 0)) { 109 // String truncation or some other error. 110 strcpy(progname, "<unknown>"); 111 } else { 112 strcpy(progname, basename(longname)); 113 } 114 first = false; 115 } 116 117 return progname; 118 } 119 120 class mutex { 121 public: 122 mutex() { 123 InitializeCriticalSection(&critical_section_); 124 } 125 ~mutex() { 126 DeleteCriticalSection(&critical_section_); 127 } 128 129 void lock() { 130 EnterCriticalSection(&critical_section_); 131 } 132 133 void unlock() { 134 LeaveCriticalSection(&critical_section_); 135 } 136 137 private: 138 CRITICAL_SECTION critical_section_; 139 }; 140 141 template <typename LockT> 142 class lock_guard { 143 public: 144 explicit lock_guard(LockT& lock) : lock_(lock) { 145 lock_.lock(); 146 } 147 148 ~lock_guard() { 149 lock_.unlock(); 150 } 151 152 private: 153 LockT& lock_; 154 155 DISALLOW_COPY_AND_ASSIGN(lock_guard); 156 }; 157 #endif 158 } // namespace 159 160 namespace android { 161 namespace base { 162 163 static auto& logging_lock = *new mutex(); 164 165 #ifdef __ANDROID__ 166 static auto& gLogger = *new LogFunction(LogdLogger()); 167 #else 168 static auto& gLogger = *new LogFunction(StderrLogger); 169 #endif 170 171 static bool gInitialized = false; 172 static LogSeverity gMinimumLogSeverity = INFO; 173 static auto& gProgramInvocationName = *new std::unique_ptr<std::string>(); 174 175 LogSeverity GetMinimumLogSeverity() { 176 return gMinimumLogSeverity; 177 } 178 179 static const char* ProgramInvocationName() { 180 if (gProgramInvocationName == nullptr) { 181 gProgramInvocationName.reset(new std::string(getprogname())); 182 } 183 184 return gProgramInvocationName->c_str(); 185 } 186 187 void StderrLogger(LogId, LogSeverity severity, const char*, const char* file, 188 unsigned int line, const char* message) { 189 static const char log_characters[] = "VDIWEF"; 190 static_assert(arraysize(log_characters) - 1 == FATAL + 1, 191 "Mismatch in size of log_characters and values in LogSeverity"); 192 char severity_char = log_characters[severity]; 193 fprintf(stderr, "%s %c %5d %5d %s:%u] %s\n", ProgramInvocationName(), 194 severity_char, getpid(), GetThreadId(), file, line, message); 195 } 196 197 198 #ifdef __ANDROID__ 199 LogdLogger::LogdLogger(LogId default_log_id) : default_log_id_(default_log_id) { 200 } 201 202 static const android_LogPriority kLogSeverityToAndroidLogPriority[] = { 203 ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, 204 ANDROID_LOG_WARN, ANDROID_LOG_ERROR, ANDROID_LOG_FATAL, 205 }; 206 static_assert(arraysize(kLogSeverityToAndroidLogPriority) == FATAL + 1, 207 "Mismatch in size of kLogSeverityToAndroidLogPriority and values " 208 "in LogSeverity"); 209 210 static const log_id kLogIdToAndroidLogId[] = { 211 LOG_ID_MAX, LOG_ID_MAIN, LOG_ID_SYSTEM, 212 }; 213 static_assert(arraysize(kLogIdToAndroidLogId) == SYSTEM + 1, 214 "Mismatch in size of kLogIdToAndroidLogId and values in LogId"); 215 216 void LogdLogger::operator()(LogId id, LogSeverity severity, const char* tag, 217 const char* file, unsigned int line, 218 const char* message) { 219 int priority = kLogSeverityToAndroidLogPriority[severity]; 220 if (id == DEFAULT) { 221 id = default_log_id_; 222 } 223 224 log_id lg_id = kLogIdToAndroidLogId[id]; 225 226 if (priority == ANDROID_LOG_FATAL) { 227 __android_log_buf_print(lg_id, priority, tag, "%s:%u] %s", file, line, 228 message); 229 } else { 230 __android_log_buf_print(lg_id, priority, tag, "%s", message); 231 } 232 } 233 #endif 234 235 void InitLogging(char* argv[], LogFunction&& logger) { 236 SetLogger(std::forward<LogFunction>(logger)); 237 InitLogging(argv); 238 } 239 240 void InitLogging(char* argv[]) { 241 if (gInitialized) { 242 return; 243 } 244 245 gInitialized = true; 246 247 // Stash the command line for later use. We can use /proc/self/cmdline on 248 // Linux to recover this, but we don't have that luxury on the Mac/Windows, 249 // and there are a couple of argv[0] variants that are commonly used. 250 if (argv != nullptr) { 251 gProgramInvocationName.reset(new std::string(basename(argv[0]))); 252 } 253 254 const char* tags = getenv("ANDROID_LOG_TAGS"); 255 if (tags == nullptr) { 256 return; 257 } 258 259 std::vector<std::string> specs = Split(tags, " "); 260 for (size_t i = 0; i < specs.size(); ++i) { 261 // "tag-pattern:[vdiwefs]" 262 std::string spec(specs[i]); 263 if (spec.size() == 3 && StartsWith(spec, "*:")) { 264 switch (spec[2]) { 265 case 'v': 266 gMinimumLogSeverity = VERBOSE; 267 continue; 268 case 'd': 269 gMinimumLogSeverity = DEBUG; 270 continue; 271 case 'i': 272 gMinimumLogSeverity = INFO; 273 continue; 274 case 'w': 275 gMinimumLogSeverity = WARNING; 276 continue; 277 case 'e': 278 gMinimumLogSeverity = ERROR; 279 continue; 280 case 'f': 281 gMinimumLogSeverity = FATAL; 282 continue; 283 // liblog will even suppress FATAL if you say 's' for silent, but that's 284 // crazy! 285 case 's': 286 gMinimumLogSeverity = FATAL; 287 continue; 288 } 289 } 290 LOG(FATAL) << "unsupported '" << spec << "' in ANDROID_LOG_TAGS (" << tags 291 << ")"; 292 } 293 } 294 295 void SetLogger(LogFunction&& logger) { 296 lock_guard<mutex> lock(logging_lock); 297 gLogger = std::move(logger); 298 } 299 300 static const char* GetFileBasename(const char* file) { 301 // We can't use basename(3) even on Unix because the Mac doesn't 302 // have a non-modifying basename. 303 const char* last_slash = strrchr(file, '/'); 304 if (last_slash != nullptr) { 305 return last_slash + 1; 306 } 307 #if defined(_WIN32) 308 const char* last_backslash = strrchr(file, '\\'); 309 if (last_backslash != nullptr) { 310 return last_backslash + 1; 311 } 312 #endif 313 return file; 314 } 315 316 // This indirection greatly reduces the stack impact of having lots of 317 // checks/logging in a function. 318 class LogMessageData { 319 public: 320 LogMessageData(const char* file, unsigned int line, LogId id, 321 LogSeverity severity, int error) 322 : file_(GetFileBasename(file)), 323 line_number_(line), 324 id_(id), 325 severity_(severity), 326 error_(error) { 327 } 328 329 const char* GetFile() const { 330 return file_; 331 } 332 333 unsigned int GetLineNumber() const { 334 return line_number_; 335 } 336 337 LogSeverity GetSeverity() const { 338 return severity_; 339 } 340 341 LogId GetId() const { 342 return id_; 343 } 344 345 int GetError() const { 346 return error_; 347 } 348 349 std::ostream& GetBuffer() { 350 return buffer_; 351 } 352 353 std::string ToString() const { 354 return buffer_.str(); 355 } 356 357 private: 358 std::ostringstream buffer_; 359 const char* const file_; 360 const unsigned int line_number_; 361 const LogId id_; 362 const LogSeverity severity_; 363 const int error_; 364 365 DISALLOW_COPY_AND_ASSIGN(LogMessageData); 366 }; 367 368 LogMessage::LogMessage(const char* file, unsigned int line, LogId id, 369 LogSeverity severity, int error) 370 : data_(new LogMessageData(file, line, id, severity, error)) { 371 } 372 373 LogMessage::~LogMessage() { 374 // Finish constructing the message. 375 if (data_->GetError() != -1) { 376 data_->GetBuffer() << ": " << strerror(data_->GetError()); 377 } 378 std::string msg(data_->ToString()); 379 380 { 381 // Do the actual logging with the lock held. 382 lock_guard<mutex> lock(logging_lock); 383 if (msg.find('\n') == std::string::npos) { 384 LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetId(), 385 data_->GetSeverity(), msg.c_str()); 386 } else { 387 msg += '\n'; 388 size_t i = 0; 389 while (i < msg.size()) { 390 size_t nl = msg.find('\n', i); 391 msg[nl] = '\0'; 392 LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetId(), 393 data_->GetSeverity(), &msg[i]); 394 i = nl + 1; 395 } 396 } 397 } 398 399 // Abort if necessary. 400 if (data_->GetSeverity() == FATAL) { 401 #ifdef __ANDROID__ 402 android_set_abort_message(msg.c_str()); 403 #endif 404 abort(); 405 } 406 } 407 408 std::ostream& LogMessage::stream() { 409 return data_->GetBuffer(); 410 } 411 412 void LogMessage::LogLine(const char* file, unsigned int line, LogId id, 413 LogSeverity severity, const char* message) { 414 const char* tag = ProgramInvocationName(); 415 gLogger(id, severity, tag, file, line, message); 416 } 417 418 ScopedLogSeverity::ScopedLogSeverity(LogSeverity level) { 419 old_ = gMinimumLogSeverity; 420 gMinimumLogSeverity = level; 421 } 422 423 ScopedLogSeverity::~ScopedLogSeverity() { 424 gMinimumLogSeverity = old_; 425 } 426 427 } // namespace base 428 } // namespace android 429