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) 72typedef uint32_t thread_id; 73#else 74typedef pid_t thread_id; 75#endif 76 77static 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 89namespace { 90#ifndef _WIN32 91using std::mutex; 92using std::lock_guard; 93 94#if defined(__GLIBC__) 95const char* getprogname() { 96 return program_invocation_short_name; 97} 98#endif 99 100#else 101const 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 120class 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 141template <typename LockT> 142class 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 160namespace android { 161namespace base { 162 163static auto& logging_lock = *new mutex(); 164 165#ifdef __ANDROID__ 166static auto& gLogger = *new LogFunction(LogdLogger()); 167#else 168static auto& gLogger = *new LogFunction(StderrLogger); 169#endif 170 171static bool gInitialized = false; 172static LogSeverity gMinimumLogSeverity = INFO; 173static auto& gProgramInvocationName = *new std::unique_ptr<std::string>(); 174 175LogSeverity GetMinimumLogSeverity() { 176 return gMinimumLogSeverity; 177} 178 179static const char* ProgramInvocationName() { 180 if (gProgramInvocationName == nullptr) { 181 gProgramInvocationName.reset(new std::string(getprogname())); 182 } 183 184 return gProgramInvocationName->c_str(); 185} 186 187void 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__ 199LogdLogger::LogdLogger(LogId default_log_id) : default_log_id_(default_log_id) { 200} 201 202static 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}; 206static_assert(arraysize(kLogSeverityToAndroidLogPriority) == FATAL + 1, 207 "Mismatch in size of kLogSeverityToAndroidLogPriority and values " 208 "in LogSeverity"); 209 210static const log_id kLogIdToAndroidLogId[] = { 211 LOG_ID_MAX, LOG_ID_MAIN, LOG_ID_SYSTEM, 212}; 213static_assert(arraysize(kLogIdToAndroidLogId) == SYSTEM + 1, 214 "Mismatch in size of kLogIdToAndroidLogId and values in LogId"); 215 216void 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 235void InitLogging(char* argv[], LogFunction&& logger) { 236 SetLogger(std::forward<LogFunction>(logger)); 237 InitLogging(argv); 238} 239 240void 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 295void SetLogger(LogFunction&& logger) { 296 lock_guard<mutex> lock(logging_lock); 297 gLogger = std::move(logger); 298} 299 300static 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. 318class 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 368LogMessage::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 373LogMessage::~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 408std::ostream& LogMessage::stream() { 409 return data_->GetBuffer(); 410} 411 412void 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 418ScopedLogSeverity::ScopedLogSeverity(LogSeverity level) { 419 old_ = gMinimumLogSeverity; 420 gMinimumLogSeverity = level; 421} 422 423ScopedLogSeverity::~ScopedLogSeverity() { 424 gMinimumLogSeverity = old_; 425} 426 427} // namespace base 428} // namespace android 429