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