| /* |
| * 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 <trusty_log.h> |
| #include <iostream> |
| #include <string> |
| |
| #include <android-base/strings.h> |
| |
| 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 <typename F, typename... Args> |
| 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 ?: "<unknown>", file, line, message); |
| } |
| |
| bool ShouldLog(LogSeverity /*severity*/, const char* /*tag*/) { |
| // This is controlled by Trusty's log level. |
| return true; |
| } |
| |
| } // namespace base |
| } // namespace android |