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 #ifndef CHRE_TOKENIZED_LOG_MESSAGE_PARSER_H_ 18 #define CHRE_TOKENIZED_LOG_MESSAGE_PARSER_H_ 19 20 #include <memory> 21 #include "chre_host/daemon_base.h" 22 #include "chre_host/log_message_parser_base.h" 23 24 #include "pw_tokenizer/detokenize.h" 25 26 using pw::tokenizer::DetokenizedString; 27 using pw::tokenizer::Detokenizer; 28 29 namespace android { 30 namespace chre { 31 32 class ChreTokenizedLogMessageParser : public ChreLogMessageParserBase { 33 public: init()34 virtual bool init() override final { 35 mDetokenizer = logDetokenizerInit(); 36 return mDetokenizer != nullptr; 37 } 38 log(const uint8_t * logBuffer,size_t logBufferSize)39 virtual void log(const uint8_t *logBuffer, 40 size_t logBufferSize) override final { 41 parseAndEmitTokenizedLogMessages(logBuffer, logBufferSize, 42 mDetokenizer.get()); 43 } 44 logV2(const uint8_t * logBuffer,size_t logBufferSize)45 void logV2(const uint8_t *logBuffer, size_t logBufferSize) override { 46 // TODO(b/172654554): Modify tokenized logging to only support v2 logs. 47 } 48 49 private: 50 std::unique_ptr<Detokenizer> mDetokenizer; 51 52 /** 53 * Initialize the Log Detokenizer 54 * 55 * The log detokenizer reads a binary database file that contains key value 56 * pairs of hash-keys <--> Decoded log messages, and creates an instance 57 * of the Detokenizer. 58 * 59 * @return an instance of the Detokenizer 60 */ logDetokenizerInit()61 std::unique_ptr<Detokenizer> logDetokenizerInit() { 62 constexpr const char kLogDatabaseFilePath[] = 63 "/vendor/etc/chre/libchre_log_database.bin"; 64 std::vector<uint8_t> tokenData; 65 if (ChreDaemonBase::readFileContents(kLogDatabaseFilePath, &tokenData)) { 66 pw::tokenizer::TokenDatabase database = 67 pw::tokenizer::TokenDatabase::Create(tokenData); 68 if (database.ok()) { 69 return std::make_unique<Detokenizer>(database); 70 } else { 71 LOGE("CHRE Token database creation not OK"); 72 } 73 } else { 74 LOGE("Failed to read CHRE Token database file"); 75 } 76 return std::unique_ptr<Detokenizer>(nullptr); 77 } 78 79 // Log messages are routed through ashLog if tokenized logging 80 // is disabled, so only parse tokenized log messages here. parseAndEmitTokenizedLogMessages(const uint8_t * message,unsigned int messageLen,const Detokenizer * detokenizer)81 void parseAndEmitTokenizedLogMessages(const uint8_t *message, 82 unsigned int messageLen, 83 const Detokenizer *detokenizer) { 84 if (detokenizer != nullptr) { 85 // TODO: Pull out common code from the tokenized/standard log 86 // parser functions when we implement batching for tokenized 87 // logs (b/148873804) 88 constexpr size_t kLogMessageHeaderSize = 89 1 /*logLevel*/ + sizeof(uint64_t) /*timestamp*/; 90 uint8_t level = *message; 91 ++message; 92 93 uint64_t timestampNanos; 94 memcpy(×tampNanos, message, sizeof(uint64_t)); 95 timestampNanos = le64toh(timestampNanos); 96 message += sizeof(uint64_t); 97 98 DetokenizedString detokenizedLog = 99 detokenizer->Detokenize(message, messageLen - kLogMessageHeaderSize); 100 std::string decodedLog = detokenizedLog.BestStringWithErrors(); 101 uint32_t timestampMillis = 102 timestampNanos / chre::kOneMillisecondInNanoseconds; 103 emitLogMessage(level, timestampNanos, decodedLog.c_str()); 104 } else { 105 // log an error and risk log spam? fail silently? log once? 106 } 107 } 108 }; 109 110 } // namespace chre 111 } // namespace android 112 113 #endif // CHRE_TOKENIZED_LOG_MESSAGE_PARSER_H_