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 <endian.h>
18 #include <cstdio>
19
20 #include "chre/util/time.h"
21 #include "chre_host/log_message_parser_base.h"
22
23 using chre::kOneMillisecondInNanoseconds;
24 using chre::kOneSecondInMilliseconds;
25
26 namespace android {
27 namespace chre {
28
29 namespace {
30 #if defined(LOG_NDEBUG) || LOG_NDEBUG != 0
31 constexpr bool kVerboseLoggingEnabled = true;
32 #else
33 constexpr bool kVerboseLoggingEnabled = false;
34 #endif
35 } // anonymous namespace
36
ChreLogMessageParserBase()37 ChreLogMessageParserBase::ChreLogMessageParserBase()
38 : mVerboseLoggingEnabled(kVerboseLoggingEnabled) {}
39
dump(const uint8_t * buffer,size_t size)40 void ChreLogMessageParserBase::dump(const uint8_t *buffer, size_t size) {
41 if (mVerboseLoggingEnabled) {
42 char line[32];
43 char lineChars[32];
44 int offset = 0;
45 int offsetChars = 0;
46
47 size_t orig_size = size;
48 if (size > 128) {
49 size = 128;
50 LOGV("Dumping first 128 bytes of buffer of size %zu", orig_size);
51 } else {
52 LOGV("Dumping buffer of size %zu bytes", size);
53 }
54 for (size_t i = 1; i <= size; ++i) {
55 offset += snprintf(&line[offset], sizeof(line) - offset, "%02x ",
56 buffer[i - 1]);
57 offsetChars +=
58 snprintf(&lineChars[offsetChars], sizeof(lineChars) - offsetChars,
59 "%c", (isprint(buffer[i - 1])) ? buffer[i - 1] : '.');
60 if ((i % 8) == 0) {
61 LOGV(" %s\t%s", line, lineChars);
62 offset = 0;
63 offsetChars = 0;
64 } else if ((i % 4) == 0) {
65 offset += snprintf(&line[offset], sizeof(line) - offset, " ");
66 }
67 }
68
69 if (offset > 0) {
70 char tabs[8];
71 char *pos = tabs;
72 while (offset < 28) {
73 *pos++ = '\t';
74 offset += 8;
75 }
76 *pos = '\0';
77 LOGV(" %s%s%s", line, tabs, lineChars);
78 }
79 }
80 }
81
chreLogLevelToAndroidLogPriority(uint8_t level)82 android_LogPriority ChreLogMessageParserBase::chreLogLevelToAndroidLogPriority(
83 uint8_t level) {
84 switch (level) {
85 case LogLevel::ERROR:
86 return ANDROID_LOG_ERROR;
87 case LogLevel::WARNING:
88 return ANDROID_LOG_WARN;
89 case LogLevel::INFO:
90 return ANDROID_LOG_INFO;
91 case LogLevel::DEBUG:
92 return ANDROID_LOG_DEBUG;
93 default:
94 return ANDROID_LOG_SILENT;
95 }
96 }
97
log(const uint8_t * logBuffer,size_t logBufferSize)98 void ChreLogMessageParserBase::log(const uint8_t *logBuffer,
99 size_t logBufferSize) {
100 size_t bufferIndex = 0;
101 while (bufferIndex < logBufferSize) {
102 const LogMessage *message =
103 reinterpret_cast<const LogMessage *>(&logBuffer[bufferIndex]);
104 uint64_t timeNs = le64toh(message->timestampNanos);
105 emitLogMessage(message->logLevel, timeNs / kOneMillisecondInNanoseconds,
106 message->logMessage);
107 bufferIndex += sizeof(LogMessage) +
108 strnlen(message->logMessage, logBufferSize - bufferIndex) +
109 1;
110 }
111 }
112
logV2(const uint8_t * logBuffer,size_t logBufferSize,uint32_t numLogsDropped)113 void ChreLogMessageParserBase::logV2(const uint8_t *logBuffer,
114 size_t logBufferSize,
115 uint32_t numLogsDropped) {
116 size_t bufferIndex = 0;
117 if (numLogsDropped < mNumLogsDropped) {
118 LOGE(
119 "The numLogsDropped value received from CHRE is less than the last "
120 "value received. Received: %" PRIu32 " Last value: %" PRIu32,
121 numLogsDropped, mNumLogsDropped);
122 }
123 // Log the number of logs dropped once before logging remaining logs from CHRE
124 uint32_t diffLogsDropped = numLogsDropped - mNumLogsDropped;
125 mNumLogsDropped = numLogsDropped;
126 if (diffLogsDropped > 0) {
127 LOGI("# logs dropped: %" PRIu32, diffLogsDropped);
128 }
129 while (bufferIndex < logBufferSize) {
130 const LogMessageV2 *message =
131 reinterpret_cast<const LogMessageV2 *>(&logBuffer[bufferIndex]);
132 emitLogMessage(message->logLevel, le32toh(message->timestampMillis),
133 message->logMessage);
134 bufferIndex += sizeof(LogMessageV2) +
135 strnlen(message->logMessage, logBufferSize - bufferIndex) +
136 1;
137 }
138 }
139
emitLogMessage(uint8_t level,uint32_t timestampMillis,const char * logMessage)140 void ChreLogMessageParserBase::emitLogMessage(uint8_t level,
141 uint32_t timestampMillis,
142 const char *logMessage) {
143 constexpr const char kLogTag[] = "CHRE";
144 uint32_t timeSec = timestampMillis / kOneSecondInMilliseconds;
145 uint32_t timeMsRemainder = timestampMillis % kOneSecondInMilliseconds;
146 android_LogPriority priority = chreLogLevelToAndroidLogPriority(level);
147 LOG_PRI(priority, kLogTag, kHubLogFormatStr, timeSec, timeMsRemainder,
148 logMessage);
149 }
150
151 } // namespace chre
152 } // namespace android
153