Home | History | Annotate | Download | only in base
      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