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 "thread-inl.h" 25#include "utils.h" 26 27// Headers for LogMessage::LogLine. 28#ifdef ART_TARGET_ANDROID 29#include <log/log.h> 30#else 31#include <sys/types.h> 32#include <unistd.h> 33#endif 34 35namespace art { 36 37LogVerbosity gLogVerbosity; 38 39unsigned int gAborting = 0; 40 41static std::unique_ptr<std::string> gCmdLine; 42static std::unique_ptr<std::string> gProgramInvocationName; 43static std::unique_ptr<std::string> gProgramInvocationShortName; 44 45const char* GetCmdLine() { 46 return (gCmdLine.get() != nullptr) ? gCmdLine->c_str() : nullptr; 47} 48 49const char* ProgramInvocationName() { 50 return (gProgramInvocationName.get() != nullptr) ? gProgramInvocationName->c_str() : "art"; 51} 52 53const char* ProgramInvocationShortName() { 54 return (gProgramInvocationShortName.get() != nullptr) ? gProgramInvocationShortName->c_str() 55 : "art"; 56} 57 58void InitLogging(char* argv[], AbortFunction& abort_function) { 59 if (gCmdLine.get() != nullptr) { 60 return; 61 } 62 // TODO: Move this to a more obvious InitART... 63 Locks::Init(); 64 65 // Stash the command line for later use. We can use /proc/self/cmdline on Linux to recover this, 66 // but we don't have that luxury on the Mac, and there are a couple of argv[0] variants that are 67 // commonly used. 68 if (argv != nullptr) { 69 gCmdLine.reset(new std::string(argv[0])); 70 for (size_t i = 1; argv[i] != nullptr; ++i) { 71 gCmdLine->append(" "); 72 gCmdLine->append(argv[i]); 73 } 74 gProgramInvocationName.reset(new std::string(argv[0])); 75 const char* last_slash = strrchr(argv[0], '/'); 76 gProgramInvocationShortName.reset(new std::string((last_slash != nullptr) ? last_slash + 1 77 : argv[0])); 78 } else { 79 // TODO: fall back to /proc/self/cmdline when argv is null on Linux. 80 gCmdLine.reset(new std::string("<unset>")); 81 } 82 83#ifdef ART_TARGET_ANDROID 84#define INIT_LOGGING_DEFAULT_LOGGER android::base::LogdLogger() 85#else 86#define INIT_LOGGING_DEFAULT_LOGGER android::base::StderrLogger 87#endif 88 android::base::InitLogging(argv, INIT_LOGGING_DEFAULT_LOGGER, 89 std::move<AbortFunction>(abort_function)); 90#undef INIT_LOGGING_DEFAULT_LOGGER 91} 92 93#ifdef ART_TARGET_ANDROID 94static const android_LogPriority kLogSeverityToAndroidLogPriority[] = { 95 ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, ANDROID_LOG_WARN, 96 ANDROID_LOG_ERROR, ANDROID_LOG_FATAL, ANDROID_LOG_FATAL 97}; 98static_assert(arraysize(kLogSeverityToAndroidLogPriority) == ::android::base::FATAL + 1, 99 "Mismatch in size of kLogSeverityToAndroidLogPriority and values in LogSeverity"); 100#endif 101 102void LogHelper::LogLineLowStack(const char* file, 103 unsigned int line, 104 LogSeverity log_severity, 105 const char* message) { 106#ifdef ART_TARGET_ANDROID 107 // Use android_writeLog() to avoid stack-based buffers used by android_printLog(). 108 const char* tag = ProgramInvocationShortName(); 109 int priority = kLogSeverityToAndroidLogPriority[static_cast<size_t>(log_severity)]; 110 char* buf = nullptr; 111 size_t buf_size = 0u; 112 if (priority == ANDROID_LOG_FATAL) { 113 // Allocate buffer for snprintf(buf, buf_size, "%s:%u] %s", file, line, message) below. 114 // If allocation fails, fall back to printing only the message. 115 buf_size = strlen(file) + 1 /* ':' */ + std::numeric_limits<typeof(line)>::max_digits10 + 116 2 /* "] " */ + strlen(message) + 1 /* terminating 0 */; 117 buf = reinterpret_cast<char*>(malloc(buf_size)); 118 } 119 if (buf != nullptr) { 120 snprintf(buf, buf_size, "%s:%u] %s", file, line, message); 121 android_writeLog(priority, tag, buf); 122 free(buf); 123 } else { 124 android_writeLog(priority, tag, message); 125 } 126#else 127 static constexpr char kLogCharacters[] = { 'V', 'D', 'I', 'W', 'E', 'F', 'F' }; 128 static_assert( 129 arraysize(kLogCharacters) == static_cast<size_t>(::android::base::FATAL) + 1, 130 "Wrong character array size"); 131 132 const char* program_name = ProgramInvocationShortName(); 133 TEMP_FAILURE_RETRY(write(STDERR_FILENO, program_name, strlen(program_name))); 134 TEMP_FAILURE_RETRY(write(STDERR_FILENO, " ", 1)); 135 TEMP_FAILURE_RETRY(write(STDERR_FILENO, &kLogCharacters[static_cast<size_t>(log_severity)], 1)); 136 TEMP_FAILURE_RETRY(write(STDERR_FILENO, " ", 1)); 137 // TODO: pid and tid. 138 TEMP_FAILURE_RETRY(write(STDERR_FILENO, file, strlen(file))); 139 // TODO: line. 140 UNUSED(line); 141 TEMP_FAILURE_RETRY(write(STDERR_FILENO, "] ", 2)); 142 TEMP_FAILURE_RETRY(write(STDERR_FILENO, message, strlen(message))); 143 TEMP_FAILURE_RETRY(write(STDERR_FILENO, "\n", 1)); 144#endif // ART_TARGET_ANDROID 145} 146 147} // namespace art 148