* Copyright (c) 2026 Huawei Device Co., Ltd.
* 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 "timer_database_monitor.h"
#include <chrono>
#ifdef RDB_ENABLE
#include "timer_database.h"
#endif
#include "cjson_helper.h"
#include "time_common.h"
#include "time_sysevent.h"
namespace OHOS {
namespace MiscServices {
using namespace std::chrono;
namespace {
constexpr int64_t DB_SIZE_BASELINE = 10 * 1024 * 1024;
constexpr int CHECK_INTERVAL_SECONDS = 43200;
constexpr int TOP_N = 10;
}
TimerDatabaseMonitor::TimerDatabaseMonitor() : running_(false) {}
TimerDatabaseMonitor::~TimerDatabaseMonitor()
{
Stop();
}
TimerDatabaseMonitor &TimerDatabaseMonitor::GetInstance()
{
static TimerDatabaseMonitor instance;
return instance;
}
void TimerDatabaseMonitor::Start()
{
{
std::lock_guard<std::mutex> lock(mutex_);
if (running_) {
return;
}
running_ = true;
}
monitorThread_.reset(new std::thread([this] { this->MonitorLoop(); }));
TIME_HILOGI(TIME_MODULE_SERVICE, "TimerDatabaseMonitor started");
}
void TimerDatabaseMonitor::Stop()
{
{
std::lock_guard<std::mutex> lock(mutex_);
if (!running_) {
return;
}
running_ = false;
}
cv_.notify_one();
if (monitorThread_ && monitorThread_->joinable()) {
monitorThread_->join();
}
TIME_HILOGI(TIME_MODULE_SERVICE, "TimerDatabaseMonitor stopped");
}
void TimerDatabaseMonitor::MonitorLoop()
{
pthread_setname_np(pthread_self(), "timer_db_monitor");
std::unique_lock<std::mutex> lock(mutex_);
while (running_) {
cv_.wait_for(lock, std::chrono::seconds(CHECK_INTERVAL_SECONDS),
[this] { return !running_; });
if (!running_) {
break;
}
lock.unlock();
CheckDatabaseAndReport();
lock.lock();
}
}
void TimerDatabaseMonitor::CheckDatabaseAndReport()
{
#ifdef RDB_ENABLE
auto &db = TimeDatabase::GetInstance();
#else
auto &db = CjsonHelper::GetInstance();
#endif
TimerDbSizeInfo sizeInfo = db.GetDatabaseSizeDetail();
int64_t dbSize = sizeInfo.GetTotalSize();
TIME_HILOGI(TIME_MODULE_SERVICE,
"TimerDB check: size=%{public}lld bytes", static_cast<long long>(dbSize));
if (dbSize <= DB_SIZE_BASELINE) {
return;
}
int32_t recordCount = db.GetTotalRecordCount();
auto topApps = db.GetTopApps(TOP_N);
std::string topAppInfo = "";
for (const auto &info : topApps) {
if (!topAppInfo.empty()) {
topAppInfo += ";";
}
topAppInfo += info.bundleName + ":" + info.timerName + ":" + std::to_string(info.count);
}
TimerDatabaseOverBaselineReporter(sizeInfo, recordCount, topAppInfo);
TIME_HILOGW(TIME_MODULE_SERVICE,
"TimerDB over baseline! size=%{public}lld, count=%{public}d, topApps=%{public}s",
static_cast<long long>(dbSize), recordCount, topAppInfo.c_str());
}
}
}