1*6777b538SAndroid Build Coastguard Worker // Copyright 2023 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "third_party/jni_zero/logging.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <stdarg.h>
8*6777b538SAndroid Build Coastguard Worker #include <stdio.h>
9*6777b538SAndroid Build Coastguard Worker #include <atomic>
10*6777b538SAndroid Build Coastguard Worker #include <memory>
11*6777b538SAndroid Build Coastguard Worker #ifndef JNI_ZERO_IS_ROBOLECTRIC
12*6777b538SAndroid Build Coastguard Worker #include <android/log.h>
13*6777b538SAndroid Build Coastguard Worker #endif
14*6777b538SAndroid Build Coastguard Worker
15*6777b538SAndroid Build Coastguard Worker namespace jni_zero {
16*6777b538SAndroid Build Coastguard Worker
17*6777b538SAndroid Build Coastguard Worker std::atomic<LogMessageCallback> g_log_callback{};
18*6777b538SAndroid Build Coastguard Worker
SetLogMessageCallback(LogMessageCallback callback)19*6777b538SAndroid Build Coastguard Worker void SetLogMessageCallback(LogMessageCallback callback) {
20*6777b538SAndroid Build Coastguard Worker g_log_callback.store(callback, std::memory_order_relaxed);
21*6777b538SAndroid Build Coastguard Worker }
22*6777b538SAndroid Build Coastguard Worker
LogMessage(LogLev level,const char * fname,int line,const char * fmt,...)23*6777b538SAndroid Build Coastguard Worker void LogMessage(LogLev level,
24*6777b538SAndroid Build Coastguard Worker const char* fname,
25*6777b538SAndroid Build Coastguard Worker int line,
26*6777b538SAndroid Build Coastguard Worker const char* fmt,
27*6777b538SAndroid Build Coastguard Worker ...) {
28*6777b538SAndroid Build Coastguard Worker char stack_buf[512];
29*6777b538SAndroid Build Coastguard Worker std::unique_ptr<char[]> large_buf;
30*6777b538SAndroid Build Coastguard Worker char* log_msg = &stack_buf[0];
31*6777b538SAndroid Build Coastguard Worker
32*6777b538SAndroid Build Coastguard Worker // By default use a stack allocated buffer because most log messages are quite
33*6777b538SAndroid Build Coastguard Worker // short. In rare cases they can be larger (e.g. --help). In those cases we
34*6777b538SAndroid Build Coastguard Worker // pay the cost of allocating the buffer on the heap.
35*6777b538SAndroid Build Coastguard Worker for (size_t max_len = sizeof(stack_buf);;) {
36*6777b538SAndroid Build Coastguard Worker va_list args;
37*6777b538SAndroid Build Coastguard Worker va_start(args, fmt);
38*6777b538SAndroid Build Coastguard Worker int res = vsnprintf(log_msg, max_len, fmt, args);
39*6777b538SAndroid Build Coastguard Worker va_end(args);
40*6777b538SAndroid Build Coastguard Worker
41*6777b538SAndroid Build Coastguard Worker // If for any reason the print fails, overwrite the message but still print
42*6777b538SAndroid Build Coastguard Worker // it. The code below will attach the filename and line, which is still
43*6777b538SAndroid Build Coastguard Worker // useful.
44*6777b538SAndroid Build Coastguard Worker if (res < 0) {
45*6777b538SAndroid Build Coastguard Worker snprintf(log_msg, max_len, "%s", "[printf format error]");
46*6777b538SAndroid Build Coastguard Worker break;
47*6777b538SAndroid Build Coastguard Worker }
48*6777b538SAndroid Build Coastguard Worker // if res == max_len, vsnprintf saturated the input buffer. Retry with a
49*6777b538SAndroid Build Coastguard Worker // larger buffer in that case (within reasonable limits).
50*6777b538SAndroid Build Coastguard Worker if (res < static_cast<int>(max_len) || max_len >= 128 * 1024) {
51*6777b538SAndroid Build Coastguard Worker break;
52*6777b538SAndroid Build Coastguard Worker }
53*6777b538SAndroid Build Coastguard Worker
54*6777b538SAndroid Build Coastguard Worker max_len *= 4;
55*6777b538SAndroid Build Coastguard Worker large_buf.reset(new char[max_len]);
56*6777b538SAndroid Build Coastguard Worker log_msg = &large_buf[0];
57*6777b538SAndroid Build Coastguard Worker }
58*6777b538SAndroid Build Coastguard Worker
59*6777b538SAndroid Build Coastguard Worker LogMessageCallback cb = g_log_callback.load(std::memory_order_relaxed);
60*6777b538SAndroid Build Coastguard Worker if (cb) {
61*6777b538SAndroid Build Coastguard Worker cb({level, line, fname, log_msg});
62*6777b538SAndroid Build Coastguard Worker return;
63*6777b538SAndroid Build Coastguard Worker }
64*6777b538SAndroid Build Coastguard Worker
65*6777b538SAndroid Build Coastguard Worker #ifdef JNI_ZERO_IS_ROBOLECTRIC
66*6777b538SAndroid Build Coastguard Worker fprintf(stderr, "%s:%d %s\n", fname, line, log_msg);
67*6777b538SAndroid Build Coastguard Worker #else
68*6777b538SAndroid Build Coastguard Worker __android_log_print(int{ANDROID_LOG_DEBUG} + level, "jni_zero", "%s:%d %s",
69*6777b538SAndroid Build Coastguard Worker fname, line, log_msg);
70*6777b538SAndroid Build Coastguard Worker #endif
71*6777b538SAndroid Build Coastguard Worker if (level >= kLogFatal) {
72*6777b538SAndroid Build Coastguard Worker JNI_ZERO_IMMEDIATE_CRASH();
73*6777b538SAndroid Build Coastguard Worker }
74*6777b538SAndroid Build Coastguard Worker }
75*6777b538SAndroid Build Coastguard Worker
76*6777b538SAndroid Build Coastguard Worker } // namespace jni_zero
77