514 lines
18 KiB
C++
514 lines
18 KiB
C++
|
|
/* Copyright Statement:
|
||
|
|
* *
|
||
|
|
* * This software/firmware and related documentation ("MediaTek Software") are
|
||
|
|
* * protected under relevant copyright laws. The information contained herein
|
||
|
|
* * is confidential and proprietary to MediaTek Inc. and/or its licensors.
|
||
|
|
* * Without the prior written permission of MediaTek inc. and/or its licensors,
|
||
|
|
* * any reproduction, modification, use or disclosure of MediaTek Software,
|
||
|
|
* * and information contained herein, in whole or in part, shall be strictly prohibited.
|
||
|
|
* *
|
||
|
|
* * MediaTek Inc. (C) 2016. All rights reserved.
|
||
|
|
* *
|
||
|
|
* * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
|
||
|
|
* * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
|
||
|
|
* * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
|
||
|
|
* * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
|
||
|
|
* * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
|
||
|
|
* * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
|
||
|
|
* * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
|
||
|
|
* * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
|
||
|
|
* * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
|
||
|
|
* * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
|
||
|
|
* * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
|
||
|
|
* * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
|
||
|
|
* * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
|
||
|
|
* * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
|
||
|
|
* * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
|
||
|
|
* * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
|
||
|
|
* * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
|
||
|
|
* * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
|
||
|
|
* *
|
||
|
|
* * The following software/firmware and/or related documentation ("MediaTek Software")
|
||
|
|
* * have been modified by MediaTek Inc. All revisions are subject to any receiver's
|
||
|
|
* * applicable license agreements with MediaTek Inc.
|
||
|
|
* */
|
||
|
|
|
||
|
|
#if defined(MTK_STACK_CONFIG_LOG) && (MTK_STACK_CONFIG_LOG == TRUE)
|
||
|
|
|
||
|
|
#define LOG_TAG "bt_log_file_controller"
|
||
|
|
|
||
|
|
#include "log_file_controller.h"
|
||
|
|
|
||
|
|
#include <errno.h>
|
||
|
|
#include <inttypes.h>
|
||
|
|
#include <sys/stat.h>
|
||
|
|
#include <sys/types.h>
|
||
|
|
#include <dirent.h>
|
||
|
|
|
||
|
|
#include <functional>
|
||
|
|
#include <set>
|
||
|
|
#include <thread>
|
||
|
|
|
||
|
|
#include <base/bind.h>
|
||
|
|
#include <base/files/file.h>
|
||
|
|
#include <base/files/file_util.h>
|
||
|
|
#include <base/logging.h>
|
||
|
|
#include <base/message_loop/message_loop.h>
|
||
|
|
#include <base/run_loop.h>
|
||
|
|
#include <base/sequenced_task_runner.h>
|
||
|
|
|
||
|
|
#include "log_tree_mgr.h"
|
||
|
|
#include "log_writer.h"
|
||
|
|
#include "logs_stats.h"
|
||
|
|
#include "osi/include/log.h"
|
||
|
|
#include "osi/include/thread.h"
|
||
|
|
#include "snoop_log_config.h"
|
||
|
|
#include "mtk_util.h"
|
||
|
|
|
||
|
|
namespace vendor {
|
||
|
|
namespace mediatek {
|
||
|
|
namespace bt {
|
||
|
|
namespace stack {
|
||
|
|
|
||
|
|
class LogFileBackupHelper {
|
||
|
|
public:
|
||
|
|
LogFileBackupHelper()
|
||
|
|
: last_logging_file_duplicated_count_(0) {}
|
||
|
|
~LogFileBackupHelper() = default;
|
||
|
|
|
||
|
|
bool StartNewOne(const std::string& file, LogWriter* log_writer) {
|
||
|
|
bool is_logging = log_writer->Open(file);
|
||
|
|
if (is_logging) {
|
||
|
|
LOG_DEBUG("%s: begin to logging %s",
|
||
|
|
__func__, file.c_str());
|
||
|
|
log_writer->AppendHeader();
|
||
|
|
}
|
||
|
|
return is_logging;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Append(const std::string& file, LogWriter* log_writer) {
|
||
|
|
bool is_ready = log_writer->AppendOpen(file);
|
||
|
|
if (is_ready) {
|
||
|
|
LOG_DEBUG("%s: be ready to append logging %s",
|
||
|
|
__func__, file.c_str());
|
||
|
|
}
|
||
|
|
return is_ready;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Backup(const std::string& file, LogWriter* log_writer) {
|
||
|
|
CHECK(log_writer);
|
||
|
|
log_writer->Close();
|
||
|
|
return Rename(file);
|
||
|
|
}
|
||
|
|
|
||
|
|
void UpdateLastLoggingFile(const std::string& file) {
|
||
|
|
if (!IsDuplicatedWithLastLoggingFile(file)) {
|
||
|
|
last_logging_file_duplicated_count_ = 0;
|
||
|
|
base::FilePath logging_file_path(file);
|
||
|
|
base::FilePath to_path = logging_file_path.RemoveFinalExtension();
|
||
|
|
last_logging_file_ = to_path;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
bool IsDuplicatedWithLastLoggingFile(const std::string& file) const {
|
||
|
|
base::FilePath file_path = RemoveExtension(file);
|
||
|
|
base::FilePath last_path = RemoveExtension(last_logging_file_.value());
|
||
|
|
return (last_path == file_path);
|
||
|
|
}
|
||
|
|
|
||
|
|
void AddRetryRenameFile(const std::string& file) {
|
||
|
|
renaming_files_.insert(file);
|
||
|
|
}
|
||
|
|
|
||
|
|
bool IsLeftFileNeedToRename() const {
|
||
|
|
return !renaming_files_.empty();
|
||
|
|
}
|
||
|
|
|
||
|
|
void RetryRename(LogFileTreeManager* files_mgr) {
|
||
|
|
for (const auto& it : renaming_files_) {
|
||
|
|
if (Rename(it)) {
|
||
|
|
renaming_files_.erase(it);
|
||
|
|
UpdateLastLoggingFile(it);
|
||
|
|
// files_mgr->AppendNewLogFileRecord(last_logging_file().value());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
std::string GenerateNewFileName(const std::string& file,
|
||
|
|
const std::string& suffix) {
|
||
|
|
base::FilePath to_path = RemoveExtension(file);
|
||
|
|
std::string padding =
|
||
|
|
std::to_string(++last_logging_file_duplicated_count_);
|
||
|
|
return (to_path.AddExtension(padding).AddExtension(suffix)).value();
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Rename(const std::string& file) const {
|
||
|
|
base::FilePath logging_file_path(file);
|
||
|
|
if (!base::PathExists(logging_file_path)) {
|
||
|
|
LOG_WARN("%s %s NOT exist!", __func__, file.c_str());
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
base::FilePath to_path = logging_file_path.RemoveFinalExtension();
|
||
|
|
// Do rename just after the file being created may cause rename hang
|
||
|
|
// which causes thread (join) quit timeout exception
|
||
|
|
// if (base::Move(logging_file_path, to_path)) {
|
||
|
|
LOG_INFO("%s try from %s to %s", __func__,
|
||
|
|
logging_file_path.value().c_str(), to_path.value().c_str());
|
||
|
|
if (!rename(logging_file_path.value().c_str(),
|
||
|
|
to_path.value().c_str())) {
|
||
|
|
LOG_WARN("%s from %s to %s", __func__,
|
||
|
|
logging_file_path.value().c_str(), to_path.value().c_str());
|
||
|
|
return true;
|
||
|
|
} else {
|
||
|
|
LOG_ERROR("%s failed to rename %s to %s, error(%s)", __func__,
|
||
|
|
logging_file_path.value().c_str(), to_path.value().c_str(),
|
||
|
|
strerror(errno));
|
||
|
|
return (errno == ENOENT) ? true : false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
base::FilePath last_logging_file() const {
|
||
|
|
return last_logging_file_;
|
||
|
|
}
|
||
|
|
|
||
|
|
private:
|
||
|
|
inline base::FilePath RemoveExtension(const std::string& file) const {
|
||
|
|
base::FilePath file_path(file);
|
||
|
|
base::FilePath to_path = file_path.RemoveFinalExtension();
|
||
|
|
to_path = to_path.RemoveExtension();
|
||
|
|
return to_path;
|
||
|
|
}
|
||
|
|
|
||
|
|
int last_logging_file_duplicated_count_;
|
||
|
|
base::FilePath last_logging_file_;
|
||
|
|
std::set<std::string> renaming_files_;
|
||
|
|
};
|
||
|
|
|
||
|
|
LogFileKeeper::LogFileKeeper(LogFileTreeManager* file_tree_mgr)
|
||
|
|
: file_tree_mgr_(file_tree_mgr),
|
||
|
|
log_writer_(LogWriter::CreateInstance(kBtHci)),
|
||
|
|
log_backup_helper_(new LogFileBackupHelper()) {}
|
||
|
|
|
||
|
|
LogFileKeeper::~LogFileKeeper() {
|
||
|
|
log_writer_.reset();
|
||
|
|
log_backup_helper_.reset();
|
||
|
|
}
|
||
|
|
|
||
|
|
bool LogFileKeeper::MakeDir(const base::FilePath &dir) {
|
||
|
|
if (base::PathExists(dir)) {
|
||
|
|
LOG_INFO("%s %s already exist.", __func__, dir.value().c_str());
|
||
|
|
return true;
|
||
|
|
} else {
|
||
|
|
bool is_done(false);
|
||
|
|
const uint8_t RETRY_TIMES(7);
|
||
|
|
uint8_t retry(RETRY_TIMES);
|
||
|
|
while (retry) {
|
||
|
|
if (_MakeDir(dir.value().c_str(), FILESYS_FOLDER_PERMISSION, FILESYS_USER, FILESYS_GROUP)) {
|
||
|
|
LOG_ERROR("%s mkdir for %s, error! %s",
|
||
|
|
__func__, dir.value().c_str(), strerror(errno));
|
||
|
|
} else {
|
||
|
|
is_done = true;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
retry--;
|
||
|
|
sleep(1);
|
||
|
|
}
|
||
|
|
return is_done;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
bool LogFileKeeper::StartLogging(const base::FilePath& dir) {
|
||
|
|
std::string logging_file = file_tree_mgr_->MakeLoggingFileName(dir.value());
|
||
|
|
bool is_logging =
|
||
|
|
log_backup_helper_->StartNewOne(logging_file, log_writer_.get());
|
||
|
|
if (is_logging) {
|
||
|
|
file_tree_mgr_->set_current_logging_file(logging_file);
|
||
|
|
}
|
||
|
|
return is_logging;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool LogFileKeeper::AppendLogging(const base::FilePath& file_path) {
|
||
|
|
if (!base::PathExists(file_path) || (nullptr == log_writer_)) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
bool is_logging =
|
||
|
|
log_backup_helper_->Append(file_path.value(), log_writer_.get());
|
||
|
|
if (is_logging) {
|
||
|
|
file_tree_mgr_->set_current_logging_file(file_path.value());
|
||
|
|
}
|
||
|
|
return is_logging;
|
||
|
|
}
|
||
|
|
|
||
|
|
ssize_t LogFileKeeper::LogData(void *parcel, size_t length) const {
|
||
|
|
CHECK(parcel);
|
||
|
|
return log_writer_->Write(parcel, length);
|
||
|
|
}
|
||
|
|
|
||
|
|
void LogFileKeeper::BackupLogFile(LogFileTreeManager* files_mgr) {
|
||
|
|
if (log_backup_helper_->IsLeftFileNeedToRename()) {
|
||
|
|
log_backup_helper_->RetryRename(files_mgr);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (log_backup_helper_->Backup(files_mgr->current_logging_file(),
|
||
|
|
log_writer_.get())) {
|
||
|
|
log_backup_helper_->UpdateLastLoggingFile(
|
||
|
|
files_mgr->current_logging_file());
|
||
|
|
// files_mgr->AppendNewLogFileRecord(
|
||
|
|
// log_backup_helper_->last_logging_file().value());
|
||
|
|
} else {
|
||
|
|
log_backup_helper_->AddRetryRenameFile(files_mgr->current_logging_file());
|
||
|
|
}
|
||
|
|
std::string new_file = files_mgr->MakeLoggingFileName(
|
||
|
|
files_mgr->current_logging_dir().value());
|
||
|
|
if (log_backup_helper_->IsDuplicatedWithLastLoggingFile(new_file)) {
|
||
|
|
new_file = log_backup_helper_->GenerateNewFileName(new_file,
|
||
|
|
files_mgr->GetCurrentLoggingFileSuffix());
|
||
|
|
LOG_INFO("%s gen new one is %s", __func__, new_file.c_str());
|
||
|
|
}
|
||
|
|
if (log_backup_helper_->StartNewOne(new_file, log_writer_.get())) {
|
||
|
|
files_mgr->set_current_logging_file(new_file);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void LogFileKeeper::StopLogging() {
|
||
|
|
LOG_INFO("%s", __func__);
|
||
|
|
log_writer_->Close();
|
||
|
|
log_backup_helper_->Rename(file_tree_mgr_->current_logging_file());
|
||
|
|
log_backup_helper_->UpdateLastLoggingFile(
|
||
|
|
file_tree_mgr_->current_logging_file());
|
||
|
|
// file_tree_mgr_->AppendNewLogFileRecord(
|
||
|
|
// log_backup_helper_->last_logging_file().value());
|
||
|
|
}
|
||
|
|
|
||
|
|
void LogFileKeeper::Update(LogStatistics *stat) {
|
||
|
|
CHECK(stat);
|
||
|
|
if (stat->current_loged_file_size() >
|
||
|
|
SnoopLogConfig::GetInstance()->GetMaxLogSizePerFile()) {
|
||
|
|
LOG_INFO("%s: current_loged_file_size_(%" PRId64 ") > "
|
||
|
|
"MaxLogSizePerFile(%" PRId64 ").",
|
||
|
|
__func__, stat->current_loged_file_size(),
|
||
|
|
SnoopLogConfig::GetInstance()->GetMaxLogSizePerFile());
|
||
|
|
BackupLogFile(file_tree_mgr_);
|
||
|
|
stat->UpdateCurrentLogedFileSize(0, false);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
class LogFileCleanRunner {
|
||
|
|
public:
|
||
|
|
LogFileCleanRunner() = default;
|
||
|
|
~LogFileCleanRunner() = default;
|
||
|
|
|
||
|
|
static int endsWith(std::string s,std::string sub);
|
||
|
|
static void Run(LogFileClearner* clearner, LogStatistics *stat);
|
||
|
|
};
|
||
|
|
|
||
|
|
int LogFileCleanRunner::endsWith(std::string s,std::string sub){
|
||
|
|
return s.rfind(sub)==(s.length()-sub.length())?1:0;
|
||
|
|
}
|
||
|
|
|
||
|
|
void LogFileCleanRunner::Run(LogFileClearner* clearner,
|
||
|
|
LogStatistics *logstat) {
|
||
|
|
CHECK(clearner);
|
||
|
|
CHECK(logstat);
|
||
|
|
// log file may changed by other program, refresh the actually total log size information here
|
||
|
|
logstat->UpdateTotalLogedSize(clearner->file_tree_mgr_->GetTotalLoggedSize(), false);
|
||
|
|
if(logstat->total_loged_size() < SnoopLogConfig::GetInstance()->GetMaxTotalLogsSize()){
|
||
|
|
LOG_INFO("%s: total_loged_size_(%" PRId64 ") < "
|
||
|
|
"MaxTotalLogsSize(%" PRId64 "). Not need delete",
|
||
|
|
__func__, logstat->total_loged_size(),
|
||
|
|
SnoopLogConfig::GetInstance()->GetMaxTotalLogsSize());
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
int64_t bytes_cleaned(0);
|
||
|
|
std::string oldest_dirpath = clearner->file_tree_mgr_->GetOldestLogDirRecord();
|
||
|
|
std::string current_dirpath = (clearner->file_tree_mgr_->current_logging_dir()).value();
|
||
|
|
if (0 == current_dirpath.compare(oldest_dirpath)) {
|
||
|
|
LOG_INFO("%s: Delete Dir equal current Dir: %s", __func__, current_dirpath.c_str());
|
||
|
|
struct dirent *dirp;
|
||
|
|
struct stat statbuf;
|
||
|
|
memset ( &statbuf, 0, sizeof(struct stat));
|
||
|
|
std::string delete_filepath;
|
||
|
|
std::string scan_filename;
|
||
|
|
std::string scan_filepath;
|
||
|
|
time_t firstTime = std::numeric_limits<time_t>::max();
|
||
|
|
off_t file_sizeb;
|
||
|
|
DIR *dp = opendir(current_dirpath.c_str());
|
||
|
|
|
||
|
|
if (NULL == dp){
|
||
|
|
LOG_ERROR("%s: Open dir failed", __func__);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
while((dirp = readdir(dp)) != NULL) {
|
||
|
|
// ignore . and ..
|
||
|
|
if (strcmp(".",dirp->d_name) == 0 || strcmp("..",dirp->d_name) == 0 ) {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
scan_filename = dirp->d_name;
|
||
|
|
scan_filepath = current_dirpath+'/'+scan_filename;
|
||
|
|
// get file information
|
||
|
|
if (-1 == lstat(scan_filepath.c_str(), &statbuf)){
|
||
|
|
LOG_ERROR("%s: stat file failed :%s", __func__, scan_filepath.c_str());
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
if (firstTime > statbuf.st_mtime ) {
|
||
|
|
LOG_DEBUG("%s: Temp delete file name:%s size(%" PRId64 ")", __func__, scan_filepath.c_str(), statbuf.st_size);
|
||
|
|
delete_filepath = scan_filepath;
|
||
|
|
firstTime = statbuf.st_mtime;
|
||
|
|
file_sizeb = statbuf.st_size;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (!delete_filepath.empty()) {
|
||
|
|
// check if it deletes current file.
|
||
|
|
if(endsWith(delete_filepath, ".curf")) {
|
||
|
|
LOG_WARN("%s: You will delete current file %s ", __func__, delete_filepath.c_str());
|
||
|
|
closedir(dp);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if (base::DeleteFile(base::FilePath(delete_filepath), true)) {
|
||
|
|
LOG_WARN("%s: path %s size(%" PRId64 ") is deleted.", __func__,
|
||
|
|
delete_filepath.c_str(), int64_t(file_sizeb));
|
||
|
|
bytes_cleaned += int64_t(file_sizeb);
|
||
|
|
}
|
||
|
|
int64_t size = logstat->total_loged_size()-bytes_cleaned;
|
||
|
|
logstat->UpdateTotalLogedSize(size > 0 ? size : 0, false);
|
||
|
|
LOG_INFO("%s: total_loged_size_(%" PRId64 ") "
|
||
|
|
"MaxTotalLogsSize(%" PRId64 ").",
|
||
|
|
__func__, logstat->total_loged_size(),
|
||
|
|
SnoopLogConfig::GetInstance()->GetMaxTotalLogsSize());
|
||
|
|
closedir(dp);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
LOG_ERROR("%s: No file in the dir:%s", __func__, current_dirpath.c_str());
|
||
|
|
closedir(dp);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
while (0 != current_dirpath.compare(oldest_dirpath)) {
|
||
|
|
base::FilePath file_path(clearner->file_tree_mgr_->GetOldestLogDirRecord());
|
||
|
|
if (base::PathExists(file_path)) {
|
||
|
|
int64_t file_size = base::ComputeDirectorySize(file_path);
|
||
|
|
if (base::DeleteFile(file_path, true)) {
|
||
|
|
LOG_WARN("%s: path %s size(%" PRId64 ") is deleted.", __func__,
|
||
|
|
file_path.value().c_str(), file_size);
|
||
|
|
bytes_cleaned += file_size;
|
||
|
|
}
|
||
|
|
clearner->file_tree_mgr_->ReleaseOldestLogDirRecord();
|
||
|
|
oldest_dirpath = clearner->file_tree_mgr_->GetOldestLogDirRecord();
|
||
|
|
if (bytes_cleaned >= clearner->bytes_to_be_cleaned_) {
|
||
|
|
int64_t size = logstat->total_loged_size()-bytes_cleaned;
|
||
|
|
logstat->UpdateTotalLogedSize(size > 0 ? size : 0, false);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
// To avoid block others too much time when delete huge files
|
||
|
|
std::this_thread::yield();
|
||
|
|
} else
|
||
|
|
clearner->file_tree_mgr_->ReleaseOldestLogDirRecord();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// It is shamed base::Thread with adaption issue with native exception
|
||
|
|
// Therefore, have to be back to use osi/thread
|
||
|
|
class RecycleThreadImpl {
|
||
|
|
public:
|
||
|
|
RecycleThreadImpl()
|
||
|
|
: thread_(nullptr),
|
||
|
|
message_loop_(nullptr),
|
||
|
|
run_loop_(nullptr) {
|
||
|
|
thread_ = thread_new("bt_log_cleaner");
|
||
|
|
if (!thread_) {
|
||
|
|
LOG_ERROR("%s unable to create thread.", __func__);
|
||
|
|
} else {
|
||
|
|
if (!thread_set_priority(thread_, 0)) {
|
||
|
|
LOG_ERROR("%s unable to make thread priority.", __func__);
|
||
|
|
}
|
||
|
|
thread_post(thread_, RunMessageLoop, this);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
~RecycleThreadImpl() {
|
||
|
|
if (message_loop_ != nullptr) {
|
||
|
|
message_loop_->task_runner()->PostTask(
|
||
|
|
FROM_HERE, run_loop_->QuitClosure());
|
||
|
|
}
|
||
|
|
|
||
|
|
if (thread_) {
|
||
|
|
thread_stop(thread_);
|
||
|
|
thread_join(thread_);
|
||
|
|
thread_free(thread_);
|
||
|
|
thread_ = nullptr;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void PostTask(LogFileClearner* clearner,
|
||
|
|
LogStatistics *stat) {
|
||
|
|
if (message_loop_ != nullptr) {
|
||
|
|
message_loop_->task_runner()->PostTask(FROM_HERE,
|
||
|
|
base::Bind(&LogFileCleanRunner::Run, clearner, stat));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private:
|
||
|
|
static void RunMessageLoop(void* context) {
|
||
|
|
RecycleThreadImpl* impl = static_cast<RecycleThreadImpl*>(context);
|
||
|
|
{
|
||
|
|
impl->message_loop_ = new base::MessageLoop();
|
||
|
|
impl->run_loop_ = new base::RunLoop();
|
||
|
|
}
|
||
|
|
|
||
|
|
impl->run_loop_->Run();
|
||
|
|
|
||
|
|
{
|
||
|
|
delete impl->message_loop_;
|
||
|
|
impl->message_loop_ = nullptr;
|
||
|
|
delete impl->run_loop_;
|
||
|
|
impl->run_loop_ = nullptr;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
thread_t* thread_;
|
||
|
|
base::MessageLoop* message_loop_;
|
||
|
|
base::RunLoop* run_loop_;
|
||
|
|
};
|
||
|
|
|
||
|
|
LogFileClearner::LogFileClearner(LogFileTreeManager* file_tree_mgr,
|
||
|
|
int64_t bytes_to_be_cleaned)
|
||
|
|
: file_tree_mgr_(file_tree_mgr),
|
||
|
|
bytes_to_be_cleaned_(bytes_to_be_cleaned),
|
||
|
|
thread_(new RecycleThreadImpl()),
|
||
|
|
cleaner_trigger_cnt_(0) {}
|
||
|
|
|
||
|
|
LogFileClearner::~LogFileClearner() {}
|
||
|
|
|
||
|
|
void LogFileClearner::Recycle(LogStatistics *stat) {
|
||
|
|
if (thread_ && !file_tree_mgr_->IsLogDirRecordEmpty()) {
|
||
|
|
thread_->PostTask(this, stat);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void LogFileClearner::Update(LogStatistics *stat) {
|
||
|
|
CHECK(stat);
|
||
|
|
// prevent try clean for each packet
|
||
|
|
if (cleaner_trigger_cnt_ > 1000) {
|
||
|
|
cleaner_trigger_cnt_ = 0;
|
||
|
|
if (stat->total_loged_size() >
|
||
|
|
SnoopLogConfig::GetInstance()->GetMaxTotalLogsSize()) {
|
||
|
|
LOG_INFO("%s: total_loged_size_(%" PRId64 ") > "
|
||
|
|
"MaxTotalLogsSize(%" PRId64 ").",
|
||
|
|
__func__, stat->total_loged_size(),
|
||
|
|
SnoopLogConfig::GetInstance()->GetMaxTotalLogsSize());
|
||
|
|
Recycle(stat);
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
cleaner_trigger_cnt_++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
} // namespace stack
|
||
|
|
} // namespace bt
|
||
|
|
} // namespace mediatek
|
||
|
|
} // namespace vendor
|
||
|
|
|
||
|
|
#endif
|