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