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