xref: /aosp_15_r20/system/chre/host/common/log_message_parser.cc (revision 84e339476a462649f82315436d70fd732297a399)
1*84e33947SAndroid Build Coastguard Worker /*
2*84e33947SAndroid Build Coastguard Worker  * Copyright (C) 2020 The Android Open Source Project
3*84e33947SAndroid Build Coastguard Worker  *
4*84e33947SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*84e33947SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*84e33947SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*84e33947SAndroid Build Coastguard Worker  *
8*84e33947SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*84e33947SAndroid Build Coastguard Worker  *
10*84e33947SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*84e33947SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*84e33947SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*84e33947SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*84e33947SAndroid Build Coastguard Worker  * limitations under the License.
15*84e33947SAndroid Build Coastguard Worker  */
16*84e33947SAndroid Build Coastguard Worker 
17*84e33947SAndroid Build Coastguard Worker #include "chre_host/log_message_parser.h"
18*84e33947SAndroid Build Coastguard Worker 
19*84e33947SAndroid Build Coastguard Worker #include <endian.h>
20*84e33947SAndroid Build Coastguard Worker #include <string.h>
21*84e33947SAndroid Build Coastguard Worker #include <optional>
22*84e33947SAndroid Build Coastguard Worker 
23*84e33947SAndroid Build Coastguard Worker #include "chre/util/macros.h"
24*84e33947SAndroid Build Coastguard Worker #include "chre/util/time.h"
25*84e33947SAndroid Build Coastguard Worker #include "chre_host/daemon_base.h"
26*84e33947SAndroid Build Coastguard Worker #include "chre_host/file_stream.h"
27*84e33947SAndroid Build Coastguard Worker #include "chre_host/log.h"
28*84e33947SAndroid Build Coastguard Worker #include "include/chre_host/log_message_parser.h"
29*84e33947SAndroid Build Coastguard Worker 
30*84e33947SAndroid Build Coastguard Worker #include "pw_result/result.h"
31*84e33947SAndroid Build Coastguard Worker #include "pw_span/span.h"
32*84e33947SAndroid Build Coastguard Worker #include "pw_tokenizer/detokenize.h"
33*84e33947SAndroid Build Coastguard Worker 
34*84e33947SAndroid Build Coastguard Worker using chre::kOneMillisecondInNanoseconds;
35*84e33947SAndroid Build Coastguard Worker using chre::kOneSecondInMilliseconds;
36*84e33947SAndroid Build Coastguard Worker using chre::fbs::LogType;
37*84e33947SAndroid Build Coastguard Worker 
38*84e33947SAndroid Build Coastguard Worker namespace android {
39*84e33947SAndroid Build Coastguard Worker namespace chre {
40*84e33947SAndroid Build Coastguard Worker 
41*84e33947SAndroid Build Coastguard Worker namespace {
42*84e33947SAndroid Build Coastguard Worker #if defined(LOG_NDEBUG) || LOG_NDEBUG != 0
43*84e33947SAndroid Build Coastguard Worker constexpr bool kVerboseLoggingEnabled = true;
44*84e33947SAndroid Build Coastguard Worker #else
45*84e33947SAndroid Build Coastguard Worker constexpr bool kVerboseLoggingEnabled = false;
46*84e33947SAndroid Build Coastguard Worker #endif
47*84e33947SAndroid Build Coastguard Worker 
48*84e33947SAndroid Build Coastguard Worker //! Offset in bytes between the address and real start of a nanoapp binary.
49*84e33947SAndroid Build Coastguard Worker constexpr size_t kImageHeaderSize = 0x1000;
50*84e33947SAndroid Build Coastguard Worker //! The number of bytes in a string log entry in addition to the log payload.
51*84e33947SAndroid Build Coastguard Worker //! The value indicate the size of the null terminator.
52*84e33947SAndroid Build Coastguard Worker constexpr size_t kStringLogOverhead = 1;
53*84e33947SAndroid Build Coastguard Worker //! The number of bytes in a tokenized log entry in addition to the log payload.
54*84e33947SAndroid Build Coastguard Worker //! The value indicate the size of the uint8_t logSize field.
55*84e33947SAndroid Build Coastguard Worker constexpr size_t kSystemTokenizedLogOffset = 1;
56*84e33947SAndroid Build Coastguard Worker //! The number of bytes in a nanoapp tokenized log entry in addition to the log
57*84e33947SAndroid Build Coastguard Worker //! payload. The value accounts for the size of the uint8_t logSize field and
58*84e33947SAndroid Build Coastguard Worker //! the uint16_t instanceId field.
59*84e33947SAndroid Build Coastguard Worker constexpr size_t kNanoappTokenizedLogOffset = 3;
60*84e33947SAndroid Build Coastguard Worker //! This value is used to indicate that a nanoapp does not have a token database
61*84e33947SAndroid Build Coastguard Worker //! section.
62*84e33947SAndroid Build Coastguard Worker constexpr uint32_t kInvalidTokenDatabaseSize = 0;
63*84e33947SAndroid Build Coastguard Worker }  // anonymous namespace
64*84e33947SAndroid Build Coastguard Worker 
LogMessageParser()65*84e33947SAndroid Build Coastguard Worker LogMessageParser::LogMessageParser()
66*84e33947SAndroid Build Coastguard Worker     : mVerboseLoggingEnabled(kVerboseLoggingEnabled) {}
67*84e33947SAndroid Build Coastguard Worker 
logDetokenizerInit()68*84e33947SAndroid Build Coastguard Worker std::unique_ptr<Detokenizer> LogMessageParser::logDetokenizerInit() {
69*84e33947SAndroid Build Coastguard Worker #ifdef CHRE_TOKENIZED_LOGGING_ENABLED
70*84e33947SAndroid Build Coastguard Worker   constexpr const char kLogDatabaseFilePath[] =
71*84e33947SAndroid Build Coastguard Worker       "/vendor/etc/chre/libchre_log_database.bin";
72*84e33947SAndroid Build Coastguard Worker   std::vector<uint8_t> tokenData;
73*84e33947SAndroid Build Coastguard Worker   if (readFileContents(kLogDatabaseFilePath, tokenData)) {
74*84e33947SAndroid Build Coastguard Worker     pw::tokenizer::TokenDatabase database =
75*84e33947SAndroid Build Coastguard Worker         pw::tokenizer::TokenDatabase::Create(tokenData);
76*84e33947SAndroid Build Coastguard Worker     if (database.ok()) {
77*84e33947SAndroid Build Coastguard Worker       LOGD("Log database initialized, creating detokenizer");
78*84e33947SAndroid Build Coastguard Worker       return std::make_unique<Detokenizer>(database);
79*84e33947SAndroid Build Coastguard Worker     } else {
80*84e33947SAndroid Build Coastguard Worker       LOGE("CHRE Token database creation not OK");
81*84e33947SAndroid Build Coastguard Worker     }
82*84e33947SAndroid Build Coastguard Worker   } else {
83*84e33947SAndroid Build Coastguard Worker     LOGE("Failed to read CHRE Token database file");
84*84e33947SAndroid Build Coastguard Worker   }
85*84e33947SAndroid Build Coastguard Worker #endif
86*84e33947SAndroid Build Coastguard Worker   return std::unique_ptr<Detokenizer>(nullptr);
87*84e33947SAndroid Build Coastguard Worker }
88*84e33947SAndroid Build Coastguard Worker 
init(size_t nanoappImageHeaderSize)89*84e33947SAndroid Build Coastguard Worker void LogMessageParser::init(size_t nanoappImageHeaderSize) {
90*84e33947SAndroid Build Coastguard Worker   mSystemDetokenizer = logDetokenizerInit();
91*84e33947SAndroid Build Coastguard Worker   mNanoappImageHeaderSize = nanoappImageHeaderSize;
92*84e33947SAndroid Build Coastguard Worker }
93*84e33947SAndroid Build Coastguard Worker 
dump(const uint8_t * buffer,size_t size)94*84e33947SAndroid Build Coastguard Worker void LogMessageParser::dump(const uint8_t *buffer, size_t size) {
95*84e33947SAndroid Build Coastguard Worker   if (mVerboseLoggingEnabled) {
96*84e33947SAndroid Build Coastguard Worker     char line[32];
97*84e33947SAndroid Build Coastguard Worker     char lineChars[32];
98*84e33947SAndroid Build Coastguard Worker     int offset = 0;
99*84e33947SAndroid Build Coastguard Worker     int offsetChars = 0;
100*84e33947SAndroid Build Coastguard Worker 
101*84e33947SAndroid Build Coastguard Worker     size_t orig_size = size;
102*84e33947SAndroid Build Coastguard Worker     if (size > 128) {
103*84e33947SAndroid Build Coastguard Worker       size = 128;
104*84e33947SAndroid Build Coastguard Worker       LOGV("Dumping first 128 bytes of buffer of size %zu", orig_size);
105*84e33947SAndroid Build Coastguard Worker     } else {
106*84e33947SAndroid Build Coastguard Worker       LOGV("Dumping buffer of size %zu bytes", size);
107*84e33947SAndroid Build Coastguard Worker     }
108*84e33947SAndroid Build Coastguard Worker     for (size_t i = 1; i <= size; ++i) {
109*84e33947SAndroid Build Coastguard Worker       offset += snprintf(&line[offset], sizeof(line) - offset, "%02x ",
110*84e33947SAndroid Build Coastguard Worker                          buffer[i - 1]);
111*84e33947SAndroid Build Coastguard Worker       offsetChars +=
112*84e33947SAndroid Build Coastguard Worker           snprintf(&lineChars[offsetChars], sizeof(lineChars) - offsetChars,
113*84e33947SAndroid Build Coastguard Worker                    "%c", (isprint(buffer[i - 1])) ? buffer[i - 1] : '.');
114*84e33947SAndroid Build Coastguard Worker       if ((i % 8) == 0) {
115*84e33947SAndroid Build Coastguard Worker         LOGV("  %s\t%s", line, lineChars);
116*84e33947SAndroid Build Coastguard Worker         offset = 0;
117*84e33947SAndroid Build Coastguard Worker         offsetChars = 0;
118*84e33947SAndroid Build Coastguard Worker       } else if ((i % 4) == 0) {
119*84e33947SAndroid Build Coastguard Worker         offset += snprintf(&line[offset], sizeof(line) - offset, " ");
120*84e33947SAndroid Build Coastguard Worker       }
121*84e33947SAndroid Build Coastguard Worker     }
122*84e33947SAndroid Build Coastguard Worker 
123*84e33947SAndroid Build Coastguard Worker     if (offset > 0) {
124*84e33947SAndroid Build Coastguard Worker       char tabs[8];
125*84e33947SAndroid Build Coastguard Worker       char *pos = tabs;
126*84e33947SAndroid Build Coastguard Worker       while (offset < 28) {
127*84e33947SAndroid Build Coastguard Worker         *pos++ = '\t';
128*84e33947SAndroid Build Coastguard Worker         offset += 8;
129*84e33947SAndroid Build Coastguard Worker       }
130*84e33947SAndroid Build Coastguard Worker       *pos = '\0';
131*84e33947SAndroid Build Coastguard Worker       LOGV("  %s%s%s", line, tabs, lineChars);
132*84e33947SAndroid Build Coastguard Worker     }
133*84e33947SAndroid Build Coastguard Worker   }
134*84e33947SAndroid Build Coastguard Worker }
135*84e33947SAndroid Build Coastguard Worker 
chreLogLevelToAndroidLogPriority(uint8_t level)136*84e33947SAndroid Build Coastguard Worker android_LogPriority LogMessageParser::chreLogLevelToAndroidLogPriority(
137*84e33947SAndroid Build Coastguard Worker     uint8_t level) {
138*84e33947SAndroid Build Coastguard Worker   switch (level) {
139*84e33947SAndroid Build Coastguard Worker     case LogLevel::ERROR:
140*84e33947SAndroid Build Coastguard Worker       return ANDROID_LOG_ERROR;
141*84e33947SAndroid Build Coastguard Worker     case LogLevel::WARNING:
142*84e33947SAndroid Build Coastguard Worker       return ANDROID_LOG_WARN;
143*84e33947SAndroid Build Coastguard Worker     case LogLevel::INFO:
144*84e33947SAndroid Build Coastguard Worker       return ANDROID_LOG_INFO;
145*84e33947SAndroid Build Coastguard Worker     case LogLevel::DEBUG:
146*84e33947SAndroid Build Coastguard Worker       return ANDROID_LOG_DEBUG;
147*84e33947SAndroid Build Coastguard Worker     default:
148*84e33947SAndroid Build Coastguard Worker       return ANDROID_LOG_SILENT;
149*84e33947SAndroid Build Coastguard Worker   }
150*84e33947SAndroid Build Coastguard Worker }
151*84e33947SAndroid Build Coastguard Worker 
getLogLevelFromMetadata(uint8_t metadata)152*84e33947SAndroid Build Coastguard Worker uint8_t LogMessageParser::getLogLevelFromMetadata(uint8_t metadata) {
153*84e33947SAndroid Build Coastguard Worker   // The lower nibble of the metadata denotes the loglevel, as indicated
154*84e33947SAndroid Build Coastguard Worker   // by the schema in host_messages.fbs.
155*84e33947SAndroid Build Coastguard Worker   return metadata & 0xf;
156*84e33947SAndroid Build Coastguard Worker }
157*84e33947SAndroid Build Coastguard Worker 
log(const uint8_t * logBuffer,size_t logBufferSize)158*84e33947SAndroid Build Coastguard Worker void LogMessageParser::log(const uint8_t *logBuffer, size_t logBufferSize) {
159*84e33947SAndroid Build Coastguard Worker   size_t bufferIndex = 0;
160*84e33947SAndroid Build Coastguard Worker   while (bufferIndex < logBufferSize) {
161*84e33947SAndroid Build Coastguard Worker     const LogMessage *message =
162*84e33947SAndroid Build Coastguard Worker         reinterpret_cast<const LogMessage *>(&logBuffer[bufferIndex]);
163*84e33947SAndroid Build Coastguard Worker     uint64_t timeNs = le64toh(message->timestampNanos);
164*84e33947SAndroid Build Coastguard Worker     emitLogMessage(message->logLevel, timeNs / kOneMillisecondInNanoseconds,
165*84e33947SAndroid Build Coastguard Worker                    message->logMessage);
166*84e33947SAndroid Build Coastguard Worker     bufferIndex += sizeof(LogMessage) +
167*84e33947SAndroid Build Coastguard Worker                    strnlen(message->logMessage, logBufferSize - bufferIndex) +
168*84e33947SAndroid Build Coastguard Worker                    1;
169*84e33947SAndroid Build Coastguard Worker   }
170*84e33947SAndroid Build Coastguard Worker }
171*84e33947SAndroid Build Coastguard Worker 
172*84e33947SAndroid Build Coastguard Worker std::optional<size_t>
parseAndEmitTokenizedLogMessageAndGetSize(const LogMessageV2 * message,size_t maxLogMessageLen)173*84e33947SAndroid Build Coastguard Worker LogMessageParser::parseAndEmitTokenizedLogMessageAndGetSize(
174*84e33947SAndroid Build Coastguard Worker     const LogMessageV2 *message, size_t maxLogMessageLen) {
175*84e33947SAndroid Build Coastguard Worker   auto detokenizer = mSystemDetokenizer.get();
176*84e33947SAndroid Build Coastguard Worker   auto *encodedLog = reinterpret_cast<const EncodedLog *>(message->logMessage);
177*84e33947SAndroid Build Coastguard Worker   size_t logMessageSize = encodedLog->size + kSystemTokenizedLogOffset;
178*84e33947SAndroid Build Coastguard Worker   if (logMessageSize > maxLogMessageLen) {
179*84e33947SAndroid Build Coastguard Worker     LOGE("Dropping log due to log message size exceeds the end of log buffer");
180*84e33947SAndroid Build Coastguard Worker     return std::nullopt;
181*84e33947SAndroid Build Coastguard Worker   } else if (detokenizer != nullptr) {
182*84e33947SAndroid Build Coastguard Worker     DetokenizedString detokenizedString =
183*84e33947SAndroid Build Coastguard Worker         detokenizer->Detokenize(encodedLog->data, encodedLog->size);
184*84e33947SAndroid Build Coastguard Worker     std::string decodedString = detokenizedString.BestStringWithErrors();
185*84e33947SAndroid Build Coastguard Worker     emitLogMessage(getLogLevelFromMetadata(message->metadata),
186*84e33947SAndroid Build Coastguard Worker                    le32toh(message->timestampMillis), decodedString.c_str());
187*84e33947SAndroid Build Coastguard Worker   } else {
188*84e33947SAndroid Build Coastguard Worker     // TODO(b/327515992): Stop decoding and emitting system log messages if
189*84e33947SAndroid Build Coastguard Worker     // detokenizer is null .
190*84e33947SAndroid Build Coastguard Worker     LOGE("Null detokenizer! Cannot decode log message");
191*84e33947SAndroid Build Coastguard Worker   }
192*84e33947SAndroid Build Coastguard Worker   return logMessageSize;
193*84e33947SAndroid Build Coastguard Worker }
194*84e33947SAndroid Build Coastguard Worker 
195*84e33947SAndroid Build Coastguard Worker std::optional<size_t>
parseAndEmitNanoappTokenizedLogMessageAndGetSize(const LogMessageV2 * message,size_t maxLogMessageLen)196*84e33947SAndroid Build Coastguard Worker LogMessageParser::parseAndEmitNanoappTokenizedLogMessageAndGetSize(
197*84e33947SAndroid Build Coastguard Worker     const LogMessageV2 *message, size_t maxLogMessageLen) {
198*84e33947SAndroid Build Coastguard Worker   std::lock_guard<std::mutex> lock(mNanoappMutex);
199*84e33947SAndroid Build Coastguard Worker   auto *tokenizedLog =
200*84e33947SAndroid Build Coastguard Worker       reinterpret_cast<const NanoappTokenizedLog *>(message->logMessage);
201*84e33947SAndroid Build Coastguard Worker   auto detokenizerIter = mNanoappDetokenizers.find(tokenizedLog->instanceId);
202*84e33947SAndroid Build Coastguard Worker   size_t logMessageSize = tokenizedLog->size + kNanoappTokenizedLogOffset;
203*84e33947SAndroid Build Coastguard Worker   if (detokenizerIter == mNanoappDetokenizers.end()) {
204*84e33947SAndroid Build Coastguard Worker     LOGE(
205*84e33947SAndroid Build Coastguard Worker         "Unable to find nanoapp log detokenizer associated with instance ID: "
206*84e33947SAndroid Build Coastguard Worker         "%" PRIu16,
207*84e33947SAndroid Build Coastguard Worker         tokenizedLog->instanceId);
208*84e33947SAndroid Build Coastguard Worker     return std::nullopt;
209*84e33947SAndroid Build Coastguard Worker   } else if (logMessageSize > maxLogMessageLen) {
210*84e33947SAndroid Build Coastguard Worker     LOGE("Dropping log due to log message size exceeds the end of log buffer");
211*84e33947SAndroid Build Coastguard Worker     logMessageSize = maxLogMessageLen;
212*84e33947SAndroid Build Coastguard Worker   } else {
213*84e33947SAndroid Build Coastguard Worker     auto detokenizer = detokenizerIter->second.detokenizer.get();
214*84e33947SAndroid Build Coastguard Worker     DetokenizedString detokenizedString =
215*84e33947SAndroid Build Coastguard Worker         detokenizer->Detokenize(tokenizedLog->data, tokenizedLog->size);
216*84e33947SAndroid Build Coastguard Worker     std::string decodedString = detokenizedString.BestStringWithErrors();
217*84e33947SAndroid Build Coastguard Worker     emitLogMessage(getLogLevelFromMetadata(message->metadata),
218*84e33947SAndroid Build Coastguard Worker                    le32toh(message->timestampMillis), decodedString.c_str());
219*84e33947SAndroid Build Coastguard Worker   }
220*84e33947SAndroid Build Coastguard Worker   return logMessageSize;
221*84e33947SAndroid Build Coastguard Worker }
222*84e33947SAndroid Build Coastguard Worker 
parseAndEmitStringLogMessageAndGetSize(const LogMessageV2 * message,size_t maxLogMessageLen)223*84e33947SAndroid Build Coastguard Worker std::optional<size_t> LogMessageParser::parseAndEmitStringLogMessageAndGetSize(
224*84e33947SAndroid Build Coastguard Worker     const LogMessageV2 *message, size_t maxLogMessageLen) {
225*84e33947SAndroid Build Coastguard Worker   maxLogMessageLen = maxLogMessageLen - kStringLogOverhead;
226*84e33947SAndroid Build Coastguard Worker   size_t logMessageSize = strnlen(message->logMessage, maxLogMessageLen);
227*84e33947SAndroid Build Coastguard Worker   if (message->logMessage[logMessageSize] != '\0') {
228*84e33947SAndroid Build Coastguard Worker     LOGE("Dropping string log due to invalid buffer structure");
229*84e33947SAndroid Build Coastguard Worker     return std::nullopt;
230*84e33947SAndroid Build Coastguard Worker   }
231*84e33947SAndroid Build Coastguard Worker   emitLogMessage(getLogLevelFromMetadata(message->metadata),
232*84e33947SAndroid Build Coastguard Worker                  le32toh(message->timestampMillis), message->logMessage);
233*84e33947SAndroid Build Coastguard Worker   return logMessageSize + kStringLogOverhead;
234*84e33947SAndroid Build Coastguard Worker }
235*84e33947SAndroid Build Coastguard Worker 
updateAndPrintDroppedLogs(uint32_t numLogsDropped)236*84e33947SAndroid Build Coastguard Worker void LogMessageParser::updateAndPrintDroppedLogs(uint32_t numLogsDropped) {
237*84e33947SAndroid Build Coastguard Worker   if (numLogsDropped < mNumLogsDropped) {
238*84e33947SAndroid Build Coastguard Worker     LOGE(
239*84e33947SAndroid Build Coastguard Worker         "The numLogsDropped value received from CHRE is less than the last "
240*84e33947SAndroid Build Coastguard Worker         "value received. Received: %" PRIu32 " Last value: %" PRIu32,
241*84e33947SAndroid Build Coastguard Worker         numLogsDropped, mNumLogsDropped);
242*84e33947SAndroid Build Coastguard Worker   }
243*84e33947SAndroid Build Coastguard Worker   // Log the number of logs dropped once before logging remaining logs from CHRE
244*84e33947SAndroid Build Coastguard Worker   uint32_t diffLogsDropped = numLogsDropped - mNumLogsDropped;
245*84e33947SAndroid Build Coastguard Worker   mNumLogsDropped = numLogsDropped;
246*84e33947SAndroid Build Coastguard Worker   if (diffLogsDropped > 0) {
247*84e33947SAndroid Build Coastguard Worker     LOGI("# logs dropped: %" PRIu32, diffLogsDropped);
248*84e33947SAndroid Build Coastguard Worker   }
249*84e33947SAndroid Build Coastguard Worker }
250*84e33947SAndroid Build Coastguard Worker 
emitLogMessage(uint8_t level,uint32_t timestampMillis,const char * logMessage)251*84e33947SAndroid Build Coastguard Worker void LogMessageParser::emitLogMessage(uint8_t level, uint32_t timestampMillis,
252*84e33947SAndroid Build Coastguard Worker                                       const char *logMessage) {
253*84e33947SAndroid Build Coastguard Worker   constexpr const char kLogTag[] = "CHRE";
254*84e33947SAndroid Build Coastguard Worker   uint32_t timeSec = timestampMillis / kOneSecondInMilliseconds;
255*84e33947SAndroid Build Coastguard Worker   uint32_t timeMsRemainder = timestampMillis % kOneSecondInMilliseconds;
256*84e33947SAndroid Build Coastguard Worker   android_LogPriority priority = chreLogLevelToAndroidLogPriority(level);
257*84e33947SAndroid Build Coastguard Worker   LOG_PRI(priority, kLogTag, kHubLogFormatStr, timeSec, timeMsRemainder,
258*84e33947SAndroid Build Coastguard Worker           logMessage);
259*84e33947SAndroid Build Coastguard Worker }
260*84e33947SAndroid Build Coastguard Worker 
logV2(const uint8_t * logBuffer,size_t logBufferSize,uint32_t numLogsDropped)261*84e33947SAndroid Build Coastguard Worker void LogMessageParser::logV2(const uint8_t *logBuffer, size_t logBufferSize,
262*84e33947SAndroid Build Coastguard Worker                              uint32_t numLogsDropped) {
263*84e33947SAndroid Build Coastguard Worker   constexpr size_t kLogHeaderSize = sizeof(LogMessageV2);
264*84e33947SAndroid Build Coastguard Worker 
265*84e33947SAndroid Build Coastguard Worker   updateAndPrintDroppedLogs(numLogsDropped);
266*84e33947SAndroid Build Coastguard Worker 
267*84e33947SAndroid Build Coastguard Worker   std::optional<size_t> logMessageSize = std::nullopt;
268*84e33947SAndroid Build Coastguard Worker   size_t bufferIndex = 0;
269*84e33947SAndroid Build Coastguard Worker   const LogMessageV2 *message = nullptr;
270*84e33947SAndroid Build Coastguard Worker   size_t maxLogMessageLen = 0;
271*84e33947SAndroid Build Coastguard Worker   while (bufferIndex + kLogHeaderSize < logBufferSize) {
272*84e33947SAndroid Build Coastguard Worker     message = reinterpret_cast<const LogMessageV2 *>(&logBuffer[bufferIndex]);
273*84e33947SAndroid Build Coastguard Worker     maxLogMessageLen = (logBufferSize - bufferIndex) - kLogHeaderSize;
274*84e33947SAndroid Build Coastguard Worker     logMessageSize = std::nullopt;
275*84e33947SAndroid Build Coastguard Worker 
276*84e33947SAndroid Build Coastguard Worker     switch (extractLogType(message)) {
277*84e33947SAndroid Build Coastguard Worker       // TODO(b/336467722): Rename the log types in fbs.
278*84e33947SAndroid Build Coastguard Worker       case LogType::STRING:
279*84e33947SAndroid Build Coastguard Worker         logMessageSize =
280*84e33947SAndroid Build Coastguard Worker             parseAndEmitStringLogMessageAndGetSize(message, maxLogMessageLen);
281*84e33947SAndroid Build Coastguard Worker         break;
282*84e33947SAndroid Build Coastguard Worker       case LogType::TOKENIZED:
283*84e33947SAndroid Build Coastguard Worker         logMessageSize = parseAndEmitTokenizedLogMessageAndGetSize(
284*84e33947SAndroid Build Coastguard Worker             message, maxLogMessageLen);
285*84e33947SAndroid Build Coastguard Worker         break;
286*84e33947SAndroid Build Coastguard Worker       case LogType::BLUETOOTH:
287*84e33947SAndroid Build Coastguard Worker         logMessageSize =
288*84e33947SAndroid Build Coastguard Worker             mBtLogParser.log(message->logMessage, maxLogMessageLen);
289*84e33947SAndroid Build Coastguard Worker         break;
290*84e33947SAndroid Build Coastguard Worker       case LogType::NANOAPP_TOKENIZED:
291*84e33947SAndroid Build Coastguard Worker         logMessageSize = parseAndEmitNanoappTokenizedLogMessageAndGetSize(
292*84e33947SAndroid Build Coastguard Worker             message, maxLogMessageLen);
293*84e33947SAndroid Build Coastguard Worker         break;
294*84e33947SAndroid Build Coastguard Worker       default:
295*84e33947SAndroid Build Coastguard Worker         LOGE("Unexpected log type 0x%" PRIx8,
296*84e33947SAndroid Build Coastguard Worker              (message->metadata & kLogTypeMask) >> kLogTypeBitOffset);
297*84e33947SAndroid Build Coastguard Worker         break;
298*84e33947SAndroid Build Coastguard Worker     }
299*84e33947SAndroid Build Coastguard Worker     if (!logMessageSize.has_value()) {
300*84e33947SAndroid Build Coastguard Worker       LOGE("Log message at offset %zu is corrupted, aborting...", bufferIndex);
301*84e33947SAndroid Build Coastguard Worker       return;
302*84e33947SAndroid Build Coastguard Worker     }
303*84e33947SAndroid Build Coastguard Worker     bufferIndex += kLogHeaderSize + logMessageSize.value();
304*84e33947SAndroid Build Coastguard Worker   }
305*84e33947SAndroid Build Coastguard Worker }
306*84e33947SAndroid Build Coastguard Worker 
addNanoappDetokenizer(uint64_t appId,uint16_t instanceId,uint64_t databaseOffset,size_t databaseSize)307*84e33947SAndroid Build Coastguard Worker void LogMessageParser::addNanoappDetokenizer(uint64_t appId,
308*84e33947SAndroid Build Coastguard Worker                                              uint16_t instanceId,
309*84e33947SAndroid Build Coastguard Worker                                              uint64_t databaseOffset,
310*84e33947SAndroid Build Coastguard Worker                                              size_t databaseSize) {
311*84e33947SAndroid Build Coastguard Worker   std::shared_ptr<const std::vector<uint8_t>> appBinary =
312*84e33947SAndroid Build Coastguard Worker       fetchNanoappBinary(appId);
313*84e33947SAndroid Build Coastguard Worker   if (!appBinary) {
314*84e33947SAndroid Build Coastguard Worker     LOGE(
315*84e33947SAndroid Build Coastguard Worker         "Binary not in cache, can't extract log token database for app ID "
316*84e33947SAndroid Build Coastguard Worker         "0x%016" PRIx64,
317*84e33947SAndroid Build Coastguard Worker         appId);
318*84e33947SAndroid Build Coastguard Worker   } else {
319*84e33947SAndroid Build Coastguard Worker     removeNanoappDetokenizerAndBinary(appId);
320*84e33947SAndroid Build Coastguard Worker     if (databaseSize != kInvalidTokenDatabaseSize) {
321*84e33947SAndroid Build Coastguard Worker       if (checkTokenDatabaseOverflow(databaseOffset, databaseSize,
322*84e33947SAndroid Build Coastguard Worker                                      appBinary->size())) {
323*84e33947SAndroid Build Coastguard Worker         LOGE(
324*84e33947SAndroid Build Coastguard Worker             "Token database fails memory bounds check for nanoapp with app ID "
325*84e33947SAndroid Build Coastguard Worker             "0x%016" PRIx64 ". Token database offset received: %" PRIu32
326*84e33947SAndroid Build Coastguard Worker             "; size received: %zu; Size of the appBinary: %zu.",
327*84e33947SAndroid Build Coastguard Worker             appId, databaseOffset, databaseSize, appBinary->size());
328*84e33947SAndroid Build Coastguard Worker       } else {
329*84e33947SAndroid Build Coastguard Worker         const uint8_t *tokenDatabaseBinaryStart =
330*84e33947SAndroid Build Coastguard Worker             appBinary->data() + kImageHeaderSize + databaseOffset;
331*84e33947SAndroid Build Coastguard Worker 
332*84e33947SAndroid Build Coastguard Worker         pw::span<const uint8_t> tokenEntries(tokenDatabaseBinaryStart,
333*84e33947SAndroid Build Coastguard Worker                                              databaseSize);
334*84e33947SAndroid Build Coastguard Worker         pw::Result<Detokenizer> nanoappDetokenizer =
335*84e33947SAndroid Build Coastguard Worker             pw::tokenizer::Detokenizer::FromElfSection(tokenEntries);
336*84e33947SAndroid Build Coastguard Worker 
337*84e33947SAndroid Build Coastguard Worker         registerDetokenizer(appId, instanceId, std::move(nanoappDetokenizer));
338*84e33947SAndroid Build Coastguard Worker       }
339*84e33947SAndroid Build Coastguard Worker     }
340*84e33947SAndroid Build Coastguard Worker   }
341*84e33947SAndroid Build Coastguard Worker }
342*84e33947SAndroid Build Coastguard Worker 
registerDetokenizer(uint64_t appId,uint16_t instanceId,pw::Result<Detokenizer> nanoappDetokenizer)343*84e33947SAndroid Build Coastguard Worker void LogMessageParser::registerDetokenizer(
344*84e33947SAndroid Build Coastguard Worker     uint64_t appId, uint16_t instanceId,
345*84e33947SAndroid Build Coastguard Worker     pw::Result<Detokenizer> nanoappDetokenizer) {
346*84e33947SAndroid Build Coastguard Worker   std::lock_guard<std::mutex> lock(mNanoappMutex);
347*84e33947SAndroid Build Coastguard Worker 
348*84e33947SAndroid Build Coastguard Worker   if (nanoappDetokenizer.ok()) {
349*84e33947SAndroid Build Coastguard Worker     NanoappDetokenizer detokenizer;
350*84e33947SAndroid Build Coastguard Worker     detokenizer.appId = appId;
351*84e33947SAndroid Build Coastguard Worker     detokenizer.detokenizer =
352*84e33947SAndroid Build Coastguard Worker         std::make_unique<Detokenizer>(std::move(*nanoappDetokenizer));
353*84e33947SAndroid Build Coastguard Worker     mNanoappDetokenizers[instanceId] = std::move(detokenizer);
354*84e33947SAndroid Build Coastguard Worker   } else {
355*84e33947SAndroid Build Coastguard Worker     LOGE("Unable to parse log detokenizer for app with ID: 0x%016" PRIx64,
356*84e33947SAndroid Build Coastguard Worker          appId);
357*84e33947SAndroid Build Coastguard Worker   }
358*84e33947SAndroid Build Coastguard Worker }
359*84e33947SAndroid Build Coastguard Worker 
360*84e33947SAndroid Build Coastguard Worker std::shared_ptr<const std::vector<uint8_t>>
fetchNanoappBinary(uint64_t appId)361*84e33947SAndroid Build Coastguard Worker LogMessageParser::fetchNanoappBinary(uint64_t appId) {
362*84e33947SAndroid Build Coastguard Worker   std::lock_guard<std::mutex> lock(mNanoappMutex);
363*84e33947SAndroid Build Coastguard Worker   auto appBinaryIter = mNanoappAppIdToBinary.find(appId);
364*84e33947SAndroid Build Coastguard Worker   if (appBinaryIter != mNanoappAppIdToBinary.end()) {
365*84e33947SAndroid Build Coastguard Worker     return appBinaryIter->second;
366*84e33947SAndroid Build Coastguard Worker   }
367*84e33947SAndroid Build Coastguard Worker   return nullptr;
368*84e33947SAndroid Build Coastguard Worker }
369*84e33947SAndroid Build Coastguard Worker 
removeNanoappDetokenizerAndBinary(uint64_t appId)370*84e33947SAndroid Build Coastguard Worker void LogMessageParser::removeNanoappDetokenizerAndBinary(uint64_t appId) {
371*84e33947SAndroid Build Coastguard Worker   std::lock_guard<std::mutex> lock(mNanoappMutex);
372*84e33947SAndroid Build Coastguard Worker   for (const auto &item : mNanoappDetokenizers) {
373*84e33947SAndroid Build Coastguard Worker     if (item.second.appId == appId) {
374*84e33947SAndroid Build Coastguard Worker       mNanoappDetokenizers.erase(item.first);
375*84e33947SAndroid Build Coastguard Worker     }
376*84e33947SAndroid Build Coastguard Worker   }
377*84e33947SAndroid Build Coastguard Worker   mNanoappAppIdToBinary.erase(appId);
378*84e33947SAndroid Build Coastguard Worker }
379*84e33947SAndroid Build Coastguard Worker 
resetNanoappDetokenizerState()380*84e33947SAndroid Build Coastguard Worker void LogMessageParser::resetNanoappDetokenizerState() {
381*84e33947SAndroid Build Coastguard Worker   std::lock_guard<std::mutex> lock(mNanoappMutex);
382*84e33947SAndroid Build Coastguard Worker   mNanoappDetokenizers.clear();
383*84e33947SAndroid Build Coastguard Worker   mNanoappAppIdToBinary.clear();
384*84e33947SAndroid Build Coastguard Worker }
385*84e33947SAndroid Build Coastguard Worker 
onNanoappLoadStarted(uint64_t appId,std::shared_ptr<const std::vector<uint8_t>> nanoappBinary)386*84e33947SAndroid Build Coastguard Worker void LogMessageParser::onNanoappLoadStarted(
387*84e33947SAndroid Build Coastguard Worker     uint64_t appId, std::shared_ptr<const std::vector<uint8_t>> nanoappBinary) {
388*84e33947SAndroid Build Coastguard Worker   std::lock_guard<std::mutex> lock(mNanoappMutex);
389*84e33947SAndroid Build Coastguard Worker   mNanoappAppIdToBinary[appId] = nanoappBinary;
390*84e33947SAndroid Build Coastguard Worker }
391*84e33947SAndroid Build Coastguard Worker 
onNanoappLoadFailed(uint64_t appId)392*84e33947SAndroid Build Coastguard Worker void LogMessageParser::onNanoappLoadFailed(uint64_t appId) {
393*84e33947SAndroid Build Coastguard Worker   removeNanoappDetokenizerAndBinary(appId);
394*84e33947SAndroid Build Coastguard Worker }
395*84e33947SAndroid Build Coastguard Worker 
onNanoappUnloaded(uint64_t appId)396*84e33947SAndroid Build Coastguard Worker void LogMessageParser::onNanoappUnloaded(uint64_t appId) {
397*84e33947SAndroid Build Coastguard Worker   removeNanoappDetokenizerAndBinary(appId);
398*84e33947SAndroid Build Coastguard Worker }
399*84e33947SAndroid Build Coastguard Worker 
checkTokenDatabaseOverflow(uint32_t databaseOffset,size_t databaseSize,size_t binarySize)400*84e33947SAndroid Build Coastguard Worker bool LogMessageParser::checkTokenDatabaseOverflow(uint32_t databaseOffset,
401*84e33947SAndroid Build Coastguard Worker                                                   size_t databaseSize,
402*84e33947SAndroid Build Coastguard Worker                                                   size_t binarySize) {
403*84e33947SAndroid Build Coastguard Worker   return databaseOffset > binarySize || databaseSize > binarySize ||
404*84e33947SAndroid Build Coastguard Worker          databaseOffset + databaseSize > binarySize ||
405*84e33947SAndroid Build Coastguard Worker          databaseOffset + databaseSize < databaseOffset;
406*84e33947SAndroid Build Coastguard Worker }
407*84e33947SAndroid Build Coastguard Worker 
408*84e33947SAndroid Build Coastguard Worker }  // namespace chre
409*84e33947SAndroid Build Coastguard Worker }  // namespace android
410