1 /* 2 * Copyright (C) 2017 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/platform_log.h" 18 19 extern "C" { 20 21 #include "a1std/AEEstd.h" 22 #include "HAP_farf.h" 23 #include "smp2p.h" 24 25 } // extern "C" 26 27 #include <cinttypes> 28 29 #include "chre/platform/assert.h" 30 #include "chre/platform/log.h" 31 #include "chre/platform/host_link.h" 32 #include "chre/platform/system_time.h" 33 #include "chre/util/lock_guard.h" 34 35 namespace chre { 36 37 PlatformLog::PlatformLog() {} 38 39 PlatformLog::~PlatformLog() {} 40 41 void PlatformLog::log(const char *formatStr, ...) { 42 LockGuard<Mutex> lock(mMutex); 43 44 if ((mLogBufferSize + kMaxLogMessageSize) < kLogBufferSize) { 45 // TODO: Pass in the log level. All messages are logged at info level. 46 char *logBuffer = &mLogBuffer[mLogBufferSize]; 47 *logBuffer = CHRE_LOG_LEVEL_INFO; 48 logBuffer++; 49 50 // Insert the timestamp of the log prior to the string. 51 // XXX Here be dragons. There are no endianness conversion macros in the 52 // SLPI source tree that support 64-bit width integers. This code assumes 53 // that it is running on a little-endian system! You have been warned. 54 uint64_t timestamp = SystemTime::getMonotonicTime().toRawNanoseconds(); 55 memcpy(logBuffer, ×tamp, sizeof(uint64_t)); 56 logBuffer += sizeof(uint64_t); 57 58 // Format the log message after the timestamp. 59 va_list argList; 60 va_start(argList, formatStr); 61 const size_t messageLen = kMaxLogMessageSize - 1 - sizeof(uint64_t); 62 int strLen = vsnprintf(logBuffer, messageLen, formatStr, argList); 63 va_end(argList); 64 65 if (strLen < 0) { 66 // A formatting error occured. Don't advance the log buffer index. 67 FARF(MEDIUM, "Failed to format log string. Dropping message"); 68 } else { 69 // Null-terminate if the formatted string does not fit into the buffer. 70 if (static_cast<size_t>(strLen) >= messageLen) { 71 logBuffer[messageLen] = '\0'; 72 strLen--; 73 } 74 75 // Increment the size of logged messages, leaving space for level, 76 // timestamp and null-terminator. 77 mLogBufferSize += 1 + sizeof(uint64_t) + strLen + 1; 78 79 // Only request a log flush if there is not one pending and the log buffer 80 // has exceeded the watermark. 81 if (!mLogFlushPending && mLogBufferSize > kLogBufferWatermarkSize) { 82 mLogFlushPending = true; 83 84 // Manually unlock the mutex in the event that the request for a log flush 85 // attempts to log. This would result in a deadlock. 86 // TODO: Consider a more elegant way to handle this unlock/lock pair. 87 mMutex.unlock(); 88 requestHostLinkLogBufferFlush(); 89 mMutex.lock(); 90 } 91 } 92 } else { 93 // TODO: Handle the condition where there is space for less than 1 message 94 // left. This might be considered a fatal error or an assert at the minimum. 95 } 96 } 97 98 void PlatformLogBase::flushLogBuffer(FlushLogBufferCallback callback, 99 void *context) { 100 CHRE_ASSERT(callback != nullptr); 101 102 LockGuard<Mutex> lock(mMutex); 103 CHRE_ASSERT(mLogFlushPending); 104 callback(mLogBuffer, mLogBufferSize, context); 105 mLogBufferSize = 0; 106 mLogFlushPending = false; 107 } 108 109 } // namespace chre 110