blob: 707cedeb9b84389e8477d124cff9126645f8fc0e [file]
/*
* Copyright 2023 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 "le_audio_log_history.h"
#include <bluetooth/log.h>
#include <cstdint>
#include <memory>
#include <string>
#include "common/circular_buffer.h"
#include "common/strings.h"
#include "main/shim/dumpsys.h"
#include "os/log.h"
#include "osi/include/osi.h"
#include "osi/include/properties.h"
using namespace bluetooth;
constexpr size_t kMaxLogSize = 255;
constexpr size_t kLeAudioLogHistoryBufferSize = 200;
class TimestampedStringCircularBuffer
: public bluetooth::common::TimestampedCircularBuffer<std::string> {
public:
explicit TimestampedStringCircularBuffer(size_t size)
: bluetooth::common::TimestampedCircularBuffer<std::string>(size) {}
void Push(const std::string& s) {
bluetooth::common::TimestampedCircularBuffer<std::string>::Push(
s.substr(0, kMaxLogSize));
}
template <typename... Args>
void Push(Args... args) {
char buf[kMaxLogSize];
std::snprintf(buf, sizeof(buf), args...);
bluetooth::common::TimestampedCircularBuffer<std::string>::Push(
std::string(buf));
}
};
class LeAudioLogHistoryImpl;
LeAudioLogHistoryImpl* instance;
constexpr size_t kMaxLogHistoryTagLength = 14;
constexpr size_t kMaxLogHistoryMsgLength = 44;
const std::string kTimeFormat("%Y-%m-%d %H:%M:%S");
using Record = bluetooth::common::TimestampedEntry<std::string>;
class LeAudioLogHistoryImpl : public LeAudioLogHistory {
public:
~LeAudioLogHistoryImpl(void) { history_.reset(); }
LeAudioLogHistoryImpl(void) {
history_ = std::make_shared<TimestampedStringCircularBuffer>(
kLeAudioLogHistoryBufferSize);
log::assert_that(history_ != nullptr, "assert failed: history_ != nullptr");
history_->Push(std::string("Initialized le_audio history"));
}
void Dump(int fd) {
#define DUMPSYS_TAG "::le_audio"
LOG_DUMPSYS_TITLE(fd, DUMPSYS_TAG);
if (history_ == nullptr) {
return;
}
std::vector<Record> history = history_->Pull();
for (auto& record : history) {
time_t then = record.timestamp / 1000;
struct tm tm;
localtime_r(&then, &tm);
auto s2 = bluetooth::common::StringFormatTime(kTimeFormat, tm);
LOG_DUMPSYS(fd, " %s.%03u %s", s2.c_str(),
static_cast<unsigned int>(record.timestamp % 1000),
record.entry.c_str());
}
#undef DUMPSYS_TAG
}
void AddLogHistory(const std::string& tag, int group_id,
const RawAddress& addr, const std::string& msg,
const std::string& extra) {
add_logs_history_common(tag, group_id, addr, msg, extra);
}
void AddLogHistory(const std::string& tag, int group_id,
const RawAddress& addr, const std::string& msg) {
AddLogHistory(tag, group_id, addr, msg, std::string());
}
private:
void add_logs_history_common(const std::string& tag, int group_id,
const RawAddress& addr, const std::string& msg,
const std::string& extra) {
if (history_ == nullptr) {
log::error(
"LeAudioLogHistory has not been constructed or already destroyed !");
return;
}
history_->Push("%-*s GID %-3d %-*s: %-22s %s", kMaxLogHistoryTagLength,
tag.substr(0, kMaxLogHistoryTagLength).c_str(), group_id,
kMaxLogHistoryMsgLength,
msg.substr(0, kMaxLogHistoryMsgLength).c_str(),
ADDRESS_TO_LOGGABLE_CSTR(addr), extra.c_str());
}
std::shared_ptr<TimestampedStringCircularBuffer> history_{nullptr};
};
LeAudioLogHistory* LeAudioLogHistory::Get(void) {
if (instance) {
return instance;
}
instance = new LeAudioLogHistoryImpl();
return instance;
}
void LeAudioLogHistory::DebugDump(int fd) {
if (instance) {
instance->Dump(fd);
}
}
void LeAudioLogHistory::Cleanup(void) {
if (!instance) {
return;
}
auto ptr = instance;
instance = nullptr;
delete ptr;
}