Home | History | Annotate | Download | only in slpi
      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, &timestamp, 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