amd killed an app that had been blocked for a long time for debugging purposes with abort.
This patch reduces the frequency of crash by modifying these parts to print backtrace and cpu usage rate periodically.
Change-Id: I405eadc72602a2be025b8d041676c1e7f7dc3edd
Signed-off-by: Changgyu Choi <changyu.choi@samsung.com>
User=app_fw
Group=app_fw
SmackProcessLabel=System
-Capabilities=cap_setuid,cap_setgid,cap_mac_admin,cap_kill,cap_dac_override,cap_sys_admin,cap_fowner=i
+Capabilities=cap_setuid,cap_setgid,cap_mac_admin,cap_kill,cap_dac_override,cap_sys_admin,cap_fowner,cap_sys_ptrace=i
SecureBits=keep-caps
Type=notify
EnvironmentFile=/run/tizen-system-env
LIB_SIGNAL_SRCS)
AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/socket
LIB_SOCKET_SRCS)
+AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/startup_monitor
+ LIB_STARTUP_MONITOR_SRCS)
ADD_LIBRARY(${TARGET_LIB_AMD} SHARED
${LIB_SRCS}
${LIB_RES_INFO_SRCS}
${LIB_SIGNAL_SRCS}
${LIB_SOCKET_SRCS}
+ ${LIB_STARTUP_MONITOR_SRCS}
)
SET_TARGET_PROPERTIES(${TARGET_LIB_AMD} PROPERTIES SOVERSION ${MAJORVER})
SET_TARGET_PROPERTIES(${TARGET_LIB_AMD} PROPERTIES VERSION ${FULLVER})
}
AppStatus::~AppStatus() {
- if (dying_timer_ != 0)
- g_source_remove(dying_timer_);
+ if (dying_timer_ != nullptr)
+ tizen_core_source_destroy(dying_timer_);
- if (startup_timer_ != 0)
- g_source_remove(startup_timer_);
+ if (startup_timer_ != nullptr)
+ tizen_core_source_destroy(startup_timer_);
}
-gboolean AppStatus::DyingTimeoutHandler(gpointer data) {
+bool AppStatus::DyingTimeoutHandler(void* data) {
auto* app_status = static_cast<AppStatus*>(data);
- app_status->dying_timer_ = 0;
+ app_status->dying_timer_ = nullptr;
app_status->event_listener_->OnDyingTimeout(app_status);
- return G_SOURCE_REMOVE;
+ return false;
}
void AppStatus::SetDyingEvent() {
- if (dying_timer_ != 0) {
+ if (dying_timer_ != nullptr) {
_E("Already set event");
return;
}
return;
}
- dying_timer_ =
- g_timeout_add_seconds(DYING_TIMEOUT, DyingTimeoutHandler, this);
- if (dying_timer_ == 0) {
+ tizen_core_h core = nullptr;
+ int ret = tizen_core_find("main", &core);
+ if (ret != TIZEN_CORE_ERROR_NONE) {
+ _E("tizen_core_find() is failed. error(%d)", ret);
+ return;
+ }
+
+ ret = tizen_core_add_timer(core, DYING_TIMEOUT * 1000, DyingTimeoutHandler,
+ this, &dying_timer_);
+ if (ret != TIZEN_CORE_ERROR_NONE) {
_E("Failed to set timeout callback");
return;
}
}
void AppStatus::SetStartupTimer() {
- if (startup_timer_ != 0)
+ if (startup_timer_ != nullptr)
return;
- startup_timer_ = g_timeout_add_seconds(STARTUP_TIMEOUT,
- +[](gpointer data) -> gboolean {
- auto* app_status = static_cast<AppStatus*>(data);
- if (!app_status->event_listener_->OnStartupTimeout(app_status)) {
- app_status->startup_timer_ = 0;
- return G_SOURCE_REMOVE;
- }
+ tizen_core_h core = nullptr;
+ int ret = tizen_core_find("main", &core);
+ if (ret != TIZEN_CORE_ERROR_NONE) {
+ _E("tizen_core_find() is failed. error(%d)", ret);
+ return;
+ }
- return G_SOURCE_CONTINUE;
- }, this);
+ tizen_core_source_h source = nullptr;
+ ret = tizen_core_add_timer(core, STARTUP_TIMEOUT * 1000,
+ +[](void* user_data) -> bool {
+ auto* app_status = static_cast<AppStatus*>(user_data);
+ if (!app_status->event_listener_->OnStartupTimeout(app_status))
+ app_status->UnsetStartupTimer();
+
+ return true;
+ }, this, &source);
+ if (ret != TIZEN_CORE_ERROR_NONE) {
+ _E("tizen_core_add_timer() is failed. error(%d)", ret);
+ return;
+ }
- if (startup_timer_ == 0) {
- _E("Failed to set timeout callback");
+ startup_timer_ = source;
+ aul_cpu_times_h cpu_times = nullptr;
+ ret = aul_cpu_times_create(pid_, &cpu_times);
+ if (ret != AUL_R_OK) {
+ _E("Failed to create cpu times handle");
return;
}
+
+ aul_cpu_times_update(cpu_times);
+ cpu_times_.reset(cpu_times, aul_cpu_times_destroy);
}
void AppStatus::UnsetStartupTimer() {
- if (startup_timer_ == 0)
+ if (startup_timer_ == nullptr)
return;
- g_source_remove(startup_timer_);
- startup_timer_ = 0;
+ cpu_times_.reset();
+ tizen_core_source_destroy(startup_timer_);
+ startup_timer_ = nullptr;
}
const AppInfo* AppStatus::GetAppInfo() const {
int AppStatus::GetLatestCmd() const { return latest_cmd_; }
+std::shared_ptr<std::remove_pointer_t<aul_cpu_times_h>> AppStatus::GetCpuTimes()
+ const {
+ return cpu_times_;
+}
+
} // namespace amd
#ifndef LIB_APP_STATUS_APP_STATUS_HH_
#define LIB_APP_STATUS_APP_STATUS_HH_
+#include <aul_cpu_monitor.h>
#include <glib.h>
+#include <tizen_core.h>
#include <memory>
#include <string>
void SetLatestCmd(int cmd);
int GetLatestCmd() const;
+ std::shared_ptr<std::remove_pointer_t<aul_cpu_times_h>> GetCpuTimes() const;
+
private:
friend class AppStatusManager;
- static gboolean DyingTimeoutHandler(gpointer user_data);
+ static bool DyingTimeoutHandler(void* user_data);
unsigned int request_id_;
std::string appid_;
IEvent* event_listener_;
int timestamp_ = 0;
int fg_count_ = 0;
- guint dying_timer_ = 0;
- guint startup_timer_ = 0;
+ tizen_core_source_h dying_timer_ = nullptr;
+ tizen_core_source_h startup_timer_ = nullptr;
bool socket_exists_ = false;
bool starting_ = false;
bool exiting_ = false;
int64_t start_time_; /* start timestamp millisecond */
int delay_count_ = 0;
int latest_cmd_ = 0;
+ std::shared_ptr<std::remove_pointer_t<aul_cpu_times_h>> cpu_times_;
};
} // namespace amd
#include "lib/app_status/app_status_manager.hh"
#include <aul.h>
+#include <aul_backtrace.h>
#include <aul_cmd.h>
+#include <aul_cpu_monitor.h>
#include <aul_proc.h>
#include <aul_sock.h>
#include <bundle.h>
return WCOREDUMP(status);
}
+class BacktraceJob : public Worker::Job {
+ public:
+ explicit BacktraceJob(pid_t pid,
+ std::shared_ptr<std::remove_pointer_t<aul_cpu_times_h>> cpu_times)
+ : pid_(pid), cpu_times_(std::move(cpu_times)) {}
+ ~BacktraceJob() override = default;
+
+ void Do() override {
+ int ret = aul_backtrace_print(pid_);
+ if (ret != 0)
+ _E("aul_backtrace_print() failed. ret(%d)", ret);
+
+ if (!cpu_times_)
+ return;
+
+ aul_cpu_times_update(cpu_times_.get());
+ double cpu_usage = 0.0f;
+ aul_cpu_monitor_get_cpu_usage(cpu_times_.get(), &cpu_usage);
+ }
+
+ private:
+ pid_t pid_;
+ std::shared_ptr<std::remove_pointer_t<aul_cpu_times_h>> cpu_times_;
+};
+
} // namespace
void AppStatusManager::OnDyingTimeout(AppStatus* app_status) {
app_status->GetAppID().c_str(), app_status->GetPID(),
app_status->GetDelayCount());
- if (app_status->GetDelayCount() >= 10) {
+ if (app_status->GetDelayCount() >= 100) {
_E("App(%s[%d]) startup signal has not been received.",
app_status->GetAppID().c_str(), app_status->GetPID());
amd::AppStatusManager::GetInst().Update(app_status->shared_from_this(),
return false;
}
+ if (app_status->GetDelayCount() % 5 == 0) {
+ backtrace_worker_->Post(
+ std::make_shared<BacktraceJob>(app_status->GetPID(), app_status->cpu_times_));
+ }
+
return true;
}
AddVconfInitTimer();
_noti_listen(AMD_NOTI_MSG_LAUNCH_PREPARE_END, OnLaunchPrepareEnd);
app_status_dao_.reset(new AppStatusDaoImpl());
+ backtrace_worker_.reset(new Worker("Backtrace+"));
RunThread();
+
disposed_ = false;
return 0;
}
int AppStatusManager::Finish() {
if (disposed_) return 0;
+ backtrace_worker_.reset();
queue_.Push(std::make_shared<AppResult>(true));
thread_.join();
#include "lib/app_status/app_status.hh"
#include "lib/app_status/app_status_dao.hh"
#include "lib/app_status/pkg_status.hh"
+#include "lib/common/worker.hh"
#include "lib/launchpad/launchpad.hh"
#include "lib/launch/launch_context.hh"
tizen_base::SharedQueue<std::shared_ptr<AppResult>> queue_;
std::unordered_map<uid_t, std::unordered_map<std::string, int>>
crash_count_map_;
+ std::unique_ptr<Worker> backtrace_worker_;
};
} // namespace amd
--- /dev/null
+/*
+ * Copyright (c) 2024 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 "lib/common/worker.hh"
+
+#include <utility>
+
+#include "lib/common/exception.hh"
+#include "lib/common/log_private.hh"
+
+namespace amd {
+
+Worker::Worker(std::string name) : name_(std::move(name)) {
+ int ret = tizen_core_task_create(name_.c_str(), true, &task_);
+ if (ret != TIZEN_CORE_ERROR_NONE) {
+ _E("tizen_core_task_create() is failed. error=%d", ret);
+ THROW(ret);
+ }
+
+ tizen_core_task_get_tizen_core(task_, &core_);
+ tizen_core_task_run(task_);
+}
+
+Worker::~Worker() {
+ bool running = false;
+ tizen_core_task_is_running(task_, &running);
+ if (running) tizen_core_task_quit(task_);
+
+ tizen_core_task_destroy(task_);
+}
+
+
+void Worker::Post(std::shared_ptr<Job> job) {
+ queue_.Push(std::move(job));
+ tizen_core_source_h source = nullptr;
+ tizen_core_add_idle_job(core_, JobCb, this, &source);
+ if (source == nullptr) _E("Failed to add idle job");
+}
+
+bool Worker::JobCb(void* user_data) {
+ auto* worker = static_cast<Worker*>(user_data);
+ while (!worker->queue_.IsEmpty()) {
+ auto job = worker->queue_.WaitAndPop();
+ if (job) job->Do();
+ }
+
+ return false;
+}
+
+} // namespace amd
--- /dev/null
+/*
+ * Copyright (c) 2024 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.
+ */
+
+#ifndef LIB_COMMON_WORKER_HH_
+#define LIB_COMMON_WORKER_HH_
+
+#include <tizen_core.h>
+
+#include <memory>
+#include <string>
+
+#include <shared-queue.hpp>
+
+namespace amd {
+
+class Worker {
+ public:
+ class Job {
+ public:
+ virtual ~Job() = default;
+ virtual void Do() {}
+ };
+
+ explicit Worker(std::string name);
+ virtual ~Worker();
+
+ void Post(std::shared_ptr<Job> job);
+ private:
+ static bool JobCb(void* user_data);
+
+ private:
+ std::string name_;
+ tizen_core_task_h task_ = nullptr;
+ tizen_core_h core_ = nullptr;
+ tizen_base::SharedQueue<std::shared_ptr<Job>> queue_;
+};
+
+} // namespace amd
+
+#endif // LIB_LAUNCHPAD_WORKER_HH_
#include <unordered_map>
#include "lib/amd_launchpad.h"
+#include "lib/common/worker.hh"
#include "lib/launchpad/client_channel.hh"
-#include "lib/launchpad/worker.hh"
namespace amd {
+++ /dev/null
-/*
- * Copyright (c) 2024 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 "lib/launchpad/worker.hh"
-
-#include <utility>
-
-#include "lib/common/exception.hh"
-#include "lib/common/log_private.hh"
-
-namespace amd {
-
-Worker::Worker(std::string name) : name_(std::move(name)) {
- int ret = tizen_core_task_create(name_.c_str(), true, &task_);
- if (ret != TIZEN_CORE_ERROR_NONE) {
- _E("tizen_core_task_create() is failed. error=%d", ret);
- THROW(ret);
- }
-
- tizen_core_task_get_tizen_core(task_, &core_);
- tizen_core_task_run(task_);
-}
-
-Worker::~Worker() {
- bool running = false;
- tizen_core_task_is_running(task_, &running);
- if (running) tizen_core_task_quit(task_);
-
- tizen_core_task_destroy(task_);
-}
-
-
-void Worker::Post(std::shared_ptr<Job> job) {
- queue_.Push(std::move(job));
- tizen_core_source_h source = nullptr;
- tizen_core_add_idle_job(core_, JobCb, this, &source);
- if (source == nullptr) _E("Failed to add idle job");
-}
-
-bool Worker::JobCb(void* user_data) {
- auto* worker = static_cast<Worker*>(user_data);
- while (!worker->queue_.IsEmpty()) {
- auto job = worker->queue_.WaitAndPop();
- if (job) job->Do();
- }
-
- return false;
-}
-
-} // namespace amd
+++ /dev/null
-/*
- * Copyright (c) 2024 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.
- */
-
-#ifndef LIB_LAUNCHPAD_WORKER_HH_
-#define LIB_LAUNCHPAD_WORKER_HH_
-
-#include <tizen_core.h>
-
-#include <memory>
-#include <string>
-
-#include <shared-queue.hpp>
-
-namespace amd {
-
-class Worker {
- public:
- class Job {
- public:
- virtual ~Job() = default;
- virtual void Do() {}
- };
-
- explicit Worker(std::string name);
- virtual ~Worker();
-
- void Post(std::shared_ptr<Job> job);
- private:
- static bool JobCb(void* user_data);
-
- private:
- std::string name_;
- tizen_core_task_h task_ = nullptr;
- tizen_core_h core_ = nullptr;
- tizen_base::SharedQueue<std::shared_ptr<Job>> queue_;
-};
-
-} // namespace amd
-
-#endif // LIB_LAUNCHPAD_WORKER_HH_
\ No newline at end of file