Home | History | Annotate | Download | only in base
      1 /*
      2  * Copyright (C) 2011 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 "logging.h"
     18 
     19 #include <iostream>
     20 #include <limits>
     21 #include <sstream>
     22 
     23 #include "base/mutex.h"
     24 #include "runtime.h"
     25 #include "thread-inl.h"
     26 #include "utils.h"
     27 
     28 // Headers for LogMessage::LogLine.
     29 #ifdef HAVE_ANDROID_OS
     30 #include "cutils/log.h"
     31 #else
     32 #include <sys/types.h>
     33 #include <unistd.h>
     34 #endif
     35 
     36 namespace art {
     37 
     38 LogVerbosity gLogVerbosity;
     39 
     40 unsigned int gAborting = 0;
     41 
     42 static LogSeverity gMinimumLogSeverity = INFO;
     43 static std::unique_ptr<std::string> gCmdLine;
     44 static std::unique_ptr<std::string> gProgramInvocationName;
     45 static std::unique_ptr<std::string> gProgramInvocationShortName;
     46 
     47 // Print INTERNAL_FATAL messages directly instead of at destruction time. This only works on the
     48 // host right now: for the device, a stream buf collating output into lines and calling LogLine or
     49 // lower-level logging is necessary.
     50 #ifdef HAVE_ANDROID_OS
     51 static constexpr bool kPrintInternalFatalDirectly = false;
     52 #else
     53 static constexpr bool kPrintInternalFatalDirectly = !kIsTargetBuild;
     54 #endif
     55 
     56 static bool PrintDirectly(LogSeverity severity) {
     57   return kPrintInternalFatalDirectly && severity == INTERNAL_FATAL;
     58 }
     59 
     60 const char* GetCmdLine() {
     61   return (gCmdLine.get() != nullptr) ? gCmdLine->c_str() : nullptr;
     62 }
     63 
     64 const char* ProgramInvocationName() {
     65   return (gProgramInvocationName.get() != nullptr) ? gProgramInvocationName->c_str() : "art";
     66 }
     67 
     68 const char* ProgramInvocationShortName() {
     69   return (gProgramInvocationShortName.get() != nullptr) ? gProgramInvocationShortName->c_str()
     70                                                         : "art";
     71 }
     72 
     73 void InitLogging(char* argv[]) {
     74   if (gCmdLine.get() != nullptr) {
     75     return;
     76   }
     77   // TODO: Move this to a more obvious InitART...
     78   Locks::Init();
     79 
     80   // Stash the command line for later use. We can use /proc/self/cmdline on Linux to recover this,
     81   // but we don't have that luxury on the Mac, and there are a couple of argv[0] variants that are
     82   // commonly used.
     83   if (argv != nullptr) {
     84     gCmdLine.reset(new std::string(argv[0]));
     85     for (size_t i = 1; argv[i] != nullptr; ++i) {
     86       gCmdLine->append(" ");
     87       gCmdLine->append(argv[i]);
     88     }
     89     gProgramInvocationName.reset(new std::string(argv[0]));
     90     const char* last_slash = strrchr(argv[0], '/');
     91     gProgramInvocationShortName.reset(new std::string((last_slash != nullptr) ? last_slash + 1
     92                                                                            : argv[0]));
     93   } else {
     94     // TODO: fall back to /proc/self/cmdline when argv is null on Linux.
     95     gCmdLine.reset(new std::string("<unset>"));
     96   }
     97   const char* tags = getenv("ANDROID_LOG_TAGS");
     98   if (tags == nullptr) {
     99     return;
    100   }
    101 
    102   std::vector<std::string> specs;
    103   Split(tags, ' ', &specs);
    104   for (size_t i = 0; i < specs.size(); ++i) {
    105     // "tag-pattern:[vdiwefs]"
    106     std::string spec(specs[i]);
    107     if (spec.size() == 3 && StartsWith(spec, "*:")) {
    108       switch (spec[2]) {
    109         case 'v':
    110           gMinimumLogSeverity = VERBOSE;
    111           continue;
    112         case 'd':
    113           gMinimumLogSeverity = DEBUG;
    114           continue;
    115         case 'i':
    116           gMinimumLogSeverity = INFO;
    117           continue;
    118         case 'w':
    119           gMinimumLogSeverity = WARNING;
    120           continue;
    121         case 'e':
    122           gMinimumLogSeverity = ERROR;
    123           continue;
    124         case 'f':
    125           gMinimumLogSeverity = FATAL;
    126           continue;
    127         // liblog will even suppress FATAL if you say 's' for silent, but that's crazy!
    128         case 's':
    129           gMinimumLogSeverity = FATAL;
    130           continue;
    131       }
    132     }
    133     LOG(FATAL) << "unsupported '" << spec << "' in ANDROID_LOG_TAGS (" << tags << ")";
    134   }
    135 }
    136 
    137 // This indirection greatly reduces the stack impact of having
    138 // lots of checks/logging in a function.
    139 class LogMessageData {
    140  public:
    141   LogMessageData(const char* file, unsigned int line, LogSeverity severity, int error)
    142       : file_(file),
    143         line_number_(line),
    144         severity_(severity),
    145         error_(error) {
    146     const char* last_slash = strrchr(file, '/');
    147     file = (last_slash == nullptr) ? file : last_slash + 1;
    148   }
    149 
    150   const char * GetFile() const {
    151     return file_;
    152   }
    153 
    154   unsigned int GetLineNumber() const {
    155     return line_number_;
    156   }
    157 
    158   LogSeverity GetSeverity() const {
    159     return severity_;
    160   }
    161 
    162   int GetError() const {
    163     return error_;
    164   }
    165 
    166   std::ostream& GetBuffer() {
    167     return buffer_;
    168   }
    169 
    170   std::string ToString() const {
    171     return buffer_.str();
    172   }
    173 
    174  private:
    175   std::ostringstream buffer_;
    176   const char* const file_;
    177   const unsigned int line_number_;
    178   const LogSeverity severity_;
    179   const int error_;
    180 
    181   DISALLOW_COPY_AND_ASSIGN(LogMessageData);
    182 };
    183 
    184 
    185 LogMessage::LogMessage(const char* file, unsigned int line, LogSeverity severity, int error)
    186   : data_(new LogMessageData(file, line, severity, error)) {
    187   if (PrintDirectly(severity)) {
    188     static const char* log_characters = "VDIWEFF";
    189     CHECK_EQ(strlen(log_characters), INTERNAL_FATAL + 1U);
    190     stream() << ProgramInvocationShortName() << " " << log_characters[static_cast<size_t>(severity)]
    191              << " " << getpid() << " " << ::art::GetTid() << " " << file << ":" <<  line << "]";
    192   }
    193 }
    194 LogMessage::~LogMessage() {
    195   if (!PrintDirectly(data_->GetSeverity())) {
    196     if (data_->GetSeverity() < gMinimumLogSeverity) {
    197       return;  // No need to format something we're not going to output.
    198     }
    199 
    200     // Finish constructing the message.
    201     if (data_->GetError() != -1) {
    202       data_->GetBuffer() << ": " << strerror(data_->GetError());
    203     }
    204     std::string msg(data_->ToString());
    205 
    206     // Do the actual logging with the lock held.
    207     {
    208       MutexLock mu(Thread::Current(), *Locks::logging_lock_);
    209       if (msg.find('\n') == std::string::npos) {
    210         LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetSeverity(), msg.c_str());
    211       } else {
    212         msg += '\n';
    213         size_t i = 0;
    214         while (i < msg.size()) {
    215           size_t nl = msg.find('\n', i);
    216           msg[nl] = '\0';
    217           LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetSeverity(), &msg[i]);
    218           i = nl + 1;
    219         }
    220       }
    221     }
    222   }
    223 
    224   // Abort if necessary.
    225   if (data_->GetSeverity() == FATAL) {
    226     Runtime::Abort();
    227   }
    228 }
    229 
    230 std::ostream& LogMessage::stream() {
    231   if (PrintDirectly(data_->GetSeverity())) {
    232     return std::cerr;
    233   }
    234   return data_->GetBuffer();
    235 }
    236 
    237 #ifdef HAVE_ANDROID_OS
    238 static const android_LogPriority kLogSeverityToAndroidLogPriority[] = {
    239   ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, ANDROID_LOG_WARN,
    240   ANDROID_LOG_ERROR, ANDROID_LOG_FATAL, ANDROID_LOG_FATAL
    241 };
    242 static_assert(arraysize(kLogSeverityToAndroidLogPriority) == INTERNAL_FATAL + 1,
    243               "Mismatch in size of kLogSeverityToAndroidLogPriority and values in LogSeverity");
    244 #endif
    245 
    246 void LogMessage::LogLine(const char* file, unsigned int line, LogSeverity log_severity,
    247                          const char* message) {
    248 #ifdef HAVE_ANDROID_OS
    249   const char* tag = ProgramInvocationShortName();
    250   int priority = kLogSeverityToAndroidLogPriority[log_severity];
    251   if (priority == ANDROID_LOG_FATAL) {
    252     LOG_PRI(priority, tag, "%s:%u] %s", file, line, message);
    253   } else {
    254     LOG_PRI(priority, tag, "%s", message);
    255   }
    256 #else
    257   static const char* log_characters = "VDIWEFF";
    258   CHECK_EQ(strlen(log_characters), INTERNAL_FATAL + 1U);
    259   char severity = log_characters[log_severity];
    260   fprintf(stderr, "%s %c %5d %5d %s:%u] %s\n",
    261           ProgramInvocationShortName(), severity, getpid(), ::art::GetTid(), file, line, message);
    262 #endif
    263 }
    264 
    265 void LogMessage::LogLineLowStack(const char* file, unsigned int line, LogSeverity log_severity,
    266                                  const char* message) {
    267 #ifdef HAVE_ANDROID_OS
    268   // Use android_writeLog() to avoid stack-based buffers used by android_printLog().
    269   const char* tag = ProgramInvocationShortName();
    270   int priority = kLogSeverityToAndroidLogPriority[log_severity];
    271   char* buf = nullptr;
    272   size_t buf_size = 0u;
    273   if (priority == ANDROID_LOG_FATAL) {
    274     // Allocate buffer for snprintf(buf, buf_size, "%s:%u] %s", file, line, message) below.
    275     // If allocation fails, fall back to printing only the message.
    276     buf_size = strlen(file) + 1 /* ':' */ + std::numeric_limits<typeof(line)>::max_digits10 +
    277         2 /* "] " */ + strlen(message) + 1 /* terminating 0 */;
    278     buf = reinterpret_cast<char*>(malloc(buf_size));
    279   }
    280   if (buf != nullptr) {
    281     snprintf(buf, buf_size, "%s:%u] %s", file, line, message);
    282     android_writeLog(priority, tag, buf);
    283     free(buf);
    284   } else {
    285     android_writeLog(priority, tag, message);
    286   }
    287 #else
    288   static const char* log_characters = "VDIWEFF";
    289   CHECK_EQ(strlen(log_characters), INTERNAL_FATAL + 1U);
    290 
    291   const char* program_name = ProgramInvocationShortName();
    292   write(STDERR_FILENO, program_name, strlen(program_name));
    293   write(STDERR_FILENO, " ", 1);
    294   write(STDERR_FILENO, &log_characters[log_severity], 1);
    295   write(STDERR_FILENO, " ", 1);
    296   // TODO: pid and tid.
    297   write(STDERR_FILENO, file, strlen(file));
    298   // TODO: line.
    299   UNUSED(line);
    300   write(STDERR_FILENO, "] ", 2);
    301   write(STDERR_FILENO, message, strlen(message));
    302   write(STDERR_FILENO, "\n", 1);
    303 #endif
    304 }
    305 
    306 ScopedLogSeverity::ScopedLogSeverity(LogSeverity level) {
    307   old_ = gMinimumLogSeverity;
    308   gMinimumLogSeverity = level;
    309 }
    310 
    311 ScopedLogSeverity::~ScopedLogSeverity() {
    312   gMinimumLogSeverity = old_;
    313 }
    314 
    315 }  // namespace art
    316