xref: /aosp_15_r20/system/chre/platform/shared/log_buffer_manager.cc (revision 84e339476a462649f82315436d70fd732297a399)
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "chre/platform/shared/log_buffer_manager.h"
18 
19 #include "chre/core/event_loop_manager.h"
20 #include "chre/platform/assert.h"
21 #include "chre/platform/shared/bt_snoop_log.h"
22 #include "chre/platform/shared/generated/host_messages_generated.h"
23 #include "chre/util/lock_guard.h"
24 
25 #ifdef CHRE_TOKENIZED_LOGGING_ENABLED
26 #include "chre/platform/log.h"
27 #include "pw_log_tokenized/config.h"
28 #include "pw_tokenizer/encode_args.h"
29 #include "pw_tokenizer/tokenize.h"
30 #endif  // CHRE_TOKENIZED_LOGGING_ENABLED
31 
chrePlatformLogToBuffer(chreLogLevel chreLogLevel,const char * format,...)32 void chrePlatformLogToBuffer(chreLogLevel chreLogLevel, const char *format,
33                              ...) {
34   va_list args;
35   va_start(args, format);
36   if (chre::LogBufferManagerSingleton::isInitialized()) {
37     chre::LogBufferManagerSingleton::get()->logVa(chreLogLevel, format, args);
38   }
39   va_end(args);
40 }
41 
chrePlatformEncodedLogToBuffer(chreLogLevel level,const uint8_t * msg,size_t msgSize)42 void chrePlatformEncodedLogToBuffer(chreLogLevel level, const uint8_t *msg,
43                                     size_t msgSize) {
44   if (chre::LogBufferManagerSingleton::isInitialized()) {
45     chre::LogBufferManagerSingleton::get()->logEncoded(level, msg, msgSize);
46   }
47 }
48 
chrePlatformBtSnoopLog(BtSnoopDirection direction,const uint8_t * buffer,size_t size)49 void chrePlatformBtSnoopLog(BtSnoopDirection direction, const uint8_t *buffer,
50                             size_t size) {
51   chre::LogBufferManagerSingleton::get()->logBtSnoop(direction, buffer, size);
52 }
53 
54 #ifdef CHRE_TOKENIZED_LOGGING_ENABLED
55 // The callback function that must be defined to handle an encoded
56 // tokenizer message.
EncodeTokenizedMessage(uint32_t level,pw_tokenizer_Token token,pw_tokenizer_ArgTypes types,...)57 void EncodeTokenizedMessage(uint32_t level, pw_tokenizer_Token token,
58                             pw_tokenizer_ArgTypes types, ...) {
59   va_list args;
60   va_start(args, types);
61   pw::tokenizer::EncodedMessage<pw::log_tokenized::kEncodingBufferSizeBytes>
62       encodedMessage(token, types, args);
63   va_end(args);
64 
65   chrePlatformEncodedLogToBuffer(static_cast<chreLogLevel>(level),
66                                  encodedMessage.data_as_uint8(),
67                                  encodedMessage.size());
68 }
69 #endif  // CHRE_TOKENIZED_LOGGING_ENABLED
70 
71 namespace chre {
72 
73 using LogType = fbs::LogType;
74 
onLogsReady()75 void LogBufferManager::onLogsReady() {
76   LockGuard<Mutex> lockGuard(mFlushLogsMutex);
77   if (!mLogFlushToHostPending) {
78     if (EventLoopManagerSingleton::isInitialized() &&
79         EventLoopManagerSingleton::get()
80             ->getEventLoop()
81             .getPowerControlManager()
82             .hostIsAwake()) {
83       mLogFlushToHostPending = true;
84       mSendLogsToHostCondition.notify_one();
85     }
86   } else {
87     mLogsBecameReadyWhileFlushPending = true;
88   }
89 }
90 
flushLogs()91 void LogBufferManager::flushLogs() {
92   onLogsReady();
93 }
94 
onLogsSentToHost(bool success)95 void LogBufferManager::onLogsSentToHost(bool success) {
96   LockGuard<Mutex> lockGuard(mFlushLogsMutex);
97   onLogsSentToHostLocked(success);
98 }
99 
startSendLogsToHostLoop()100 void LogBufferManager::startSendLogsToHostLoop() {
101   LockGuard<Mutex> lockGuard(mFlushLogsMutex);
102   // TODO(b/181871430): Allow this loop to exit for certain platforms
103   while (true) {
104     while (!mLogFlushToHostPending) {
105       mSendLogsToHostCondition.wait(mFlushLogsMutex);
106     }
107     bool logWasSent = false;
108     if (EventLoopManagerSingleton::get()
109             ->getEventLoop()
110             .getPowerControlManager()
111             .hostIsAwake()) {
112       auto &hostCommsMgr =
113           EventLoopManagerSingleton::get()->getHostCommsManager();
114       preSecondaryBufferUse();
115       if (mSecondaryLogBuffer.getBufferSize() == 0) {
116         // TODO (b/184178045): Transfer logs into the secondary buffer from
117         // primary if there is room.
118         mPrimaryLogBuffer.transferTo(mSecondaryLogBuffer);
119       }
120       // If the primary buffer was not flushed to the secondary buffer then set
121       // the flag that will cause sendLogsToHost to be run again after
122       // onLogsSentToHost has been called and the secondary buffer has been
123       // cleared out.
124       if (mPrimaryLogBuffer.getBufferSize() > 0) {
125         mLogsBecameReadyWhileFlushPending = true;
126       }
127       if (mSecondaryLogBuffer.getBufferSize() > 0) {
128         mNumLogsDroppedTotal += mSecondaryLogBuffer.getNumLogsDropped();
129         mFlushLogsMutex.unlock();
130         hostCommsMgr.sendLogMessageV2(mSecondaryLogBuffer.getBufferData(),
131                                       mSecondaryLogBuffer.getBufferSize(),
132                                       mNumLogsDroppedTotal);
133         logWasSent = true;
134         mFlushLogsMutex.lock();
135       }
136     }
137     if (!logWasSent) {
138       onLogsSentToHostLocked(false);
139     }
140   }
141 }
142 
log(chreLogLevel logLevel,const char * formatStr,...)143 void LogBufferManager::log(chreLogLevel logLevel, const char *formatStr, ...) {
144   va_list args;
145   va_start(args, formatStr);
146   logVa(logLevel, formatStr, args);
147   va_end(args);
148 }
149 
getTimestampMs()150 uint32_t LogBufferManager::getTimestampMs() {
151   uint64_t timeNs = SystemTime::getMonotonicTime().toRawNanoseconds();
152   return static_cast<uint32_t>(timeNs / kOneMillisecondInNanoseconds);
153 }
154 
bufferOverflowGuard(size_t logSize,LogType type)155 void LogBufferManager::bufferOverflowGuard(size_t logSize, LogType type) {
156   switch (type) {
157     case LogType::STRING:
158       logSize += LogBuffer::kStringLogOverhead;
159       break;
160     case LogType::TOKENIZED:
161       logSize += LogBuffer::kTokenizedLogOffset;
162       break;
163     case LogType::BLUETOOTH:
164       logSize += LogBuffer::kBtSnoopLogOffset;
165       break;
166     case LogType::NANOAPP_TOKENIZED:
167       logSize += LogBuffer::kNanoappTokenizedLogOffset;
168       break;
169     default:
170       CHRE_ASSERT_LOG(false, "Received unexpected log message type");
171       break;
172   }
173   if (mPrimaryLogBuffer.logWouldCauseOverflow(logSize)) {
174     LockGuard<Mutex> lockGuard(mFlushLogsMutex);
175     if (!mLogFlushToHostPending) {
176       preSecondaryBufferUse();
177       mPrimaryLogBuffer.transferTo(mSecondaryLogBuffer);
178     }
179   }
180 }
181 
logVa(chreLogLevel logLevel,const char * formatStr,va_list args)182 void LogBufferManager::logVa(chreLogLevel logLevel, const char *formatStr,
183                              va_list args) {
184   // Copy the va_list before getting size from vsnprintf so that the next
185   // argument that will be accessed in buffer.handleLogVa is the starting one.
186   va_list getSizeArgs;
187   va_copy(getSizeArgs, args);
188   size_t logSize = vsnprintf(nullptr, 0, formatStr, getSizeArgs);
189   va_end(getSizeArgs);
190   bufferOverflowGuard(logSize, LogType::STRING);
191   mPrimaryLogBuffer.handleLogVa(chreToLogBufferLogLevel(logLevel),
192                                 getTimestampMs(), formatStr, args);
193 }
194 
logBtSnoop(BtSnoopDirection direction,const uint8_t * buffer,size_t size)195 void LogBufferManager::logBtSnoop(BtSnoopDirection direction,
196                                   const uint8_t *buffer, size_t size) {
197 #ifdef CHRE_BLE_SUPPORT_ENABLED
198   bufferOverflowGuard(size, LogType::BLUETOOTH);
199   mPrimaryLogBuffer.handleBtLog(direction, getTimestampMs(), buffer, size);
200 #else
201   UNUSED_VAR(direction);
202   UNUSED_VAR(buffer);
203   UNUSED_VAR(size);
204 #endif  // CHRE_BLE_SUPPORT_ENABLED
205 }
206 
logEncoded(chreLogLevel logLevel,const uint8_t * encodedLog,size_t encodedLogSize)207 void LogBufferManager::logEncoded(chreLogLevel logLevel,
208                                   const uint8_t *encodedLog,
209                                   size_t encodedLogSize) {
210   bufferOverflowGuard(encodedLogSize, LogType::TOKENIZED);
211   mPrimaryLogBuffer.handleEncodedLog(chreToLogBufferLogLevel(logLevel),
212                                      getTimestampMs(), encodedLog,
213                                      encodedLogSize);
214 }
215 
logNanoappTokenized(chreLogLevel logLevel,uint16_t instanceId,const uint8_t * msg,size_t msgSize)216 void LogBufferManager::logNanoappTokenized(chreLogLevel logLevel,
217                                            uint16_t instanceId,
218                                            const uint8_t *msg, size_t msgSize) {
219   bufferOverflowGuard(msgSize, LogType::NANOAPP_TOKENIZED);
220   mPrimaryLogBuffer.handleNanoappTokenizedLog(chreToLogBufferLogLevel(logLevel),
221                                               getTimestampMs(), instanceId, msg,
222                                               msgSize);
223 }
224 
chreToLogBufferLogLevel(chreLogLevel chreLogLevel)225 LogBufferLogLevel LogBufferManager::chreToLogBufferLogLevel(
226     chreLogLevel chreLogLevel) {
227   switch (chreLogLevel) {
228     case CHRE_LOG_ERROR:
229       return LogBufferLogLevel::ERROR;
230     case CHRE_LOG_WARN:
231       return LogBufferLogLevel::WARN;
232     case CHRE_LOG_INFO:
233       return LogBufferLogLevel::INFO;
234     default:  // CHRE_LOG_DEBUG
235       return LogBufferLogLevel::DEBUG;
236   }
237 }
238 
onLogsSentToHostLocked(bool success)239 void LogBufferManager::onLogsSentToHostLocked(bool success) {
240   if (success) {
241     mSecondaryLogBuffer.reset();
242   }
243   // If there is a failure to send a log through do not try to send another
244   // one to avoid an infinite loop occurring
245   mLogFlushToHostPending = mLogsBecameReadyWhileFlushPending && success;
246   mLogsBecameReadyWhileFlushPending = false;
247   if (mLogFlushToHostPending) {
248     mSendLogsToHostCondition.notify_one();
249   }
250 }
251 
252 //! Explicitly instantiate the EventLoopManagerSingleton to reduce codesize.
253 template class Singleton<LogBufferManager>;
254 
255 }  // namespace chre
256