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-current-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 35 namespace art { 36 37 // We test here that the runtime-debug-checks are actually a no-op constexpr false in release 38 // builds, as we can't check that in gtests (which are always debug). 39 40 #ifdef NDEBUG 41 namespace { 42 DECLARE_RUNTIME_DEBUG_FLAG(kTestForConstexpr); 43 static_assert(!kTestForConstexpr, "Issue with DECLARE_RUNTIME_DEBUG_FLAG in NDEBUG."); 44 } 45 #endif 46 47 // Implementation of runtime debug flags. This should be compile-time optimized away in release 48 // builds. 49 namespace { 50 bool gSlowEnabled = false; // Default for slow flags is "off." 51 52 // Use a function with a static to ensure our vector storage doesn't have initialization order 53 // issues. 54 std::vector<bool*>& GetFlagPtrs() { 55 static std::vector<bool*> g_flag_ptrs; 56 return g_flag_ptrs; 57 } 58 59 bool RegisterRuntimeDebugFlagImpl(bool* flag_ptr) { 60 GetFlagPtrs().push_back(flag_ptr); 61 return gSlowEnabled; 62 } 63 64 void SetRuntimeDebugFlagsEnabledImpl(bool enabled) { 65 gSlowEnabled = enabled; 66 for (bool* flag_ptr : GetFlagPtrs()) { 67 *flag_ptr = enabled; 68 } 69 } 70 71 } // namespace 72 73 bool RegisterRuntimeDebugFlag(bool* flag_ptr) { 74 if (kIsDebugBuild) { 75 return RegisterRuntimeDebugFlagImpl(flag_ptr); 76 } 77 return false; 78 } 79 80 void SetRuntimeDebugFlagsEnabled(bool enabled) { 81 if (kIsDebugBuild) { 82 SetRuntimeDebugFlagsEnabledImpl(enabled); 83 } 84 } 85 86 LogVerbosity gLogVerbosity; 87 88 std::atomic<unsigned int> gAborting(0); 89 90 static std::unique_ptr<std::string> gCmdLine; 91 static std::unique_ptr<std::string> gProgramInvocationName; 92 static std::unique_ptr<std::string> gProgramInvocationShortName; 93 94 const char* GetCmdLine() { 95 return (gCmdLine.get() != nullptr) ? gCmdLine->c_str() : nullptr; 96 } 97 98 const char* ProgramInvocationName() { 99 return (gProgramInvocationName.get() != nullptr) ? gProgramInvocationName->c_str() : "art"; 100 } 101 102 const char* ProgramInvocationShortName() { 103 return (gProgramInvocationShortName.get() != nullptr) ? gProgramInvocationShortName->c_str() 104 : "art"; 105 } 106 107 void InitLogging(char* argv[], AbortFunction& abort_function) { 108 if (gCmdLine.get() != nullptr) { 109 return; 110 } 111 // TODO: Move this to a more obvious InitART... 112 Locks::Init(); 113 114 // Stash the command line for later use. We can use /proc/self/cmdline on Linux to recover this, 115 // but we don't have that luxury on the Mac, and there are a couple of argv[0] variants that are 116 // commonly used. 117 if (argv != nullptr) { 118 gCmdLine.reset(new std::string(argv[0])); 119 for (size_t i = 1; argv[i] != nullptr; ++i) { 120 gCmdLine->append(" "); 121 gCmdLine->append(argv[i]); 122 } 123 gProgramInvocationName.reset(new std::string(argv[0])); 124 const char* last_slash = strrchr(argv[0], '/'); 125 gProgramInvocationShortName.reset(new std::string((last_slash != nullptr) ? last_slash + 1 126 : argv[0])); 127 } else { 128 // TODO: fall back to /proc/self/cmdline when argv is null on Linux. 129 gCmdLine.reset(new std::string("<unset>")); 130 } 131 132 #ifdef ART_TARGET_ANDROID 133 #define INIT_LOGGING_DEFAULT_LOGGER android::base::LogdLogger() 134 #else 135 #define INIT_LOGGING_DEFAULT_LOGGER android::base::StderrLogger 136 #endif 137 android::base::InitLogging(argv, INIT_LOGGING_DEFAULT_LOGGER, 138 std::move<AbortFunction>(abort_function)); 139 #undef INIT_LOGGING_DEFAULT_LOGGER 140 } 141 142 #ifdef ART_TARGET_ANDROID 143 static const android_LogPriority kLogSeverityToAndroidLogPriority[] = { 144 ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, ANDROID_LOG_WARN, 145 ANDROID_LOG_ERROR, ANDROID_LOG_FATAL, ANDROID_LOG_FATAL 146 }; 147 static_assert(arraysize(kLogSeverityToAndroidLogPriority) == ::android::base::FATAL + 1, 148 "Mismatch in size of kLogSeverityToAndroidLogPriority and values in LogSeverity"); 149 #endif 150 151 void LogHelper::LogLineLowStack(const char* file, 152 unsigned int line, 153 LogSeverity log_severity, 154 const char* message) { 155 #ifdef ART_TARGET_ANDROID 156 // Use android_writeLog() to avoid stack-based buffers used by android_printLog(). 157 const char* tag = ProgramInvocationShortName(); 158 int priority = kLogSeverityToAndroidLogPriority[static_cast<size_t>(log_severity)]; 159 char* buf = nullptr; 160 size_t buf_size = 0u; 161 if (priority == ANDROID_LOG_FATAL) { 162 // Allocate buffer for snprintf(buf, buf_size, "%s:%u] %s", file, line, message) below. 163 // If allocation fails, fall back to printing only the message. 164 buf_size = strlen(file) + 1 /* ':' */ + std::numeric_limits<decltype(line)>::max_digits10 + 165 2 /* "] " */ + strlen(message) + 1 /* terminating 0 */; 166 buf = reinterpret_cast<char*>(malloc(buf_size)); 167 } 168 if (buf != nullptr) { 169 snprintf(buf, buf_size, "%s:%u] %s", file, line, message); 170 android_writeLog(priority, tag, buf); 171 free(buf); 172 } else { 173 android_writeLog(priority, tag, message); 174 } 175 #else 176 static constexpr char kLogCharacters[] = { 'V', 'D', 'I', 'W', 'E', 'F', 'F' }; 177 static_assert( 178 arraysize(kLogCharacters) == static_cast<size_t>(::android::base::FATAL) + 1, 179 "Wrong character array size"); 180 181 const char* program_name = ProgramInvocationShortName(); 182 TEMP_FAILURE_RETRY(write(STDERR_FILENO, program_name, strlen(program_name))); 183 TEMP_FAILURE_RETRY(write(STDERR_FILENO, " ", 1)); 184 TEMP_FAILURE_RETRY(write(STDERR_FILENO, &kLogCharacters[static_cast<size_t>(log_severity)], 1)); 185 TEMP_FAILURE_RETRY(write(STDERR_FILENO, " ", 1)); 186 // TODO: pid and tid. 187 TEMP_FAILURE_RETRY(write(STDERR_FILENO, file, strlen(file))); 188 // TODO: line. 189 UNUSED(line); 190 TEMP_FAILURE_RETRY(write(STDERR_FILENO, "] ", 2)); 191 TEMP_FAILURE_RETRY(write(STDERR_FILENO, message, strlen(message))); 192 TEMP_FAILURE_RETRY(write(STDERR_FILENO, "\n", 1)); 193 #endif // ART_TARGET_ANDROID 194 } 195 196 } // namespace art 197