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