/* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define TLOG_TAG "libbinder" #include "android-base/logging.h" #include #include #include #include #include namespace android { namespace base { static const char* GetFileBasename(const char* file) { const char* last_slash = strrchr(file, '/'); if (last_slash != nullptr) { return last_slash + 1; } return file; } // This splits the message up line by line, by calling log_function with a pointer to the start of // each line and the size up to the newline character. It sends size = -1 for the final line. template static void SplitByLines(const char* msg, const F& log_function, Args&&... args) { const char* newline; while ((newline = strchr(msg, '\n')) != nullptr) { log_function(msg, newline - msg, args...); msg = newline + 1; } log_function(msg, -1, args...); } void DefaultAborter(const char* abort_message) { TLOGC("aborting: %s\n", abort_message); abort(); } static void TrustyLogLine(const char* msg, int /*length*/, android::base::LogSeverity severity, const char* tag) { switch (severity) { case VERBOSE: case DEBUG: TLOGD("%s: %s\n", tag, msg); break; case INFO: TLOGI("%s: %s\n", tag, msg); break; case WARNING: TLOGW("%s: %s\n", tag, msg); break; case ERROR: TLOGE("%s: %s\n", tag, msg); break; case FATAL_WITHOUT_ABORT: case FATAL: TLOGC("%s: %s\n", tag, msg); break; } } void TrustyLogger(android::base::LogId, android::base::LogSeverity severity, const char* tag, const char*, unsigned int, const char* full_message) { SplitByLines(full_message, TrustyLogLine, severity, tag); } // This indirection greatly reduces the stack impact of having lots of // checks/logging in a function. class LogMessageData { public: LogMessageData(const char* file, unsigned int line, LogSeverity severity, const char* tag, int error) : file_(GetFileBasename(file)), line_number_(line), severity_(severity), tag_(tag), error_(error) {} const char* GetFile() const { return file_; } unsigned int GetLineNumber() const { return line_number_; } LogSeverity GetSeverity() const { return severity_; } const char* GetTag() const { return tag_; } int GetError() const { return error_; } std::ostream& GetBuffer() { return buffer_; } std::string ToString() const { return buffer_.str(); } private: std::ostringstream buffer_; const char* const file_; const unsigned int line_number_; const LogSeverity severity_; const char* const tag_; const int error_; DISALLOW_COPY_AND_ASSIGN(LogMessageData); }; LogMessage::LogMessage(const char* file, unsigned int line, LogId, LogSeverity severity, const char* tag, int error) : LogMessage(file, line, severity, tag, error) {} LogMessage::LogMessage(const char* file, unsigned int line, LogSeverity severity, const char* tag, int error) : data_(new LogMessageData(file, line, severity, tag, error)) {} LogMessage::~LogMessage() { // Check severity again. This is duplicate work wrt/ LOG macros, but not LOG_STREAM. if (!WOULD_LOG(data_->GetSeverity())) { return; } // Finish constructing the message. if (data_->GetError() != -1) { data_->GetBuffer() << ": " << strerror(data_->GetError()); } std::string msg(data_->ToString()); LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetSeverity(), data_->GetTag(), msg.c_str()); // Abort if necessary. if (data_->GetSeverity() == FATAL) { DefaultAborter(msg.c_str()); } } std::ostream& LogMessage::stream() { return data_->GetBuffer(); } void LogMessage::LogLine(const char* file, unsigned int line, LogSeverity severity, const char* tag, const char* message) { TrustyLogger(DEFAULT, severity, tag ?: "", file, line, message); } bool ShouldLog(LogSeverity /*severity*/, const char* /*tag*/) { // This is controlled by Trusty's log level. return true; } } // namespace base } // namespace android