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 __ANDROID__ 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 __ANDROID__ 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 constexpr char kLogCharacters[] = { 'N', 'V', 'D', 'I', 'W', 'E', 'F', 'F' }; 189 static_assert(arraysize(kLogCharacters) == static_cast<size_t>(INTERNAL_FATAL) + 1, 190 "Wrong character array size"); 191 stream() << ProgramInvocationShortName() << " " << kLogCharacters[static_cast<size_t>(severity)] 192 << " " << getpid() << " " << ::art::GetTid() << " " << file << ":" << line << "]"; 193 } 194 } 195 LogMessage::~LogMessage() { 196 if (!PrintDirectly(data_->GetSeverity()) && data_->GetSeverity() != LogSeverity::NONE) { 197 if (data_->GetSeverity() < gMinimumLogSeverity) { 198 return; // No need to format something we're not going to output. 199 } 200 201 // Finish constructing the message. 202 if (data_->GetError() != -1) { 203 data_->GetBuffer() << ": " << strerror(data_->GetError()); 204 } 205 std::string msg(data_->ToString()); 206 207 // Do the actual logging with the lock held. 208 { 209 MutexLock mu(Thread::Current(), *Locks::logging_lock_); 210 if (msg.find('\n') == std::string::npos) { 211 LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetSeverity(), msg.c_str()); 212 } else { 213 msg += '\n'; 214 size_t i = 0; 215 while (i < msg.size()) { 216 size_t nl = msg.find('\n', i); 217 msg[nl] = '\0'; 218 LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetSeverity(), &msg[i]); 219 i = nl + 1; 220 } 221 } 222 } 223 } 224 225 // Abort if necessary. 226 if (data_->GetSeverity() == FATAL) { 227 Runtime::Abort(); 228 } 229 } 230 231 std::ostream& LogMessage::stream() { 232 if (PrintDirectly(data_->GetSeverity())) { 233 return std::cerr; 234 } 235 return data_->GetBuffer(); 236 } 237 238 #ifdef __ANDROID__ 239 static const android_LogPriority kLogSeverityToAndroidLogPriority[] = { 240 ANDROID_LOG_VERBOSE, // NONE, use verbose as stand-in, will never be printed. 241 ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, ANDROID_LOG_WARN, 242 ANDROID_LOG_ERROR, ANDROID_LOG_FATAL, ANDROID_LOG_FATAL 243 }; 244 static_assert(arraysize(kLogSeverityToAndroidLogPriority) == INTERNAL_FATAL + 1, 245 "Mismatch in size of kLogSeverityToAndroidLogPriority and values in LogSeverity"); 246 #endif 247 248 void LogMessage::LogLine(const char* file, unsigned int line, LogSeverity log_severity, 249 const char* message) { 250 if (log_severity == LogSeverity::NONE) { 251 return; 252 } 253 254 #ifdef __ANDROID__ 255 const char* tag = ProgramInvocationShortName(); 256 int priority = kLogSeverityToAndroidLogPriority[static_cast<size_t>(log_severity)]; 257 if (priority == ANDROID_LOG_FATAL) { 258 LOG_PRI(priority, tag, "%s:%u] %s", file, line, message); 259 } else { 260 LOG_PRI(priority, tag, "%s", message); 261 } 262 #else 263 static const char* log_characters = "NVDIWEFF"; 264 CHECK_EQ(strlen(log_characters), INTERNAL_FATAL + 1U); 265 char severity = log_characters[log_severity]; 266 fprintf(stderr, "%s %c %5d %5d %s:%u] %s\n", 267 ProgramInvocationShortName(), severity, getpid(), ::art::GetTid(), file, line, message); 268 #endif 269 } 270 271 void LogMessage::LogLineLowStack(const char* file, unsigned int line, LogSeverity log_severity, 272 const char* message) { 273 if (log_severity == LogSeverity::NONE) { 274 return; 275 } 276 277 #ifdef __ANDROID__ 278 // Use android_writeLog() to avoid stack-based buffers used by android_printLog(). 279 const char* tag = ProgramInvocationShortName(); 280 int priority = kLogSeverityToAndroidLogPriority[static_cast<size_t>(log_severity)]; 281 char* buf = nullptr; 282 size_t buf_size = 0u; 283 if (priority == ANDROID_LOG_FATAL) { 284 // Allocate buffer for snprintf(buf, buf_size, "%s:%u] %s", file, line, message) below. 285 // If allocation fails, fall back to printing only the message. 286 buf_size = strlen(file) + 1 /* ':' */ + std::numeric_limits<typeof(line)>::max_digits10 + 287 2 /* "] " */ + strlen(message) + 1 /* terminating 0 */; 288 buf = reinterpret_cast<char*>(malloc(buf_size)); 289 } 290 if (buf != nullptr) { 291 snprintf(buf, buf_size, "%s:%u] %s", file, line, message); 292 android_writeLog(priority, tag, buf); 293 free(buf); 294 } else { 295 android_writeLog(priority, tag, message); 296 } 297 #else 298 static constexpr char kLogCharacters[] = { 'N', 'V', 'D', 'I', 'W', 'E', 'F', 'F' }; 299 static_assert(arraysize(kLogCharacters) == static_cast<size_t>(INTERNAL_FATAL) + 1, 300 "Wrong character array size"); 301 302 const char* program_name = ProgramInvocationShortName(); 303 TEMP_FAILURE_RETRY(write(STDERR_FILENO, program_name, strlen(program_name))); 304 TEMP_FAILURE_RETRY(write(STDERR_FILENO, " ", 1)); 305 TEMP_FAILURE_RETRY(write(STDERR_FILENO, &kLogCharacters[static_cast<size_t>(log_severity)], 1)); 306 TEMP_FAILURE_RETRY(write(STDERR_FILENO, " ", 1)); 307 // TODO: pid and tid. 308 TEMP_FAILURE_RETRY(write(STDERR_FILENO, file, strlen(file))); 309 // TODO: line. 310 UNUSED(line); 311 TEMP_FAILURE_RETRY(write(STDERR_FILENO, "] ", 2)); 312 TEMP_FAILURE_RETRY(write(STDERR_FILENO, message, strlen(message))); 313 TEMP_FAILURE_RETRY(write(STDERR_FILENO, "\n", 1)); 314 #endif 315 } 316 317 ScopedLogSeverity::ScopedLogSeverity(LogSeverity level) { 318 old_ = gMinimumLogSeverity; 319 gMinimumLogSeverity = level; 320 } 321 322 ScopedLogSeverity::~ScopedLogSeverity() { 323 gMinimumLogSeverity = old_; 324 } 325 326 } // namespace art 327