| // Copyright 2023 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "third_party/jni_zero/logging.h" |
| |
| #include <stdarg.h> |
| #include <stdio.h> |
| #include <atomic> |
| #include <memory> |
| #ifndef JNI_ZERO_IS_ROBOLECTRIC |
| #include <android/log.h> |
| #endif |
| |
| namespace jni_zero { |
| |
| std::atomic<LogMessageCallback> g_log_callback{}; |
| |
| void SetLogMessageCallback(LogMessageCallback callback) { |
| g_log_callback.store(callback, std::memory_order_relaxed); |
| } |
| |
| void LogMessage(LogLev level, |
| const char* fname, |
| int line, |
| const char* fmt, |
| ...) { |
| char stack_buf[512]; |
| std::unique_ptr<char[]> large_buf; |
| char* log_msg = &stack_buf[0]; |
| |
| // By default use a stack allocated buffer because most log messages are quite |
| // short. In rare cases they can be larger (e.g. --help). In those cases we |
| // pay the cost of allocating the buffer on the heap. |
| for (size_t max_len = sizeof(stack_buf);;) { |
| va_list args; |
| va_start(args, fmt); |
| int res = vsnprintf(log_msg, max_len, fmt, args); |
| va_end(args); |
| |
| // If for any reason the print fails, overwrite the message but still print |
| // it. The code below will attach the filename and line, which is still |
| // useful. |
| if (res < 0) { |
| snprintf(log_msg, max_len, "%s", "[printf format error]"); |
| break; |
| } |
| // if res == max_len, vsnprintf saturated the input buffer. Retry with a |
| // larger buffer in that case (within reasonable limits). |
| if (res < static_cast<int>(max_len) || max_len >= 128 * 1024) { |
| break; |
| } |
| |
| max_len *= 4; |
| large_buf.reset(new char[max_len]); |
| log_msg = &large_buf[0]; |
| } |
| |
| LogMessageCallback cb = g_log_callback.load(std::memory_order_relaxed); |
| if (cb) { |
| cb({level, line, fname, log_msg}); |
| return; |
| } |
| |
| #ifdef JNI_ZERO_IS_ROBOLECTRIC |
| fprintf(stderr, "%s:%d %s\n", fname, line, log_msg); |
| #else |
| __android_log_print(int{ANDROID_LOG_DEBUG} + level, "jni_zero", "%s:%d %s", |
| fname, line, log_msg); |
| #endif |
| if (level >= kLogFatal) { |
| JNI_ZERO_IMMEDIATE_CRASH(); |
| } |
| } |
| |
| } // namespace jni_zero |