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