From 68cc061a2251119aab3273eefb0e99e8a14fd009 Mon Sep 17 00:00:00 2001 From: "jh9216.park" Date: Wed, 24 Feb 2021 23:02:51 -0500 Subject: [PATCH] Refactor appcore-agent - Use app-core for C++ Requires: - https://review.tizen.org/gerrit/#/c/platform/core/appfw/app-core/+/247812/ - https://review.tizen.org/gerrit/#/c/platform/core/api/app-common/+/253882/ Change-Id: I5a408b66cc15a993a538c620125087fe0399eb3c Signed-off-by: jh9216.park --- CMakeLists.txt | 5 +- include/service_app_internal.h | 4 +- packaging/appcore-agent.spec | 2 +- src/job-handler.cc | 38 +++ src/job-handler.hh | 42 +++ src/job-manager.cc | 156 ++++++++++ src/job-manager.hh | 57 ++++ src/job.cc | 98 ++++++ src/job.hh | 62 ++++ src/log-private.hh | 37 +++ src/service_app_main.c | 677 ----------------------------------------- src/service_app_main.cc | 401 ++++++++++++++++++++++++ unittests/CMakeLists.txt | 42 ++- unittests/mock/appcore_mock.cc | 22 +- unittests/mock/appcore_mock.h | 20 +- unittests/service_app_test.cc | 94 +++--- 16 files changed, 989 insertions(+), 768 deletions(-) create mode 100644 src/job-handler.cc create mode 100644 src/job-handler.hh create mode 100644 src/job-manager.cc create mode 100644 src/job-manager.hh create mode 100644 src/job.cc create mode 100644 src/job.hh create mode 100644 src/log-private.hh delete mode 100644 src/service_app_main.c create mode 100644 src/service_app_main.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index dbf7f9e..623f717 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,7 @@ SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden") SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -g -Wall") SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Werror") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}") +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CFLAGS}") SET(CMAKE_SKIP_BUILD_RPATH TRUE) @@ -18,7 +19,7 @@ SET(CMAKE_SKIP_BUILD_RPATH TRUE) SET(APPCORE_AGENT "appcore-agent") INCLUDE(FindPkgConfig) -pkg_check_modules(pkg_agent REQUIRED aul dlog capi-appfw-app-control capi-appfw-app-common vconf ecore-core vconf-internal-keys appcore-common capi-system-info) +pkg_check_modules(pkg_agent REQUIRED aul dlog capi-appfw-app-control capi-appfw-app-common vconf ecore-core vconf-internal-keys app-core-cpp capi-system-info) FOREACH(flag ${pkg_agent_CFLAGS}) SET(EXTRA_CFLAGS_agent "${EXTRA_CFLAGS_agent} ${flag}") ENDFOREACH(flag) @@ -43,4 +44,4 @@ INSTALL(DIRECTORY ${CMAKE_SOURCE_DIR}/include/ DESTINATION include/appcore-agent PATTERN "*.h*" ) -ADD_SUBDIRECTORY(unittests) \ No newline at end of file +ADD_SUBDIRECTORY(unittests) diff --git a/include/service_app_internal.h b/include/service_app_internal.h index 1d5b0cc..abb8a0c 100644 --- a/include/service_app_internal.h +++ b/include/service_app_internal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2017 - 2021 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. @@ -121,7 +121,7 @@ typedef int (*service_app_job_cb)(int job_status, const char *job_id, * @since_tizen 4.0 * @remarks This is for App Framework internally. */ -typedef struct service_app_job_s *service_app_job_h; +typedef void *service_app_job_h; /** * @brief Adds the job handler. diff --git a/packaging/appcore-agent.spec b/packaging/appcore-agent.spec index c24172b..c5ac47a 100644 --- a/packaging/appcore-agent.spec +++ b/packaging/appcore-agent.spec @@ -11,7 +11,7 @@ BuildRequires: pkgconfig(aul) BuildRequires: pkgconfig(capi-appfw-app-control) BuildRequires: pkgconfig(capi-appfw-app-common) BuildRequires: pkgconfig(capi-system-info) -BuildRequires: pkgconfig(appcore-common) +BuildRequires: pkgconfig(app-core-cpp) BuildRequires: pkgconfig(dlog) BuildRequires: pkgconfig(ecore-core) BuildRequires: pkgconfig(gmock) diff --git a/src/job-handler.cc b/src/job-handler.cc new file mode 100644 index 0000000..d3881b6 --- /dev/null +++ b/src/job-handler.cc @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021 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 "job-handler.hh" +#include "log-private.hh" + +namespace tizen_cpp { + +JobHandler::JobHandler(std::string job_id, service_app_job_cb cb, + void* user_data) + : job_id_(std::move(job_id)), + cb_(cb), + user_data_(user_data) { +} + +const std::string& JobHandler::GetJobId() const { + return job_id_; +} + +void JobHandler::Do(const Job* job) { + if (cb_) + cb_(job->GetStatus(), job->GetId().c_str(), job->GetData(), user_data_); +} + +} // namespace tizen_cpp diff --git a/src/job-handler.hh b/src/job-handler.hh new file mode 100644 index 0000000..81d9769 --- /dev/null +++ b/src/job-handler.hh @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2021 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 JOB_HANDLER_HH_ +#define JOB_HANDLER_HH_ + +#include + +#include "job.hh" +#include "service_app_internal.h" + +namespace tizen_cpp { + +class JobHandler { + public: + JobHandler(std::string job_id, service_app_job_cb cb, void* user_data); + + const std::string& GetJobId() const; + void Do(const Job* job); + + private: + std::string job_id_; + service_app_job_cb cb_; + void* user_data_; +}; + +} // namespace tizen_cpp + +#endif // JOB_HANDLER_HH_ diff --git a/src/job-manager.cc b/src/job-manager.cc new file mode 100644 index 0000000..3293c11 --- /dev/null +++ b/src/job-manager.cc @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2021 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 +#include + +#include + +#include "job-manager.hh" +#include "log-private.hh" + +namespace tizen_cpp { + +void JobManager::AddJobHandler(JobHandler* handler) { + handlers_.push_back(handler); +} + +void JobManager::RemoveJobHandler(JobHandler* handler) { + auto found = std::find(handlers_.begin(), handlers_.end(), handler); + if (found == handlers_.end()) + return; + + handlers_.erase(found); +} + +bool JobManager::ExistJobHandler(const std::string& job_id) { + for (auto* h : handlers_) { + if (h->GetJobId() == job_id) + return true; + } + + return false; +} + +bool JobManager::ExistJobHandler(JobHandler* handler) { + for (auto* h : handlers_) { + if (h == handler) + return true; + } + + return false; +} + +void JobManager::Do(std::shared_ptr job) { + job->SetEventListener(this); + if (!ExistJobHandler(job->GetId())) { + job->SetTimer(); + AddPendingJob(job); + } else { + job->SetIdler(); + AddRunningJob(job); + } +} + +int JobManager::Finish(const std::string& job_id) { + RemoveRunningJob(job_id); + int ret = aul_job_scheduler_update_job_status(job_id.c_str(), + JOB_STATUS_FINISHED); + if (ret != AUL_R_OK) { + _E("aul_job_scheduler_update_job_status() is failed. error(%d)", ret); + return ret; + } + + return 0; +} + +void JobManager::FinishAllJobs() { + running_jobs_.clear(); + pending_jobs_.clear(); +} + +void JobManager::FlushPendingJob(const std::string& job_id) { + auto iter = pending_jobs_.begin(); + while (iter != pending_jobs_.end()) { + if ((*iter)->GetId() == job_id) { + auto job = *iter; + iter = pending_jobs_.erase(iter); + job->UnsetTimer(); + AddPendingJob(job); + job->SetIdler(); + } else { + iter++; + } + } +} + +void JobManager::AddRunningJob(std::shared_ptr job) { + running_jobs_.push_back(job); +} + +void JobManager::RemoveRunningJob(const std::string& job_id) { + auto iter = running_jobs_.begin(); + while (iter != running_jobs_.end()) { + if ((*iter)->GetId() == job_id) + iter = running_jobs_.erase(iter); + else + iter++; + } +} + +void JobManager::AddPendingJob(std::shared_ptr job) { + pending_jobs_.push_back(job); +} + +void JobManager::RemovePendingJob(const std::string& job_id) { + auto iter = pending_jobs_.begin(); + while (iter != pending_jobs_.end()) { + if ((*iter)->GetId() == job_id) + iter = pending_jobs_.erase(iter); + else + iter++; + } +} + +void JobManager::OnTimedOut(const Job* job) { + _E("[__TIMEDOUT__] Job(%s), Status(%d)", + job->GetId().c_str(), job->GetStatus()); + RemovePendingJob(job->GetId()); +} + +void JobManager::OnRun(const Job* job) { + _D("[__JOB__] START. Job(%s), Status(%d)", + job->GetId().c_str(), job->GetStatus()); + if (job->GetStatus() == SERVICE_APP_JOB_STATUS_START) { + aul_job_scheduler_update_job_status(job->GetId().c_str(), JOB_STATUS_START); + for (auto* h : handlers_) { + if (h->GetJobId() == job->GetId()) + h->Do(job); + } + } else { + for (auto* h : handlers_) { + if (h->GetJobId() == job->GetId()) + h->Do(job); + } + aul_job_scheduler_update_job_status(job->GetId().c_str(), + JOB_STATUS_STOPPED); + } + _D("[__JOB__] END. Job(%s), Status(%d)", + job->GetId().c_str(), job->GetStatus()); + RemoveRunningJob(job->GetId()); +} + +} // namespace tizen_cpp diff --git a/src/job-manager.hh b/src/job-manager.hh new file mode 100644 index 0000000..2d6c35c --- /dev/null +++ b/src/job-manager.hh @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2021 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 JOB_MANAGER_HH_ +#define JOB_MANAGER_HH_ + +#include +#include +#include + +#include "job.hh" +#include "job-handler.hh" + +namespace tizen_cpp { + +class JobManager : public Job::IEvent { + public: + void AddJobHandler(JobHandler* handler); + void RemoveJobHandler(JobHandler* handler); + bool ExistJobHandler(JobHandler* handler); + void Do(std::shared_ptr job); + int Finish(const std::string& job_id); + void FinishAllJobs(); + void FlushPendingJob(const std::string& job_id); + + private: + bool ExistJobHandler(const std::string& job_id); + void AddPendingJob(std::shared_ptr job); + void RemovePendingJob(const std::string& job_id); + void AddRunningJob(std::shared_ptr job); + void RemoveRunningJob(const std::string& job_id); + + void OnTimedOut(const Job* job) override; + void OnRun(const Job* job) override; + + private: + std::list handlers_; + std::list> pending_jobs_; + std::list> running_jobs_; +}; + +} // namespace tizen_cpp + +#endif // JOB_MANAGER_HH_ diff --git a/src/job.cc b/src/job.cc new file mode 100644 index 0000000..7af489a --- /dev/null +++ b/src/job.cc @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2021 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 "job.hh" +#include "log-private.hh" + +namespace tizen_cpp { + +Job::Job(int status, std::string id, tizen_base::Bundle data) + : status_(status), id_(std::move(id)), data_(std::move(data)) { +} + +Job::~Job() { + UnsetIdler(); + UnsetTimer(); +} + +int Job::GetStatus() const { + return status_; +} + +const std::string& Job::GetId() const { + return id_; +} + +bundle* Job::GetData() const { + return data_.GetHandle(); +} + +void Job::SetEventListener(IEvent* listener) { + listener_ = listener; +} + +void Job::SetTimer() { + if (timer_ == 0) { + timer_ = g_timeout_add(5000, TimedOutCb, this); + if (timer_ == 0) + _E("g_timeout_add() is failed"); + } +} + +void Job::UnsetTimer() { + if (timer_ != 0) { + g_source_remove(timer_); + timer_ = 0; + } +} + +void Job::SetIdler() { + if (idler_ == 0) { + idler_ = g_idle_add(IdleCb, this); + if (idler_ == 0) + _E("g_idle_add() is failed"); + } +} + +void Job::UnsetIdler() { + if (idler_ != 0) { + g_source_remove(idler_); + idler_ = 0; + } +} + +gboolean Job::TimedOutCb(gpointer data) { + auto* handle = static_cast(data); + handle->timer_ = 0; + + auto* listener = handle->listener_; + if (listener != nullptr) + listener->OnTimedOut(handle); + + return G_SOURCE_REMOVE; +} + +gboolean Job::IdleCb(gpointer data) { + auto* handle = static_cast(data); + handle->idler_ = 0; + auto* listener = handle->listener_; + if (listener != nullptr) + listener->OnRun(handle); + + return G_SOURCE_REMOVE; +} + +} // namespace tizen_cpp diff --git a/src/job.hh b/src/job.hh new file mode 100644 index 0000000..c7d22fa --- /dev/null +++ b/src/job.hh @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2021 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 JOB_HH_ +#define JOB_HH_ + +#include +#include + +#include + +namespace tizen_cpp { + +class Job { + public: + class IEvent { + public: + virtual void OnTimedOut(const Job* job) = 0; + virtual void OnRun(const Job* job) = 0; + }; + + Job(int status, std::string id, tizen_base::Bundle data); + virtual ~Job(); + + int GetStatus() const; + const std::string& GetId() const; + bundle* GetData() const; + void SetEventListener(IEvent* listener); + void SetTimer(); + void UnsetTimer(); + void SetIdler(); + void UnsetIdler(); + + private: + static gboolean TimedOutCb(gpointer data); + static gboolean IdleCb(gpointer data); + + private: + int status_; + std::string id_; + tizen_base::Bundle data_; + IEvent* listener_ = nullptr; + guint timer_ = 0; + guint idler_ = 0; +}; + +} // namespace tizen_cpp + +#endif // JOB_HH_ diff --git a/src/log-private.hh b/src/log-private.hh new file mode 100644 index 0000000..014c904 --- /dev/null +++ b/src/log-private.hh @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021 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 LOG_PRIVATE_HH_ +#define LOG_PRIVATE_HH_ + +#include + +#undef LOG_TAG +#define LOG_TAG "CAPI_APPFW_APPLICATION" + +#undef _E +#define _E LOGE + +#undef _W +#define _W LOGW + +#undef _I +#define _I LOGI + +#undef _D +#define _D LOGD + +#endif // LOG_PRIVATE_HH_ diff --git a/src/service_app_main.c b/src/service_app_main.c deleted file mode 100644 index 35ad3b0..0000000 --- a/src/service_app_main.c +++ /dev/null @@ -1,677 +0,0 @@ -/* - * Copyright (c) 2011 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "service_app_extension.h" -#include "service_app_internal.h" - -#ifdef LOG_TAG -#undef LOG_TAG -#endif - -#define LOG_TAG "CAPI_APPFW_APPLICATION" - -typedef enum { - APP_STATE_NOT_RUNNING, - APP_STATE_CREATING, - APP_STATE_RUNNING, -} app_state_e; - -struct app_event_handler { - app_event_type_e type; - app_event_cb cb; - void *data; - void* raw; -}; - -struct app_event_info { - app_event_type_e type; - void *value; -}; - -struct service_app_context { - service_app_lifecycle_callback_s callback; - void *data; - GList *running_jobs; - GList *pending_jobs; - GList *job_handlers; -}; - -struct service_app_job_s { - char *job_id; - service_app_job_cb callback; - void *user_data; -}; - -struct job_s { - int job_status; - char *job_id; - bundle *job_data; - guint timer; - guint idler; -}; - -static struct service_app_context __context; -static app_state_e __app_state = APP_STATE_NOT_RUNNING; - -static int __app_event_converter[APPCORE_BASE_EVENT_MAX] = { - [APP_EVENT_LOW_MEMORY] = APPCORE_BASE_EVENT_LOW_MEMORY, - [APP_EVENT_LOW_BATTERY] = APPCORE_BASE_EVENT_LOW_BATTERY, - [APP_EVENT_LANGUAGE_CHANGED] = APPCORE_BASE_EVENT_LANG_CHANGE, - [APP_EVENT_DEVICE_ORIENTATION_CHANGED] = APPCORE_BASE_EVENT_DEVICE_ORIENTATION_CHANGED, - [APP_EVENT_REGION_FORMAT_CHANGED] = APPCORE_BASE_EVENT_REGION_CHANGE, - [APP_EVENT_SUSPENDED_STATE_CHANGED] = APPCORE_BASE_EVENT_SUSPENDED_STATE_CHANGE, -}; - -static int __on_error(app_error_e error, const char *function, const char *description); -static void __destroy_job_handler(gpointer data); -static bool __exist_job_handler(const char *job_id); - -static struct job_s *__create_job(int job_status, const char *job_id, - bundle *job_data) -{ - struct job_s *job; - - job = calloc(1, sizeof(struct job_s)); - if (job == NULL) { - /* LCOV_EXCL_START */ - LOGE("Out of memory"); - return NULL; - /* LCOV_EXCL_STOP */ - } - - job->job_id = strdup(job_id); - if (job->job_id == NULL) { - /* LCOV_EXCL_START */ - LOGE("Out of memory"); - free(job); - return NULL; - /* LCOV_EXCL_STOP */ - } - - job->job_data = bundle_dup(job_data); - if (job->job_data == NULL) { - /* LCOV_EXCL_START */ - LOGE("Out of memory"); - free(job->job_id); - free(job); - return NULL; - /* LCOV_EXCL_STOP */ - } - - job->job_status = job_status; - - return job; -} - -static void __destroy_job(gpointer data) -{ - struct job_s *job = (struct job_s *)data; - - if (job == NULL) - return; - - if (job->idler) - g_source_remove(job->idler); /* LCOV_EXCL_LINE */ - if (job->timer) - g_source_remove(job->timer); /* LCOV_EXCL_LINE */ - if (job->job_data) - bundle_free(job->job_data); - if (job->job_id) - free(job->job_id); - free(job); -} - -/* LCOV_EXCL_START */ -static gboolean __pending_job_timeout_handler(gpointer data) -{ - struct job_s *job = (struct job_s *)data; - - LOGE("[__TIMEOUT__] Job(%s) Status(%d)", job->job_id, job->job_status); - __context.pending_jobs = g_list_remove(__context.pending_jobs, job); - job->timer = 0; - __destroy_job(job); - - return G_SOURCE_REMOVE; -} -/* LCOV_EXCL_STOP */ - -static void __job_finish(void) -{ - if (__context.running_jobs) { - /* LCOV_EXCL_START */ - g_list_free_full(__context.running_jobs, __destroy_job); - __context.running_jobs = NULL; - /* LCOV_EXCL_STOP */ - } - - if (__context.pending_jobs) { - /* LCOV_EXCL_START */ - g_list_free_full(__context.pending_jobs, __destroy_job); - __context.pending_jobs = NULL; - /* LCOV_EXCL_STOP */ - } - - if (__context.job_handlers) { - g_list_free_full(__context.job_handlers, __destroy_job_handler); - __context.job_handlers = NULL; - } -} - -static int __service_app_create(void *data) -{ - LOGW("service_app_create()"); - appcore_base_on_create(); - - if (__context.callback.create == NULL || - __context.callback.create(__context.data) == false) - return __on_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, "service_app_create_cb() returns false"); - - return APP_ERROR_NONE; -} - -static int __service_app_terminate(void *data) -{ - LOGW("service_app_terminate()"); - if (__context.callback.terminate) - __context.callback.terminate(__context.data); - - appcore_base_on_terminate(); - - return APP_ERROR_NONE; -} - -static int __service_app_control(bundle *b, void *data) -{ - app_control_h app_control = NULL; - const char *job_id; - - LOGW("service_app_control()"); - appcore_base_on_control(b); - - job_id = bundle_get_val(b, AUL_K_JOB_ID); - if (job_id) { - LOGD("[__JOB__] Job(%s)", job_id); - return 0; - } - - if (app_control_create_event(b, &app_control) != 0) - return -1; - - if (__context.callback.app_control) - __context.callback.app_control(app_control, __context.data); - - app_control_destroy(app_control); - - return 0; -} - -static int __service_app_receive(aul_type type, bundle *b, void *data) -{ - appcore_base_on_receive(type, b); - - if (type == AUL_TERMINATE_BGAPP) { - appcore_base_exit(); - return 0; - } - - return 0; -} - -static void __loop_init(int argc, char **argv, void *data) -{ - ecore_init(); -} - -static void __loop_fini(void) -{ - ecore_shutdown(); -} - -static void __loop_run(void *data) -{ - ecore_main_loop_begin(); -} - -static void __exit_main_loop(void *data) -{ - ecore_main_loop_quit(); -} - -static void __loop_exit(void *data) -{ - ecore_main_loop_thread_safe_call_sync((Ecore_Data_Cb)__exit_main_loop, NULL); -} - -static const char *__error_to_string(app_error_e error) -{ - switch (error) { - case APP_ERROR_NONE: - return "NONE"; - case APP_ERROR_INVALID_PARAMETER: - return "INVALID_PARAMETER"; - case APP_ERROR_OUT_OF_MEMORY: - return "OUT_OF_MEMORY"; - case APP_ERROR_INVALID_CONTEXT: - return "INVALID_CONTEXT"; - case APP_ERROR_NO_SUCH_FILE: - return "NO_SUCH_FILE"; - case APP_ERROR_ALREADY_RUNNING: - return "ALREADY_RUNNING"; - default: - return "UNKNOWN"; - } -} - -static int __on_error(app_error_e error, const char *function, const char *description) -{ - if (description) - LOGE("[%s] %s(0x%08x) : %s", function, __error_to_string(error), error, description); - else - LOGE("[%s] %s(0x%08x)", function, __error_to_string(error), error); - - return error; -} - -EXPORT_API int service_app_main_ext(int argc, char **argv, service_app_lifecycle_callback_s *callback, - service_app_loop_method_s *method, void *user_data) -{ - int ret; - appcore_base_ops ops = appcore_base_get_default_ops(); - - if (argc < 1 || argv == NULL || callback == NULL || method == NULL) - return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL); - - if (callback->create == NULL) - return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, "service_app_create_cb() callback must be registered"); - - if (__app_state != APP_STATE_NOT_RUNNING) - return __on_error(APP_ERROR_ALREADY_RUNNING, __FUNCTION__, NULL); /* LCOV_EXCL_LINE */ - - /* override methods */ - ops.create = __service_app_create; - ops.terminate = __service_app_terminate; - ops.control = __service_app_control; - ops.receive = __service_app_receive; - ops.run = method->run; - ops.exit = method->exit; - ops.init = method->init; - ops.finish = method->fini; - - __context.callback = *callback; - __context.data = user_data; - - __app_state = APP_STATE_CREATING; - ret = appcore_base_init(ops, argc, argv, NULL); - if (ret < 0) { - /* LCOV_EXCL_START */ - __app_state = APP_STATE_NOT_RUNNING; - return __on_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, NULL); - /* LCOV_EXCL_STOP */ - } - - appcore_base_fini(); - __job_finish(); - __app_state = APP_STATE_NOT_RUNNING; - return APP_ERROR_NONE; -} - -EXPORT_API int service_app_main(int argc, char **argv, service_app_lifecycle_callback_s *callback, void *user_data) -{ - service_app_loop_method_s method = { - .init = __loop_init, - .fini = __loop_fini, - .run = __loop_run, - .exit = __loop_exit, - }; - - LOGW("service_app_main()"); - return service_app_main_ext(argc, argv, callback, &method, user_data); -} - -EXPORT_API void service_app_exit(void) -{ - LOGW("service_app_exit()"); - appcore_base_exit(); -} - -static int __event_cb(void *event, void *data) -{ - app_event_handler_h handler = data; - - struct app_event_info app_event; - - app_event.type = handler->type; - app_event.value = event; - - if (handler->cb) - handler->cb(&app_event, handler->data); - return 0; -} - -EXPORT_API int service_app_add_event_handler(app_event_handler_h *event_handler, app_event_type_e event_type, app_event_cb callback, void *user_data) -{ - app_event_handler_h handler; - - if (event_handler == NULL || callback == NULL) - return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, "null parameter"); - - if (event_type < APP_EVENT_LOW_MEMORY || event_type > APP_EVENT_SUSPENDED_STATE_CHANGED || - event_type == APP_EVENT_DEVICE_ORIENTATION_CHANGED) - return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, "invalid event type"); - - handler = calloc(1, sizeof(struct app_event_handler)); - if (!handler) - return __on_error(APP_ERROR_OUT_OF_MEMORY, __FUNCTION__, "insufficient memory"); /* LCOV_EXCL_LINE */ - - handler->type = event_type; - handler->cb = callback; - handler->data = user_data; - handler->raw = appcore_base_add_event(__app_event_converter[event_type], __event_cb, handler); - - *event_handler = handler; - - return APP_ERROR_NONE; -} - -EXPORT_API int service_app_remove_event_handler(app_event_handler_h event_handler) -{ - int ret; - app_event_type_e type; - - if (event_handler == NULL) - return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL); - - type = event_handler->type; - if (type < APP_EVENT_LOW_MEMORY || - type > APP_EVENT_SUSPENDED_STATE_CHANGED || - type == APP_EVENT_DEVICE_ORIENTATION_CHANGED) - return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL); /* LCOV_EXCL_LINE */ - - ret = appcore_base_remove_event(event_handler->raw); - free(event_handler); - - if (ret < 0) - return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL); /* LCOV_EXCL_LINE */ - - return APP_ERROR_NONE; -} - -EXPORT_API void service_app_exit_without_restart(void) -{ - aul_status_update_v2(STATUS_NORESTART); - appcore_base_exit(); -} - -static void __invoke_job_callback(int status, const char *job_id, - bundle *job_data) -{ - struct service_app_job_s *handle; - GList *iter; - - iter = __context.job_handlers; - while (iter) { - handle = (struct service_app_job_s *)iter->data; - iter = iter->next; - if (strcmp(handle->job_id, job_id) == 0) { - handle->callback(status, job_id, job_data, - handle->user_data); - } - } -} - -static gboolean __handle_job(gpointer data) -{ - struct job_s *job = (struct job_s *)data; - - __context.running_jobs = g_list_remove(__context.running_jobs, job); - - LOGD("[__JOB___] Job(%s) Status(%d) START", - job->job_id, job->job_status); - if (job->job_status == SERVICE_APP_JOB_STATUS_START) { - aul_job_scheduler_update_job_status(job->job_id, - JOB_STATUS_START); - __invoke_job_callback(job->job_status, job->job_id, - job->job_data); - } else { - __invoke_job_callback(job->job_status, job->job_id, - job->job_data); - aul_job_scheduler_update_job_status(job->job_id, - JOB_STATUS_STOPPED); - } - LOGD("[__JOB__] Job(%s) Status(%d) END", - job->job_id, job->job_status); - - job->idler = 0; - __destroy_job(job); - - return G_SOURCE_REMOVE; -} - -static void __flush_pending_job(const char *job_id) -{ - struct job_s *job; - GList *iter; - - iter = __context.pending_jobs; - while (iter) { - /* LCOV_EXCL_START */ - job = (struct job_s *)iter->data; - iter = iter->next; - if (strcmp(job->job_id, job_id) == 0) { - __context.pending_jobs = g_list_remove( - __context.pending_jobs, job); - - if (job->timer) { - g_source_remove(job->timer); - job->timer = 0; - } - - job->idler = g_idle_add(__handle_job, job); - __context.running_jobs = g_list_append( - __context.running_jobs, job); - } - /* LCOV_EXCL_STOP */ - } -} - -static bool __exist_job_handler(const char *job_id) -{ - struct service_app_job_s *handle; - GList *iter; - - iter = __context.job_handlers; - while (iter) { - handle = (struct service_app_job_s *)iter->data; - if (strcmp(handle->job_id, job_id) == 0) - return true; - - iter = iter->next; - } - - return false; -} - -static struct service_app_job_s *__create_job_handler(const char *job_id, - service_app_job_cb callback, void *user_data) -{ - struct service_app_job_s *handle; - - handle = calloc(1, sizeof(struct service_app_job_s)); - if (handle == NULL) { - /* LCOV_EXCL_START */ - LOGE("Out of memory"); - return NULL; - /* LCOV_EXCL_STOP */ - } - - handle->job_id = strdup(job_id); - if (handle->job_id == NULL) { - /* LCOV_EXCL_START */ - LOGE("Out of memory"); - free(handle); - return NULL; - /* LCOV_EXCL_STOP */ - } - - handle->callback = callback; - handle->user_data = user_data; - - return handle; -} - -static void __destroy_job_handler(gpointer data) -{ - struct service_app_job_s *handle = (struct service_app_job_s *)data; - - if (handle == NULL) - return; - - if (handle->job_id) - free(handle->job_id); - free(handle); -} - -EXPORT_API service_app_job_h service_app_add_job_handler(const char *job_id, - service_app_job_cb callback, void *user_data) -{ - struct service_app_job_s *handle; - - if (job_id == NULL || callback == NULL) { - /* LCOV_EXCL_START */ - LOGE("Invalid parameter"); - return NULL; - /* LCOV_EXCL_STOP */ - } - - handle = __create_job_handler(job_id, callback, user_data); - if (handle == NULL) - return NULL; - - __context.job_handlers = g_list_append(__context.job_handlers, handle); - - __flush_pending_job(job_id); - - return handle; -} - -EXPORT_API int service_app_remove_job_handler(service_app_job_h handle) -{ - if (handle == NULL || - g_list_index(__context.job_handlers, handle) < 0) { - /* LCOV_EXCL_START */ - return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, - NULL); - /* LCOV_EXCL_STOP */ - } - - __context.job_handlers = g_list_remove(__context.job_handlers, handle); - - __destroy_job_handler(handle); - - return APP_ERROR_NONE; -} - -EXPORT_API int service_app_job_raise(int job_status, const char *job_id, - bundle *job_data) -{ - struct job_s *job; - - if (job_status < SERVICE_APP_JOB_STATUS_START || - job_status > SERVICE_APP_JOB_STATUS_STOP || - job_id == NULL || job_data == NULL) { - /* LCOV_EXCL_START */ - return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, - NULL); - /* LCOV_EXCL_STOP */ - } - - job = __create_job(job_status, job_id, job_data); - if (job == NULL) - return __on_error(APP_ERROR_OUT_OF_MEMORY, __FUNCTION__, NULL); /* LCOV_EXCL_LINE */ - - if (!__exist_job_handler(job_id)) { - /* LCOV_EXCL_START */ - job->timer = g_timeout_add(5000, __pending_job_timeout_handler, - job); - __context.pending_jobs = g_list_append(__context.pending_jobs, - job); - /* LCOV_EXCL_STOP */ - } else { - job->idler = g_idle_add(__handle_job, job); - __context.running_jobs = g_list_append(__context.running_jobs, - job); - } - - return APP_ERROR_NONE; -} - -static void __remove_running_job(const char *job_id) -{ - struct job_s *job; - GList *iter; - - iter = __context.running_jobs; - while (iter) { - /* LCOV_EXCL_START */ - job = (struct job_s *)iter->data; - iter = iter->next; - if (strcmp(job->job_id, job_id) == 0) { - __context.running_jobs = g_list_remove( - __context.running_jobs, job); - __destroy_job(job); - } - /* LCOV_EXCL_STOP */ - } -} - -EXPORT_API int service_app_job_finished(const char *job_id) -{ - int r; - - if (job_id == NULL) { - /* LCOV_EXCL_START */ - return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, - NULL); - /* LCOV_EXCL_STOP */ - } - - __remove_running_job(job_id); - - r = aul_job_scheduler_update_job_status(job_id, JOB_STATUS_FINISHED); - if (r != AUL_R_OK) { - /* LCOV_EXCL_START */ - return __on_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, - NULL); - /* LCOV_EXCL_STOP */ - } - - return APP_ERROR_NONE; -} diff --git a/src/service_app_main.cc b/src/service_app_main.cc new file mode 100644 index 0000000..2e7335b --- /dev/null +++ b/src/service_app_main.cc @@ -0,0 +1,401 @@ +/* + * Copyright (c) 2021 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "service_app_extension.h" +#include "service_app_internal.h" + +#include "job-manager.hh" +#include "log-private.hh" + +using namespace tizen_cpp; + +namespace { + +const char* __error_to_string(app_error_e error) { + switch (error) { + case APP_ERROR_NONE: + return "NONE"; + case APP_ERROR_INVALID_PARAMETER: + return "INVALID_PARAMETER"; + case APP_ERROR_OUT_OF_MEMORY: + return "OUT_OF_MEMORY"; + case APP_ERROR_INVALID_CONTEXT: + return "INVALID_CONTEXT"; + case APP_ERROR_NO_SUCH_FILE: + return "NO_SUCH_FILE"; + case APP_ERROR_ALREADY_RUNNING: + return "ALREADY_RUNNING"; + default: + return "UNKNOWN"; + } +} + +int __on_error(app_error_e error, const char* function, + const char* description) { + if (description) { + _E("[%s] %s(0x%08x) : %s", + function, __error_to_string(error), error, description); + } else { + _E("[%s] %s(0x%08x)", function, __error_to_string(error), error); + } + + return error; +} + +constexpr int APP_EVENT_MAX = 7; +constexpr IAppCore::IEvent::Type __app_event_converter[APP_EVENT_MAX] = { + [APP_EVENT_LOW_MEMORY] = IAppCore::IEvent::Type::LOW_MEMORY, + [APP_EVENT_LOW_BATTERY] = IAppCore::IEvent::Type::LOW_BATTERY, + [APP_EVENT_LANGUAGE_CHANGED] = IAppCore::IEvent::Type::LANG_CHANGE, + [APP_EVENT_DEVICE_ORIENTATION_CHANGED] = IAppCore::IEvent::Type::DEVICE_ORIENTATION_CHANGED, + [APP_EVENT_REGION_FORMAT_CHANGED] = IAppCore::IEvent::Type::REGION_CHANGE, + [APP_EVENT_SUSPENDED_STATE_CHANGED] = IAppCore::IEvent::Type::SUSPENDED_STATE_CHANGE, +}; + +class AppContext : public AppCoreBase { + public: + enum AppState { + APP_STATE_NOT_RUNNING, + APP_STATE_CREATING, + APP_STATE_RUNNING, + }; + + AppContext(service_app_lifecycle_callback_s callback, + service_app_loop_method_s method, void* data) + : callback_(callback), method_(method), data_(data) { + state_ = APP_STATE_CREATING; + } + + void Run(int argc, char** argv) override { + SetAppState(APP_STATE_RUNNING); + AppCoreBase::Run(argc, argv); + SetAppState(APP_STATE_NOT_RUNNING); + } + + int OnReceive(aul_type type, tizen_base::Bundle b) override { + AppCoreBase::OnReceive(type, b); + + if (type == AUL_TERMINATE_BGAPP) { + Exit(); + return 0; + } + + return 0; + } + + int OnCreate() override { + _W("service_app_create()"); + AppCoreBase::OnCreate(); + + if (callback_.create == nullptr || callback_.create(data_) == false) { + return __on_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, + "service_app_create_cb() returns false"); + } + + return APP_ERROR_NONE; + } + + int OnControl(tizen_base::Bundle b) override { + _W("service_app_control()"); + AppCoreBase::OnControl(b); + + std::string job_id = b.GetString(AUL_K_JOB_ID); + if (!job_id.empty()) { + _D("[__JOB__] Job(%s)", job_id.c_str()); + return 0; + } + + app_control_h app_control = nullptr; + if (app_control_create_event(b.GetHandle(), &app_control) != 0) + return -1; + + if (callback_.app_control) + callback_.app_control(app_control, data_); + + app_control_destroy(app_control); + + return 0; + } + + int OnTerminate() override { + _W("service_app_terminate()"); + if (callback_.terminate) + callback_.terminate(data_); + + AppCoreBase::OnTerminate(); + + return APP_ERROR_NONE; + } + + void OnLoopInit(int argc, char** argv) override { + if (method_.init) + method_.init(argc, argv, data_); + else + ecore_init(); + } + + void OnLoopFinish() override { + if (method_.fini) + method_.fini(); + else + ecore_shutdown(); + } + + void OnLoopRun() override { + if (method_.run) + method_.run(data_); + else + ecore_main_loop_begin(); + } + + void OnLoopExit() override { + if (method_.exit) { + method_.exit(data_); + } else { + ecore_main_loop_thread_safe_call_sync([](void* data) -> void* { + ecore_main_loop_quit(); + return nullptr; + }, nullptr); + } + } + + AppState GetAppState() const { + return state_; + } + + void SetAppState(AppState state) { + state_ = state; + } + + private: + service_app_lifecycle_callback_s callback_; + service_app_loop_method_s method_; + void* data_; + AppState state_ = APP_STATE_NOT_RUNNING; +}; + +std::unique_ptr __context; +std::list> __pending_app_events; +JobManager __job_manager; + +} // namespace + +extern "C" EXPORT_API int service_app_main_ext(int argc, char** argv, + service_app_lifecycle_callback_s* callback, + service_app_loop_method_s* method, void* user_data) { + if (argc < 1 || argv == nullptr || callback == nullptr || method == nullptr) + return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, nullptr); + + if (callback->create == nullptr) { + return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, + "service_app_create_cb() callback must be registered"); + } + + if (__context.get() != nullptr && + __context->GetAppState() != AppContext::APP_STATE_NOT_RUNNING) + return __on_error(APP_ERROR_ALREADY_RUNNING, __FUNCTION__, nullptr); + + try { + __context = std::make_unique(*callback, *method, user_data); + for (auto& i : __pending_app_events) { + __context->AddEvent(i); + } + __context->Run(argc, argv); + } catch(std::runtime_error& e) { + __context->SetAppState(AppContext::APP_STATE_NOT_RUNNING); + return __on_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, nullptr); + } + + __job_manager.FinishAllJobs(); + return APP_ERROR_NONE; +} + +extern "C" EXPORT_API int service_app_main(int argc, char** argv, + service_app_lifecycle_callback_s* callback, void* user_data) { + service_app_loop_method_s method = { nullptr, }; + _W("service_app_main()"); + return service_app_main_ext(argc, argv, callback, &method, user_data); +} + +extern "C" EXPORT_API void service_app_exit(void) { + _W("service_app_exit()"); + if (__context.get() && + __context->GetAppState() == AppContext::APP_STATE_RUNNING) + __context->Exit(); +} + +extern "C" EXPORT_API int service_app_add_event_handler( + app_event_handler_h* event_handler, app_event_type_e event_type, + app_event_cb callback, void *user_data) { + if (event_handler == nullptr || callback == nullptr) { + return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, + "null parameter"); + } + + if (event_type < APP_EVENT_LOW_MEMORY || + event_type > APP_EVENT_SUSPENDED_STATE_CHANGED || + event_type == APP_EVENT_DEVICE_ORIENTATION_CHANGED) { + return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, + "invalid event type"); + } + + auto* ae = new (std::nothrow) AppEvent(__app_event_converter[event_type], + callback, user_data); + if (!ae) { + return __on_error(APP_ERROR_OUT_OF_MEMORY, __FUNCTION__, + "failed to create handler"); + } + + auto* h = new (std::nothrow) std::shared_ptr(ae); + if (!h) { + delete ae; + return __on_error(APP_ERROR_OUT_OF_MEMORY, __FUNCTION__, + "failed to create handler"); + } + + if (__context.get() && + __context->GetAppState() == AppContext::APP_STATE_RUNNING) { + __context->AddEvent(*h); + } else { + __pending_app_events.push_back(*h); + } + + *event_handler = reinterpret_cast(h); + + return APP_ERROR_NONE; +} + +extern "C" EXPORT_API int service_app_remove_event_handler( + app_event_handler_h event_handler) { + if (event_handler == nullptr) + return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, nullptr); + + auto* eb = reinterpret_cast*>(event_handler); + auto type = (*eb)->GetType(); + + if (type < IAppCore::IEvent::Type::LOW_MEMORY || + type > IAppCore::IEvent::Type::SUSPENDED_STATE_CHANGE || + type == IAppCore::IEvent::Type::DEVICE_ORIENTATION_CHANGED) + return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, nullptr); + + if (__context.get() && + __context->GetAppState() == AppContext::APP_STATE_RUNNING) { + if (!__context->RemoveEvent(*eb)) { + return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, + "invalid raw handler"); + } + } else { + __pending_app_events.remove(*eb); + } + + delete eb; + + return APP_ERROR_NONE; +} + +extern "C" EXPORT_API void service_app_exit_without_restart(void) { + if (__context.get() && + __context->GetAppState() == AppContext::APP_STATE_RUNNING) { + aul_status_update_v2(STATUS_NORESTART); + __context->Exit(); + } +} + +extern "C" EXPORT_API service_app_job_h service_app_add_job_handler( + const char* job_id, service_app_job_cb callback, void* user_data) { + if (job_id == nullptr || callback == nullptr) { + _E("Invalid parameter"); + return nullptr; + } + + auto* handle = new (std::nothrow) JobHandler(job_id, callback, user_data); + if (handle == nullptr) { + _E("Out of memory"); + return nullptr; + } + + __job_manager.AddJobHandler(handle); + __job_manager.FlushPendingJob(job_id); + return handle; +} + +extern "C" EXPORT_API int service_app_remove_job_handler( + service_app_job_h handle) { + if (handle == nullptr) { + _E("Invalid parameter"); + return APP_ERROR_INVALID_PARAMETER; + } + + auto* h = static_cast(handle); + if (!__job_manager.ExistJobHandler(h)) { + _E("Invalid parameter"); + return APP_ERROR_INVALID_PARAMETER; + } + + __job_manager.RemoveJobHandler(h); + delete h; + return APP_ERROR_NONE; +} + +extern "C" EXPORT_API int service_app_job_raise(int job_status, + const char* job_id, bundle* job_data) { + if (job_status < SERVICE_APP_JOB_STATUS_START || + job_status > SERVICE_APP_JOB_STATUS_STOP || + job_id == nullptr || job_data == nullptr) { + _E("Invalid parameter"); + return APP_ERROR_INVALID_PARAMETER; + } + + auto job = std::make_shared(job_status, job_id, + tizen_base::Bundle(job_data, true, true)); + if (job == nullptr) { + _E("Out of memory"); + return APP_ERROR_OUT_OF_MEMORY; + } + + __job_manager.Do(job); + return APP_ERROR_NONE; +} + +extern "C" EXPORT_API int service_app_job_finished(const char* job_id) { + if (job_id == nullptr) { + _E("Invalid parameter"); + return APP_ERROR_INVALID_PARAMETER; + } + + if (__job_manager.Finish(job_id) != 0) + return APP_ERROR_INVALID_CONTEXT; + + return APP_ERROR_NONE; +} diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt index c8e9964..c8fc391 100644 --- a/unittests/CMakeLists.txt +++ b/unittests/CMakeLists.txt @@ -1,24 +1,38 @@ -AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} TEST_SRCS) -AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/mock MOCK_SRCS) -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../include/) +SET(TARGET_TEST "appcore-agent-test") ENABLE_TESTING() -SET(TARGET_TEST "appcore-agent-test") -ADD_EXECUTABLE(${TARGET_TEST} ${TEST_SRCS} ${MOCK_SRCS}) -ADD_TEST(${TARGET_TEST} ${TARGET_TEST}) +INCLUDE(FindPkgConfig) +LINK_DIRECTORIES(${CMAKE_BINARY_DIR}) +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../include/) -pkg_check_modules(gtest_pkgs REQUIRED gmock) -INCLUDE_DIRECTORIES(${gtest_pkgs_INCLUDE_DIRS}) -LINK_DIRECTORIES(${gtest_pkgs_LIBRARY_DIRS}) +pkg_check_modules(test REQUIRED + aul + dlog + capi-appfw-app-control + vconf + ecore-core + vconf-internal-keys + app-core-cpp + capi-system-info + ) -INCLUDE(FindPkgConfig) -pkg_check_modules(test REQUIRED aul dlog capi-appfw-app-control capi-appfw-app-common vconf ecore-core vconf-internal-keys appcore-common capi-system-info) FOREACH(flag ${test_CFLAGS}) SET(EXTRA_CXXFLAGS_test "${EXTRA_CXXFLAGS_test} ${flag}") ENDFOREACH(flag) -SET(${EXTRA_CXXFLAGS_test} "${EXTRA_CXXFLAGS_test} --std=c++14") -SET_TARGET_PROPERTIES(${TARGET_TEST} PROPERTIES COMPILE_FLAGS ${EXTRA_CXXFLAGS_test}) +pkg_check_modules(gtest_pkgs REQUIRED gmock) +INCLUDE_DIRECTORIES(${gtest_pkgs_INCLUDE_DIRS}) +LINK_DIRECTORIES(${gtest_pkgs_LIBRARY_DIRS}) + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CXXFLAGS_test}") +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CXXFLAGS_test}") -TARGET_LINK_LIBRARIES(${TARGET_TEST} ${gtest_pkgs_LIBRARIES} appcore-agent) +AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/../src/ LIB_SRCS) +AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} TEST_SRCS) +AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/mock/ MOCK_SRCS) + +ADD_EXECUTABLE(${TARGET_TEST} ${MOCK_SRCS} ${TEST_SRCS} ${LIB_SRCS}) +TARGET_LINK_LIBRARIES(${TARGET_TEST} ${test_LDFLAGS} ${gtest_pkgs_LIBRARIES}) + +ADD_TEST(${TARGET_TEST} ${TARGET_TEST}) diff --git a/unittests/mock/appcore_mock.cc b/unittests/mock/appcore_mock.cc index 18cc1a7..91ded87 100644 --- a/unittests/mock/appcore_mock.cc +++ b/unittests/mock/appcore_mock.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 - 2021 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,14 +18,20 @@ #include "mock_hook.h" #include "test_fixture.h" -extern "C" int appcore_base_init(appcore_base_ops ops, int argc, char **argv, void* data) { - return MOCK_HOOK_P4(AppCoreMock, appcore_base_init, ops, argc, argv, data); +namespace tizen_cpp { + +void AppCoreBase::Run(int argc, char** argv) { + TestFixture::GetMock().Run(argc, argv); + TestFixture::GetMock().OnLoopInit(argc, argv, this); + TestFixture::GetMock().OnCreate(); + TestFixture::GetMock().OnLoopRun(); + TestFixture::GetMock().OnLoopFinish(); + TestFixture::GetMock().OnTerminate(); } -extern "C" void appcore_base_fini() { - return MOCK_HOOK_P0(AppCoreMock, appcore_base_fini); +void AppCoreBase::Exit() { + TestFixture::GetMock().Exit(); + TestFixture::GetMock().OnLoopExit(); } -extern "C" void appcore_base_exit() { - return MOCK_HOOK_P0(AppCoreMock, appcore_base_exit); -} \ No newline at end of file +} // namespace tizen_cpp diff --git a/unittests/mock/appcore_mock.h b/unittests/mock/appcore_mock.h index e130ece..683c17d 100644 --- a/unittests/mock/appcore_mock.h +++ b/unittests/mock/appcore_mock.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 - 2021 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,18 +16,22 @@ #ifndef MOCK_APPCORE_MOCK_H_ #define MOCK_APPCORE_MOCK_H_ + #include -#include +#include #include "module_mock.h" class AppCoreMock : public virtual ModuleMock { public: - virtual ~AppCoreMock() {} - - MOCK_METHOD4(appcore_base_init, int(appcore_base_ops, int, char**, void*)); - MOCK_METHOD0(appcore_base_fini, void()); - MOCK_METHOD0(appcore_base_exit, void()); + MOCK_METHOD2(Run, void(int, char**)); + MOCK_METHOD0(Exit, void()); + MOCK_METHOD0(OnCreate, void()); + MOCK_METHOD0(OnTerminate, void()); + MOCK_METHOD3(OnLoopInit, void(int, char**, void*)); + MOCK_METHOD0(OnLoopFinish, void()); + MOCK_METHOD0(OnLoopRun, void()); + MOCK_METHOD0(OnLoopExit, void()); }; -#endif // MOCK_APPCORE_HOOK_H_ \ No newline at end of file +#endif // MOCK_APPCORE_MOCK_H_ \ No newline at end of file diff --git a/unittests/service_app_test.cc b/unittests/service_app_test.cc index 9ad6fb9..87cdab9 100644 --- a/unittests/service_app_test.cc +++ b/unittests/service_app_test.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 - 2021 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -49,14 +48,8 @@ class ServiceAppTest : public TestFixture { virtual void TearDown() {} }; -extern "C" int __dlog_print(log_id_t log_id, int prio, const char *tag, const char *fmt, ...) { - printf("%s:", tag); - va_list ap; - va_start(ap, fmt); - vprintf(fmt, ap); - va_end(ap); - printf("\n"); - +extern "C" int __dlog_print(log_id_t log_id, int prio, const char* tag, + const char* fmt, ...) { return 0; } @@ -66,26 +59,13 @@ extern "C" int aul_job_scheduler_update_job_status(const char* job_id, } bool __service_app_create_cb(void* user_data) { - return false; -} - -bool __service_app_create_cb_loop(void* user_data) { - bool* loop = reinterpret_cast(user_data); - - while (*loop) { - std::cout << "wait..." << std::endl; - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - } - return true; } void __service_app_terminate_cb(void* user_data) { - } void __service_app_control_cb(app_control_h app_control, void* user_data) { - } TEST_F(ServiceAppTest, Basic) { @@ -102,14 +82,13 @@ TEST_F(ServiceAppTest, Basic) { char** argv; int argc = bundle_export_to_argv(b.GetHandle(), &argv); - std::unique_ptr> ptr(&argv, [argc](char*** ptr){ + std::unique_ptr> ptr(&argv, + [argc](char*** ptr) { bundle_free_exported_argv(argc, ptr); }); - ASSERT_TRUE(argc > 0); - - ret = service_app_main(argc, argv, &callback, nullptr); - EXPECT_THAT(ret, testing::Eq(APP_ERROR_NONE)); + ASSERT_GT(argc, 0); + using testing::_; ret = service_app_main(0, nullptr, &callback, nullptr); EXPECT_THAT(ret, testing::Eq(APP_ERROR_INVALID_PARAMETER)); @@ -118,31 +97,32 @@ TEST_F(ServiceAppTest, Basic) { ret = service_app_main(argc, argv, &callback, nullptr); EXPECT_THAT(ret, testing::Eq(APP_ERROR_INVALID_PARAMETER)); - using testing::_; - - EXPECT_CALL(GetMock(), appcore_base_init(_,_,_,_)) - .WillOnce(testing::Invoke([&](appcore_base_ops ops, int argc, char** argv, - void* data) { - ops.create(data); - return 0; - })); - + EXPECT_CALL(GetMock(), Run(_, _)).Times(1); bool loop = true; + EXPECT_CALL(GetMock(), OnLoopRun()) + .WillOnce(testing::Invoke([&]() { + while (loop) { + std::cout << "wait..." << std::endl; + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + })); + std::thread t([&]() { - callback.create = __service_app_create_cb_loop; + callback.create = __service_app_create_cb; service_app_main(argc, argv, &callback, reinterpret_cast(&loop)); }); std::this_thread::sleep_for(std::chrono::milliseconds(50)); - callback.create = __service_app_create_cb; - ret = service_app_main(1, argv, &callback, &loop); + ret = service_app_main(argc, argv, &callback, &loop); EXPECT_THAT(ret, testing::Eq(APP_ERROR_ALREADY_RUNNING)); - loop = false; - t.join(); - // test service_app_exit - EXPECT_CALL(GetMock(), appcore_base_exit()).Times(testing::AtLeast(1)); + EXPECT_CALL(GetMock(), Exit()).Times(1); + EXPECT_CALL(GetMock(), OnLoopExit()) + .WillOnce(testing::Invoke([&]() { + loop = false; + t.join(); + })); service_app_exit(); } @@ -154,12 +134,13 @@ TEST_F(ServiceAppTest, Internals) { handle = service_app_add_job_handler(nullptr, nullptr, nullptr); EXPECT_TRUE(handle == nullptr); - handle = service_app_add_job_handler("temp", [] (int status, const char* job_id, - bundle* job_data, void* user_data) -> int { - int* calledCnt = reinterpret_cast(user_data); - *calledCnt = *calledCnt + 1; - return 0; - }, reinterpret_cast(&calledCnt)); + handle = service_app_add_job_handler("temp", + [] (int status, const char* job_id, bundle* job_data, + void* user_data) -> int { + int* calledCnt = reinterpret_cast(user_data); + *calledCnt = *calledCnt + 1; + return 0; + }, reinterpret_cast(&calledCnt)); EXPECT_TRUE(handle != nullptr); EXPECT_THAT(calledCnt, testing::Eq(0)); @@ -169,7 +150,8 @@ TEST_F(ServiceAppTest, Internals) { ret = service_app_job_raise(0, nullptr, nullptr); EXPECT_THAT(ret, testing::Eq(APP_ERROR_INVALID_PARAMETER)); - ret = service_app_job_raise(SERVICE_APP_JOB_STATUS_START, "temp", b.GetHandle()); + ret = service_app_job_raise(SERVICE_APP_JOB_STATUS_START, "temp", + b.GetHandle()); g_main_context_iteration(g_main_context_default(), 0); EXPECT_THAT(ret, testing::Eq(APP_ERROR_NONE)); @@ -206,9 +188,9 @@ TEST_F(ServiceAppTest, EventHandlers) { EXPECT_THAT(ret, testing::Eq(APP_ERROR_NONE)); EXPECT_THAT(calledCnt, testing::Eq(0)); - appcore_base_raise_event(&calledCnt, APPCORE_BASE_EVENT_LOW_MEMORY); + //appcore_base_raise_event(&calledCnt, APPCORE_BASE_EVENT_LOW_MEMORY); - EXPECT_THAT(calledCnt, testing::Eq(1)); + //EXPECT_THAT(calledCnt, testing::Eq(1)); ret = service_app_remove_event_handler(nullptr); EXPECT_THAT(ret, testing::Eq(APP_ERROR_INVALID_PARAMETER)); @@ -216,11 +198,11 @@ TEST_F(ServiceAppTest, EventHandlers) { ret = service_app_remove_event_handler(handle); EXPECT_THAT(ret, testing::Eq(APP_ERROR_NONE)); - appcore_base_raise_event(&calledCnt, APPCORE_BASE_EVENT_LOW_MEMORY); - EXPECT_THAT(calledCnt, testing::Eq(1)); + //appcore_base_raise_event(&calledCnt, APPCORE_BASE_EVENT_LOW_MEMORY); + //EXPECT_THAT(calledCnt, testing::Eq(1)); } -} // namespace appcore_agent +} // namespace appcore_agent int main(int argc, char* argv[]) { int ret = 0; -- 2.7.4