constexpr const char kPathUnitedService[] = "/usr/share/united-service/";
constexpr const char kConf[] = "/conf/";
+bool ComparePriority(const std::pair<std::string, unsigned int>& pair1,
+ const std::pair<std::string, unsigned int>& pair2) {
+ return pair1.second > pair2.second;
+}
+
+std::string ServiceStateToString(tizen_base::Service::State state) {
+ switch(state) {
+ case tizen_base::Service::State::Initialized:
+ return std::string("Initialized");
+ case tizen_base::Service::State::Created:
+ return std::string("Created");
+ case tizen_base::Service::State::Running:
+ return std::string("Running");
+ case tizen_base::Service::State::Destroyed:
+ return std::string("Destroyed");
+ }
+ return "";
+}
+
+ static const std::string kTagServiceLoader = "service-loader";
+ static const std::string kWatchdogSec = kTagServiceLoader + ":watchdogsec";
+ static const std::string kCpuTimeSec = kTagServiceLoader + ":cputimesec";
+ static const std::string kMemoryMonitor = kTagServiceLoader + ":memorymonitor";
+ static const std::string kCpuMonitor = kTagServiceLoader + ":cpumonitor";
+ static const std::string kBacktrace = kTagServiceLoader + ":backtrace";
+
} // namespace
namespace tizen_base {
--- /dev/null
- _W("(PSS %-4ld kb) %s\n", pss, libinfo.c_str());
+ /*
+ * Copyright (c) 2025 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 "inspector.hh"
+ #include "cpu_time.hh"
+
+ #include <filesystem>
+ #include <string>
+ #include <iostream>
+ #include <fstream>
+
+ #include <aul_backtrace.h>
+
+ #include <sys/ptrace.h>
+ #include <sys/wait.h>
+
+ namespace tizen_base::Inspector {
+ void PrintBacktrace(pid_t tid, std::string name) {
+ int ret = aul_send_backtrace_request(tid);
+ if (ret != AUL_R_OK) {
+ _E("Fail to print bt for %d (%d)", tid, ret);
+ }
+ }
+
+ void MemoryMonitor(std::string loader_name) {
+ if (loader_name.empty()) {
+ _E("Invalid parameter");
+ return;
+ }
+
+ std::filesystem::path smaps_path = "/proc/" + std::to_string(getpid()) +
+ "/smaps";
+ if (!std::filesystem::exists(smaps_path)) {
+ _E("%s does not exist", smaps_path.c_str());
+ return;
+ }
+
+ std::ifstream file(smaps_path);
+ if (!file) {
+ _E("Failed to open %s", smaps_path.c_str());
+ return;
+ }
+
+ _W("[Loader %d(%s)] Memory monitor", getpid(), loader_name.c_str());
+
+ uint64_t total_pss = 0;
+ std::string line;
+ std::string libinfo;
+ while (std::getline(file, line)) {
+ std::stringstream stream(line);
+ std::string tag;
+
+ if (stream >> tag) {
+ if (!tag.ends_with(":")) {
+ std::string area = std::move(tag);
+ std::string perm;
+ std::string dummy;
+ std::string filename;
+ stream >> perm;
+ stream >> dummy >> dummy >> dummy;
+ stream >> filename;
+
+ libinfo = area + " " + perm + " " + filename;
+
+ } else if (tag == "Pss:") {
+ uint64_t pss = 0;
+ stream >> pss;
+ total_pss += pss;
+ if (pss > 0) {
- _W("[%d] Total PSS %-4ld kB", getpid(), total_pss);
++ _W("(PSS %-4llu kb) %s\n", pss, libinfo.c_str());
+ }
+ }
+ }
+ }
+
++ _W("[%d] Total PSS %-4llu kB", getpid(), total_pss);
+ return;
+ }
+
+ void CpuMonitor(std::shared_ptr<CpuTime> cpu_time) {
+ double cpu_usage = cpu_time->CalculateCpuUsage();
+ _W("[%d:%d] CPU usage = %.4f%%", getpid(), cpu_time->GetTid(), cpu_usage);
+ return;
+ }
+ } // namespace tizen_base
--- /dev/null
- _I("[%d/%ld] %s Interval",
+ /*
+ * Copyright (c) 2025 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 "watchdog_manager.hh"
+ #include "log_private.hh"
+
+ namespace tizen_base {
+
+ WatchdogManager& WatchdogManager::GetInst() {
+ static WatchdogManager inst;
+ return inst;
+ }
+
+ WatchdogManager::~WatchdogManager() {
+ int ret = tizen_core_task_destroy(task_);
+ if (ret != TIZEN_CORE_ERROR_NONE)
+ _E("Cannot destroy watchdog task");
+ }
+
+ bool WatchdogManager::Init(std::shared_ptr<WatchdogConf> conf) {
+ if (init_)
+ _W("Reinitialize manager instance");
+
+ conf_ = std::move(conf);
+ int ret = tizen_core_task_create("watchdog", true, &task_);
+ if (ret != TIZEN_CORE_ERROR_NONE) {
+ _E("Cannot create watchdog task(%d)", ret);
+ return false;
+ }
+
+ ret = tizen_core_task_get_tizen_core(task_, &core_);
+ if (ret != TIZEN_CORE_ERROR_NONE) {
+ _E("Cannot find core from watchdog task(%d)", ret);
+ return false;
+ }
+
+ if (!StartWatchdog())
+ return false;
+
+ _D("Manager instance initialied done");
+ init_ = true;
+ return true;
+ }
+
+ void WatchdogManager::RegisterService(pid_t tid, std::string name,
+ tizen_core_h core) {
+ _I("Loader(%s) register tid %d(%s)",
+ conf_->GetLoaderName().c_str(), tid, name.c_str());
+ std::shared_ptr<CpuTime> cputime = nullptr;
+ std::shared_ptr<Heartbeat> heartbeat = nullptr;
+
+ if (conf_->IsCpuMonitor())
+ cputime = std::make_shared<CpuTime>(tid);
+
+ if (conf_->GetWatchdogSec() > 0)
+ heartbeat = std::make_shared<Heartbeat>(tid, core);
+
+ auto ctx = WatchdogContext::Builder()
+ .SetLoaderName(conf_->GetLoaderName())
+ .SetCpuMonitorFlag(conf_->IsCpuMonitor())
+ .SetCpuTime(cputime)
+ .SetHeartbeat(heartbeat)
+ .SetServiceName(std::move(name))
+ .SetTid(std::move(tid))
+ .SetMemoryMonitorFlag(conf_->IsMemoryMonitor())
+ .SetBacktraceFlag(conf_->IsBacktrace())
+ .Build();
+
+ std::unique_lock<std::mutex> lock(context_list_mutex_);
+ contexts_.emplace_back(std::move(ctx));
+ }
+
+ void WatchdogManager::UnregisterService(pid_t tid) {
+ std::unique_lock<std::mutex> lock(context_list_mutex_);
+ int ret = contexts_.remove_if([tid](auto context) {
+ return context->GetTid() == tid;
+ });
+
+ if (ret == 1)
+ _I("Loader(%s) unregister tid %d", conf_->GetLoaderName().c_str(), tid);
+ else
+ _E("Loader(%s) unregister tid %d return %d",
+ conf_->GetLoaderName().c_str(), tid, ret);
+ }
+
+ void WatchdogManager::Interval() {
+ std::unique_lock<std::mutex> lock(context_list_mutex_);
+ int count = 1;
+ for (auto& context : contexts_) {
++ _I("[%d/%u] %s Interval",
+ count++, contexts_.size(), context->GetServiceName().c_str());
+
+ if (!context->CpuTimeInterval())
+ _W("Failed to update CpuTime of tid %d", context->GetTid());
+
+ if (!context->HeartbeatInterval()) {
+ _E("Failed to verify Heartbeat of tid %d", context->GetTid());
+ context->OnWatchdogTimeout();
+ }
+ }
+ }
+
+ bool WatchdogManager::StartWatchdog() {
+ int ret = 0;
+ tizen_core_source_h oneshot_source;
+
+ if (conf_->GetWatchdogSec() == 0) {
+ _W("Watchdog is disabled (WatchdogSec 0)");
+ return true;
+ }
+
+ // Initial logging
+ ret = tizen_core_add_idle_job(core_, [](void* user_data) -> bool {
+ _I("Watchdog Manager Job Thread %d", gettid());
+ return false;
+ }, nullptr, &oneshot_source);
+ if (ret != TIZEN_CORE_ERROR_NONE) {
+ _E("Cannot add idle job to watchdog %d", ret);
+ return false;
+ }
+
+ // Interval
+ ret = tizen_core_add_timer(core_, conf_->GetWatchdogSec() * 1000,
+ [](void* user_data) -> bool {
+ WatchdogManager::GetInst().Interval();
+ return true;
+ }, nullptr, &source_);
+ if (ret != TIZEN_CORE_ERROR_NONE) {
+ _E("Cannot add watchdog interval %d", ret);
+ return false;
+ }
+
+ // Run
+ ret = tizen_core_task_run(task_);
+ if (ret != TIZEN_CORE_ERROR_NONE) {
+ _E("Cannot run watchdog task %d", ret);
+ return false;
+ }
+
+ return true;
+ }
+
+ bool WatchdogManager::StopWatchdog() {
+ int ret = 0;
+ int result = true;
+
+ ret = tizen_core_remove_source(core_, source_);
+ if (ret != TIZEN_CORE_ERROR_NONE) {
+ _E("Cannot Stop Watchdog Monitor %d", ret);
+ result = false;
+ }
+
+ return result;
+ }
+
+ } // namespace tizen_base