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 
chrePlatformLogToBuffer(chreLogLevel chreLogLevel,const char * format,...)25 void chrePlatformLogToBuffer(chreLogLevel chreLogLevel, const char *format,
26                              ...) {
27   va_list args;
28   va_start(args, format);
29   if (chre::LogBufferManagerSingleton::isInitialized()) {
30     chre::LogBufferManagerSingleton::get()->logVa(chreLogLevel, format, args);
31   }
32   va_end(args);
33 }
34 
chrePlatformEncodedLogToBuffer(chreLogLevel level,const uint8_t * msg,size_t msgSize)35 void chrePlatformEncodedLogToBuffer(chreLogLevel level, const uint8_t *msg,
36                                     size_t msgSize) {
37   if (chre::LogBufferManagerSingleton::isInitialized()) {
38     chre::LogBufferManagerSingleton::get()->logEncoded(level, msg, msgSize);
39   }
40 }
41 
chrePlatformBtSnoopLog(BtSnoopDirection direction,const uint8_t * buffer,size_t size)42 void chrePlatformBtSnoopLog(BtSnoopDirection direction, const uint8_t *buffer,
43                             size_t size) {
44   chre::LogBufferManagerSingleton::get()->logBtSnoop(direction, buffer, size);
45 }
46 
47 namespace chre {
48 
49 using LogType = fbs::LogType;
50 
onLogsReady()51 void LogBufferManager::onLogsReady() {
52   LockGuard<Mutex> lockGuard(mFlushLogsMutex);
53   if (!mLogFlushToHostPending) {
54     if (EventLoopManagerSingleton::isInitialized() &&
55         EventLoopManagerSingleton::get()
56             ->getEventLoop()
57             .getPowerControlManager()
58             .hostIsAwake()) {
59       mLogFlushToHostPending = true;
60       mSendLogsToHostCondition.notify_one();
61     }
62   } else {
63     mLogsBecameReadyWhileFlushPending = true;
64   }
65 }
66 
flushLogs()67 void LogBufferManager::flushLogs() {
68   onLogsReady();
69 }
70 
onLogsSentToHost(bool success)71 void LogBufferManager::onLogsSentToHost(bool success) {
72   LockGuard<Mutex> lockGuard(mFlushLogsMutex);
73   onLogsSentToHostLocked(success);
74 }
75 
startSendLogsToHostLoop()76 void LogBufferManager::startSendLogsToHostLoop() {
77   LockGuard<Mutex> lockGuard(mFlushLogsMutex);
78   // TODO(b/181871430): Allow this loop to exit for certain platforms
79   while (true) {
80     while (!mLogFlushToHostPending) {
81       mSendLogsToHostCondition.wait(mFlushLogsMutex);
82     }
83     bool logWasSent = false;
84     if (EventLoopManagerSingleton::get()
85             ->getEventLoop()
86             .getPowerControlManager()
87             .hostIsAwake()) {
88       auto &hostCommsMgr =
89           EventLoopManagerSingleton::get()->getHostCommsManager();
90       preSecondaryBufferUse();
91       if (mSecondaryLogBuffer.getBufferSize() == 0) {
92         // TODO (b/184178045): Transfer logs into the secondary buffer from
93         // primary if there is room.
94         mPrimaryLogBuffer.transferTo(mSecondaryLogBuffer);
95       }
96       // If the primary buffer was not flushed to the secondary buffer then set
97       // the flag that will cause sendLogsToHost to be run again after
98       // onLogsSentToHost has been called and the secondary buffer has been
99       // cleared out.
100       if (mPrimaryLogBuffer.getBufferSize() > 0) {
101         mLogsBecameReadyWhileFlushPending = true;
102       }
103       if (mSecondaryLogBuffer.getBufferSize() > 0) {
104         mNumLogsDroppedTotal += mSecondaryLogBuffer.getNumLogsDropped();
105         mFlushLogsMutex.unlock();
106         hostCommsMgr.sendLogMessageV2(mSecondaryLogBuffer.getBufferData(),
107                                       mSecondaryLogBuffer.getBufferSize(),
108                                       mNumLogsDroppedTotal);
109         logWasSent = true;
110         mFlushLogsMutex.lock();
111       }
112     }
113     if (!logWasSent) {
114       onLogsSentToHostLocked(false);
115     }
116   }
117 }
118 
log(chreLogLevel logLevel,const char * formatStr,...)119 void LogBufferManager::log(chreLogLevel logLevel, const char *formatStr, ...) {
120   va_list args;
121   va_start(args, formatStr);
122   logVa(logLevel, formatStr, args);
123   va_end(args);
124 }
125 
getTimestampMs()126 uint32_t LogBufferManager::getTimestampMs() {
127   uint64_t timeNs = SystemTime::getMonotonicTime().toRawNanoseconds();
128   return static_cast<uint32_t>(timeNs / kOneMillisecondInNanoseconds);
129 }
130 
bufferOverflowGuard(size_t logSize,LogType type)131 void LogBufferManager::bufferOverflowGuard(size_t logSize, LogType type) {
132   switch (type) {
133     case LogType::STRING:
134       logSize += LogBuffer::kStringLogOverhead;
135       break;
136     case LogType::TOKENIZED:
137       logSize += LogBuffer::kTokenizedLogOffset;
138       break;
139     case LogType::BLUETOOTH:
140       logSize += LogBuffer::kBtSnoopLogOffset;
141       break;
142     case LogType::NANOAPP_TOKENIZED:
143       logSize += LogBuffer::kNanoappTokenizedLogOffset;
144       break;
145     default:
146       CHRE_ASSERT_LOG(false, "Received unexpected log message type");
147       break;
148   }
149   if (mPrimaryLogBuffer.logWouldCauseOverflow(logSize)) {
150     LockGuard<Mutex> lockGuard(mFlushLogsMutex);
151     if (!mLogFlushToHostPending) {
152       preSecondaryBufferUse();
153       mPrimaryLogBuffer.transferTo(mSecondaryLogBuffer);
154     }
155   }
156 }
157 
logVa(chreLogLevel logLevel,const char * formatStr,va_list args)158 void LogBufferManager::logVa(chreLogLevel logLevel, const char *formatStr,
159                              va_list args) {
160   // Copy the va_list before getting size from vsnprintf so that the next
161   // argument that will be accessed in buffer.handleLogVa is the starting one.
162   va_list getSizeArgs;
163   va_copy(getSizeArgs, args);
164   size_t logSize = vsnprintf(nullptr, 0, formatStr, getSizeArgs);
165   va_end(getSizeArgs);
166   bufferOverflowGuard(logSize, LogType::STRING);
167   mPrimaryLogBuffer.handleLogVa(chreToLogBufferLogLevel(logLevel),
168                                 getTimestampMs(), formatStr, args);
169 }
170 
logBtSnoop(BtSnoopDirection direction,const uint8_t * buffer,size_t size)171 void LogBufferManager::logBtSnoop(BtSnoopDirection direction,
172                                   const uint8_t *buffer, size_t size) {
173 #ifdef CHRE_BLE_SUPPORT_ENABLED
174   bufferOverflowGuard(size, LogType::BLUETOOTH);
175   mPrimaryLogBuffer.handleBtLog(direction, getTimestampMs(), buffer, size);
176 #else
177   UNUSED_VAR(direction);
178   UNUSED_VAR(buffer);
179   UNUSED_VAR(size);
180 #endif  // CHRE_BLE_SUPPORT_ENABLED
181 }
182 
logEncoded(chreLogLevel logLevel,const uint8_t * encodedLog,size_t encodedLogSize)183 void LogBufferManager::logEncoded(chreLogLevel logLevel,
184                                   const uint8_t *encodedLog,
185                                   size_t encodedLogSize) {
186   bufferOverflowGuard(encodedLogSize, LogType::TOKENIZED);
187   mPrimaryLogBuffer.handleEncodedLog(chreToLogBufferLogLevel(logLevel),
188                                      getTimestampMs(), encodedLog,
189                                      encodedLogSize);
190 }
191 
logNanoappTokenized(chreLogLevel logLevel,uint16_t instanceId,const uint8_t * msg,size_t msgSize)192 void LogBufferManager::logNanoappTokenized(chreLogLevel logLevel,
193                                            uint16_t instanceId,
194                                            const uint8_t *msg, size_t msgSize) {
195   bufferOverflowGuard(msgSize, LogType::NANOAPP_TOKENIZED);
196   mPrimaryLogBuffer.handleNanoappTokenizedLog(chreToLogBufferLogLevel(logLevel),
197                                               getTimestampMs(), instanceId, msg,
198                                               msgSize);
199 }
200 
chreToLogBufferLogLevel(chreLogLevel chreLogLevel)201 LogBufferLogLevel LogBufferManager::chreToLogBufferLogLevel(
202     chreLogLevel chreLogLevel) {
203   switch (chreLogLevel) {
204     case CHRE_LOG_ERROR:
205       return LogBufferLogLevel::ERROR;
206     case CHRE_LOG_WARN:
207       return LogBufferLogLevel::WARN;
208     case CHRE_LOG_INFO:
209       return LogBufferLogLevel::INFO;
210     default:  // CHRE_LOG_DEBUG
211       return LogBufferLogLevel::DEBUG;
212   }
213 }
214 
onLogsSentToHostLocked(bool success)215 void LogBufferManager::onLogsSentToHostLocked(bool success) {
216   if (success) {
217     mSecondaryLogBuffer.reset();
218   }
219   // If there is a failure to send a log through do not try to send another
220   // one to avoid an infinite loop occurring
221   mLogFlushToHostPending = mLogsBecameReadyWhileFlushPending && success;
222   mLogsBecameReadyWhileFlushPending = false;
223   if (mLogFlushToHostPending) {
224     mSendLogsToHostCondition.notify_one();
225   }
226 }
227 
228 //! Explicitly instantiate the EventLoopManagerSingleton to reduce codesize.
229 template class Singleton<LogBufferManager>;
230 
231 }  // namespace chre
232