| /* |
| * Copyright (C) 2022 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "event_logger.h" |
| |
| #include <inttypes.h> |
| #include <stdio.h> |
| #include <chrono> |
| #include <cstddef> |
| #include <ctime> |
| #include <string> |
| |
| namespace aidl::android::hardware::contexthub { |
| |
| namespace { |
| |
| /** |
| * Returns the time formatted in the local timezone. |
| * The format is similar to the adb logcat format, i.e. `01-31 18:22:51.275`. |
| */ |
| std::string formatLocalTime(int64_t ms) { |
| const std::chrono::milliseconds duration(ms); |
| const std::chrono::time_point<std::chrono::system_clock> timePoint(duration); |
| time_t time = std::chrono::system_clock::to_time_t(timePoint); |
| constexpr int kBufferSize = 50; |
| char buffer[kBufferSize]; |
| std::strftime(buffer, kBufferSize, "%m-%d %H:%M:%S.", std::localtime(&time)); |
| return std::string(buffer) + std::to_string(1000 + ms % 1000).substr(1); |
| } |
| |
| } // namespace |
| |
| void EventLogger::logNanoappLoad(uint64_t appId, size_t appSize, |
| uint32_t appVersion, bool success) { |
| std::lock_guard<std::mutex> lock(mQueuesMutex); |
| mNanoappLoads.kick_push({ |
| .timestampMs = getTimeMs(), |
| .id = static_cast<int64_t>(appId), |
| .version = static_cast<int32_t>(appVersion), |
| .sizeBytes = appSize, |
| .success = success, |
| }); |
| } |
| |
| void EventLogger::logNanoappUnload(int64_t appId, bool success) { |
| std::lock_guard<std::mutex> lock(mQueuesMutex); |
| mNanoappUnloads.kick_push({ |
| .timestampMs = getTimeMs(), |
| .id = appId, |
| .success = success, |
| }); |
| } |
| |
| void EventLogger::logContextHubRestart() { |
| std::lock_guard<std::mutex> lock(mQueuesMutex); |
| mContextHubRestarts.kick_push(getTimeMs()); |
| } |
| |
| void EventLogger::logMessageToNanoapp(const ContextHubMessage &message, |
| bool success) { |
| std::lock_guard<std::mutex> lock(mQueuesMutex); |
| mMsgToNanoapp.kick_push({ |
| .timestampMs = getTimeMs(), |
| .id = message.nanoappId, |
| .sizeBytes = message.messageBody.size(), |
| .success = success, |
| }); |
| } |
| |
| void EventLogger::logMessageFromNanoapp( |
| const ::chre::fbs::NanoappMessageT &message) { |
| std::lock_guard<std::mutex> lock(mQueuesMutex); |
| mMsgFromNanoapp.kick_push({ |
| .timestampMs = getTimeMs(), |
| .id = static_cast<int64_t>(message.app_id), |
| .sizeBytes = message.message.size(), |
| }); |
| } |
| |
| void EventLogger::logMessageFromNanoapp(const ContextHubMessage &message) { |
| std::lock_guard<std::mutex> lock(mQueuesMutex); |
| mMsgFromNanoapp.kick_push({ |
| .timestampMs = getTimeMs(), |
| .id = message.nanoappId, |
| .sizeBytes = message.messageBody.size(), |
| }); |
| } |
| |
| std::string EventLogger::dump() const { |
| constexpr int kBufferSize = 100; |
| char buffer[kBufferSize]; |
| std::string logs; |
| std::lock_guard<std::mutex> lock(mQueuesMutex); |
| |
| logs.append("\nNanoapp loads:\n"); |
| for (const NanoappLoad &load : mNanoappLoads) { |
| // Use snprintf because std::format is not available and fmtlib {:x} format |
| // crashes. |
| if (snprintf(buffer, kBufferSize, |
| " %s id 0x%" PRIx64 " version 0x%" PRIx32 " size %zu" |
| " status %s\n", |
| formatLocalTime(load.timestampMs).c_str(), load.id, |
| load.version, load.sizeBytes, |
| load.success ? "ok" : "fail") > 0) { |
| logs.append(buffer); |
| } |
| } |
| |
| logs.append("\nNanoapp unloads:\n"); |
| for (const NanoappUnload &unload : mNanoappUnloads) { |
| if (snprintf(buffer, kBufferSize, " %s id 0x%" PRIx64 " status %s\n", |
| formatLocalTime(unload.timestampMs).c_str(), unload.id, |
| unload.success ? "ok" : "fail") > 0) { |
| logs.append(buffer); |
| } |
| } |
| |
| logs.append("\nMessages to Nanoapps:\n"); |
| for (const NanoappMessage &msg : mMsgToNanoapp) { |
| if (snprintf(buffer, kBufferSize, |
| " %s to id 0x%" PRIx64 " size %zu status %s\n", |
| formatLocalTime(msg.timestampMs).c_str(), msg.id, |
| msg.sizeBytes, msg.success ? "ok" : "fail") > 0) { |
| logs.append(buffer); |
| } |
| } |
| |
| logs.append("\nMessages from Nanoapps:\n"); |
| for (const NanoappMessage &msg : mMsgFromNanoapp) { |
| if (snprintf(buffer, kBufferSize, " %s from id 0x%" PRIx64 " size %zu\n", |
| formatLocalTime(msg.timestampMs).c_str(), msg.id, |
| msg.sizeBytes) > 0) { |
| logs.append(buffer); |
| } |
| } |
| |
| logs.append("\nContext hub restarts:\n"); |
| for (const int64_t &ms : mContextHubRestarts) { |
| if (snprintf(buffer, kBufferSize, " %s\n", formatLocalTime(ms).c_str()) > |
| 0) { |
| logs.append(buffer); |
| } |
| } |
| |
| return logs; |
| } |
| |
| int64_t EventLogger::getTimeMs() const { |
| if (mNowMs.has_value()) { |
| return mNowMs.value(); |
| } |
| struct timespec now; |
| clock_gettime(CLOCK_REALTIME, &now); |
| return 1000 * now.tv_sec + static_cast<int64_t>(now.tv_nsec / 1e6); |
| } |
| |
| } // namespace aidl::android::hardware::contexthub |